소스 검색

refactor(drivers/usb):replace rtt usb stack with cherryusb (#8799)

sakumisu 11 달 전
부모
커밋
62d321caa0
100개의 변경된 파일25691개의 추가작업 그리고 1809개의 파일을 삭제
  1. 145 26
      bsp/bouffalo_lab/bl61x/.config
  2. 1 6
      bsp/bouffalo_lab/bl61x/Kconfig
  3. 1 0
      bsp/bouffalo_lab/bl61x/board/Kconfig
  4. 14 0
      bsp/bouffalo_lab/bl61x/board/cherryusb_port.c
  5. 265 0
      bsp/bouffalo_lab/bl61x/board/usb_config.h
  6. 88 11
      bsp/bouffalo_lab/bl61x/rtconfig.h
  7. 1518 1
      bsp/bouffalo_lab/libraries/Kconfig
  8. 0 1519
      bsp/bouffalo_lab/libraries/rt_drivers/Kconfig
  9. 261 32
      bsp/hpmicro/hpm6750evk2/.config
  10. 14 0
      bsp/hpmicro/hpm6750evk2/board/cherryusb_port.c
  11. 6 0
      bsp/hpmicro/hpm6750evk2/board/linker_scripts/flash_rtt.ld
  12. 267 0
      bsp/hpmicro/hpm6750evk2/board/usb_config.h
  13. 163 9
      bsp/hpmicro/hpm6750evk2/rtconfig.h
  14. 1 1
      bsp/hpmicro/libraries/hpm_sdk/SConscript
  15. 3 0
      components/Kconfig
  16. 1 200
      components/drivers/Kconfig
  17. 6 0
      components/drivers/usb/.ignore_format.yml
  18. 6 4
      components/drivers/usb/SConscript
  19. 171 0
      components/drivers/usb/cherryusb/.clang-format
  20. 47 0
      components/drivers/usb/cherryusb/.gitattributes
  21. 23 0
      components/drivers/usb/cherryusb/.gitignore
  22. 35 0
      components/drivers/usb/cherryusb/.readthedocs.yaml
  23. 2 0
      components/drivers/usb/cherryusb/CherryUSB.svg
  24. 310 0
      components/drivers/usb/cherryusb/Kconfig
  25. 304 0
      components/drivers/usb/cherryusb/Kconfig.cherryusb
  26. 201 0
      components/drivers/usb/cherryusb/LICENSE
  27. 196 0
      components/drivers/usb/cherryusb/README.md
  28. 198 0
      components/drivers/usb/cherryusb/README_zh.md
  29. 210 0
      components/drivers/usb/cherryusb/SConscript
  30. 5 0
      components/drivers/usb/cherryusb/VERSION
  31. 241 0
      components/drivers/usb/cherryusb/cherryusb.cmake
  32. 261 0
      components/drivers/usb/cherryusb/cherryusb_config_template.h
  33. 1165 0
      components/drivers/usb/cherryusb/class/audio/usb_audio.h
  34. 344 0
      components/drivers/usb/cherryusb/class/audio/usbd_audio.c
  35. 43 0
      components/drivers/usb/cherryusb/class/audio/usbd_audio.h
  36. 483 0
      components/drivers/usb/cherryusb/class/audio/usbh_audio.c
  37. 76 0
      components/drivers/usb/cherryusb/class/audio/usbh_audio.h
  38. 698 0
      components/drivers/usb/cherryusb/class/cdc/usb_cdc.h
  39. 118 0
      components/drivers/usb/cherryusb/class/cdc/usbd_cdc.c
  40. 29 0
      components/drivers/usb/cherryusb/class/cdc/usbd_cdc.h
  41. 247 0
      components/drivers/usb/cherryusb/class/cdc/usbd_cdc_ecm.c
  42. 42 0
      components/drivers/usb/cherryusb/class/cdc/usbd_cdc_ecm.h
  43. 263 0
      components/drivers/usb/cherryusb/class/cdc/usbh_cdc_acm.c
  44. 50 0
      components/drivers/usb/cherryusb/class/cdc/usbh_cdc_acm.h
  45. 319 0
      components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ecm.c
  46. 49 0
      components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ecm.h
  47. 388 0
      components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ncm.c
  48. 53 0
      components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ncm.h
  49. 137 0
      components/drivers/usb/cherryusb/class/dfu/usb_dfu.h
  50. 505 0
      components/drivers/usb/cherryusb/class/dfu/usbd_dfu.c
  51. 27 0
      components/drivers/usb/cherryusb/class/dfu/usbd_dfu.h
  52. 585 0
      components/drivers/usb/cherryusb/class/hid/usb_hid.h
  53. 89 0
      components/drivers/usb/cherryusb/class/hid/usbd_hid.c
  54. 34 0
      components/drivers/usb/cherryusb/class/hid/usbd_hid.h
  55. 231 0
      components/drivers/usb/cherryusb/class/hid/usbh_hid.c
  56. 41 0
      components/drivers/usb/cherryusb/class/hid/usbh_hid.h
  57. 121 0
      components/drivers/usb/cherryusb/class/hub/usb_hub.h
  58. 711 0
      components/drivers/usb/cherryusb/class/hub/usbh_hub.c
  59. 33 0
      components/drivers/usb/cherryusb/class/hub/usbh_hub.h
  60. 240 0
      components/drivers/usb/cherryusb/class/midi/usb_midi.h
  61. 89 0
      components/drivers/usb/cherryusb/class/msc/usb_msc.h
  62. 972 0
      components/drivers/usb/cherryusb/class/msc/usb_scsi.h
  63. 938 0
      components/drivers/usb/cherryusb/class/msc/usbd_msc.c
  64. 32 0
      components/drivers/usb/cherryusb/class/msc/usbd_msc.h
  65. 436 0
      components/drivers/usb/cherryusb/class/msc/usbh_msc.c
  66. 49 0
      components/drivers/usb/cherryusb/class/msc/usbh_msc.h
  67. 4 0
      components/drivers/usb/cherryusb/class/template/usb_xxx.h
  68. 39 0
      components/drivers/usb/cherryusb/class/template/usbd_xxx.c
  69. 16 0
      components/drivers/usb/cherryusb/class/template/usbd_xxx.h
  70. 97 0
      components/drivers/usb/cherryusb/class/template/usbh_xxx.c
  71. 22 0
      components/drivers/usb/cherryusb/class/template/usbh_xxx.h
  72. 774 0
      components/drivers/usb/cherryusb/class/vendor/net/usbh_asix.c
  73. 176 0
      components/drivers/usb/cherryusb/class/vendor/net/usbh_asix.h
  74. 2249 0
      components/drivers/usb/cherryusb/class/vendor/net/usbh_rtl8152.c
  75. 67 0
      components/drivers/usb/cherryusb/class/vendor/net/usbh_rtl8152.h
  76. 356 0
      components/drivers/usb/cherryusb/class/vendor/serial/usbh_ch34x.c
  77. 76 0
      components/drivers/usb/cherryusb/class/vendor/serial/usbh_ch34x.h
  78. 295 0
      components/drivers/usb/cherryusb/class/vendor/serial/usbh_cp210x.c
  79. 73 0
      components/drivers/usb/cherryusb/class/vendor/serial/usbh_cp210x.h
  80. 363 0
      components/drivers/usb/cherryusb/class/vendor/serial/usbh_ftdi.c
  81. 76 0
      components/drivers/usb/cherryusb/class/vendor/serial/usbh_ftdi.h
  82. 426 0
      components/drivers/usb/cherryusb/class/vendor/serial/usbh_pl2303.c
  83. 62 0
      components/drivers/usb/cherryusb/class/vendor/serial/usbh_pl2303.h
  84. 1198 0
      components/drivers/usb/cherryusb/class/video/usb_video.h
  85. 789 0
      components/drivers/usb/cherryusb/class/video/usbd_video.c
  86. 29 0
      components/drivers/usb/cherryusb/class/video/usbd_video.h
  87. 522 0
      components/drivers/usb/cherryusb/class/video/usbh_video.c
  88. 85 0
      components/drivers/usb/cherryusb/class/video/usbh_video.h
  89. 270 0
      components/drivers/usb/cherryusb/class/wireless/ndis.h
  90. 302 0
      components/drivers/usb/cherryusb/class/wireless/rndis_protocol.h
  91. 566 0
      components/drivers/usb/cherryusb/class/wireless/usbd_rndis.c
  92. 32 0
      components/drivers/usb/cherryusb/class/wireless/usbd_rndis.h
  93. 402 0
      components/drivers/usb/cherryusb/class/wireless/usbh_bluetooth.c
  94. 56 0
      components/drivers/usb/cherryusb/class/wireless/usbh_bluetooth.h
  95. 561 0
      components/drivers/usb/cherryusb/class/wireless/usbh_rndis.c
  96. 51 0
      components/drivers/usb/cherryusb/class/wireless/usbh_rndis.h
  97. 194 0
      components/drivers/usb/cherryusb/common/usb_dc.h
  98. 724 0
      components/drivers/usb/cherryusb/common/usb_def.h
  99. 24 0
      components/drivers/usb/cherryusb/common/usb_errno.h
  100. 114 0
      components/drivers/usb/cherryusb/common/usb_hc.h

+ 145 - 26
bsp/bouffalo_lab/bl61x/.config

@@ -1,7 +1,3 @@
-#
-# Automatically generated file; DO NOT EDIT.
-# RT-Thread Project Configuration
-#
 
 #
 # RT-Thread Kernel
@@ -12,7 +8,7 @@ CONFIG_RT_NAME_MAX=8
 # CONFIG_RT_USING_AMP is not set
 # CONFIG_RT_USING_SMP is not set
 CONFIG_RT_CPUS_NR=1
-CONFIG_RT_ALIGN_SIZE=8
+CONFIG_RT_ALIGN_SIZE=32
 # CONFIG_RT_THREAD_PRIORITY_8 is not set
 CONFIG_RT_THREAD_PRIORITY_32=y
 # CONFIG_RT_THREAD_PRIORITY_256 is not set
@@ -24,20 +20,27 @@ CONFIG_RT_HOOK_USING_FUNC_PTR=y
 # CONFIG_RT_USING_HOOKLIST is not set
 CONFIG_RT_USING_IDLE_HOOK=y
 CONFIG_RT_IDLE_HOOK_LIST_SIZE=4
-CONFIG_IDLE_THREAD_STACK_SIZE=512
+CONFIG_IDLE_THREAD_STACK_SIZE=2048
 CONFIG_RT_USING_TIMER_SOFT=y
 CONFIG_RT_TIMER_THREAD_PRIO=4
-CONFIG_RT_TIMER_THREAD_STACK_SIZE=512
+CONFIG_RT_TIMER_THREAD_STACK_SIZE=2048
 
 #
 # kservice optimization
 #
-CONFIG_RT_KSERVICE_USING_STDLIB=y
-# CONFIG_RT_KSERVICE_USING_STDLIB_MEMORY is not set
-# CONFIG_RT_KSERVICE_USING_TINY_SIZE is not set
 # CONFIG_RT_USING_TINY_FFS is not set
-# CONFIG_RT_KPRINTF_USING_LONGLONG is not set
+# end of kservice optimization
+
+#
+# klibc optimization
+#
+# CONFIG_RT_KLIBC_USING_STDLIB is not set
+# CONFIG_RT_KLIBC_USING_TINY_SIZE is not set
+# CONFIG_RT_KLIBC_USING_PRINTF_LONGLONG is not set
+# end of klibc optimization
+
 CONFIG_RT_USING_DEBUG=y
+CONFIG_RT_DEBUGING_ASSERT=y
 CONFIG_RT_DEBUGING_COLOR=y
 CONFIG_RT_DEBUGING_CONTEXT=y
 # CONFIG_RT_DEBUGING_AUTO_INIT is not set
@@ -52,6 +55,7 @@ CONFIG_RT_USING_MAILBOX=y
 CONFIG_RT_USING_MESSAGEQUEUE=y
 # CONFIG_RT_USING_MESSAGEQUEUE_PRIORITY is not set
 # CONFIG_RT_USING_SIGNALS is not set
+# end of Inter-Thread communication
 
 #
 # Memory Management
@@ -68,6 +72,8 @@ CONFIG_RT_USING_SMALL_MEM_AS_HEAP=y
 # CONFIG_RT_USING_MEMTRACE is not set
 # CONFIG_RT_USING_HEAP_ISR is not set
 CONFIG_RT_USING_HEAP=y
+# end of Memory Management
+
 CONFIG_RT_USING_DEVICE=y
 # CONFIG_RT_USING_DEVICE_OPS is not set
 # CONFIG_RT_USING_INTERRUPT_INFO is not set
@@ -76,14 +82,12 @@ CONFIG_RT_USING_DEVICE=y
 CONFIG_RT_USING_CONSOLE=y
 CONFIG_RT_CONSOLEBUF_SIZE=128
 CONFIG_RT_CONSOLE_DEVICE_NAME="uart0"
-CONFIG_RT_VER_NUM=0x50100
+CONFIG_RT_VER_NUM=0x50200
 # CONFIG_RT_USING_STDC_ATOMIC is not set
 CONFIG_RT_BACKTRACE_LEVEL_MAX_NR=32
-# CONFIG_RT_USING_CACHE is not set
-# CONFIG_RT_USING_HW_ATOMIC is not set
-# CONFIG_ARCH_ARM_BOOTWITH_FLUSH_CACHE is not set
-# CONFIG_ARCH_CPU_STACK_GROWS_UPWARD is not set
-# CONFIG_RT_USING_CPU_FFS is not set
+# end of RT-Thread Kernel
+
+CONFIG_RT_USING_CACHE=y
 CONFIG_ARCH_RISCV=y
 CONFIG_ARCH_RISCV_FPU=y
 CONFIG_ARCH_RISCV_FPU_S=y
@@ -150,6 +154,8 @@ CONFIG_RT_DFS_ELM_MAX_SECTOR_SIZE=512
 CONFIG_RT_DFS_ELM_REENTRANT=y
 CONFIG_RT_DFS_ELM_MUTEX_TIMEOUT=3000
 # CONFIG_RT_DFS_ELM_USE_EXFAT is not set
+# end of elm-chan's FatFs, Generic FAT Filesystem Module
+
 CONFIG_RT_USING_DFS_DEVFS=y
 CONFIG_RT_USING_DFS_ROMFS=y
 # CONFIG_RT_USING_DFS_ROMFS_USER_ROOT is not set
@@ -157,6 +163,8 @@ CONFIG_RT_USING_DFS_ROMFS=y
 # CONFIG_RT_USING_DFS_RAMFS is not set
 # CONFIG_RT_USING_DFS_TMPFS is not set
 # CONFIG_RT_USING_DFS_MQUEUE is not set
+# end of DFS: device virtual file system
+
 # CONFIG_RT_USING_FAL is not set
 
 #
@@ -207,13 +215,44 @@ CONFIG_RT_MMCSD_MAX_PARTITION=16
 CONFIG_RT_USING_PIN=y
 # CONFIG_RT_USING_KTIME is not set
 # CONFIG_RT_USING_HWTIMER is not set
-
-#
-# Using USB
-#
-# CONFIG_RT_USING_USB is not set
-# CONFIG_RT_USING_USB_HOST is not set
-# CONFIG_RT_USING_USB_DEVICE is not set
+CONFIG_RT_USING_CHERRYUSB=y
+# CONFIG_RT_CHERRYUSB_DEVICE is not set
+CONFIG_RT_CHERRYUSB_HOST=y
+# CONFIG_RT_CHERRYUSB_HOST_CUSTOM is not set
+CONFIG_RT_CHERRYUSB_HOST_EHCI_BL=y
+# CONFIG_RT_CHERRYUSB_HOST_EHCI_HPM is not set
+# CONFIG_RT_CHERRYUSB_HOST_EHCI_AIC is not set
+# CONFIG_RT_CHERRYUSB_HOST_EHCI_NUVOTON_NUC980 is not set
+# CONFIG_RT_CHERRYUSB_HOST_EHCI_NUVOTON_MA35D0 is not set
+# CONFIG_RT_CHERRYUSB_HOST_EHCI_CUSTOM is not set
+# CONFIG_RT_CHERRYUSB_HOST_DWC2_ST is not set
+# CONFIG_RT_CHERRYUSB_HOST_DWC2_ESP is not set
+# CONFIG_RT_CHERRYUSB_HOST_DWC2_CUSTOM is not set
+# CONFIG_RT_CHERRYUSB_HOST_MUSB_STANDARD is not set
+# CONFIG_RT_CHERRYUSB_HOST_MUSB_SUNXI is not set
+# CONFIG_RT_CHERRYUSB_HOST_MUSB_CUSTOM is not set
+# CONFIG_RT_CHERRYUSB_HOST_PUSB2 is not set
+# CONFIG_RT_CHERRYUSB_HOST_XHCI is not set
+CONFIG_RT_CHERRYUSB_HOST_CDC_ACM=y
+CONFIG_RT_CHERRYUSB_HOST_HID=y
+CONFIG_RT_CHERRYUSB_HOST_MSC=y
+# CONFIG_RT_CHERRYUSB_HOST_CDC_RNDIS is not set
+# CONFIG_RT_CHERRYUSB_HOST_CDC_ECM is not set
+# CONFIG_RT_CHERRYUSB_HOST_CDC_NCM is not set
+# CONFIG_RT_CHERRYUSB_HOST_VIDEO is not set
+# CONFIG_RT_CHERRYUSB_HOST_AUDIO is not set
+# CONFIG_RT_CHERRYUSB_HOST_BLUETOOTH is not set
+# CONFIG_RT_CHERRYUSB_HOST_ASIX is not set
+# CONFIG_RT_CHERRYUSB_HOST_RTL8152 is not set
+# CONFIG_RT_CHERRYUSB_HOST_FTDI is not set
+# CONFIG_RT_CHERRYUSB_HOST_CH34X is not set
+# CONFIG_RT_CHERRYUSB_HOST_CP210X is not set
+# CONFIG_RT_CHERRYUSB_HOST_PL2303 is not set
+CONFIG_RT_CHERRYUSB_HOST_TEMPLATE=y
+CONFIG_TEST_USBH_CDC_ACM=1
+CONFIG_TEST_USBH_HID=1
+CONFIG_TEST_USBH_MSC=0
+# end of Device Drivers
 
 #
 # C/C++ and POSIX layer
@@ -231,6 +270,8 @@ CONFIG_RT_LIBC_USING_LIGHT_TZ_DST=y
 CONFIG_RT_LIBC_TZ_DEFAULT_HOUR=8
 CONFIG_RT_LIBC_TZ_DEFAULT_MIN=0
 CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
+# end of Timezone and Daylight Saving Time
+# end of ISO-ANSI C layer
 
 #
 # POSIX (Portable Operating System Interface) layer
@@ -252,7 +293,11 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 #
 # Socket is in the 'Network' category
 #
+# end of Interprocess Communication (IPC)
+# end of POSIX (Portable Operating System Interface) layer
+
 # CONFIG_RT_USING_CPLUSPLUS is not set
+# end of C/C++ and POSIX layer
 
 #
 # Network
@@ -261,12 +306,14 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_RT_USING_NETDEV is not set
 # CONFIG_RT_USING_LWIP is not set
 # CONFIG_RT_USING_AT is not set
+# end of Network
 
 #
 # Memory protection
 #
 # CONFIG_RT_USING_MEM_PROTECTION is not set
 # CONFIG_RT_USING_HW_STACK_GUARD is not set
+# end of Memory protection
 
 #
 # Utilities
@@ -278,12 +325,23 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_RT_USING_RESOURCE_ID is not set
 # CONFIG_RT_USING_ADT is not set
 # CONFIG_RT_USING_RT_LINK is not set
+# end of Utilities
+
 # CONFIG_RT_USING_VBUS is not set
 
+#
+# Using USB legacy version
+#
+# CONFIG_RT_USING_USB_HOST is not set
+# CONFIG_RT_USING_USB_DEVICE is not set
+# end of Using USB legacy version
+# end of RT-Thread Components
+
 #
 # RT-Thread Utestcases
 #
 # CONFIG_RT_USING_UTESTCASES is not set
+# end of RT-Thread Utestcases
 
 #
 # RT-Thread online packages
@@ -292,7 +350,6 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 #
 # IoT - internet of things
 #
-# CONFIG_PKG_USING_LWIP is not set
 # CONFIG_PKG_USING_LORAWAN_DRIVER is not set
 # CONFIG_PKG_USING_PAHOMQTT is not set
 # CONFIG_PKG_USING_UMQTT is not set
@@ -314,27 +371,35 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # Marvell WiFi
 #
 # CONFIG_PKG_USING_WLANMARVELL is not set
+# end of Marvell WiFi
 
 #
 # Wiced WiFi
 #
 # CONFIG_PKG_USING_WLAN_WICED is not set
+# end of Wiced WiFi
+
 # CONFIG_PKG_USING_RW007 is not set
 
 #
 # CYW43012 WiFi
 #
 # CONFIG_PKG_USING_WLAN_CYW43012 is not set
+# end of CYW43012 WiFi
 
 #
 # BL808 WiFi
 #
 # CONFIG_PKG_USING_WLAN_BL808 is not set
+# end of BL808 WiFi
 
 #
 # CYW43439 WiFi
 #
 # CONFIG_PKG_USING_WLAN_CYW43439 is not set
+# end of CYW43439 WiFi
+# end of Wi-Fi
+
 # CONFIG_PKG_USING_COAP is not set
 # CONFIG_PKG_USING_NOPOLL is not set
 # CONFIG_PKG_USING_NETUTILS is not set
@@ -357,6 +422,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_UCLOUD_IOT_SDK is not set
 # CONFIG_PKG_USING_JOYLINK is not set
 # CONFIG_PKG_USING_IOTSHARP_SDK is not set
+# end of IoT Cloud
+
 # CONFIG_PKG_USING_NIMBLE is not set
 # CONFIG_PKG_USING_LLSYNC_SDK_ADAPTER is not set
 # CONFIG_PKG_USING_OTA_DOWNLOADER is not set
@@ -399,6 +466,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ZEPHYR_POLLING is not set
 # CONFIG_PKG_USING_MATTER_ADAPTATION_LAYER is not set
 # CONFIG_PKG_USING_LHC_MODBUS is not set
+# CONFIG_PKG_USING_QMODBUS is not set
+# end of IoT - internet of things
 
 #
 # security packages
@@ -409,6 +478,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_TINYCRYPT is not set
 # CONFIG_PKG_USING_TFM is not set
 # CONFIG_PKG_USING_YD_CRYPTO is not set
+# end of security packages
 
 #
 # language packages
@@ -424,18 +494,22 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_JSMN is not set
 # CONFIG_PKG_USING_AGILE_JSMN is not set
 # CONFIG_PKG_USING_PARSON is not set
+# end of JSON: JavaScript Object Notation, a lightweight data-interchange format
 
 #
 # XML: Extensible Markup Language
 #
 # CONFIG_PKG_USING_SIMPLE_XML is not set
 # CONFIG_PKG_USING_EZXML is not set
+# end of XML: Extensible Markup Language
+
 # CONFIG_PKG_USING_LUATOS_SOC is not set
 # CONFIG_PKG_USING_LUA is not set
 # CONFIG_PKG_USING_JERRYSCRIPT is not set
 # CONFIG_PKG_USING_MICROPYTHON is not set
 # CONFIG_PKG_USING_PIKASCRIPT is not set
 # CONFIG_PKG_USING_RTT_RUST is not set
+# end of language packages
 
 #
 # multimedia packages
@@ -447,12 +521,15 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_LVGL is not set
 # CONFIG_PKG_USING_LV_MUSIC_DEMO is not set
 # CONFIG_PKG_USING_GUI_GUIDER_DEMO is not set
+# end of LVGL: powerful and easy-to-use embedded GUI library
 
 #
 # u8g2: a monochrome graphic library
 #
 # CONFIG_PKG_USING_U8G2_OFFICIAL is not set
 # CONFIG_PKG_USING_U8G2 is not set
+# end of u8g2: a monochrome graphic library
+
 # CONFIG_PKG_USING_OPENMV is not set
 # CONFIG_PKG_USING_MUPDF is not set
 # CONFIG_PKG_USING_STEMWIN is not set
@@ -472,6 +549,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_QRCODE is not set
 # CONFIG_PKG_USING_GUIENGINE is not set
 # CONFIG_PKG_USING_3GPP_AMRNB is not set
+# end of multimedia packages
 
 #
 # tools packages
@@ -520,6 +598,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARMV7M_DWT_TOOL is not set
 # CONFIG_PKG_USING_VOFA_PLUS is not set
 # CONFIG_PKG_USING_ZDEBUG is not set
+# end of tools packages
 
 #
 # system packages
@@ -531,6 +610,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_RT_MEMCPY_CM is not set
 # CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
 # CONFIG_PKG_USING_RT_VSNPRINTF_FULL is not set
+# end of enhanced kernel services
 
 #
 # acceleration: Assembly language or algorithmic acceleration packages
@@ -538,6 +618,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_QFPLIB_M0_FULL is not set
 # CONFIG_PKG_USING_QFPLIB_M0_TINY is not set
 # CONFIG_PKG_USING_QFPLIB_M3 is not set
+# end of acceleration: Assembly language or algorithmic acceleration packages
 
 #
 # CMSIS: ARM Cortex-M Microcontroller Software Interface Standard
@@ -548,6 +629,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_CMSIS_NN is not set
 # CONFIG_PKG_USING_CMSIS_RTOS1 is not set
 # CONFIG_PKG_USING_CMSIS_RTOS2 is not set
+# end of CMSIS: ARM Cortex-M Microcontroller Software Interface Standard
 
 #
 # Micrium: Micrium software products porting for RT-Thread
@@ -558,6 +640,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_UC_CLK is not set
 # CONFIG_PKG_USING_UC_COMMON is not set
 # CONFIG_PKG_USING_UC_MODBUS is not set
+# end of Micrium: Micrium software products porting for RT-Thread
+
 # CONFIG_PKG_USING_FREERTOS_WRAPPER is not set
 # CONFIG_PKG_USING_LITEOS_SDK is not set
 # CONFIG_PKG_USING_TZ_DATABASE is not set
@@ -605,6 +689,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_RTP is not set
 # CONFIG_PKG_USING_REB is not set
 # CONFIG_PKG_USING_R_RHEALSTONE is not set
+# end of system packages
 
 #
 # peripheral libraries and drivers
@@ -617,9 +702,12 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 #
 # STM32 HAL & SDK Drivers
 #
-# CONFIG_PKG_USING_STM32L4XX_HAL_DRIVER is not set
+# CONFIG_PKG_USING_STM32L4_HAL_DRIVER is not set
+# CONFIG_PKG_USING_STM32L4_CMSIS_DRIVER is not set
 # CONFIG_PKG_USING_STM32WB55_SDK is not set
 # CONFIG_PKG_USING_STM32_SDIO is not set
+# end of STM32 HAL & SDK Drivers
+
 # CONFIG_PKG_USING_BLUETRUM_SDK is not set
 # CONFIG_PKG_USING_EMBARC_BSP is not set
 # CONFIG_PKG_USING_ESP_IDF is not set
@@ -629,10 +717,13 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 #
 # CONFIG_PKG_USING_K210_SDK is not set
 # CONFIG_PKG_USING_KENDRYTE_SDK is not set
+# end of Kendryte SDK
+
 # CONFIG_PKG_USING_NRF5X_SDK is not set
 # CONFIG_PKG_USING_NRFX is not set
 # CONFIG_PKG_USING_NUCLEI_SDK is not set
 # CONFIG_PKG_USING_RASPBERRYPI_PICO_SDK is not set
+# end of HAL & SDK Drivers
 
 #
 # sensors drivers
@@ -702,6 +793,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ICM20608 is not set
 # CONFIG_PKG_USING_PAJ7620 is not set
 # CONFIG_PKG_USING_STHS34PF80 is not set
+# end of sensors drivers
 
 #
 # touch drivers
@@ -716,6 +808,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_XPT2046_TOUCH is not set
 # CONFIG_PKG_USING_CST816X is not set
 # CONFIG_PKG_USING_CST812T is not set
+# end of touch drivers
+
 # CONFIG_PKG_USING_REALTEK_AMEBA is not set
 # CONFIG_PKG_USING_BUTTON is not set
 # CONFIG_PKG_USING_PCF8574 is not set
@@ -788,6 +882,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_BT_MX01 is not set
 # CONFIG_PKG_USING_RGPOWER is not set
 # CONFIG_PKG_USING_SPI_TOOLS is not set
+# end of peripheral libraries and drivers
 
 #
 # AI packages
@@ -802,6 +897,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_QUEST is not set
 # CONFIG_PKG_USING_NAXOS is not set
 # CONFIG_PKG_USING_R_TINYMAIX is not set
+# end of AI packages
 
 #
 # Signal Processing and Control Algorithm Packages
@@ -811,6 +907,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_UKAL is not set
 # CONFIG_PKG_USING_DIGITALCTRL is not set
 # CONFIG_PKG_USING_KISSFFT is not set
+# end of Signal Processing and Control Algorithm Packages
 
 #
 # miscellaneous packages
@@ -819,6 +916,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 #
 # project laboratory
 #
+# end of project laboratory
 
 #
 # samples: kernel and components samples
@@ -827,6 +925,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_FILESYSTEM_SAMPLES is not set
 # CONFIG_PKG_USING_NETWORK_SAMPLES is not set
 # CONFIG_PKG_USING_PERIPHERAL_SAMPLES is not set
+# end of samples: kernel and components samples
 
 #
 # entertainment: terminal games and other interesting software packages
@@ -842,6 +941,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_DONUT is not set
 # CONFIG_PKG_USING_COWSAY is not set
 # CONFIG_PKG_USING_MORSE is not set
+# end of entertainment: terminal games and other interesting software packages
+
 # CONFIG_PKG_USING_LIBCSV is not set
 # CONFIG_PKG_USING_OPTPARSE is not set
 # CONFIG_PKG_USING_FASTLZ is not set
@@ -875,6 +976,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_SOEM is not set
 # CONFIG_PKG_USING_QPARAM is not set
 # CONFIG_PKG_USING_CorevMCU_CLI is not set
+# end of miscellaneous packages
 
 #
 # Arduino libraries
@@ -890,6 +992,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_NINEINONE_SENSOR_SHIELD is not set
 # CONFIG_PKG_USING_ARDUINO_SENSOR_KIT is not set
 # CONFIG_PKG_USING_ARDUINO_MATLAB_SUPPORT is not set
+# end of Projects and Demos
 
 #
 # Sensors
@@ -1029,6 +1132,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_SEEED_LTC2941 is not set
 # CONFIG_PKG_USING_ARDUINO_SEEED_LDC1612 is not set
 # CONFIG_PKG_USING_ARDUINO_CAPACITIVESENSOR is not set
+# CONFIG_PKG_USING_ARDUINO_JARZEBSKI_MPU6050 is not set
+# end of Sensors
 
 #
 # Display
@@ -1040,6 +1145,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SSD1306 is not set
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ILI9341 is not set
 # CONFIG_PKG_USING_SEEED_TM1637 is not set
+# end of Display
 
 #
 # Timing
@@ -1048,6 +1154,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_MSTIMER2 is not set
 # CONFIG_PKG_USING_ARDUINO_TICKER is not set
 # CONFIG_PKG_USING_ARDUINO_TASKSCHEDULER is not set
+# end of Timing
 
 #
 # Data Processing
@@ -1055,6 +1162,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_KALMANFILTER is not set
 # CONFIG_PKG_USING_ARDUINO_ARDUINOJSON is not set
 # CONFIG_PKG_USING_ARDUINO_TENSORFLOW_LITE_MICRO is not set
+# CONFIG_PKG_USING_ARDUINO_RUNNINGMEDIAN is not set
+# end of Data Processing
 
 #
 # Data Storage
@@ -1065,6 +1174,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 #
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PN532 is not set
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI4713 is not set
+# end of Communication
 
 #
 # Device Control
@@ -1076,12 +1186,14 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DS1841 is not set
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DS3502 is not set
 # CONFIG_PKG_USING_ARDUINO_SEEED_PCF85063TP is not set
+# end of Device Control
 
 #
 # Other
 #
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MFRC630 is not set
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI5351 is not set
+# end of Other
 
 #
 # Signal IO
@@ -1094,10 +1206,14 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP3008 is not set
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP4725 is not set
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BD3491FS is not set
+# end of Signal IO
 
 #
 # Uncategorized
 #
+# end of Arduino libraries
+# end of RT-Thread online packages
+
 CONFIG_BSP_USING_BL61X=y
 CONFIG_BSP_USING_ROMAPI=y
 # CONFIG_BSP_USING_PSRAM is not set
@@ -1184,6 +1300,8 @@ CONFIG_UART0_RX_USING_GPIO22=y
 # CONFIG_UART0_RX_USING_GPIO33 is not set
 # CONFIG_UART0_RX_USING_GPIO34 is not set
 # CONFIG_BSP_USING_UART1 is not set
+# end of General Purpose UARTs
+
 # CONFIG_BSP_USING_GPIO is not set
 # CONFIG_BSP_USING_ADC is not set
 # CONFIG_BSP_USING_RTC is not set
@@ -1194,3 +1312,4 @@ CONFIG_UART0_RX_USING_GPIO22=y
 # CONFIG_BSP_USING_SPI is not set
 # CONFIG_BSP_USING_ON_CHIP_FLASH is not set
 # CONFIG_BSP_USING_SDH is not set
+# end of General Drivers Configuration

+ 1 - 6
bsp/bouffalo_lab/bl61x/Kconfig

@@ -15,12 +15,7 @@ config PKGS_DIR
     option env="PKGS_ROOT"
     default "packages"
 
-config LIBRARIES_DIR
-    string
-    option env="LIBRARIES_DIR"
-    default "../libraries"
-
 source "$RTT_DIR/Kconfig"
 source "$PKGS_DIR/Kconfig"
 source "board/Kconfig"
-source "$LIBRARIES_DIR/Kconfig"
+source "../libraries/Kconfig"

+ 1 - 0
bsp/bouffalo_lab/bl61x/board/Kconfig

@@ -5,6 +5,7 @@ config BSP_USING_BL61X
     select ARCH_RISCV32
     select ARCH_RISCV_FPU_S
     select BSP_USING_ROMAPI
+    select RT_USING_CACHE
     default y
 
 config BSP_USING_ROMAPI

+ 14 - 0
bsp/bouffalo_lab/bl61x/board/cherryusb_port.c

@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2024/04/23     sakumisu    first version
+ */
+#include <rtthread.h>
+
+/* low level init here, this has implemented in cherryusb */
+
+/* low level deinit here, this has implemented in cherryusb */

+ 265 - 0
bsp/bouffalo_lab/bl61x/board/usb_config.h

@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef CHERRYUSB_CONFIG_H
+#define CHERRYUSB_CONFIG_H
+
+#define CHERRYUSB_VERSION     0x010300
+#define CHERRYUSB_VERSION_STR "v1.3.0"
+
+/* ================ USB common Configuration ================ */
+
+#include <rtthread.h>
+
+#define CONFIG_USB_PRINTF(...) rt_kprintf(__VA_ARGS__)
+
+#define usb_malloc(size) rt_malloc(size)
+#define usb_free(ptr)    rt_free(ptr)
+
+#define memcpy rt_memcpy
+
+#ifndef CONFIG_USB_DBG_LEVEL
+#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
+#endif
+
+/* Enable print with color */
+#define CONFIG_USB_PRINTF_COLOR_ENABLE
+
+/* data align size when use dma */
+#ifndef CONFIG_USB_ALIGN_SIZE
+#define CONFIG_USB_ALIGN_SIZE 4
+#endif
+
+/* attribute data into no cache ram */
+#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
+
+/* ================= USB Device Stack Configuration ================ */
+
+/* Ep0 in and out transfer buffer */
+#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
+#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
+#endif
+
+/* Setup packet log for debug */
+// #define CONFIG_USBDEV_SETUP_LOG_PRINT
+
+/* Send ep0 in data from user buffer instead of copying into ep0 reqdata
+ * Please note that user buffer must be aligned with CONFIG_USB_ALIGN_SIZE
+*/
+// #define CONFIG_USBDEV_EP0_INDATA_NO_COPY
+
+/* Check if the input descriptor is correct */
+// #define CONFIG_USBDEV_DESC_CHECK
+
+/* Enable test mode */
+// #define CONFIG_USBDEV_TEST_MODE
+
+#ifndef CONFIG_USBDEV_MSC_MAX_LUN
+#define CONFIG_USBDEV_MSC_MAX_LUN 1
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
+#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
+#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
+#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
+#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
+#endif
+
+// #define CONFIG_USBDEV_MSC_THREAD
+
+#ifndef CONFIG_USBDEV_MSC_PRIO
+#define CONFIG_USBDEV_MSC_PRIO 4
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_STACKSIZE
+#define CONFIG_USBDEV_MSC_STACKSIZE 2048
+#endif
+
+#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
+#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
+#endif
+
+/* rndis transfer buffer size, must be a multiple of (1536 + 44)*/
+#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
+#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
+#endif
+
+#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID
+#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff
+#endif
+
+#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC
+#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB"
+#endif
+
+#define CONFIG_USBDEV_RNDIS_USING_LWIP
+
+/* ================ USB HOST Stack Configuration ================== */
+
+#define CONFIG_USBHOST_MAX_RHPORTS          1
+#define CONFIG_USBHOST_MAX_EXTHUBS          1
+#define CONFIG_USBHOST_MAX_EHPORTS          4
+#define CONFIG_USBHOST_MAX_INTERFACES       8
+#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
+#define CONFIG_USBHOST_MAX_ENDPOINTS        4
+
+#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
+#define CONFIG_USBHOST_MAX_HID_CLASS     4
+#define CONFIG_USBHOST_MAX_MSC_CLASS     2
+#define CONFIG_USBHOST_MAX_AUDIO_CLASS   1
+#define CONFIG_USBHOST_MAX_VIDEO_CLASS   1
+
+#define CONFIG_USBHOST_DEV_NAMELEN 16
+
+#ifndef CONFIG_USBHOST_PSC_PRIO
+#define CONFIG_USBHOST_PSC_PRIO 0
+#endif
+#ifndef CONFIG_USBHOST_PSC_STACKSIZE
+#define CONFIG_USBHOST_PSC_STACKSIZE 2048
+#endif
+
+//#define CONFIG_USBHOST_GET_STRING_DESC
+
+// #define CONFIG_USBHOST_MSOS_ENABLE
+#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE
+#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
+#endif
+
+/* Ep0 max transfer buffer */
+#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN
+#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512
+#endif
+
+#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
+#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
+#endif
+
+#ifndef CONFIG_USBHOST_MSC_TIMEOUT
+#define CONFIG_USBHOST_MSC_TIMEOUT 5000
+#endif
+
+/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
+ * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
+ */
+#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE
+#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048)
+#endif
+
+/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
+#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE
+#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
+#endif
+
+/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
+ * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
+ */
+#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE
+#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE (2048)
+#endif
+/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
+#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE
+#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE (2048)
+#endif
+
+/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
+ * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
+ */
+#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE
+#define CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE (2048)
+#endif
+/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
+#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE
+#define CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE (2048)
+#endif
+
+#define CONFIG_USBHOST_BLUETOOTH_HCI_H4
+// #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG
+
+#ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE
+#define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048
+#endif
+#ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE
+#define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048
+#endif
+
+/* ================ USB Device Port Configuration ================*/
+
+#ifndef CONFIG_USBDEV_MAX_BUS
+#define CONFIG_USBDEV_MAX_BUS 1 // for now, bus num must be 1 except hpm ip
+#endif
+
+#ifndef CONFIG_USBDEV_EP_NUM
+#define CONFIG_USBDEV_EP_NUM 4
+#endif
+
+/* ---------------- FSDEV Configuration ---------------- */
+//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
+
+/* ---------------- DWC2 Configuration ---------------- */
+// #define CONFIG_USB_DWC2_RXALL_FIFO_SIZE (1024 / 4)
+// #define CONFIG_USB_DWC2_TX0_FIFO_SIZE (64 / 4)
+// #define CONFIG_USB_DWC2_TX1_FIFO_SIZE (512 / 4)
+// #define CONFIG_USB_DWC2_TX2_FIFO_SIZE (64 / 4)
+// #define CONFIG_USB_DWC2_TX3_FIFO_SIZE (64 / 4)
+// #define CONFIG_USB_DWC2_TX4_FIFO_SIZE (0 / 4)
+// #define CONFIG_USB_DWC2_TX5_FIFO_SIZE (0 / 4)
+// #define CONFIG_USB_DWC2_TX6_FIFO_SIZE (0 / 4)
+// #define CONFIG_USB_DWC2_TX7_FIFO_SIZE (0 / 4)
+// #define CONFIG_USB_DWC2_TX8_FIFO_SIZE (0 / 4)
+
+/* ---------------- MUSB Configuration ---------------- */
+// #define CONFIG_USB_MUSB_SUNXI
+
+/* ================ USB Host Port Configuration ==================*/
+#ifndef CONFIG_USBHOST_MAX_BUS
+#define CONFIG_USBHOST_MAX_BUS 1
+#endif
+
+#ifndef CONFIG_USBHOST_PIPE_NUM
+#define CONFIG_USBHOST_PIPE_NUM 10
+#endif
+
+/* ---------------- EHCI Configuration ---------------- */
+
+#define CONFIG_USB_EHCI_HCCR_OFFSET     (0x0)
+#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
+#define CONFIG_USB_EHCI_QH_NUM          CONFIG_USBHOST_PIPE_NUM
+#define CONFIG_USB_EHCI_QTD_NUM         3
+#define CONFIG_USB_EHCI_ITD_NUM         20
+#define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
+// #define CONFIG_USB_EHCI_CONFIGFLAG
+// #define CONFIG_USB_EHCI_ISO
+// #define CONFIG_USB_EHCI_WITH_OHCI
+
+/* ---------------- OHCI Configuration ---------------- */
+#define CONFIG_USB_OHCI_HCOR_OFFSET (0x0)
+
+/* ---------------- XHCI Configuration ---------------- */
+#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
+
+/* ---------------- DWC2 Configuration ---------------- */
+/* largest non-periodic USB packet used / 4 */
+// #define CONFIG_USB_DWC2_NPTX_FIFO_SIZE (512 / 4)
+/* largest periodic USB packet used / 4 */
+// #define CONFIG_USB_DWC2_PTX_FIFO_SIZE (1024 / 4)
+/*
+ * (largest USB packet used / 4) + 1 for status information + 1 transfer complete +
+ * 1 location each for Bulk/Control endpoint for handling NAK/NYET scenario
+ */
+// #define CONFIG_USB_DWC2_RX_FIFO_SIZE ((1012 - CONFIG_USB_DWC2_NPTX_FIFO_SIZE - CONFIG_USB_DWC2_PTX_FIFO_SIZE) / 4)
+
+/* ---------------- MUSB Configuration ---------------- */
+// #define CONFIG_USB_MUSB_SUNXI
+
+#endif

+ 88 - 11
bsp/bouffalo_lab/bl61x/rtconfig.h

@@ -1,14 +1,11 @@
 #ifndef RT_CONFIG_H__
 #define RT_CONFIG_H__
 
-/* Automatically generated file; DO NOT EDIT. */
-/* RT-Thread Project Configuration */
-
 /* RT-Thread Kernel */
 
 #define RT_NAME_MAX 8
 #define RT_CPUS_NR 1
-#define RT_ALIGN_SIZE 8
+#define RT_ALIGN_SIZE 32
 #define RT_THREAD_PRIORITY_32
 #define RT_THREAD_PRIORITY_MAX 32
 #define RT_TICK_PER_SECOND 1000
@@ -17,15 +14,20 @@
 #define RT_HOOK_USING_FUNC_PTR
 #define RT_USING_IDLE_HOOK
 #define RT_IDLE_HOOK_LIST_SIZE 4
-#define IDLE_THREAD_STACK_SIZE 512
+#define IDLE_THREAD_STACK_SIZE 2048
 #define RT_USING_TIMER_SOFT
 #define RT_TIMER_THREAD_PRIO 4
-#define RT_TIMER_THREAD_STACK_SIZE 512
+#define RT_TIMER_THREAD_STACK_SIZE 2048
 
 /* kservice optimization */
 
-#define RT_KSERVICE_USING_STDLIB
+/* end of kservice optimization */
+
+/* klibc optimization */
+
+/* end of klibc optimization */
 #define RT_USING_DEBUG
+#define RT_DEBUGING_ASSERT
 #define RT_DEBUGING_COLOR
 #define RT_DEBUGING_CONTEXT
 
@@ -36,6 +38,7 @@
 #define RT_USING_EVENT
 #define RT_USING_MAILBOX
 #define RT_USING_MESSAGEQUEUE
+/* end of Inter-Thread communication */
 
 /* Memory Management */
 
@@ -43,12 +46,15 @@
 #define RT_USING_SMALL_MEM
 #define RT_USING_SMALL_MEM_AS_HEAP
 #define RT_USING_HEAP
+/* end of Memory Management */
 #define RT_USING_DEVICE
 #define RT_USING_CONSOLE
 #define RT_CONSOLEBUF_SIZE 128
 #define RT_CONSOLE_DEVICE_NAME "uart0"
-#define RT_VER_NUM 0x50100
+#define RT_VER_NUM 0x50200
 #define RT_BACKTRACE_LEVEL_MAX_NR 32
+/* end of RT-Thread Kernel */
+#define RT_USING_CACHE
 #define ARCH_RISCV
 #define ARCH_RISCV_FPU
 #define ARCH_RISCV_FPU_S
@@ -99,8 +105,10 @@
 #define RT_DFS_ELM_MAX_SECTOR_SIZE 512
 #define RT_DFS_ELM_REENTRANT
 #define RT_DFS_ELM_MUTEX_TIMEOUT 3000
+/* end of elm-chan's FatFs, Generic FAT Filesystem Module */
 #define RT_USING_DFS_DEVFS
 #define RT_USING_DFS_ROMFS
+/* end of DFS: device virtual file system */
 
 /* Device Drivers */
 
@@ -117,9 +125,17 @@
 #define RT_MMCSD_THREAD_PREORITY 22
 #define RT_MMCSD_MAX_PARTITION 16
 #define RT_USING_PIN
-
-/* Using USB */
-
+#define RT_USING_CHERRYUSB
+#define RT_CHERRYUSB_HOST
+#define RT_CHERRYUSB_HOST_EHCI_BL
+#define RT_CHERRYUSB_HOST_CDC_ACM
+#define RT_CHERRYUSB_HOST_HID
+#define RT_CHERRYUSB_HOST_MSC
+#define RT_CHERRYUSB_HOST_TEMPLATE
+#define TEST_USBH_CDC_ACM 1
+#define TEST_USBH_HID 1
+#define TEST_USBH_MSC 0
+/* end of Device Drivers */
 
 /* C/C++ and POSIX layer */
 
@@ -131,6 +147,8 @@
 #define RT_LIBC_TZ_DEFAULT_HOUR 8
 #define RT_LIBC_TZ_DEFAULT_MIN 0
 #define RT_LIBC_TZ_DEFAULT_SEC 0
+/* end of Timezone and Daylight Saving Time */
+/* end of ISO-ANSI C layer */
 
 /* POSIX (Portable Operating System Interface) layer */
 
@@ -140,18 +158,30 @@
 
 /* Socket is in the 'Network' category */
 
+/* end of Interprocess Communication (IPC) */
+/* end of POSIX (Portable Operating System Interface) layer */
+/* end of C/C++ and POSIX layer */
 
 /* Network */
 
+/* end of Network */
 
 /* Memory protection */
 
+/* end of Memory protection */
 
 /* Utilities */
 
+/* end of Utilities */
+
+/* Using USB legacy version */
+
+/* end of Using USB legacy version */
+/* end of RT-Thread Components */
 
 /* RT-Thread Utestcases */
 
+/* end of RT-Thread Utestcases */
 
 /* RT-Thread online packages */
 
@@ -162,57 +192,78 @@
 
 /* Marvell WiFi */
 
+/* end of Marvell WiFi */
 
 /* Wiced WiFi */
 
+/* end of Wiced WiFi */
 
 /* CYW43012 WiFi */
 
+/* end of CYW43012 WiFi */
 
 /* BL808 WiFi */
 
+/* end of BL808 WiFi */
 
 /* CYW43439 WiFi */
 
+/* end of CYW43439 WiFi */
+/* end of Wi-Fi */
 
 /* IoT Cloud */
 
+/* end of IoT Cloud */
+/* end of IoT - internet of things */
 
 /* security packages */
 
+/* end of security packages */
 
 /* language packages */
 
 /* JSON: JavaScript Object Notation, a lightweight data-interchange format */
 
+/* end of JSON: JavaScript Object Notation, a lightweight data-interchange format */
 
 /* XML: Extensible Markup Language */
 
+/* end of XML: Extensible Markup Language */
+/* end of language packages */
 
 /* multimedia packages */
 
 /* LVGL: powerful and easy-to-use embedded GUI library */
 
+/* end of LVGL: powerful and easy-to-use embedded GUI library */
 
 /* u8g2: a monochrome graphic library */
 
+/* end of u8g2: a monochrome graphic library */
+/* end of multimedia packages */
 
 /* tools packages */
 
+/* end of tools packages */
 
 /* system packages */
 
 /* enhanced kernel services */
 
+/* end of enhanced kernel services */
 
 /* acceleration: Assembly language or algorithmic acceleration packages */
 
+/* end of acceleration: Assembly language or algorithmic acceleration packages */
 
 /* CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */
 
+/* end of CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */
 
 /* Micrium: Micrium software products porting for RT-Thread */
 
+/* end of Micrium: Micrium software products porting for RT-Thread */
+/* end of system packages */
 
 /* peripheral libraries and drivers */
 
@@ -220,66 +271,90 @@
 
 /* STM32 HAL & SDK Drivers */
 
+/* end of STM32 HAL & SDK Drivers */
 
 /* Kendryte SDK */
 
+/* end of Kendryte SDK */
+/* end of HAL & SDK Drivers */
 
 /* sensors drivers */
 
+/* end of sensors drivers */
 
 /* touch drivers */
 
+/* end of touch drivers */
+/* end of peripheral libraries and drivers */
 
 /* AI packages */
 
+/* end of AI packages */
 
 /* Signal Processing and Control Algorithm Packages */
 
+/* end of Signal Processing and Control Algorithm Packages */
 
 /* miscellaneous packages */
 
 /* project laboratory */
 
+/* end of project laboratory */
+
 /* samples: kernel and components samples */
 
+/* end of samples: kernel and components samples */
 
 /* entertainment: terminal games and other interesting software packages */
 
+/* end of entertainment: terminal games and other interesting software packages */
+/* end of miscellaneous packages */
 
 /* Arduino libraries */
 
 
 /* Projects and Demos */
 
+/* end of Projects and Demos */
 
 /* Sensors */
 
+/* end of Sensors */
 
 /* Display */
 
+/* end of Display */
 
 /* Timing */
 
+/* end of Timing */
 
 /* Data Processing */
 
+/* end of Data Processing */
 
 /* Data Storage */
 
 /* Communication */
 
+/* end of Communication */
 
 /* Device Control */
 
+/* end of Device Control */
 
 /* Other */
 
+/* end of Other */
 
 /* Signal IO */
 
+/* end of Signal IO */
 
 /* Uncategorized */
 
+/* end of Arduino libraries */
+/* end of RT-Thread online packages */
 #define BSP_USING_BL61X
 #define BSP_USING_ROMAPI
 #define BSP_USING_BL61X_MODULE_DEFAULT
@@ -292,5 +367,7 @@
 #define BSP_USING_UART0
 #define UART0_TX_USING_GPIO21
 #define UART0_RX_USING_GPIO22
+/* end of General Purpose UARTs */
+/* end of General Drivers Configuration */
 
 #endif

+ 1518 - 1
bsp/bouffalo_lab/libraries/Kconfig

@@ -1,2 +1,1519 @@
-source "$BSP_DIR/$LIBRARIES_DIR/rt_drivers/Kconfig"
+menu "General Drivers Configuration"
 
+    config BSP_DRIVER_DEBUG
+        bool "Enable Driver Debug Log Output"
+        default n
+
+    menu "General Purpose UARTs"
+    menuconfig BSP_USING_UART0
+        bool "Enable UART0"
+        default y
+        if BSP_USING_UART0
+            choice
+                prompt "UART0 TX PIN"
+                default UART0_TX_USING_GPIO16 if BSP_USING_BL60X
+                default UART0_TX_USING_GPIO21 if BSP_USING_BL61X
+                default UART0_TX_USING_GPIO14 if BSP_USING_BL70X
+                default UART0_TX_USING_GPIO14 if BSP_USING_BL808
+
+                config UART0_TX_USING_GPIO0
+                    bool "GPIO_0"
+                config UART0_TX_USING_GPIO1
+                    bool "GPIO_1"
+                config UART0_TX_USING_GPIO2
+                    bool "GPIO_2"
+                config UART0_TX_USING_GPIO3
+                    bool "GPIO_3"
+                config UART0_TX_USING_GPIO4
+                    bool "GPIO_4"
+                config UART0_TX_USING_GPIO5
+                    bool "GPIO_5"
+                config UART0_TX_USING_GPIO6
+                    bool "GPIO_6"
+                config UART0_TX_USING_GPIO7
+                    bool "GPIO_7"
+                config UART0_TX_USING_GPIO8
+                    bool "GPIO_8"
+                config UART0_TX_USING_GPIO9
+                    bool "GPIO_9"
+                config UART0_TX_USING_GPIO10
+                    bool "GPIO_10"
+                config UART0_TX_USING_GPIO11
+                    bool "GPIO_11"
+                config UART0_TX_USING_GPIO12
+                    bool "GPIO_12"
+                config UART0_TX_USING_GPIO13
+                    bool "GPIO_13"
+                config UART0_TX_USING_GPIO13
+                    bool "GPIO_13"
+                config UART0_TX_USING_GPIO14
+                    bool "GPIO_14"
+                config UART0_TX_USING_GPIO15
+                    bool "GPIO_15"
+                config UART0_TX_USING_GPIO16
+                    bool "GPIO_16"
+                config UART0_TX_USING_GPIO17
+                    bool "GPIO_17"
+                config UART0_TX_USING_GPIO18
+                    bool "GPIO_18"
+                config UART0_TX_USING_GPIO19
+                    bool "GPIO_19"
+                config UART0_TX_USING_GPIO20
+                    bool "GPIO_20"
+                config UART0_TX_USING_GPIO21
+                    bool "GPIO_21"
+                config UART0_TX_USING_GPIO22
+                    bool "GPIO_22"
+                config UART0_TX_USING_GPIO23
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_23"
+                config UART0_TX_USING_GPIO24
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_24"
+                config UART0_TX_USING_GPIO25
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_25"
+                config UART0_TX_USING_GPIO26
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_26"
+                config UART0_TX_USING_GPIO27
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_27"
+                config UART0_TX_USING_GPIO28
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_28"
+                config UART0_TX_USING_GPIO29
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_29"
+                config UART0_TX_USING_GPIO30
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_30"
+                config UART0_TX_USING_GPIO31
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_31"
+                config UART0_TX_USING_GPIO32
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_32"
+                config UART0_TX_USING_GPIO33
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_33"
+                config UART0_TX_USING_GPIO34
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_34"
+                config UART0_TX_USING_GPIO35
+                    depends on BSP_USING_BL808
+                    bool "GPIO_35"
+                config UART0_TX_USING_GPIO36
+                    depends on BSP_USING_BL808
+                    bool "GPIO_36"
+                config UART0_TX_USING_GPIO37
+                    depends on BSP_USING_BL808
+                    bool "GPIO_37"
+                config UART0_TX_USING_GPIO38
+                    depends on BSP_USING_BL808
+                    bool "GPIO_38"
+                config UART0_TX_USING_GPIO39
+                    depends on BSP_USING_BL808
+                    bool "GPIO_39"
+                config UART0_TX_USING_GPIO44
+                    depends on BSP_USING_BL808
+                    bool "GPIO_44"
+                config UART0_TX_USING_GPIO45
+                    depends on BSP_USING_BL808
+                    bool "GPIO_45"
+            endchoice
+
+            choice
+                prompt "UART0 RX PIN"
+                default UART0_RX_USING_GPIO7 if BSP_USING_BL60X
+                default UART0_RX_USING_GPIO22 if BSP_USING_BL61X
+                default UART0_RX_USING_GPIO23 if BSP_USING_BL70X
+                default UART0_RX_USING_GPIO15 if BSP_USING_BL808
+
+                config UART0_RX_USING_GPIO0
+                    bool "GPIO_0"
+                config UART0_RX_USING_GPIO1
+                    bool "GPIO_1"
+                config UART0_RX_USING_GPIO2
+                    bool "GPIO_2"
+                config UART0_RX_USING_GPIO3
+                    bool "GPIO_3"
+                config UART0_RX_USING_GPIO4
+                    bool "GPIO_4"
+                config UART0_RX_USING_GPIO5
+                    bool "GPIO_5"
+                config UART0_RX_USING_GPIO6
+                    bool "GPIO_6"
+                config UART0_RX_USING_GPIO7
+                    bool "GPIO_7"
+                config UART0_RX_USING_GPIO8
+                    bool "GPIO_8"
+                config UART0_RX_USING_GPIO9
+                    bool "GPIO_9"
+                config UART0_RX_USING_GPIO10
+                    bool "GPIO_10"
+                config UART0_RX_USING_GPIO11
+                    bool "GPIO_11"
+                config UART0_RX_USING_GPIO12
+                    bool "GPIO_12"
+                config UART0_RX_USING_GPIO13
+                    bool "GPIO_13"
+                config UART0_RX_USING_GPIO14
+                    bool "GPIO_14"
+                config UART0_RX_USING_GPIO15
+                    bool "GPIO_15"
+                config UART0_RX_USING_GPIO16
+                    bool "GPIO_16"
+                config UART0_RX_USING_GPIO17
+                    bool "GPIO_17"
+                config UART0_RX_USING_GPIO18
+                    bool "GPIO_18"
+                config UART0_RX_USING_GPIO19
+                    bool "GPIO_19"
+                config UART0_RX_USING_GPIO20
+                    bool "GPIO_20"
+                config UART0_RX_USING_GPIO21
+                    bool "GPIO_21"
+                config UART0_RX_USING_GPIO22
+                    bool "GPIO_22"
+                config UART0_RX_USING_GPIO23
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_23"
+                config UART0_RX_USING_GPIO24
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_24"
+                config UART0_RX_USING_GPIO25
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_25"
+                config UART0_RX_USING_GPIO26
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_26"
+                config UART0_RX_USING_GPIO27
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_27"
+                config UART0_RX_USING_GPIO28
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_28"
+                config UART0_RX_USING_GPIO29
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_29"
+                config UART0_RX_USING_GPIO30
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_30"
+                config UART0_RX_USING_GPIO31
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_31"
+                config UART0_RX_USING_GPIO32
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_32"
+                config UART0_RX_USING_GPIO33
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_33"
+                config UART0_RX_USING_GPIO34
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_34"
+                config UART0_RX_USING_GPIO35
+                    depends on BSP_USING_BL808
+                    bool "GPIO_35"
+                config UART0_RX_USING_GPIO36
+                    depends on BSP_USING_BL808
+                    bool "GPIO_36"
+                config UART0_RX_USING_GPIO37
+                    depends on BSP_USING_BL808
+                    bool "GPIO_37"
+                config UART0_RX_USING_GPIO38
+                    depends on BSP_USING_BL808
+                    bool "GPIO_38"
+                config UART0_RX_USING_GPIO39
+                    depends on BSP_USING_BL808
+                    bool "GPIO_39"
+                config UART0_RX_USING_GPIO44
+                    depends on BSP_USING_BL808
+                    bool "GPIO_44"
+                config UART0_RX_USING_GPIO45
+                    depends on BSP_USING_BL808
+                    bool "GPIO_45"
+
+            endchoice
+        endif
+
+    menuconfig BSP_USING_UART1
+        bool "Enable UART1"
+        default n
+        if BSP_USING_UART1
+            choice
+                prompt "UART1 TX PIN"
+                default UART1_TX_USING_GPIO4 if BSP_USING_BL60X
+                default UART1_TX_USING_GPIO16 if BSP_USING_BL61X
+                default UART1_TX_USING_GPIO26 if BSP_USING_BL70X
+                default UART1_TX_USING_GPIO18 if BSP_USING_BL808
+
+                config UART1_TX_USING_GPIO0
+                    bool "GPIO_0"
+                config UART1_TX_USING_GPIO1
+                    bool "GPIO_1"
+                config UART1_TX_USING_GPIO2
+                    bool "GPIO_2"
+                config UART1_TX_USING_GPIO3
+                    bool "GPIO_3"
+                config UART1_TX_USING_GPIO4
+                    bool "GPIO_4"
+                config UART1_TX_USING_GPIO5
+                    bool "GPIO_5"
+                config UART1_TX_USING_GPIO6
+                    bool "GPIO_6"
+                config UART1_TX_USING_GPIO7
+                    bool "GPIO_7"
+                config UART1_TX_USING_GPIO8
+                    bool "GPIO_8"
+                config UART1_TX_USING_GPIO9
+                    bool "GPIO_9"
+                config UART1_TX_USING_GPIO10
+                    bool "GPIO_10"
+                config UART1_TX_USING_GPIO11
+                    bool "GPIO_11"
+                config UART1_TX_USING_GPIO12
+                    bool "GPIO_12"
+                config UART1_TX_USING_GPIO13
+                    bool "GPIO_13"
+                config UART1_TX_USING_GPIO14
+                    bool "GPIO_14"
+                config UART1_TX_USING_GPIO15
+                    bool "GPIO_15"
+                config UART1_TX_USING_GPIO16
+                    bool "GPIO_16"
+                config UART1_TX_USING_GPIO17
+                    bool "GPIO_17"
+                config UART1_TX_USING_GPIO18
+                    bool "GPIO_18"
+                config UART1_TX_USING_GPIO19
+                    bool "GPIO_19"
+                config UART1_TX_USING_GPIO20
+                    bool "GPIO_20"
+                config UART1_TX_USING_GPIO21
+                    bool "GPIO_21"
+                config UART1_TX_USING_GPIO22
+                    bool "GPIO_22"
+                config UART1_TX_USING_GPIO23
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_23"
+                config UART1_TX_USING_GPIO24
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_24"
+                config UART1_TX_USING_GPIO25
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_25"
+                config UART1_TX_USING_GPIO26
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_26"
+                config UART1_TX_USING_GPIO27
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_27"
+                config UART1_TX_USING_GPIO28
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_28"
+                config UART1_TX_USING_GPIO29
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_29"
+                config UART1_TX_USING_GPIO30
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_30"
+                config UART1_TX_USING_GPIO31
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_31"
+                config UART1_TX_USING_GPIO32
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_32"
+                config UART1_TX_USING_GPIO33
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_33"
+                config UART1_TX_USING_GPIO34
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_34"
+                config UART1_TX_USING_GPIO35
+                    depends on BSP_USING_BL808
+                    bool "GPIO_35"
+                config UART1_TX_USING_GPIO36
+                    depends on BSP_USING_BL808
+                    bool "GPIO_36"
+                config UART1_TX_USING_GPIO37
+                    depends on BSP_USING_BL808
+                    bool "GPIO_37"
+                config UART1_TX_USING_GPIO38
+                    depends on BSP_USING_BL808
+                    bool "GPIO_38"
+                config UART1_TX_USING_GPIO39
+                    depends on BSP_USING_BL808
+                    bool "GPIO_39"
+                config UART1_TX_USING_GPIO44
+                    depends on BSP_USING_BL808
+                    bool "GPIO_44"
+                config UART1_TX_USING_GPIO45
+                    depends on BSP_USING_BL808
+                    bool "GPIO_45"
+            endchoice
+
+            choice
+                prompt "UART1 RX PIN"
+                default UART1_RX_USING_GPIO3 if BSP_USING_BL60X
+                default UART1_RX_USING_GPIO17 if BSP_USING_BL61X
+                default UART1_RX_USING_GPIO27 if BSP_USING_BL70X
+                default UART1_RX_USING_GPIO19 if BSP_USING_BL808
+
+                config UART1_RX_USING_GPIO0
+                    bool "GPIO_0"
+                config UART1_RX_USING_GPIO1
+                    bool "GPIO_1"
+                config UART1_RX_USING_GPIO2
+                    bool "GPIO_2"
+                config UART1_RX_USING_GPIO3
+                    bool "GPIO_3"
+                config UART1_RX_USING_GPIO4
+                    bool "GPIO_4"
+                config UART1_RX_USING_GPIO5
+                    bool "GPIO_5"
+                config UART1_RX_USING_GPIO6
+                    bool "GPIO_6"
+                config UART1_RX_USING_GPIO7
+                    bool "GPIO_7"
+                config UART1_RX_USING_GPIO8
+                    bool "GPIO_8"
+                config UART1_RX_USING_GPIO9
+                    bool "GPIO_9"
+                config UART1_RX_USING_GPIO10
+                    bool "GPIO_10"
+                config UART1_RX_USING_GPIO11
+                    bool "GPIO_11"
+                config UART1_RX_USING_GPIO12
+                    bool "GPIO_12"
+                config UART1_RX_USING_GPIO13
+                    bool "GPIO_13"
+                config UART1_RX_USING_GPIO14
+                    bool "GPIO_14"
+                config UART1_RX_USING_GPIO15
+                    bool "GPIO_15"
+                config UART1_RX_USING_GPIO16
+                    bool "GPIO_16"
+                config UART1_RX_USING_GPIO17
+                    bool "GPIO_17"
+                config UART1_RX_USING_GPIO18
+                    bool "GPIO_18"
+                config UART1_RX_USING_GPIO19
+                    bool "GPIO_19"
+                config UART1_RX_USING_GPIO20
+                    bool "GPIO_20"
+                config UART1_RX_USING_GPIO21
+                    bool "GPIO_21"
+                config UART1_RX_USING_GPIO22
+                    bool "GPIO_22"
+                config UART1_RX_USING_GPIO23
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_23"
+                config UART1_RX_USING_GPIO24
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_24"
+                config UART1_RX_USING_GPIO25
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_25"
+                config UART1_RX_USING_GPIO26
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_26"
+                config UART1_RX_USING_GPIO27
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_27"
+                config UART1_RX_USING_GPIO28
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_28"
+                config UART1_RX_USING_GPIO29
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_29"
+                config UART1_RX_USING_GPIO30
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_30"
+                config UART1_RX_USING_GPIO31
+                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_31"
+                config UART1_RX_USING_GPIO32
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_32"
+                config UART1_RX_USING_GPIO33
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_33"
+                config UART1_RX_USING_GPIO34
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_34"
+                config UART1_RX_USING_GPIO35
+                    depends on BSP_USING_BL808
+                    bool "GPIO_35"
+                config UART1_RX_USING_GPIO36
+                    depends on BSP_USING_BL808
+                    bool "GPIO_36"
+                config UART1_RX_USING_GPIO37
+                    depends on BSP_USING_BL808
+                    bool "GPIO_37"
+                config UART1_RX_USING_GPIO38
+                    depends on BSP_USING_BL808
+                    bool "GPIO_38"
+                config UART1_RX_USING_GPIO39
+                    depends on BSP_USING_BL808
+                    bool "GPIO_39"
+                config UART1_RX_USING_GPIO44
+                    depends on BSP_USING_BL808
+                    bool "GPIO_44"
+                config UART1_RX_USING_GPIO45
+                    depends on BSP_USING_BL808
+                    bool "GPIO_45"
+            endchoice
+        endif
+
+    if BSP_USING_BL808
+        menuconfig BSP_USING_UART2
+            bool "Enable UART2"
+            default n
+            if BSP_USING_UART2
+                choice
+                    prompt "UART2 TX PIN"
+                    default UART2_TX_USING_GPIO20
+
+                    config UART2_TX_USING_GPIO0
+                        bool "GPIO_0"
+                    config UART2_TX_USING_GPIO1
+                        bool "GPIO_1"
+                    config UART2_TX_USING_GPIO2
+                        bool "GPIO_2"
+                    config UART2_TX_USING_GPIO3
+                        bool "GPIO_3"
+                    config UART2_TX_USING_GPIO4
+                        bool "GPIO_4"
+                    config UART2_TX_USING_GPIO5
+                        bool "GPIO_5"
+                    config UART2_TX_USING_GPIO6
+                        bool "GPIO_6"
+                    config UART2_TX_USING_GPIO7
+                        bool "GPIO_7"
+                    config UART2_TX_USING_GPIO8
+                        bool "GPIO_8"
+                    config UART2_TX_USING_GPIO9
+                        bool "GPIO_9"
+                    config UART2_TX_USING_GPIO10
+                        bool "GPIO_10"
+                    config UART2_TX_USING_GPIO11
+                        bool "GPIO_11"
+                    config UART2_TX_USING_GPIO12
+                        bool "GPIO_12"
+                    config UART2_TX_USING_GPIO13
+                        bool "GPIO_13"
+                    config UART2_TX_USING_GPIO14
+                        bool "GPIO_14"
+                    config UART2_TX_USING_GPIO15
+                        bool "GPIO_15"
+                    config UART2_TX_USING_GPIO16
+                        bool "GPIO_16"
+                    config UART2_TX_USING_GPIO17
+                        bool "GPIO_17"
+                    config UART2_TX_USING_GPIO18
+                        bool "GPIO_18"
+                    config UART2_TX_USING_GPIO19
+                        bool "GPIO_19"
+                    config UART2_TX_USING_GPIO20
+                        bool "GPIO_20"
+                    config UART2_TX_USING_GPIO21
+                        bool "GPIO_21"
+                    config UART2_TX_USING_GPIO22
+                        bool "GPIO_22"
+                    config UART2_TX_USING_GPIO23
+                        bool "GPIO_23"
+                    config UART2_TX_USING_GPIO24
+                        bool "GPIO_24"
+                    config UART2_TX_USING_GPIO25
+                        bool "GPIO_25"
+                    config UART2_TX_USING_GPIO26
+                        bool "GPIO_26"
+                    config UART2_TX_USING_GPIO27
+                        bool "GPIO_27"
+                    config UART2_TX_USING_GPIO28
+                        bool "GPIO_28"
+                    config UART2_TX_USING_GPIO29
+                        bool "GPIO_29"
+                    config UART2_TX_USING_GPIO30
+                        bool "GPIO_30"
+                    config UART2_TX_USING_GPIO31
+                        bool "GPIO_31"
+                    config UART2_TX_USING_GPIO32
+                        bool "GPIO_32"
+                    config UART2_TX_USING_GPIO33
+                        bool "GPIO_33"
+                    config UART2_TX_USING_GPIO34
+                        bool "GPIO_34"
+                    config UART2_TX_USING_GPIO35
+                        bool "GPIO_35"
+                    config UART2_TX_USING_GPIO36
+                        bool "GPIO_36"
+                    config UART2_TX_USING_GPIO37
+                        bool "GPIO_37"
+                    config UART2_TX_USING_GPIO38
+                        bool "GPIO_38"
+                    config UART2_TX_USING_GPIO39
+                        bool "GPIO_39"
+                    config UART2_TX_USING_GPIO44
+                        bool "GPIO_44"
+                    config UART2_TX_USING_GPIO45
+                        bool "GPIO_45"
+                endchoice
+                choice
+                    prompt "UART2 RX PIN"
+                    default UART2_RX_USING_GPIO21
+
+                    config UART2_RX_USING_GPIO0
+                        bool "GPIO_0"
+                    config UART2_RX_USING_GPIO1
+                        bool "GPIO_1"
+                    config UART2_RX_USING_GPIO2
+                        bool "GPIO_2"
+                    config UART2_RX_USING_GPIO3
+                        bool "GPIO_3"
+                    config UART2_RX_USING_GPIO4
+                        bool "GPIO_4"
+                    config UART2_RX_USING_GPIO5
+                        bool "GPIO_5"
+                    config UART2_RX_USING_GPIO6
+                        bool "GPIO_6"
+                    config UART2_RX_USING_GPIO7
+                        bool "GPIO_7"
+                    config UART2_RX_USING_GPIO8
+                        bool "GPIO_8"
+                    config UART2_RX_USING_GPIO9
+                        bool "GPIO_9"
+                    config UART2_RX_USING_GPIO10
+                        bool "GPIO_10"
+                    config UART2_RX_USING_GPIO11
+                        bool "GPIO_11"
+                    config UART2_RX_USING_GPIO12
+                        bool "GPIO_12"
+                    config UART2_RX_USING_GPIO13
+                        bool "GPIO_13"
+                    config UART2_RX_USING_GPIO13
+                        bool "GPIO_13"
+                    config UART2_RX_USING_GPIO14
+                        bool "GPIO_14"
+                    config UART2_RX_USING_GPIO15
+                        bool "GPIO_15"
+                    config UART2_RX_USING_GPIO16
+                        bool "GPIO_16"
+                    config UART2_RX_USING_GPIO17
+                        bool "GPIO_17"
+                    config UART2_RX_USING_GPIO18
+                        bool "GPIO_18"
+                    config UART2_RX_USING_GPIO19
+                        bool "GPIO_19"
+                    config UART2_RX_USING_GPIO20
+                        bool "GPIO_20"
+                    config UART2_RX_USING_GPIO21
+                        bool "GPIO_21"
+                    config UART2_RX_USING_GPIO22
+                        bool "GPIO_22"
+                    config UART2_RX_USING_GPIO23
+                        bool "GPIO_23"
+                    config UART2_RX_USING_GPIO24
+                        bool "GPIO_24"
+                    config UART2_RX_USING_GPIO25
+                        bool "GPIO_25"
+                    config UART2_RX_USING_GPIO26
+                        bool "GPIO_26"
+                    config UART2_RX_USING_GPIO27
+                        bool "GPIO_27"
+                    config UART2_RX_USING_GPIO28
+                        bool "GPIO_28"
+                    config UART2_RX_USING_GPIO29
+                        bool "GPIO_29"
+                    config UART2_RX_USING_GPIO30
+                        bool "GPIO_30"
+                    config UART2_RX_USING_GPIO31
+                        bool "GPIO_31"
+                    config UART2_RX_USING_GPIO32
+                        bool "GPIO_32"
+                    config UART2_RX_USING_GPIO33
+                        bool "GPIO_33"
+                    config UART2_RX_USING_GPIO34
+                        bool "GPIO_34"
+                    config UART2_RX_USING_GPIO35
+                        bool "GPIO_35"
+                    config UART2_RX_USING_GPIO36
+                        bool "GPIO_36"
+                    config UART2_RX_USING_GPIO37
+                        bool "GPIO_37"
+                    config UART2_RX_USING_GPIO38
+                        bool "GPIO_38"
+                    config UART2_RX_USING_GPIO39
+                        bool "GPIO_39"
+                    config UART2_RX_USING_GPIO44
+                        bool "GPIO_44"
+                    config UART2_RX_USING_GPIO45
+                        bool "GPIO_45"
+                endchoice
+            endif
+        endif
+
+    endmenu
+
+    config BSP_USING_GPIO
+        bool "Enable GPIO"
+        select RT_USING_PIN
+        default n
+
+    config BSP_USING_ADC
+        bool "Enable ADC"
+        select RT_USING_ADC
+        default n
+        if BSP_USING_ADC
+            config BSP_ADC_DMA_CHANNEL
+                string "ADC DMA Channel Name"
+                default "dma0_ch2"
+            config BSP_USING_ADC_CH0
+                bool "USING ADC CH0"
+                default n
+                if BSP_USING_ADC_CH0
+                    config BSP_ADC_CH0_PIN
+                        int "ADC CH0 Pin Num (GPIO_X)"
+                        default 17
+                endif
+            config BSP_USING_ADC_CH1
+                bool "USING ADC CH1"
+                default n
+                if BSP_USING_ADC_CH1
+                    config BSP_ADC_CH1_PIN
+                        int "ADC CH1 Pin Num (GPIO_X)"
+                        default 5
+                endif
+            config BSP_USING_ADC_CH2
+                bool "USING ADC CH2"
+                default n
+                if BSP_USING_ADC_CH2
+                    config BSP_ADC_CH2_PIN
+                        int "ADC CH2 Pin Num (GPIO_X)"
+                        default 4
+                endif
+            config BSP_USING_ADC_CH3
+                bool "USING ADC CH3"
+                default n
+                if BSP_USING_ADC_CH3
+                    config BSP_ADC_CH3_PIN
+                        int "ADC CH3 Pin Num (GPIO_X)"
+                        default 11
+                endif
+            config BSP_USING_ADC_CH4
+                bool "USING ADC CH4"
+                default n
+                if BSP_USING_ADC_CH4
+                    config BSP_ADC_CH4_PIN
+                        int "ADC CH4 Pin Num (GPIO_X)"
+                        default 6
+                endif
+            config BSP_USING_ADC_CH5
+                bool "USING ADC CH5"
+                default n
+                if BSP_USING_ADC_CH5
+                    config BSP_ADC_CH5_PIN
+                        int "ADC CH5 Pin Num (GPIO_X)"
+                        default 40
+                endif
+            config BSP_USING_ADC_CH6
+                bool "USING ADC CH6"
+                default n
+                if BSP_USING_ADC_CH6
+                    config BSP_ADC_CH6_PIN
+                        int "ADC CH6 Pin Num (GPIO_X)"
+                        default 12
+                endif
+            config BSP_USING_ADC_CH7
+                bool "USING ADC CH7"
+                default n
+                if BSP_USING_ADC_CH7
+                    config BSP_ADC_CH7_PIN
+                        int "ADC CH7 Pin Num (GPIO_X)"
+                        default 13
+                endif
+            config BSP_USING_ADC_CH8
+                bool "USING ADC CH8"
+                default n
+                if BSP_USING_ADC_CH8
+                    config BSP_ADC_CH8_PIN
+                        int "ADC CH8 Pin Num (GPIO_X)"
+                        default 16
+                endif
+            config BSP_USING_ADC_CH9
+                bool "USING ADC CH9"
+                default n
+                if BSP_USING_ADC_CH9
+                    config BSP_ADC_CH9_PIN
+                        int "ADC CH9 Pin Num (GPIO_X)"
+                        default 18
+                endif
+            config BSP_USING_ADC_CH10
+                bool "USING ADC CH10"
+                default n
+                if BSP_USING_ADC_CH10
+                    config BSP_ADC_CH10_PIN
+                        int "ADC CH10 Pin Num (GPIO_X)"
+                        default 19
+                endif
+        endif
+
+    config BSP_USING_RTC
+        bool "Enable RTC"
+        select RT_USING_RTC
+        default n
+
+    config BSP_USING_WDT
+        bool "Enable Watchdog Timer"
+        select RT_USING_WDT
+        default n
+
+    menuconfig BSP_USING_PWM
+        bool "Enable PWM"
+        default n
+        select RT_USING_PWM
+        if BSP_USING_PWM
+            config BSP_USING_PWM0
+                bool "Enable PWM0"
+                default n
+
+            config BSP_USING_PWM1
+                bool "Enable PWM1"
+                default n
+
+            config BSP_USING_PWM2
+                bool "Enable PWM2"
+                default n
+
+            config BSP_USING_PWM3
+                bool "Enable PWM3"
+                default n
+        endif
+
+    menuconfig BSP_USING_HWTIMER
+        bool "Enable HWTIMER"
+        default n
+        select RT_USING_HWTIMER
+        if BSP_USING_HWTIMER
+            config BSP_USING_TIMER0
+                bool "Enable TIMER0"
+                default n
+            config BSP_USING_TIMER1
+                bool "Enable TIMER1"
+                default n
+        endif
+
+    menuconfig BSP_USING_I2C
+        bool "Enable I2C BUS"
+        default n
+        select RT_USING_I2C
+        if BSP_USING_I2C
+            config BSP_USING_HW_I2C
+                bool "Enable Hardware I2C BUS"
+                default n
+            if BSP_USING_HW_I2C
+                menuconfig BSP_USING_I2C0
+                    bool "Enable I2C0 (hardware)"
+                    default n
+                    if BSP_USING_I2C0
+                        choice
+                            prompt "I2C0 SCL"
+                            default I2C0_SCL_USING_GPIO14
+
+                            config I2C0_SCL_USING_GPIO0
+                                bool "GPIO_0"
+                            config I2C0_SCL_USING_GPIO2
+                                bool "GPIO_2"
+                            config I2C0_SCL_USING_GPIO4
+                                bool "GPIO_4"
+                            config I2C0_SCL_USING_GPIO6
+                                bool "GPIO_6"
+                            config I2C0_SCL_USING_GPIO8
+                                bool "GPIO_8"
+                            config I2C0_SCL_USING_GPIO10
+                                bool "GPIO_10"
+                            config I2C0_SCL_USING_GPIO12
+                                bool "GPIO_12"
+                            config I2C0_SCL_USING_GPIO14
+                                bool "GPIO_14"
+                            config I2C0_SCL_USING_GPIO16
+                                bool "GPIO_16"
+                            config I2C0_SCL_USING_GPIO18
+                                bool "GPIO_18"
+                            config I2C0_SCL_USING_GPIO20
+                                bool "GPIO_20"
+                            config I2C0_SCL_USING_GPIO22
+                                bool "GPIO_22"
+                            config I2C0_SCL_USING_GPIO24
+                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                                bool "GPIO_8"
+                            config I2C0_SCL_USING_GPIO26
+                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                                bool "GPIO_26"
+                            config I2C0_SCL_USING_GPIO28
+                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                                bool "GPIO_28"
+                            config I2C0_SCL_USING_GPIO30
+                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                                bool "GPIO_30"
+                            config I2C0_SCL_USING_GPIO32
+                                depends on BSP_USING_BL61X || BSP_USING_BL808
+                                bool "GPIO_32"
+                            config I2C0_SCL_USING_GPIO34
+                                depends on BSP_USING_BL61X || BSP_USING_BL808
+                                bool "GPIO_34"
+                            config I2C0_SDA_USING_GPIO36
+                                depends on BSP_USING_BL808
+                                bool "GPIO_36"
+                            config I2C0_SDA_USING_GPIO38
+                                depends on BSP_USING_BL808
+                                bool "GPIO_38"
+                            config I2C0_SDA_USING_GPIO40
+                                depends on BSP_USING_BL808
+                                bool "GPIO_40"
+                            config I2C1_SDA_USING_GPIO42
+                                depends on BSP_USING_BL808
+                                bool "GPIO_42"
+                            config I2C0_SDA_USING_GPIO44
+                                depends on BSP_USING_BL808
+                                bool "GPIO_44"
+                        endchoice
+
+                        choice
+                            prompt "I2C0 SDA"
+                            default I2C0_SDA_USING_GPIO15
+
+                            config I2C0_SDA_USING_GPIO1
+                                bool "GPIO_1"
+                            config I2C0_SDA_USING_GPIO3
+                                bool "GPIO_3"
+                            config I2C0_SDA_USING_GPIO5
+                                bool "GPIO_5"
+                            config I2C0_SDA_USING_GPIO7
+                                bool "GPIO_7"
+                            config I2C0_SDA_USING_GPIO9
+                                bool "GPIO_9"
+                            config I2C0_SDA_USING_GPIO11
+                                bool "GPIO_11"
+                            config I2C0_SDA_USING_GPIO13
+                                bool "GPIO_13"
+                            config I2C0_SDA_USING_GPIO15
+                                bool "GPIO_15"
+                            config I2C0_SDA_USING_GPIO17
+                                bool "GPIO_17"
+                            config I2C0_SDA_USING_GPIO19
+                                bool "GPIO_19"
+                            config I2C0_SDA_USING_GPIO21
+                                bool "GPIO_21"
+                            config I2C0_SDA_USING_GPIO23
+                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                                bool "GPIO_23"
+                            config I2C0_SDA_USING_GPIO25
+                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                                bool "GPIO_25"
+                            config I2C0_SDA_USING_GPIO27
+                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                                bool "GPIO_27"
+                            config I2C0_SDA_USING_GPIO29
+                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                                bool "GPIO_29"
+                            config I2C0_SDA_USING_GPIO31
+                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
+                                bool "GPIO_31"
+                            config I2C0_SDA_USING_GPIO33
+                                depends on BSP_USING_BL61X || BSP_USING_BL808
+                                bool "GPIO_33"
+                            config I2C0_SDA_USING_GPIO35
+                                depends on BSP_USING_BL808
+                                bool "GPIO_35"
+                            config I2C0_SDA_USING_GPIO37
+                                depends on BSP_USING_BL808
+                                bool "GPIO_37"
+                            config I2C0_SDA_USING_GPIO39
+                                depends on BSP_USING_BL808
+                                bool "GPIO_39"
+                            config I2C0_SDA_USING_GPIO41
+                                depends on BSP_USING_BL808
+                                bool "GPIO_41"
+                            config I2C0_SDA_USING_GPIO43
+                                depends on BSP_USING_BL808
+                                bool "GPIO_43"
+                            config I2C0_SDA_USING_GPIO45
+                                depends on BSP_USING_BL808
+                                bool "GPIO_45"
+                            endchoice
+
+                        config I2C0_FREQUENCY
+                            int "I2C0 Frequency"
+                            default 400000
+                    endif
+
+
+                menuconfig BSP_USING_I2C1
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "Enable I2C1 (hardware)"
+                    default n
+                    if BSP_USING_I2C1
+                        choice
+                            prompt "I2C1 SCL"
+                            default I2C1_SCL_USING_GPIO0
+
+                            config I2C1_SCL_USING_GPIO0
+                                bool "GPIO_0"
+                            config I2C1_SCL_USING_GPIO2
+                                bool "GPIO_2"
+                            config I2C1_SCL_USING_GPIO4
+                                bool "GPIO_4"
+                            config I2C1_SCL_USING_GPIO6
+                                bool "GPIO_6"
+                            config I2C1_SCL_USING_GPIO8
+                                bool "GPIO_8"
+                            config I2C1_SCL_USING_GPIO10
+                                bool "GPIO_10"
+                            config I2C1_SCL_USING_GPIO12
+                                bool "GPIO_12"
+                            config I2C1_SCL_USING_GPIO14
+                                bool "GPIO_14"
+                            config I2C1_SCL_USING_GPIO16
+                                bool "GPIO_16"
+                            config I2C1_SCL_USING_GPIO18
+                                bool "GPIO_18"
+                            config I2C1_SCL_USING_GPIO20
+                                bool "GPIO_20"
+                            config I2C1_SCL_USING_GPIO22
+                                bool "GPIO_22"
+                            config I2C1_SCL_USING_GPIO24
+                                bool "GPIO_24"
+                            config I2C1_SCL_USING_GPIO26
+                                bool "GPIO_26"
+                            config I2C1_SCL_USING_GPIO28
+                                bool "GPIO_28"
+                            config I2C1_SCL_USING_GPIO30
+                                bool "GPIO_30"
+                            config I2C1_SCL_USING_GPIO32
+                                bool "GPIO_32"
+                            config I2C1_SCL_USING_GPIO34
+                                bool "GPIO_34"
+                            config I2C1_SDA_USING_GPIO36
+                                depends on BSP_USING_BL808
+                                bool "GPIO_36"
+                            config I2C1_SDA_USING_GPIO38
+                                depends on BSP_USING_BL808
+                                bool "GPIO_38"
+                            config I2C1_SDA_USING_GPIO40
+                                depends on BSP_USING_BL808
+                                bool "GPIO_40"
+                            config I2C1_SDA_USING_GPIO42
+                                depends on BSP_USING_BL808
+                                bool "GPIO_42"
+                            config I2C1_SDA_USING_GPIO44
+                                depends on BSP_USING_BL808
+                                bool "GPIO_44"
+                        endchoice
+
+                        choice
+                            prompt "I2C1 SDA"
+                            default I2C1_SDA_USING_GPIO1
+
+                            config I2C1_SDA_USING_GPIO1
+                                bool "GPIO_1"
+                            config I2C1_SDA_USING_GPIO3
+                                bool "GPIO_3"
+                            config I2C1_SDA_USING_GPIO5
+                                bool "GPIO_5"
+                            config I2C1_SDA_USING_GPIO7
+                                bool "GPIO_7"
+                            config I2C1_SDA_USING_GPIO9
+                                bool "GPIO_9"
+                            config I2C1_SDA_USING_GPIO11
+                                bool "GPIO_11"
+                            config I2C1_SDA_USING_GPIO13
+                                bool "GPIO_13"
+                            config I2C1_SDA_USING_GPIO15
+                                bool "GPIO_15"
+                            config I2C1_SDA_USING_GPIO17
+                                bool "GPIO_17"
+                            config I2C1_SDA_USING_GPIO19
+                                bool "GPIO_19"
+                            config I2C1_SDA_USING_GPIO21
+                                bool "GPIO_21"
+                            config I2C1_SDA_USING_GPIO23
+                                bool "GPIO_23"
+                            config I2C1_SDA_USING_GPIO25
+                                bool "GPIO_25"
+                            config I2C1_SDA_USING_GPIO27
+                                bool "GPIO_27"
+                            config I2C1_SDA_USING_GPIO29
+                                bool "GPIO_29"
+                            config I2C1_SDA_USING_GPIO31
+                                bool "GPIO_31"
+                            config I2C1_SDA_USING_GPIO33
+                                bool "GPIO_33"
+                            config I2C1_SDA_USING_GPIO35
+                                depends on BSP_USING_BL808
+                                bool "GPIO_35"
+                            config I2C1_SDA_USING_GPIO37
+                                depends on BSP_USING_BL808
+                                bool "GPIO_37"
+                            config I2C1_SDA_USING_GPIO39
+                                depends on BSP_USING_BL808
+                                bool "GPIO_39"
+                            config I2C1_SDA_USING_GPIO41
+                                depends on BSP_USING_BL808
+                                bool "GPIO_41"
+                            config I2C1_SDA_USING_GPIO43
+                                depends on BSP_USING_BL808
+                                bool "GPIO_43"
+                            config I2C1_SDA_USING_GPIO45
+                                depends on BSP_USING_BL808
+                                bool "GPIO_45"
+                        endchoice
+
+                        config I2C1_FREQUENCY
+                            int "I2C1 Frequency"
+                            default 400000
+                    endif
+
+            endif
+            if !BSP_USING_HW_I2C
+                menuconfig BSP_USING_SOFT_I2C1
+                    bool "Enable I2C1 BUS (software simulation)"
+                    select RT_USING_I2C_BITOPS
+                    select BSP_USING_GPIO
+                    default n
+                    if BSP_USING_SOFT_I2C1
+                        choice
+                            prompt "I2C1 SCL"
+                            default SOFT_I2C1_SCL_USING_GPIO0
+
+                            config SOFT_I2C1_SCL_USING_GPIO0
+                                bool "GPIO_0"
+                            config SOFT_I2C1_SCL_USING_GPIO2
+                                bool "GPIO_2"
+                            config SOFT_I2C1_SCL_USING_GPIO4
+                                bool "GPIO_4"
+                            config SOFT_I2C1_SCL_USING_GPIO6
+                                bool "GPIO_6"
+                            config SOFT_I2C1_SCL_USING_GPIO8
+                                bool "GPIO_8"
+                            config SOFT_I2C1_SCL_USING_GPIO10
+                                bool "GPIO_10"
+                            config SOFT_I2C1_SCL_USING_GPIO12
+                                bool "GPIO_12"
+                            config SOFT_I2C1_SCL_USING_GPIO14
+                                bool "GPIO_14"
+                            config SOFT_I2C1_SCL_USING_GPIO16
+                                bool "GPIO_16"
+                            config SOFT_I2C1_SCL_USING_GPIO18
+                                bool "GPIO_18"
+                            config SOFT_I2C1_SCL_USING_GPIO20
+                                bool "GPIO_20"
+                            config SOFT_I2C1_SCL_USING_GPIO22
+                                bool "GPIO_22"
+                            config SOFT_I2C1_SCL_USING_GPIO24
+                                bool "GPIO_8"
+                            config SOFT_I2C1_SCL_USING_GPIO26
+                                bool "GPIO_26"
+                            config SOFT_I2C1_SCL_USING_GPIO28
+                                bool "GPIO_28"
+                            config SOFT_I2C1_SCL_USING_GPIO30
+                                bool "GPIO_30"
+                            config SOFT_I2C1_SCL_USING_GPIO32
+                                bool "GPIO_32"
+                            config SOFT_I2C1_SCL_USING_GPIO34
+                                bool "GPIO_34"
+                            config SOFT_I2C1_SDA_USING_GPIO36
+                                depends on BSP_USING_BL808
+                                bool "GPIO_36"
+                            config SOFT_I2C1_SDA_USING_GPIO38
+                                depends on BSP_USING_BL808
+                                bool "GPIO_38"
+                            config SOFT_I2C1_SDA_USING_GPIO40
+                                depends on BSP_USING_BL808
+                                bool "GPIO_40"
+                            config SOFT_I2C1_SDA_USING_GPIO42
+                                depends on BSP_USING_BL808
+                                bool "GPIO_42"
+                            config SOFT_I2C1_SDA_USING_GPIO44
+                                depends on BSP_USING_BL808
+                                bool "GPIO_44"
+                        endchoice
+
+                        choice
+                            prompt "I2C1 SDA"
+                            default SOFT_I2C1_SDA_USING_GPIO1
+
+                            config SOFT_I2C1_SDA_USING_GPIO1
+                                bool "GPIO_1"
+                            config SOFT_I2C1_SDA_USING_GPIO3
+                                bool "GPIO_3"
+                            config SOFT_I2C1_SDA_USING_GPIO5
+                                bool "GPIO_5"
+                            config SOFT_I2C1_SDA_USING_GPIO7
+                                bool "GPIO_7"
+                            config SOFT_I2C1_SDA_USING_GPIO9
+                                bool "GPIO_9"
+                            config SOFT_I2C1_SDA_USING_GPIO11
+                                bool "GPIO_11"
+                            config SOFT_I2C1_SDA_USING_GPIO13
+                                bool "GPIO_13"
+                            config SOFT_I2C1_SDA_USING_GPIO15
+                                bool "GPIO_15"
+                            config SOFT_I2C1_SDA_USING_GPIO17
+                                bool "GPIO_17"
+                            config SOFT_I2C1_SDA_USING_GPIO19
+                                bool "GPIO_19"
+                            config SOFT_I2C1_SDA_USING_GPIO21
+                                bool "GPIO_21"
+                            config SOFT_I2C1_SDA_USING_GPIO23
+                                bool "GPIO_23"
+                            config SOFT_I2C1_SDA_USING_GPIO25
+                                bool "GPIO_25"
+                            config SOFT_I2C1_SDA_USING_GPIO27
+                                bool "GPIO_27"
+                            config SOFT_I2C1_SDA_USING_GPIO29
+                                bool "GPIO_29"
+                            config SOFT_I2C1_SDA_USING_GPIO31
+                                bool "GPIO_31"
+                            config SOFT_I2C1_SDA_USING_GPIO33
+                                bool "GPIO_33"
+                            config SOFT_I2C1_SDA_USING_GPIO35
+                                depends on BSP_USING_BL808
+                                bool "GPIO_35"
+                            config SOFT_I2C1_SDA_USING_GPIO37
+                                depends on BSP_USING_BL808
+                                bool "GPIO_37"
+                            config SOFT_I2C1_SDA_USING_GPIO39
+                                depends on BSP_USING_BL808
+                                bool "GPIO_39"
+                            config SOFT_I2C1_SDA_USING_GPIO41
+                                depends on BSP_USING_BL808
+                                bool "GPIO_41"
+                            config SOFT_I2C1_SDA_USING_GPIO43
+                                depends on BSP_USING_BL808
+                                bool "GPIO_43"
+                            config SOFT_I2C1_SDA_USING_GPIO45
+                                depends on BSP_USING_BL808
+                                bool "GPIO_45"
+                        endchoice
+                    endif
+                endif
+        endif
+
+    menuconfig BSP_USING_SPI
+        bool "Enable SPI"
+        select RT_USING_SPI
+        select RT_USING_PIN
+        default n
+
+        if BSP_USING_SPI
+            choice
+                prompt "SPI SCK PIN"
+                default SPI_SCK_USING_GPIO3 if BSP_USING_BL60X
+                default SPI_SCK_USING_GPIO13 if BSP_USING_BL61X
+                default SPI_SCK_USING_GPIO15 if BSP_USING_BL70X
+                default SPI_SCK_USING_GPIO19 if BSP_USING_BL808
+
+                config SPI_SCK_USING_GPIO1
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_1"
+                config SPI_SCK_USING_GPIO3
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_3"
+                config SPI_SCK_USING_GPIO5
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_5"
+                config SPI_SCK_USING_GPIO7
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_7"
+                config SPI_SCK_USING_GPIO9
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_9"
+                config SPI_SCK_USING_GPIO11
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_11"
+                config SPI_SCK_USING_GPIO13
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_13"
+                config SPI_SCK_USING_GPIO15
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_15"
+                config SPI_SCK_USING_GPIO17
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_17"
+                config SPI_SCK_USING_GPIO19
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_19"
+                config SPI_SCK_USING_GPIO21
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_21"
+                config SPI_SCK_USING_GPIO23
+                    depends on BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_23"
+                config SPI_SCK_USING_GPIO25
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_25"
+                config SPI_SCK_USING_GPIO27
+                    depends on BSP_USING_BL70X || BSP_USING_BL808
+                    bool "GPIO_27"
+                config SPI_SCK_USING_GPIO29
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_29"
+                config SPI_SCK_USING_GPIO31
+                    depends on BSP_USING_BL808
+                    bool "GPIO_31"
+                config SPI_SCK_USING_GPIO33
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_33"
+                config SPI_SCK_USING_GPIO35
+                    depends on BSP_USING_BL808
+                    bool "GPIO_35"
+                config SPI_SCK_USING_GPIO39
+                    depends on BSP_USING_BL808
+                    bool "GPIO_39"
+                config SPI_SCK_USING_GPIO43
+                    depends on BSP_USING_BL808
+                    bool "GPIO_43"
+            endchoice
+
+            choice
+                prompt "SPI MISO PIN"
+                default SPI_MISO_USING_GPIO0 if BSP_USING_BL60X
+                default SPI_MISO_USING_GPIO10 if BSP_USING_BL61X
+                default SPI_MISO_USING_GPIO17 if BSP_USING_BL70X
+                default SPI_MISO_USING_GPIO22 if BSP_USING_BL808
+
+                config SPI_MISO_USING_GPIO0
+                    depends on BSP_USING_BL60X
+                    bool "GPIO_0"
+                config SPI_MISO_USING_GPIO1
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X
+                    bool "GPIO_1"
+                config SPI_MISO_USING_GPIO2
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_2"
+                config SPI_MISO_USING_GPIO4
+                    depends on BSP_USING_BL60X
+                    bool "GPIO_4"
+                config SPI_MISO_USING_GPIO5
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X
+                    bool "GPIO_5"
+                config SPI_MISO_USING_GPIO6
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_6"
+                config SPI_MISO_USING_GPIO8
+                    depends on BSP_USING_BL60X
+                    bool "GPIO_8"
+                config SPI_MISO_USING_GPIO9
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X
+                    bool "GPIO_9"
+                config SPI_MISO_USING_GPIO10
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_10"
+                config SPI_MISO_USING_GPIO12
+                    depends on BSP_USING_BL60X
+                    bool "GPIO_12"
+                config SPI_MISO_USING_GPIO13
+                    depends on BSP_USING_BL60X || BSP_USING_BL60X
+                    bool "GPIO_13"
+                config SPI_MISO_USING_GPIO14
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_14"
+                config SPI_MISO_USING_GPIO16
+                    depends on BSP_USING_BL60X
+                    bool "GPIO_16"
+                config SPI_MISO_USING_GPIO17
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X
+                    bool "GPIO_17"
+                config SPI_MISO_USING_GPIO18
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_18"
+                config SPI_MISO_USING_GPIO20
+                    depends on BSP_USING_BL60X
+                    bool "GPIO_20"
+                config SPI_MISO_USING_GPIO21
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X
+                    bool "GPIO_21"
+                config SPI_MISO_USING_GPIO22
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_22"
+                config SPI_MISO_USING_GPIO25
+                    depends on BSP_USING_BL70X
+                    bool "GPIO_25"
+                config SPI_MISO_USING_GPIO26
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_26"
+                config SPI_MISO_USING_GPIO29
+                    depends on BSP_USING_BL70X
+                    bool "GPIO_29"
+                config SPI_MISO_USING_GPIO30
+                    depends on BSP_USING_BL61X || BSP_USING_BL808
+                    bool "GPIO_30"
+                config SPI_MISO_USING_GPIO34
+                    depends on BSP_USING_BL808
+                    bool "GPIO_34"
+                config SPI_MISO_USING_GPIO38
+                    depends on BSP_USING_BL808
+                    bool "GPIO_38"
+                config SPI_MISO_USING_GPIO42
+                    depends on BSP_USING_BL808
+                    bool "GPIO_42"
+            endchoice
+
+            choice
+                prompt "SPI MOSI PIN"
+                default SPI_MOSI_USING_GPIO1 if BSP_USING_BL60X
+                default SPI_MOSI_USING_GPIO11 if BSP_USING_BL61X
+                default SPI_MOSI_USING_GPIO16 if BSP_USING_BL70X
+                default SPI_MOSI_USING_GPIO21 if BSP_USING_BL808
+
+                config SPI_MOSI_USING_GPIO0
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X
+                    bool "GPIO_0"
+                config SPI_MOSI_USING_GPIO1
+                    depends on BSP_USING_BL60X || BSP_USING_BL808
+                    bool "GPIO_1"
+                config SPI_MOSI_USING_GPIO3
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_3"
+                config SPI_MOSI_USING_GPIO4
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X
+                    bool "GPIO_4"
+                config SPI_MOSI_USING_GPIO5
+                    depends on BSP_USING_BL60X || BSP_USING_BL808
+                    bool "GPIO_5"
+                config SPI_MOSI_USING_GPIO7
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_7"
+                config SPI_MOSI_USING_GPIO8
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X
+                    bool "GPIO_8"
+                config SPI_MOSI_USING_GPIO9
+                    depends on BSP_USING_BL60X || BSP_USING_BL808
+                    bool "GPIO_9"
+                config SPI_MOSI_USING_GPIO11
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_11"
+                config SPI_MOSI_USING_GPIO12
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X
+                    bool "GPIO_12"
+                config SPI_MOSI_USING_GPIO13
+                    depends on BSP_USING_BL60X || BSP_USING_BL808
+                    bool "GPIO_13"
+                config SPI_MOSI_USING_GPIO15
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_15"
+                config SPI_MOSI_USING_GPIO16
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X
+                    bool "GPIO_16"
+                config SPI_MOSI_USING_GPIO17
+                    depends on BSP_USING_BL60X || BSP_USING_BL808
+                    bool "GPIO_17"
+                config SPI_MOSI_USING_GPIO19
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_19"
+                config SPI_MOSI_USING_GPIO20
+                    depends on BSP_USING_BL60X || BSP_USING_BL70X
+                    bool "GPIO_20"
+                config SPI_MOSI_USING_GPIO21
+                    depends on BSP_USING_BL60X || BSP_USING_BL808
+                    bool "GPIO_21"
+                config SPI_MOSI_USING_GPIO23
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_23"
+                config SPI_MOSI_USING_GPIO24
+                    depends on BSP_USING_BL70X
+                    bool "GPIO_24"
+                config SPI_MOSI_USING_GPIO25
+                    depends on BSP_USING_BL808
+                    bool "GPIO_25"
+                config SPI_MOSI_USING_GPIO27
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_27"
+                config SPI_MOSI_USING_GPIO28
+                    depends on BSP_USING_BL70X
+                    bool "GPIO_28"
+                config SPI_MOSI_USING_GPIO29
+                    depends on BSP_USING_BL808
+                    bool "GPIO_29"
+                config SPI_MOSI_USING_GPIO31
+                    depends on BSP_USING_BL61X
+                    bool "GPIO_31"
+                config SPI_MOSI_USING_GPIO33
+                    depends on BSP_USING_BL808
+                    bool "GPIO_33"
+                config SPI_MOSI_USING_GPIO37
+                    depends on BSP_USING_BL808
+                    bool "GPIO_37"
+                config SPI_MOSI_USING_GPIO41
+                    depends on BSP_USING_BL808
+                    bool "GPIO_41"
+                config SPI_MOSI_USING_GPIO45
+                    depends on BSP_USING_BL808
+                    bool "GPIO_45"
+            endchoice
+
+            config BSP_SPI_TX_USING_DMA
+                bool "Enable SPI TX DMA"
+                default n
+                if BSP_SPI_TX_USING_DMA
+                    config BSP_SPI_TX_DMA_CHANNEL
+                        string "SPI TX DMA Channel Name"
+                        default "dma0_ch0"
+
+                    config BSP_SPI_TX_DMA_TIMEOUT
+                        int "SPI TX DMA Timeout(ms)"
+                        default 10
+                        range 5 100
+
+                    config BSP_SPI_TX_DMA_NOCACHE_BUFSIZE
+                        depends on BSP_USING_BL61X || BSP_USING_BL808
+                        int "SPI TX DMA Nocache Buffer Size"
+                        default 512
+                        range 0 4095
+                endif
+
+            config BSP_SPI_RX_USING_DMA
+                bool "Enable SPI RX DMA"
+                default n
+                if BSP_SPI_RX_USING_DMA
+                    config BSP_SPI_RX_DMA_CHANNEL
+                        string "SPI RX DMA Channel Name"
+                        default "dma0_ch1"
+
+                    config BSP_SPI_RX_DMA_TIMEOUT
+                        int "SPI RX DMA Timeout(ms)"
+                        default 10
+                        range 5 100
+
+                    config BSP_SPI_RX_DMA_NOCACHE_BUFSIZE
+                        depends on BSP_USING_BL61X || BSP_USING_BL808
+                        int "SPI RX DMA Nocache Buffer Size"
+                        default 512
+                        range 0 4095
+                endif
+        endif
+
+    menuconfig BSP_USING_ON_CHIP_FLASH
+        bool "Enable On-Chip FLASH"
+        select FAL_DEBUG_CONFIG
+        select FAL_PART_HAS_TABLE_CFG
+        default n
+        if BSP_USING_ON_CHIP_FLASH
+            config BSP_USING_ON_CHIP_FLASH_FS
+                bool "Enable On-Chip FLASH File System"
+                select PKG_USING_LITTLEFS
+                default n
+        endif
+
+    config BSP_USING_SDH
+        depends on BSP_USING_BL61X || BSP_USING_BL808
+        select RT_USING_SDIO
+        select RT_USING_DFS
+        select RT_USING_DFS_ELMFAT
+        select RT_USING_DFS_ROMFS
+        bool "Enable Secure Digital Host Controller(SDH)"
+        default n
+
+endmenu

+ 0 - 1519
bsp/bouffalo_lab/libraries/rt_drivers/Kconfig

@@ -1,1519 +0,0 @@
-menu "General Drivers Configuration"
-
-    config BSP_DRIVER_DEBUG
-        bool "Enable Driver Debug Log Output"
-        default n
-
-    menu "General Purpose UARTs"
-    menuconfig BSP_USING_UART0
-        bool "Enable UART0"
-        default y
-        if BSP_USING_UART0
-            choice
-                prompt "UART0 TX PIN"
-                default UART0_TX_USING_GPIO16 if BSP_USING_BL60X
-                default UART0_TX_USING_GPIO21 if BSP_USING_BL61X
-                default UART0_TX_USING_GPIO14 if BSP_USING_BL70X
-                default UART0_TX_USING_GPIO14 if BSP_USING_BL808
-
-                config UART0_TX_USING_GPIO0
-                    bool "GPIO_0"
-                config UART0_TX_USING_GPIO1
-                    bool "GPIO_1"
-                config UART0_TX_USING_GPIO2
-                    bool "GPIO_2"
-                config UART0_TX_USING_GPIO3
-                    bool "GPIO_3"
-                config UART0_TX_USING_GPIO4
-                    bool "GPIO_4"
-                config UART0_TX_USING_GPIO5
-                    bool "GPIO_5"
-                config UART0_TX_USING_GPIO6
-                    bool "GPIO_6"
-                config UART0_TX_USING_GPIO7
-                    bool "GPIO_7"
-                config UART0_TX_USING_GPIO8
-                    bool "GPIO_8"
-                config UART0_TX_USING_GPIO9
-                    bool "GPIO_9"
-                config UART0_TX_USING_GPIO10
-                    bool "GPIO_10"
-                config UART0_TX_USING_GPIO11
-                    bool "GPIO_11"
-                config UART0_TX_USING_GPIO12
-                    bool "GPIO_12"
-                config UART0_TX_USING_GPIO13
-                    bool "GPIO_13"
-                config UART0_TX_USING_GPIO13
-                    bool "GPIO_13"
-                config UART0_TX_USING_GPIO14
-                    bool "GPIO_14"
-                config UART0_TX_USING_GPIO15
-                    bool "GPIO_15"
-                config UART0_TX_USING_GPIO16
-                    bool "GPIO_16"
-                config UART0_TX_USING_GPIO17
-                    bool "GPIO_17"
-                config UART0_TX_USING_GPIO18
-                    bool "GPIO_18"
-                config UART0_TX_USING_GPIO19
-                    bool "GPIO_19"
-                config UART0_TX_USING_GPIO20
-                    bool "GPIO_20"
-                config UART0_TX_USING_GPIO21
-                    bool "GPIO_21"
-                config UART0_TX_USING_GPIO22
-                    bool "GPIO_22"
-                config UART0_TX_USING_GPIO23
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_23"
-                config UART0_TX_USING_GPIO24
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_24"
-                config UART0_TX_USING_GPIO25
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_25"
-                config UART0_TX_USING_GPIO26
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_26"
-                config UART0_TX_USING_GPIO27
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_27"
-                config UART0_TX_USING_GPIO28
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_28"
-                config UART0_TX_USING_GPIO29
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_29"
-                config UART0_TX_USING_GPIO30
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_30"
-                config UART0_TX_USING_GPIO31
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_31"
-                config UART0_TX_USING_GPIO32
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_32"
-                config UART0_TX_USING_GPIO33
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_33"
-                config UART0_TX_USING_GPIO34
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_34"
-                config UART0_TX_USING_GPIO35
-                    depends on BSP_USING_BL808
-                    bool "GPIO_35"
-                config UART0_TX_USING_GPIO36
-                    depends on BSP_USING_BL808
-                    bool "GPIO_36"
-                config UART0_TX_USING_GPIO37
-                    depends on BSP_USING_BL808
-                    bool "GPIO_37"
-                config UART0_TX_USING_GPIO38
-                    depends on BSP_USING_BL808
-                    bool "GPIO_38"
-                config UART0_TX_USING_GPIO39
-                    depends on BSP_USING_BL808
-                    bool "GPIO_39"
-                config UART0_TX_USING_GPIO44
-                    depends on BSP_USING_BL808
-                    bool "GPIO_44"
-                config UART0_TX_USING_GPIO45
-                    depends on BSP_USING_BL808
-                    bool "GPIO_45"
-            endchoice
-
-            choice
-                prompt "UART0 RX PIN"
-                default UART0_RX_USING_GPIO7 if BSP_USING_BL60X
-                default UART0_RX_USING_GPIO22 if BSP_USING_BL61X
-                default UART0_RX_USING_GPIO23 if BSP_USING_BL70X
-                default UART0_RX_USING_GPIO15 if BSP_USING_BL808
-
-                config UART0_RX_USING_GPIO0
-                    bool "GPIO_0"
-                config UART0_RX_USING_GPIO1
-                    bool "GPIO_1"
-                config UART0_RX_USING_GPIO2
-                    bool "GPIO_2"
-                config UART0_RX_USING_GPIO3
-                    bool "GPIO_3"
-                config UART0_RX_USING_GPIO4
-                    bool "GPIO_4"
-                config UART0_RX_USING_GPIO5
-                    bool "GPIO_5"
-                config UART0_RX_USING_GPIO6
-                    bool "GPIO_6"
-                config UART0_RX_USING_GPIO7
-                    bool "GPIO_7"
-                config UART0_RX_USING_GPIO8
-                    bool "GPIO_8"
-                config UART0_RX_USING_GPIO9
-                    bool "GPIO_9"
-                config UART0_RX_USING_GPIO10
-                    bool "GPIO_10"
-                config UART0_RX_USING_GPIO11
-                    bool "GPIO_11"
-                config UART0_RX_USING_GPIO12
-                    bool "GPIO_12"
-                config UART0_RX_USING_GPIO13
-                    bool "GPIO_13"
-                config UART0_RX_USING_GPIO14
-                    bool "GPIO_14"
-                config UART0_RX_USING_GPIO15
-                    bool "GPIO_15"
-                config UART0_RX_USING_GPIO16
-                    bool "GPIO_16"
-                config UART0_RX_USING_GPIO17
-                    bool "GPIO_17"
-                config UART0_RX_USING_GPIO18
-                    bool "GPIO_18"
-                config UART0_RX_USING_GPIO19
-                    bool "GPIO_19"
-                config UART0_RX_USING_GPIO20
-                    bool "GPIO_20"
-                config UART0_RX_USING_GPIO21
-                    bool "GPIO_21"
-                config UART0_RX_USING_GPIO22
-                    bool "GPIO_22"
-                config UART0_RX_USING_GPIO23
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_23"
-                config UART0_RX_USING_GPIO24
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_24"
-                config UART0_RX_USING_GPIO25
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_25"
-                config UART0_RX_USING_GPIO26
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_26"
-                config UART0_RX_USING_GPIO27
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_27"
-                config UART0_RX_USING_GPIO28
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_28"
-                config UART0_RX_USING_GPIO29
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_29"
-                config UART0_RX_USING_GPIO30
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_30"
-                config UART0_RX_USING_GPIO31
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_31"
-                config UART0_RX_USING_GPIO32
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_32"
-                config UART0_RX_USING_GPIO33
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_33"
-                config UART0_RX_USING_GPIO34
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_34"
-                config UART0_RX_USING_GPIO35
-                    depends on BSP_USING_BL808
-                    bool "GPIO_35"
-                config UART0_RX_USING_GPIO36
-                    depends on BSP_USING_BL808
-                    bool "GPIO_36"
-                config UART0_RX_USING_GPIO37
-                    depends on BSP_USING_BL808
-                    bool "GPIO_37"
-                config UART0_RX_USING_GPIO38
-                    depends on BSP_USING_BL808
-                    bool "GPIO_38"
-                config UART0_RX_USING_GPIO39
-                    depends on BSP_USING_BL808
-                    bool "GPIO_39"
-                config UART0_RX_USING_GPIO44
-                    depends on BSP_USING_BL808
-                    bool "GPIO_44"
-                config UART0_RX_USING_GPIO45
-                    depends on BSP_USING_BL808
-                    bool "GPIO_45"
-
-            endchoice
-        endif
-        
-    menuconfig BSP_USING_UART1
-        bool "Enable UART1"
-        default n
-        if BSP_USING_UART1
-            choice
-                prompt "UART1 TX PIN"
-                default UART1_TX_USING_GPIO4 if BSP_USING_BL60X
-                default UART1_TX_USING_GPIO16 if BSP_USING_BL61X
-                default UART1_TX_USING_GPIO26 if BSP_USING_BL70X
-                default UART1_TX_USING_GPIO18 if BSP_USING_BL808
-
-                config UART1_TX_USING_GPIO0
-                    bool "GPIO_0"
-                config UART1_TX_USING_GPIO1
-                    bool "GPIO_1"
-                config UART1_TX_USING_GPIO2
-                    bool "GPIO_2"
-                config UART1_TX_USING_GPIO3
-                    bool "GPIO_3"
-                config UART1_TX_USING_GPIO4
-                    bool "GPIO_4"
-                config UART1_TX_USING_GPIO5
-                    bool "GPIO_5"
-                config UART1_TX_USING_GPIO6
-                    bool "GPIO_6"
-                config UART1_TX_USING_GPIO7
-                    bool "GPIO_7"
-                config UART1_TX_USING_GPIO8
-                    bool "GPIO_8"
-                config UART1_TX_USING_GPIO9
-                    bool "GPIO_9"
-                config UART1_TX_USING_GPIO10
-                    bool "GPIO_10"
-                config UART1_TX_USING_GPIO11
-                    bool "GPIO_11"
-                config UART1_TX_USING_GPIO12
-                    bool "GPIO_12"
-                config UART1_TX_USING_GPIO13
-                    bool "GPIO_13"
-                config UART1_TX_USING_GPIO14
-                    bool "GPIO_14"
-                config UART1_TX_USING_GPIO15
-                    bool "GPIO_15"
-                config UART1_TX_USING_GPIO16
-                    bool "GPIO_16"
-                config UART1_TX_USING_GPIO17
-                    bool "GPIO_17"
-                config UART1_TX_USING_GPIO18
-                    bool "GPIO_18"
-                config UART1_TX_USING_GPIO19
-                    bool "GPIO_19"
-                config UART1_TX_USING_GPIO20
-                    bool "GPIO_20"
-                config UART1_TX_USING_GPIO21
-                    bool "GPIO_21"
-                config UART1_TX_USING_GPIO22
-                    bool "GPIO_22"
-                config UART1_TX_USING_GPIO23
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_23"
-                config UART1_TX_USING_GPIO24
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_24"
-                config UART1_TX_USING_GPIO25
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_25"
-                config UART1_TX_USING_GPIO26
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_26"
-                config UART1_TX_USING_GPIO27
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_27"
-                config UART1_TX_USING_GPIO28
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_28"
-                config UART1_TX_USING_GPIO29
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_29"
-                config UART1_TX_USING_GPIO30
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_30"
-                config UART1_TX_USING_GPIO31
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_31"
-                config UART1_TX_USING_GPIO32
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_32"
-                config UART1_TX_USING_GPIO33
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_33"
-                config UART1_TX_USING_GPIO34
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_34"
-                config UART1_TX_USING_GPIO35
-                    depends on BSP_USING_BL808
-                    bool "GPIO_35"
-                config UART1_TX_USING_GPIO36
-                    depends on BSP_USING_BL808
-                    bool "GPIO_36"
-                config UART1_TX_USING_GPIO37
-                    depends on BSP_USING_BL808
-                    bool "GPIO_37"
-                config UART1_TX_USING_GPIO38
-                    depends on BSP_USING_BL808
-                    bool "GPIO_38"
-                config UART1_TX_USING_GPIO39
-                    depends on BSP_USING_BL808
-                    bool "GPIO_39"
-                config UART1_TX_USING_GPIO44
-                    depends on BSP_USING_BL808
-                    bool "GPIO_44"
-                config UART1_TX_USING_GPIO45
-                    depends on BSP_USING_BL808
-                    bool "GPIO_45"
-            endchoice
-
-            choice
-                prompt "UART1 RX PIN"
-                default UART1_RX_USING_GPIO3 if BSP_USING_BL60X
-                default UART1_RX_USING_GPIO17 if BSP_USING_BL61X
-                default UART1_RX_USING_GPIO27 if BSP_USING_BL70X
-                default UART1_RX_USING_GPIO19 if BSP_USING_BL808
-
-                config UART1_RX_USING_GPIO0
-                    bool "GPIO_0"
-                config UART1_RX_USING_GPIO1
-                    bool "GPIO_1"
-                config UART1_RX_USING_GPIO2
-                    bool "GPIO_2"
-                config UART1_RX_USING_GPIO3
-                    bool "GPIO_3"
-                config UART1_RX_USING_GPIO4
-                    bool "GPIO_4"
-                config UART1_RX_USING_GPIO5
-                    bool "GPIO_5"
-                config UART1_RX_USING_GPIO6
-                    bool "GPIO_6"
-                config UART1_RX_USING_GPIO7
-                    bool "GPIO_7"
-                config UART1_RX_USING_GPIO8
-                    bool "GPIO_8"
-                config UART1_RX_USING_GPIO9
-                    bool "GPIO_9"
-                config UART1_RX_USING_GPIO10
-                    bool "GPIO_10"
-                config UART1_RX_USING_GPIO11
-                    bool "GPIO_11"
-                config UART1_RX_USING_GPIO12
-                    bool "GPIO_12"
-                config UART1_RX_USING_GPIO13
-                    bool "GPIO_13"
-                config UART1_RX_USING_GPIO14
-                    bool "GPIO_14"
-                config UART1_RX_USING_GPIO15
-                    bool "GPIO_15"
-                config UART1_RX_USING_GPIO16
-                    bool "GPIO_16"
-                config UART1_RX_USING_GPIO17
-                    bool "GPIO_17"
-                config UART1_RX_USING_GPIO18
-                    bool "GPIO_18"
-                config UART1_RX_USING_GPIO19
-                    bool "GPIO_19"
-                config UART1_RX_USING_GPIO20
-                    bool "GPIO_20"
-                config UART1_RX_USING_GPIO21
-                    bool "GPIO_21"
-                config UART1_RX_USING_GPIO22
-                    bool "GPIO_22"
-                config UART1_RX_USING_GPIO23
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_23"
-                config UART1_RX_USING_GPIO24
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_24"
-                config UART1_RX_USING_GPIO25
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_25"
-                config UART1_RX_USING_GPIO26
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_26"
-                config UART1_RX_USING_GPIO27
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_27"
-                config UART1_RX_USING_GPIO28
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_28"
-                config UART1_RX_USING_GPIO29
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_29"
-                config UART1_RX_USING_GPIO30
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_30"
-                config UART1_RX_USING_GPIO31
-                    depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_31"
-                config UART1_RX_USING_GPIO32
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_32"
-                config UART1_RX_USING_GPIO33
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_33"
-                config UART1_RX_USING_GPIO34
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_34"
-                config UART1_RX_USING_GPIO35
-                    depends on BSP_USING_BL808
-                    bool "GPIO_35"                    
-                config UART1_RX_USING_GPIO36
-                    depends on BSP_USING_BL808
-                    bool "GPIO_36"           
-                config UART1_RX_USING_GPIO37
-                    depends on BSP_USING_BL808
-                    bool "GPIO_37"    
-                config UART1_RX_USING_GPIO38
-                    depends on BSP_USING_BL808
-                    bool "GPIO_38"    
-                config UART1_RX_USING_GPIO39
-                    depends on BSP_USING_BL808
-                    bool "GPIO_39"    
-                config UART1_RX_USING_GPIO44
-                    depends on BSP_USING_BL808
-                    bool "GPIO_44"    
-                config UART1_RX_USING_GPIO45
-                    depends on BSP_USING_BL808
-                    bool "GPIO_45"  
-            endchoice
-        endif
-
-    if BSP_USING_BL808
-        menuconfig BSP_USING_UART2
-            bool "Enable UART2"
-            default n
-            if BSP_USING_UART2
-                choice
-                    prompt "UART2 TX PIN"
-                    default UART2_TX_USING_GPIO20
-
-                    config UART2_TX_USING_GPIO0
-                        bool "GPIO_0"
-                    config UART2_TX_USING_GPIO1
-                        bool "GPIO_1"
-                    config UART2_TX_USING_GPIO2
-                        bool "GPIO_2"
-                    config UART2_TX_USING_GPIO3
-                        bool "GPIO_3"
-                    config UART2_TX_USING_GPIO4
-                        bool "GPIO_4"
-                    config UART2_TX_USING_GPIO5
-                        bool "GPIO_5"
-                    config UART2_TX_USING_GPIO6
-                        bool "GPIO_6"
-                    config UART2_TX_USING_GPIO7
-                        bool "GPIO_7"
-                    config UART2_TX_USING_GPIO8
-                        bool "GPIO_8"
-                    config UART2_TX_USING_GPIO9
-                        bool "GPIO_9"
-                    config UART2_TX_USING_GPIO10
-                        bool "GPIO_10"
-                    config UART2_TX_USING_GPIO11
-                        bool "GPIO_11"
-                    config UART2_TX_USING_GPIO12
-                        bool "GPIO_12"
-                    config UART2_TX_USING_GPIO13
-                        bool "GPIO_13"
-                    config UART2_TX_USING_GPIO14
-                        bool "GPIO_14"
-                    config UART2_TX_USING_GPIO15
-                        bool "GPIO_15"
-                    config UART2_TX_USING_GPIO16
-                        bool "GPIO_16"
-                    config UART2_TX_USING_GPIO17
-                        bool "GPIO_17"
-                    config UART2_TX_USING_GPIO18
-                        bool "GPIO_18"
-                    config UART2_TX_USING_GPIO19
-                        bool "GPIO_19"
-                    config UART2_TX_USING_GPIO20
-                        bool "GPIO_20"
-                    config UART2_TX_USING_GPIO21
-                        bool "GPIO_21"
-                    config UART2_TX_USING_GPIO22
-                        bool "GPIO_22"
-                    config UART2_TX_USING_GPIO23
-                        bool "GPIO_23"
-                    config UART2_TX_USING_GPIO24
-                        bool "GPIO_24"
-                    config UART2_TX_USING_GPIO25
-                        bool "GPIO_25"
-                    config UART2_TX_USING_GPIO26
-                        bool "GPIO_26"
-                    config UART2_TX_USING_GPIO27
-                        bool "GPIO_27"
-                    config UART2_TX_USING_GPIO28
-                        bool "GPIO_28"
-                    config UART2_TX_USING_GPIO29
-                        bool "GPIO_29"
-                    config UART2_TX_USING_GPIO30
-                        bool "GPIO_30"
-                    config UART2_TX_USING_GPIO31
-                        bool "GPIO_31"
-                    config UART2_TX_USING_GPIO32
-                        bool "GPIO_32"
-                    config UART2_TX_USING_GPIO33
-                        bool "GPIO_33"
-                    config UART2_TX_USING_GPIO34
-                        bool "GPIO_34"
-                    config UART2_TX_USING_GPIO35
-                        bool "GPIO_35"
-                    config UART2_TX_USING_GPIO36
-                        bool "GPIO_36"
-                    config UART2_TX_USING_GPIO37
-                        bool "GPIO_37"
-                    config UART2_TX_USING_GPIO38
-                        bool "GPIO_38"
-                    config UART2_TX_USING_GPIO39
-                        bool "GPIO_39"
-                    config UART2_TX_USING_GPIO44
-                        bool "GPIO_44"
-                    config UART2_TX_USING_GPIO45
-                        bool "GPIO_45"
-                endchoice
-                choice
-                    prompt "UART2 RX PIN"
-                    default UART2_RX_USING_GPIO21
-
-                    config UART2_RX_USING_GPIO0
-                        bool "GPIO_0"
-                    config UART2_RX_USING_GPIO1
-                        bool "GPIO_1"
-                    config UART2_RX_USING_GPIO2
-                        bool "GPIO_2"
-                    config UART2_RX_USING_GPIO3
-                        bool "GPIO_3"
-                    config UART2_RX_USING_GPIO4
-                        bool "GPIO_4"
-                    config UART2_RX_USING_GPIO5
-                        bool "GPIO_5"
-                    config UART2_RX_USING_GPIO6
-                        bool "GPIO_6"
-                    config UART2_RX_USING_GPIO7
-                        bool "GPIO_7"
-                    config UART2_RX_USING_GPIO8
-                        bool "GPIO_8"
-                    config UART2_RX_USING_GPIO9
-                        bool "GPIO_9"
-                    config UART2_RX_USING_GPIO10
-                        bool "GPIO_10"
-                    config UART2_RX_USING_GPIO11
-                        bool "GPIO_11"
-                    config UART2_RX_USING_GPIO12
-                        bool "GPIO_12"
-                    config UART2_RX_USING_GPIO13
-                        bool "GPIO_13"
-                    config UART2_RX_USING_GPIO13
-                        bool "GPIO_13"
-                    config UART2_RX_USING_GPIO14
-                        bool "GPIO_14"
-                    config UART2_RX_USING_GPIO15
-                        bool "GPIO_15"
-                    config UART2_RX_USING_GPIO16
-                        bool "GPIO_16"
-                    config UART2_RX_USING_GPIO17
-                        bool "GPIO_17"
-                    config UART2_RX_USING_GPIO18
-                        bool "GPIO_18"
-                    config UART2_RX_USING_GPIO19
-                        bool "GPIO_19"
-                    config UART2_RX_USING_GPIO20
-                        bool "GPIO_20"
-                    config UART2_RX_USING_GPIO21
-                        bool "GPIO_21"
-                    config UART2_RX_USING_GPIO22
-                        bool "GPIO_22"
-                    config UART2_RX_USING_GPIO23
-                        bool "GPIO_23"
-                    config UART2_RX_USING_GPIO24
-                        bool "GPIO_24"
-                    config UART2_RX_USING_GPIO25
-                        bool "GPIO_25"
-                    config UART2_RX_USING_GPIO26
-                        bool "GPIO_26"
-                    config UART2_RX_USING_GPIO27
-                        bool "GPIO_27"
-                    config UART2_RX_USING_GPIO28
-                        bool "GPIO_28"
-                    config UART2_RX_USING_GPIO29
-                        bool "GPIO_29"
-                    config UART2_RX_USING_GPIO30
-                        bool "GPIO_30"
-                    config UART2_RX_USING_GPIO31
-                        bool "GPIO_31"
-                    config UART2_RX_USING_GPIO32
-                        bool "GPIO_32"
-                    config UART2_RX_USING_GPIO33
-                        bool "GPIO_33"
-                    config UART2_RX_USING_GPIO34
-                        bool "GPIO_34"
-                    config UART2_RX_USING_GPIO35
-                        bool "GPIO_35"
-                    config UART2_RX_USING_GPIO36
-                        bool "GPIO_36"
-                    config UART2_RX_USING_GPIO37
-                        bool "GPIO_37"
-                    config UART2_RX_USING_GPIO38
-                        bool "GPIO_38"
-                    config UART2_RX_USING_GPIO39
-                        bool "GPIO_39"
-                    config UART2_RX_USING_GPIO44
-                        bool "GPIO_44"
-                    config UART2_RX_USING_GPIO45
-                        bool "GPIO_45"
-                endchoice
-            endif
-        endif
-
-    endmenu
-
-    config BSP_USING_GPIO
-        bool "Enable GPIO"
-        select RT_USING_PIN
-        default n
-
-    config BSP_USING_ADC
-        bool "Enable ADC"
-        select RT_USING_ADC
-        default n
-        if BSP_USING_ADC
-            config BSP_ADC_DMA_CHANNEL
-                string "ADC DMA Channel Name" 
-                default "dma0_ch2"
-            config BSP_USING_ADC_CH0
-                bool "USING ADC CH0"
-                default n
-                if BSP_USING_ADC_CH0
-                    config BSP_ADC_CH0_PIN
-                        int "ADC CH0 Pin Num (GPIO_X)"
-                        default 17
-                endif
-            config BSP_USING_ADC_CH1
-                bool "USING ADC CH1"
-                default n
-                if BSP_USING_ADC_CH1
-                    config BSP_ADC_CH1_PIN
-                        int "ADC CH1 Pin Num (GPIO_X)"
-                        default 5
-                endif
-            config BSP_USING_ADC_CH2
-                bool "USING ADC CH2"
-                default n
-                if BSP_USING_ADC_CH2
-                    config BSP_ADC_CH2_PIN
-                        int "ADC CH2 Pin Num (GPIO_X)"
-                        default 4
-                endif
-            config BSP_USING_ADC_CH3
-                bool "USING ADC CH3"
-                default n
-                if BSP_USING_ADC_CH3
-                    config BSP_ADC_CH3_PIN
-                        int "ADC CH3 Pin Num (GPIO_X)"
-                        default 11
-                endif
-            config BSP_USING_ADC_CH4
-                bool "USING ADC CH4"
-                default n
-                if BSP_USING_ADC_CH4
-                    config BSP_ADC_CH4_PIN
-                        int "ADC CH4 Pin Num (GPIO_X)"
-                        default 6
-                endif
-            config BSP_USING_ADC_CH5
-                bool "USING ADC CH5"
-                default n
-                if BSP_USING_ADC_CH5
-                    config BSP_ADC_CH5_PIN
-                        int "ADC CH5 Pin Num (GPIO_X)"
-                        default 40
-                endif
-            config BSP_USING_ADC_CH6
-                bool "USING ADC CH6"
-                default n
-                if BSP_USING_ADC_CH6
-                    config BSP_ADC_CH6_PIN
-                        int "ADC CH6 Pin Num (GPIO_X)"
-                        default 12
-                endif
-            config BSP_USING_ADC_CH7
-                bool "USING ADC CH7"
-                default n
-                if BSP_USING_ADC_CH7
-                    config BSP_ADC_CH7_PIN
-                        int "ADC CH7 Pin Num (GPIO_X)"
-                        default 13
-                endif
-            config BSP_USING_ADC_CH8
-                bool "USING ADC CH8"
-                default n
-                if BSP_USING_ADC_CH8
-                    config BSP_ADC_CH8_PIN
-                        int "ADC CH8 Pin Num (GPIO_X)"
-                        default 16
-                endif
-            config BSP_USING_ADC_CH9
-                bool "USING ADC CH9"
-                default n
-                if BSP_USING_ADC_CH9
-                    config BSP_ADC_CH9_PIN
-                        int "ADC CH9 Pin Num (GPIO_X)"
-                        default 18
-                endif
-            config BSP_USING_ADC_CH10
-                bool "USING ADC CH10"
-                default n
-                if BSP_USING_ADC_CH10
-                    config BSP_ADC_CH10_PIN
-                        int "ADC CH10 Pin Num (GPIO_X)"
-                        default 19
-                endif
-        endif
-
-    config BSP_USING_RTC
-        bool "Enable RTC"
-        select RT_USING_RTC
-        default n
-
-    config BSP_USING_WDT
-        bool "Enable Watchdog Timer"
-        select RT_USING_WDT
-        default n
-
-    menuconfig BSP_USING_PWM
-        bool "Enable PWM"
-        default n
-        select RT_USING_PWM
-        if BSP_USING_PWM
-            config BSP_USING_PWM0
-                bool "Enable PWM0"
-                default n
-
-            config BSP_USING_PWM1
-                bool "Enable PWM1"
-                default n
-
-            config BSP_USING_PWM2
-                bool "Enable PWM2"
-                default n
-
-            config BSP_USING_PWM3
-                bool "Enable PWM3"
-                default n
-        endif
-
-    menuconfig BSP_USING_HWTIMER
-        bool "Enable HWTIMER"
-        default n
-        select RT_USING_HWTIMER
-        if BSP_USING_HWTIMER
-            config BSP_USING_TIMER0
-                bool "Enable TIMER0"
-                default n
-            config BSP_USING_TIMER1
-                bool "Enable TIMER1"
-                default n
-        endif
-
-    menuconfig BSP_USING_I2C
-        bool "Enable I2C BUS"
-        default n
-        select RT_USING_I2C
-        if BSP_USING_I2C
-            config BSP_USING_HW_I2C
-                bool "Enable Hardware I2C BUS"
-                default n
-            if BSP_USING_HW_I2C
-                menuconfig BSP_USING_I2C0
-                    bool "Enable I2C0 (hardware)"
-                    default n
-                    if BSP_USING_I2C0
-                        choice 
-                            prompt "I2C0 SCL"
-                            default I2C0_SCL_USING_GPIO14
-
-                            config I2C0_SCL_USING_GPIO0
-                                bool "GPIO_0"
-                            config I2C0_SCL_USING_GPIO2
-                                bool "GPIO_2"
-                            config I2C0_SCL_USING_GPIO4
-                                bool "GPIO_4"
-                            config I2C0_SCL_USING_GPIO6
-                                bool "GPIO_6"
-                            config I2C0_SCL_USING_GPIO8
-                                bool "GPIO_8"
-                            config I2C0_SCL_USING_GPIO10
-                                bool "GPIO_10"
-                            config I2C0_SCL_USING_GPIO12
-                                bool "GPIO_12"
-                            config I2C0_SCL_USING_GPIO14
-                                bool "GPIO_14"
-                            config I2C0_SCL_USING_GPIO16
-                                bool "GPIO_16"
-                            config I2C0_SCL_USING_GPIO18
-                                bool "GPIO_18"
-                            config I2C0_SCL_USING_GPIO20
-                                bool "GPIO_20"
-                            config I2C0_SCL_USING_GPIO22
-                                bool "GPIO_22"
-                            config I2C0_SCL_USING_GPIO24
-                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                                bool "GPIO_8"
-                            config I2C0_SCL_USING_GPIO26
-                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                                bool "GPIO_26"
-                            config I2C0_SCL_USING_GPIO28
-                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                                bool "GPIO_28"
-                            config I2C0_SCL_USING_GPIO30
-                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                                bool "GPIO_30"
-                            config I2C0_SCL_USING_GPIO32
-                                depends on BSP_USING_BL61X || BSP_USING_BL808
-                                bool "GPIO_32"
-                            config I2C0_SCL_USING_GPIO34
-                                depends on BSP_USING_BL61X || BSP_USING_BL808
-                                bool "GPIO_34"
-                            config I2C0_SDA_USING_GPIO36
-                                depends on BSP_USING_BL808
-                                bool "GPIO_36"
-                            config I2C0_SDA_USING_GPIO38
-                                depends on BSP_USING_BL808
-                                bool "GPIO_38"
-                            config I2C0_SDA_USING_GPIO40
-                                depends on BSP_USING_BL808
-                                bool "GPIO_40"
-                            config I2C1_SDA_USING_GPIO42
-                                depends on BSP_USING_BL808
-                                bool "GPIO_42"
-                            config I2C0_SDA_USING_GPIO44
-                                depends on BSP_USING_BL808
-                                bool "GPIO_44"
-                        endchoice
-
-                        choice
-                            prompt "I2C0 SDA"
-                            default I2C0_SDA_USING_GPIO15
-
-                            config I2C0_SDA_USING_GPIO1
-                                bool "GPIO_1"
-                            config I2C0_SDA_USING_GPIO3
-                                bool "GPIO_3"
-                            config I2C0_SDA_USING_GPIO5
-                                bool "GPIO_5"
-                            config I2C0_SDA_USING_GPIO7
-                                bool "GPIO_7"
-                            config I2C0_SDA_USING_GPIO9
-                                bool "GPIO_9"
-                            config I2C0_SDA_USING_GPIO11
-                                bool "GPIO_11"
-                            config I2C0_SDA_USING_GPIO13
-                                bool "GPIO_13"
-                            config I2C0_SDA_USING_GPIO15
-                                bool "GPIO_15"
-                            config I2C0_SDA_USING_GPIO17
-                                bool "GPIO_17"
-                            config I2C0_SDA_USING_GPIO19
-                                bool "GPIO_19"
-                            config I2C0_SDA_USING_GPIO21
-                                bool "GPIO_21"
-                            config I2C0_SDA_USING_GPIO23
-                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                                bool "GPIO_23"                        
-                            config I2C0_SDA_USING_GPIO25
-                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                                bool "GPIO_25"
-                            config I2C0_SDA_USING_GPIO27
-                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                                bool "GPIO_27"
-                            config I2C0_SDA_USING_GPIO29
-                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                                bool "GPIO_29"
-                            config I2C0_SDA_USING_GPIO31
-                                depends on BSP_USING_BL61X || BSP_USING_BL70X || BSP_USING_BL808
-                                bool "GPIO_31"
-                            config I2C0_SDA_USING_GPIO33
-                                depends on BSP_USING_BL61X || BSP_USING_BL808
-                                bool "GPIO_33"
-                            config I2C0_SDA_USING_GPIO35
-                                depends on BSP_USING_BL808
-                                bool "GPIO_35"
-                            config I2C0_SDA_USING_GPIO37
-                                depends on BSP_USING_BL808
-                                bool "GPIO_37"
-                            config I2C0_SDA_USING_GPIO39
-                                depends on BSP_USING_BL808
-                                bool "GPIO_39"
-                            config I2C0_SDA_USING_GPIO41
-                                depends on BSP_USING_BL808
-                                bool "GPIO_41"
-                            config I2C0_SDA_USING_GPIO43
-                                depends on BSP_USING_BL808
-                                bool "GPIO_43"
-                            config I2C0_SDA_USING_GPIO45
-                                depends on BSP_USING_BL808
-                                bool "GPIO_45"
-                            endchoice
-
-                        config I2C0_FREQUENCY
-                            int "I2C0 Frequency"
-                            default 400000
-                    endif
-            
-
-                menuconfig BSP_USING_I2C1
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "Enable I2C1 (hardware)"
-                    default n
-                    if BSP_USING_I2C1
-                        choice 
-                            prompt "I2C1 SCL"
-                            default I2C1_SCL_USING_GPIO0
-
-                            config I2C1_SCL_USING_GPIO0
-                                bool "GPIO_0"
-                            config I2C1_SCL_USING_GPIO2
-                                bool "GPIO_2"
-                            config I2C1_SCL_USING_GPIO4
-                                bool "GPIO_4"
-                            config I2C1_SCL_USING_GPIO6
-                                bool "GPIO_6"
-                            config I2C1_SCL_USING_GPIO8
-                                bool "GPIO_8"
-                            config I2C1_SCL_USING_GPIO10
-                                bool "GPIO_10"
-                            config I2C1_SCL_USING_GPIO12
-                                bool "GPIO_12"
-                            config I2C1_SCL_USING_GPIO14
-                                bool "GPIO_14"
-                            config I2C1_SCL_USING_GPIO16
-                                bool "GPIO_16"
-                            config I2C1_SCL_USING_GPIO18
-                                bool "GPIO_18"
-                            config I2C1_SCL_USING_GPIO20
-                                bool "GPIO_20"
-                            config I2C1_SCL_USING_GPIO22
-                                bool "GPIO_22"
-                            config I2C1_SCL_USING_GPIO24
-                                bool "GPIO_24"
-                            config I2C1_SCL_USING_GPIO26
-                                bool "GPIO_26"
-                            config I2C1_SCL_USING_GPIO28
-                                bool "GPIO_28"
-                            config I2C1_SCL_USING_GPIO30
-                                bool "GPIO_30"
-                            config I2C1_SCL_USING_GPIO32
-                                bool "GPIO_32"
-                            config I2C1_SCL_USING_GPIO34
-                                bool "GPIO_34"
-                            config I2C1_SDA_USING_GPIO36
-                                depends on BSP_USING_BL808
-                                bool "GPIO_36"
-                            config I2C1_SDA_USING_GPIO38
-                                depends on BSP_USING_BL808
-                                bool "GPIO_38"
-                            config I2C1_SDA_USING_GPIO40
-                                depends on BSP_USING_BL808
-                                bool "GPIO_40"
-                            config I2C1_SDA_USING_GPIO42
-                                depends on BSP_USING_BL808
-                                bool "GPIO_42"
-                            config I2C1_SDA_USING_GPIO44
-                                depends on BSP_USING_BL808
-                                bool "GPIO_44"
-                        endchoice
-
-                        choice
-                            prompt "I2C1 SDA"
-                            default I2C1_SDA_USING_GPIO1
-
-                            config I2C1_SDA_USING_GPIO1
-                                bool "GPIO_1"
-                            config I2C1_SDA_USING_GPIO3
-                                bool "GPIO_3"
-                            config I2C1_SDA_USING_GPIO5
-                                bool "GPIO_5"
-                            config I2C1_SDA_USING_GPIO7
-                                bool "GPIO_7"
-                            config I2C1_SDA_USING_GPIO9
-                                bool "GPIO_9"
-                            config I2C1_SDA_USING_GPIO11
-                                bool "GPIO_11"
-                            config I2C1_SDA_USING_GPIO13
-                                bool "GPIO_13"
-                            config I2C1_SDA_USING_GPIO15
-                                bool "GPIO_15"
-                            config I2C1_SDA_USING_GPIO17
-                                bool "GPIO_17"
-                            config I2C1_SDA_USING_GPIO19
-                                bool "GPIO_19"
-                            config I2C1_SDA_USING_GPIO21
-                                bool "GPIO_21"
-                            config I2C1_SDA_USING_GPIO23
-                                bool "GPIO_23"                        
-                            config I2C1_SDA_USING_GPIO25
-                                bool "GPIO_25"
-                            config I2C1_SDA_USING_GPIO27
-                                bool "GPIO_27"
-                            config I2C1_SDA_USING_GPIO29
-                                bool "GPIO_29"
-                            config I2C1_SDA_USING_GPIO31
-                                bool "GPIO_31"
-                            config I2C1_SDA_USING_GPIO33
-                                bool "GPIO_33"
-                            config I2C1_SDA_USING_GPIO35
-                                depends on BSP_USING_BL808
-                                bool "GPIO_35"
-                            config I2C1_SDA_USING_GPIO37
-                                depends on BSP_USING_BL808
-                                bool "GPIO_37"
-                            config I2C1_SDA_USING_GPIO39
-                                depends on BSP_USING_BL808
-                                bool "GPIO_39"
-                            config I2C1_SDA_USING_GPIO41
-                                depends on BSP_USING_BL808
-                                bool "GPIO_41"
-                            config I2C1_SDA_USING_GPIO43
-                                depends on BSP_USING_BL808
-                                bool "GPIO_43"
-                            config I2C1_SDA_USING_GPIO45
-                                depends on BSP_USING_BL808
-                                bool "GPIO_45"
-                        endchoice
-
-                        config I2C1_FREQUENCY
-                            int "I2C1 Frequency"
-                            default 400000
-                    endif
-                
-            endif
-            if !BSP_USING_HW_I2C
-                menuconfig BSP_USING_SOFT_I2C1
-                    bool "Enable I2C1 BUS (software simulation)"
-                    select RT_USING_I2C_BITOPS
-                    select BSP_USING_GPIO
-                    default n
-                    if BSP_USING_SOFT_I2C1
-                        choice 
-                            prompt "I2C1 SCL"
-                            default SOFT_I2C1_SCL_USING_GPIO0
-
-                            config SOFT_I2C1_SCL_USING_GPIO0
-                                bool "GPIO_0"
-                            config SOFT_I2C1_SCL_USING_GPIO2
-                                bool "GPIO_2"
-                            config SOFT_I2C1_SCL_USING_GPIO4
-                                bool "GPIO_4"
-                            config SOFT_I2C1_SCL_USING_GPIO6
-                                bool "GPIO_6"
-                            config SOFT_I2C1_SCL_USING_GPIO8
-                                bool "GPIO_8"
-                            config SOFT_I2C1_SCL_USING_GPIO10
-                                bool "GPIO_10"
-                            config SOFT_I2C1_SCL_USING_GPIO12
-                                bool "GPIO_12"
-                            config SOFT_I2C1_SCL_USING_GPIO14
-                                bool "GPIO_14"
-                            config SOFT_I2C1_SCL_USING_GPIO16
-                                bool "GPIO_16"
-                            config SOFT_I2C1_SCL_USING_GPIO18
-                                bool "GPIO_18"
-                            config SOFT_I2C1_SCL_USING_GPIO20
-                                bool "GPIO_20"
-                            config SOFT_I2C1_SCL_USING_GPIO22
-                                bool "GPIO_22"
-                            config SOFT_I2C1_SCL_USING_GPIO24
-                                bool "GPIO_8"
-                            config SOFT_I2C1_SCL_USING_GPIO26
-                                bool "GPIO_26"
-                            config SOFT_I2C1_SCL_USING_GPIO28
-                                bool "GPIO_28"
-                            config SOFT_I2C1_SCL_USING_GPIO30
-                                bool "GPIO_30"
-                            config SOFT_I2C1_SCL_USING_GPIO32
-                                bool "GPIO_32"
-                            config SOFT_I2C1_SCL_USING_GPIO34
-                                bool "GPIO_34"
-                            config SOFT_I2C1_SDA_USING_GPIO36
-                                depends on BSP_USING_BL808
-                                bool "GPIO_36"
-                            config SOFT_I2C1_SDA_USING_GPIO38
-                                depends on BSP_USING_BL808
-                                bool "GPIO_38"
-                            config SOFT_I2C1_SDA_USING_GPIO40
-                                depends on BSP_USING_BL808
-                                bool "GPIO_40"
-                            config SOFT_I2C1_SDA_USING_GPIO42
-                                depends on BSP_USING_BL808
-                                bool "GPIO_42"
-                            config SOFT_I2C1_SDA_USING_GPIO44
-                                depends on BSP_USING_BL808
-                                bool "GPIO_44"
-                        endchoice
-
-                        choice
-                            prompt "I2C1 SDA"
-                            default SOFT_I2C1_SDA_USING_GPIO1
-
-                            config SOFT_I2C1_SDA_USING_GPIO1
-                                bool "GPIO_1"
-                            config SOFT_I2C1_SDA_USING_GPIO3
-                                bool "GPIO_3"
-                            config SOFT_I2C1_SDA_USING_GPIO5
-                                bool "GPIO_5"
-                            config SOFT_I2C1_SDA_USING_GPIO7
-                                bool "GPIO_7"
-                            config SOFT_I2C1_SDA_USING_GPIO9
-                                bool "GPIO_9"
-                            config SOFT_I2C1_SDA_USING_GPIO11
-                                bool "GPIO_11"
-                            config SOFT_I2C1_SDA_USING_GPIO13
-                                bool "GPIO_13"
-                            config SOFT_I2C1_SDA_USING_GPIO15
-                                bool "GPIO_15"
-                            config SOFT_I2C1_SDA_USING_GPIO17
-                                bool "GPIO_17"
-                            config SOFT_I2C1_SDA_USING_GPIO19
-                                bool "GPIO_19"
-                            config SOFT_I2C1_SDA_USING_GPIO21
-                                bool "GPIO_21"
-                            config SOFT_I2C1_SDA_USING_GPIO23
-                                bool "GPIO_23"                        
-                            config SOFT_I2C1_SDA_USING_GPIO25
-                                bool "GPIO_25"
-                            config SOFT_I2C1_SDA_USING_GPIO27
-                                bool "GPIO_27"
-                            config SOFT_I2C1_SDA_USING_GPIO29
-                                bool "GPIO_29"
-                            config SOFT_I2C1_SDA_USING_GPIO31
-                                bool "GPIO_31"
-                            config SOFT_I2C1_SDA_USING_GPIO33
-                                bool "GPIO_33"
-                            config SOFT_I2C1_SDA_USING_GPIO35
-                                depends on BSP_USING_BL808
-                                bool "GPIO_35"
-                            config SOFT_I2C1_SDA_USING_GPIO37
-                                depends on BSP_USING_BL808
-                                bool "GPIO_37"
-                            config SOFT_I2C1_SDA_USING_GPIO39
-                                depends on BSP_USING_BL808
-                                bool "GPIO_39"
-                            config SOFT_I2C1_SDA_USING_GPIO41
-                                depends on BSP_USING_BL808
-                                bool "GPIO_41"
-                            config SOFT_I2C1_SDA_USING_GPIO43
-                                depends on BSP_USING_BL808
-                                bool "GPIO_43"
-                            config SOFT_I2C1_SDA_USING_GPIO45
-                                depends on BSP_USING_BL808
-                                bool "GPIO_45"
-                        endchoice
-                    endif
-                endif
-        endif
-
-    menuconfig BSP_USING_SPI
-        bool "Enable SPI"
-        select RT_USING_SPI
-        select RT_USING_PIN
-        default n
-
-        if BSP_USING_SPI
-            choice
-                prompt "SPI SCK PIN"
-                default SPI_SCK_USING_GPIO3 if BSP_USING_BL60X
-                default SPI_SCK_USING_GPIO13 if BSP_USING_BL61X
-                default SPI_SCK_USING_GPIO15 if BSP_USING_BL70X
-                default SPI_SCK_USING_GPIO19 if BSP_USING_BL808
-
-                config SPI_SCK_USING_GPIO1
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_1"
-                config SPI_SCK_USING_GPIO3
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_3" 
-                config SPI_SCK_USING_GPIO5
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_5"                    
-                config SPI_SCK_USING_GPIO7
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_7"   
-                config SPI_SCK_USING_GPIO9
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_9"   
-                config SPI_SCK_USING_GPIO11
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_11"   
-                config SPI_SCK_USING_GPIO13
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_13"
-                config SPI_SCK_USING_GPIO15
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_15"
-                config SPI_SCK_USING_GPIO17
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_17"
-                config SPI_SCK_USING_GPIO19
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_19"
-                config SPI_SCK_USING_GPIO21
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_21"
-                config SPI_SCK_USING_GPIO23
-                    depends on BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_23"
-                config SPI_SCK_USING_GPIO25
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_25"
-                config SPI_SCK_USING_GPIO27
-                    depends on BSP_USING_BL70X || BSP_USING_BL808
-                    bool "GPIO_27"
-                config SPI_SCK_USING_GPIO29
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_29"
-                config SPI_SCK_USING_GPIO31
-                    depends on BSP_USING_BL808
-                    bool "GPIO_31"
-                config SPI_SCK_USING_GPIO33
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_33"
-                config SPI_SCK_USING_GPIO35
-                    depends on BSP_USING_BL808
-                    bool "GPIO_35"
-                config SPI_SCK_USING_GPIO39
-                    depends on BSP_USING_BL808
-                    bool "GPIO_39"
-                config SPI_SCK_USING_GPIO43
-                    depends on BSP_USING_BL808
-                    bool "GPIO_43"
-            endchoice
-
-            choice
-                prompt "SPI MISO PIN"
-                default SPI_MISO_USING_GPIO0 if BSP_USING_BL60X
-                default SPI_MISO_USING_GPIO10 if BSP_USING_BL61X
-                default SPI_MISO_USING_GPIO17 if BSP_USING_BL70X
-                default SPI_MISO_USING_GPIO22 if BSP_USING_BL808
-
-                config SPI_MISO_USING_GPIO0
-                    depends on BSP_USING_BL60X
-                    bool "GPIO_0"
-                config SPI_MISO_USING_GPIO1
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X
-                    bool "GPIO_1"
-                config SPI_MISO_USING_GPIO2
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_2"
-                config SPI_MISO_USING_GPIO4
-                    depends on BSP_USING_BL60X
-                    bool "GPIO_4"
-                config SPI_MISO_USING_GPIO5
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X
-                    bool "GPIO_5"
-                config SPI_MISO_USING_GPIO6
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_6"
-                config SPI_MISO_USING_GPIO8
-                    depends on BSP_USING_BL60X
-                    bool "GPIO_8"
-                config SPI_MISO_USING_GPIO9
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X
-                    bool "GPIO_9"
-                config SPI_MISO_USING_GPIO10
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_10"
-                config SPI_MISO_USING_GPIO12
-                    depends on BSP_USING_BL60X
-                    bool "GPIO_12"
-                config SPI_MISO_USING_GPIO13
-                    depends on BSP_USING_BL60X || BSP_USING_BL60X
-                    bool "GPIO_13"
-                config SPI_MISO_USING_GPIO14
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_14"
-                config SPI_MISO_USING_GPIO16
-                    depends on BSP_USING_BL60X
-                    bool "GPIO_16"
-                config SPI_MISO_USING_GPIO17
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X
-                    bool "GPIO_17"
-                config SPI_MISO_USING_GPIO18
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_18"
-                config SPI_MISO_USING_GPIO20
-                    depends on BSP_USING_BL60X
-                    bool "GPIO_20"
-                config SPI_MISO_USING_GPIO21
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X
-                    bool "GPIO_21"
-                config SPI_MISO_USING_GPIO22
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_22"
-                config SPI_MISO_USING_GPIO25
-                    depends on BSP_USING_BL70X
-                    bool "GPIO_25"
-                config SPI_MISO_USING_GPIO26
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_26"
-                config SPI_MISO_USING_GPIO29
-                    depends on BSP_USING_BL70X
-                    bool "GPIO_29"
-                config SPI_MISO_USING_GPIO30
-                    depends on BSP_USING_BL61X || BSP_USING_BL808
-                    bool "GPIO_30"
-                config SPI_MISO_USING_GPIO34
-                    depends on BSP_USING_BL808
-                    bool "GPIO_34"
-                config SPI_MISO_USING_GPIO38
-                    depends on BSP_USING_BL808
-                    bool "GPIO_38"
-                config SPI_MISO_USING_GPIO42
-                    depends on BSP_USING_BL808
-                    bool "GPIO_42"
-            endchoice
-
-            choice
-                prompt "SPI MOSI PIN"
-                default SPI_MOSI_USING_GPIO1 if BSP_USING_BL60X
-                default SPI_MOSI_USING_GPIO11 if BSP_USING_BL61X
-                default SPI_MOSI_USING_GPIO16 if BSP_USING_BL70X
-                default SPI_MOSI_USING_GPIO21 if BSP_USING_BL808
-
-                config SPI_MOSI_USING_GPIO0
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X
-                    bool "GPIO_0"
-                config SPI_MOSI_USING_GPIO1
-                    depends on BSP_USING_BL60X || BSP_USING_BL808
-                    bool "GPIO_1"
-                config SPI_MOSI_USING_GPIO3
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_3"
-                config SPI_MOSI_USING_GPIO4
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X
-                    bool "GPIO_4"
-                config SPI_MOSI_USING_GPIO5
-                    depends on BSP_USING_BL60X || BSP_USING_BL808
-                    bool "GPIO_5"
-                config SPI_MOSI_USING_GPIO7
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_7"                    
-                config SPI_MOSI_USING_GPIO8
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X
-                    bool "GPIO_8" 
-                config SPI_MOSI_USING_GPIO9
-                    depends on BSP_USING_BL60X || BSP_USING_BL808
-                    bool "GPIO_9"  
-                config SPI_MOSI_USING_GPIO11
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_11"
-                config SPI_MOSI_USING_GPIO12
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X
-                    bool "GPIO_12"
-                config SPI_MOSI_USING_GPIO13
-                    depends on BSP_USING_BL60X || BSP_USING_BL808
-                    bool "GPIO_13"
-                config SPI_MOSI_USING_GPIO15
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_15"
-                config SPI_MOSI_USING_GPIO16
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X
-                    bool "GPIO_16"
-                config SPI_MOSI_USING_GPIO17
-                    depends on BSP_USING_BL60X || BSP_USING_BL808
-                    bool "GPIO_17"
-                config SPI_MOSI_USING_GPIO19
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_19"
-                config SPI_MOSI_USING_GPIO20
-                    depends on BSP_USING_BL60X || BSP_USING_BL70X
-                    bool "GPIO_20"
-                config SPI_MOSI_USING_GPIO21
-                    depends on BSP_USING_BL60X || BSP_USING_BL808
-                    bool "GPIO_21"
-                config SPI_MOSI_USING_GPIO23
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_23"
-                config SPI_MOSI_USING_GPIO24
-                    depends on BSP_USING_BL70X
-                    bool "GPIO_24"
-                config SPI_MOSI_USING_GPIO25
-                    depends on BSP_USING_BL808
-                    bool "GPIO_25"
-                config SPI_MOSI_USING_GPIO27
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_27"
-                config SPI_MOSI_USING_GPIO28
-                    depends on BSP_USING_BL70X
-                    bool "GPIO_28"
-                config SPI_MOSI_USING_GPIO29
-                    depends on BSP_USING_BL808
-                    bool "GPIO_29"
-                config SPI_MOSI_USING_GPIO31
-                    depends on BSP_USING_BL61X
-                    bool "GPIO_31"
-                config SPI_MOSI_USING_GPIO33
-                    depends on BSP_USING_BL808
-                    bool "GPIO_33"
-                config SPI_MOSI_USING_GPIO37
-                    depends on BSP_USING_BL808
-                    bool "GPIO_37"
-                config SPI_MOSI_USING_GPIO41
-                    depends on BSP_USING_BL808
-                    bool "GPIO_41"
-                config SPI_MOSI_USING_GPIO45
-                    depends on BSP_USING_BL808
-                    bool "GPIO_45"
-            endchoice
-
-            config BSP_SPI_TX_USING_DMA
-                bool "Enable SPI TX DMA"
-                default n
-                if BSP_SPI_TX_USING_DMA
-                    config BSP_SPI_TX_DMA_CHANNEL
-                        string "SPI TX DMA Channel Name" 
-                        default "dma0_ch0"
-                        
-                    config BSP_SPI_TX_DMA_TIMEOUT
-                        int "SPI TX DMA Timeout(ms)"
-                        default 10
-                        range 5 100
-
-                    config BSP_SPI_TX_DMA_NOCACHE_BUFSIZE 
-                        depends on BSP_USING_BL61X || BSP_USING_BL808
-                        int "SPI TX DMA Nocache Buffer Size"
-                        default 512
-                        range 0 4095
-                endif
-
-            config BSP_SPI_RX_USING_DMA
-                bool "Enable SPI RX DMA"
-                default n
-                if BSP_SPI_RX_USING_DMA
-                    config BSP_SPI_RX_DMA_CHANNEL
-                        string "SPI RX DMA Channel Name" 
-                        default "dma0_ch1"
-
-                    config BSP_SPI_RX_DMA_TIMEOUT
-                        int "SPI RX DMA Timeout(ms)"
-                        default 10
-                        range 5 100
-
-                    config BSP_SPI_RX_DMA_NOCACHE_BUFSIZE 
-                        depends on BSP_USING_BL61X || BSP_USING_BL808
-                        int "SPI RX DMA Nocache Buffer Size"
-                        default 512
-                        range 0 4095
-                endif
-        endif
-
-    menuconfig BSP_USING_ON_CHIP_FLASH
-        bool "Enable On-Chip FLASH"
-        select FAL_DEBUG_CONFIG
-        select FAL_PART_HAS_TABLE_CFG
-        default n
-        if BSP_USING_ON_CHIP_FLASH
-            config BSP_USING_ON_CHIP_FLASH_FS
-                bool "Enable On-Chip FLASH File System"
-                select PKG_USING_LITTLEFS
-                default n
-        endif
-
-    config BSP_USING_SDH
-        depends on BSP_USING_BL61X || BSP_USING_BL808
-        select RT_USING_SDIO
-        select RT_USING_DFS
-        select RT_USING_DFS_ELMFAT
-        select RT_USING_DFS_ROMFS
-        bool "Enable Secure Digital Host Controller(SDH)"
-        default n
-
-endmenu

+ 261 - 32
bsp/hpmicro/hpm6750evk2/.config

@@ -1,7 +1,3 @@
-#
-# Automatically generated file; DO NOT EDIT.
-# RT-Thread Configuration
-#
 
 #
 # RT-Thread Kernel
@@ -24,18 +20,25 @@ CONFIG_RT_HOOK_USING_FUNC_PTR=y
 # CONFIG_RT_USING_HOOKLIST is not set
 CONFIG_RT_USING_IDLE_HOOK=y
 CONFIG_RT_IDLE_HOOK_LIST_SIZE=4
-CONFIG_IDLE_THREAD_STACK_SIZE=512
+CONFIG_IDLE_THREAD_STACK_SIZE=2048
 CONFIG_RT_USING_TIMER_SOFT=y
 CONFIG_RT_TIMER_THREAD_PRIO=4
-CONFIG_RT_TIMER_THREAD_STACK_SIZE=512
+CONFIG_RT_TIMER_THREAD_STACK_SIZE=2048
 
 #
 # kservice optimization
 #
-# CONFIG_RT_KSERVICE_USING_STDLIB is not set
-# CONFIG_RT_KSERVICE_USING_TINY_SIZE is not set
 # CONFIG_RT_USING_TINY_FFS is not set
-# CONFIG_RT_KPRINTF_USING_LONGLONG is not set
+# end of kservice optimization
+
+#
+# klibc optimization
+#
+# CONFIG_RT_KLIBC_USING_STDLIB is not set
+# CONFIG_RT_KLIBC_USING_TINY_SIZE is not set
+# CONFIG_RT_KLIBC_USING_PRINTF_LONGLONG is not set
+# end of klibc optimization
+
 # CONFIG_RT_USING_DEBUG is not set
 
 #
@@ -48,6 +51,7 @@ CONFIG_RT_USING_MAILBOX=y
 CONFIG_RT_USING_MESSAGEQUEUE=y
 # CONFIG_RT_USING_MESSAGEQUEUE_PRIORITY is not set
 # CONFIG_RT_USING_SIGNALS is not set
+# end of Inter-Thread communication
 
 #
 # Memory Management
@@ -64,6 +68,8 @@ CONFIG_RT_USING_SMALL_MEM_AS_HEAP=y
 # CONFIG_RT_USING_MEMTRACE is not set
 # CONFIG_RT_USING_HEAP_ISR is not set
 CONFIG_RT_USING_HEAP=y
+# end of Memory Management
+
 CONFIG_RT_USING_DEVICE=y
 # CONFIG_RT_USING_DEVICE_OPS is not set
 # CONFIG_RT_USING_INTERRUPT_INFO is not set
@@ -72,14 +78,10 @@ CONFIG_RT_USING_DEVICE=y
 CONFIG_RT_USING_CONSOLE=y
 CONFIG_RT_CONSOLEBUF_SIZE=128
 CONFIG_RT_CONSOLE_DEVICE_NAME="uart0"
-CONFIG_RT_VER_NUM=0x50100
+CONFIG_RT_VER_NUM=0x50200
 # CONFIG_RT_USING_STDC_ATOMIC is not set
 CONFIG_RT_BACKTRACE_LEVEL_MAX_NR=32
-# CONFIG_RT_USING_CACHE is not set
-# CONFIG_RT_USING_HW_ATOMIC is not set
-# CONFIG_ARCH_ARM_BOOTWITH_FLUSH_CACHE is not set
-# CONFIG_ARCH_CPU_STACK_GROWS_UPWARD is not set
-# CONFIG_RT_USING_CPU_FFS is not set
+# end of RT-Thread Kernel
 
 #
 # RT-Thread Components
@@ -109,7 +111,25 @@ CONFIG_FINSH_USING_OPTION_COMPLETION=y
 #
 # DFS: device virtual file system
 #
-# CONFIG_RT_USING_DFS is not set
+CONFIG_RT_USING_DFS=y
+CONFIG_DFS_USING_POSIX=y
+CONFIG_DFS_USING_WORKDIR=y
+# CONFIG_RT_USING_DFS_MNTTABLE is not set
+CONFIG_DFS_FD_MAX=16
+CONFIG_RT_USING_DFS_V1=y
+# CONFIG_RT_USING_DFS_V2 is not set
+CONFIG_DFS_FILESYSTEMS_MAX=4
+CONFIG_DFS_FILESYSTEM_TYPES_MAX=4
+# CONFIG_RT_USING_DFS_ELMFAT is not set
+CONFIG_RT_USING_DFS_DEVFS=y
+# CONFIG_RT_USING_DFS_ROMFS is not set
+# CONFIG_RT_USING_DFS_CROMFS is not set
+# CONFIG_RT_USING_DFS_RAMFS is not set
+# CONFIG_RT_USING_DFS_TMPFS is not set
+# CONFIG_RT_USING_DFS_MQUEUE is not set
+# CONFIG_RT_USING_DFS_NFS is not set
+# end of DFS: device virtual file system
+
 # CONFIG_RT_USING_FAL is not set
 
 #
@@ -118,7 +138,9 @@ CONFIG_FINSH_USING_OPTION_COMPLETION=y
 # CONFIG_RT_USING_DM is not set
 CONFIG_RT_USING_DEVICE_IPC=y
 CONFIG_RT_UNAMED_PIPE_NUMBER=64
-# CONFIG_RT_USING_SYSTEM_WORKQUEUE is not set
+CONFIG_RT_USING_SYSTEM_WORKQUEUE=y
+CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=2048
+CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23
 CONFIG_RT_USING_SERIAL=y
 CONFIG_RT_USING_SERIAL_V1=y
 # CONFIG_RT_USING_SERIAL_V2 is not set
@@ -156,13 +178,43 @@ CONFIG_RT_USING_RTC=y
 CONFIG_RT_USING_PIN=y
 # CONFIG_RT_USING_KTIME is not set
 # CONFIG_RT_USING_HWTIMER is not set
-
-#
-# Using USB
-#
-# CONFIG_RT_USING_USB is not set
-# CONFIG_RT_USING_USB_HOST is not set
-# CONFIG_RT_USING_USB_DEVICE is not set
+CONFIG_RT_USING_CHERRYUSB=y
+# CONFIG_RT_CHERRYUSB_DEVICE is not set
+CONFIG_RT_CHERRYUSB_HOST=y
+# CONFIG_RT_CHERRYUSB_HOST_CUSTOM is not set
+# CONFIG_RT_CHERRYUSB_HOST_EHCI_BL is not set
+CONFIG_RT_CHERRYUSB_HOST_EHCI_HPM=y
+# CONFIG_RT_CHERRYUSB_HOST_EHCI_AIC is not set
+# CONFIG_RT_CHERRYUSB_HOST_EHCI_NUVOTON_NUC980 is not set
+# CONFIG_RT_CHERRYUSB_HOST_EHCI_NUVOTON_MA35D0 is not set
+# CONFIG_RT_CHERRYUSB_HOST_EHCI_CUSTOM is not set
+# CONFIG_RT_CHERRYUSB_HOST_DWC2_ST is not set
+# CONFIG_RT_CHERRYUSB_HOST_DWC2_ESP is not set
+# CONFIG_RT_CHERRYUSB_HOST_DWC2_CUSTOM is not set
+# CONFIG_RT_CHERRYUSB_HOST_MUSB_STANDARD is not set
+# CONFIG_RT_CHERRYUSB_HOST_MUSB_SUNXI is not set
+# CONFIG_RT_CHERRYUSB_HOST_MUSB_CUSTOM is not set
+# CONFIG_RT_CHERRYUSB_HOST_PUSB2 is not set
+# CONFIG_RT_CHERRYUSB_HOST_XHCI is not set
+CONFIG_RT_CHERRYUSB_HOST_CDC_ACM=y
+CONFIG_RT_CHERRYUSB_HOST_HID=y
+# CONFIG_RT_CHERRYUSB_HOST_MSC is not set
+# CONFIG_RT_CHERRYUSB_HOST_CDC_RNDIS is not set
+# CONFIG_RT_CHERRYUSB_HOST_CDC_ECM is not set
+# CONFIG_RT_CHERRYUSB_HOST_CDC_NCM is not set
+# CONFIG_RT_CHERRYUSB_HOST_VIDEO is not set
+# CONFIG_RT_CHERRYUSB_HOST_AUDIO is not set
+# CONFIG_RT_CHERRYUSB_HOST_BLUETOOTH is not set
+# CONFIG_RT_CHERRYUSB_HOST_ASIX is not set
+# CONFIG_RT_CHERRYUSB_HOST_RTL8152 is not set
+# CONFIG_RT_CHERRYUSB_HOST_FTDI is not set
+# CONFIG_RT_CHERRYUSB_HOST_CH34X is not set
+# CONFIG_RT_CHERRYUSB_HOST_CP210X is not set
+# CONFIG_RT_CHERRYUSB_HOST_PL2303 is not set
+CONFIG_RT_CHERRYUSB_HOST_TEMPLATE=y
+CONFIG_TEST_USBH_CDC_ACM=1
+CONFIG_TEST_USBH_HID=1
+# end of Device Drivers
 
 #
 # C/C++ and POSIX layer
@@ -180,11 +232,23 @@ CONFIG_RT_LIBC_USING_LIGHT_TZ_DST=y
 CONFIG_RT_LIBC_TZ_DEFAULT_HOUR=8
 CONFIG_RT_LIBC_TZ_DEFAULT_MIN=0
 CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
+# end of Timezone and Daylight Saving Time
+# end of ISO-ANSI C layer
 
 #
 # POSIX (Portable Operating System Interface) layer
 #
-# CONFIG_RT_USING_POSIX_FS is not set
+CONFIG_RT_USING_POSIX_FS=y
+# CONFIG_RT_USING_POSIX_DEVIO is not set
+# CONFIG_RT_USING_POSIX_STDIO is not set
+CONFIG_RT_USING_POSIX_POLL=y
+CONFIG_RT_USING_POSIX_SELECT=y
+# CONFIG_RT_USING_POSIX_EVENTFD is not set
+# CONFIG_RT_USING_POSIX_TIMERFD is not set
+CONFIG_RT_USING_POSIX_SOCKET=y
+# CONFIG_RT_USING_POSIX_TERMIOS is not set
+# CONFIG_RT_USING_POSIX_AIO is not set
+# CONFIG_RT_USING_POSIX_MMAN is not set
 # CONFIG_RT_USING_POSIX_DELAY is not set
 # CONFIG_RT_USING_POSIX_CLOCK is not set
 # CONFIG_RT_USING_POSIX_TIMER is not set
@@ -201,21 +265,105 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 #
 # Socket is in the 'Network' category
 #
+# end of Interprocess Communication (IPC)
+# end of POSIX (Portable Operating System Interface) layer
+
 # CONFIG_RT_USING_CPLUSPLUS is not set
+# end of C/C++ and POSIX layer
 
 #
 # Network
 #
-# CONFIG_RT_USING_SAL is not set
-# CONFIG_RT_USING_NETDEV is not set
-# CONFIG_RT_USING_LWIP is not set
+CONFIG_RT_USING_SAL=y
+CONFIG_SAL_INTERNET_CHECK=y
+
+#
+# Docking with protocol stacks
+#
+CONFIG_SAL_USING_LWIP=y
+# CONFIG_SAL_USING_AT is not set
+# CONFIG_SAL_USING_TLS is not set
+# end of Docking with protocol stacks
+
+CONFIG_SAL_USING_POSIX=y
+CONFIG_RT_USING_NETDEV=y
+CONFIG_NETDEV_USING_IFCONFIG=y
+CONFIG_NETDEV_USING_PING=y
+CONFIG_NETDEV_USING_NETSTAT=y
+CONFIG_NETDEV_USING_AUTO_DEFAULT=y
+# CONFIG_NETDEV_USING_IPV6 is not set
+CONFIG_NETDEV_IPV4=1
+CONFIG_NETDEV_IPV6=0
+CONFIG_RT_USING_LWIP=y
+# CONFIG_RT_USING_LWIP_LOCAL_VERSION is not set
+# CONFIG_RT_USING_LWIP141 is not set
+# CONFIG_RT_USING_LWIP203 is not set
+CONFIG_RT_USING_LWIP212=y
+# CONFIG_RT_USING_LWIP_LATEST is not set
+CONFIG_RT_USING_LWIP_VER_NUM=0x20102
+# CONFIG_RT_USING_LWIP_IPV6 is not set
+CONFIG_RT_LWIP_MEM_ALIGNMENT=4
+CONFIG_RT_LWIP_IGMP=y
+CONFIG_RT_LWIP_ICMP=y
+# CONFIG_RT_LWIP_SNMP is not set
+CONFIG_RT_LWIP_DNS=y
+CONFIG_RT_LWIP_DHCP=y
+CONFIG_IP_SOF_BROADCAST=1
+CONFIG_IP_SOF_BROADCAST_RECV=1
+
+#
+# Static IPv4 Address
+#
+CONFIG_RT_LWIP_IPADDR="192.168.1.30"
+CONFIG_RT_LWIP_GWADDR="192.168.1.1"
+CONFIG_RT_LWIP_MSKADDR="255.255.255.0"
+# end of Static IPv4 Address
+
+CONFIG_RT_LWIP_UDP=y
+CONFIG_RT_LWIP_TCP=y
+CONFIG_RT_LWIP_RAW=y
+# CONFIG_RT_LWIP_PPP is not set
+CONFIG_RT_MEMP_NUM_NETCONN=8
+CONFIG_RT_LWIP_PBUF_NUM=16
+CONFIG_RT_LWIP_RAW_PCB_NUM=4
+CONFIG_RT_LWIP_UDP_PCB_NUM=4
+CONFIG_RT_LWIP_TCP_PCB_NUM=4
+CONFIG_RT_LWIP_TCP_SEG_NUM=40
+CONFIG_RT_LWIP_TCP_SND_BUF=8196
+CONFIG_RT_LWIP_TCP_WND=8196
+CONFIG_RT_LWIP_TCPTHREAD_PRIORITY=10
+CONFIG_RT_LWIP_TCPTHREAD_MBOX_SIZE=8
+CONFIG_RT_LWIP_TCPTHREAD_STACKSIZE=1024
+CONFIG_LWIP_NO_RX_THREAD=y
+# CONFIG_LWIP_NO_TX_THREAD is not set
+CONFIG_RT_LWIP_ETHTHREAD_PRIORITY=12
+CONFIG_RT_LWIP_ETHTHREAD_STACKSIZE=1024
+CONFIG_RT_LWIP_ETHTHREAD_MBOX_SIZE=8
+# CONFIG_RT_LWIP_REASSEMBLY_FRAG is not set
+CONFIG_LWIP_NETIF_STATUS_CALLBACK=1
+CONFIG_LWIP_NETIF_LINK_CALLBACK=1
+CONFIG_RT_LWIP_NETIF_NAMESIZE=6
+CONFIG_SO_REUSE=1
+CONFIG_LWIP_SO_RCVTIMEO=1
+CONFIG_LWIP_SO_SNDTIMEO=1
+CONFIG_LWIP_SO_RCVBUF=1
+CONFIG_LWIP_SO_LINGER=0
+# CONFIG_RT_LWIP_NETIF_LOOPBACK is not set
+CONFIG_LWIP_NETIF_LOOPBACK=0
+# CONFIG_RT_LWIP_STATS is not set
+# CONFIG_RT_LWIP_USING_HW_CHECKSUM is not set
+CONFIG_RT_LWIP_USING_PING=y
+# CONFIG_LWIP_USING_DHCPD is not set
+# CONFIG_RT_LWIP_DEBUG is not set
 # CONFIG_RT_USING_AT is not set
+# end of Network
 
 #
 # Memory protection
 #
 # CONFIG_RT_USING_MEM_PROTECTION is not set
 # CONFIG_RT_USING_HW_STACK_GUARD is not set
+# end of Memory protection
 
 #
 # Utilities
@@ -227,12 +375,23 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_RT_USING_RESOURCE_ID is not set
 # CONFIG_RT_USING_ADT is not set
 # CONFIG_RT_USING_RT_LINK is not set
+# end of Utilities
+
 # CONFIG_RT_USING_VBUS is not set
 
+#
+# Using USB legacy version
+#
+# CONFIG_RT_USING_USB_HOST is not set
+# CONFIG_RT_USING_USB_DEVICE is not set
+# end of Using USB legacy version
+# end of RT-Thread Components
+
 #
 # RT-Thread Utestcases
 #
 # CONFIG_RT_USING_UTESTCASES is not set
+# end of RT-Thread Utestcases
 
 #
 # RT-Thread online packages
@@ -241,7 +400,6 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 #
 # IoT - internet of things
 #
-# CONFIG_PKG_USING_LWIP is not set
 # CONFIG_PKG_USING_LORAWAN_DRIVER is not set
 # CONFIG_PKG_USING_PAHOMQTT is not set
 # CONFIG_PKG_USING_UMQTT is not set
@@ -263,30 +421,50 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # Marvell WiFi
 #
 # CONFIG_PKG_USING_WLANMARVELL is not set
+# end of Marvell WiFi
 
 #
 # Wiced WiFi
 #
 # CONFIG_PKG_USING_WLAN_WICED is not set
+# end of Wiced WiFi
+
 # CONFIG_PKG_USING_RW007 is not set
 
 #
 # CYW43012 WiFi
 #
 # CONFIG_PKG_USING_WLAN_CYW43012 is not set
+# end of CYW43012 WiFi
 
 #
 # BL808 WiFi
 #
 # CONFIG_PKG_USING_WLAN_BL808 is not set
+# end of BL808 WiFi
 
 #
 # CYW43439 WiFi
 #
 # CONFIG_PKG_USING_WLAN_CYW43439 is not set
+# end of CYW43439 WiFi
+# end of Wi-Fi
+
 # CONFIG_PKG_USING_COAP is not set
 # CONFIG_PKG_USING_NOPOLL is not set
-# CONFIG_PKG_USING_NETUTILS is not set
+CONFIG_PKG_USING_NETUTILS=y
+CONFIG_PKG_NETUTILS_PATH="/packages/iot/netutils"
+# CONFIG_PKG_NETUTILS_TFTP is not set
+CONFIG_PKG_NETUTILS_IPERF=y
+CONFIG_IPERF_THREAD_STACK_SIZE=2048
+# CONFIG_PKG_NETUTILS_NETIO is not set
+# CONFIG_PKG_NETUTILS_NTP is not set
+# CONFIG_PKG_NETUTILS_TELNET is not set
+# CONFIG_PKG_NETUTILS_TCPDUMP is not set
+CONFIG_PKG_USING_NETUTILS_LATEST_VERSION=y
+# CONFIG_PKG_USING_NETUTILS_V133 is not set
+CONFIG_PKG_NETUTILS_VER="latest"
+CONFIG_PKG_NETUTILS_VER_NUM=0x99999
 # CONFIG_PKG_USING_CMUX is not set
 # CONFIG_PKG_USING_PPP_DEVICE is not set
 # CONFIG_PKG_USING_AT_DEVICE is not set
@@ -306,6 +484,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_UCLOUD_IOT_SDK is not set
 # CONFIG_PKG_USING_JOYLINK is not set
 # CONFIG_PKG_USING_IOTSHARP_SDK is not set
+# end of IoT Cloud
+
 # CONFIG_PKG_USING_NIMBLE is not set
 # CONFIG_PKG_USING_LLSYNC_SDK_ADAPTER is not set
 # CONFIG_PKG_USING_OTA_DOWNLOADER is not set
@@ -348,6 +528,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ZEPHYR_POLLING is not set
 # CONFIG_PKG_USING_MATTER_ADAPTATION_LAYER is not set
 # CONFIG_PKG_USING_LHC_MODBUS is not set
+# CONFIG_PKG_USING_QMODBUS is not set
+# end of IoT - internet of things
 
 #
 # security packages
@@ -358,6 +540,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_TINYCRYPT is not set
 # CONFIG_PKG_USING_TFM is not set
 # CONFIG_PKG_USING_YD_CRYPTO is not set
+# end of security packages
 
 #
 # language packages
@@ -373,18 +556,22 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_JSMN is not set
 # CONFIG_PKG_USING_AGILE_JSMN is not set
 # CONFIG_PKG_USING_PARSON is not set
+# end of JSON: JavaScript Object Notation, a lightweight data-interchange format
 
 #
 # XML: Extensible Markup Language
 #
 # CONFIG_PKG_USING_SIMPLE_XML is not set
 # CONFIG_PKG_USING_EZXML is not set
+# end of XML: Extensible Markup Language
+
 # CONFIG_PKG_USING_LUATOS_SOC is not set
 # CONFIG_PKG_USING_LUA is not set
 # CONFIG_PKG_USING_JERRYSCRIPT is not set
 # CONFIG_PKG_USING_MICROPYTHON is not set
 # CONFIG_PKG_USING_PIKASCRIPT is not set
 # CONFIG_PKG_USING_RTT_RUST is not set
+# end of language packages
 
 #
 # multimedia packages
@@ -396,12 +583,15 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_LVGL is not set
 # CONFIG_PKG_USING_LV_MUSIC_DEMO is not set
 # CONFIG_PKG_USING_GUI_GUIDER_DEMO is not set
+# end of LVGL: powerful and easy-to-use embedded GUI library
 
 #
 # u8g2: a monochrome graphic library
 #
 # CONFIG_PKG_USING_U8G2_OFFICIAL is not set
 # CONFIG_PKG_USING_U8G2 is not set
+# end of u8g2: a monochrome graphic library
+
 # CONFIG_PKG_USING_OPENMV is not set
 # CONFIG_PKG_USING_MUPDF is not set
 # CONFIG_PKG_USING_STEMWIN is not set
@@ -421,6 +611,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_QRCODE is not set
 # CONFIG_PKG_USING_GUIENGINE is not set
 # CONFIG_PKG_USING_3GPP_AMRNB is not set
+# end of multimedia packages
 
 #
 # tools packages
@@ -469,6 +660,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARMV7M_DWT_TOOL is not set
 # CONFIG_PKG_USING_VOFA_PLUS is not set
 # CONFIG_PKG_USING_ZDEBUG is not set
+# end of tools packages
 
 #
 # system packages
@@ -480,6 +672,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_RT_MEMCPY_CM is not set
 # CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
 # CONFIG_PKG_USING_RT_VSNPRINTF_FULL is not set
+# end of enhanced kernel services
 
 #
 # acceleration: Assembly language or algorithmic acceleration packages
@@ -487,6 +680,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_QFPLIB_M0_FULL is not set
 # CONFIG_PKG_USING_QFPLIB_M0_TINY is not set
 # CONFIG_PKG_USING_QFPLIB_M3 is not set
+# end of acceleration: Assembly language or algorithmic acceleration packages
 
 #
 # CMSIS: ARM Cortex-M Microcontroller Software Interface Standard
@@ -497,6 +691,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_CMSIS_NN is not set
 # CONFIG_PKG_USING_CMSIS_RTOS1 is not set
 # CONFIG_PKG_USING_CMSIS_RTOS2 is not set
+# end of CMSIS: ARM Cortex-M Microcontroller Software Interface Standard
 
 #
 # Micrium: Micrium software products porting for RT-Thread
@@ -507,6 +702,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_UC_CLK is not set
 # CONFIG_PKG_USING_UC_COMMON is not set
 # CONFIG_PKG_USING_UC_MODBUS is not set
+# end of Micrium: Micrium software products porting for RT-Thread
+
 # CONFIG_PKG_USING_FREERTOS_WRAPPER is not set
 # CONFIG_PKG_USING_LITEOS_SDK is not set
 # CONFIG_PKG_USING_TZ_DATABASE is not set
@@ -554,6 +751,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_RTP is not set
 # CONFIG_PKG_USING_REB is not set
 # CONFIG_PKG_USING_R_RHEALSTONE is not set
+# end of system packages
 
 #
 # peripheral libraries and drivers
@@ -566,9 +764,12 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 #
 # STM32 HAL & SDK Drivers
 #
-# CONFIG_PKG_USING_STM32L4XX_HAL_DRIVER is not set
+# CONFIG_PKG_USING_STM32L4_HAL_DRIVER is not set
+# CONFIG_PKG_USING_STM32L4_CMSIS_DRIVER is not set
 # CONFIG_PKG_USING_STM32WB55_SDK is not set
 # CONFIG_PKG_USING_STM32_SDIO is not set
+# end of STM32 HAL & SDK Drivers
+
 # CONFIG_PKG_USING_BLUETRUM_SDK is not set
 # CONFIG_PKG_USING_EMBARC_BSP is not set
 # CONFIG_PKG_USING_ESP_IDF is not set
@@ -578,9 +779,12 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 #
 # CONFIG_PKG_USING_K210_SDK is not set
 # CONFIG_PKG_USING_KENDRYTE_SDK is not set
+# end of Kendryte SDK
+
 # CONFIG_PKG_USING_NRF5X_SDK is not set
 # CONFIG_PKG_USING_NRFX is not set
 # CONFIG_PKG_USING_RASPBERRYPI_PICO_SDK is not set
+# end of HAL & SDK Drivers
 
 #
 # sensors drivers
@@ -650,6 +854,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ICM20608 is not set
 # CONFIG_PKG_USING_PAJ7620 is not set
 # CONFIG_PKG_USING_STHS34PF80 is not set
+# end of sensors drivers
 
 #
 # touch drivers
@@ -664,6 +869,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_XPT2046_TOUCH is not set
 # CONFIG_PKG_USING_CST816X is not set
 # CONFIG_PKG_USING_CST812T is not set
+# end of touch drivers
+
 # CONFIG_PKG_USING_REALTEK_AMEBA is not set
 # CONFIG_PKG_USING_BUTTON is not set
 # CONFIG_PKG_USING_PCF8574 is not set
@@ -736,6 +943,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_BT_MX01 is not set
 # CONFIG_PKG_USING_RGPOWER is not set
 # CONFIG_PKG_USING_SPI_TOOLS is not set
+# end of peripheral libraries and drivers
 
 #
 # AI packages
@@ -750,6 +958,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_QUEST is not set
 # CONFIG_PKG_USING_NAXOS is not set
 # CONFIG_PKG_USING_R_TINYMAIX is not set
+# end of AI packages
 
 #
 # Signal Processing and Control Algorithm Packages
@@ -759,6 +968,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_UKAL is not set
 # CONFIG_PKG_USING_DIGITALCTRL is not set
 # CONFIG_PKG_USING_KISSFFT is not set
+# end of Signal Processing and Control Algorithm Packages
 
 #
 # miscellaneous packages
@@ -767,6 +977,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 #
 # project laboratory
 #
+# end of project laboratory
 
 #
 # samples: kernel and components samples
@@ -775,6 +986,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_FILESYSTEM_SAMPLES is not set
 # CONFIG_PKG_USING_NETWORK_SAMPLES is not set
 # CONFIG_PKG_USING_PERIPHERAL_SAMPLES is not set
+# end of samples: kernel and components samples
 
 #
 # entertainment: terminal games and other interesting software packages
@@ -790,6 +1002,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_DONUT is not set
 # CONFIG_PKG_USING_COWSAY is not set
 # CONFIG_PKG_USING_MORSE is not set
+# end of entertainment: terminal games and other interesting software packages
+
 # CONFIG_PKG_USING_LIBCSV is not set
 # CONFIG_PKG_USING_OPTPARSE is not set
 # CONFIG_PKG_USING_FASTLZ is not set
@@ -823,6 +1037,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_SOEM is not set
 # CONFIG_PKG_USING_QPARAM is not set
 # CONFIG_PKG_USING_CorevMCU_CLI is not set
+# end of miscellaneous packages
 
 #
 # Arduino libraries
@@ -838,6 +1053,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_NINEINONE_SENSOR_SHIELD is not set
 # CONFIG_PKG_USING_ARDUINO_SENSOR_KIT is not set
 # CONFIG_PKG_USING_ARDUINO_MATLAB_SUPPORT is not set
+# end of Projects and Demos
 
 #
 # Sensors
@@ -977,6 +1193,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_SEEED_LTC2941 is not set
 # CONFIG_PKG_USING_ARDUINO_SEEED_LDC1612 is not set
 # CONFIG_PKG_USING_ARDUINO_CAPACITIVESENSOR is not set
+# CONFIG_PKG_USING_ARDUINO_JARZEBSKI_MPU6050 is not set
+# end of Sensors
 
 #
 # Display
@@ -988,6 +1206,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SSD1306 is not set
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_ILI9341 is not set
 # CONFIG_PKG_USING_SEEED_TM1637 is not set
+# end of Display
 
 #
 # Timing
@@ -996,6 +1215,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_MSTIMER2 is not set
 # CONFIG_PKG_USING_ARDUINO_TICKER is not set
 # CONFIG_PKG_USING_ARDUINO_TASKSCHEDULER is not set
+# end of Timing
 
 #
 # Data Processing
@@ -1003,6 +1223,8 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_KALMANFILTER is not set
 # CONFIG_PKG_USING_ARDUINO_ARDUINOJSON is not set
 # CONFIG_PKG_USING_ARDUINO_TENSORFLOW_LITE_MICRO is not set
+# CONFIG_PKG_USING_ARDUINO_RUNNINGMEDIAN is not set
+# end of Data Processing
 
 #
 # Data Storage
@@ -1013,6 +1235,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 #
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_PN532 is not set
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI4713 is not set
+# end of Communication
 
 #
 # Device Control
@@ -1024,12 +1247,14 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DS1841 is not set
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_DS3502 is not set
 # CONFIG_PKG_USING_ARDUINO_SEEED_PCF85063TP is not set
+# end of Device Control
 
 #
 # Other
 #
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MFRC630 is not set
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_SI5351 is not set
+# end of Other
 
 #
 # Signal IO
@@ -1042,16 +1267,18 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP3008 is not set
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_MCP4725 is not set
 # CONFIG_PKG_USING_ARDUINO_ADAFRUIT_BD3491FS is not set
+# end of Signal IO
 
 #
 # Uncategorized
 #
+# end of Arduino libraries
+# end of RT-Thread online packages
 
 #
 # Hardware Drivers Config
 #
 CONFIG_SOC_HPM6000=y
-# CONFIG_BSP_USING_ENET_PHY_RTL8201 is not set
 
 #
 # On-chip Peripheral Drivers
@@ -1083,3 +1310,5 @@ CONFIG_BSP_USING_RTC=y
 # CONFIG_BSP_USING_WDG is not set
 # CONFIG_BSP_USING_CAN is not set
 # CONFIG_BSP_USING_ADC is not set
+# end of On-chip Peripheral Drivers
+# end of Hardware Drivers Config

+ 14 - 0
bsp/hpmicro/hpm6750evk2/board/cherryusb_port.c

@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2024/04/23     sakumisu    first version
+ */
+#include <rtthread.h>
+
+/* low level init here, this has implemented in cherryusb */
+
+/* low level deinit here, this has implemented in cherryusb */

+ 6 - 0
bsp/hpmicro/hpm6750evk2/board/linker_scripts/flash_rtt.ld

@@ -111,6 +111,12 @@ SECTIONS
         KEEP (*(.fini))
         . = ALIGN(8);
 
+        /* section information for usbh class */
+        . = ALIGN(8);
+        __usbh_class_info_start__ = .;
+        KEEP(*(.usbh_class_info))
+        __usbh_class_info_end__ = .;
+
         /*********************************************
          *
          *      RT-Thread related sections - Start

+ 267 - 0
bsp/hpmicro/hpm6750evk2/board/usb_config.h

@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef CHERRYUSB_CONFIG_H
+#define CHERRYUSB_CONFIG_H
+
+#define CHERRYUSB_VERSION     0x010300
+#define CHERRYUSB_VERSION_STR "v1.3.0"
+
+/* ================ USB common Configuration ================ */
+
+#include <rtthread.h>
+#include "hpm_soc_feature.h"
+
+#define CONFIG_USB_PRINTF(...) rt_kprintf(__VA_ARGS__)
+
+#define usb_malloc(size) rt_malloc(size)
+#define usb_free(ptr)    rt_free(ptr)
+
+#define memcpy rt_memcpy
+
+#ifndef CONFIG_USB_DBG_LEVEL
+#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
+#endif
+
+/* Enable print with color */
+#define CONFIG_USB_PRINTF_COLOR_ENABLE
+
+/* data align size when use dma */
+#ifndef CONFIG_USB_ALIGN_SIZE
+#define CONFIG_USB_ALIGN_SIZE 4
+#endif
+
+/* attribute data into no cache ram */
+#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
+
+/* ================= USB Device Stack Configuration ================ */
+
+/* Ep0 in and out transfer buffer */
+#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
+#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
+#endif
+
+/* Setup packet log for debug */
+// #define CONFIG_USBDEV_SETUP_LOG_PRINT
+
+/* Send ep0 in data from user buffer instead of copying into ep0 reqdata
+ * Please note that user buffer must be aligned with CONFIG_USB_ALIGN_SIZE
+*/
+// #define CONFIG_USBDEV_EP0_INDATA_NO_COPY
+
+/* Check if the input descriptor is correct */
+// #define CONFIG_USBDEV_DESC_CHECK
+
+/* Enable test mode */
+// #define CONFIG_USBDEV_TEST_MODE
+
+#ifndef CONFIG_USBDEV_MSC_MAX_LUN
+#define CONFIG_USBDEV_MSC_MAX_LUN 1
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
+#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
+#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
+#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
+#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
+#endif
+
+// #define CONFIG_USBDEV_MSC_THREAD
+
+#ifndef CONFIG_USBDEV_MSC_PRIO
+#define CONFIG_USBDEV_MSC_PRIO 4
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_STACKSIZE
+#define CONFIG_USBDEV_MSC_STACKSIZE 2048
+#endif
+
+#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
+#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
+#endif
+
+/* rndis transfer buffer size, must be a multiple of (1536 + 44)*/
+#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
+#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
+#endif
+
+#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID
+#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff
+#endif
+
+#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC
+#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB"
+#endif
+
+#define CONFIG_USBDEV_RNDIS_USING_LWIP
+
+/* ================ USB HOST Stack Configuration ================== */
+
+#define CONFIG_USBHOST_MAX_RHPORTS          1
+#define CONFIG_USBHOST_MAX_EXTHUBS          1
+#define CONFIG_USBHOST_MAX_EHPORTS          4
+#define CONFIG_USBHOST_MAX_INTERFACES       8
+#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
+#define CONFIG_USBHOST_MAX_ENDPOINTS        4
+
+#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
+#define CONFIG_USBHOST_MAX_HID_CLASS     4
+#define CONFIG_USBHOST_MAX_MSC_CLASS     2
+#define CONFIG_USBHOST_MAX_AUDIO_CLASS   1
+#define CONFIG_USBHOST_MAX_VIDEO_CLASS   1
+
+#define CONFIG_USBHOST_DEV_NAMELEN 16
+
+#ifndef CONFIG_USBHOST_PSC_PRIO
+#define CONFIG_USBHOST_PSC_PRIO 0
+#endif
+#ifndef CONFIG_USBHOST_PSC_STACKSIZE
+#define CONFIG_USBHOST_PSC_STACKSIZE 2048
+#endif
+
+//#define CONFIG_USBHOST_GET_STRING_DESC
+
+// #define CONFIG_USBHOST_MSOS_ENABLE
+#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE
+#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
+#endif
+
+/* Ep0 max transfer buffer */
+#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN
+#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512
+#endif
+
+#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
+#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
+#endif
+
+#ifndef CONFIG_USBHOST_MSC_TIMEOUT
+#define CONFIG_USBHOST_MSC_TIMEOUT 5000
+#endif
+
+/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
+ * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
+ */
+#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE
+#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048)
+#endif
+
+/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
+#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE
+#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
+#endif
+
+/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
+ * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
+ */
+#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE
+#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE (2048)
+#endif
+/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
+#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE
+#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE (2048)
+#endif
+
+/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
+ * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
+ */
+#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE
+#define CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE (2048)
+#endif
+/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
+#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE
+#define CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE (2048)
+#endif
+
+#define CONFIG_USBHOST_BLUETOOTH_HCI_H4
+// #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG
+
+#ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE
+#define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048
+#endif
+#ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE
+#define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048
+#endif
+
+/* ================ USB Device Port Configuration ================*/
+
+#ifndef CONFIG_USBDEV_MAX_BUS
+#define CONFIG_USBDEV_MAX_BUS USB_SOC_MAX_COUNT // for now, bus num must be 1 except hpm ip
+#endif
+
+#ifndef CONFIG_USBDEV_EP_NUM
+#define CONFIG_USBDEV_EP_NUM USB_SOC_DCD_MAX_ENDPOINT_COUNT
+#endif
+
+/* ---------------- FSDEV Configuration ---------------- */
+//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
+
+/* ---------------- DWC2 Configuration ---------------- */
+// #define CONFIG_USB_DWC2_RXALL_FIFO_SIZE (1024 / 4)
+// #define CONFIG_USB_DWC2_TX0_FIFO_SIZE (64 / 4)
+// #define CONFIG_USB_DWC2_TX1_FIFO_SIZE (512 / 4)
+// #define CONFIG_USB_DWC2_TX2_FIFO_SIZE (64 / 4)
+// #define CONFIG_USB_DWC2_TX3_FIFO_SIZE (64 / 4)
+// #define CONFIG_USB_DWC2_TX4_FIFO_SIZE (0 / 4)
+// #define CONFIG_USB_DWC2_TX5_FIFO_SIZE (0 / 4)
+// #define CONFIG_USB_DWC2_TX6_FIFO_SIZE (0 / 4)
+// #define CONFIG_USB_DWC2_TX7_FIFO_SIZE (0 / 4)
+// #define CONFIG_USB_DWC2_TX8_FIFO_SIZE (0 / 4)
+
+/* ---------------- MUSB Configuration ---------------- */
+// #define CONFIG_USB_MUSB_SUNXI
+
+/* ================ USB Host Port Configuration ==================*/
+#ifndef CONFIG_USBHOST_MAX_BUS
+#define CONFIG_USBHOST_MAX_BUS USB_SOC_MAX_COUNT
+#endif
+
+#ifndef CONFIG_USBHOST_PIPE_NUM
+#define CONFIG_USBHOST_PIPE_NUM 10
+#endif
+
+/* ---------------- EHCI Configuration ---------------- */
+
+#define CONFIG_USB_EHCI_HCCR_OFFSET     (0x100)
+#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
+#define CONFIG_USB_EHCI_QH_NUM          CONFIG_USBHOST_PIPE_NUM
+#define CONFIG_USB_EHCI_QTD_NUM         3
+#define CONFIG_USB_EHCI_ITD_NUM         20
+// #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
+// #define CONFIG_USB_EHCI_CONFIGFLAG
+// #define CONFIG_USB_EHCI_ISO
+// #define CONFIG_USB_EHCI_WITH_OHCI
+
+/* ---------------- OHCI Configuration ---------------- */
+#define CONFIG_USB_OHCI_HCOR_OFFSET (0x0)
+
+/* ---------------- XHCI Configuration ---------------- */
+#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
+
+/* ---------------- DWC2 Configuration ---------------- */
+/* largest non-periodic USB packet used / 4 */
+// #define CONFIG_USB_DWC2_NPTX_FIFO_SIZE (512 / 4)
+/* largest periodic USB packet used / 4 */
+// #define CONFIG_USB_DWC2_PTX_FIFO_SIZE (1024 / 4)
+/*
+ * (largest USB packet used / 4) + 1 for status information + 1 transfer complete +
+ * 1 location each for Bulk/Control endpoint for handling NAK/NYET scenario
+ */
+// #define CONFIG_USB_DWC2_RX_FIFO_SIZE ((1012 - CONFIG_USB_DWC2_NPTX_FIFO_SIZE - CONFIG_USB_DWC2_PTX_FIFO_SIZE) / 4)
+
+/* ---------------- MUSB Configuration ---------------- */
+// #define CONFIG_USB_MUSB_SUNXI
+
+#define CONFIG_USB_EHCI_HPMICRO         (1)
+#endif

+ 163 - 9
bsp/hpmicro/hpm6750evk2/rtconfig.h

@@ -1,9 +1,6 @@
 #ifndef RT_CONFIG_H__
 #define RT_CONFIG_H__
 
-/* Automatically generated file; DO NOT EDIT. */
-/* RT-Thread Configuration */
-
 /* RT-Thread Kernel */
 
 #define RT_NAME_MAX 8
@@ -17,13 +14,18 @@
 #define RT_HOOK_USING_FUNC_PTR
 #define RT_USING_IDLE_HOOK
 #define RT_IDLE_HOOK_LIST_SIZE 4
-#define IDLE_THREAD_STACK_SIZE 512
+#define IDLE_THREAD_STACK_SIZE 2048
 #define RT_USING_TIMER_SOFT
 #define RT_TIMER_THREAD_PRIO 4
-#define RT_TIMER_THREAD_STACK_SIZE 512
+#define RT_TIMER_THREAD_STACK_SIZE 2048
 
 /* kservice optimization */
 
+/* end of kservice optimization */
+
+/* klibc optimization */
+
+/* end of klibc optimization */
 
 /* Inter-Thread communication */
 
@@ -32,6 +34,7 @@
 #define RT_USING_EVENT
 #define RT_USING_MAILBOX
 #define RT_USING_MESSAGEQUEUE
+/* end of Inter-Thread communication */
 
 /* Memory Management */
 
@@ -39,12 +42,14 @@
 #define RT_USING_SMALL_MEM
 #define RT_USING_SMALL_MEM_AS_HEAP
 #define RT_USING_HEAP
+/* end of Memory Management */
 #define RT_USING_DEVICE
 #define RT_USING_CONSOLE
 #define RT_CONSOLEBUF_SIZE 128
 #define RT_CONSOLE_DEVICE_NAME "uart0"
-#define RT_VER_NUM 0x50100
+#define RT_VER_NUM 0x50200
 #define RT_BACKTRACE_LEVEL_MAX_NR 32
+/* end of RT-Thread Kernel */
 
 /* RT-Thread Components */
 
@@ -70,19 +75,37 @@
 
 /* DFS: device virtual file system */
 
+#define RT_USING_DFS
+#define DFS_USING_POSIX
+#define DFS_USING_WORKDIR
+#define DFS_FD_MAX 16
+#define RT_USING_DFS_V1
+#define DFS_FILESYSTEMS_MAX 4
+#define DFS_FILESYSTEM_TYPES_MAX 4
+#define RT_USING_DFS_DEVFS
+/* end of DFS: device virtual file system */
 
 /* Device Drivers */
 
 #define RT_USING_DEVICE_IPC
 #define RT_UNAMED_PIPE_NUMBER 64
+#define RT_USING_SYSTEM_WORKQUEUE
+#define RT_SYSTEM_WORKQUEUE_STACKSIZE 2048
+#define RT_SYSTEM_WORKQUEUE_PRIORITY 23
 #define RT_USING_SERIAL
 #define RT_USING_SERIAL_V1
 #define RT_SERIAL_RB_BUFSZ 64
 #define RT_USING_RTC
 #define RT_USING_PIN
-
-/* Using USB */
-
+#define RT_USING_CHERRYUSB
+#define RT_CHERRYUSB_HOST
+#define RT_CHERRYUSB_HOST_EHCI_HPM
+#define RT_CHERRYUSB_HOST_CDC_ACM
+#define RT_CHERRYUSB_HOST_HID
+#define RT_CHERRYUSB_HOST_TEMPLATE
+#define TEST_USBH_CDC_ACM 1
+#define TEST_USBH_HID 1
+/* end of Device Drivers */
 
 /* C/C++ and POSIX layer */
 
@@ -94,27 +117,105 @@
 #define RT_LIBC_TZ_DEFAULT_HOUR 8
 #define RT_LIBC_TZ_DEFAULT_MIN 0
 #define RT_LIBC_TZ_DEFAULT_SEC 0
+/* end of Timezone and Daylight Saving Time */
+/* end of ISO-ANSI C layer */
 
 /* POSIX (Portable Operating System Interface) layer */
 
+#define RT_USING_POSIX_FS
+#define RT_USING_POSIX_POLL
+#define RT_USING_POSIX_SELECT
+#define RT_USING_POSIX_SOCKET
 
 /* Interprocess Communication (IPC) */
 
 
 /* Socket is in the 'Network' category */
 
+/* end of Interprocess Communication (IPC) */
+/* end of POSIX (Portable Operating System Interface) layer */
+/* end of C/C++ and POSIX layer */
 
 /* Network */
 
+#define RT_USING_SAL
+#define SAL_INTERNET_CHECK
+
+/* Docking with protocol stacks */
+
+#define SAL_USING_LWIP
+/* end of Docking with protocol stacks */
+#define SAL_USING_POSIX
+#define RT_USING_NETDEV
+#define NETDEV_USING_IFCONFIG
+#define NETDEV_USING_PING
+#define NETDEV_USING_NETSTAT
+#define NETDEV_USING_AUTO_DEFAULT
+#define NETDEV_IPV4 1
+#define NETDEV_IPV6 0
+#define RT_USING_LWIP
+#define RT_USING_LWIP212
+#define RT_USING_LWIP_VER_NUM 0x20102
+#define RT_LWIP_MEM_ALIGNMENT 4
+#define RT_LWIP_IGMP
+#define RT_LWIP_ICMP
+#define RT_LWIP_DNS
+#define RT_LWIP_DHCP
+#define IP_SOF_BROADCAST 1
+#define IP_SOF_BROADCAST_RECV 1
+
+/* Static IPv4 Address */
+
+#define RT_LWIP_IPADDR "192.168.1.30"
+#define RT_LWIP_GWADDR "192.168.1.1"
+#define RT_LWIP_MSKADDR "255.255.255.0"
+/* end of Static IPv4 Address */
+#define RT_LWIP_UDP
+#define RT_LWIP_TCP
+#define RT_LWIP_RAW
+#define RT_MEMP_NUM_NETCONN 8
+#define RT_LWIP_PBUF_NUM 16
+#define RT_LWIP_RAW_PCB_NUM 4
+#define RT_LWIP_UDP_PCB_NUM 4
+#define RT_LWIP_TCP_PCB_NUM 4
+#define RT_LWIP_TCP_SEG_NUM 40
+#define RT_LWIP_TCP_SND_BUF 8196
+#define RT_LWIP_TCP_WND 8196
+#define RT_LWIP_TCPTHREAD_PRIORITY 10
+#define RT_LWIP_TCPTHREAD_MBOX_SIZE 8
+#define RT_LWIP_TCPTHREAD_STACKSIZE 1024
+#define LWIP_NO_RX_THREAD
+#define RT_LWIP_ETHTHREAD_PRIORITY 12
+#define RT_LWIP_ETHTHREAD_STACKSIZE 1024
+#define RT_LWIP_ETHTHREAD_MBOX_SIZE 8
+#define LWIP_NETIF_STATUS_CALLBACK 1
+#define LWIP_NETIF_LINK_CALLBACK 1
+#define RT_LWIP_NETIF_NAMESIZE 6
+#define SO_REUSE 1
+#define LWIP_SO_RCVTIMEO 1
+#define LWIP_SO_SNDTIMEO 1
+#define LWIP_SO_RCVBUF 1
+#define LWIP_SO_LINGER 0
+#define LWIP_NETIF_LOOPBACK 0
+#define RT_LWIP_USING_PING
+/* end of Network */
 
 /* Memory protection */
 
+/* end of Memory protection */
 
 /* Utilities */
 
+/* end of Utilities */
+
+/* Using USB legacy version */
+
+/* end of Using USB legacy version */
+/* end of RT-Thread Components */
 
 /* RT-Thread Utestcases */
 
+/* end of RT-Thread Utestcases */
 
 /* RT-Thread online packages */
 
@@ -125,57 +226,83 @@
 
 /* Marvell WiFi */
 
+/* end of Marvell WiFi */
 
 /* Wiced WiFi */
 
+/* end of Wiced WiFi */
 
 /* CYW43012 WiFi */
 
+/* end of CYW43012 WiFi */
 
 /* BL808 WiFi */
 
+/* end of BL808 WiFi */
 
 /* CYW43439 WiFi */
 
+/* end of CYW43439 WiFi */
+/* end of Wi-Fi */
+#define PKG_USING_NETUTILS
+#define PKG_NETUTILS_IPERF
+#define IPERF_THREAD_STACK_SIZE 2048
+#define PKG_USING_NETUTILS_LATEST_VERSION
+#define PKG_NETUTILS_VER_NUM 0x99999
 
 /* IoT Cloud */
 
+/* end of IoT Cloud */
+/* end of IoT - internet of things */
 
 /* security packages */
 
+/* end of security packages */
 
 /* language packages */
 
 /* JSON: JavaScript Object Notation, a lightweight data-interchange format */
 
+/* end of JSON: JavaScript Object Notation, a lightweight data-interchange format */
 
 /* XML: Extensible Markup Language */
 
+/* end of XML: Extensible Markup Language */
+/* end of language packages */
 
 /* multimedia packages */
 
 /* LVGL: powerful and easy-to-use embedded GUI library */
 
+/* end of LVGL: powerful and easy-to-use embedded GUI library */
 
 /* u8g2: a monochrome graphic library */
 
+/* end of u8g2: a monochrome graphic library */
+/* end of multimedia packages */
 
 /* tools packages */
 
+/* end of tools packages */
 
 /* system packages */
 
 /* enhanced kernel services */
 
+/* end of enhanced kernel services */
 
 /* acceleration: Assembly language or algorithmic acceleration packages */
 
+/* end of acceleration: Assembly language or algorithmic acceleration packages */
 
 /* CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */
 
+/* end of CMSIS: ARM Cortex-M Microcontroller Software Interface Standard */
 
 /* Micrium: Micrium software products porting for RT-Thread */
 
+/* end of Micrium: Micrium software products porting for RT-Thread */
+/* end of system packages */
 
 /* peripheral libraries and drivers */
 
@@ -183,66 +310,91 @@
 
 /* STM32 HAL & SDK Drivers */
 
+/* end of STM32 HAL & SDK Drivers */
 
 /* Kendryte SDK */
 
+/* end of Kendryte SDK */
+/* end of HAL & SDK Drivers */
 
 /* sensors drivers */
 
+/* end of sensors drivers */
 
 /* touch drivers */
 
+/* end of touch drivers */
+/* end of peripheral libraries and drivers */
 
 /* AI packages */
 
+/* end of AI packages */
 
 /* Signal Processing and Control Algorithm Packages */
 
+/* end of Signal Processing and Control Algorithm Packages */
 
 /* miscellaneous packages */
 
 /* project laboratory */
 
+/* end of project laboratory */
+
 /* samples: kernel and components samples */
 
+/* end of samples: kernel and components samples */
 
 /* entertainment: terminal games and other interesting software packages */
 
+/* end of entertainment: terminal games and other interesting software packages */
+/* end of miscellaneous packages */
 
 /* Arduino libraries */
 
 
 /* Projects and Demos */
 
+/* end of Projects and Demos */
 
 /* Sensors */
 
+/* end of Sensors */
 
 /* Display */
 
+/* end of Display */
 
 /* Timing */
 
+/* end of Timing */
 
 /* Data Processing */
 
+/* end of Data Processing */
 
 /* Data Storage */
 
 /* Communication */
 
+/* end of Communication */
 
 /* Device Control */
 
+/* end of Device Control */
 
 /* Other */
 
+/* end of Other */
 
 /* Signal IO */
 
+/* end of Signal IO */
 
 /* Uncategorized */
 
+/* end of Arduino libraries */
+/* end of RT-Thread online packages */
+
 /* Hardware Drivers Config */
 
 #define SOC_HPM6000
@@ -253,5 +405,7 @@
 #define BSP_USING_UART
 #define BSP_USING_UART0
 #define BSP_USING_RTC
+/* end of On-chip Peripheral Drivers */
+/* end of Hardware Drivers Config */
 
 #endif

+ 1 - 1
bsp/hpmicro/libraries/hpm_sdk/SConscript

@@ -68,7 +68,7 @@ if GetDepend(['BSP_USING_FEMC']):
 if GetDepend(['BSP_USING_PWM']):
     src += ['drivers/src/hpm_pwm_drv.c']
 
-if GetDepend(['BSP_USING_USB']):
+if GetDepend(['BSP_USING_USB']) or GetDepend(['RT_USING_CHERRYUSB']):
     src += ['drivers/src/hpm_usb_drv.c']
 
 if GetDepend(['BSP_USING_I2S']):

+ 3 - 0
components/Kconfig

@@ -44,4 +44,7 @@ if RT_USING_SMART
 source "$RTT_DIR/components/lwp/Kconfig"
 source "$RTT_DIR/components/mm/Kconfig"
 endif
+
+source "$RTT_DIR/components/legacy/Kconfig"
+
 endmenu

+ 1 - 200
components/drivers/Kconfig

@@ -937,205 +937,6 @@ source "$RTT_DIR/components/drivers/pinctrl/Kconfig"
 source "$RTT_DIR/components/drivers/ktime/Kconfig"
 source "$RTT_DIR/components/drivers/clk/Kconfig"
 source "$RTT_DIR/components/drivers/hwtimer/Kconfig"
+source "$RTT_DIR/components/drivers/usb/cherryusb/Kconfig"
 
-menu "Using USB"
-    config RT_USING_USB
-        bool
-        default n
-
-    config RT_USING_USB_HOST
-        bool "Using USB host"
-        default n
-        select RT_USING_USB
-
-        if RT_USING_USB_HOST
-            config RT_USBH_MSTORAGE
-                bool "Enable Udisk Drivers"
-                default n
-                if RT_USBH_MSTORAGE
-                    config UDISK_MOUNTPOINT
-                        string "Udisk mount dir"
-                        default "/"
-                endif
-            config RT_USBH_HID
-                bool "Enable HID Drivers"
-                default n
-                if RT_USBH_HID
-                    config RT_USBH_HID_MOUSE
-                        bool "Enable HID mouse protocol"
-                        default n
-                    config RT_USBH_HID_KEYBOARD
-                        bool "Enable HID keyboard protocol"
-                        default n
-                endif
-        endif
-    config RT_USING_USB_DEVICE
-        bool "Using USB device"
-        default n
-        select RT_USING_USB
-
-        if RT_USING_USB_DEVICE || RT_USING_USB_HOST
-            config RT_USBD_THREAD_STACK_SZ
-                int "usb thread stack size"
-                default 4096
-        endif
-        if RT_USING_USB_DEVICE
-            config USB_VENDOR_ID
-                hex "USB Vendor ID"
-                default 0x0FFE
-            config USB_PRODUCT_ID
-                hex "USB Product ID"
-                default 0x0001
-
-            config RT_USB_DEVICE_COMPOSITE
-                bool "Enable composite device"
-                default n
-                choice
-                    prompt "Device type"
-                    default _RT_USB_DEVICE_NONE
-                    depends on !RT_USB_DEVICE_COMPOSITE
-                    config _RT_USB_DEVICE_NONE
-                        bool "Using custom class by register interface"
-                        select RT_USB_DEVICE_NONE
-                    config _RT_USB_DEVICE_CDC
-                        bool "Enable to use device as CDC device"
-                        select RT_USB_DEVICE_CDC
-                    config _RT_USB_DEVICE_MSTORAGE
-                        bool "Enable to use device as Mass Storage device"
-                        select RT_USB_DEVICE_MSTORAGE
-                    config _RT_USB_DEVICE_HID
-                        bool "Enable to use device as HID device"
-                        select RT_USB_DEVICE_HID
-                    config _RT_USB_DEVICE_RNDIS
-                        bool "Enable to use device as rndis device"
-                        select RT_USB_DEVICE_RNDIS
-                        depends on RT_USING_LWIP
-                    config _RT_USB_DEVICE_ECM
-                        bool "Enable to use device as ecm device"
-                        select RT_USB_DEVICE_ECM
-                        depends on RT_USING_LWIP
-                    config _RT_USB_DEVICE_WINUSB
-                        bool "Enable to use device as winusb device"
-                        select RT_USB_DEVICE_WINUSB
-                    config _RT_USB_DEVICE_AUDIO
-                        bool "Enable to use device as audio device"
-                        select RT_USB_DEVICE_AUDIO
-                endchoice
-                if RT_USB_DEVICE_COMPOSITE
-                    config RT_USB_DEVICE_CDC
-                        bool "Enable to use device as CDC device"
-                        default n
-                    config RT_USB_DEVICE_NONE
-                        bool
-                        default y
-                    config RT_USB_DEVICE_MSTORAGE
-                        bool "Enable to use device as Mass Storage device"
-                        default n
-                    config RT_USB_DEVICE_HID
-                        bool "Enable to use device as HID device"
-                        default n
-                    config RT_USB_DEVICE_RNDIS
-                        bool "Enable to use device as rndis device"
-                        default n
-                        depends on RT_USING_LWIP
-                    config RT_USB_DEVICE_ECM
-                        bool "Enable to use device as ecm device"
-                        default n
-                        depends on RT_USING_LWIP
-                    config RT_USB_DEVICE_WINUSB
-                        bool "Enable to use device as winusb device"
-                        default n
-                    config RT_USB_DEVICE_AUDIO
-                        bool "Enable to use device as audio device"
-                        default n
-                endif
-                if RT_USB_DEVICE_CDC
-                    config RT_VCOM_TASK_STK_SIZE
-                        int "virtual com thread stack size"
-                        default 512
-                    config RT_CDC_RX_BUFSIZE
-                        int "virtual com rx buffer size"
-                        default 128
-                    config RT_VCOM_TX_USE_DMA
-                        bool "Enable to use dma for vcom tx"
-                        default n
-                    config RT_VCOM_SERNO
-                        string "serial number of virtual com"
-                        default "32021919830108"
-                    config RT_VCOM_SER_LEN
-                        int "serial number length of virtual com"
-                        default 14
-                    config RT_VCOM_TX_TIMEOUT
-                        int "tx timeout(ticks) of virtual com"
-                        default 1000
-                endif
-                if RT_USB_DEVICE_WINUSB
-                    config RT_WINUSB_GUID
-                    string "Guid for winusb"
-                    default "{6860DC3C-C05F-4807-8807-1CA861CC1D66}"
-                endif
-                if RT_USB_DEVICE_MSTORAGE
-                    config RT_USB_MSTORAGE_DISK_NAME
-                    string "msc class disk name"
-                    default "flash0"
-                endif
-
-                if RT_USB_DEVICE_RNDIS
-                    config RNDIS_DELAY_LINK_UP
-                        bool "Delay linkup media connection"
-                        select RT_USING_TIMER_SOFT
-                        default n
-                endif
-
-                if RT_USB_DEVICE_HID
-                    config RT_USB_DEVICE_HID_KEYBOARD
-                        bool "Use to HID device as Keyboard"
-                        default n
-                    if RT_USB_DEVICE_HID_KEYBOARD
-                        config RT_USB_DEVICE_HID_KEYBOARD_NUMBER
-                        int "Number of Keyboard(max 3)"
-                        default 1
-                        range 1 3
-                    endif
-                    config RT_USB_DEVICE_HID_MOUSE
-                        bool "Use to HID device as Mouse"
-                        default n
-                    config RT_USB_DEVICE_HID_GENERAL
-                        bool "Use to HID device as General HID device"
-                        default y
-                        if RT_USB_DEVICE_HID_GENERAL
-                            config RT_USB_DEVICE_HID_GENERAL_OUT_REPORT_LENGTH
-                                int "General HID device out report length"
-                                default 63
-                                range 0 63
-
-                            config RT_USB_DEVICE_HID_GENERAL_IN_REPORT_LENGTH
-                                int "General HID device in report length"
-                                default 63
-                                range 0 63
-                        endif
-                    config RT_USB_DEVICE_HID_MEDIA
-                        bool "Use to HID device as media keyboard"
-                        default y
-                endif
-                if RT_USB_DEVICE_AUDIO
-                    config RT_USB_DEVICE_AUDIO_MIC
-                        bool "Use usb mic device as audio device"
-                        default n
-                        if RT_USB_DEVICE_AUDIO_MIC
-                            config RT_USBD_MIC_DEVICE_NAME
-                            string "audio mic device name"
-                            default "mic0"
-                        endif
-                    config RT_USB_DEVICE_AUDIO_SPEAKER
-                        bool "Use usb speaker device as audio device"
-                        default n
-                        if RT_USB_DEVICE_AUDIO_SPEAKER
-                            config RT_USBD_SPEAKER_DEVICE_NAME
-                            string "audio speaker device name"
-                            default "sound0"
-                        endif
-                endif
-        endif
-    endmenu
 endmenu

+ 6 - 0
components/drivers/usb/.ignore_format.yml

@@ -0,0 +1,6 @@
+# files format check exclude path, please follow the instructions below to modify;
+# If you need to exclude an entire folder, add the folder path in dir_path;
+# If you need to exclude a file, add the path to the file in file_path.
+
+dir_path:
+- cherryusb

+ 6 - 4
components/drivers/usb/SConscript

@@ -1,13 +1,15 @@
-# for module compiling
+# RT-Thread building script for bridge
+
 import os
 from building import *
 
-cwd     = GetCurrentDir()
-objs    = []
-list    = os.listdir(cwd)
+cwd = GetCurrentDir()
+objs = []
+list = os.listdir(cwd)
 
 for d in list:
     path = os.path.join(cwd, d)
     if os.path.isfile(os.path.join(path, 'SConscript')):
         objs = objs + SConscript(os.path.join(d, 'SConscript'))
+
 Return('objs')

+ 171 - 0
components/drivers/usb/cherryusb/.clang-format

@@ -0,0 +1,171 @@
+# clang-format configuration file. Intended for clang-format >= 11.0
+#
+# For more information, see:
+#
+#   https://clang.llvm.org/docs/ClangFormat.html
+#   https://clang.llvm.org/docs/ClangFormatStyleOptions.html
+#
+---
+# 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto
+Language:	Cpp
+# BasedOnStyle:	LLVM
+# 访问说明符(public、private等)的偏移
+AccessModifierOffset:	-4
+# 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行)
+AlignAfterOpenBracket:	Align
+# 连续赋值时,对齐所有等号
+AlignConsecutiveAssignments:	false
+# 对齐位域
+AlignConsecutiveBitFields: true
+# 连续声明时,对齐所有声明的变量名
+AlignConsecutiveDeclarations:	false
+# 连续宏时,进行对齐
+AlignConsecutiveMacros: true
+# 左对齐逃脱换行(使用反斜杠换行)的反斜杠
+AlignEscapedNewlines:	Left
+# 水平对齐二元和三元表达式的操作数
+AlignOperands:	true
+# 对齐连续的尾随的注释
+AlignTrailingComments:	true
+# 允许函数声明的所有参数在放在下一行
+AllowAllParametersOfDeclarationOnNextLine:	false
+# 允许短的块放在同一行
+AllowShortBlocksOnASingleLine:	false
+# 允许短的case标签放在同一行
+AllowShortCaseLabelsOnASingleLine:	false
+# 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All
+AllowShortFunctionsOnASingleLine:	None
+# 允许短的if语句保持在同一行
+AllowShortIfStatementsOnASingleLine:	false
+# 允许短的循环保持在同一行
+AllowShortLoopsOnASingleLine:	false
+# 总是在定义返回类型后换行(deprecated)
+AlwaysBreakAfterDefinitionReturnType:	None
+# 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数),
+#  AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义)
+AlwaysBreakAfterReturnType:	None
+# 总是在多行string字面量前换行
+AlwaysBreakBeforeMultilineStrings:	false
+# 总是在template声明后换行
+AlwaysBreakTemplateDeclarations:	false
+# false表示函数实参要么都在同一行,要么都各自一行
+BinPackArguments:	true
+# false表示所有形参要么都在同一行,要么都各自一行
+BinPackParameters:	true
+# 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效
+BraceWrapping:
+    AfterClass: false
+    AfterControlStatement: false
+    AfterEnum: false
+    AfterFunction: true
+    AfterNamespace: false
+    AfterObjCDeclaration: false
+    AfterStruct: false
+    AfterUnion: false
+    AfterExternBlock: false # Unknown to clang-format-5.0
+    BeforeCatch: false
+    BeforeElse: false
+    IndentBraces: false
+    SplitEmptyFunction: true # Unknown to clang-format-4.0
+    SplitEmptyRecord: true # Unknown to clang-format-4.0
+    SplitEmptyNamespace: true # Unknown to clang-format-4.0
+# 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行)
+BreakBeforeBinaryOperators:	None
+BreakBeforeBraces:	Custom
+#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
+# 在三元运算符前换行
+BreakBeforeTernaryOperators:	false
+# 在构造函数的初始化列表的逗号前换行
+BreakConstructorInitializersBeforeComma:	false
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: false
+# 每行字符的限制,0表示没有限制
+ColumnLimit:	0
+# 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变
+CommentPragmas:	'^ IWYU pragma:'
+CompactNamespaces: false # Unknown to clang-format-4.0
+# 构造函数的初始化列表要么都在同一行,要么都各自一行
+ConstructorInitializerAllOnOneLineOrOnePerLine:	false
+# 构造函数的初始化列表的缩进宽度
+ConstructorInitializerIndentWidth:	4
+# 延续的行的缩进宽度
+ContinuationIndentWidth:	4
+# 去除C++11的列表初始化的大括号{后和}前的空格
+Cpp11BracedListStyle:	false
+# 继承最常用的指针和引用的对齐方式
+DerivePointerAlignment:	false
+# 关闭格式化
+DisableFormat:	false
+ForEachMacros:
+  - 'SHELL_EXPORT_CMD'
+
+# 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental)
+ExperimentalAutoDetectBinPacking:	false
+# 缩进case标签
+IndentCaseLabels:	true
+# 缩进宽度
+IndentWidth:	4
+# 函数返回类型换行时,缩进函数声明或函数定义的函数名
+IndentWrappedFunctionNames:	false
+# 保留在块开始处的空行
+KeepEmptyLinesAtTheStartOfBlocks:	false
+# 开始一个块的宏的正则表达式
+MacroBlockBegin:	''
+# 结束一个块的宏的正则表达式
+MacroBlockEnd:	''
+# 连续空行的最大数量
+MaxEmptyLinesToKeep:	1
+# 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All
+NamespaceIndentation:	None
+# 使用ObjC块时缩进宽度
+ObjCBlockIndentWidth:	4
+# 在ObjC的@property后添加一个空格
+ObjCSpaceAfterProperty:	false
+# 在ObjC的protocol列表前添加一个空格
+ObjCSpaceBeforeProtocolList:	true
+# 在call(后对函数调用换行的penalty
+PenaltyBreakBeforeFirstCallParameter:	30
+# 在一个注释中引入换行的penalty
+PenaltyBreakComment:	10
+# 第一次在<<前换行的penalty
+PenaltyBreakFirstLessLess:	0
+# 在一个字符串字面量中引入换行的penalty
+PenaltyBreakString:	10
+# 对于每个在行字符数限制之外的字符的penalty
+PenaltyExcessCharacter:	100
+# 将函数的返回类型放到它自己的行的penalty
+PenaltyReturnTypeOnItsOwnLine:	60
+# 指针和引用的对齐: Left, Right, Middle
+PointerAlignment:	Right
+# 允许重新排版注释
+ReflowComments:	false
+# 允许排序#include
+SortIncludes:	false
+# 在C风格类型转换后添加空格
+SpaceAfterCStyleCast:	false
+# 在赋值运算符之前添加空格
+SpaceBeforeAssignmentOperators:	true
+# 开圆括号之前添加一个空格: Never, ControlStatements, Always
+SpaceBeforeParens:	ControlStatements
+# 在空的圆括号中添加空格
+SpaceInEmptyParentheses:	false
+# 在尾随的评论前添加的空格数(只适用于//)
+SpacesBeforeTrailingComments:	1
+# 在尖括号的<后和>前添加空格
+SpacesInAngles:	false
+# 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格
+SpacesInContainerLiterals:	false
+# 在C风格类型转换的括号中添加空格
+SpacesInCStyleCastParentheses:	false
+# 在圆括号的(后和)前添加空格
+SpacesInParentheses:	false
+# 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响
+SpacesInSquareBrackets:	false
+# 标准: Cpp03, Cpp11, Auto
+Standard:	Cpp03
+# tab宽度
+TabWidth:	4
+# 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always
+UseTab:	Never
+...
+

+ 47 - 0
components/drivers/usb/cherryusb/.gitattributes

@@ -0,0 +1,47 @@
+*.c linguist-language=C
+*.C linguist-language=C
+*.h linguist-language=C
+*.H linguist-language=C
+
+* text=auto
+
+*.S text
+*.asm text
+*.c text
+*.cc text
+*.cpp text
+*.cxx text
+*.h text
+*.htm text
+*.html text
+*.in text
+*.ld text
+*.m4 text
+*.mak text
+*.mk text
+*.py text
+*.rb text
+*.s text
+*.sct text
+*.sh text
+*.txt text
+*.xml text
+SConscript text
+Makefile text
+AUTHORS text
+COPYING text
+
+*.LZO -text
+*.Opt -text
+*.Uv2 -text
+*.ewp -text
+*.eww -text
+*.vcproj -text
+*.bat -text
+*.dos -text
+*.icf -text
+*.inf -text
+*.ini -text
+*.sct -text
+*.xsd -text
+Jamfile -text

+ 23 - 0
components/drivers/usb/cherryusb/.gitignore

@@ -0,0 +1,23 @@
+.vscode
+**/Drivers/**
+**/MDK-ARM/DebugConfig/**
+**/MDK-ARM/RTE/**
+**/obj/**
+**/RET/**
+**/Listings/**
+**/Objects/**
+*.map
+*.o
+*.d
+*.htm
+*.dep
+*.lnp
+*.iex
+*.lst
+*.axf
+*.crf
+*.hex
+*.Bak
+*.uvguix.*
+*.scvd
+*.usb.tmp

+ 35 - 0
components/drivers/usb/cherryusb/.readthedocs.yaml

@@ -0,0 +1,35 @@
+# Read the Docs configuration file for Sphinx projects
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+# Set the OS, Python version and other tools you might need
+build:
+  os: ubuntu-22.04
+  tools:
+    python: "3.11"
+    # You can also specify other tool versions:
+    # nodejs: "20"
+    # rust: "1.70"
+    # golang: "1.20"
+
+# Build documentation in the "docs/" directory with Sphinx
+sphinx:
+  configuration: docs/source/conf.py
+  # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
+  # builder: "dirhtml"
+  # Fail on all warnings to avoid broken references
+  # fail_on_warning: true
+
+# Optionally build your docs in additional formats such as PDF and ePub
+# formats:
+#    - pdf
+#    - epub
+
+# Optional but recommended, declare the Python requirements required
+# to build your documentation
+# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
+python:
+   install:
+   - requirements: docs/requirements.txt

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2 - 0
components/drivers/usb/cherryusb/CherryUSB.svg


+ 310 - 0
components/drivers/usb/cherryusb/Kconfig

@@ -0,0 +1,310 @@
+# Kconfig file for package CherryUSB
+menuconfig RT_USING_CHERRYUSB
+    bool "Using USB with CherryUSB"
+    default n
+
+if RT_USING_CHERRYUSB
+
+    menuconfig RT_CHERRYUSB_DEVICE
+        bool "Enable usb device mode"
+        default n
+
+    if RT_CHERRYUSB_DEVICE
+        choice
+            prompt "Select usb device speed"
+            default RT_CHERRYUSB_DEVICE_SPEED_FS
+            config RT_CHERRYUSB_DEVICE_SPEED_FS
+                bool "FS"
+            config RT_CHERRYUSB_DEVICE_SPEED_HS
+                bool "HS"
+            config RT_CHERRYUSB_DEVICE_SPEED_AUTO
+                bool "AUTO"
+        endchoice
+
+        choice
+            prompt "Select usb device ip, and some ip need config in usb_config.h, please check"
+            default RT_CHERRYUSB_DEVICE_CUSTOM
+            config RT_CHERRYUSB_DEVICE_CUSTOM
+                bool "CUSTOM (Implement it yourself)"
+            config RT_CHERRYUSB_DEVICE_FSDEV
+                bool "fsdev"
+            config RT_CHERRYUSB_DEVICE_DWC2_ST
+                bool "dwc2_st"
+            config RT_CHERRYUSB_DEVICE_DWC2_ESP
+                bool "dwc2_esp"
+            config RT_CHERRYUSB_DEVICE_DWC2_AT
+                bool "dwc2_at"
+            config RT_CHERRYUSB_DEVICE_DWC2_GD
+                bool "dwc2_gd"
+            config RT_CHERRYUSB_DEVICE_DWC2_CUSTOM
+                bool "dwc2_custom"
+            config RT_CHERRYUSB_DEVICE_MUSB_STANDARD
+                bool "musb_standard"
+            config RT_CHERRYUSB_DEVICE_MUSB_SUNXI
+                bool "musb_sunxi"
+            config RT_CHERRYUSB_DEVICE_MUSB_CUSTOM
+                bool "musb_custom"
+            config RT_CHERRYUSB_DEVICE_BL
+                bool "bouffalo"
+            config RT_CHERRYUSB_DEVICE_CH32
+                bool "ch32"
+            config RT_CHERRYUSB_DEVICE_HPM
+                bool "hpm"
+            config RT_CHERRYUSB_DEVICE_AIC
+                bool "aic"
+            config RT_CHERRYUSB_DEVICE_PUSB2
+                bool "pusb2"
+        endchoice
+
+        config RT_CHERRYUSB_DEVICE_CDC_ACM
+            bool
+            prompt "Enable usb cdc acm device"
+            default n
+
+        config RT_CHERRYUSB_DEVICE_HID
+            bool
+            prompt "Enable usb hid device"
+            default n
+
+        config RT_CHERRYUSB_DEVICE_MSC
+            bool
+            prompt "Enable usb msc device"
+            default n
+
+        config RT_CHERRYUSB_DEVICE_AUDIO
+            bool
+            prompt "Enable usb audio device"
+            default n
+
+        config RT_CHERRYUSB_DEVICE_VIDEO
+            bool
+            prompt "Enable usb video device"
+            default n
+
+        config RT_CHERRYUSB_DEVICE_CDC_RNDIS
+            bool
+            prompt "Enable usb cdc rndis device"
+            default n
+
+        config RT_CHERRYUSB_DEVICE_CDC_ECM
+            bool
+            prompt "Enable usb cdc ecm device"
+            default n
+
+        config RT_CHERRYUSB_DEVICE_CDC_NCM
+            bool
+            prompt "Enable usb cdc ncm device"
+            default n
+
+        config RT_CHERRYUSB_DEVICE_DFU
+            bool
+            prompt "Enable usb dfu device"
+            default n
+
+        choice
+            prompt "Select usb device template"
+            default RT_CHERRYUSB_DEVICE_TEMPLATE
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_NONE
+                bool "none (Implement it yourself)"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM
+                bool "cdc_acm"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_MSC
+                bool "msc"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_HID_KEYBOARD
+                bool "hid_keyboard"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_HID_MOUSE
+                bool "hid_mouse"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_HID_CUSTOM
+                bool "hid_custom"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_VIDEO
+                bool "video"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V1_MIC_SPEAKER
+                bool "audio_v1_mic_speaker_multichan"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V2_MIC_SPEAKER
+                bool "audio_v2_mic_speaker_multichan"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_RNDIS
+                bool "cdc_rndis"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ECM
+                bool "cdc_ecm"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM
+                bool "cdc_ncm"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
+                bool "cdc_acm_msc"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID
+                bool "cdc_acm_msc_hid"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1
+                bool "winusbv1"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC
+                bool "winusbv2_cdc"
+            config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_HID
+                bool "winusbv2_hid"
+        endchoice
+
+    endif
+
+    menuconfig RT_CHERRYUSB_HOST
+        bool "Enable usb host mode"
+        default n
+
+    if RT_CHERRYUSB_HOST
+        choice
+            prompt "Select usb host ip, and some ip need config in usb_config.h, please check"
+            default RT_CHERRYUSB_HOST_CUSTOM
+            config RT_CHERRYUSB_HOST_CUSTOM
+                bool "CUSTOM (Implement it yourself)"
+            config RT_CHERRYUSB_HOST_EHCI_BL
+                bool "ehci_bouffalo"
+            config RT_CHERRYUSB_HOST_EHCI_HPM
+                bool "ehci_hpm"
+            config RT_CHERRYUSB_HOST_EHCI_AIC
+                bool "ehci_aic"
+            config RT_CHERRYUSB_HOST_EHCI_NUVOTON_NUC980
+                bool "ehci_nuvoton_nuc980"
+            config RT_CHERRYUSB_HOST_EHCI_NUVOTON_MA35D0
+                bool "ehci_nuvoton_ma35d0"
+            config RT_CHERRYUSB_HOST_EHCI_CUSTOM
+                bool "ehci_custom"
+            config RT_CHERRYUSB_HOST_DWC2_ST
+                bool "dwc2_st"
+            config RT_CHERRYUSB_HOST_DWC2_ESP
+                bool "dwc2_esp"
+            config RT_CHERRYUSB_HOST_DWC2_CUSTOM
+                bool "dwc2_custom"
+            config RT_CHERRYUSB_HOST_MUSB_STANDARD
+                bool "musb_standard"
+            config RT_CHERRYUSB_HOST_MUSB_SUNXI
+                bool "musb_sunxi"
+            config RT_CHERRYUSB_HOST_MUSB_CUSTOM
+                bool "musb_custom"
+            config RT_CHERRYUSB_HOST_PUSB2
+                bool "pusb2"
+            config RT_CHERRYUSB_HOST_XHCI
+                bool "xhci"
+        endchoice
+
+        config RT_CHERRYUSB_HOST_CDC_ACM
+            bool
+            prompt "Enable usb cdc acm driver"
+            default n
+
+        config RT_CHERRYUSB_HOST_HID
+            bool
+            prompt "Enable usb hid driver"
+            default n
+
+        config RT_CHERRYUSB_HOST_MSC
+            bool
+            prompt "Enable usb msc driver"
+            default n
+            select RT_USING_DFS
+
+        config RT_CHERRYUSB_HOST_CDC_ECM
+            bool
+            prompt "Enable usb cdc ecm driver"
+            select RT_USING_LWIP
+            select RT_USING_LWIP212
+            select CONFIG_USBHOST_PLATFORM_CDC_ECM
+            default n
+
+        config RT_CHERRYUSB_HOST_CDC_RNDIS
+            bool
+            prompt "Enable usb rndis driver"
+            select RT_USING_LWIP
+            select RT_USING_LWIP212
+            select CONFIG_USBHOST_PLATFORM_CDC_RNDIS
+            default n
+
+        config RT_CHERRYUSB_HOST_CDC_NCM
+            bool
+            prompt "Enable usb cdc ncm driver"
+            select RT_USING_LWIP
+            select RT_USING_LWIP212
+            select CONFIG_USBHOST_PLATFORM_CDC_NCM
+            default n
+
+        config RT_CHERRYUSB_HOST_VIDEO
+            bool
+            prompt "Enable usb video driver, it is commercial charge"
+            default n
+
+        config RT_CHERRYUSB_HOST_AUDIO
+            bool
+            prompt "Enable usb audio driver, it is commercial charge"
+            default n
+
+        config RT_CHERRYUSB_HOST_BLUETOOTH
+            bool
+            prompt "Enable usb bluetooth driver"
+            default n
+
+        config RT_CHERRYUSB_HOST_ASIX
+            bool
+            prompt "Enable usb asix driver"
+            select RT_USING_LWIP
+            select RT_USING_LWIP212
+            select CONFIG_USBHOST_PLATFORM_CDC_ASIX
+            default n
+
+        config RT_CHERRYUSB_HOST_RTL8152
+            bool
+            prompt "Enable usb rtl8152 driver"
+            select RT_USING_LWIP
+            select RT_USING_LWIP212
+            select CONFIG_USBHOST_PLATFORM_CDC_RTL8152
+            default n
+
+        config RT_CHERRYUSB_HOST_FTDI
+            bool
+            prompt "Enable usb ftdi driver"
+            default n
+
+        config RT_CHERRYUSB_HOST_CH34X
+            bool
+            prompt "Enable usb ch34x driver"
+            default n
+
+        config RT_CHERRYUSB_HOST_CP210X
+            bool
+            prompt "Enable usb cp210x driver"
+            default n
+
+        config RT_CHERRYUSB_HOST_PL2303
+            bool
+            prompt "Enable usb pl2303 driver"
+            default n
+
+        config CONFIG_USBHOST_PLATFORM_CDC_ECM
+            bool
+
+        config CONFIG_USBHOST_PLATFORM_CDC_RNDIS
+            bool
+
+        config CONFIG_USBHOST_PLATFORM_CDC_NCM
+            bool
+
+        config CONFIG_USBHOST_PLATFORM_ASIX
+            bool
+
+        config CONFIG_USBHOST_PLATFORM_RTL152
+            bool
+
+        config CHERRYUSB_HOST_TEMPLATE
+            bool
+            prompt "Use usb host template"
+            default n
+
+        if RT_CHERRYUSB_HOST_TEMPLATE
+            config TEST_USBH_CDC_ACM
+                int
+                prompt "demo for test cdc acm"
+                default 0
+                depends on CHERRYUSB_HOST_CDC_ACM
+            config TEST_USBH_HID
+                int
+                prompt "demo for test hid"
+                default 0
+                depends on CHERRYUSB_HOST_HID
+        endif
+    endif
+
+endif

+ 304 - 0
components/drivers/usb/cherryusb/Kconfig.cherryusb

@@ -0,0 +1,304 @@
+# Kconfig file for CherryUSB
+menuconfig CHERRYUSB
+    bool "Using CherryUSB"
+    default n
+
+if CHERRYUSB
+
+    menuconfig CHERRYUSB_DEVICE
+        bool "Enable usb device mode"
+        default n
+
+    if CHERRYUSB_DEVICE
+        choice
+            prompt "Select usb device speed"
+            default CHERRYUSB_DEVICE_SPEED_FS
+            config CHERRYUSB_DEVICE_SPEED_FS
+                bool "FS"
+            config CHERRYUSB_DEVICE_SPEED_HS
+                bool "HS"
+            config CHERRYUSB_DEVICE_SPEED_AUTO
+                bool "AUTO"
+        endchoice
+
+        choice
+            prompt "Select usb device ip, and some ip need config in usb_config.h, please check"
+            default CHERRYUSB_DEVICE_CUSTOM
+            config CHERRYUSB_DEVICE_CUSTOM
+                bool "CUSTOM (Implement it yourself)"
+            config CHERRYUSB_DEVICE_FSDEV
+                bool "fsdev"
+            config CHERRYUSB_DEVICE_DWC2_ST
+                bool "dwc2_st"
+            config CHERRYUSB_DEVICE_DWC2_ESP
+                bool "dwc2_esp"
+            config CHERRYUSB_DEVICE_DWC2_AT
+                bool "dwc2_at"
+            config CHERRYUSB_DEVICE_DWC2_GD
+                bool "dwc2_gd"
+            config CHERRYUSB_DEVICE_DWC2_CUSTOM
+                bool "dwc2_custom"
+            config CHERRYUSB_DEVICE_MUSB_STANDARD
+                bool "musb_standard"
+            config CHERRYUSB_DEVICE_MUSB_SUNXI
+                bool "musb_sunxi"
+            config CHERRYUSB_DEVICE_MUSB_CUSTOM
+                bool "musb_custom"
+            config CHERRYUSB_DEVICE_BL
+                bool "bouffalo"
+            config CHERRYUSB_DEVICE_HPM
+                bool "hpm"
+            config CHERRYUSB_DEVICE_AIC
+                bool "aic"
+            config CHERRYUSB_DEVICE_CH32
+                bool "ch32"
+            config CHERRYUSB_DEVICE_PUSB2
+                bool "pusb2"
+        endchoice
+
+        config CHERRYUSB_DEVICE_CDC_ACM
+            bool
+            prompt "Enable usb cdc acm device"
+            default n
+
+        config CHERRYUSB_DEVICE_HID
+            bool
+            prompt "Enable usb hid device"
+            default n
+
+        config CHERRYUSB_DEVICE_MSC
+            bool
+            prompt "Enable usb msc device"
+            default n
+
+        config CHERRYUSB_DEVICE_AUDIO
+            bool
+            prompt "Enable usb audio device"
+            default n
+
+        config CHERRYUSB_DEVICE_VIDEO
+            bool
+            prompt "Enable usb video device"
+            default n
+
+        config CHERRYUSB_DEVICE_CDC_RNDIS
+            bool
+            prompt "Enable usb cdc rndis device"
+            default n
+
+        config CHERRYUSB_DEVICE_CDC_ECM
+            bool
+            prompt "Enable usb cdc ecm device"
+            default n
+
+        config CHERRYUSB_DEVICE_CDC_NCM
+            bool
+            prompt "Enable usb cdc ncm device"
+            default n
+
+        config CHERRYUSB_DEVICE_DFU
+            bool
+            prompt "Enable usb dfu device"
+            default n
+
+        choice
+            prompt "Select usb device template"
+            default CHERRYUSB_DEVICE_TEMPLATE
+            config CHERRYUSB_DEVICE_TEMPLATE_NONE
+                bool "none (Implement it yourself)"
+            config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM
+                bool "cdc_acm"
+            config CHERRYUSB_DEVICE_TEMPLATE_MSC
+                bool "msc"
+            config CHERRYUSB_DEVICE_TEMPLATE_HID_KEYBOARD
+                bool "hid_keyboard"
+            config CHERRYUSB_DEVICE_TEMPLATE_HID_MOUSE
+                bool "hid_mouse"
+            config CHERRYUSB_DEVICE_TEMPLATE_HID_CUSTOM
+                bool "hid_custom"
+            config CHERRYUSB_DEVICE_TEMPLATE_VIDEO
+                bool "video"
+            config CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V1_MIC_SPEAKER
+                bool "audio_v1_mic_speaker_multichan"
+            config CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V2_MIC_SPEAKER
+                bool "audio_v2_mic_speaker_multichan"
+            config CHERRYUSB_DEVICE_TEMPLATE_CDC_RNDIS
+                bool "cdc_rndis"
+            config CHERRYUSB_DEVICE_TEMPLATE_CDC_ECM
+                bool "cdc_ecm"
+            config CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM
+                bool "cdc_ncm"
+            config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
+                bool "cdc_acm_msc"
+            config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID
+                bool "cdc_acm_msc_hid"
+            config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1
+                bool "winusbv1"
+            config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC
+                bool "winusbv2_cdc"
+            config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_HID
+                bool "winusbv2_hid"
+        endchoice
+
+    endif
+
+    menuconfig CHERRYUSB_HOST
+        bool "Enable usb host mode"
+        default n
+
+    if CHERRYUSB_HOST
+        choice
+            prompt "Select usb host ip, and some ip need config in usb_config.h, please check"
+            default CHERRYUSB_HOST_CUSTOM
+            config CHERRYUSB_HOST_CUSTOM
+                bool "CUSTOM (Implement it yourself)"
+            config CHERRYUSB_HOST_EHCI_BL
+                bool "ehci_bouffalo"
+            config CHERRYUSB_HOST_EHCI_HPM
+                bool "ehci_hpm"
+            config CHERRYUSB_HOST_EHCI_AIC
+                bool "ehci_aic"
+            config CHERRYUSB_HOST_EHCI_NUVOTON_NUC980
+                bool "ehci_nuvoton_nuc980"
+            config CHERRYUSB_HOST_EHCI_NUVOTON_MA35D0
+                bool "ehci_nuvoton_ma35d0"
+            config CHERRYUSB_HOST_EHCI_CUSTOM
+                bool "ehci_custom"
+            config CHERRYUSB_HOST_DWC2_ST
+                bool "dwc2_st"
+            config CHERRYUSB_HOST_DWC2_ESP
+                bool "dwc2_esp"
+            config CHERRYUSB_HOST_DWC2_CUSTOM
+                bool "dwc2_custom"
+            config CHERRYUSB_HOST_MUSB_STANDARD
+                bool "musb_standard"
+            config CHERRYUSB_HOST_MUSB_SUNXI
+                bool "musb_sunxi"
+            config CHERRYUSB_HOST_MUSB_CUSTOM
+                bool "musb_custom"
+            config CHERRYUSB_HOST_PUSB2
+                bool "pusb2"
+            config CHERRYUSB_HOST_XHCI
+                bool "xhci"
+        endchoice
+
+        config CHERRYUSB_HOST_CDC_ACM
+            bool
+            prompt "Enable usb cdc acm driver"
+            default n
+
+        config CHERRYUSB_HOST_HID
+            bool
+            prompt "Enable usb hid driver"
+            default n
+
+        config CHERRYUSB_HOST_MSC
+            bool
+            prompt "Enable usb msc driver"
+            default n
+
+        config CHERRYUSB_HOST_CDC_ECM
+            bool
+            prompt "Enable usb cdc ecm driver"
+            select USBHOST_PLATFORM_CDC_ECM
+            default n
+
+        config CHERRYUSB_HOST_CDC_RNDIS
+            bool
+            prompt "Enable usb rndis driver"
+            select USBHOST_PLATFORM_CDC_RNDIS
+            default n
+
+        config CHERRYUSB_HOST_CDC_NCM
+            bool
+            prompt "Enable usb cdc ncm driver"
+            select USBHOST_PLATFORM_CDC_NCM
+            default n
+
+        config CHERRYUSB_HOST_VIDEO
+            bool
+            prompt "Enable usb video driver, it is commercial charge"
+            default n
+
+        config CHERRYUSB_HOST_AUDIO
+            bool
+            prompt "Enable usb audio driver, it is commercial charge"
+            default n
+
+        config CHERRYUSB_HOST_BLUETOOTH
+            bool
+            prompt "Enable usb bluetooth driver"
+            default n
+
+        config CHERRYUSB_HOST_ASIX
+            bool
+            prompt "Enable usb asix driver"
+            select USBHOST_PLATFORM_ASIX
+            default n
+
+        config CHERRYUSB_HOST_RTL8152
+            bool
+            prompt "Enable usb rtl8152 driver"
+            select USBHOST_PLATFORM_RTL8152
+            default n
+
+        config CHERRYUSB_HOST_FTDI
+            bool
+            prompt "Enable usb ftdi driver"
+            default n
+
+        config CHERRYUSB_HOST_CH34X
+            bool
+            prompt "Enable usb ch34x driver"
+            default n
+
+        config CHERRYUSB_HOST_CP210X
+            bool
+            prompt "Enable usb cp210x driver"
+            default n
+
+        config CHERRYUSB_HOST_PL2303
+            bool
+            prompt "Enable usb pl2303 driver"
+            default n
+
+        config USBHOST_PLATFORM_CDC_ECM
+            bool
+
+        config USBHOST_PLATFORM_CDC_RNDIS
+            bool
+
+        config USBHOST_PLATFORM_CDC_NCM
+            bool
+
+        config USBHOST_PLATFORM_ASIX
+            bool
+
+        config USBHOST_PLATFORM_RTL152
+            bool
+
+        config CHERRYUSB_HOST_TEMPLATE
+            bool
+            prompt "Use usb host template"
+            default n
+
+        if CHERRYUSB_HOST_TEMPLATE
+            config TEST_USBH_CDC_ACM
+                int
+                prompt "demo for test cdc acm"
+                default 0
+                depends on CHERRYUSB_HOST_CDC_ACM
+            config TEST_USBH_HID
+                int
+                prompt "demo for test hid"
+                default 0
+                depends on CHERRYUSB_HOST_HID
+            config TEST_USBH_MSC
+                int
+                prompt "demo for test msc, do not enable because it has used dfs instead"
+                default 0
+                depends on CHERRYUSB_HOST_MSC
+        endif
+    endif
+
+endif

+ 201 - 0
components/drivers/usb/cherryusb/LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 196 - 0
components/drivers/usb/cherryusb/README.md

@@ -0,0 +1,196 @@
+# CherryUSB
+
+[中文版](./README_zh.md)
+
+CherryUSB is a tiny, beautiful and portable USB host and device stack for embedded system with USB IP.
+
+![CherryUSB](CherryUSB.svg)
+
+## Why choose
+
+### Easy to study USB
+
+In order to make it easier for users to learn USB basics, enumeration, driver loading and IP drivers, the code has been written with the following advantages:
+
+- Lean code, simple logic, no complex C syntax
+- Tree-based programming with cascading code
+- Class-drivers and porting-drivers are templating and simplification
+- Clear API classification (slave: initialisation, registration api, command callback api, data sending and receiving api; host: initialisation, lookup api, data sending and receiving api)
+
+### Easy to use  USB
+
+In order to facilitate the use of the USB interface and to take into account the fact that users have learned about uart and dma, the following advantages have been designed for the data sending and receiving class of interface:
+
+- Equivalent to using uart tx dma/uart rx dma
+- There is no limit to the length of send and receive, the user does not need to care about the USB packetization process (the porting driver does the packetization process)
+
+### Easy to bring out USB performance
+
+Taking into account USB performance issues and trying to achieve the theoretical bandwidth of the USB hardware, the design of the data transceiver class interface has the following advantages:
+
+- Porting drivers directly to registers, no abstraction layer encapsulation
+- Memory zero copy
+- If IP has DMA then uses DMA mode (DMA with hardware packetization)
+- Unlimited length make it easier to interface with hardware DMA and take advantage of DMA
+- Subcontracting function is handled in interrupt
+
+## Directoy Structure
+
+|   Directory       |  Description            |
+|:-------------:|:---------------------------:|
+|class          |  usb class driver           |
+|common         |  usb spec macros and utils  |
+|core           |  usb core implementation    |
+|demo           |  usb device and host demo   |
+|osal           |  os wrapper                 |
+|platform       |  class support for other os |
+|docs           |  doc for guiding            |
+|port           |  usb dcd and hcd porting    |
+|tools          |  tool url                   |
+
+## Device Stack Overview
+
+CherryUSB Device Stack provides a unified framework of functions for standard device requests, CLASS requests, VENDOR requests and custom special requests. The object-oriented and chained approach allows the user to quickly get started with composite devices without having to worry about the underlying logic. At the same time, a standard dcd porting interface has been standardised for adapting different USB IPs to achieve ip-oriented programming.
+
+CherryUSB Device Stack has the following functions:
+
+- Support USB2.0 full and high speed, USB3.0 super speed
+- Support endpoint irq callback register by users, let users do whatever they wants in endpoint irq callback.
+- Support Composite Device
+- Support Communication Device Class (CDC_ACM, CDC_ECM)
+- Support Human Interface Device (HID)
+- Support Mass Storage Class (MSC)
+- Support USB VIDEO CLASS (UVC1.0、UVC1.5)
+- Support USB AUDIO CLASS (UAC1.0、UAC2.0)
+- Support Device Firmware Upgrade CLASS (DFU)
+- Support USB MIDI CLASS (MIDI)
+- Support Remote NDIS (RNDIS)
+- Support WINUSB1.0、WINUSB2.0(with BOS)
+- Support Vendor class
+- Support multi device with the same USB IP
+
+CherryUSB Device Stack resource usage (GCC 10.2 with -O2):
+
+|   file        |  FLASH (Byte)  |  No Cache RAM (Byte)      |  RAM (Byte)   |  Heap (Byte)     |
+|:-------------:|:--------------:|:-------------------------:|:-------------:|:----------------:|
+|usbd_core.c    |  3516          | 256(default) + 320        | 0             | 0                |
+|usbd_cdc.c     |  392           | 0                         | 0             | 0                |
+|usbd_msc.c     |  2839          | 128 + 512(default)        | 16            | 0                |
+|usbd_hid.c     |  364           | 0                         | 0             | 0                |
+|usbd_audio.c   |  1455          | 0                         | 0             | 0                |
+|usbd_video.c   |  2494          | 0                         | 84            | 0                |
+|usbd_rndis.c   |  2109          | 3340                      | 76            | 0                |
+
+## Host Stack Overview
+
+The CherryUSB Host Stack has a standard enumeration implementation for devices mounted on roothubs and external hubs, and a standard interface for different Classes to indicate what the Class driver needs to do after enumeration and after disconnection. A standard hcd porting interface has also been standardised for adapting different USB IPs for IP-oriented programming. Finally, the host stack is managed using os, and provides osal to make a adaptation for different os.
+
+CherryUSB Host Stack has the following functions:
+
+- Automatic loading of supported Class drivers
+- Support blocking transfers and asynchronous transfers
+- Support Composite Device
+- Multi-level HUB support, expandable up to 7 levels(Testing hub with 10 ports works well,only support dwc2 and ehci now)
+- Support Communication Device Class (CDC_ACM, CDC_ECM)
+- Support Human Interface Device (HID)
+- Support Mass Storage Class (MSC)
+- Support USB Video CLASS (commercial charge)
+- Support USB Audio CLASS (commercial charge)
+- Support Remote NDIS (RNDIS)
+- Support USB Bluetooth class (support nimble and zephyr bluetooth stack, support **CLASS:0xE0** or vendor class like cdc acm)
+- Support Vendor class
+- Support USB modeswitch
+- Support multi host with the same USB IP
+
+The CherryUSB Host stack also provides the lsusb function, which allows you to view information about all mounted devices, including those on external hubs, with the help of a shell plugin.
+
+CherryUSB Host Stack resource usage (GCC 10.2 with -O2):
+
+|   file        |  FLASH (Byte)  |  No Cache RAM (Byte)            |  RAM (Byte)                 |  Heap (Byte) |
+|:-------------:|:--------------:|:-------------------------------:|:---------------------------:|:------------:|
+|usbh_core.c    |  ~7700          | 512 + 8 * (1+x) *n              | 28                          | 0            |
+|usbh_hub.c     |  ~5600          | 32 + 4* (1+x) | 12 + sizeof(struct usbh_hub) * (1+x)          | 0            |
+|usbh_cdc_acm.c |  ~1200          | 7             | 4  + sizeof(struct usbh_cdc_acm) * x          | 0            |
+|usbh_msc.c     |  ~2500          | 32            | 4  + sizeof(struct usbh_msc) * x              | 0            |
+|usbh_hid.c     |  ~1000          | 128           | 4  + sizeof(struct usbh_hid) * x              | 0            |
+|usbh_video.c   |  ~3700          | 128           | 4  + sizeof(struct usbh_video) * x            | 0            |
+|usbh_audio.c   |  ~3100          | 128           | 4  + sizeof(struct usbh_audio) * x            | 0            |
+|usbh_rndis.c   |  ~3900          | 4096 + 2 * 2048         | sizeof(struct usbh_rndis) * 1       | 0            |
+|usbh_cdc_ecm.c |  ~2500          | 2 * 1514              | sizeof(struct usbh_cdc_ecm) * 1       | 0            |
+|usbh_bluetooth.c |  ~2300        | 2 * 2048(default)   | sizeof(struct usbh_bluetooth) * 1       | 0            |
+
+Among them, `sizeof(struct usbh_hub)` and `sizeof(struct usbh_hubport)` are affected by the following macros:
+
+```
+#define CONFIG_USBHOST_MAX_EXTHUBS          1
+#define CONFIG_USBHOST_MAX_EHPORTS          4
+#define CONFIG_USBHOST_MAX_INTERFACES       8
+#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
+#define CONFIG_USBHOST_MAX_ENDPOINTS        4
+```
+
+x is affected by the following macros:
+
+```
+#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
+#define CONFIG_USBHOST_MAX_HID_CLASS     4
+#define CONFIG_USBHOST_MAX_MSC_CLASS     2
+#define CONFIG_USBHOST_MAX_AUDIO_CLASS   1
+#define CONFIG_USBHOST_MAX_VIDEO_CLASS   1
+```
+
+## USB IP Support
+
+Only standard and commercial USB IP are listed.
+
+|   IP             |  device    | host     | Support status |
+|:----------------:|:----------:|:--------:|:--------------:|
+|  OHCI(intel)     |  none      | OHCI     |  ×   |
+|  EHCI(intel)     |  none      | EHCI     |  √   |
+|  XHCI(intel)     |  none      | XHCI     |  √   |
+|  UHCI(intel)     |  none      | UHCI     |  ×  |
+|  DWC2(synopsys)  |  DWC2      | DWC2     |  √   |
+|  MUSB(mentor)    |  MUSB      | MUSB     |  √   |
+|  FOTG210(faraday)|  FOTG210   | EHCI     |  √   |
+|  CDNS2(cadence)  |  CDNS2     | CDNS2    |  √   |
+|  CDNS3(cadence)  |  CDNS3     | XHCI     |  ×   |
+|  DWC3(synopsys)  |  DWC3      | XHCI     |  ×   |
+
+## Documentation Tutorial
+
+Quickly start, USB basic concepts, API manual, Class basic concepts and examples, see [CherryUSB Documentation Tutorial](https://cherryusb.readthedocs.io/)
+
+## Video Tutorial
+
+USB basic concepts and how the CherryUSB Device stack is implemented, see [CherryUSB Device Stack Tutorial](https://www.bilibili.com/video/BV1Ef4y1t73d).
+
+## Graphical Config Tool
+
+[chryusb_configurator](https://github.com/Egahp/chryusb_configurator) is written in **electron + vite2 + ts** framework,currently used to automate the generation of descriptor arrays, with additional functionality to be added later.
+
+## Demo Repo
+
+|   Manufacturer       |  CHIP or Series    | USB IP| Repo Url | Support version     | Support status |
+|:--------------------:|:------------------:|:-----:|:--------:|:------------------:|:-------------:|
+|Bouffalolab    |  BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/bouffalo_sdk)|<= latest | Long-term |
+|ST    |  STM32F1x | fsdev |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Long-term |
+|ST    |  STM32F4/STM32H7 | dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Long-term |
+|HPMicro    |  HPM6750 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/hpm_sdk)|<= latest | Long-term |
+|Essemi    |  ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Long-term |
+|Phytium |  e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.2  | Long-term |
+|artinchip |  d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest  | Long-term |
+|Espressif    |  esp32s2/esp32s3 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | the same with ST |
+|AllwinnerTech    |  F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with Essemi |
+|WCH    |  CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2 | TBD |
+|Nordicsemi |  Nrf52840 | nrf5x |[nrf5x_repo](https://github.com/CherryUSB/cherryusb_nrf5x)|<= v0.10.2 | No more updated |
+|Raspberry pi |  rp2040 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|<= v0.10.2 | No more updated |
+
+## Contact
+
+CherryUSB discord: https://discord.com/invite/wFfvrSAey8.
+
+## Company Support
+
+Thanks to the following companies for their support (in no particular order).
+
+<img src="docs/assets/bouffalolab.jpg"  width="100" height="100"/> <img src="docs/assets/hpmicro.jpg"  width="100" height="100" /> <img src="docs/assets/eastsoft.jpg"  width="100" height="100" /> <img src="docs/assets/rtthread.jpg"  width="100" height="100" /> <img src="docs/assets/sophgo.jpg"  width="100" height="100" /> <img src="docs/assets/phytium.jpg"  width="100" height="100" /> <img src="docs/assets/thead.jpg"  width="100" height="100" /> <img src="docs/assets/nuvoton.jpg"  width="100" height="100" /> <img src="docs/assets/artinchip.jpg"  width="100" height="100" />

+ 198 - 0
components/drivers/usb/cherryusb/README_zh.md

@@ -0,0 +1,198 @@
+# CherryUSB
+
+[English](./README.md)
+
+CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统(带 USB IP)的 USB 主从协议栈。
+
+![CherryUSB](CherryUSB.svg)
+
+## 为什么选择
+
+### 易于学习 USB
+
+为了方便用户学习 USB 基本知识、枚举、驱动加载、IP 驱动,因此,编写的代码具备以下优点:
+
+- 代码精简,逻辑简单,无复杂 C 语言语法
+- 树状化编程,代码层层递进
+- Class 驱动和 porting 驱动模板化、精简化
+- API 分类清晰(从机:初始化、注册类、命令回调类、数据收发类;主机:初始化、查找类、数据收发类)
+
+### 易于使用 USB
+
+为了方便用户使用 USB 接口,考虑到用户学习过 uart 和 dma,因此,设计的数据收发类接口具备以下优点:
+
+- 等价于使用 uart tx dma/uart rx dma
+- 收发长度没有限制,用户不需要关心 USB 分包过程(porting 驱动做分包过程)
+
+### 易于发挥 USB 性能
+
+考虑到 USB 性能问题,尽量达到 USB 硬件理论带宽,因此,设计的数据收发类接口具备以下优点:
+
+- Porting 驱动直接对接寄存器,无抽象层封装
+- Memory zero copy
+- IP 如果带 DMA 则使用 DMA 模式(DMA 带硬件分包功能)
+- 长度无限制,方便对接硬件 DMA 并且发挥 DMA 的优势
+- 分包功能在中断中处理
+
+## 目录结构
+
+|   目录名       |  描述                          |
+|:-------------:|:-------------------------------:|
+|class          |  usb class 类主从驱动           |
+|common         |  usb spec 定义、常用宏、标准接口定义 |
+|core           |  usb 主从协议栈核心实现          |
+|demo           |  主从 class demo                 |
+|docs           |  文档                            |
+|osal           |  os 封装层                       |
+|platform       |  其他 os 全家桶适配              |
+|port           |  usb 主从需要实现的 porting 接口 |
+|tools          |  工具链接                        |
+
+## Device 协议栈简介
+
+CherryUSB Device 协议栈对标准设备请求、CLASS 请求、VENDOR 请求以及 custom 特殊请求规范了一套统一的函数框架,采用面向对象和链表的方式,能够使得用户快速上手复合设备,不用管底层的逻辑。同时,规范了一套标准的 dcd porting 接口,用于适配不同的 USB IP,达到面向 ip 编程。
+
+CherryUSB Device 协议栈当前实现以下功能:
+
+- 支持 USB2.0 全速和高速设备,USB3.0 超速设备
+- 支持端点中断注册功能,porting 给用户自己处理中断里的数据
+- 支持复合设备
+- 支持 Communication Device Class (CDC_ACM, CDC_ECM)
+- 支持 Human Interface Device (HID)
+- 支持 Mass Storage Class (MSC)
+- 支持 USB VIDEO CLASS (UVC1.0、UVC1.5)
+- 支持 USB AUDIO CLASS (UAC1.0、UAC2.0)
+- 支持 Device Firmware Upgrade CLASS (DFU)
+- 支持 USB MIDI CLASS (MIDI)
+- 支持 Remote NDIS (RNDIS)
+- 支持 WINUSB1.0、WINUSB2.0(带 BOS )
+- 支持 Vendor 类 class
+- 支持相同 USB IP 的多从机
+
+CherryUSB Device 协议栈资源占用说明(GCC 10.2 with -O2):
+
+|   file        |  FLASH (Byte)  |  No Cache RAM (Byte)      |  RAM (Byte)   |  Heap (Byte)     |
+|:-------------:|:--------------:|:-------------------------:|:-------------:|:----------------:|
+|usbd_core.c    |  3516          | 256(default) + 320        | 0             | 0                |
+|usbd_cdc.c     |  392           | 0                         | 0             | 0                |
+|usbd_msc.c     |  2839          | 128 + 512(default)        | 16            | 0                |
+|usbd_hid.c     |  364           | 0                         | 0             | 0                |
+|usbd_audio.c   |  1455          | 0                         | 0             | 0                |
+|usbd_video.c   |  2494          | 0                         | 84            | 0                |
+|usbd_rndis.c   |  2109          | 3340                      | 76            | 0                |
+
+## Host 协议栈简介
+
+CherryUSB Host 协议栈对挂载在 roothub、外部 hub 上的设备规范了一套标准的枚举实现,对不同的 Class 类也规范了一套标准接口,用来指示在枚举后和断开连接后该 Class 驱动需要做的事情。同时,规范了一套标准的 hcd porting 接口,用于适配不同的 USB IP,达到面向 IP 编程。最后,协议栈使用 OS 管理,并提供了 osal 用来适配不同的 os。
+
+CherryUSB Host 协议栈当前实现以下功能:
+
+- 自动加载支持的Class 驱动
+- 支持阻塞式传输和异步传输
+- 支持复合设备
+- 支持多级 HUB,最高可拓展到 7 级(目前测试 1拖 10 没有问题,当前仅支持 dwc2 和 ehci)
+- 支持 Communication Device Class (CDC_ACM, CDC_ECM)
+- 支持 Human Interface Device (HID)
+- 支持 Mass Storage Class (MSC)
+- Support USB Video CLASS(商业收费)
+- Support USB Audio CLASS(商业收费)
+- 支持 Remote NDIS (RNDIS)
+- 支持 USB Bluetooth (支持 nimble and zephyr bluetooth 协议栈,支持 **CLASS: 0xE0** 或者厂家自定义类,类似于 cdc acm 功能)
+- 支持 Vendor 类 class
+- 支持 USB modeswitch
+- 支持相同 USB IP 的多主机
+
+同时,CherryUSB Host 协议栈还提供了 lsusb 的功能,借助 shell 插件可以查看所有挂载设备的信息,包括外部 hub 上的设备的信息。
+
+CherryUSB Host 协议栈资源占用说明(GCC 10.2 with -O2):
+
+|   file        |  FLASH (Byte)  |  No Cache RAM (Byte)            |  RAM (Byte)                 |  Heap (Byte) |
+|:-------------:|:--------------:|:-------------------------------:|:---------------------------:|:------------:|
+|usbh_core.c    |  ~7700          | 512 + 8 * (1+x) *n              | 28                          | 0            |
+|usbh_hub.c     |  ~5600          | 32 + 4* (1+x) | 12 + sizeof(struct usbh_hub) * (1+x)          | 0            |
+|usbh_cdc_acm.c |  ~1200          | 7             | 4  + sizeof(struct usbh_cdc_acm) * x          | 0            |
+|usbh_msc.c     |  ~2500          | 32            | 4  + sizeof(struct usbh_msc) * x              | 0            |
+|usbh_hid.c     |  ~1000          | 128           | 4  + sizeof(struct usbh_hid) * x              | 0            |
+|usbh_video.c   |  ~3700          | 128           | 4  + sizeof(struct usbh_video) * x            | 0            |
+|usbh_audio.c   |  ~3100          | 128           | 4  + sizeof(struct usbh_audio) * x            | 0            |
+|usbh_rndis.c   |  ~3900          | 4096 + 2 * 2048         | sizeof(struct usbh_rndis) * 1       | 0            |
+|usbh_cdc_ecm.c |  ~2500          | 2 * 1514              | sizeof(struct usbh_cdc_ecm) * 1       | 0            |
+|usbh_bluetooth.c |  ~2300        | 2 * 2048(default)   | sizeof(struct usbh_bluetooth) * 1       | 0            |
+
+其中,`sizeof(struct usbh_hub)` 和 `sizeof(struct usbh_hubport)` 受以下宏影响:
+
+```
+#define CONFIG_USBHOST_MAX_EXTHUBS          1
+#define CONFIG_USBHOST_MAX_EHPORTS          4
+#define CONFIG_USBHOST_MAX_INTERFACES       8
+#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
+#define CONFIG_USBHOST_MAX_ENDPOINTS        4
+```
+
+x 受以下宏影响:
+
+```
+#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
+#define CONFIG_USBHOST_MAX_HID_CLASS     4
+#define CONFIG_USBHOST_MAX_MSC_CLASS     2
+#define CONFIG_USBHOST_MAX_AUDIO_CLASS   1
+#define CONFIG_USBHOST_MAX_VIDEO_CLASS   1
+```
+
+## USB IP 支持情况
+
+仅列举标准 USB IP 和商业性 USB IP
+
+|   IP             |  device    | host     | Support status |
+|:----------------:|:----------:|:--------:|:--------------:|
+|  OHCI(intel)     |  none      | OHCI     |  ×   |
+|  EHCI(intel)     |  none      | EHCI     |  √   |
+|  XHCI(intel)     |  none      | XHCI     |  √   |
+|  UHCI(intel)     |  none      | UHCI     |  ×  |
+|  DWC2(synopsys)  |  DWC2      | DWC2     |  √   |
+|  MUSB(mentor)    |  MUSB      | MUSB     |  √   |
+|  FOTG210(faraday)|  FOTG210   | EHCI     |  √   |
+|  CDNS2(cadence)  |  CDNS2     | CDNS2    |  √   |
+|  CDNS3(cadence)  |  CDNS3     | XHCI     |  ×   |
+|  DWC3(synopsys)  |  DWC3      | XHCI     |  ×   |
+
+## 文档教程
+
+CherryUSB 快速入门、USB 基本概念,API 手册,Class 基本概念和例程,参考 [CherryUSB Documentation Tutorial](https://cherryusb.readthedocs.io/)
+
+## 视频教程
+
+- USB 基本知识点与 CherryUSB Device 协议栈是如何编写的(使用v0.4.1 版本),参考 https://www.bilibili.com/video/BV1Ef4y1t73d.
+- CherryUSB 腾讯会议(使用v1.1.0 版本),参考 https://www.bilibili.com/video/BV16x421y7mM.
+
+## 图形化界面配置工具
+
+[chryusb_configurator](https://github.com/Egahp/chryusb_configurator) 采用 **electron + vite2 + ts** 框架编写,当前用于自动化生成描述符数组,后续会增加其他功能。
+
+## 示例仓库
+
+|   Manufacturer       |  CHIP or Series    | USB IP| Repo Url | Support version     | Support status |
+|:--------------------:|:------------------:|:-----:|:--------:|:------------------:|:-------------:|
+|Bouffalolab    |  BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/bouffalo_sdk)|<= latest | Long-term |
+|ST    |  STM32F1x | fsdev |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Long-term |
+|ST    |  STM32F4/STM32H7 | dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Long-term |
+|HPMicro    |  HPM6750 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/hpm_sdk)|<= latest | Long-term |
+|Essemi    |  ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Long-term |
+|Phytium |  e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.2  | Long-term |
+|artinchip |  d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest  | Long-term |
+|Espressif    |  esp32s2/esp32s3 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | the same with ST |
+|AllwinnerTech    |  F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with Essemi |
+|WCH    |  CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2 | TBD |
+|Nordicsemi |  Nrf52840 | nrf5x |[nrf5x_repo](https://github.com/CherryUSB/cherryusb_nrf5x)|<= v0.10.2 | No more updated |
+|Raspberry pi |  rp2040 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|<= v0.10.2 | No more updated |
+
+## Contact
+
+CherryUSB QQ 群:642693751
+CherryUSB 微信群:与我联系后邀请加入
+
+## 支持企业
+
+感谢以下企业支持(顺序不分先后)。
+
+<img src="docs/assets/bouffalolab.jpg"  width="100" height="100"/> <img src="docs/assets/hpmicro.jpg"  width="100" height="100" /> <img src="docs/assets/eastsoft.jpg"  width="100" height="100" /> <img src="docs/assets/rtthread.jpg"  width="100" height="100" /> <img src="docs/assets/sophgo.jpg"  width="100" height="100" /> <img src="docs/assets/phytium.jpg"  width="100" height="100" /> <img src="docs/assets/thead.jpg"  width="100" height="100" /> <img src="docs/assets/nuvoton.jpg"  width="100" height="100" /> <img src="docs/assets/artinchip.jpg"  width="100" height="100" />

+ 210 - 0
components/drivers/usb/cherryusb/SConscript

@@ -0,0 +1,210 @@
+from building import *
+
+cwd = GetCurrentDir()
+path = [cwd + '/common']
+path += [cwd + '/core']
+path += [cwd + '/class/cdc']
+path += [cwd + '/class/msc']
+path += [cwd + '/class/hid']
+path += [cwd + '/class/audio']
+path += [cwd + '/class/video']
+path += [cwd + '/class/wireless']
+path += [cwd + '/class/dfu']
+path += [cwd + '/class/midi']
+path += [cwd + '/class/vendor/net']
+path += [cwd + '/class/vendor/serial']
+src = []
+
+CPPDEFINES = []
+
+# USB DEVICE
+if GetDepend(['RT_CHERRYUSB_DEVICE']):
+    path += [cwd + '/osal']
+    src += Glob('core/usbd_core.c')
+    src += Glob('osal/usb_osal_rtthread.c')
+
+    if GetDepend(['RT_CHERRYUSB_DEVICE_SPEED_HS']):
+        CPPDEFINES+=['CONFIG_USB_HS']
+
+    if GetDepend(['RT_CHERRYUSB_DEVICE_FSDEV']):
+        src += Glob('port/fsdev/usb_dc_fsdev.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_ST']):
+        src += Glob('port/dwc2/usb_dc_dwc2.c')
+        src += Glob('port/dwc2/usb_glue_st.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_ESP']):
+        src += Glob('port/dwc2/usb_dc_dwc2.c')
+        src += Glob('port/dwc2/usb_glue_esp.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_AT']):
+        src += Glob('port/dwc2/usb_dc_dwc2.c')
+        src += Glob('port/dwc2/usb_glue_at.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_GD']):
+        src += Glob('port/dwc2/usb_dc_dwc2.c')
+        src += Glob('port/dwc2/usb_glue_gd.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_CUSTOM']):
+        src += Glob('port/dwc2/usb_dc_dwc2.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_MUSB_STANDARD']):
+        src += Glob('port/musb/usb_dc_musb.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_MUSB_SUNXI']):
+        src += Glob('port/musb/usb_dc_musb.c')
+        src += Glob('port/musb/usb_glue_sunxi.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_MUSB_CUSTOM']):
+        src += Glob('port/musb/usb_dc_musb.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_BL']):
+        src += Glob('port/bouffalolab/usb_dc_bl.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_HPM']):
+        src += Glob('port/hpm/usb_dc_hpm.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_AIC']):
+        src += Glob('port/aic/usb_dc_aic.c')
+        src += Glob('port/aic/usb_dc_aic_ll.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_CH32']):
+        if GetDepend(['RT_CHERRYUSB_DEVICE_SPEED_HS']):
+            src += Glob('port/ch32/usb_dc_usbhs.c')
+        else:
+            src += Glob('port/ch32/usb_dc_usbfs.c')
+
+    if GetDepend(['RT_CHERRYUSB_DEVICE_CDC_ACM']):
+        src += Glob('class/cdc/usbd_cdc.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_HID']):
+        src += Glob('class/hid/usbd_hid.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_MSC']):
+        src += Glob('class/msc/usbd_msc.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_AUDIO']):
+        src += Glob('class/audio/usbd_audio.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_VIDEO']):
+        src += Glob('class/video/usbd_video.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_CDC_RNDIS']):
+        src += Glob('class/wireless/usbd_rndis.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_CDC_ECM']):
+        src += Glob('class/cdc/usbd_cdc_ecm.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_CDC_NCM']):
+        src += Glob('class/cdc/usbd_cdc_ncm.c')
+    if GetDepend(['RT_CHERRYUSB_USING_DFU']):
+        src += Glob('class/dfu/usbd_dfu.c')
+
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM']):
+        src += Glob('demo/cdc_acm_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_MSC']):
+        src += Glob('demo/msc_ram_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_HID_MOUSE']):
+        src += Glob('demo/hid_mouse_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_HID_KEYBOARD']):
+        src += Glob('demo/hid_keyboard_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_HID_CUSTOM']):
+        src += Glob('demo/hid_custom_inout_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_VIDEO']):
+        src += Glob('demo/video_static_mjpeg_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V1_MIC_SPEAKER']):
+        src += Glob('demo/audio_v1_mic_speaker_multichan_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V2_MIC_SPEAKER']):
+        src += Glob('demo/audio_v2_mic_speaker_multichan_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_RNDIS']):
+        src += Glob('demo/cdc_rndis_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ECM']):
+        src += Glob('demo/cdc_ecm_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM']):
+        src += Glob('demo/cdc_ncm_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC']):
+        src += Glob('demo/cdc_acm_msc_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID']):
+        src += Glob('demo/cdc_acm_hid_msc_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1']):
+        src += Glob('demo/winusb1.0_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC']):
+        src += Glob('demo/winusb2.0_cdc_template.c')
+    if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_HID']):
+        src += Glob('demo/winusb2.0_hid_template.c')
+
+# USB HOST
+if GetDepend(['RT_CHERRYUSB_HOST']):
+    path += [cwd + '/class/hub']
+    src += Glob('core/usbh_core.c')
+    src += Glob('class/hub/usbh_hub.c')
+    src += Glob('osal/usb_osal_rtthread.c')
+
+    if GetDepend(['RT_CHERRYUSB_HOST_EHCI_BL']):
+        src += Glob('port/ehci/usb_hc_ehci.c')
+        src += Glob('port/ehci/usb_glue_bouffalo.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_EHCI_HPM']):
+        src += Glob('port/ehci/usb_hc_ehci.c')
+        src += Glob('port/ehci/usb_glue_hpm.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_EHCI_AIC']):
+        path += [cwd + '/port/ehci']
+        path += [cwd + '/port/ohci']
+        src += Glob('port/ehci/usb_hc_ehci.c')
+        src += Glob('port/ehci/usb_glue_aic.c')
+        src += Glob('port/ohci/usb_hc_ohci.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_EHCI_NUVOTON_NUC980']):
+        src += Glob('port/ehci/usb_hc_ehci.c')
+        src += Glob('port/ehci/usb_glue_nuc980.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_EHCI_NUVOTON_MA35D0']):
+        src += Glob('port/ehci/usb_hc_ehci.c')
+        src += Glob('port/ehci/usb_glue_ma35d0.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_EHCI_CUSTOM']):
+        src += Glob('port/ehci/usb_hc_ehci.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_DWC2_ST']):
+        src += Glob('port/dwc2/usb_hc_dwc2.c')
+        src += Glob('port/dwc2/usb_glue_st.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_DWC2_ESP']):
+        src += Glob('port/dwc2/usb_hc_dwc2.c')
+        src += Glob('port/dwc2/usb_glue_esp.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_DWC2_CUSTOM']):
+        src += Glob('port/dwc2/usb_hc_dwc2.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_MUSB_STANDARD']):
+        src += Glob('port/musb/usb_hc_musb.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_MUSB_SUNXI']):
+        src += Glob('port/musb/usb_hc_musb.c')
+        src += Glob('port/musb/usb_glue_sunxi.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_MUSB_CUSTOM']):
+        src += Glob('port/musb/usb_hc_musb.c')
+
+    if GetDepend(['RT_CHERRYUSB_HOST_CDC_ACM']):
+        src += Glob('class/cdc/usbh_cdc_acm.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_HID']):
+        src += Glob('class/hid/usbh_hid.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_MSC']):
+        src += Glob('class/msc/usbh_msc.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_CDC_RNDIS']):
+        src += Glob('class/wireless/usbh_rndis.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_CDC_ECM']):
+        src += Glob('class/cdc/usbh_cdc_ecm.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_CDC_NCM']):
+        src += Glob('class/cdc/usbh_cdc_ncm.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_VIDEO']):
+        src += Glob('class/video/usbh_video.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_AUDIO']):
+        src += Glob('class/audio/usbh_audio.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_BLUETOOTH']):
+        src += Glob('class/wireless/usbh_bluetooth.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_ASIX']):
+        src += Glob('class/vendor/net/usbh_asix.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_RTL8152']):
+        src += Glob('class/vendor/net/usbh_rtl8152.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_FTDI']):
+        src += Glob('class/vendor/serial/usbh_ftdi.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_CH34X']):
+        src += Glob('class/vendor/serial/usbh_ch34x.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_CP210X']):
+        src += Glob('class/vendor/serial/usbh_cp210x.c')
+    if GetDepend(['RT_CHERRYUSB_HOST_PL2303']):
+        src += Glob('class/vendor/serial/usbh_pl2303.c')
+
+    if GetDepend(['RT_CHERRYUSB_HOST_TEMPLATE']):
+        src += Glob('demo/usb_host.c')
+
+    if GetDepend('RT_USING_DFS') and GetDepend(['RT_CHERRYUSB_HOST_MSC']):
+       src += Glob('platform/rtthread/usbh_dfs.c')
+
+    if GetDepend('RT_CHERRYUSB_HOST_CDC_ECM') \
+        or GetDepend('RT_CHERRYUSB_HOST_CDC_RNDIS') \
+        or GetDepend('RT_CHERRYUSB_HOST_CDC_NCM') \
+        or GetDepend('RT_CHERRYUSB_HOST_CDC_ASIX') \
+        or GetDepend('RT_CHERRYUSB_HOST_CDC_RTL8152'):
+        src += Glob('platform/rtthread/usbh_lwip.c')
+
+src += Glob('platform/rtthread/usb_msh.c')
+src += Glob('platform/rtthread/usb_check.c')
+
+group = DefineGroup('CherryUSB', src, depend = ['RT_USING_CHERRYUSB'], CPPPATH = path, CPPDEFINES = CPPDEFINES)
+
+Return('group')
+

+ 5 - 0
components/drivers/usb/cherryusb/VERSION

@@ -0,0 +1,5 @@
+VERSION_MAJOR = 1
+VERSION_MINOR = 3
+PATCHLEVEL = 0
+VERSION_TWEAK = 0
+EXTRAVERSION = 0

+ 241 - 0
components/drivers/usb/cherryusb/cherryusb.cmake

@@ -0,0 +1,241 @@
+#
+# Copyright (c) 2024, sakumisu
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+# set(CONFIG_CHERRYUSB_DEVICE 1)
+# set(CONFIG_CHERRYUSB_DEVICE_CDC 1)
+# set(CONFIG_CHERRYUSB_DEVICE_HID 1)
+# set(CONFIG_CHERRYUSB_DEVICE_MSC 1)
+# set(CONFIG_CHERRYUSB_DEVICE_DCD "dwc2_st")
+
+# set(CONFIG_CHERRYUSB_HOST 1)
+# set(CONFIG_CHERRYUSB_HOST_CDC_ACM 1)
+# set(CONFIG_CHERRYUSB_HOST_CDC_ECM 1)
+# set(CONFIG_CHERRYUSB_HOST_CDC_NCM 1)
+# set(CONFIG_CHERRYUSB_HOST_HID 1)
+# set(CONFIG_CHERRYUSB_HOST_MSC 1)
+# set(CONFIG_CHERRYUSB_HOST_VIDEO 1)
+# set(CONFIG_CHERRYUSB_HOST_AUDIO 1)
+# set(CONFIG_CHERRYUSB_HOST_CDC_RNDIS 1)
+# set(CONFIG_CHERRYUSB_HOST_BLUETOOTH 1)
+# set(CONFIG_CHERRYUSB_HOST_ASIX 1)
+# set(CONFIG_CHERRYUSB_HOST_RTL8152 1)
+# set(CONFIG_CHERRYUSB_OSAL "freertos")
+# set(CONFIG_CHERRYUSB_HOST_HCD "ehci_xxx")
+
+list(APPEND cherryusb_incs
+${CMAKE_CURRENT_LIST_DIR}/common
+${CMAKE_CURRENT_LIST_DIR}/core
+${CMAKE_CURRENT_LIST_DIR}/class/hub
+${CMAKE_CURRENT_LIST_DIR}/class/cdc
+${CMAKE_CURRENT_LIST_DIR}/class/hid
+${CMAKE_CURRENT_LIST_DIR}/class/msc
+${CMAKE_CURRENT_LIST_DIR}/class/audio
+${CMAKE_CURRENT_LIST_DIR}/class/video
+${CMAKE_CURRENT_LIST_DIR}/class/wireless
+${CMAKE_CURRENT_LIST_DIR}/class/midi
+${CMAKE_CURRENT_LIST_DIR}/class/vendor/net
+${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial
+)
+
+if(CONFIG_CHERRYUSB_DEVICE)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/core/usbd_core.c)
+    if(CONFIG_CHERRYUSB_DEVICE_CDC)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbd_cdc.c)
+    endif()
+    if(CONFIG_CHERRYUSB_DEVICE_HID)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/hid/usbd_hid.c)
+    endif()
+    if(CONFIG_CHERRYUSB_DEVICE_MSC)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/msc/usbd_msc.c)
+    endif()
+    if(CONFIG_CHERRYUSB_DEVICE_AUDIO)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/audio/usbd_audio.c)
+    endif()
+    if(CONFIG_CHERRYUSB_DEVICE_VIDEO)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/video/usbd_video.c)
+    endif()
+    if(CONFIG_CHERRYUSB_DEVICE_CDC_ECM)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbd_cdc_ecm.c)
+    endif()
+    if(CONFIG_CHERRYUSB_DEVICE_CDC_NCM)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbd_cdc_ncm.c)
+    endif()
+    if(CONFIG_CHERRYUSB_DEVICE_CDC_RNDIS)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/wireless/usbd_rndis.c)
+    endif()
+    if(CONFIG_CHERRYUSB_DEVICE_DFU)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/dfu/usbd_dfu.c)
+    endif()
+
+    if(DEFINED CONFIG_CHERRYUSB_DEVICE_DCD)
+        if("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "dwc2_st")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_dc_dwc2.c)
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_st.c)
+        elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "dwc2_esp")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_dc_dwc2.c)
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_esp.c)
+        elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "dwc2_aic")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_dc_dwc2.c)
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_aic.c)
+        elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "dwc2_at")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_dc_dwc2.c)
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_at.c)
+        elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "fsdev")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/fsdev/usb_dc_fsdev.c)
+        elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "hpm")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/hpm/usb_dc_hpm.c)
+        elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "bl")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/bouffalolab/usb_dc_bl.c)
+        elseif("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "musb")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_dc_musb.c)
+        endif()
+    endif()
+
+endif()
+
+if(CONFIG_CHERRYUSB_HOST)
+    list(APPEND cherryusb_srcs
+    ${CMAKE_CURRENT_LIST_DIR}/core/usbh_core.c
+    ${CMAKE_CURRENT_LIST_DIR}/class/hub/usbh_hub.c
+    )
+
+    if(CONFIG_CHERRYUSB_HOST_CDC_ACM)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbh_cdc_acm.c)
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_CDC_ECM)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbh_cdc_ecm.c)
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_CDC_NCM)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbh_cdc_ncm.c)
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_HID)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/hid/usbh_hid.c)
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_MSC)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/msc/usbh_msc.c)
+
+    if(CONFIG_CHERRYUSB_HOST_MSC_FATFS)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/port/fatfs_usbh.c)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/diskio.c)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/ff.c)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/ffsystem.c)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source/ffunicode.c)
+
+    list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/third_party/fatfs-0.14/source)
+    endif()
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_VIDEO)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/video/usbh_video.c)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherryrb/chry_ringbuffer.c)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrypool/chry_pool.c)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrypool/usbh_uvc_queue.c)
+    list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherryrb)
+    list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrypool)
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_AUDIO)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/audio/usbh_audio.c)
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_CDC_RNDIS)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/wireless/usbh_rndis.c)
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_BLUETOOTH)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/wireless/usbh_bluetooth.c)
+
+    set(BLUETOOTH_PATH ${CMAKE_CURRENT_LIST_DIR}/third_party/zephyr_bluetooth-2.7.5)
+
+    list(APPEND cherryusb_srcs
+    ${BLUETOOTH_PATH}/ble_hci_usbh.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/beacon/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central_hr/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central_ht/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central_multilink/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/central_multilink/src/central_multilink.c
+    # ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/handsfree/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/ibeacon/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral/src/cts.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_csc/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_dis/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_esp/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_hids/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_hids/src/hog.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_hr/src/main.c
+    # ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_ht/src/main.c
+    # ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_ht/src/hts.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_identity/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_identity/src/peripheral_identity.c
+    # ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_ots/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/peripheral_sc_only/src/main.c
+    ${BLUETOOTH_PATH}/zephyr_bluetooth/examples/scan_adv/src/main.c
+    )
+
+    include(${BLUETOOTH_PATH}/zephyr_bluetooth/zephyr_bluetooth.cmake)
+    list(APPEND cherryusb_srcs ${zephyr_bluetooth_srcs})
+    list(APPEND cherryusb_incs ${zephyr_bluetooth_incs})
+    endif()
+
+    if(CONFIG_CHERRYUSB_HOST_ASIX)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/net/usbh_asix.c)
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_RTL8152)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/net/usbh_rtl8152.c)
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_CH34X)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_ch34x.c)
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_CP210X)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_cp210x.c)
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_FTDI)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_ftdi.c)
+    endif()
+    if(CONFIG_CHERRYUSB_HOST_PL2303)
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_pl2303.c)
+    endif()
+
+    if(DEFINED CONFIG_CHERRYUSB_HOST_HCD)
+        if("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "ehci_bouffalo")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
+        #list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_glue_bouffalo.c)
+        list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
+        elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "ehci_hpm")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
+        #list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_glue_hpm.c)
+        list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
+        elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "ehci_aic")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
+        #list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_glue_aic.c)
+        list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
+        elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "ehci_nuvoton")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
+        #list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_glue_nuvoton.c)
+        elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "dwc2_st")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_hc_dwc2.c)
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_st.c)
+        elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "dwc2_esp")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_hc_dwc2.c)
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/dwc2/usb_glue_esp.c)
+        elseif("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "musb")
+        list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/musb/usb_hc_musb.c)
+        endif()
+    endif()
+
+endif()
+
+if(DEFINED CONFIG_CHERRYUSB_OSAL)
+    if("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "freertos")
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/osal/usb_osal_freertos.c)
+    elseif("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "rtthread")
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/osal/usb_osal_rtthread.c)
+    elseif("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "yoc")
+    list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/osal/usb_osal_yoc.c)
+    endif()
+endif()

+ 261 - 0
components/drivers/usb/cherryusb/cherryusb_config_template.h

@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef CHERRYUSB_CONFIG_H
+#define CHERRYUSB_CONFIG_H
+
+#define CHERRYUSB_VERSION     0x010300
+#define CHERRYUSB_VERSION_STR "v1.3.0"
+
+/* ================ USB common Configuration ================ */
+
+#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__)
+
+#define usb_malloc(size) malloc(size)
+#define usb_free(ptr)    free(ptr)
+
+#ifndef CONFIG_USB_DBG_LEVEL
+#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
+#endif
+
+/* Enable print with color */
+#define CONFIG_USB_PRINTF_COLOR_ENABLE
+
+/* data align size when use dma */
+#ifndef CONFIG_USB_ALIGN_SIZE
+#define CONFIG_USB_ALIGN_SIZE 4
+#endif
+
+/* attribute data into no cache ram */
+#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
+
+/* ================= USB Device Stack Configuration ================ */
+
+/* Ep0 in and out transfer buffer */
+#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
+#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
+#endif
+
+/* Setup packet log for debug */
+// #define CONFIG_USBDEV_SETUP_LOG_PRINT
+
+/* Send ep0 in data from user buffer instead of copying into ep0 reqdata
+ * Please note that user buffer must be aligned with CONFIG_USB_ALIGN_SIZE
+*/
+// #define CONFIG_USBDEV_EP0_INDATA_NO_COPY
+
+/* Check if the input descriptor is correct */
+// #define CONFIG_USBDEV_DESC_CHECK
+
+/* Enable test mode */
+// #define CONFIG_USBDEV_TEST_MODE
+
+#ifndef CONFIG_USBDEV_MSC_MAX_LUN
+#define CONFIG_USBDEV_MSC_MAX_LUN 1
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
+#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
+#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
+#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
+#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
+#endif
+
+// #define CONFIG_USBDEV_MSC_THREAD
+
+#ifndef CONFIG_USBDEV_MSC_PRIO
+#define CONFIG_USBDEV_MSC_PRIO 4
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_STACKSIZE
+#define CONFIG_USBDEV_MSC_STACKSIZE 2048
+#endif
+
+#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
+#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
+#endif
+
+/* rndis transfer buffer size, must be a multiple of (1536 + 44)*/
+#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
+#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
+#endif
+
+#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID
+#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff
+#endif
+
+#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC
+#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB"
+#endif
+
+#define CONFIG_USBDEV_RNDIS_USING_LWIP
+
+/* ================ USB HOST Stack Configuration ================== */
+
+#define CONFIG_USBHOST_MAX_RHPORTS          1
+#define CONFIG_USBHOST_MAX_EXTHUBS          1
+#define CONFIG_USBHOST_MAX_EHPORTS          4
+#define CONFIG_USBHOST_MAX_INTERFACES       8
+#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
+#define CONFIG_USBHOST_MAX_ENDPOINTS        4
+
+#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
+#define CONFIG_USBHOST_MAX_HID_CLASS     4
+#define CONFIG_USBHOST_MAX_MSC_CLASS     2
+#define CONFIG_USBHOST_MAX_AUDIO_CLASS   1
+#define CONFIG_USBHOST_MAX_VIDEO_CLASS   1
+
+#define CONFIG_USBHOST_DEV_NAMELEN 16
+
+#ifndef CONFIG_USBHOST_PSC_PRIO
+#define CONFIG_USBHOST_PSC_PRIO 0
+#endif
+#ifndef CONFIG_USBHOST_PSC_STACKSIZE
+#define CONFIG_USBHOST_PSC_STACKSIZE 2048
+#endif
+
+//#define CONFIG_USBHOST_GET_STRING_DESC
+
+// #define CONFIG_USBHOST_MSOS_ENABLE
+#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE
+#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
+#endif
+
+/* Ep0 max transfer buffer */
+#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN
+#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512
+#endif
+
+#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
+#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
+#endif
+
+#ifndef CONFIG_USBHOST_MSC_TIMEOUT
+#define CONFIG_USBHOST_MSC_TIMEOUT 5000
+#endif
+
+/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
+ * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
+ */
+#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE
+#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048)
+#endif
+
+/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
+#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE
+#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
+#endif
+
+/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
+ * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
+ */
+#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE
+#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE (2048)
+#endif
+/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
+#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE
+#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE (2048)
+#endif
+
+/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
+ * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
+ */
+#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE
+#define CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE (2048)
+#endif
+/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
+#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE
+#define CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE (2048)
+#endif
+
+#define CONFIG_USBHOST_BLUETOOTH_HCI_H4
+// #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG
+
+#ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE
+#define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048
+#endif
+#ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE
+#define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048
+#endif
+
+/* ================ USB Device Port Configuration ================*/
+
+#ifndef CONFIG_USBDEV_MAX_BUS
+#define CONFIG_USBDEV_MAX_BUS 1 // for now, bus num must be 1 except hpm ip
+#endif
+
+#ifndef CONFIG_USBDEV_EP_NUM
+#define CONFIG_USBDEV_EP_NUM 8
+#endif
+
+/* ---------------- FSDEV Configuration ---------------- */
+//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
+
+/* ---------------- DWC2 Configuration ---------------- */
+// #define CONFIG_USB_DWC2_RXALL_FIFO_SIZE (1024 / 4)
+// #define CONFIG_USB_DWC2_TX0_FIFO_SIZE (64 / 4)
+// #define CONFIG_USB_DWC2_TX1_FIFO_SIZE (512 / 4)
+// #define CONFIG_USB_DWC2_TX2_FIFO_SIZE (64 / 4)
+// #define CONFIG_USB_DWC2_TX3_FIFO_SIZE (64 / 4)
+// #define CONFIG_USB_DWC2_TX4_FIFO_SIZE (0 / 4)
+// #define CONFIG_USB_DWC2_TX5_FIFO_SIZE (0 / 4)
+// #define CONFIG_USB_DWC2_TX6_FIFO_SIZE (0 / 4)
+// #define CONFIG_USB_DWC2_TX7_FIFO_SIZE (0 / 4)
+// #define CONFIG_USB_DWC2_TX8_FIFO_SIZE (0 / 4)
+
+/* ---------------- MUSB Configuration ---------------- */
+// #define CONFIG_USB_MUSB_SUNXI
+
+/* ================ USB Host Port Configuration ==================*/
+#ifndef CONFIG_USBHOST_MAX_BUS
+#define CONFIG_USBHOST_MAX_BUS 1
+#endif
+
+#ifndef CONFIG_USBHOST_PIPE_NUM
+#define CONFIG_USBHOST_PIPE_NUM 10
+#endif
+
+/* ---------------- EHCI Configuration ---------------- */
+
+#define CONFIG_USB_EHCI_HCCR_OFFSET     (0x0)
+#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
+#define CONFIG_USB_EHCI_QH_NUM          CONFIG_USBHOST_PIPE_NUM
+#define CONFIG_USB_EHCI_QTD_NUM         3
+#define CONFIG_USB_EHCI_ITD_NUM         20
+// #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
+// #define CONFIG_USB_EHCI_CONFIGFLAG
+// #define CONFIG_USB_EHCI_ISO
+// #define CONFIG_USB_EHCI_WITH_OHCI
+
+/* ---------------- OHCI Configuration ---------------- */
+#define CONFIG_USB_OHCI_HCOR_OFFSET (0x0)
+
+/* ---------------- XHCI Configuration ---------------- */
+#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
+
+/* ---------------- DWC2 Configuration ---------------- */
+/* largest non-periodic USB packet used / 4 */
+// #define CONFIG_USB_DWC2_NPTX_FIFO_SIZE (512 / 4)
+/* largest periodic USB packet used / 4 */
+// #define CONFIG_USB_DWC2_PTX_FIFO_SIZE (1024 / 4)
+/*
+ * (largest USB packet used / 4) + 1 for status information + 1 transfer complete +
+ * 1 location each for Bulk/Control endpoint for handling NAK/NYET scenario
+ */
+// #define CONFIG_USB_DWC2_RX_FIFO_SIZE ((1012 - CONFIG_USB_DWC2_NPTX_FIFO_SIZE - CONFIG_USB_DWC2_PTX_FIFO_SIZE) / 4)
+
+/* ---------------- MUSB Configuration ---------------- */
+// #define CONFIG_USB_MUSB_SUNXI
+
+#endif

+ 1165 - 0
components/drivers/usb/cherryusb/class/audio/usb_audio.h

@@ -0,0 +1,1165 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_AUDIO_H
+#define USB_AUDIO_H
+
+/** Audio Interface Subclass Codes
+ * Refer to Table A-2 from audio10.pdf
+ */
+#define AUDIO_SUBCLASS_UNDEFINED      0x00
+#define AUDIO_SUBCLASS_AUDIOCONTROL   0x01
+#define AUDIO_SUBCLASS_AUDIOSTREAMING 0x02
+#define AUDIO_SUBCLASS_MIDISTREAMING  0x03
+
+#define AUDIO_PROTOCOL_UNDEFINED 0x00
+#define AUDIO_PROTOCOLv20        0x20 /* IP version 2.0 */
+
+/** Audio Class-Specific Request Codes
+ * Refer to Table A-9 from audio10.pdf
+ */
+#define AUDIO_REQUEST_UNDEFINED 0x00
+#define AUDIO_REQUEST_SET_CUR   0x01
+#define AUDIO_REQUEST_GET_CUR   0x81
+#define AUDIO_REQUEST_SET_MIN   0x02
+#define AUDIO_REQUEST_GET_MIN   0x82
+#define AUDIO_REQUEST_SET_MAX   0x03
+#define AUDIO_REQUEST_GET_MAX   0x83
+#define AUDIO_REQUEST_SET_RES   0x04
+#define AUDIO_REQUEST_GET_RES   0x84
+#define AUDIO_REQUEST_SET_MEM   0x05
+#define AUDIO_REQUEST_GET_MEM   0x85
+#define AUDIO_REQUEST_GET_STAT  0xFF
+
+/** Audio Class-Specific Request Codes
+ * Refer from audio20_final.pdf
+ */
+#define AUDIO_REQUEST_CUR   0x01
+#define AUDIO_REQUEST_RANGE 0x02
+/** Audio Class-Specific Control Interface Descriptor Subtypes
+ * Refer to Table A-5 from audio10.pdf
+ */
+#define AUDIO_CONTROL_UNDEF                0x01U
+#define AUDIO_CONTROL_HEADER               0x01U
+#define AUDIO_CONTROL_INPUT_TERMINAL       0x02U
+#define AUDIO_CONTROL_OUTPUT_TERMINAL      0x03U
+#define AUDIO_CONTROL_MIXER_UNIT           0x04U
+#define AUDIO_CONTROL_SELECTOR_UNIT        0x05U
+#define AUDIO_CONTROL_FEATURE_UNIT         0x06U
+#define AUDIO_CONTROL_EFFECT_UNIT          0x07U
+#define AUDIO_CONTROL_PROCESSING_UNIT      0x08U
+#define AUDIO_CONTROL_EXTENSION_UNIT       0x09U
+#define AUDIO_CONTROL_CLOCK_SOURCE         0x0aU
+#define AUDIO_CONTROL_CLOCK_SELECTOR       0x0bU
+#define AUDIO_CONTROL_CLOCK_MULTIPLIER     0x0cU
+#define AUDIO_CONTROL_SAMPLERATE_CONVERTER 0x0dU
+
+/** Audio Class-Specific AS Interface Descriptor Subtypes
+ * Refer to Table A-6 from audio10.pdf
+ */
+#define AUDIO_STREAMING_UNDEFINED   0x00U
+#define AUDIO_STREAMING_GENERAL     0x01U
+#define AUDIO_STREAMING_FORMAT_TYPE 0x02U
+#define AUDIO_STREAMING_ENCODER     0x03U
+#define AUDIO_STREAMING_DECODER     0x04U
+
+/* Clock Source Descriptor Clock Types */
+#define AUDIO_CLKSRC_EXTERNAL       0x00 /* External clock */
+#define AUDIO_CLKSRC_INTERNAL_FIXED 0x01 /* Internal fixed clock */
+#define AUDIO_CLKSRC_INTERNAL_VAR   0x02 /* Internal variable clock */
+#define AUDIO_CLKSRC_INTERNAL_PROG  0x03 /* Internal programmable clock */
+
+/* Effect Unit Effect Types */
+#define AUDIO_EFFECT_UNDEF            0x00
+#define AUDIO_EFFECT_PARAM_EQ_SECTION 0x01
+#define AUDIO_EFFECT_REVERBERATION    0x02
+#define AUDIO_EFFECT_MOD_DELAY        0x03
+#define AUDIO_EFFECT_DYN_RANGE_COMP   0x04
+
+/* Processing Unit Process Types */
+#define AUDIO_PROCESS_UNDEFINED       0x00
+#define AUDIO_PROCESS_UPDOWNMIX       0x01
+#define AUDIO_PROCESS_DOLBY_PROLOGIC  0x02
+#define AUDIO_PROCESS_STEREO_EXTENDER 0x03
+
+/* Audio Class-Specific Endpoint Descriptor Subtypes */
+#define AUDIO_ENDPOINT_UNDEFINED 0x00U
+#define AUDIO_ENDPOINT_GENERAL   0x01U
+
+/* Feature Unit Control Bits */
+#define AUDIO_CONTROL_MUTE              0x0001
+#define AUDIO_CONTROL_VOLUME            0x0002
+#define AUDIO_CONTROL_BASS              0x0004
+#define AUDIO_CONTROL_MID               0x0008
+#define AUDIO_CONTROL_TREBLE            0x0010
+#define AUDIO_CONTROL_GRAPHIC_EQUALIZER 0x0020
+#define AUDIO_CONTROL_AUTOMATIC_GAIN    0x0040
+#define AUDIO_CONTROL_DEALY             0x0080
+#define AUDIO_CONTROL_BASS_BOOST        0x0100
+#define AUDIO_CONTROL_LOUDNESS          0x0200
+
+/* Encoder Type Codes */
+#define AUDIO_ENCODER_UNDEF 0x00
+#define AUDIO_ENCODER_OTHER 0x01
+#define AUDIO_ENCODER_MPEG  0x02
+#define AUDIO_ENCODER_AC3   0x03
+#define AUDIO_ENCODER_WMA   0x04
+#define AUDIO_ENCODER_DTS   0x05
+
+/* Decoder Type Codes */
+#define AUDIO_DECODER_UNDEF 0x00
+#define AUDIO_DECODER_OTHER 0x01
+#define AUDIO_DECODER_MPEG  0x02
+#define AUDIO_DECODER_AC3   0x03
+#define AUDIO_DECODER_WMA   0x04
+#define AUDIO_DECODER_DTS   0x05
+
+/* Audio Descriptor Types */
+#define AUDIO_UNDEFINED_DESCRIPTOR_TYPE     0x20
+#define AUDIO_DEVICE_DESCRIPTOR_TYPE        0x21
+#define AUDIO_CONFIGURATION_DESCRIPTOR_TYPE 0x22
+#define AUDIO_STRING_DESCRIPTOR_TYPE        0x23
+#define AUDIO_INTERFACE_DESCRIPTOR_TYPE     0x24
+#define AUDIO_ENDPOINT_DESCRIPTOR_TYPE      0x25
+
+/* Audio Data Format Type I Codes */
+#define AUDIO_FORMAT_TYPE_I_UNDEFINED 0x0000
+#define AUDIO_FORMAT_PCM              0x0001
+#define AUDIO_FORMAT_PCM8             0x0002
+#define AUDIO_FORMAT_IEEE_FLOAT       0x0003
+#define AUDIO_FORMAT_ALAW             0x0004
+#define AUDIO_FORMAT_MULAW            0x0005
+
+#define AUDIO_V2_FORMAT_PCM              0x00000001
+#define AUDIO_V2_FORMAT_PCM8             0x00000002
+#define AUDIO_V2_FORMAT_IEEE_FLOAT       0x00000004
+#define AUDIO_V2_FORMAT_ALAW             0x00000008
+#define AUDIO_V2_FORMAT_MULAW            0x00000010
+
+/* bmChannelConfig: a bitmap field that indicates which spatial locations
+ * are occupied by the channels present in the cluster. The bit allocations
+ * are as follows:
+ */
+#define AUDIO_CHANNEL_M    0         /* Mono */
+#define AUDIO_CHANNEL_FL   (1 << 0)  /*  Front Left */
+#define AUDIO_CHANNEL_FR   (1 << 1)  /*  Front Right */
+#define AUDIO_CHANNEL_FC   (1 << 2)  /*  Front Center */
+#define AUDIO_CHANNEL_LFE  (1 << 3)  /*  Low Frequency Effects */
+#define AUDIO_CHANNEL_BL   (1 << 4)  /*  Back Left */
+#define AUDIO_CHANNEL_BR   (1 << 5)  /*  Back Right */
+#define AUDIO_CHANNEL_FLC  (1 << 6)  /*  Front Left of Center */
+#define AUDIO_CHANNEL_FRC  (1 << 7)  /*  Front Right of Center */
+#define AUDIO_CHANNEL_BC   (1 << 8)  /*  Back Center */
+#define AUDIO_CHANNEL_SL   (1 << 9)  /*  Side Left */
+#define AUDIO_CHANNEL_SR   (1 << 10) /*  Side Right */
+#define AUDIO_CHANNEL_TC   (1 << 11) /*  Top Center */
+#define AUDIO_CHANNEL_TFL  (1 << 12) /*  Top Front Left */
+#define AUDIO_CHANNEL_TFC  (1 << 13) /*  Top Front Center */
+#define AUDIO_CHANNEL_TFR  (1 << 14) /*  Top Front Right */
+#define AUDIO_CHANNEL_TBL  (1 << 15) /*  Top Back Left */
+#define AUDIO_CHANNEL_TBC  (1 << 16) /*  Top Back Center */
+#define AUDIO_CHANNEL_TBR  (1 << 17) /*  Top Back Right */
+#define AUDIO_CHANNEL_TFLC (1 << 18) /*  Top Front Left of Center */
+#define AUDIO_CHANNEL_TFRC (1 << 19) /*  Top Front Right of Center */
+#define AUDIO_CHANNEL_LLFE (1 << 20) /*  Left Low Frequency Effects */
+#define AUDIO_CHANNEL_RLFE (1 << 21) /*  Right Low Frequency Effects */
+#define AUDIO_CHANNEL_TSL  (1 << 22) /*  Top Side Left */
+#define AUDIO_CHANNEL_TSR  (1 << 23) /*  Top Side Right */
+#define AUDIO_CHANNEL_BOC  (1 << 24) /*  Bottom Center */
+#define AUDIO_CHANNEL_BLC  (1 << 25) /*  Back Left of Center */
+#define AUDIO_CHANNEL_BRC  (1 << 26) /*  Back Right of Center */
+                                     /* Bits 27-30: Reserved */
+#define AUDIO_CHANNEL_RD (1 << 31)   /*  Raw Data */
+
+/* Audio Function Category Codes */
+#define AUDIO_CATEGORY_UNDEF      0x00 /* Undefined */
+#define AUDIO_CATEGORY_SPEAKER    0x01 /* Desktop speaker */
+#define AUDIO_CATEGORY_THEATER    0x02 /* Home theater */
+#define AUDIO_CATEGORY_MICROPHONE 0x03 /* Microphone */
+#define AUDIO_CATEGORY_HEADSET    0x04 /* Headset */
+#define AUDIO_CATEGORY_TELEPHONE  0x05 /* Telephone */
+#define AUDIO_CATEGORY_CONVERTER  0x06 /* Converter */
+#define AUDIO_CATEGORY_RECORDER   0x07 /* Voice/Sound recorder */
+#define AUDIO_CATEGORY_IO_BOX     0x08 /* I/O box */
+#define AUDIO_CATEGORY_INSTRUMENT 0x09 /* Musical instrument */
+#define AUDIO_CATEGORY_PROAUDIO   0x0a /* Pro-audio */
+#define AUDIO_CATEGORY_AV         0x0b /* Audio/video */
+#define AUDIO_CATEGORY_CONTROL    0x0c /* Control panel */
+#define AUDIO_CATEGORY_OTHER      0xff
+
+/* Clock Source Control Selectors */
+#define AUDIO_CS_CONTROL_UNDEF       0x00
+#define AUDIO_CS_CONTROL_SAM_FREQ    0x01
+#define AUDIO_CS_CONTROL_CLOCK_VALID 0x02
+
+/* Clock Selector Control Selectors */
+#define AUDIO_CX_CONTROL_UNDEF    0x00
+#define AUDIO_CX_CONTROL_CLOCKSEL 0x01
+
+/* Clock Multiplier Control Selectors */
+#define AUDIO_CM_CONTROL_UNDEF       0x00
+#define AUDIO_CM_CONTROL_NUMERATOR   0x01
+#define AUDIO_CM_CONTROL_DENOMINATOR 0x02
+
+/* Terminal Control Selectors */
+#define AUDIO_TE_CONTROL_UNDEF        0x00
+#define AUDIO_TE_CONTROL_COPY_PROTECT 0x01
+#define AUDIO_TE_CONTROL_CONNECTOR    0x02
+#define AUDIO_TE_CONTROL_OVERLOAD     0x03
+#define AUDIO_TE_CONTROL_CLUSTER      0x04
+#define AUDIO_TE_CONTROL_UNDERFLOW    0x05
+#define AUDIO_TE_CONTROL_OVERFLOW     0x06
+#define AUDIO_TE_CONTROL_LATENCY      0x07
+
+/* Mixer Control Selectors */
+#define AUDIO_MU_CONTROL_UNDEF     0x00
+#define AUDIO_MU_CONTROL_MIXER     0x01
+#define AUDIO_MU_CONTROL_CLUSTER   0x02
+#define AUDIO_MU_CONTROL_UNDERFLOW 0x03
+#define AUDIO_MU_CONTROL_OVERFLOW  0x04
+#define AUDIO_MU_CONTROL_LATENCY   0x05
+
+/* Selector Control Selectors */
+#define AUDIO_SU_CONTROL_UNDEFINE 0x00
+#define AUDIO_SU_CONTROL_SELECTOR 0x01
+#define AUDIO_SU_CONTROL_LATENCY  0x02
+
+/* Feature Unit Control Selectors */
+#define AUDIO_FU_CONTROL_UNDEF        0x00
+#define AUDIO_FU_CONTROL_MUTE         0x01
+#define AUDIO_FU_CONTROL_VOLUME       0x02
+#define AUDIO_FU_CONTROL_BASS         0x03
+#define AUDIO_FU_CONTROL_MID          0x04
+#define AUDIO_FU_CONTROL_TREBLE       0x05
+#define AUDIO_FU_CONTROL_EQUALIZER    0x06
+#define AUDIO_FU_CONTROL_AGC          0x07
+#define AUDIO_FU_CONTROL_DELAY        0x08
+#define AUDIO_FU_CONTROL_BASS_BOOST   0x09
+#define AUDIO_FU_CONTROL_LOUDNESS     0x0a
+#define AUDIO_FU_CONTROL_INP_GAIN     0x0b
+#define AUDIO_FU_CONTROL_INP_GAIN_PAD 0x0c
+#define AUDIO_FU_CONTROL_PHASE_INVERT 0x0d
+#define AUDIO_FU_CONTROL_UNDERFLOW    0x0e
+#define AUDIO_FU_CONTROL_OVERFLOW     0x0f
+#define AUDIO_FU_CONTROL_LATENCY      0x10
+
+#define AUDIO_V2_FU_CONTROL_UNDEF        0x00
+#define AUDIO_V2_FU_CONTROL_MUTE         (0x03 << 0)
+#define AUDIO_V2_FU_CONTROL_VOLUME       (0x03 << 2)
+#define AUDIO_V2_FU_CONTROL_BASS         (0x03 << 4)
+#define AUDIO_V2_FU_CONTROL_MID          (0x03 << 6)
+#define AUDIO_V2_FU_CONTROL_TREBLE       (0x03 << 8)
+#define AUDIO_V2_FU_CONTROL_EQUALIZER    (0x03 << 10)
+#define AUDIO_V2_FU_CONTROL_AGC          (0x03 << 12)
+#define AUDIO_V2_FU_CONTROL_DELAY        (0x03 << 14)
+#define AUDIO_V2_FU_CONTROL_BASS_BOOST   (0x03 << 16)
+#define AUDIO_V2_FU_CONTROL_LOUDNESS     (0x03 << 18)
+#define AUDIO_V2_FU_CONTROL_INP_GAIN     (0x03 << 20)
+#define AUDIO_V2_FU_CONTROL_INP_GAIN_PAD (0x03 << 22)
+#define AUDIO_V2_FU_CONTROL_PHASE_INVERT (0x03 << 24)
+#define AUDIO_V2_FU_CONTROL_UNDERFLOW    (0x03 << 26)
+#define AUDIO_V2_FU_CONTROL_OVERFLOW     (0x03 << 28)
+
+/* Parametric Equalizer Section Effect Unit Control Selectors */
+#define AUDIO_PE_CONTROL_UNDEF      0x00
+#define AUDIO_PE_CONTROL_ENABLE     0x01
+#define AUDIO_PE_CONTROL_CENTERFREQ 0x02
+#define AUDIO_PE_CONTROL_QFACTOR    0x03
+#define AUDIO_PE_CONTROL_GAIN       0x04
+#define AUDIO_PE_CONTROL_UNDERFLOW  0x05
+#define AUDIO_PE_CONTROL_OVERFLOW   0x06
+#define AUDIO_PE_CONTROL_LATENCY    0x07
+
+/* Reverberation Effect Unit Control Selectors */
+#define AUDIO_RV_CONTROL_UNDEF      0x00
+#define AUDIO_RV_CONTROL_ENABLE     0x01
+#define AUDIO_RV_CONTROL_TYPE       0x02
+#define AUDIO_RV_CONTROL_LEVEL      0x03
+#define AUDIO_RV_CONTROL_TIME       0x04
+#define AUDIO_RV_CONTROL_FEEDBACK   0x05
+#define AUDIO_RV_CONTROL_PREDELAY   0x06
+#define AUDIO_RV_CONTROL_DENSITY    0x07
+#define AUDIO_RV_CONTROL_HF_ROLLOFF 0x08
+#define AUDIO_RV_CONTROL_UNDERFLOW  0x09
+#define AUDIO_RV_CONTROL_OVERFLOW   0x0a
+#define AUDIO_RV_CONTROL_LATENCY    0x0b
+
+/* Modulation Delay Effect Unit Control Selectors */
+#define AUDIO_MD_CONTROL_UNDEF     0x00
+#define AUDIO_MD_CONTROL_ENABLE    0x01
+#define AUDIO_MD_CONTROL_BALANCE   0x02
+#define AUDIO_MD_CONTROL_RATE      0x03
+#define AUDIO_MD_CONTROL_DEPTH     0x04
+#define AUDIO_MD_CONTROL_TIME      0x05
+#define AUDIO_MD_CONTROL_FEEDBACK  0x06
+#define AUDIO_MD_CONTROL_UNDERFLOW 0x07
+#define AUDIO_MD_CONTROL_OVERFLOW  0x08
+#define AUDIO_MD_CONTROL_LATENCY   0x09
+
+/* Dynamic Range Compressor Effect Unit Control Selectors */
+#define AUDIO_DR_CONTROL_UNDEF        0x00
+#define AUDIO_DR_CONTROL_ENABLE       0x01
+#define AUDIO_DR_CONTROL_COMP_RATE    0x02
+#define AUDIO_DR_CONTROL_MAXAMPL      0x03
+#define AUDIO_DR_CONTROL_THRESHOLD    0x04
+#define AUDIO_DR_CONTROL_ATTACK_TIME  0x05
+#define AUDIO_DR_CONTROL_RELEASE_TIME 0x06
+#define AUDIO_DR_CONTROL_UNDERFLOW    0x07
+#define AUDIO_DR_CONTROL_OVERFLOW     0x08
+#define AUDIO_DR_CONTROL_LATENCY      0x09
+
+/* Up/Down-mix Processing Unit Control Selectors */
+#define AUDIO_UD_CONTROL_UNDEF       0x00
+#define AUDIO_UD_CONTROL_ENABLE      0x01
+#define AUDIO_UD_CONTROL_MODE_SELECT 0x02
+#define AUDIO_UD_CONTROL_CLUSTER     0x03
+#define AUDIO_UD_CONTROL_UNDERFLOW   0x04
+#define AUDIO_UD_CONTROL_OVERFLOW    0x05
+#define AUDIO_UD_CONTROL_LATENCY     0x06
+
+/* Dolby Prologic?Processing Unit Control Selectors */
+#define AUDIO_DP_CONTROL_UNDEF       0x00
+#define AUDIO_DP_CONTROL_ENABLE      0x01
+#define AUDIO_DP_CONTROL_MODE_SELECT 0x02
+#define AUDIO_DP_CONTROL_CLUSTER     0x03
+#define AUDIO_DP_CONTROL_UNDERFLOW   0x04
+#define AUDIO_DP_CONTROL_OVERFLOW    0x05
+#define AUDIO_DP_CONTROL_LATENCY     0x06
+
+/* Stereo Extender Processing Unit Control Selectors */
+#define AUDIO_STEXT_CONTROL_UNDEF     0x00
+#define AUDIO_STEXT_CONTROL_ENABLE    0x01
+#define AUDIO_STEXT_CONTROL_WIDTH     0x02
+#define AUDIO_STEXT_CONTROL_UNDERFLOW 0x03
+#define AUDIO_STEXT_CONTROL_OVERFLOW  0x04
+#define AUDIO_STEXT_CONTROL_LATENCY   0x05
+
+/* Extension Unit Control Selectors */
+
+#define AUDIO_XU_CONTROL_UNDEF     0x00
+#define AUDIO_XU_CONTROL_ENABLE    0x01
+#define AUDIO_XU_CONTROL_CLUSTER   0x02
+#define AUDIO_XU_CONTROL_UNDERFLOW 0x03
+#define AUDIO_XU_CONTROL_OVERFLOW  0x04
+#define AUDIO_XU_CONTROL_LATENCY   0x05
+
+/* AudioStreaming Interface Control Selectors */
+
+#define AUDIO_AS_CONTROL_UNDEF        0x00
+#define AUDIO_AS_CONTROL_ACT_ALT      0x01
+#define AUDIO_AS_CONTROL_VAL_ALT      0x02
+#define AUDIO_AS_CONTROL_AUDIO_FORMAT 0x03
+
+/* Encoder Control Selectors */
+
+#define AUDIO_EN_CONTROL_UNDEF       0x00
+#define AUDIO_EN_CONTROL_BIT_RATE    0x01
+#define AUDIO_EN_CONTROL_QUALITY     0x02
+#define AUDIO_EN_CONTROL_VBR         0x03
+#define AUDIO_EN_CONTROL_TYPE        0x04
+#define AUDIO_EN_CONTROL_UNDERFLOW   0x05
+#define AUDIO_EN_CONTROL_OVERFLOW    0x06
+#define AUDIO_EN_CONTROL_ENCODER_ERR 0x07
+#define AUDIO_EN_CONTROL_PARAM1      0x08
+#define AUDIO_EN_CONTROL_PARAM2      0x09
+#define AUDIO_EN_CONTROL_PARAM3      0x0a
+#define AUDIO_EN_CONTROL_PARAM4      0x0b
+#define AUDIO_EN_CONTROL_PARAM5      0x0c
+#define AUDIO_EN_CONTROL_PARAM6      0x0d
+#define AUDIO_EN_CONTROL_PARAM7      0x0e
+#define AUDIO_EN_CONTROL_PARAM8      0x0f
+
+/* MPEG Decoder Control Selectors */
+
+#define AUDIO_MPGD_CONTROL_UNDEF      0x00
+#define AUDIO_MPGD_CONTROL_DUAL_CHAN  0x01
+#define AUDIO_MPGD_CONTROL_2ND_STEREO 0x02
+#define AUDIO_MPGD_CONTROL_MULTILING  0x03
+#define AUDIO_MPGD_CONTROL_DYN_RANGE  0x04
+#define AUDIO_MPGD_CONTROL_SCALING    0x05
+#define AUDIO_MPGD_CONTROL_HILO_SCALE 0x06
+#define AUDIO_MPGD_CONTROL_UNDERFLOW  0x07
+#define AUDIO_MPGD_CONTROL_OVERFLOW   0x08
+#define AUDIO_MPGD_CONTROL_DECODE_ERR 0x09
+
+/* AC-3 Decoder Control Selectors */
+
+#define AUDIO_AC3D_CONTROL_UNDEF      0x00
+#define AUDIO_AC3D_CONTROL_MODE       0x01
+#define AUDIO_AC3D_CONTROL_DYN_RANGE  0x02
+#define AUDIO_AC3D_CONTROL_SCALING    0x03
+#define AUDIO_AC3D_CONTROL_HILO_SCALE 0x04
+#define AUDIO_AC3D_CONTROL_UNDERFLOW  0x05
+#define AUDIO_AC3D_CONTROL_OVERFLOW   0x06
+#define AUDIO_AC3D_CONTROL_DECODE_ERR 0x07
+
+/* WMA Decoder Control Selectors */
+
+#define AUDIO_WMAD_CONTROL_UNDEF      0x00
+#define AUDIO_WMAD_CONTROL_UNDERFLOW  0x01
+#define AUDIO_WMAD_CONTROL_OVERFLOW   0x02
+#define AUDIO_WMAD_CONTROL_DECODE_ERR 0x03
+
+/* DTS Decoder Control Selectors */
+
+#define AUDIO_DTSD_CONTROL_UNDEF      0x00
+#define AUDIO_DTSD_CONTROL_UNDERFLOW  0x01
+#define AUDIO_DTSD_CONTROL_OVERFLOW   0x02
+#define AUDIO_DTSD_CONTROL_DECODE_ERR 0x03
+
+/* Endpoint Control Selectors */
+#define AUDIO_EP_CONTROL_UNDEF        0x00
+#define AUDIO_EP_CONTROL_SAMPLING_FEQ 0x01
+#define AUDIO_EP_CONTROL_PITCH        0x02
+
+/* Encoder Error Codes */
+
+/* <0: Reserved for vendor extensions */
+
+#define AUDIO_ENCODER_SUCCESS         0  /* No Error */
+#define AUDIO_ENCODER_ERROR_NOMEM     1  /* Out of Memory */
+#define AUDIO_ENCODER_ERROR_BW        2  /* Out of Bandwidth */
+#define AUDIO_ENCODER_ERROR_CYCLE     3  /* Out of Processing Cycles */
+#define AUDIO_ENCODER_ERROR_FRAME     4  /* General Format Frame Error */
+#define AUDIO_ENCODER_ERROR_TOOSMALL  5  /* Format Frame Too Small */
+#define AUDIO_ENCODER_ERROR_TOOBIG    6  /* Format Frame Too Large */
+#define AUDIO_ENCODER_ERROR_BADFORMAT 7  /* Bad Data Format */
+#define AUDIO_ENCODER_ERROR_NCHAN     8  /* Incorrect Number of Channels */
+#define AUDIO_ENCODER_ERROR_RATE      9  /* Incorrect Sampling Rate */
+#define AUDIO_ENCODER_ERROR_BITRATE   10 /* Unable to Meet Target Bitrate */
+#define AUDIO_ENCODER_ERROR_PARMS     11 /* Inconsistent Set of Parameters */
+#define AUDIO_ENCODER_ERROR_NOTREADY  12 /* Not Ready */
+#define AUDIO_ENCODER_ERROR_BUSY      13 /* Busy */
+                                         /* >13: Reserved */
+
+/* Format Type Codes */
+
+#define AUDIO_FORMAT_TYPE_UNDEF  0x00
+#define AUDIO_FORMAT_TYPEI       0x01
+#define AUDIO_FORMAT_TYPEII      0x02
+#define AUDIO_FORMAT_TYPEIII     0x03
+#define AUDIO_FORMAT_TYPEIV      0x04
+#define AUDIO_FORMAT_EXT_TYPEI   0x81
+#define AUDIO_FORMAT_EXT_TYPEII  0x82
+#define AUDIO_FORMAT_EXT_TYPEIII 0x83
+
+/* Audio Data Format Type I Bit Allocations */
+
+#define AUDIO_FORMAT_TYPEI_PCM       (1 << 0)
+#define AUDIO_FORMAT_TYPEI_PCM8      (1 << 1)
+#define AUDIO_FORMAT_TYPEI_IEEEFLOAT (1 << 2)
+#define AUDIO_FORMAT_TYPEI_ALAW      (1 << 3)
+#define AUDIO_FORMAT_TYPEI_MULAW     (1 << 4)
+#define AUDIO_FORMAT_TYPEI_RAWDATA   (1 << 31)
+
+/* Audio Data Format Type II Bit Allocations */
+
+#define AUDIO_FORMAT_TYPEII_MPEG    (1 << 0)
+#define AUDIO_FORMAT_TYPEII_AC3     (1 << 1)
+#define AUDIO_FORMAT_TYPEII_WMA     (1 << 2)
+#define AUDIO_FORMAT_TYPEII_DTS     (1 << 3)
+#define AUDIO_FORMAT_TYPEII_RAWDATA (1 << 31)
+
+/* Audio Data Format Type III Bit Allocations */
+
+#define AUDIO_FORMAT_TYPEIII_IEC61937_AC3            (1 << 0)
+#define AUDIO_FORMAT_TYPEIII_IEC61937_MPEG1_L1       (1 << 1)
+#define AUDIO_FORMAT_TYPEIII_IEC61937_MPEG1_L2_3     (1 << 1)
+#define AUDIO_FORMAT_TYPEIII_IEC61937_MPEG2_NOEXT    (1 << 2)
+#define AUDIO_FORMAT_TYPEIII_IEC61937_MPEG2_EXT      (1 << 3)
+#define AUDIO_FORMAT_TYPEIII_IEC61937_MPEG2_AAC_ADTS (1 << 4)
+#define AUDIO_FORMAT_TYPEIII_IEC61937_MPEG2_L1_LS    (1 << 5)
+#define AUDIO_FORMAT_TYPEIII_IEC61937_MPEG2_L2_3_LS  (1 << 6)
+#define AUDIO_FORMAT_TYPEIII_IEC61937_DTS_I          (1 << 7)
+#define AUDIO_FORMAT_TYPEIII_IEC61937_DTS_II         (1 << 8)
+#define AUDIO_FORMAT_TYPEIII_IEC61937_DTS_III        (1 << 9)
+#define AUDIO_FORMAT_TYPEIII_IEC61937_ATRAC          (1 << 10)
+#define AUDIO_FORMAT_TYPEIII_IEC61937_ATRAC2_3       (1 << 11)
+#define AUDIO_FORMAT_TYPEIII_WMA                     (1 << 12)
+
+/* Audio Data Format Type IV Bit Allocations */
+
+#define AUDIO_FORMAT_TYPEIV_PCM                     (1 << 0)
+#define AUDIO_FORMAT_TYPEIV_PCM8                    (1 << 1)
+#define AUDIO_FORMAT_TYPEIV_IEEE_FLOAT              (1 << 2)
+#define AUDIO_FORMAT_TYPEIV_ALAW                    (1 << 3)
+#define AUDIO_FORMAT_TYPEIV_MULAW                   (1 << 4)
+#define AUDIO_FORMAT_TYPEIV_MPEG                    (1 << 5)
+#define AUDIO_FORMAT_TYPEIV_AC3                     (1 << 6)
+#define AUDIO_FORMAT_TYPEIV_WMA                     (1 << 7)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_AC3            (1 << 8)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_MPEG1_L1       (1 << 9)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_MPEG1_L2_3     (1 << 10)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_MPEG2_NOEXT    (1 << 10)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_MPEG2_EXT      (1 << 11)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_MPEG2_AAC_ADTS (1 << 12)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_MPEG2_L1_LS    (1 << 13)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_MPEG2_L2_3_LS  (1 << 14)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_DTS_I          (1 << 15)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_DTS_II         (1 << 16)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_DTS_III        (1 << 17)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_ATRAC          (1 << 18)
+#define AUDIO_FORMAT_TYPEIV_IEC61937_ATRAC2_3       (1 << 19)
+#define AUDIO_FORMAT_TYPEIV_TYPE_III_WMA            (1 << 20)
+#define AUDIO_FORMAT_TYPEIV_IEC60958_PCM            (1 << 21)
+
+/* Side Band Protocol Codes */
+#define AUDIO_SIDEBAND_PROTOCOL_UNDEF 0x00
+#define AUDIO_PRES_TIMESTAMP_PROTOCOL 0x01
+
+/** USB Terminal Types
+ * Refer to Table 2-1 - Table 2-4 from termt10.pdf
+ */
+
+/* USB Terminal Types */
+#define AUDIO_TERMINAL_UNDEF     0x0100
+#define AUDIO_TERMINAL_STREAMING 0x0101
+#define AUDIO_TERMINAL_VENDOR    0x01ff
+
+/* Input Terminal Types */
+#define AUDIO_INTERM_UNDEF          0x0200 /* Undefined Type */
+#define AUDIO_INTERM_MIC            0x0201 /* A generic microhpone */
+#define AUDIO_INTERM_DESKTOP_MIC    0x0202 /* A desktop microphone */
+#define AUDIO_INTERM_PERSONAL_MIC   0x0203 /* Head-mounted or clip-on microphone */
+#define AUDIO_INTERM_OMNI_MIC       0x0204 /* Omni-directional microphone */
+#define AUDIO_INTERM_MIC_ARRAY      0x0205 /* Microphone array */
+#define AUDIO_INTERM_PROC_MIC_ARRAY 0x0206 /* Microphone array with signal processor */
+
+/* Output Terminal Types */
+#define AUDIO_OUTTERM_UNDEF       0x0300 /* Undefined Type */
+#define AUDIO_OUTTERM_SPEAKER     0x0301 /* Generic speakers */
+#define AUDIO_OUTTERM_HEADPHONES  0x0302 /* A head-mounted audio output device */
+#define AUDIO_OUTTERM_HEADDISPLAY 0x0303 /* Head Mounted Display Audio */
+#define AUDIO_OUTTERM_DESKTOP     0x0304 /* Desktop speaker */
+#define AUDIO_OUTTERM_ROOM        0x0305 /* Room speaker */
+#define AUDIO_OUTTERM_COMMS       0x0306 /* Communication speaker */
+#define AUDIO_OUTTERM_LOFREQ      0x0307 /* Low frequency effects speaker */
+
+/* Bi-directional Terminal Types */
+#define AUDIO_BIDITERM_UNDEF        0x0400 /* Undefined Type */
+#define AUDIO_BIDITERM_HANDSET      0x0401 /* Hand-held bi-directional audio device */
+#define AUDIO_BIDITERM_HEADSET      0x0402 /* Head-mounted bi-directional audio device */
+#define AUDIO_BIDITERM_SPEAKERPHONE 0x0403 /* Speakerphone, no echo reduction */
+#define AUDIO_BIDITERM_ECHOSUPPRESS 0x0404 /* Echo-suppressing speakerphone */
+#define AUDIO_BIDITERM_ECHOCANCEL   0x0405 /* Echo-canceling speakerphone */
+
+/* Telephony Terminal Types */
+#define AUDIO_TELETERM_UNDEF     0x0500 /* Undefined Type */
+#define AUDIO_TELETERM_PHONELINE 0x0501 /* Analog telephone line jack, an ISDN line,
+                                                * a proprietary PBX interface, or a wireless link */
+#define AUDIO_TELETERM_TELEPHONE 0x0502 /* Device can be used as a telephone */
+#define AUDIO_TELETERM_DOWNLINE  0x0503 /* Down Line Phone */
+
+/* External Terminal Types */
+#define AUDIO_EXTTERM_UNDEF   0x0600 /* Undefined Type */
+#define AUDIO_EXTTERM_ANALOG  0x0601 /* Generic analog connector */
+#define AUDIO_EXTTERM_DIGITAL 0x0602 /* Generic digital audio interface */
+#define AUDIO_EXTTERM_LINE    0x0603 /* Analog connector at standard line levels */
+#define AUDIO_EXTTERM_LEGACY  0x0604 /* Legacy audio line out connector */
+#define AUDIO_EXTTERM_SPDIF   0x0605 /* SPDIF interface */
+#define AUDIO_EXTTERM_1394DA  0x0606 /* 1394 DA stream */
+#define AUDIO_EXTTERM_1394DV  0x0607 /* 1394 DV stream soundtrack */
+#define AUDIO_EXTTERM_ADAT    0x0608 /* ADAT Lightpipe */
+#define AUDIO_EXTTERM_TDIF    0x0609 /* TDIF  - Tascam Digital Interface */
+#define AUDIO_EXTTERM_MADI    0x060a /* MADI - Multi-channel Audio Digital Interface (AES) */
+
+/* Embedded Function Terminal Types */
+#define AUDIO_EMBEDTERM_UNDEF        0x0700 /* Undefined Type */
+#define AUDIO_EMBEDTERM_CALIBRATION  0x0701 /* Level Calibration Noise Source */
+#define AUDIO_EMBEDTERM_EQUALIZATION 0x0702 /* Equalization Noise */
+#define AUDIO_EMBEDTERM_CD           0x0703 /* CD player */
+#define AUDIO_EMBEDTERM_DAT          0x0704 /* Digital Audio Tape */
+#define AUDIO_EMBEDTERM_DCC          0x0705 /* Digital Compact Cassette */
+#define AUDIO_EMBEDTERM_COMPRESSED   0x0706 /* Compressed Audio Player */
+#define AUDIO_EMBEDTERM_TAPE         0x0707 /* Analog Audio Tape */
+#define AUDIO_EMBEDTERM_PHONOGRAPH   0x0708 /* Analog vinyl record player */
+#define AUDIO_EMBEDTERM_VCR          0x0709 /* Audio track of VCR */
+#define AUDIO_EMBEDTERM_VIDDISC      0x070a /* Audio track of VideoDisc player */
+#define AUDIO_EMBEDTERM_DVD          0x070b /* Audio track of DVD player */
+#define AUDIO_EMBEDTERM_TVTUNER      0x070c /* Audio track of TV tuner */
+#define AUDIO_EMBEDTERM_SATELLITE    0x070d /* Audio track of satellite receiver */
+#define AUDIO_EMBEDTERM_CABLETUNER   0x070e /* Audio track of cable tuner */
+#define AUDIO_EMBEDTERM_DSS          0x070f /* Audio track of DSS receiver */
+#define AUDIO_EMBEDTERM_RADIO        0x0710 /* AM/FM radio receiver */
+#define AUDIO_EMBEDTERM_TRANSMITTER  0x0711 /* AM/FM radio transmitter */
+#define AUDIO_EMBEDTERM_MULTITRACK   0x0712 /* A multi-track recording system */
+#define AUDIO_EMBEDTERM_SYNTHESIZER  0x0713 /* Synthesizer */
+#define AUDIO_EMBEDTERM_PIANO        0x0714 /* Piano */
+#define AUDIO_EMBEDTERM_GUITAR       0x0715 /* Guitar */
+#define AUDIO_EMBEDTERM_PERCUSSON    0x0716 /* Percussion Instrument */
+#define AUDIO_EMBEDTERM_INSTRUMENT   0x0717 /* Other Musical Instrument */
+
+#define AUDIO_FORMAT_TYPE_I   0x01
+#define AUDIO_FORMAT_TYPE_II  0x02
+#define AUDIO_FORMAT_TYPE_III 0x03
+
+struct audio_cs_if_ac_header_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint16_t bcdADC;
+    uint16_t wTotalLength;
+    uint8_t bInCollection;
+    uint8_t baInterfaceNr[];
+} __PACKED;
+
+#define AUDIO_SIZEOF_AC_HEADER_DESC(n) (8 + n)
+
+struct audio_cs_if_ac_input_terminal_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bTerminalID;
+    uint16_t wTerminalType;
+    uint8_t bAssocTerminal;
+    uint8_t bNrChannels;
+    uint16_t wChannelConfig;
+    uint8_t iChannelNames;
+    uint8_t iTerminal;
+} __PACKED;
+
+#define AUDIO_SIZEOF_AC_INPUT_TERMINAL_DESC (12)
+
+struct audio_cs_if_ac_output_terminal_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bTerminalID;
+    uint16_t wTerminalType;
+    uint8_t bAssocTerminal;
+    uint8_t bSourceID;
+    uint8_t iTerminal;
+} __PACKED;
+
+#define AUDIO_SIZEOF_AC_OUTPUT_TERMINAL_DESC (9)
+
+struct audio_cs_if_ac_feature_unit_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bUnitID;
+    uint8_t bSourceID;
+    uint8_t bControlSize;
+    uint8_t bmaControls[1];
+    uint8_t iFeature;
+} __PACKED;
+
+#define AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(ch, n) (7 + (ch + 1) * n)
+
+struct audio_cs_if_as_general_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bTerminalLink;
+    uint8_t bDelay;
+    uint16_t wFormatTag;
+} __PACKED;
+
+#define AUDIO_SIZEOF_AS_GENERAL_DESC (7)
+
+struct audio_cs_if_as_format_type_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bFormatType;
+    uint8_t bNrChannels;
+    uint8_t bSubframeSize;
+    uint8_t bBitResolution;
+    uint8_t bSamFreqType;
+    uint8_t tSamFreq[3];
+} __PACKED;
+
+#define AUDIO_SIZEOF_FORMAT_TYPE_DESC(n) (8 + 3 * n)
+
+struct audio_ep_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bEndpointAddress;
+    uint8_t bmAttributes;
+    uint16_t wMaxPacketSize;
+    uint8_t bInterval;
+    uint8_t bRefresh;
+    uint8_t bSynchAddress;
+} __PACKED;
+
+#define AUDIO_SIZEOF_EP_DESC (9)
+
+struct audio_cs_ep_ep_general_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bmAttributes;
+    uint8_t bLockDelayUnits;
+    uint16_t wLockDelay;
+} __PACKED;
+
+#define AUDIO_SIZEOF_CS_EP_GENERAL_DESC (7)
+
+// clang-format off
+#define AUDIO_AC_DESCRIPTOR_INIT(bFirstInterface, bInterfaceCount, wTotalLength, stridx, ...) \
+    /* Interface Association Descriptor */                                                                                       \
+    0x08,                                                                                                                        \
+    USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION,                                                                                   \
+    bFirstInterface,                                                                                                             \
+    bInterfaceCount,                                                                                                             \
+    USB_DEVICE_CLASS_AUDIO,                                                                                                      \
+    AUDIO_SUBCLASS_AUDIOCONTROL,                                                                                                 \
+    AUDIO_PROTOCOL_UNDEFINED,                                                                                                    \
+    0x00,                                                                                                                        \
+    /* ------------------ AudioControl Interface ------------------ */\
+    0x09,                            /* bLength */                                                                               \
+    USB_DESCRIPTOR_TYPE_INTERFACE,   /* bDescriptorType */                                                                       \
+    bFirstInterface,                 /* bInterfaceNumber */                                                                      \
+    0x00,                            /* bAlternateSetting */                                                                     \
+    0x00,                            /* bNumEndpoints */                                                                         \
+    USB_DEVICE_CLASS_AUDIO,          /* bInterfaceClass */                                                                       \
+    AUDIO_SUBCLASS_AUDIOCONTROL,     /* bInterfaceSubClass */                                                                    \
+    AUDIO_PROTOCOL_UNDEFINED,        /* bInterfaceProtocol */                                                                    \
+    stridx,                          /* iInterface */                                                                            \
+    0x08 + PP_NARG(__VA_ARGS__),     /* bLength */                                                                               \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                                                       \
+    AUDIO_CONTROL_HEADER,            /* bDescriptorSubtype */                                                                    \
+    WBVAL(0x0100),                   /* bcdADC */                                                                                \
+    WBVAL(wTotalLength),             /* wTotalLength */                                                                          \
+    PP_NARG(__VA_ARGS__),            /* bInCollection */                                                                         \
+    __VA_ARGS__                      /* baInterfaceNr */
+
+#define AUDIO_AC_DESCRIPTOR_INIT_LEN(n) (0x08 + 0x09 + 0x08 + n)
+
+#define AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(bTerminalID, wTerminalType, bNrChannels, wChannelConfig) \
+    0x0C,                            /* bLength */                                                   \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                           \
+    AUDIO_CONTROL_INPUT_TERMINAL,    /* bDescriptorSubtype */                                        \
+    bTerminalID,                     /* bTerminalID */                                               \
+    WBVAL(wTerminalType),            /* wTerminalType : Microphone 0x0201 */                         \
+    0x00,                            /* bAssocTerminal */                                            \
+    bNrChannels,                     /* bNrChannels */                                               \
+    WBVAL(wChannelConfig),           /* wChannelConfig : Mono sets no position bits */               \
+    0x00,                            /* iChannelNames */                                             \
+    0x00                             /* iTerminal */
+
+#define AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(bTerminalID, wTerminalType, bSourceID) \
+    0x09,                            /* bLength */                                  \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                          \
+    AUDIO_CONTROL_OUTPUT_TERMINAL,   /* bDescriptorSubtype */                       \
+    bTerminalID,                     /* bTerminalID */                              \
+    WBVAL(wTerminalType),            /* wTerminalType : USB Streaming */            \
+    0x00,                            /* bAssocTerminal */                           \
+    bSourceID,                       /* bSourceID */                                \
+    0x00                             /* iTerminal */
+
+#define AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(bUnitID, bSourceID, bControlSize, ...) \
+    0x07 + PP_NARG(__VA_ARGS__),     /* bLength */                               \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                       \
+    AUDIO_CONTROL_FEATURE_UNIT,      /* bDescriptorSubtype */                    \
+    bUnitID,                         /* bUnitID */                               \
+    bSourceID,                       /* bSourceID */                             \
+    bControlSize,                    /* bControlSize */                          \
+    __VA_ARGS__,                     /* bmaControls(0) Mute */                   \
+    0x00                             /* iTerminal */
+
+#define AUDIO_AS_DESCRIPTOR_INIT(bInterfaceNumber, bTerminalLink, bNrChannels, bSubFrameSize, bBitResolution, bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval, ...) \
+    0x09,                            /* bLength */                                                                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE,   /* bDescriptorType */                                                               \
+    bInterfaceNumber,                /* bInterfaceNumber */                                                              \
+    0x00,                            /* bAlternateSetting */                                                             \
+    0x00,                            /* bNumEndpoints */                                                                 \
+    USB_DEVICE_CLASS_AUDIO,          /* bInterfaceClass */                                                               \
+    AUDIO_SUBCLASS_AUDIOSTREAMING,   /* bInterfaceSubClass */                                                            \
+    AUDIO_PROTOCOL_UNDEFINED,        /* bInterfaceProtocol */                                                            \
+    0x00,                            /* iInterface */                                                                    \
+    0x09,                            /* bLength */                                                                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE,   /* bDescriptorType */                                                               \
+    bInterfaceNumber,                /* bInterfaceNumber */                                                              \
+    0x01,                            /* bAlternateSetting */                                                             \
+    0x01,                            /* bNumEndpoints */                                                                 \
+    USB_DEVICE_CLASS_AUDIO,          /* bInterfaceClass */                                                               \
+    AUDIO_SUBCLASS_AUDIOSTREAMING,   /* bInterfaceSubClass */                                                            \
+    AUDIO_PROTOCOL_UNDEFINED,        /* bInterfaceProtocol */                                                            \
+    0x00,                            /* iInterface */                                                                    \
+    0x07,                            /* bLength */                                                                       \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                                               \
+    AUDIO_STREAMING_GENERAL,         /* bDescriptorSubtype */                                                            \
+    bTerminalLink,                   /* bTerminalLink : Unit ID of the Output Terminal*/                                 \
+    0x01,                            /* bDelay */                                                                        \
+    WBVAL(AUDIO_FORMAT_PCM),         /* wFormatTag : AUDIO_FORMAT_PCM */                                                 \
+    0x08 + PP_NARG(__VA_ARGS__),     /* bLength */                                                                       \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                                               \
+    AUDIO_STREAMING_FORMAT_TYPE,     /* bDescriptorSubtype */                                                            \
+    AUDIO_FORMAT_TYPE_I,             /* bFormatType */                                                                   \
+    bNrChannels,                     /* bNrChannels */                                                                   \
+    bSubFrameSize,                   /* bSubFrameSize : Bytes per audio subframe */                                      \
+    bBitResolution,                  /* bBitResolution : bits per sample */                                              \
+    (PP_NARG(__VA_ARGS__)/3),        /* bSamFreqType : only one frequency supported */                                   \
+    __VA_ARGS__,                     /* tSamFreq : Audio sampling frequency coded on 3 bytes */                          \
+    0x09,                            /* bLength */                                                                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,    /* bDescriptorType */                                                               \
+    bEndpointAddress,                /* bEndpointAddress : IN endpoint 1 */                                              \
+    bmAttributes,                    /* bmAttributes */                                                                  \
+    WBVAL(wMaxPacketSize),           /* wMaxPacketSize */                                                                \
+    bInterval,                       /* bInterval : one packet per frame */                                              \
+    0x00,                            /* bRefresh */                                                                      \
+    0x00,                            /* bSynchAddress */                                                                 \
+    0x07,                            /* bLength */                                                                       \
+    AUDIO_ENDPOINT_DESCRIPTOR_TYPE,  /* bDescriptorType */                                                               \
+    AUDIO_ENDPOINT_GENERAL,          /* bDescriptor */                                                                   \
+    AUDIO_EP_CONTROL_SAMPLING_FEQ,   /* bmAttributes AUDIO_SAMPLING_FREQ_CONTROL */                                      \
+    0x00,                            /* bLockDelayUnits */                                                               \
+    0x00,                            /* wLockDelay */                                                                    \
+    0x00
+
+#define AUDIO_AS_DESCRIPTOR_INIT_LEN(n) (0x09 + 0x09 + 0x07 + 0x08 + 3 * n + 0x09 + 0x07)
+
+#define AUDIO_MS_STANDARD_DESCRIPTOR_INIT(bInterfaceNumber, bNumEndpoints)                                               \
+    0x09,                            /* bLength */                                                                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE,   /* bDescriptorType */                                                               \
+    bInterfaceNumber,                /* bInterfaceNumber */                                                              \
+    0x00,                            /* bAlternateSetting */                                                             \
+    bNumEndpoints,                   /* bNumEndpoints */                                                                 \
+    USB_DEVICE_CLASS_AUDIO,          /* bInterfaceClass */                                                               \
+    AUDIO_SUBCLASS_MIDISTREAMING,    /* bInterfaceSubClass */                                                            \
+    AUDIO_PROTOCOL_UNDEFINED,        /* bInterfaceProtocol */                                                            \
+    0x00                             /* iInterface */
+
+#define AUDIO_MS_STANDARD_DESCRIPTOR_INIT_LEN 0x09
+
+struct audio_v2_channel_cluster_descriptor {
+    uint8_t bNrChannels;
+    uint32_t bmChannelConfig;
+    uint8_t iChannelNames;
+} __PACKED;
+
+#define AUDIO_V2_SIZEOF_CHANNEL_CLUSTER_DESC (6)
+
+struct audio_v2_cs_if_ac_header_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint16_t bcdADC;
+    uint8_t bCategory;
+    uint16_t wTotalLength;
+    uint8_t bmControls;
+} __PACKED;
+
+#define AUDIO_V2_SIZEOF_AC_HEADER_DESC (9)
+
+struct audio_v2_cs_if_ac_clock_source_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bClockID;
+    uint8_t bmAttributes;
+    uint8_t bmControls;
+    uint8_t bAssocTerminal;
+    uint8_t iClockSource;
+} __PACKED;
+
+#define AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC (8)
+
+struct audio_v2_cs_if_ac_clock_selector_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bClockID;
+    uint8_t bNrInPins;
+    uint8_t baCSourceID[1];
+    uint8_t iClockSelector;
+} __PACKED;
+
+#define AUDIO_SIZEOF_AC_CLOCK_SELECTOR_DESC(n) (7 + n)
+
+struct audio_v2_cs_if_ac_clock_multiplier_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bClockID;
+    uint8_t bCSourceID;
+    uint8_t bmControls;
+    uint8_t iClockMultiplier;
+} __PACKED;
+
+#define AUDIO_SIZEOF_AC_CLOCK_MULTIPLIER_DESC() (7)
+
+struct audio_v2_cs_if_ac_input_terminal_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bTerminalID;
+    uint16_t wTerminalType;
+    uint8_t bAssocTerminal;
+    uint8_t bCSourceID;
+    uint8_t bNrChannels;
+    uint32_t wChannelConfig;
+    uint8_t iChannelNames;
+    uint16_t bmControls;
+    uint8_t iTerminal;
+} __PACKED;
+
+#define AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC (17)
+
+struct audio_v2_cs_if_ac_output_terminal_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bTerminalID;
+    uint16_t wTerminalType;
+    uint8_t bAssocTerminal;
+    uint8_t bSourceID;
+    uint8_t bCSourceID;
+    uint16_t bmControls;
+    uint8_t iTerminal;
+} __PACKED;
+
+#define AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC (12)
+
+struct audio_v2_cs_if_ac_feature_unit_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bUnitID;
+    uint8_t bSourceID;
+    uint32_t bmaControls[1];
+    uint8_t iFeature;
+} __PACKED;
+
+#define AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(ch) (6 + (ch + 1) * 4)
+
+struct audio_v2_cs_if_as_general_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bTerminalLink;
+    uint8_t bmControls;
+    uint8_t bFormatType;
+    uint32_t bmFormats;
+    uint8_t bNrChannels;
+    uint32_t bmChannelConfig;
+    uint8_t iChannelNames;
+} __PACKED;
+
+#define AUDIO_V2_SIZEOF_AS_GENERAL_DESC (16)
+
+struct audio_v2_control_range1_param_block {
+    uint16_t wNumSubRanges;
+    struct
+    {
+        uint8_t bMin;
+        uint8_t bMax;
+        uint8_t bRes;
+    }subrange[];
+} __PACKED;
+
+struct audio_v2_control_range2_param_block {
+    uint16_t wNumSubRanges;
+    struct
+    {
+        uint16_t wMin;
+        uint16_t wMax;
+        uint16_t wRes;
+    }subrange[];
+} __PACKED;
+
+struct audio_v2_control_range3_param_block {
+    uint16_t wNumSubRanges;
+    struct
+    {
+        uint32_t dMin;
+        uint32_t dMax;
+        uint32_t dRes;
+    }subrange[];
+} __PACKED;
+
+#define AUDIO_V2_AC_DESCRIPTOR_INIT(bFirstInterface, bInterfaceCount, wTotalLength, bCategory, bmControls, stridx) \
+    /* Interface Association Descriptor */                                                                                       \
+    0x08,                                                                                                                        \
+    USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION,                                                                                   \
+    bFirstInterface,                                                                                                             \
+    bInterfaceCount,                                                                                                             \
+    USB_DEVICE_CLASS_AUDIO,                                                                                                      \
+    AUDIO_SUBCLASS_UNDEFINED,                                                                                                    \
+    AUDIO_PROTOCOLv20,                                                                                                           \
+    0x00,                                                                                                                        \
+    /* ------------------ AudioControl Interface ------------------ */\
+    0x09,                            /* bLength */                                                                               \
+    USB_DESCRIPTOR_TYPE_INTERFACE,   /* bDescriptorType */                                                                       \
+    bFirstInterface,                 /* bInterfaceNumber */                                                                      \
+    0x00,                            /* bAlternateSetting */                                                                     \
+    0x00,                            /* bNumEndpoints */                                                                         \
+    USB_DEVICE_CLASS_AUDIO,          /* bInterfaceClass */                                                                       \
+    AUDIO_SUBCLASS_AUDIOCONTROL,     /* bInterfaceSubClass */                                                                    \
+    AUDIO_PROTOCOLv20,               /* bInterfaceProtocol */                                                                    \
+    stridx,                          /* iInterface */                                                                            \
+    0x09,                            /* bLength */                                                                               \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                                                       \
+    AUDIO_CONTROL_HEADER,            /* bDescriptorSubtype */                                                                    \
+    WBVAL(0x0200),                   /* bcdADC */                                                                                \
+    bCategory,                       /* bCategory */                                                                             \
+    WBVAL(wTotalLength),             /* wTotalLength */                                                                          \
+    bmControls                       /* bmControls */                                                                            \
+
+#define AUDIO_V2_AC_DESCRIPTOR_INIT_LEN (0x08 + 0x09 + 0x09)
+
+#define AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(bClockID, bmAttributes, bmControls) \
+    0x08,                            /* bLength */                               \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                       \
+    AUDIO_CONTROL_CLOCK_SOURCE,      /* bDescriptorSubtype */                    \
+    bClockID,                        /* bClockID */                              \
+    bmAttributes,                    /* bmAttributes */                          \
+    bmControls,                      /* bmControls */                            \
+    0x00,                            /* bAssocTerminal */                        \
+    0x00                             /* iClockSource */
+
+#define AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(bTerminalID, wTerminalType, bCSourceID, bNrChannels, wChannelConfig, bmControls) \
+    0x11,                            /* bLength */                                                                              \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                                                      \
+    AUDIO_CONTROL_INPUT_TERMINAL,    /* bDescriptorSubtype */                                                                   \
+    bTerminalID,                     /* bTerminalID */                                                                          \
+    WBVAL(wTerminalType),            /* wTerminalType : Microphone 0x0201 */                                                    \
+    0x00,                            /* bAssocTerminal */                                                                       \
+    bCSourceID,                      /* bCSourceID */                                                                           \
+    bNrChannels,                     /* bNrChannels */                                                                          \
+    DBVAL(wChannelConfig),           /* wChannelConfig : Mono sets no position bits */                                          \
+    0x00,                            /* iChannelNames */                                                                        \
+    WBVAL(bmControls),               /* bmControls */                                                                           \
+    0x00                             /* iTerminal */
+
+#define AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(bTerminalID, wTerminalType, bSourceID, bCSourceID, bmControls) \
+    0x0c,                            /* bLength */                                                 \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                         \
+    AUDIO_CONTROL_OUTPUT_TERMINAL,   /* bDescriptorSubtype */                                      \
+    bTerminalID,                     /* bTerminalID */                                             \
+    WBVAL(wTerminalType),            /* wTerminalType : USB Streaming */                           \
+    0x00,                            /* bAssocTerminal */                                          \
+    bSourceID,                       /* bSourceID */                                               \
+    bCSourceID,                      /* bCSourceID */                                              \
+    WBVAL(bmControls),               /* bmControls */                                              \
+    0x00                             /* iTerminal */
+
+#define AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(bUnitID, bSourceID, ...) \
+    0x06 + (PP_NARG(__VA_ARGS__)),   /* bLength */                    \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */            \
+    AUDIO_CONTROL_FEATURE_UNIT,      /* bDescriptorSubtype */         \
+    bUnitID,                         /* bUnitID */                    \
+    bSourceID,                       /* bSourceID */                  \
+    __VA_ARGS__,                     /* bmaControls(0) Mute */        \
+    0x00                             /* iTerminal */
+
+#define AUDIO_V2_AS_DESCRIPTOR_INIT(bInterfaceNumber, bTerminalLink, bNrChannels, bmChannelConfig, bSubslotSize, bBitResolution, bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval) \
+    0x09,                            /* bLength */                                                                                                                        \
+    USB_DESCRIPTOR_TYPE_INTERFACE,   /* bDescriptorType */                                                                                                                \
+    bInterfaceNumber,                /* bInterfaceNumber */                                                                                                               \
+    0x00,                            /* bAlternateSetting */                                                                                                              \
+    0x00,                            /* bNumEndpoints */                                                                                                                  \
+    USB_DEVICE_CLASS_AUDIO,          /* bInterfaceClass */                                                                                                                \
+    AUDIO_SUBCLASS_AUDIOSTREAMING,   /* bInterfaceSubClass */                                                                                                             \
+    AUDIO_PROTOCOLv20,               /* bInterfaceProtocol */                                                                                                             \
+    0x00,                            /* iInterface */                                                                                                                     \
+    0x09,                            /* bLength */                                                                                                                        \
+    USB_DESCRIPTOR_TYPE_INTERFACE,   /* bDescriptorType */                                                                                                                \
+    bInterfaceNumber,                /* bInterfaceNumber */                                                                                                               \
+    0x01,                            /* bAlternateSetting */                                                                                                              \
+    0x01,                            /* bNumEndpoints */                                                                                                                  \
+    USB_DEVICE_CLASS_AUDIO,          /* bInterfaceClass */                                                                                                                \
+    AUDIO_SUBCLASS_AUDIOSTREAMING,   /* bInterfaceSubClass */                                                                                                             \
+    AUDIO_PROTOCOLv20,               /* bInterfaceProtocol */                                                                                                             \
+    0x00,                            /* iInterface */                                                                                                                     \
+    0x10,                            /* bLength */                                                                                                                        \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                                                                                                \
+    AUDIO_STREAMING_GENERAL,         /* bDescriptorSubtype */                                                                                                             \
+    bTerminalLink,                   /* bTerminalLink : Unit ID of the Output or Input Terminal*/                                                                         \
+    0x00,                            /* bmControls */                                                                                                                     \
+    AUDIO_FORMAT_TYPE_I,             /* bFormatType : AUDIO_FORMAT_TYPE_I */                                                                                              \
+    DBVAL(AUDIO_V2_FORMAT_PCM),      /* bmFormats PCM */                                                                                                                  \
+    bNrChannels,                     /* bNrChannels */                                                                                                                    \
+    DBVAL(bmChannelConfig),          /* bmChannelConfig */                                                                                                                \
+    0x00,                            /* iChannelNames */                                                                                                                  \
+    0x06,                            /* bLength */                                                                                                                        \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                                                                                                \
+    AUDIO_STREAMING_FORMAT_TYPE,     /* bDescriptorSubtype */                                                                                                             \
+    AUDIO_FORMAT_TYPE_I,             /* bFormatType */                                                                                                                    \
+    bSubslotSize,                    /* bSubslotSize */                                                                                                                   \
+    bBitResolution,                  /* bBitResolution */                                                                                                                 \
+    0x07,                            /* bLength */                                                                                                                        \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,    /* bDescriptorType */                                                                                                                \
+    bEndpointAddress,                /* bEndpointAddress 3 out endpoint for Audio */                                                                                      \
+    bmAttributes,                    /* bmAttributes */                                                                                                                   \
+    WBVAL(wMaxPacketSize),           /* XXXX wMaxPacketSize in Bytes (SampleRate * SlotByteSize * NumChannels) */                                                         \
+    bInterval,                       /* bInterval */                                                                                                                      \
+    0x08,                            /* bLength */                                                                                                                        \
+    AUDIO_ENDPOINT_DESCRIPTOR_TYPE,  /* bDescriptorType */                                                                                                                \
+    AUDIO_ENDPOINT_GENERAL,          /* bDescriptor */                                                                                                                    \
+    0x00,                            /* bmAttributes */                                                                                                                   \
+    0x00,                            /* bmControls */                                                                                                                     \
+    0x00,                            /* bLockDelayUnits */                                                                                                                \
+    0x00,                            /* wLockDelay */                                                                                                                     \
+    0x00
+
+#define AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(bInterfaceNumber, bTerminalLink, bNrChannels, bmChannelConfig, bSubslotSize, bBitResolution, bEndpointAddress, wMaxPacketSize, bInterval, bFeedbackEndpointAddress) \
+    0x09,                            /* bLength */                                                                                                                        \
+    USB_DESCRIPTOR_TYPE_INTERFACE,   /* bDescriptorType */                                                                                                                \
+    bInterfaceNumber,                /* bInterfaceNumber */                                                                                                               \
+    0x00,                            /* bAlternateSetting */                                                                                                              \
+    0x00,                            /* bNumEndpoints */                                                                                                                  \
+    USB_DEVICE_CLASS_AUDIO,          /* bInterfaceClass */                                                                                                                \
+    AUDIO_SUBCLASS_AUDIOSTREAMING,   /* bInterfaceSubClass */                                                                                                             \
+    AUDIO_PROTOCOLv20,               /* bInterfaceProtocol */                                                                                                             \
+    0x00,                            /* iInterface */                                                                                                                     \
+    0x09,                            /* bLength */                                                                                                                        \
+    USB_DESCRIPTOR_TYPE_INTERFACE,   /* bDescriptorType */                                                                                                                \
+    bInterfaceNumber,                /* bInterfaceNumber */                                                                                                               \
+    0x01,                            /* bAlternateSetting */                                                                                                              \
+    0x02,                            /* bNumEndpoints */                                                                                                                  \
+    USB_DEVICE_CLASS_AUDIO,          /* bInterfaceClass */                                                                                                                \
+    AUDIO_SUBCLASS_AUDIOSTREAMING,   /* bInterfaceSubClass */                                                                                                             \
+    AUDIO_PROTOCOLv20,               /* bInterfaceProtocol */                                                                                                             \
+    0x00,                            /* iInterface */                                                                                                                     \
+    0x10,                            /* bLength */                                                                                                                        \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                                                                                                \
+    AUDIO_STREAMING_GENERAL,         /* bDescriptorSubtype */                                                                                                             \
+    bTerminalLink,                   /* bTerminalLink : Unit ID of the Output or Input Terminal*/                                                                         \
+    0x00,                            /* bmControls */                                                                                                                     \
+    AUDIO_FORMAT_TYPE_I,             /* bFormatType : AUDIO_FORMAT_TYPE_I */                                                                                              \
+    DBVAL(AUDIO_V2_FORMAT_PCM),      /* bmFormats PCM */                                                                                                                  \
+    bNrChannels,                     /* bNrChannels */                                                                                                                    \
+    DBVAL(bmChannelConfig),          /* bmChannelConfig */                                                                                                                \
+    0x00,                            /* iChannelNames */                                                                                                                  \
+    0x06,                            /* bLength */                                                                                                                        \
+    AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                                                                                                \
+    AUDIO_STREAMING_FORMAT_TYPE,     /* bDescriptorSubtype */                                                                                                             \
+    AUDIO_FORMAT_TYPE_I,             /* bFormatType */                                                                                                                    \
+    bSubslotSize,                    /* bSubslotSize */                                                                                                                   \
+    bBitResolution,                  /* bBitResolution */                                                                                                                 \
+    0x07,                            /* bLength */                                                                                                                        \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,    /* bDescriptorType */                                                                                                                \
+    bEndpointAddress,                /* bEndpointAddress 3 out endpoint for Audio */                                                                                      \
+    0x05,                            /* bmAttributes: TransferType=Isochronous  SyncType=Asynchronous  EndpointType=Data*/                                                \
+    WBVAL(wMaxPacketSize),           /* XXXX wMaxPacketSize in Bytes (SampleRate * SlotByteSize * NumChannels) */                                                         \
+    bInterval,                       /* bInterval */                                                                                                                      \
+    0x08,                            /* bLength */                                                                                                                        \
+    AUDIO_ENDPOINT_DESCRIPTOR_TYPE,  /* bDescriptorType */                                                                                                                \
+    AUDIO_ENDPOINT_GENERAL,          /* bDescriptor */                                                                                                                    \
+    0x00,                            /* bmAttributes */                                                                                                                   \
+    0x00,                            /* bmControls */                                                                                                                     \
+    0x00,                            /* bLockDelayUnits */                                                                                                                \
+    0x00,                            /* wLockDelay */                                                                                                                     \
+    0x00,                                                                                                                                                                 \
+    0x07,                            /* bLength */                                                                                                                        \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,    /* bDescriptorType */                                                                                                                \
+    bFeedbackEndpointAddress,        /* bFeedbackEndpointAddress Revise Dir to bEndpointAddress */                                                                        \
+    0x11,                            /* bmAttributes: TransferType=Isochronous  SyncType=None  EndpointType=Feedback */                                                   \
+    WBVAL(4),                        /* XXXX wMaxPacketSize in Bytes */                                                                                                   \
+    bInterval                        /* bInterval */                                                                                                                      \
+
+// clang-format on
+
+#define AUDIO_V2_AS_DESCRIPTOR_INIT_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08)
+#define AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08 + 0x07)
+
+#define AUDIO_SAMPLE_FREQ_NUM(num) (uint8_t)(num), (uint8_t)((num >> 8))
+#define AUDIO_SAMPLE_FREQ_3B(frq)  (uint8_t)(frq), (uint8_t)((frq >> 8)), (uint8_t)((frq >> 16))
+#define AUDIO_SAMPLE_FREQ_4B(frq)  (uint8_t)(frq), (uint8_t)((frq >> 8)), \
+                                  (uint8_t)((frq >> 16)), (uint8_t)((frq >> 24))
+
+#endif /* USB_AUDIO_H */

+ 344 - 0
components/drivers/usb/cherryusb/class/audio/usbd_audio.c

@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_audio.h"
+
+struct audio_entity_param {
+    uint32_t wCur;
+    uint32_t wMin;
+    uint32_t wMax;
+    uint32_t wRes;
+};
+
+struct usbd_audio_priv {
+    struct audio_entity_info *table;
+    uint8_t num;
+    uint16_t uac_version;
+} g_usbd_audio[CONFIG_USBDEV_MAX_BUS];
+
+static int audio_class_endpoint_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    uint8_t control_selector;
+    uint32_t sampling_freq = 0;
+    uint8_t ep;
+
+    control_selector = HI_BYTE(setup->wValue);
+    ep = LO_BYTE(setup->wIndex);
+
+    switch (control_selector) {
+        case AUDIO_EP_CONTROL_SAMPLING_FEQ:
+            switch (setup->bRequest) {
+                case AUDIO_REQUEST_SET_CUR:
+                    memcpy((uint8_t *)&sampling_freq, *data, *len);
+                    USB_LOG_DBG("Set ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
+                    usbd_audio_set_sampling_freq(busid, ep, sampling_freq);
+                    break;
+                case AUDIO_REQUEST_GET_CUR:
+                case AUDIO_REQUEST_GET_MIN:
+                case AUDIO_REQUEST_GET_MAX:
+                case AUDIO_REQUEST_GET_RES:
+                    sampling_freq = usbd_audio_get_sampling_freq(busid, ep);
+                    memcpy(*data, &sampling_freq, 3);
+                    USB_LOG_DBG("Get ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
+                    *len = 3;
+                    break;
+            }
+
+            break;
+        default:
+            USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector);
+            return -1;
+    }
+    return 0;
+}
+
+static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    USB_LOG_DBG("Audio Class request: "
+                "bRequest 0x%02x\r\n",
+                setup->bRequest);
+
+    uint8_t entity_id;
+    uint8_t ep;
+    uint8_t subtype = 0x01;
+    uint8_t control_selector;
+    uint8_t ch;
+    uint8_t mute;
+    uint16_t volume;
+    int volume_db = 0;
+    uint32_t sampling_freq = 0;
+
+    const char *mute_string[2] = { "off", "on" };
+
+    entity_id = HI_BYTE(setup->wIndex);
+    control_selector = HI_BYTE(setup->wValue);
+    ch = LO_BYTE(setup->wValue);
+
+    ARG_UNUSED(mute_string);
+
+    for (uint8_t i = 0; i < g_usbd_audio[busid].num; i++) {
+        if (g_usbd_audio[busid].table[i].bEntityId == entity_id) {
+            subtype = g_usbd_audio[busid].table[i].bDescriptorSubtype;
+            ep = g_usbd_audio[busid].table[i].ep;
+            break;
+        }
+    }
+
+    if (subtype == 0x01) {
+        USB_LOG_ERR("Do not find subtype for 0x%02x\r\n", entity_id);
+        return -1;
+    }
+
+    USB_LOG_DBG("Audio entity_id:%02x, subtype:%02x, cs:%02x\r\n", entity_id, subtype, control_selector);
+
+    switch (subtype) {
+        case AUDIO_CONTROL_FEATURE_UNIT:
+            switch (control_selector) {
+                case AUDIO_FU_CONTROL_MUTE:
+                    if (g_usbd_audio[busid].uac_version < 0x0200) {
+                        switch (setup->bRequest) {
+                            case AUDIO_REQUEST_SET_CUR:
+                                mute = (*data)[0];
+                                usbd_audio_set_mute(busid, ep, ch, mute);
+                                break;
+                            case AUDIO_REQUEST_GET_CUR:
+                                (*data)[0] = usbd_audio_get_mute(busid, ep, ch);
+                                *len = 1;
+                                break;
+                            default:
+                                USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
+                                return -1;
+                        }
+                    } else {
+                        switch (setup->bRequest) {
+                            case AUDIO_REQUEST_CUR:
+                                if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
+                                    (*data)[0] = usbd_audio_get_mute(busid, ep, ch);
+                                    *len = 1;
+                                } else {
+                                    mute = (*data)[0];
+                                    usbd_audio_set_mute(busid, ep, ch, mute);
+                                }
+                                break;
+                            default:
+                                //USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
+                                return -1;
+                        }
+                    }
+                    break;
+                case AUDIO_FU_CONTROL_VOLUME:
+                    if (g_usbd_audio[busid].uac_version < 0x0200) {
+                        switch (setup->bRequest) {
+                            case AUDIO_REQUEST_SET_CUR:
+                                memcpy(&volume, *data, *len);
+                                if (volume < 0x8000) {
+                                    volume_db = volume / 256;
+                                } else if (volume > 0x8000) {
+                                    volume_db = (0xffff - volume + 1) / -256;
+                                }
+                                volume_db += 128; /* 0 ~ 255 */
+                                USB_LOG_DBG("Set ep:0x%02x ch:%d volume:0x%04x\r\n", ep, ch, volume);
+                                usbd_audio_set_volume(busid, ep, ch, volume_db);
+                                break;
+                            case AUDIO_REQUEST_GET_CUR:
+                                volume_db = usbd_audio_get_volume(busid, ep, ch);
+                                volume_db -= 128;
+                                if (volume_db >= 0) {
+                                    volume = volume_db * 256;
+                                } else {
+                                    volume = volume_db * 256 + 0xffff + 1;
+                                }
+                                memcpy(*data, &volume, 2);
+                                *len = 2;
+                                break;
+                            case AUDIO_REQUEST_GET_MIN:
+                                (*data)[0] = 0x00; /* -2560/256 dB */
+                                (*data)[1] = 0xdb;
+                                *len = 2;
+                                break;
+                            case AUDIO_REQUEST_GET_MAX:
+                                (*data)[0] = 0x00; /* 0 dB */
+                                (*data)[1] = 0x00;
+                                *len = 2;
+                                break;
+                            case AUDIO_REQUEST_GET_RES:
+                                (*data)[0] = 0x00; /* -256/256 dB */
+                                (*data)[1] = 0x01;
+                                *len = 2;
+                                break;
+                            default:
+                                USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
+                                return -1;
+                        }
+                    } else {
+                        switch (setup->bRequest) {
+                            case AUDIO_REQUEST_CUR:
+                                if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
+                                    volume_db = usbd_audio_get_volume(busid, ep, ch);
+                                    volume = volume_db;
+                                    memcpy(*data, &volume, 2);
+                                    *len = 2;
+                                } else {
+                                    memcpy(&volume, *data, *len);
+                                    volume_db = volume;
+                                    USB_LOG_DBG("Set ep:0x%02x ch:%d volume:0x%02x\r\n", ep, ch, volume);
+                                    usbd_audio_set_volume(busid, ep, ch, volume_db);
+                                }
+                                break;
+                            case AUDIO_REQUEST_RANGE:
+                                if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
+                                    *((uint16_t *)(*data + 0)) = 1;
+                                    *((uint16_t *)(*data + 2)) = 0;
+                                    *((uint16_t *)(*data + 4)) = 100;
+                                    *((uint16_t *)(*data + 6)) = 1;
+                                    *len = 8;
+                                } else {
+                                }
+                                break;
+                            default:
+                                //USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
+                                return -1;
+                        }
+                    }
+                    break;
+
+                default:
+                    USB_LOG_WRN("Unhandled Audio Class cs 0x%02x \r\n", control_selector);
+                    return -1;
+            }
+            break;
+        case AUDIO_CONTROL_CLOCK_SOURCE:
+            switch (control_selector) {
+                case AUDIO_CS_CONTROL_SAM_FREQ:
+                    switch (setup->bRequest) {
+                        case AUDIO_REQUEST_CUR:
+                            if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
+                                sampling_freq = usbd_audio_get_sampling_freq(busid, ep);
+                                memcpy(*data, &sampling_freq, 4);
+                                USB_LOG_DBG("Get ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
+                                *len = 4;
+                            } else {
+                                memcpy(&sampling_freq, *data, setup->wLength);
+                                USB_LOG_DBG("Set ep:0x%02x %d Hz\r\n", ep, (int)sampling_freq);
+                                usbd_audio_set_sampling_freq(busid, ep, sampling_freq);
+                            }
+                            break;
+                        case AUDIO_REQUEST_RANGE:
+                            if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
+                                uint8_t *sampling_freq_table = NULL;
+                                uint16_t num;
+
+                                usbd_audio_get_sampling_freq_table(busid, ep, &sampling_freq_table);
+                                num = (uint16_t)((uint16_t)(sampling_freq_table[1] << 8) | ((uint16_t)sampling_freq_table[0]));
+                                memcpy(*data, sampling_freq_table, (12 * num + 2));
+                                *len = (12 * num + 2);
+                            } else {
+                            }
+                            break;
+                        default:
+                            //USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
+                            return -1;
+                    }
+                    break;
+                case AUDIO_CS_CONTROL_CLOCK_VALID:
+                    if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
+                        (*data)[0] = 1;
+                        *len = 1;
+                    } else {
+                        return -1;
+                    }
+                    break;
+
+                default:
+                    //USB_LOG_WRN("Unhandled Audio Class cs 0x%02x \r\n", control_selector);
+                    return -1;
+            }
+            break;
+
+        default:
+            break;
+    }
+    return 0;
+}
+
+static void audio_notify_handler(uint8_t busid, uint8_t event, void *arg)
+{
+    switch (event) {
+        case USBD_EVENT_RESET:
+
+            break;
+
+        case USBD_EVENT_SET_INTERFACE: {
+            struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)arg;
+            if (intf->bAlternateSetting) {
+                usbd_audio_open(busid, intf->bInterfaceNumber);
+            } else {
+                usbd_audio_close(busid, intf->bInterfaceNumber);
+            }
+        }
+
+        break;
+
+        default:
+            break;
+    }
+}
+
+struct usbd_interface *usbd_audio_init_intf(uint8_t busid, 
+                                            struct usbd_interface *intf,
+                                            uint16_t uac_version,
+                                            struct audio_entity_info *table,
+                                            uint8_t num)
+{
+    if (uac_version < 0x0200) {
+        intf->class_interface_handler = audio_class_interface_request_handler;
+        intf->class_endpoint_handler = audio_class_endpoint_request_handler;
+        intf->vendor_handler = NULL;
+        intf->notify_handler = audio_notify_handler;
+    } else {
+        intf->class_interface_handler = audio_class_interface_request_handler;
+        intf->class_endpoint_handler = NULL;
+        intf->vendor_handler = NULL;
+        intf->notify_handler = audio_notify_handler;
+    }
+
+    g_usbd_audio[busid].uac_version = uac_version;
+    g_usbd_audio[busid].table = table;
+    g_usbd_audio[busid].num = num;
+
+    return intf;
+}
+
+__WEAK void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume)
+{
+}
+
+__WEAK int usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch)
+{
+    return 0;
+}
+
+__WEAK void usbd_audio_set_mute(uint8_t busid, uint8_t ep, uint8_t ch, bool mute)
+{
+}
+
+__WEAK bool usbd_audio_get_mute(uint8_t busid, uint8_t ep, uint8_t ch)
+{
+    return 0;
+}
+
+__WEAK void usbd_audio_set_sampling_freq(uint8_t busid, uint8_t ep, uint32_t sampling_freq)
+{
+}
+
+__WEAK uint32_t usbd_audio_get_sampling_freq(uint8_t busid, uint8_t ep)
+{
+    return 0;
+}
+
+__WEAK void usbd_audio_get_sampling_freq_table(uint8_t busid, uint8_t ep, uint8_t **sampling_freq_table)
+{
+}

+ 43 - 0
components/drivers/usb/cherryusb/class/audio/usbd_audio.h

@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_AUDIO_H
+#define USBD_AUDIO_H
+
+#include "usb_audio.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct audio_entity_info {
+    uint8_t bDescriptorSubtype;
+    uint8_t bEntityId;
+    uint8_t ep;
+};
+
+/* Init audio interface driver */
+struct usbd_interface *usbd_audio_init_intf(uint8_t busid, struct usbd_interface *intf,
+                                            uint16_t uac_version,
+                                            struct audio_entity_info *table,
+                                            uint8_t num);
+
+void usbd_audio_open(uint8_t busid, uint8_t intf);
+void usbd_audio_close(uint8_t busid, uint8_t intf);
+
+void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume);
+int usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch);
+void usbd_audio_set_mute(uint8_t busid, uint8_t ep, uint8_t ch, bool mute);
+bool usbd_audio_get_mute(uint8_t busid, uint8_t ep, uint8_t ch);
+void usbd_audio_set_sampling_freq(uint8_t busid, uint8_t ep, uint32_t sampling_freq);
+uint32_t usbd_audio_get_sampling_freq(uint8_t busid, uint8_t ep);
+
+void usbd_audio_get_sampling_freq_table(uint8_t busid, uint8_t ep, uint8_t **sampling_freq_table);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBD_AUDIO_H */

+ 483 - 0
components/drivers/usb/cherryusb/class/audio/usbh_audio.c

@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_audio.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "usbh_audio"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/audio%d"
+
+/* general descriptor field offsets */
+#define DESC_bLength            0 /** Length offset */
+#define DESC_bDescriptorType    1 /** Descriptor type offset */
+#define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
+
+/* interface descriptor field offsets */
+#define INTF_DESC_bInterfaceNumber  2 /** Interface number offset */
+#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
+
+#ifndef CONFIG_USBHOST_MAX_AUDIO_CLASS
+#define CONFIG_USBHOST_MAX_AUDIO_CLASS 4
+#endif
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_audio_buf[128];
+
+static struct usbh_audio g_audio_class[CONFIG_USBHOST_MAX_AUDIO_CLASS];
+static uint32_t g_devinuse = 0;
+
+static struct usbh_audio *usbh_audio_class_alloc(void)
+{
+    int devno;
+
+    for (devno = 0; devno < CONFIG_USBHOST_MAX_AUDIO_CLASS; devno++) {
+        if ((g_devinuse & (1 << devno)) == 0) {
+            g_devinuse |= (1 << devno);
+            memset(&g_audio_class[devno], 0, sizeof(struct usbh_audio));
+            g_audio_class[devno].minor = devno;
+            return &g_audio_class[devno];
+        }
+    }
+    return NULL;
+}
+
+static void usbh_audio_class_free(struct usbh_audio *audio_class)
+{
+    int devno = audio_class->minor;
+
+    if (devno >= 0 && devno < 32) {
+        g_devinuse &= ~(1 << devno);
+    }
+    memset(audio_class, 0, sizeof(struct usbh_audio));
+}
+
+int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t samp_freq)
+{
+    struct usb_setup_packet *setup = audio_class->hport->setup;
+    struct usb_endpoint_descriptor *ep_desc;
+    uint8_t mult;
+    uint16_t mps;
+    int ret;
+    uint8_t intf = 0xff;
+    uint8_t altsetting = 1;
+
+    if (audio_class->is_opened) {
+        return 0;
+    }
+
+    for (uint8_t i = 0; i < audio_class->module_num; i++) {
+        if (strcmp(name, audio_class->module[i].name) == 0) {
+            for (uint8_t j = 0; j < audio_class->num_of_intf_altsettings; j++) {
+                for (uint8_t k = 0; k < audio_class->module[i].altsetting[j].sampfreq_num; k++) {
+                    if (audio_class->module[i].altsetting[j].sampfreq[k] == samp_freq) {
+                        intf = audio_class->module[i].data_intf;
+                        altsetting = j;
+                        goto freq_found;
+                    }
+                }
+            }
+        }
+    }
+
+    return -USB_ERR_NODEV;
+
+freq_found:
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = USB_REQUEST_SET_INTERFACE;
+    setup->wValue = altsetting;
+    setup->wIndex = intf;
+    setup->wLength = 0;
+
+    ret = usbh_control_transfer(audio_class->hport, setup, NULL);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_ENDPOINT;
+    setup->bRequest = AUDIO_REQUEST_SET_CUR;
+    setup->wValue = (AUDIO_EP_CONTROL_SAMPLING_FEQ << 8) | 0x00;
+    setup->wIndex = ep_desc->bEndpointAddress;
+    setup->wLength = 3;
+
+    memcpy(g_audio_buf, &samp_freq, 3);
+    ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
+    if (ret < 0) {
+        return ret;
+    }
+
+    mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
+    mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
+    if (ep_desc->bEndpointAddress & 0x80) {
+        audio_class->isoin_mps = mps * (mult + 1);
+        USBH_EP_INIT(audio_class->isoin, ep_desc);
+    } else {
+        audio_class->isoout_mps = mps * (mult + 1);
+        USBH_EP_INIT(audio_class->isoout, ep_desc);
+    }
+
+    USB_LOG_INFO("Open audio module :%s, altsetting: %u\r\n", name, altsetting);
+    audio_class->is_opened = true;
+    return ret;
+}
+
+int usbh_audio_close(struct usbh_audio *audio_class, const char *name)
+{
+    struct usb_setup_packet *setup = audio_class->hport->setup;
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret;
+    uint8_t intf = 0xff;
+    uint8_t altsetting = 1;
+
+    for (size_t i = 0; i < audio_class->module_num; i++) {
+        if (strcmp(name, audio_class->module[i].name) == 0) {
+            intf = audio_class->module[i].data_intf;
+        }
+    }
+
+    if (intf == 0xff) {
+        return -USB_ERR_NODEV;
+    }
+
+    USB_LOG_INFO("Close audio module :%s\r\n", name);
+    audio_class->is_opened = false;
+
+    ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
+    if (ep_desc->bEndpointAddress & 0x80) {
+        if (audio_class->isoin) {
+            audio_class->isoin = NULL;
+        }
+    } else {
+        if (audio_class->isoout) {
+            audio_class->isoout = NULL;
+        }
+    }
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = USB_REQUEST_SET_INTERFACE;
+    setup->wValue = 0;
+    setup->wIndex = intf;
+    setup->wLength = 0;
+
+    ret = usbh_control_transfer(audio_class->hport, setup, NULL);
+
+    return ret;
+}
+
+int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, uint8_t volume)
+{
+    struct usb_setup_packet *setup = audio_class->hport->setup;
+    int ret;
+    uint8_t intf = 0xff;
+    uint8_t feature_id = 0xff;
+    uint16_t volume_hex;
+
+    for (size_t i = 0; i < audio_class->module_num; i++) {
+        if (strcmp(name, audio_class->module[i].name) == 0) {
+            intf = audio_class->ctrl_intf;
+            feature_id = audio_class->module[i].feature_unit_id;
+        }
+    }
+
+    if (intf == 0xff) {
+        return -USB_ERR_NODEV;
+    }
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = AUDIO_REQUEST_SET_CUR;
+    setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
+    setup->wIndex = (feature_id << 8) | intf;
+    setup->wLength = 2;
+
+    volume_hex = -0xDB00 / 100 * volume + 0xdb00;
+
+    memcpy(g_audio_buf, &volume_hex, 2);
+    ret = usbh_control_transfer(audio_class->hport, setup, NULL);
+
+    return ret;
+}
+
+int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_t ch, bool mute)
+{
+    struct usb_setup_packet *setup = audio_class->hport->setup;
+    int ret;
+    uint8_t intf = 0xff;
+    uint8_t feature_id = 0xff;
+
+    for (size_t i = 0; i < audio_class->module_num; i++) {
+        if (strcmp(name, audio_class->module[i].name) == 0) {
+            intf = audio_class->ctrl_intf;
+            feature_id = audio_class->module[i].feature_unit_id;
+        }
+    }
+
+    if (intf == 0xff) {
+        return -USB_ERR_NODEV;
+    }
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = AUDIO_REQUEST_SET_CUR;
+    setup->wValue = (AUDIO_FU_CONTROL_MUTE << 8) | ch;
+    setup->wIndex = (feature_id << 8) | intf;
+    setup->wLength = 1;
+
+    memcpy(g_audio_buf, &mute, 1);
+    ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
+
+    return ret;
+}
+
+void usbh_audio_list_module(struct usbh_audio *audio_class)
+{
+    USB_LOG_INFO("============= Audio module information ===================\r\n");
+    USB_LOG_RAW("bcdADC :%04x\r\n", audio_class->bcdADC);
+    USB_LOG_RAW("Num of modules :%u\r\n", audio_class->module_num);
+    USB_LOG_RAW("Num of altsettings:%u\r\n", audio_class->num_of_intf_altsettings);
+
+    for (uint8_t i = 0; i < audio_class->module_num; i++) {
+        USB_LOG_RAW("  module name :%s\r\n", audio_class->module[i].name);
+        USB_LOG_RAW("  module feature unit id :%d\r\n", audio_class->module[i].feature_unit_id);
+
+        for (uint8_t j = 0; j < audio_class->num_of_intf_altsettings; j++) {
+            if (j == 0) {
+                USB_LOG_RAW("      Ingore altsetting 0\r\n");
+                continue;
+            }
+            USB_LOG_RAW("      Altsetting %u\r\n", j);
+            USB_LOG_RAW("          module channels :%u\r\n", audio_class->module[i].altsetting[j].channels);
+            //USB_LOG_RAW("        module format_type :%u\r\n",audio_class->module[i].altsetting[j].format_type);
+            USB_LOG_RAW("          module bitresolution :%u\r\n", audio_class->module[i].altsetting[j].bitresolution);
+            USB_LOG_RAW("          module sampfreq num :%u\r\n", audio_class->module[i].altsetting[j].sampfreq_num);
+
+            for (uint8_t k = 0; k < audio_class->module[i].altsetting[j].sampfreq_num; k++) {
+                USB_LOG_RAW("              module sampfreq :%d hz\r\n", audio_class->module[i].altsetting[j].sampfreq[k]);
+            }
+        }
+    }
+
+    USB_LOG_INFO("============= Audio module information ===================\r\n");
+}
+
+static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret;
+    uint8_t cur_iface = 0xff;
+    uint8_t cur_iface_count = 0xff;
+    uint8_t cur_alt_setting = 0xff;
+    uint8_t input_offset = 0;
+    uint8_t output_offset = 0;
+    uint8_t feature_unit_offset = 0;
+    uint8_t format_offset = 0;
+    uint8_t *p;
+
+    struct usbh_audio *audio_class = usbh_audio_class_alloc();
+    if (audio_class == NULL) {
+        USB_LOG_ERR("Fail to alloc audio_class\r\n");
+        return -USB_ERR_NOMEM;
+    }
+
+    audio_class->hport = hport;
+    audio_class->ctrl_intf = intf;
+    audio_class->num_of_intf_altsettings = hport->config.intf[intf + 1].altsetting_num;
+
+    hport->config.intf[intf].priv = audio_class;
+
+    p = hport->raw_config_desc;
+    while (p[DESC_bLength]) {
+        switch (p[DESC_bDescriptorType]) {
+            case USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION:
+                cur_iface_count = p[3];
+                break;
+            case USB_DESCRIPTOR_TYPE_INTERFACE:
+                cur_iface = p[INTF_DESC_bInterfaceNumber];
+                cur_alt_setting = p[INTF_DESC_bAlternateSetting];
+                break;
+            case USB_DESCRIPTOR_TYPE_ENDPOINT:
+                break;
+            case AUDIO_INTERFACE_DESCRIPTOR_TYPE:
+                if (cur_iface == audio_class->ctrl_intf) {
+                    switch (p[DESC_bDescriptorSubType]) {
+                        case AUDIO_CONTROL_HEADER: {
+                            struct audio_cs_if_ac_header_descriptor *desc = (struct audio_cs_if_ac_header_descriptor *)p;
+                            audio_class->bcdADC = desc->bcdADC;
+                            audio_class->bInCollection = desc->bInCollection;
+                        } break;
+                        case AUDIO_CONTROL_INPUT_TERMINAL: {
+                            struct audio_cs_if_ac_input_terminal_descriptor *desc = (struct audio_cs_if_ac_input_terminal_descriptor *)p;
+
+                            audio_class->module[input_offset].input_terminal_id = desc->bTerminalID;
+                            audio_class->module[input_offset].input_terminal_type = desc->wTerminalType;
+                            audio_class->module[input_offset].input_channel_config = desc->wChannelConfig;
+
+                            if (desc->wTerminalType == AUDIO_TERMINAL_STREAMING) {
+                                audio_class->module[input_offset].terminal_link_id = desc->bTerminalID;
+                            }
+                            if (desc->wTerminalType == AUDIO_INTERM_MIC) {
+                                audio_class->module[input_offset].name = "mic";
+                            }
+                            input_offset++;
+                        } break;
+                            break;
+                        case AUDIO_CONTROL_OUTPUT_TERMINAL: {
+                            struct audio_cs_if_ac_output_terminal_descriptor *desc = (struct audio_cs_if_ac_output_terminal_descriptor *)p;
+                            audio_class->module[output_offset].output_terminal_id = desc->bTerminalID;
+                            audio_class->module[output_offset].output_terminal_type = desc->wTerminalType;
+                            if (desc->wTerminalType == AUDIO_TERMINAL_STREAMING) {
+                                audio_class->module[output_offset].terminal_link_id = desc->bTerminalID;
+                            }
+                            if (desc->wTerminalType == AUDIO_OUTTERM_SPEAKER) {
+                                audio_class->module[output_offset].name = "speaker";
+                            }
+                            output_offset++;
+                        } break;
+                        case AUDIO_CONTROL_FEATURE_UNIT: {
+                            struct audio_cs_if_ac_feature_unit_descriptor *desc = (struct audio_cs_if_ac_feature_unit_descriptor *)p;
+                            audio_class->module[feature_unit_offset].feature_unit_id = desc->bUnitID;
+                            audio_class->module[feature_unit_offset].feature_unit_controlsize = desc->bControlSize;
+
+                            for (uint8_t j = 0; j < desc->bControlSize; j++) {
+                                audio_class->module[feature_unit_offset].feature_unit_controls[j] = p[6 + j];
+                            }
+                            feature_unit_offset++;
+                        } break;
+                        case AUDIO_CONTROL_PROCESSING_UNIT:
+
+                            break;
+                        default:
+                            break;
+                    }
+                } else if ((cur_iface < (audio_class->ctrl_intf + cur_iface_count)) && (cur_iface > audio_class->ctrl_intf)) {
+                    switch (p[DESC_bDescriptorSubType]) {
+                        case AUDIO_STREAMING_GENERAL:
+
+                            break;
+                        case AUDIO_STREAMING_FORMAT_TYPE: {
+                            struct audio_cs_if_as_format_type_descriptor *desc = (struct audio_cs_if_as_format_type_descriptor *)p;
+
+                            audio_class->module[format_offset].data_intf = cur_iface;
+                            audio_class->module[format_offset].altsetting[cur_alt_setting].channels = desc->bNrChannels;
+                            audio_class->module[format_offset].altsetting[cur_alt_setting].format_type = desc->bFormatType;
+                            audio_class->module[format_offset].altsetting[cur_alt_setting].bitresolution = desc->bBitResolution;
+                            audio_class->module[format_offset].altsetting[cur_alt_setting].sampfreq_num = desc->bSamFreqType;
+
+                            for (uint8_t j = 0; j < desc->bSamFreqType; j++) {
+                                audio_class->module[format_offset].altsetting[cur_alt_setting].sampfreq[j] = (uint32_t)(p[10 + j] << 16) |
+                                                                                                             (uint32_t)(p[9 + j] << 8) |
+                                                                                                             (uint32_t)(p[8 + j] << 0);
+                            }
+                            if (cur_alt_setting == (hport->config.intf[intf + 1].altsetting_num - 1)) {
+                                format_offset++;
+                            }
+                        } break;
+                        default:
+                            break;
+                    }
+                }
+                break;
+            default:
+                break;
+        }
+        /* skip to next descriptor */
+        p += p[DESC_bLength];
+    }
+
+    if ((input_offset != output_offset) && (input_offset != feature_unit_offset) && (input_offset != format_offset)) {
+        return -USB_ERR_INVAL;
+    }
+
+    audio_class->module_num = input_offset;
+
+    for (size_t i = 0; i < audio_class->module_num; i++) {
+        ret = usbh_audio_close(audio_class, audio_class->module[i].name);
+        if (ret < 0) {
+            USB_LOG_ERR("Fail to close audio module :%s\r\n", audio_class->module[i].name);
+            return ret;
+        }
+    }
+
+    usbh_audio_list_module(audio_class);
+
+    snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, audio_class->minor);
+    USB_LOG_INFO("Register Audio Class:%s\r\n", hport->config.intf[intf].devname);
+
+    usbh_audio_run(audio_class);
+    return 0;
+}
+
+static int usbh_audio_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_audio *audio_class = (struct usbh_audio *)hport->config.intf[intf].priv;
+
+    if (audio_class) {
+        if (audio_class->isoin) {
+        }
+
+        if (audio_class->isoout) {
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister Audio Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_audio_stop(audio_class);
+        }
+
+        usbh_audio_class_free(audio_class);
+    }
+
+    return ret;
+}
+
+static int usbh_audio_data_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    return 0;
+}
+
+static int usbh_audio_data_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    return 0;
+}
+
+__WEAK void usbh_audio_run(struct usbh_audio *audio_class)
+{
+}
+
+__WEAK void usbh_audio_stop(struct usbh_audio *audio_class)
+{
+}
+
+const struct usbh_class_driver audio_ctrl_class_driver = {
+    .driver_name = "audio_ctrl",
+    .connect = usbh_audio_ctrl_connect,
+    .disconnect = usbh_audio_ctrl_disconnect
+};
+
+const struct usbh_class_driver audio_streaming_class_driver = {
+    .driver_name = "audio_streaming",
+    .connect = usbh_audio_data_connect,
+    .disconnect = usbh_audio_data_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info audio_ctrl_intf_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
+    .class = USB_DEVICE_CLASS_AUDIO,
+    .subclass = AUDIO_SUBCLASS_AUDIOCONTROL,
+    .protocol = 0x00,
+    .id_table = NULL,
+    .class_driver = &audio_ctrl_class_driver
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info audio_streaming_intf_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
+    .class = USB_DEVICE_CLASS_AUDIO,
+    .subclass = AUDIO_SUBCLASS_AUDIOSTREAMING,
+    .protocol = 0x00,
+    .id_table = NULL,
+    .class_driver = &audio_streaming_class_driver
+};

+ 76 - 0
components/drivers/usb/cherryusb/class/audio/usbh_audio.h

@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_AUDIO_H
+#define USBH_AUDIO_H
+
+#include "usb_audio.h"
+
+struct usbh_audio_format_type {
+    uint8_t channels;
+    uint8_t format_type;
+    uint8_t bitresolution;
+    uint8_t sampfreq_num;
+    uint32_t sampfreq[3];
+};
+
+/**
+ * bSourceID in feature_unit = input_terminal_id
+ * bSourceID in output_terminal = feature_unit_id
+ * terminal_link_id = input_terminal_id or output_terminal_id (if input_terminal_type or output_terminal_type is 0x0101)
+ *
+ *
+*/
+struct usbh_audio_module {
+    const char *name;
+    uint8_t data_intf;
+    uint8_t input_terminal_id;
+    uint16_t input_terminal_type;
+    uint16_t input_channel_config;
+    uint8_t output_terminal_id;
+    uint16_t output_terminal_type;
+    uint8_t feature_unit_id;
+    uint8_t feature_unit_controlsize;
+    uint8_t feature_unit_controls[8];
+    uint8_t terminal_link_id;
+    struct usbh_audio_format_type altsetting[CONFIG_USBHOST_MAX_INTF_ALTSETTINGS];
+};
+
+struct usbh_audio {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *isoin;  /* ISO IN endpoint */
+    struct usb_endpoint_descriptor *isoout; /* ISO OUT endpoint */
+
+    uint8_t ctrl_intf; /* interface number */
+    uint8_t minor;
+    uint16_t isoin_mps;
+    uint16_t isoout_mps;
+    bool is_opened;
+    uint16_t bcdADC;
+    uint8_t bInCollection;
+    uint8_t num_of_intf_altsettings;
+    struct usbh_audio_module module[2];
+    uint8_t module_num;
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t samp_freq);
+int usbh_audio_close(struct usbh_audio *audio_class, const char *name);
+int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, uint8_t volume);
+int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_t ch, bool mute);
+
+void usbh_audio_run(struct usbh_audio *audio_class);
+void usbh_audio_stop(struct usbh_audio *audio_class);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_AUDIO_H */

+ 698 - 0
components/drivers/usb/cherryusb/class/cdc/usb_cdc.h

@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_CDC_H
+#define USB_CDC_H
+
+/*------------------------------------------------------------------------------
+ *      Definitions  based on usbcdc11.pdf (www.usb.org)
+ *----------------------------------------------------------------------------*/
+/* Communication device class specification version 1.10 */
+#define CDC_V1_10 0x0110U
+// Communication device class specification version 1.2
+#define CDC_V1_2_0 0x0120U
+
+/* Communication interface class code */
+/* (usbcdc11.pdf, 4.2, Table 15) */
+#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02U
+
+/* Communication interface class subclass codes */
+/* (usbcdc11.pdf, 4.3, Table 16) */
+#define CDC_SUBCLASS_NONE       0x00 /* Reserved */
+#define CDC_SUBCLASS_DLC        0x01 /* Direct Line Control Model */
+#define CDC_SUBCLASS_ACM        0x02 /* Abstract Control Model */
+#define CDC_SUBCLASS_TCM        0x03 /* Telephone Control Model */
+#define CDC_SUBCLASS_MCM        0x04 /* Multi-Channel Control Model */
+#define CDC_SUBCLASS_CAPI       0x05 /* CAPI Control Model */
+#define CDC_SUBCLASS_ECM        0x06 /* Ethernet Networking Control Model */
+#define CDC_SUBCLASS_ATM        0x07 /* ATM Networking Control Model */
+                                     /* 0x08-0x0d Reserved (future use) */
+#define CDC_SUBCLASS_MBIM       0x0e /* MBIM Control Model */
+                                     /* 0x0f-0x7f Reserved (future use) */
+                                     /* 0x80-0xfe Reserved (vendor specific) */
+
+#define CDC_DIRECT_LINE_CONTROL_MODEL         0x01U
+#define CDC_ABSTRACT_CONTROL_MODEL            0x02U
+#define CDC_TELEPHONE_CONTROL_MODEL           0x03U
+#define CDC_MULTI_CHANNEL_CONTROL_MODEL       0x04U
+#define CDC_CAPI_CONTROL_MODEL                0x05U
+#define CDC_ETHERNET_NETWORKING_CONTROL_MODEL 0x06U
+#define CDC_ATM_NETWORKING_CONTROL_MODEL      0x07U
+#define CDC_WIRELESS_HANDSET_CONTROL_MODEL    0x08U
+#define CDC_DEVICE_MANAGEMENT                 0x09U
+#define CDC_MOBILE_DIRECT_LINE_MODEL          0x0AU
+#define CDC_OBEX                              0x0BU
+#define CDC_ETHERNET_EMULATION_MODEL          0x0CU
+#define CDC_NETWORK_CONTROL_MODEL             0x0DU
+
+/* Communication interface class control protocol codes */
+/* (usbcdc11.pdf, 4.4, Table 17) */
+#define CDC_COMMON_PROTOCOL_NONE                            0x00U
+#define CDC_COMMON_PROTOCOL_AT_COMMANDS                     0x01U
+#define CDC_COMMON_PROTOCOL_AT_COMMANDS_PCCA_101            0x02U
+#define CDC_COMMON_PROTOCOL_AT_COMMANDS_PCCA_101_AND_ANNEXO 0x03U
+#define CDC_COMMON_PROTOCOL_AT_COMMANDS_GSM_707             0x04U
+#define CDC_COMMON_PROTOCOL_AT_COMMANDS_3GPP_27007          0x05U
+#define CDC_COMMON_PROTOCOL_AT_COMMANDS_CDMA                0x06U
+#define CDC_COMMON_PROTOCOL_ETHERNET_EMULATION_MODEL        0x07U
+// NCM Communication Interface Protocol Codes
+// (usbncm10.pdf, 4.2, Table 4-2)
+#define CDC_NCM_PROTOCOL_NONE 0x00U
+#define CDC_NCM_PROTOCOL_OEM  0xFEU
+
+/* Data interface class code */
+/* (usbcdc11.pdf, 4.5, Table 18) */
+#define CDC_DATA_INTERFACE_CLASS 0x0A
+
+/* Data Interface Sub-Class Codes ********************************************/
+#define CDC_DATA_SUBCLASS_NONE  0x00
+
+/* Data interface class protocol codes */
+/* (usbcdc11.pdf, 4.7, Table 19) */
+#define CDC_DATA_PROTOCOL_ISDN_BRI            0x30
+#define CDC_DATA_PROTOCOL_HDLC                0x31
+#define CDC_DATA_PROTOCOL_TRANSPARENT         0x32
+#define CDC_DATA_PROTOCOL_Q921_MANAGEMENT     0x50
+#define CDC_DATA_PROTOCOL_Q921_DATA_LINK      0x51
+#define CDC_DATA_PROTOCOL_Q921_MULTIPLEXOR    0x52
+#define CDC_DATA_PROTOCOL_V42                 0x90
+#define CDC_DATA_PROTOCOL_EURO_ISDN           0x91
+#define CDC_DATA_PROTOCOL_V24_RATE_ADAPTATION 0x92
+#define CDC_DATA_PROTOCOL_CAPI                0x93
+#define CDC_DATA_PROTOCOL_HOST_BASED_DRIVER   0xFD
+#define CDC_DATA_PROTOCOL_DESCRIBED_IN_PUFD   0xFE
+
+/* Type values for bDescriptorType field of functional descriptors */
+/* (usbcdc11.pdf, 5.2.3, Table 24) */
+#define CDC_CS_INTERFACE 0x24
+#define CDC_CS_ENDPOINT  0x25
+
+/* Type values for bDescriptorSubtype field of functional descriptors */
+/* (usbcdc11.pdf, 5.2.3, Table 25) */
+#define CDC_FUNC_DESC_HEADER                          0x00
+#define CDC_FUNC_DESC_CALL_MANAGEMENT                 0x01
+#define CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT     0x02
+#define CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT          0x03
+#define CDC_FUNC_DESC_TELEPHONE_RINGER                0x04
+#define CDC_FUNC_DESC_REPORTING_CAPABILITIES          0x05
+#define CDC_FUNC_DESC_UNION                           0x06
+#define CDC_FUNC_DESC_COUNTRY_SELECTION               0x07
+#define CDC_FUNC_DESC_TELEPHONE_OPERATIONAL_MODES     0x08
+#define CDC_FUNC_DESC_USB_TERMINAL                    0x09
+#define CDC_FUNC_DESC_NETWORK_CHANNEL                 0x0A
+#define CDC_FUNC_DESC_PROTOCOL_UNIT                   0x0B
+#define CDC_FUNC_DESC_EXTENSION_UNIT                  0x0C
+#define CDC_FUNC_DESC_MULTI_CHANNEL_MANAGEMENT        0x0D
+#define CDC_FUNC_DESC_CAPI_CONTROL_MANAGEMENT         0x0E
+#define CDC_FUNC_DESC_ETHERNET_NETWORKING             0x0F
+#define CDC_FUNC_DESC_ATM_NETWORKING                  0x10
+#define CDC_FUNC_DESC_WIRELESS_HANDSET_CONTROL_MODEL  0x11
+#define CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL        0x12
+#define CDC_FUNC_DESC_MOBILE_DIRECT_LINE_MODEL_DETAIL 0x13
+#define CDC_FUNC_DESC_DEVICE_MANAGEMENT_MODEL         0x14
+#define CDC_FUNC_DESC_OBEX                            0x15
+#define CDC_FUNC_DESC_COMMAND_SET                     0x16
+#define CDC_FUNC_DESC_COMMAND_SET_DETAIL              0x17
+#define CDC_FUNC_DESC_TELEPHONE_CONTROL_MODEL         0x18
+#define CDC_FUNC_DESC_OBEX_SERVICE_IDENTIFIER         0x19
+#define CDC_FUNC_DESC_NCM                             0x1A
+
+/* CDC class-specific request codes */
+/* (usbcdc11.pdf, 6.2, Table 46) */
+/* see Table 45 for info about the specific requests. */
+#define CDC_REQUEST_SEND_ENCAPSULATED_COMMAND      0x00
+#define CDC_REQUEST_GET_ENCAPSULATED_RESPONSE      0x01
+#define CDC_REQUEST_SET_COMM_FEATURE               0x02
+#define CDC_REQUEST_GET_COMM_FEATURE               0x03
+#define CDC_REQUEST_CLEAR_COMM_FEATURE             0x04
+#define CDC_REQUEST_SET_AUX_LINE_STATE             0x10
+#define CDC_REQUEST_SET_HOOK_STATE                 0x11
+#define CDC_REQUEST_PULSE_SETUP                    0x12
+#define CDC_REQUEST_SEND_PULSE                     0x13
+#define CDC_REQUEST_SET_PULSE_TIME                 0x14
+#define CDC_REQUEST_RING_AUX_JACK                  0x15
+#define CDC_REQUEST_SET_LINE_CODING                0x20
+#define CDC_REQUEST_GET_LINE_CODING                0x21
+#define CDC_REQUEST_SET_CONTROL_LINE_STATE         0x22
+#define CDC_REQUEST_SEND_BREAK                     0x23
+#define CDC_REQUEST_SET_RINGER_PARMS               0x30
+#define CDC_REQUEST_GET_RINGER_PARMS               0x31
+#define CDC_REQUEST_SET_OPERATION_PARMS            0x32
+#define CDC_REQUEST_GET_OPERATION_PARMS            0x33
+#define CDC_REQUEST_SET_LINE_PARMS                 0x34
+#define CDC_REQUEST_GET_LINE_PARMS                 0x35
+#define CDC_REQUEST_DIAL_DIGITS                    0x36
+#define CDC_REQUEST_SET_UNIT_PARAMETER             0x37
+#define CDC_REQUEST_GET_UNIT_PARAMETER             0x38
+#define CDC_REQUEST_CLEAR_UNIT_PARAMETER           0x39
+#define CDC_REQUEST_GET_PROFILE                    0x3A
+#define CDC_REQUEST_SET_ETHERNET_MULTICAST_FILTERS 0x40
+#define CDC_REQUEST_SET_ETHERNET_PMP_FILTER        0x41
+#define CDC_REQUEST_GET_ETHERNET_PMP_FILTER        0x42
+#define CDC_REQUEST_SET_ETHERNET_PACKET_FILTER     0x43
+#define CDC_REQUEST_GET_ETHERNET_STATISTIC         0x44
+#define CDC_REQUEST_SET_ATM_DATA_FORMAT            0x50
+#define CDC_REQUEST_GET_ATM_DEVICE_STATISTICS      0x51
+#define CDC_REQUEST_SET_ATM_DEFAULT_VC             0x52
+#define CDC_REQUEST_GET_ATM_VC_STATISTICS          0x53
+#define CDC_REQUEST_GET_NTB_PARAMETERS             0x80
+#define CDC_REQUEST_GET_NET_ADDRESS                0x81
+#define CDC_REQUEST_SET_NET_ADDRESS                0x82
+#define CDC_REQUEST_GET_NTB_FORMAT                 0x83
+#define CDC_REQUEST_SET_NTB_FORMAT                 0x84
+#define CDC_REQUEST_GET_NTB_INPUT_SIZE             0x85
+#define CDC_REQUEST_SET_NTB_INPUT_SIZE             0x86
+#define CDC_REQUEST_GET_MAX_DATAGRAM_SIZE          0x87
+#define CDC_REQUEST_SET_MAX_DATAGRAM_SIZE          0x88
+#define CDC_REQUEST_GET_CRC_MODE                   0x89
+#define CDC_REQUEST_SET_CRC_MODE                   0x90
+
+/* Communication feature selector codes */
+/* (usbcdc11.pdf, 6.2.2..6.2.4, Table 47) */
+#define CDC_ABSTRACT_STATE  0x01
+#define CDC_COUNTRY_SETTING 0x02
+
+/** Control Signal Bitmap Values for SetControlLineState */
+#define SET_CONTROL_LINE_STATE_RTS 0x02
+#define SET_CONTROL_LINE_STATE_DTR 0x01
+
+/* Feature Status returned for ABSTRACT_STATE Selector */
+/* (usbcdc11.pdf, 6.2.3, Table 48) */
+#define CDC_IDLE_SETTING          (1 << 0)
+#define CDC_DATA_MULTPLEXED_STATE (1 << 1)
+
+/* Control signal bitmap values for the SetControlLineState request */
+/* (usbcdc11.pdf, 6.2.14, Table 51) */
+#define CDC_DTE_PRESENT      (1 << 0)
+#define CDC_ACTIVATE_CARRIER (1 << 1)
+
+/* CDC class-specific notification codes */
+/* (usbcdc11.pdf, 6.3, Table 68) */
+/* see Table 67 for Info about class-specific notifications */
+#define CDC_NOTIFICATION_NETWORK_CONNECTION 0x00
+#define CDC_RESPONSE_AVAILABLE              0x01
+#define CDC_AUX_JACK_HOOK_STATE             0x08
+#define CDC_RING_DETECT                     0x09
+#define CDC_NOTIFICATION_SERIAL_STATE       0x20
+#define CDC_CALL_STATE_CHANGE               0x28
+#define CDC_LINE_STATE_CHANGE               0x29
+#define CDC_CONNECTION_SPEED_CHANGE         0x2A
+
+/* UART state bitmap values (Serial state notification). */
+/* (usbcdc11.pdf, 6.3.5, Table 69) */
+#define CDC_SERIAL_STATE_OVERRUN        (1 << 6) /* receive data overrun error has occurred */
+#define CDC_SERIAL_STATE_OVERRUN_Pos    (6)
+#define CDC_SERIAL_STATE_OVERRUN_Msk    (1 << CDC_SERIAL_STATE_OVERRUN_Pos)
+#define CDC_SERIAL_STATE_PARITY         (1 << 5) /* parity error has occurred */
+#define CDC_SERIAL_STATE_PARITY_Pos     (5)
+#define CDC_SERIAL_STATE_PARITY_Msk     (1 << CDC_SERIAL_STATE_PARITY_Pos)
+#define CDC_SERIAL_STATE_FRAMING        (1 << 4) /* framing error has occurred */
+#define CDC_SERIAL_STATE_FRAMING_Pos    (4)
+#define CDC_SERIAL_STATE_FRAMING_Msk    (1 << CDC_SERIAL_STATE_FRAMING_Pos)
+#define CDC_SERIAL_STATE_RING           (1 << 3) /* state of ring signal detection */
+#define CDC_SERIAL_STATE_RING_Pos       (3)
+#define CDC_SERIAL_STATE_RING_Msk       (1 << CDC_SERIAL_STATE_RING_Pos)
+#define CDC_SERIAL_STATE_BREAK          (1 << 2) /* state of break detection */
+#define CDC_SERIAL_STATE_BREAK_Pos      (2)
+#define CDC_SERIAL_STATE_BREAK_Msk      (1 << CDC_SERIAL_STATE_BREAK_Pos)
+#define CDC_SERIAL_STATE_TX_CARRIER     (1 << 1) /* state of transmission carrier */
+#define CDC_SERIAL_STATE_TX_CARRIER_Pos (1)
+#define CDC_SERIAL_STATE_TX_CARRIER_Msk (1 << CDC_SERIAL_STATE_TX_CARRIER_Pos)
+#define CDC_SERIAL_STATE_RX_CARRIER     (1 << 0) /* state of receiver carrier */
+#define CDC_SERIAL_STATE_RX_CARRIER_Pos (0)
+#define CDC_SERIAL_STATE_RX_CARRIER_Msk (1 << CDC_SERIAL_STATE_RX_CARRIER_Pos)
+
+#define CDC_ECM_XMIT_OK                                     (1 << 0)
+#define CDC_ECM_RVC_OK                                      (1 << 1)
+#define CDC_ECM_XMIT_ERROR                                  (1 << 2)
+#define CDC_ECM_RCV_ERROR                                   (1 << 3)
+#define CDC_ECM_RCV_NO_BUFFER                               (1 << 4)
+#define CDC_ECM_DIRECTED_BYTES_XMIT                         (1 << 5)
+#define CDC_ECM_DIRECTED_FRAMES_XMIT                        (1 << 6)
+#define CDC_ECM_MULTICAST_BYTES_XMIT                        (1 << 7)
+#define CDC_ECM_MULTICAST_FRAMES_XMIT                       (1 << 8)
+#define CDC_ECM_BROADCAST_BYTES_XMIT                        (1 << 9)
+#define CDC_ECM_BROADCAST_FRAMES_XMIT                       (1 << 10)
+#define CDC_ECM_DIRECTED_BYTES_RCV                          (1 << 11)
+#define CDC_ECM_DIRECTED_FRAMES_RCV                         (1 << 12)
+#define CDC_ECM_MULTICAST_BYTES_RCV                         (1 << 13)
+#define CDC_ECM_MULTICAST_FRAMES_RCV                        (1 << 14)
+#define CDC_ECM_BROADCAST_BYTES_RCV                         (1 << 15)
+#define CDC_ECM_BROADCAST_FRAMES_RCV                        (1 << 16)
+#define CDC_ECM_RCV_CRC_ERROR                               (1 << 17)
+#define CDC_ECM_TRANSMIT_QUEUE_LENGTH                       (1 << 18)
+#define CDC_ECM_RCV_ERROR_ALIGNMENT                         (1 << 19)
+#define CDC_ECM_XMIT_ONE_COLLISION                          (1 << 20)
+#define CDC_ECM_XMIT_MORE_COLLISIONS                        (1 << 21)
+#define CDC_ECM_XMIT_DEFERRED                               (1 << 22)
+#define CDC_ECM_XMIT_MAX_COLLISIONS                         (1 << 23)
+#define CDC_ECM_RCV_OVERRUN                                 (1 << 24)
+#define CDC_ECM_XMIT_UNDERRUN                               (1 << 25)
+#define CDC_ECM_XMIT_HEARTBEAT_FAILURE                      (1 << 26)
+#define CDC_ECM_XMIT_TIMES_CRS_LOST                         (1 << 27)
+#define CDC_ECM_XMIT_LATE_COLLISIONS                        (1 << 28)
+
+#define CDC_ECM_MAC_STR_DESC                                (uint8_t *)"010202030000"
+#define CDC_ECM_MAC_ADDR0                                   0x00U /* 01 */
+#define CDC_ECM_MAC_ADDR1                                   0x02U /* 02 */
+#define CDC_ECM_MAC_ADDR2                                   0x02U /* 03 */
+#define CDC_ECM_MAC_ADDR3                                   0x03U /* 00 */
+#define CDC_ECM_MAC_ADDR4                                   0x00U /* 00 */
+#define CDC_ECM_MAC_ADDR5                                   0x00U /* 00 */
+
+#define CDC_ECM_NET_DISCONNECTED                            0x00U
+#define CDC_ECM_NET_CONNECTED                               0x01U
+
+#define CDC_ECM_ETH_STATS_RESERVED                          0xE0U
+#define CDC_ECM_BMREQUEST_TYPE_ECM                          0xA1U
+
+#define CDC_ECM_CONNECT_SPEED_UPSTREAM                      0x004C4B40U /* 5Mbps */
+#define CDC_ECM_CONNECT_SPEED_DOWNSTREAM                    0x004C4B40U /* 5Mbps */
+
+#define CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION              0x00
+#define CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE              0x01
+#define CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE         0x2A
+
+#define CDC_NCM_NTH16_SIGNATURE             0x484D434E
+#define CDC_NCM_NDP16_SIGNATURE_NCM0        0x304D434E
+#define CDC_NCM_NDP16_SIGNATURE_NCM1        0x314D434E
+
+/*------------------------------------------------------------------------------
+ *      Structures  based on usbcdc11.pdf (www.usb.org)
+ *----------------------------------------------------------------------------*/
+
+/* Header functional descriptor */
+/* (usbcdc11.pdf, 5.2.3.1) */
+/* This header must precede any list of class-specific descriptors. */
+struct cdc_header_descriptor {
+    uint8_t bFunctionLength;    /* size of this descriptor in bytes */
+    uint8_t bDescriptorType;    /* CS_INTERFACE descriptor type */
+    uint8_t bDescriptorSubtype; /* Header functional descriptor subtype */
+    uint16_t bcdCDC;            /* USB CDC specification release version */
+} __PACKED;
+
+/* Call management functional descriptor */
+/* (usbcdc11.pdf, 5.2.3.2) */
+/* Describes the processing of calls for the communication class interface. */
+struct cdc_call_management_descriptor {
+    uint8_t bFunctionLength;    /* size of this descriptor in bytes */
+    uint8_t bDescriptorType;    /* CS_INTERFACE descriptor type */
+    uint8_t bDescriptorSubtype; /* call management functional descriptor subtype */
+    uint8_t bmCapabilities;     /* capabilities that this configuration supports */
+    uint8_t bDataInterface;     /* interface number of the data class interface used for call management (optional) */
+} __PACKED;
+
+/* Abstract control management functional descriptor */
+/* (usbcdc11.pdf, 5.2.3.3) */
+/* Describes the command supported by the communication interface class with the Abstract Control Model subclass code. */
+struct cdc_abstract_control_management_descriptor {
+    uint8_t bFunctionLength;    /* size of this descriptor in bytes */
+    uint8_t bDescriptorType;    /* CS_INTERFACE descriptor type */
+    uint8_t bDescriptorSubtype; /* abstract control management functional descriptor subtype */
+    uint8_t bmCapabilities;     /* capabilities supported by this configuration */
+} __PACKED;
+
+/* Union functional descriptors */
+/* (usbcdc11.pdf, 5.2.3.8) */
+/* Describes the relationship between a group of interfaces that can be considered to form a functional unit. */
+struct cdc_union_descriptor {
+    uint8_t bFunctionLength;    /* size of this descriptor in bytes */
+    uint8_t bDescriptorType;    /* CS_INTERFACE descriptor type */
+    uint8_t bDescriptorSubtype; /* union functional descriptor subtype */
+    uint8_t bMasterInterface;   /* interface number designated as master */
+} __PACKED;
+
+/* Union functional descriptors with one slave interface */
+/* (usbcdc11.pdf, 5.2.3.8) */
+struct cdc_union_1slave_descriptor {
+    uint8_t bFunctionLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t bControlInterface;
+    uint8_t bSubordinateInterface0;
+} __PACKED;
+
+/* Line coding structure for GET_LINE_CODING / SET_LINE_CODING class requests*/
+/* Format of the data returned when a GetLineCoding request is received */
+/* (usbcdc11.pdf, 6.2.13) */
+struct cdc_line_coding {
+    uint32_t dwDTERate;  /* Data terminal rate in bits per second */
+    uint8_t bCharFormat; /* Number of stop bits */
+    uint8_t bParityType; /* Parity bit type */
+    uint8_t bDataBits;   /* Number of data bits */
+} __PACKED;
+
+/** Data structure for the notification about SerialState */
+struct cdc_acm_notification {
+    uint8_t bmRequestType;
+    uint8_t bNotificationType;
+    uint16_t wValue;
+    uint16_t wIndex;
+    uint16_t wLength;
+    uint16_t data;
+} __PACKED;
+
+/** Ethernet Networking Functional Descriptor */
+struct cdc_eth_descriptor {
+    uint8_t bFunctionLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubtype;
+    uint8_t iMACAddress;
+    uint32_t bmEthernetStatistics;
+    uint16_t wMaxSegmentSize;
+    uint16_t wNumberMCFilters;
+    uint8_t bNumberPowerFilters;
+} __PACKED;
+
+struct cdc_eth_notification {
+    uint8_t bmRequestType;
+    uint8_t bNotificationType;
+    uint16_t wValue;
+    uint16_t wIndex;
+    uint16_t wLength;
+    uint8_t data[8];
+} __PACKED;
+
+struct cdc_ncm_ntb_parameters {
+    uint16_t wLength;
+    uint16_t bmNtbFormatsSupported;
+    uint32_t dwNtbInMaxSize;
+    uint16_t wNdbInDivisor;
+    uint16_t wNdbInPayloadRemainder;
+    uint16_t wNdbInAlignment;
+    uint16_t wReserved;
+    uint32_t dwNtbOutMaxSize;
+    uint16_t wNdbOutDivisor;
+    uint16_t wNdbOutPayloadRemainder;
+    uint16_t wNdbOutAlignment;
+    uint16_t wNtbOutMaxDatagrams;
+};
+
+struct cdc_ncm_nth16 {
+    uint32_t dwSignature;
+    uint16_t wHeaderLength;
+    uint16_t wSequence;
+    uint16_t wBlockLength;
+    uint16_t wNdpIndex;
+};
+
+struct cdc_ncm_ndp16_datagram {
+    uint16_t wDatagramIndex;
+    uint16_t wDatagramLength;
+};
+
+struct cdc_ncm_ndp16 {
+    uint32_t dwSignature;
+    uint16_t wLength;
+    uint16_t wNextNdpIndex;
+    struct cdc_ncm_ndp16_datagram datagram[];
+};
+
+/*Length of template descriptor: 66 bytes*/
+#define CDC_ACM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 7)
+// clang-format off
+#define CDC_ACM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, str_idx) \
+    /* Interface Associate */                                                                  \
+    0x08,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION,             /* bDescriptorType */               \
+    bFirstInterface,                                       /* bFirstInterface */               \
+    0x02,                                                  /* bInterfaceCount */               \
+    USB_DEVICE_CLASS_CDC,                                  /* bFunctionClass */                \
+    CDC_ABSTRACT_CONTROL_MODEL,                            /* bFunctionSubClass */             \
+    CDC_COMMON_PROTOCOL_AT_COMMANDS,                       /* bFunctionProtocol */             \
+    0x00,                                                  /* iFunction */                     \
+    0x09,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE,                         /* bDescriptorType */               \
+    bFirstInterface,                                       /* bInterfaceNumber */              \
+    0x00,                                                  /* bAlternateSetting */             \
+    0x01,                                                  /* bNumEndpoints */                 \
+    USB_DEVICE_CLASS_CDC,                                  /* bInterfaceClass */               \
+    CDC_ABSTRACT_CONTROL_MODEL,                            /* bInterfaceSubClass */            \
+    CDC_COMMON_PROTOCOL_AT_COMMANDS,                       /* bInterfaceProtocol */            \
+    str_idx,                                               /* iInterface */                    \
+    0x05,                                                  /* bLength */                       \
+    CDC_CS_INTERFACE,                                      /* bDescriptorType */               \
+    CDC_FUNC_DESC_HEADER,                                  /* bDescriptorSubtype */            \
+    WBVAL(CDC_V1_10),                                      /* bcdCDC */                        \
+    0x05,                                                  /* bLength */                       \
+    CDC_CS_INTERFACE,                                      /* bDescriptorType */               \
+    CDC_FUNC_DESC_CALL_MANAGEMENT,                         /* bDescriptorSubtype */            \
+    0x00,                                                  /* bmCapabilities */                \
+    (uint8_t)(bFirstInterface + 1),                        /* bDataInterface */                \
+    0x04,                                                  /* bLength */                       \
+    CDC_CS_INTERFACE,                                      /* bDescriptorType */               \
+    CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT,             /* bDescriptorSubtype */            \
+    0x02,                                                  /* bmCapabilities */                \
+    0x05,                                                  /* bLength */                       \
+    CDC_CS_INTERFACE,                                      /* bDescriptorType */               \
+    CDC_FUNC_DESC_UNION,                                   /* bDescriptorSubtype */            \
+    bFirstInterface,                                       /* bMasterInterface */              \
+    (uint8_t)(bFirstInterface + 1),                        /* bSlaveInterface0 */              \
+    0x07,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,                          /* bDescriptorType */               \
+    int_ep,                                                /* bEndpointAddress */              \
+    0x03,                                                  /* bmAttributes */                  \
+    0x08, 0x00,                                            /* wMaxPacketSize */                \
+    0x0a,                                                  /* bInterval */                     \
+    0x09,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE,                         /* bDescriptorType */               \
+    (uint8_t)(bFirstInterface + 1),                        /* bInterfaceNumber */              \
+    0x00,                                                  /* bAlternateSetting */             \
+    0x02,                                                  /* bNumEndpoints */                 \
+    CDC_DATA_INTERFACE_CLASS,                              /* bInterfaceClass */               \
+    0x00,                                                  /* bInterfaceSubClass */            \
+    0x00,                                                  /* bInterfaceProtocol */            \
+    0x00,                                                  /* iInterface */                    \
+    0x07,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,                          /* bDescriptorType */               \
+    out_ep,                                                /* bEndpointAddress */              \
+    0x02,                                                  /* bmAttributes */                  \
+    WBVAL(wMaxPacketSize),                                 /* wMaxPacketSize */                \
+    0x00,                                                  /* bInterval */                     \
+    0x07,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,                          /* bDescriptorType */               \
+    in_ep,                                                 /* bEndpointAddress */              \
+    0x02,                                                  /* bmAttributes */                  \
+    WBVAL(wMaxPacketSize),                                 /* wMaxPacketSize */                \
+    0x00                                                   /* bInterval */
+// clang-format on
+
+/*Length of template descriptor: 66 bytes*/
+#define CDC_RNDIS_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 7)
+// clang-format off
+#define CDC_RNDIS_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, str_idx) \
+    /* Interface Associate */                                                                  \
+    0x08,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION,             /* bDescriptorType */               \
+    bFirstInterface,                                       /* bFirstInterface */               \
+    0x02,                                                  /* bInterfaceCount */               \
+    USB_DEVICE_CLASS_WIRELESS,                             /* bFunctionClass */                \
+    CDC_DIRECT_LINE_CONTROL_MODEL,                         /* bFunctionSubClass */             \
+    CDC_COMMON_PROTOCOL_AT_COMMANDS_PCCA_101_AND_ANNEXO,   /* bFunctionProtocol */             \
+    0x00,                                                  /* iFunction */                     \
+    0x09,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE,                         /* bDescriptorType */               \
+    bFirstInterface,                                       /* bInterfaceNumber */              \
+    0x00,                                                  /* bAlternateSetting */             \
+    0x01,                                                  /* bNumEndpoints */                 \
+    USB_DEVICE_CLASS_WIRELESS,                             /* bInterfaceClass */               \
+    CDC_DIRECT_LINE_CONTROL_MODEL,                         /* bInterfaceSubClass */            \
+    CDC_COMMON_PROTOCOL_AT_COMMANDS_PCCA_101_AND_ANNEXO,   /* bInterfaceProtocol */            \
+    str_idx,                                               /* iInterface */                    \
+    0x05,                                                  /* bLength */                       \
+    CDC_CS_INTERFACE,                                      /* bDescriptorType */               \
+    CDC_FUNC_DESC_HEADER,                                  /* bDescriptorSubtype */            \
+    WBVAL(CDC_V1_10),                                      /* bcdCDC */                        \
+    0x05,                                                  /* bLength */                       \
+    CDC_CS_INTERFACE,                                      /* bDescriptorType */               \
+    CDC_FUNC_DESC_CALL_MANAGEMENT,                         /* bDescriptorSubtype */            \
+    0x00,                                                  /* bmCapabilities */                \
+    (uint8_t)(bFirstInterface + 1),                        /* bDataInterface */                \
+    0x04,                                                  /* bLength */                       \
+    CDC_CS_INTERFACE,                                      /* bDescriptorType */               \
+    CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT,             /* bDescriptorSubtype */            \
+    0x00,                                                  /* bmCapabilities */                \
+    0x05,                                                  /* bLength */                       \
+    CDC_CS_INTERFACE,                                      /* bDescriptorType */               \
+    CDC_FUNC_DESC_UNION,                                   /* bDescriptorSubtype */            \
+    bFirstInterface,                                       /* bMasterInterface */              \
+    (uint8_t)(bFirstInterface + 1),                        /* bSlaveInterface0 */              \
+    0x07,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,                          /* bDescriptorType */               \
+    int_ep,                                                /* bEndpointAddress */              \
+    0x03,                                                  /* bmAttributes */                  \
+    0x08, 0x00,                                            /* wMaxPacketSize */                \
+    0x10,                                                  /* bInterval */                     \
+    0x09,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE,                         /* bDescriptorType */               \
+    (uint8_t)(bFirstInterface + 1),                        /* bInterfaceNumber */              \
+    0x00,                                                  /* bAlternateSetting */             \
+    0x02,                                                  /* bNumEndpoints */                 \
+    CDC_DATA_INTERFACE_CLASS,                              /* bInterfaceClass */               \
+    0x00,                                                  /* bInterfaceSubClass */            \
+    0x00,                                                  /* bInterfaceProtocol */            \
+    0x00,                                                  /* iInterface */                    \
+    0x07,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,                          /* bDescriptorType */               \
+    out_ep,                                                /* bEndpointAddress */              \
+    0x02,                                                  /* bmAttributes */                  \
+    WBVAL(wMaxPacketSize),                                 /* wMaxPacketSize */                \
+    0x00,                                                  /* bInterval */                     \
+    0x07,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,                          /* bDescriptorType */               \
+    in_ep,                                                 /* bEndpointAddress */              \
+    0x02,                                                  /* bmAttributes */                  \
+    WBVAL(wMaxPacketSize),                                 /* wMaxPacketSize */                \
+    0x00                                                   /* bInterval */
+// clang-format on
+
+#define DBVAL_BE(x) ((x >> 24) & 0xFF), ((x >> 16) & 0xFF), ((x >> 8) & 0xFF), (x & 0xFF)
+
+/*Length of template descriptor: 71 bytes*/
+#define CDC_ECM_DESCRIPTOR_LEN   (8 + 9 + 5 + 5 + 13 + 7 + 9 + 7 + 7)
+// clang-format off
+#define CDC_ECM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, \
+eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx) \
+    /* Interface Associate */                                                                  \
+    0x08,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION,             /* bDescriptorType */               \
+    bFirstInterface,                                       /* bFirstInterface */               \
+    0x02,                                                  /* bInterfaceCount */               \
+    USB_DEVICE_CLASS_CDC,                                  /* bFunctionClass */                \
+    CDC_ETHERNET_NETWORKING_CONTROL_MODEL,                 /* bFunctionSubClass */             \
+    CDC_COMMON_PROTOCOL_NONE,                              /* bFunctionProtocol */             \
+    0x00,                                                  /* iFunction */                     \
+    0x09,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE,                         /* bDescriptorType */               \
+    bFirstInterface,                                       /* bInterfaceNumber */              \
+    0x00,                                                  /* bAlternateSetting */             \
+    0x01,                                                  /* bNumEndpoints */                 \
+    USB_DEVICE_CLASS_CDC,                                  /* bInterfaceClass */               \
+    CDC_ETHERNET_NETWORKING_CONTROL_MODEL,                 /* bInterfaceSubClass */            \
+    CDC_COMMON_PROTOCOL_NONE,                              /* bInterfaceProtocol */            \
+    str_idx,                                               /* iInterface */                    \
+    0x05,                                                  /* bLength */                       \
+    CDC_CS_INTERFACE,                                      /* bDescriptorType */               \
+    CDC_FUNC_DESC_HEADER,                                  /* bDescriptorSubtype */            \
+    WBVAL(CDC_V1_10),                                      /* bcdCDC */                        \
+    0x05,                                                  /* bLength */                       \
+    CDC_CS_INTERFACE,                                      /* bDescriptorType */               \
+    CDC_FUNC_DESC_UNION,                                   /* bDescriptorSubtype */            \
+    bFirstInterface,                                       /* bMasterInterface */              \
+    (uint8_t)(bFirstInterface + 1),                        /* bSlaveInterface0 */              \
+    /* CDC_ECM Functional Descriptor */ \
+    0x0D,                                                   /* bFunctionLength */\
+    CDC_CS_INTERFACE,                                       /* bDescriptorType: CS_INTERFACE */\
+    CDC_FUNC_DESC_ETHERNET_NETWORKING, /* Ethernet Networking functional descriptor subtype  */\
+    str_idx,                                                    /* Device's MAC string index */\
+    DBVAL_BE(eth_statistics),                                /* Ethernet statistics (bitmap) */\
+    WBVAL(wMaxPacketSize),/* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
+    WBVAL(wNumberMCFilters),            /* wNumberMCFilters: the number of multicast filters */\
+    bNumberPowerFilters,          /* bNumberPowerFilters: the number of wakeup power filters */\
+    0x07,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,                          /* bDescriptorType */               \
+    int_ep,                                                /* bEndpointAddress */              \
+    0x03,                                                  /* bmAttributes */                  \
+    0x10, 0x00,                                            /* wMaxPacketSize */                \
+    0x10,                                                  /* bInterval */                     \
+    0x09,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE,                         /* bDescriptorType */               \
+    (uint8_t)(bFirstInterface + 1),                        /* bInterfaceNumber */              \
+    0x00,                                                  /* bAlternateSetting */             \
+    0x02,                                                  /* bNumEndpoints */                 \
+    CDC_DATA_INTERFACE_CLASS,                              /* bInterfaceClass */               \
+    0x00,                                                  /* bInterfaceSubClass */            \
+    0x00,                                                  /* bInterfaceProtocol */            \
+    0x00,                                                  /* iInterface */                    \
+    0x07,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,                          /* bDescriptorType */               \
+    out_ep,                                                /* bEndpointAddress */              \
+    0x02,                                                  /* bmAttributes */                  \
+    WBVAL(wMaxPacketSize),                                 /* wMaxPacketSize */                \
+    0x00,                                                  /* bInterval */                     \
+    0x07,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,                          /* bDescriptorType */               \
+    in_ep,                                                 /* bEndpointAddress */              \
+    0x02,                                                  /* bmAttributes */                  \
+    WBVAL(wMaxPacketSize),                                 /* wMaxPacketSize */                \
+    0x00                                                   /* bInterval */
+// clang-format on
+
+/*Length of template descriptor: 77 bytes*/
+#define CDC_NCM_DESCRIPTOR_LEN   (8 + 9 + 5 + 5 + 13 + 6 + 7 + 9 + 7 + 7)
+// clang-format off
+#define CDC_NCM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, \
+eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx) \
+    /* Interface Associate */                                                                  \
+    0x08,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION,             /* bDescriptorType */               \
+    bFirstInterface,                                       /* bFirstInterface */               \
+    0x02,                                                  /* bInterfaceCount */               \
+    USB_DEVICE_CLASS_CDC,                                  /* bFunctionClass */                \
+    CDC_NETWORK_CONTROL_MODEL,                             /* bFunctionSubClass */             \
+    CDC_COMMON_PROTOCOL_NONE,                              /* bFunctionProtocol */             \
+    0x00,                                                  /* iFunction */                     \
+    0x09,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE,                         /* bDescriptorType */               \
+    bFirstInterface,                                       /* bInterfaceNumber */              \
+    0x00,                                                  /* bAlternateSetting */             \
+    0x01,                                                  /* bNumEndpoints */                 \
+    USB_DEVICE_CLASS_CDC,                                  /* bInterfaceClass */               \
+    CDC_NETWORK_CONTROL_MODEL,                             /* bInterfaceSubClass */            \
+    CDC_COMMON_PROTOCOL_NONE,                              /* bInterfaceProtocol */            \
+    str_idx,                                               /* iInterface */                    \
+    0x05,                                                  /* bLength */                       \
+    CDC_CS_INTERFACE,                                      /* bDescriptorType */               \
+    CDC_FUNC_DESC_HEADER,                                  /* bDescriptorSubtype */            \
+    WBVAL(CDC_V1_10),                                      /* bcdCDC */                        \
+    0x05,                                                  /* bLength */                       \
+    CDC_CS_INTERFACE,                                      /* bDescriptorType */               \
+    CDC_FUNC_DESC_UNION,                                   /* bDescriptorSubtype */            \
+    bFirstInterface,                                       /* bMasterInterface */              \
+    (uint8_t)(bFirstInterface + 1),                        /* bSlaveInterface0 */              \
+    /* CDC ETH Functional Descriptor */ \
+    0x0D,                                                   /* bFunctionLength */\
+    CDC_CS_INTERFACE,                                       /* bDescriptorType: CS_INTERFACE */\
+    CDC_FUNC_DESC_ETHERNET_NETWORKING, /* Ethernet Networking functional descriptor subtype  */\
+    str_idx,                                                    /* Device's MAC string index */\
+    DBVAL_BE(eth_statistics),                                /* Ethernet statistics (bitmap) */\
+    WBVAL(wMaxPacketSize),/* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
+    WBVAL(wNumberMCFilters),            /* wNumberMCFilters: the number of multicast filters */\
+    bNumberPowerFilters,          /* bNumberPowerFilters: the number of wakeup power filters */\
+    0x06,                                                                                      \
+    CDC_CS_INTERFACE,                                                                          \
+    CDC_FUNC_DESC_NCM,                                                                         \
+    0x00, 0x01,                                                                                \
+    0x23,                                                                                      \
+    0x07,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,                          /* bDescriptorType */               \
+    int_ep,                                                /* bEndpointAddress */              \
+    0x03,                                                  /* bmAttributes */                  \
+    0x10, 0x00,                                            /* wMaxPacketSize */                \
+    0x10,                                                  /* bInterval */                     \
+    0x09,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE,                         /* bDescriptorType */               \
+    (uint8_t)(bFirstInterface + 1),                        /* bInterfaceNumber */              \
+    0x00,                                                  /* bAlternateSetting */             \
+    0x02,                                                  /* bNumEndpoints */                 \
+    CDC_DATA_INTERFACE_CLASS,                              /* bInterfaceClass */               \
+    0x00,                                                  /* bInterfaceSubClass */            \
+    0x00,                                                  /* bInterfaceProtocol */            \
+    0x00,                                                  /* iInterface */                    \
+    0x07,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,                          /* bDescriptorType */               \
+    out_ep,                                                /* bEndpointAddress */              \
+    0x02,                                                  /* bmAttributes */                  \
+    WBVAL(wMaxPacketSize),                                 /* wMaxPacketSize */                \
+    0x00,                                                  /* bInterval */                     \
+    0x07,                                                  /* bLength */                       \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,                          /* bDescriptorType */               \
+    in_ep,                                                 /* bEndpointAddress */              \
+    0x02,                                                  /* bmAttributes */                  \
+    WBVAL(wMaxPacketSize),                                 /* wMaxPacketSize */                \
+    0x00                                                   /* bInterval */
+// clang-format on
+
+#endif /* USB_CDC_H */

+ 118 - 0
components/drivers/usb/cherryusb/class/cdc/usbd_cdc.c

@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_cdc.h"
+
+const char *stop_name[] = { "1", "1.5", "2" };
+const char *parity_name[] = { "N", "O", "E", "M", "S" };
+
+static int cdc_acm_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    USB_LOG_DBG("CDC Class request: "
+                "bRequest 0x%02x\r\n",
+                setup->bRequest);
+
+    struct cdc_line_coding line_coding;
+    bool dtr, rts;
+    uint8_t intf_num = LO_BYTE(setup->wIndex);
+
+    switch (setup->bRequest) {
+        case CDC_REQUEST_SET_LINE_CODING:
+
+            /*******************************************************************************/
+            /* Line Coding Structure                                                       */
+            /*-----------------------------------------------------------------------------*/
+            /* Offset | Field       | Size | Value  | Description                          */
+            /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/
+            /* 4      | bCharFormat |   1  | Number | Stop bits                            */
+            /*                                        0 - 1 Stop bit                       */
+            /*                                        1 - 1.5 Stop bits                    */
+            /*                                        2 - 2 Stop bits                      */
+            /* 5      | bParityType |  1   | Number | Parity                               */
+            /*                                        0 - None                             */
+            /*                                        1 - Odd                              */
+            /*                                        2 - Even                             */
+            /*                                        3 - Mark                             */
+            /*                                        4 - Space                            */
+            /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).          */
+            /*******************************************************************************/
+            memcpy(&line_coding, *data, setup->wLength);
+            USB_LOG_DBG("Set intf:%d linecoding <%d %d %s %s>\r\n",
+                        intf_num,
+                        line_coding.dwDTERate,
+                        line_coding.bDataBits,
+                        parity_name[line_coding.bParityType],
+                        stop_name[line_coding.bCharFormat]);
+
+            usbd_cdc_acm_set_line_coding(busid, intf_num, &line_coding);
+            break;
+
+        case CDC_REQUEST_SET_CONTROL_LINE_STATE:
+            dtr = (setup->wValue & 0x0001);
+            rts = (setup->wValue & 0x0002);
+            USB_LOG_DBG("Set intf:%d DTR 0x%x,RTS 0x%x\r\n",
+                        intf_num,
+                        dtr,
+                        rts);
+            usbd_cdc_acm_set_dtr(busid, intf_num, dtr);
+            usbd_cdc_acm_set_rts(busid, intf_num, rts);
+            break;
+
+        case CDC_REQUEST_GET_LINE_CODING:
+            usbd_cdc_acm_get_line_coding(busid, intf_num, &line_coding);
+            memcpy(*data, &line_coding, 7);
+            *len = 7;
+            USB_LOG_DBG("Get intf:%d linecoding %d %d %d %d\r\n",
+                        intf_num,
+                        line_coding.dwDTERate,
+                        line_coding.bCharFormat,
+                        line_coding.bParityType,
+                        line_coding.bDataBits);
+            break;
+        case CDC_REQUEST_SEND_BREAK:
+            usbd_cdc_acm_send_break(busid, intf_num);
+            break;
+        default:
+            USB_LOG_WRN("Unhandled CDC Class bRequest 0x%02x\r\n", setup->bRequest);
+            return -1;
+    }
+
+    return 0;
+}
+
+struct usbd_interface *usbd_cdc_acm_init_intf(uint8_t busid, struct usbd_interface *intf)
+{
+    intf->class_interface_handler = cdc_acm_class_interface_request_handler;
+    intf->class_endpoint_handler = NULL;
+    intf->vendor_handler = NULL;
+    intf->notify_handler = NULL;
+
+    return intf;
+}
+
+__WEAK void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding)
+{
+}
+
+__WEAK void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding)
+{
+    line_coding->dwDTERate = 2000000;
+    line_coding->bDataBits = 8;
+    line_coding->bParityType = 0;
+    line_coding->bCharFormat = 0;
+}
+
+__WEAK void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr)
+{
+}
+
+__WEAK void usbd_cdc_acm_set_rts(uint8_t busid, uint8_t intf, bool rts)
+{
+}
+
+__WEAK void usbd_cdc_acm_send_break(uint8_t busid, uint8_t intf)
+{
+}

+ 29 - 0
components/drivers/usb/cherryusb/class/cdc/usbd_cdc.h

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_CDC_H
+#define USBD_CDC_H
+
+#include "usb_cdc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Init cdc acm interface driver */
+struct usbd_interface *usbd_cdc_acm_init_intf(uint8_t busid, struct usbd_interface *intf);
+
+/* Setup request command callback api */
+void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding);
+void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding);
+void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr);
+void usbd_cdc_acm_set_rts(uint8_t busid, uint8_t intf, bool rts);
+void usbd_cdc_acm_send_break(uint8_t busid, uint8_t intf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBD_CDC_H */

+ 247 - 0
components/drivers/usb/cherryusb/class/cdc/usbd_cdc_ecm.c

@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2023, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_cdc_ecm.h"
+
+#define CDC_ECM_OUT_EP_IDX 0
+#define CDC_ECM_IN_EP_IDX   1
+#define CDC_ECM_INT_EP_IDX  2
+
+/* Describe EndPoints configuration */
+static struct usbd_endpoint cdc_ecm_ep_data[3];
+
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_notify_buf[16];
+
+volatile uint8_t *g_cdc_ecm_rx_data_buffer = NULL;
+volatile uint32_t g_cdc_ecm_rx_data_length = 0;
+volatile uint32_t g_cdc_ecm_tx_data_length = 0;
+
+static volatile uint8_t g_current_net_status = 0;
+static volatile uint8_t g_cmd_intf = 0;
+
+static uint32_t g_connect_speed_table[2] = { CDC_ECM_CONNECT_SPEED_UPSTREAM,
+                                             CDC_ECM_CONNECT_SPEED_DOWNSTREAM };
+
+void usbd_cdc_ecm_send_notify(uint8_t notifycode, uint8_t value, uint32_t *speed)
+{
+    struct cdc_eth_notification *notify = (struct cdc_eth_notification *)g_cdc_ecm_notify_buf;
+    uint8_t bytes2send = 0;
+
+    notify->bmRequestType = CDC_ECM_BMREQUEST_TYPE_ECM;
+    notify->bNotificationType = notifycode;
+
+    switch (notifycode) {
+        case CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION:
+            notify->wValue = value;
+            notify->wIndex = g_cmd_intf;
+            notify->wLength = 0U;
+
+            for (uint8_t i = 0U; i < 8U; i++) {
+                notify->data[i] = 0U;
+            }
+            bytes2send = 8U;
+            break;
+        case CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE:
+            notify->wValue = 0U;
+            notify->wIndex = g_cmd_intf;
+            notify->wLength = 0U;
+            for (uint8_t i = 0U; i < 8U; i++) {
+                notify->data[i] = 0U;
+            }
+            bytes2send = 8U;
+            break;
+        case CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE:
+            notify->wValue = 0U;
+            notify->wIndex = g_cmd_intf;
+            notify->wLength = 0x0008U;
+            bytes2send = 16U;
+
+            memcpy(notify->data, speed, 8);
+            break;
+
+        default:
+            break;
+    }
+
+    if (bytes2send) {
+        usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr, g_cdc_ecm_notify_buf, bytes2send);
+    }
+}
+
+static int cdc_ecm_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    USB_LOG_DBG("CDC ECM Class request: "
+                "bRequest 0x%02x\r\n",
+                setup->bRequest);
+
+    g_cmd_intf = LO_BYTE(setup->wIndex);
+
+    switch (setup->bRequest) {
+        case CDC_REQUEST_SET_ETHERNET_PACKET_FILTER:
+            /* bit0 Promiscuous
+             * bit1 ALL Multicast
+             * bit2 Directed
+             * bit3 Broadcast
+             * bit4 Multicast
+            */
+            if (g_current_net_status == 0) {
+                g_current_net_status = 1;
+                usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, NULL);
+            }
+
+            break;
+        default:
+            USB_LOG_WRN("Unhandled CDC ECM Class bRequest 0x%02x\r\n", setup->bRequest);
+            return -1;
+    }
+
+    return 0;
+}
+
+void cdc_ecm_notify_handler(uint8_t busid, uint8_t event, void *arg)
+{
+    switch (event) {
+        case USBD_EVENT_RESET:
+            g_current_net_status = 0;
+            g_cdc_ecm_rx_data_length = 0;
+            g_cdc_ecm_tx_data_length = 0;
+            g_cdc_ecm_rx_data_buffer = NULL;
+            break;
+        case USBD_EVENT_CONFIGURED:
+            usbd_ep_start_read(0, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_data_length], usbd_get_ep_mps(busid, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr));
+            break;
+
+        default:
+            break;
+    }
+}
+
+void cdc_ecm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+    g_cdc_ecm_rx_data_length += nbytes;
+
+    if (nbytes < usbd_get_ep_mps(busid, ep)) {
+        g_cdc_ecm_rx_data_buffer = g_cdc_ecm_rx_buffer;
+        usbd_cdc_ecm_data_recv_done(g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_data_length);
+    } else {
+        usbd_ep_start_read(0, ep, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_data_length], usbd_get_ep_mps(busid, ep));
+    }
+}
+
+void cdc_ecm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+    if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
+        /* send zlp */
+        usbd_ep_start_write(0, ep, NULL, 0);
+    } else {
+        g_cdc_ecm_tx_data_length = 0;
+    }
+}
+
+void cdc_ecm_int_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+    if (g_current_net_status == 1) {
+        g_current_net_status = 2;
+        usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, g_connect_speed_table);
+    }
+}
+
+int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len)
+{
+    if (g_cdc_ecm_tx_data_length > 0) {
+        return -USB_ERR_BUSY;
+    }
+
+    g_cdc_ecm_tx_data_length = len;
+
+    USB_LOG_DBG("txlen:%d\r\n", g_cdc_ecm_tx_data_length);
+    return usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr, buf, g_cdc_ecm_tx_data_length);
+}
+
+void usbd_cdc_ecm_start_read_next(void)
+{
+    g_cdc_ecm_rx_data_length = 0;
+    g_cdc_ecm_rx_data_buffer = NULL;
+    usbd_ep_start_read(0, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, g_cdc_ecm_rx_buffer, usbd_get_ep_mps(busid, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr));
+}
+
+#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
+struct pbuf *usbd_cdc_ecm_eth_rx(void)
+{
+    struct pbuf *p;
+
+    if (g_cdc_ecm_rx_data_buffer == NULL) {
+        return NULL;
+    }
+    p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_data_length, PBUF_POOL);
+    if (p == NULL) {
+        usbd_cdc_ecm_start_read_next();
+        return NULL;
+    }
+    memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_data_length);
+    p->len = g_cdc_ecm_rx_data_length;
+
+    USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_data_length);
+    usbd_cdc_ecm_start_read_next();
+    return p;
+}
+
+int usbd_cdc_ecm_eth_tx(struct pbuf *p)
+{
+    struct pbuf *q;
+    uint8_t *buffer;
+
+    if (g_cdc_ecm_tx_data_length > 0) {
+        return -USB_ERR_BUSY;
+    }
+
+    if (p->tot_len > sizeof(g_cdc_ecm_tx_buffer)) {
+        p->tot_len = sizeof(g_cdc_ecm_tx_buffer);
+    }
+
+    buffer = g_cdc_ecm_tx_buffer;
+    for (q = p; q != NULL; q = q->next) {
+        memcpy(buffer, q->payload, q->len);
+        buffer += q->len;
+    }
+
+    g_cdc_ecm_tx_data_length = p->tot_len;
+
+    return usbd_cdc_ecm_start_write(g_cdc_ecm_tx_buffer, g_cdc_ecm_tx_data_length);
+}
+#endif
+
+struct usbd_interface *usbd_cdc_ecm_init_intf(struct usbd_interface *intf, const uint8_t int_ep, const uint8_t out_ep, const uint8_t in_ep)
+{
+    intf->class_interface_handler = cdc_ecm_class_interface_request_handler;
+    intf->class_endpoint_handler = NULL;
+    intf->vendor_handler = NULL;
+    intf->notify_handler = cdc_ecm_notify_handler;
+
+    cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr = out_ep;
+    cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_cb = cdc_ecm_bulk_out;
+    cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr = in_ep;
+    cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_cb = cdc_ecm_bulk_in;
+    cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr = int_ep;
+    cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_cb = cdc_ecm_int_in;
+
+    usbd_add_endpoint(0, &cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX]);
+    usbd_add_endpoint(0, &cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX]);
+    usbd_add_endpoint(0, &cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX]);
+
+    return intf;
+}
+
+void usbd_cdc_ecm_set_connect_speed(uint32_t speed[2])
+{
+    memcpy(g_connect_speed_table, speed, 8);
+}
+
+__WEAK void usbd_cdc_ecm_data_recv_done(uint8_t *buf, uint32_t len)
+{
+}

+ 42 - 0
components/drivers/usb/cherryusb/class/cdc/usbd_cdc_ecm.h

@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_CDC_ECM_H
+#define USBD_CDC_ECM_H
+
+#include "usb_cdc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Ethernet Maximum Segment size, typically 1514 bytes */
+#define CONFIG_CDC_ECM_ETH_MAX_SEGSZE 1514U
+
+/* Init cdc ecm interface driver */
+struct usbd_interface *usbd_cdc_ecm_init_intf(struct usbd_interface *intf, const uint8_t int_ep, const uint8_t out_ep, const uint8_t in_ep);
+
+/* Setup request command callback api */
+void usbd_cdc_ecm_set_connect_speed(uint32_t speed[2]);
+
+/* Api for eth only without any net stack */
+uint8_t *usbd_cdc_ecm_get_tx_buffer(void);
+void usbd_cdc_ecm_send_done(void);
+int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len);
+void usbd_cdc_ecm_data_recv_done(uint8_t *buf, uint32_t len);
+void usbd_cdc_ecm_start_read_next(void);
+
+#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
+#include "lwip/netif.h"
+#include "lwip/pbuf.h"
+struct pbuf *usbd_cdc_ecm_eth_rx(void);
+int usbd_cdc_ecm_eth_tx(struct pbuf *p);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBD_CDC_ECM_H */

+ 263 - 0
components/drivers/usb/cherryusb/class/cdc/usbh_cdc_acm.c

@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_cdc_acm.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "usbh_cdc_acm"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/ttyACM%d"
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_acm_buf[64];
+
+static struct usbh_cdc_acm g_cdc_acm_class[CONFIG_USBHOST_MAX_CDC_ACM_CLASS];
+static uint32_t g_devinuse = 0;
+
+static struct usbh_cdc_acm *usbh_cdc_acm_class_alloc(void)
+{
+    int devno;
+
+    for (devno = 0; devno < CONFIG_USBHOST_MAX_CDC_ACM_CLASS; devno++) {
+        if ((g_devinuse & (1 << devno)) == 0) {
+            g_devinuse |= (1 << devno);
+            memset(&g_cdc_acm_class[devno], 0, sizeof(struct usbh_cdc_acm));
+            g_cdc_acm_class[devno].minor = devno;
+            return &g_cdc_acm_class[devno];
+        }
+    }
+    return NULL;
+}
+
+static void usbh_cdc_acm_class_free(struct usbh_cdc_acm *cdc_acm_class)
+{
+    int devno = cdc_acm_class->minor;
+
+    if (devno >= 0 && devno < 32) {
+        g_devinuse &= ~(1 << devno);
+    }
+    memset(cdc_acm_class, 0, sizeof(struct usbh_cdc_acm));
+}
+
+int usbh_cdc_acm_set_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_line_coding *line_coding)
+{
+    struct usb_setup_packet *setup = cdc_acm_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_SET_LINE_CODING;
+    setup->wValue = 0;
+    setup->wIndex = cdc_acm_class->intf;
+    setup->wLength = 7;
+
+    memcpy(g_cdc_acm_buf, line_coding, sizeof(struct cdc_line_coding));
+
+    return usbh_control_transfer(cdc_acm_class->hport, setup, g_cdc_acm_buf);
+}
+
+int usbh_cdc_acm_get_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_line_coding *line_coding)
+{
+    struct usb_setup_packet *setup = cdc_acm_class->hport->setup;
+    int ret;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_GET_LINE_CODING;
+    setup->wValue = 0;
+    setup->wIndex = cdc_acm_class->intf;
+    setup->wLength = 7;
+
+    ret = usbh_control_transfer(cdc_acm_class->hport, setup, g_cdc_acm_buf);
+    if (ret < 0) {
+        return ret;
+    }
+    memcpy(line_coding, g_cdc_acm_buf, sizeof(struct cdc_line_coding));
+    return ret;
+}
+
+int usbh_cdc_acm_set_line_state(struct usbh_cdc_acm *cdc_acm_class, bool dtr, bool rts)
+{
+    struct usb_setup_packet *setup = cdc_acm_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE;
+    setup->wValue = (dtr << 0) | (rts << 1);
+    setup->wIndex = cdc_acm_class->intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(cdc_acm_class->hport, setup, NULL);
+}
+
+static int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret = 0;
+
+    struct usbh_cdc_acm *cdc_acm_class = usbh_cdc_acm_class_alloc();
+    if (cdc_acm_class == NULL) {
+        USB_LOG_ERR("Fail to alloc cdc_acm_class\r\n");
+        return -USB_ERR_NOMEM;
+    }
+
+    cdc_acm_class->hport = hport;
+    cdc_acm_class->intf = intf;
+
+    hport->config.intf[intf].priv = cdc_acm_class;
+    hport->config.intf[intf + 1].priv = NULL;
+
+#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY
+    ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
+    USBH_EP_INIT(cdc_acm_class->intin, ep_desc);
+#endif
+    for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[0].intf_desc.bNumEndpoints; i++) {
+        ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
+
+        if (ep_desc->bEndpointAddress & 0x80) {
+            USBH_EP_INIT(cdc_acm_class->bulkin, ep_desc);
+        } else {
+            USBH_EP_INIT(cdc_acm_class->bulkout, ep_desc);
+        }
+    }
+
+    snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, cdc_acm_class->minor);
+
+    USB_LOG_INFO("Register CDC ACM Class:%s\r\n", hport->config.intf[intf].devname);
+
+#if 0
+    USB_LOG_INFO("Test cdc acm rx and tx and rx for 5 times, baudrate is 115200\r\n");
+
+    struct cdc_line_coding linecoding;
+    uint8_t count = 5;
+
+    linecoding.dwDTERate = 115200;
+    linecoding.bDataBits = 8;
+    linecoding.bParityType = 0;
+    linecoding.bCharFormat = 0;
+    usbh_cdc_acm_set_line_coding(cdc_acm_class, &linecoding);
+    usbh_cdc_acm_set_line_state(cdc_acm_class, true, false);
+
+    memset(g_cdc_acm_buf, 'a', sizeof(g_cdc_acm_buf));
+    ret = usbh_cdc_acm_bulk_out_transfer(cdc_acm_class, g_cdc_acm_buf, sizeof(g_cdc_acm_buf), 0xfffffff);
+    USB_LOG_RAW("out ret:%d\r\n", ret);
+    while (count--) {
+        ret = usbh_cdc_acm_bulk_in_transfer(cdc_acm_class, g_cdc_acm_buf, sizeof(g_cdc_acm_buf), 0xfffffff);
+        USB_LOG_RAW("in ret:%d\r\n", ret);
+        if (ret > 0) {
+            for (uint32_t i = 0; i < ret; i++) {
+                USB_LOG_RAW("%02x ", g_cdc_acm_buf[i]);
+            }
+        }
+        USB_LOG_RAW("\r\n");
+    }
+#endif
+
+    usbh_cdc_acm_run(cdc_acm_class);
+    return ret;
+}
+
+static int usbh_cdc_acm_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)hport->config.intf[intf].priv;
+
+    if (cdc_acm_class) {
+        if (cdc_acm_class->bulkin) {
+            usbh_kill_urb(&cdc_acm_class->bulkin_urb);
+        }
+
+        if (cdc_acm_class->bulkout) {
+            usbh_kill_urb(&cdc_acm_class->bulkout_urb);
+        }
+
+#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY
+        if (cdc_acm_class->intin) {
+            usbh_kill_urb(&cdc_acm_class->intin_urb);
+        }
+#endif
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister CDC ACM Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_cdc_acm_stop(cdc_acm_class);
+        }
+
+        usbh_cdc_acm_class_free(cdc_acm_class);
+    }
+
+    return ret;
+}
+
+int usbh_cdc_acm_bulk_in_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+{
+    int ret;
+    struct usbh_urb *urb = &cdc_acm_class->bulkin_urb;
+
+    usbh_bulk_urb_fill(urb, cdc_acm_class->hport, cdc_acm_class->bulkin, buffer, buflen, timeout, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+int usbh_cdc_acm_bulk_out_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+{
+    int ret;
+    struct usbh_urb *urb = &cdc_acm_class->bulkout_urb;
+
+    usbh_bulk_urb_fill(urb, cdc_acm_class->hport, cdc_acm_class->bulkout, buffer, buflen, timeout, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+static int usbh_cdc_data_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    return 0;
+}
+
+static int usbh_cdc_data_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    return 0;
+}
+
+__WEAK void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class)
+{
+}
+
+__WEAK void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class)
+{
+}
+
+const struct usbh_class_driver cdc_acm_class_driver = {
+    .driver_name = "cdc_acm",
+    .connect = usbh_cdc_acm_connect,
+    .disconnect = usbh_cdc_acm_disconnect
+};
+
+const struct usbh_class_driver cdc_data_class_driver = {
+    .driver_name = "cdc_data",
+    .connect = usbh_cdc_data_connect,
+    .disconnect = usbh_cdc_data_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
+    .class = USB_DEVICE_CLASS_CDC,
+    .subclass = CDC_ABSTRACT_CONTROL_MODEL,
+    .protocol = CDC_COMMON_PROTOCOL_AT_COMMANDS,
+    .id_table = NULL,
+    .class_driver = &cdc_acm_class_driver
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info cdc_data_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS,
+    .class = USB_DEVICE_CLASS_CDC_DATA,
+    .subclass = 0x00,
+    .protocol = 0x00,
+    .id_table = NULL,
+    .class_driver = &cdc_data_class_driver
+};

+ 50 - 0
components/drivers/usb/cherryusb/class/cdc/usbh_cdc_acm.h

@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_CDC_ACM_H
+#define USBH_CDC_ACM_H
+
+#include "usb_cdc.h"
+
+struct usbh_cdc_acm {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY
+    struct usb_endpoint_descriptor *intin;   /* INTR IN endpoint (optional) */
+#endif
+    struct usbh_urb bulkout_urb;
+    struct usbh_urb bulkin_urb;
+#ifdef CONFIG_USBHOST_CDC_ACM_NOTIFY
+    struct usbh_urb intin_urb;
+#endif
+
+    struct cdc_line_coding linecoding;
+
+    uint8_t intf;
+    uint8_t minor;
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_cdc_acm_set_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_line_coding *line_coding);
+int usbh_cdc_acm_get_line_coding(struct usbh_cdc_acm *cdc_acm_class, struct cdc_line_coding *line_coding);
+int usbh_cdc_acm_set_line_state(struct usbh_cdc_acm *cdc_acm_class, bool dtr, bool rts);
+
+int usbh_cdc_acm_bulk_in_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
+int usbh_cdc_acm_bulk_out_transfer(struct usbh_cdc_acm *cdc_acm_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
+
+void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class);
+void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_CDC_ACM_H */

+ 319 - 0
components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ecm.c

@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_cdc_ecm.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "usbh_cdc_ecm"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/cdc_ether"
+
+/* general descriptor field offsets */
+#define DESC_bLength            0 /** Length offset */
+#define DESC_bDescriptorType    1 /** Descriptor type offset */
+#define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
+
+/* interface descriptor field offsets */
+#define INTF_DESC_bInterfaceNumber  2 /** Interface number offset */
+#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
+
+#define CONFIG_USBHOST_CDC_ECM_PKT_FILTER   0x000C
+#define CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE 1514U
+
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_inttx_buffer[16];
+
+static struct usbh_cdc_ecm g_cdc_ecm_class;
+
+static int usbh_cdc_ecm_set_eth_packet_filter(struct usbh_cdc_ecm *cdc_ecm_class, uint16_t filter_value)
+{
+    struct usb_setup_packet *setup = cdc_ecm_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_SET_ETHERNET_PACKET_FILTER;
+    setup->wValue = filter_value;
+    setup->wIndex = cdc_ecm_class->ctrl_intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(cdc_ecm_class->hport, setup, NULL);
+}
+
+int usbh_cdc_ecm_get_connect_status(struct usbh_cdc_ecm *cdc_ecm_class)
+{
+    int ret;
+
+    usbh_int_urb_fill(&cdc_ecm_class->intin_urb, cdc_ecm_class->hport, cdc_ecm_class->intin, g_cdc_ecm_inttx_buffer, 16, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+    ret = usbh_submit_urb(&cdc_ecm_class->intin_urb);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (g_cdc_ecm_inttx_buffer[1] == CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION) {
+        if (g_cdc_ecm_inttx_buffer[2] == CDC_ECM_NET_CONNECTED) {
+            cdc_ecm_class->connect_status = true;
+        } else {
+            cdc_ecm_class->connect_status = false;
+        }
+    } else if (g_cdc_ecm_inttx_buffer[1] == CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE) {
+        memcpy(cdc_ecm_class->speed, &g_cdc_ecm_inttx_buffer[8], 8);
+    }
+    return 0;
+}
+
+static int usbh_cdc_ecm_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret;
+    uint8_t altsetting = 0;
+    char mac_buffer[12];
+    uint8_t *p;
+    uint8_t cur_iface = 0xff;
+    uint8_t mac_str_idx = 0xff;
+
+    struct usbh_cdc_ecm *cdc_ecm_class = &g_cdc_ecm_class;
+
+    memset(cdc_ecm_class, 0, sizeof(struct usbh_cdc_ecm));
+
+    cdc_ecm_class->hport = hport;
+    cdc_ecm_class->ctrl_intf = intf;
+    cdc_ecm_class->data_intf = intf + 1;
+
+    hport->config.intf[intf].priv = cdc_ecm_class;
+    hport->config.intf[intf + 1].priv = NULL;
+
+    p = hport->raw_config_desc;
+    while (p[DESC_bLength]) {
+        switch (p[DESC_bDescriptorType]) {
+            case USB_DESCRIPTOR_TYPE_INTERFACE:
+                cur_iface = p[INTF_DESC_bInterfaceNumber];
+                //cur_alt_setting = p[INTF_DESC_bAlternateSetting];
+                break;
+            case CDC_CS_INTERFACE:
+                if ((cur_iface == cdc_ecm_class->ctrl_intf) && p[DESC_bDescriptorSubType] == CDC_FUNC_DESC_ETHERNET_NETWORKING) {
+                    struct cdc_eth_descriptor *desc = (struct cdc_eth_descriptor *)p;
+                    mac_str_idx = desc->iMACAddress;
+                    cdc_ecm_class->max_segment_size = desc->wMaxSegmentSize;
+                    goto get_mac;
+                }
+                break;
+
+            default:
+                break;
+        }
+        /* skip to next descriptor */
+        p += p[DESC_bLength];
+    }
+
+get_mac:
+    if (mac_str_idx == 0xff) {
+        USB_LOG_ERR("Do not find cdc ecm mac string\r\n");
+        return -1;
+    }
+
+    memset(mac_buffer, 0, 12);
+    ret = usbh_get_string_desc(cdc_ecm_class->hport, mac_str_idx, (uint8_t *)mac_buffer);
+    if (ret < 0) {
+        return ret;
+    }
+
+    for (int i = 0, j = 0; i < 12; i += 2, j++) {
+        char byte_str[3];
+        byte_str[0] = mac_buffer[i];
+        byte_str[1] = mac_buffer[i + 1];
+        byte_str[2] = '\0';
+
+        uint32_t byte = strtoul(byte_str, NULL, 16);
+        cdc_ecm_class->mac[j] = (unsigned char)byte;
+    }
+
+    USB_LOG_INFO("CDC ECM MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
+                 cdc_ecm_class->mac[0],
+                 cdc_ecm_class->mac[1],
+                 cdc_ecm_class->mac[2],
+                 cdc_ecm_class->mac[3],
+                 cdc_ecm_class->mac[4],
+                 cdc_ecm_class->mac[5]);
+
+    if (cdc_ecm_class->max_segment_size > CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE) {
+        USB_LOG_ERR("CDC ECM Max Segment Size is overflow, default is %u, but now %u\r\n", CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE, cdc_ecm_class->max_segment_size);
+    } else {
+        USB_LOG_INFO("CDC ECM Max Segment Size:%u\r\n", cdc_ecm_class->max_segment_size);
+    }
+
+    /* enable int ep */
+    ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
+    USBH_EP_INIT(cdc_ecm_class->intin, ep_desc);
+
+    if (hport->config.intf[intf + 1].altsetting_num > 1) {
+        altsetting = hport->config.intf[intf + 1].altsetting_num - 1;
+
+        for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[altsetting].intf_desc.bNumEndpoints; i++) {
+            ep_desc = &hport->config.intf[intf + 1].altsetting[altsetting].ep[i].ep_desc;
+
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(cdc_ecm_class->bulkin, ep_desc);
+            } else {
+                USBH_EP_INIT(cdc_ecm_class->bulkout, ep_desc);
+            }
+        }
+
+        USB_LOG_INFO("Select cdc ecm altsetting: %d\r\n", altsetting);
+        usbh_set_interface(cdc_ecm_class->hport, cdc_ecm_class->data_intf, altsetting);
+    } else {
+        for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[0].intf_desc.bNumEndpoints; i++) {
+            ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
+
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(cdc_ecm_class->bulkin, ep_desc);
+            } else {
+                USBH_EP_INIT(cdc_ecm_class->bulkout, ep_desc);
+            }
+        }
+    }
+
+    /* bit0 Promiscuous
+    * bit1 ALL Multicast
+    * bit2 Directed
+    * bit3 Broadcast
+    * bit4 Multicast
+    */
+    ret = usbh_cdc_ecm_set_eth_packet_filter(cdc_ecm_class, CONFIG_USBHOST_CDC_ECM_PKT_FILTER);
+    if (ret < 0) {
+        return ret;
+    }
+    USB_LOG_INFO("Set CDC ECM packet filter:%04x\r\n", CONFIG_USBHOST_CDC_ECM_PKT_FILTER);
+
+    memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
+
+    USB_LOG_INFO("Register CDC ECM Class:%s\r\n", hport->config.intf[intf].devname);
+
+    usbh_cdc_ecm_run(cdc_ecm_class);
+    return ret;
+}
+
+static int usbh_cdc_ecm_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_cdc_ecm *cdc_ecm_class = (struct usbh_cdc_ecm *)hport->config.intf[intf].priv;
+
+    if (cdc_ecm_class) {
+        if (cdc_ecm_class->bulkin) {
+            usbh_kill_urb(&cdc_ecm_class->bulkin_urb);
+        }
+
+        if (cdc_ecm_class->bulkout) {
+            usbh_kill_urb(&cdc_ecm_class->bulkout_urb);
+        }
+
+        if (cdc_ecm_class->intin) {
+            usbh_kill_urb(&cdc_ecm_class->intin_urb);
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister CDC ECM Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_cdc_ecm_stop(cdc_ecm_class);
+        }
+
+        memset(cdc_ecm_class, 0, sizeof(struct usbh_cdc_ecm));
+    }
+
+    return ret;
+}
+
+void usbh_cdc_ecm_rx_thread(void *argument)
+{
+    uint32_t g_cdc_ecm_rx_length;
+    int ret;
+
+    USB_LOG_INFO("Create cdc ecm rx thread\r\n");
+    // clang-format off
+find_class:
+    // clang-format on
+    g_cdc_ecm_class.connect_status = false;
+    if (usbh_find_class_instance("/dev/cdc_ether") == NULL) {
+        goto delete;
+    }
+
+    while (g_cdc_ecm_class.connect_status == false) {
+        ret = usbh_cdc_ecm_get_connect_status(&g_cdc_ecm_class);
+        if (ret < 0) {
+            usb_osal_msleep(100);
+            goto find_class;
+        }
+    }
+
+    g_cdc_ecm_rx_length = 0;
+    while (1) {
+        usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkin_urb, g_cdc_ecm_class.hport, g_cdc_ecm_class.bulkin, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_length], CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+        ret = usbh_submit_urb(&g_cdc_ecm_class.bulkin_urb);
+        if (ret < 0) {
+            goto find_class;
+        }
+
+        g_cdc_ecm_rx_length += g_cdc_ecm_class.bulkin_urb.actual_length;
+
+        if (g_cdc_ecm_rx_length % USB_GET_MAXPACKETSIZE(g_cdc_ecm_class.bulkin->wMaxPacketSize)) {
+            USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_length);
+
+            usbh_cdc_ecm_eth_input(g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_length);
+
+            g_cdc_ecm_rx_length = 0;
+        } else {
+            /* read continue util read short packet */
+            if (g_cdc_ecm_rx_length > CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE) {
+                USB_LOG_ERR("Rx packet is overflow\r\n");
+                g_cdc_ecm_rx_length = 0;
+            }
+        }
+    }
+    // clang-format off
+delete:
+    USB_LOG_INFO("Delete cdc ecm rx thread\r\n");
+    usb_osal_thread_delete(NULL);
+    // clang-format on
+}
+
+int usbh_cdc_ecm_eth_output(uint8_t *buf, uint32_t buflen)
+{
+    uint8_t *buffer = g_cdc_ecm_tx_buffer;
+
+    if (g_cdc_ecm_class.connect_status == false) {
+        return -USB_ERR_NOTCONN;
+    }
+
+    memcpy(buffer, buf, buflen);
+
+    USB_LOG_DBG("txlen:%d\r\n", buflen);
+
+    usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkout_urb, g_cdc_ecm_class.hport, g_cdc_ecm_class.bulkout, g_cdc_ecm_tx_buffer, buflen, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+    return usbh_submit_urb(&g_cdc_ecm_class.bulkout_urb);
+}
+
+__WEAK void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
+{
+}
+
+__WEAK void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
+{
+}
+
+const struct usbh_class_driver cdc_ecm_class_driver = {
+    .driver_name = "cdc_ecm",
+    .connect = usbh_cdc_ecm_connect,
+    .disconnect = usbh_cdc_ecm_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info cdc_ecm_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
+    .class = USB_DEVICE_CLASS_CDC,
+    .subclass = CDC_ETHERNET_NETWORKING_CONTROL_MODEL,
+    .protocol = CDC_COMMON_PROTOCOL_NONE,
+    .id_table = NULL,
+    .class_driver = &cdc_ecm_class_driver
+};

+ 49 - 0
components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ecm.h

@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_CDC_ECM_H
+#define USBH_CDC_ECM_H
+
+#include "usb_cdc.h"
+
+struct usbh_cdc_ecm {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+    struct usb_endpoint_descriptor *intin;   /* Interrupt IN endpoint */
+    struct usbh_urb bulkout_urb; /* Bulk out endpoint */
+    struct usbh_urb bulkin_urb; /* Bulk IN endpoint */
+    struct usbh_urb intin_urb; /* Interrupt IN endpoint */
+
+    uint8_t ctrl_intf; /* Control interface number */
+    uint8_t data_intf; /* Data interface number */
+    uint8_t minor;
+
+    uint8_t mac[6];
+    bool connect_status;
+    uint16_t max_segment_size;
+    uint32_t speed[2];
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_cdc_ecm_get_connect_status(struct usbh_cdc_ecm *cdc_ecm_class);
+
+void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class);
+void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class);
+
+int usbh_cdc_ecm_eth_output(uint8_t *buf, uint32_t buflen);
+void usbh_cdc_ecm_eth_input(uint8_t *buf, uint32_t buflen);
+void usbh_cdc_ecm_rx_thread(void *argument);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_CDC_ECM_H */

+ 388 - 0
components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ncm.c

@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_cdc_ncm.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "usbh_cdc_ncm"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/cdc_ncm"
+
+/* general descriptor field offsets */
+#define DESC_bLength            0 /** Length offset */
+#define DESC_bDescriptorType    1 /** Descriptor type offset */
+#define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
+
+/* interface descriptor field offsets */
+#define INTF_DESC_bInterfaceNumber  2 /** Interface number offset */
+#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
+
+#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_SEGSZE 1514U
+
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_rx_buffer[CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_tx_buffer[CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_inttx_buffer[16];
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_buf[32];
+
+static struct usbh_cdc_ncm g_cdc_ncm_class;
+
+static int usbh_cdc_ncm_get_ntb_parameters(struct usbh_cdc_ncm *cdc_ncm_class, struct cdc_ncm_ntb_parameters *param)
+{
+    struct usb_setup_packet *setup = cdc_ncm_class->hport->setup;
+    int ret;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_GET_NTB_PARAMETERS;
+    setup->wValue = 0;
+    setup->wIndex = cdc_ncm_class->ctrl_intf;
+    setup->wLength = 28;
+
+    ret = usbh_control_transfer(cdc_ncm_class->hport, setup, g_cdc_ncm_buf);
+    if (ret < 0) {
+        return ret;
+    }
+
+    memcpy((uint8_t *)param, g_cdc_ncm_buf, ret - 8);
+    return 0;
+}
+
+static void print_ntb_parameters(struct cdc_ncm_ntb_parameters *param)
+{
+    USB_LOG_RAW("CDC NCM ntb parameters:\r\n");
+    USB_LOG_RAW("wLength: 0x%02x             \r\n", param->wLength);
+    USB_LOG_RAW("bmNtbFormatsSupported: %s     \r\n", param->bmNtbFormatsSupported ? "NTB16" : "NTB32");
+
+    USB_LOG_RAW("dwNtbInMaxSize: 0x%04x           \r\n", param->dwNtbInMaxSize);
+    USB_LOG_RAW("wNdbInDivisor: 0x%02x \r\n", param->wNdbInDivisor);
+    USB_LOG_RAW("wNdbInPayloadRemainder: 0x%02x      \r\n", param->wNdbInPayloadRemainder);
+    USB_LOG_RAW("wNdbInAlignment: 0x%02x    \r\n", param->wNdbInAlignment);
+
+    USB_LOG_RAW("dwNtbOutMaxSize: 0x%04x     \r\n", param->dwNtbOutMaxSize);
+    USB_LOG_RAW("wNdbOutDivisor: 0x%02x     \r\n", param->wNdbOutDivisor);
+    USB_LOG_RAW("wNdbOutPayloadRemainder: 0x%02x     \r\n", param->wNdbOutPayloadRemainder);
+    USB_LOG_RAW("wNdbOutAlignment: 0x%02x     \r\n", param->wNdbOutAlignment);
+
+    USB_LOG_RAW("wNtbOutMaxDatagrams: 0x%02x     \r\n", param->wNtbOutMaxDatagrams);
+}
+
+int usbh_cdc_ncm_get_connect_status(struct usbh_cdc_ncm *cdc_ncm_class)
+{
+    int ret;
+
+    usbh_int_urb_fill(&cdc_ncm_class->intin_urb, cdc_ncm_class->hport, cdc_ncm_class->intin, g_cdc_ncm_inttx_buffer, 16, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+    ret = usbh_submit_urb(&cdc_ncm_class->intin_urb);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (g_cdc_ncm_inttx_buffer[1] == CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION) {
+        if (g_cdc_ncm_inttx_buffer[2] == CDC_ECM_NET_CONNECTED) {
+            cdc_ncm_class->connect_status = true;
+        } else {
+            cdc_ncm_class->connect_status = false;
+        }
+    } else if (g_cdc_ncm_inttx_buffer[1] == CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE) {
+        memcpy(cdc_ncm_class->speed, &g_cdc_ncm_inttx_buffer[8], 8);
+    }
+    return 0;
+}
+
+static int usbh_cdc_ncm_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret;
+    uint8_t altsetting = 0;
+    char mac_buffer[12];
+    uint8_t *p;
+    uint8_t cur_iface = 0xff;
+    uint8_t mac_str_idx = 0xff;
+
+    struct usbh_cdc_ncm *cdc_ncm_class = &g_cdc_ncm_class;
+
+    memset(cdc_ncm_class, 0, sizeof(struct usbh_cdc_ncm));
+
+    cdc_ncm_class->hport = hport;
+    cdc_ncm_class->ctrl_intf = intf;
+    cdc_ncm_class->data_intf = intf + 1;
+
+    hport->config.intf[intf].priv = cdc_ncm_class;
+    hport->config.intf[intf + 1].priv = NULL;
+
+    p = hport->raw_config_desc;
+    while (p[DESC_bLength]) {
+        switch (p[DESC_bDescriptorType]) {
+            case USB_DESCRIPTOR_TYPE_INTERFACE:
+                cur_iface = p[INTF_DESC_bInterfaceNumber];
+                //cur_alt_setting = p[INTF_DESC_bAlternateSetting];
+                break;
+            case CDC_CS_INTERFACE:
+                if ((cur_iface == cdc_ncm_class->ctrl_intf) && p[DESC_bDescriptorSubType] == CDC_FUNC_DESC_ETHERNET_NETWORKING) {
+                    struct cdc_eth_descriptor *desc = (struct cdc_eth_descriptor *)p;
+                    mac_str_idx = desc->iMACAddress;
+                    cdc_ncm_class->max_segment_size = desc->wMaxSegmentSize;
+                    goto get_mac;
+                }
+                break;
+
+            default:
+                break;
+        }
+        /* skip to next descriptor */
+        p += p[DESC_bLength];
+    }
+
+get_mac:
+    if (mac_str_idx == 0xff) {
+        USB_LOG_ERR("Do not find cdc ncm mac string\r\n");
+        return -1;
+    }
+
+    memset(mac_buffer, 0, 12);
+    ret = usbh_get_string_desc(cdc_ncm_class->hport, mac_str_idx, (uint8_t *)mac_buffer);
+    if (ret < 0) {
+        return ret;
+    }
+
+    for (int i = 0, j = 0; i < 12; i += 2, j++) {
+        char byte_str[3];
+        byte_str[0] = mac_buffer[i];
+        byte_str[1] = mac_buffer[i + 1];
+        byte_str[2] = '\0';
+
+        uint32_t byte = strtoul(byte_str, NULL, 16);
+        cdc_ncm_class->mac[j] = (unsigned char)byte;
+    }
+
+    USB_LOG_INFO("CDC NCM MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
+                 cdc_ncm_class->mac[0],
+                 cdc_ncm_class->mac[1],
+                 cdc_ncm_class->mac[2],
+                 cdc_ncm_class->mac[3],
+                 cdc_ncm_class->mac[4],
+                 cdc_ncm_class->mac[5]);
+
+    if (cdc_ncm_class->max_segment_size > CONFIG_USBHOST_CDC_NCM_ETH_MAX_SEGSZE) {
+        USB_LOG_ERR("CDC NCM Max Segment Size is overflow, default is %u, but now %u\r\n", CONFIG_USBHOST_CDC_NCM_ETH_MAX_SEGSZE, cdc_ncm_class->max_segment_size);
+    } else {
+        USB_LOG_INFO("CDC NCM Max Segment Size:%u\r\n", cdc_ncm_class->max_segment_size);
+    }
+
+    usbh_cdc_ncm_get_ntb_parameters(cdc_ncm_class, &cdc_ncm_class->ntb_param);
+    print_ntb_parameters(&cdc_ncm_class->ntb_param);
+
+    /* enable int ep */
+    ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
+    USBH_EP_INIT(cdc_ncm_class->intin, ep_desc);
+
+    if (hport->config.intf[intf + 1].altsetting_num > 1) {
+        altsetting = hport->config.intf[intf + 1].altsetting_num - 1;
+
+        for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[altsetting].intf_desc.bNumEndpoints; i++) {
+            ep_desc = &hport->config.intf[intf + 1].altsetting[altsetting].ep[i].ep_desc;
+
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(cdc_ncm_class->bulkin, ep_desc);
+            } else {
+                USBH_EP_INIT(cdc_ncm_class->bulkout, ep_desc);
+            }
+        }
+
+        USB_LOG_INFO("Select cdc ncm altsetting: %d\r\n", altsetting);
+        usbh_set_interface(cdc_ncm_class->hport, cdc_ncm_class->data_intf, altsetting);
+    } else {
+        for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[0].intf_desc.bNumEndpoints; i++) {
+            ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
+
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(cdc_ncm_class->bulkin, ep_desc);
+            } else {
+                USBH_EP_INIT(cdc_ncm_class->bulkout, ep_desc);
+            }
+        }
+    }
+
+    memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
+
+    USB_LOG_INFO("Register CDC NCM Class:%s\r\n", hport->config.intf[intf].devname);
+
+    usbh_cdc_ncm_run(cdc_ncm_class);
+    return ret;
+}
+
+static int usbh_cdc_ncm_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_cdc_ncm *cdc_ncm_class = (struct usbh_cdc_ncm *)hport->config.intf[intf].priv;
+
+    if (cdc_ncm_class) {
+        if (cdc_ncm_class->bulkin) {
+            usbh_kill_urb(&cdc_ncm_class->bulkin_urb);
+        }
+
+        if (cdc_ncm_class->bulkout) {
+            usbh_kill_urb(&cdc_ncm_class->bulkout_urb);
+        }
+
+        if (cdc_ncm_class->intin) {
+            usbh_kill_urb(&cdc_ncm_class->intin_urb);
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister CDC NCM Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_cdc_ncm_stop(cdc_ncm_class);
+        }
+
+        memset(cdc_ncm_class, 0, sizeof(struct usbh_cdc_ncm));
+    }
+
+    return ret;
+}
+
+void usbh_cdc_ncm_rx_thread(void *argument)
+{
+    uint32_t g_cdc_ncm_rx_length;
+    int ret;
+
+    USB_LOG_INFO("Create cdc ncm rx thread\r\n");
+    // clang-format off
+find_class:
+    // clang-format on
+    g_cdc_ncm_class.connect_status = false;
+    if (usbh_find_class_instance("/dev/cdc_ncm") == NULL) {
+        goto delete;
+    }
+
+    while (g_cdc_ncm_class.connect_status == false) {
+        ret = usbh_cdc_ncm_get_connect_status(&g_cdc_ncm_class);
+        if (ret < 0) {
+            usb_osal_msleep(100);
+            goto find_class;
+        }
+    }
+
+    g_cdc_ncm_rx_length = 0;
+    while (1) {
+        usbh_bulk_urb_fill(&g_cdc_ncm_class.bulkin_urb, g_cdc_ncm_class.hport, g_cdc_ncm_class.bulkin, &g_cdc_ncm_rx_buffer[g_cdc_ncm_rx_length], (CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE > (16 * 1024)) ? (16 * 1024) : CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+        ret = usbh_submit_urb(&g_cdc_ncm_class.bulkin_urb);
+        if (ret < 0) {
+            goto find_class;
+        }
+
+        g_cdc_ncm_rx_length += g_cdc_ncm_class.bulkin_urb.actual_length;
+
+        if (g_cdc_ncm_rx_length % USB_GET_MAXPACKETSIZE(g_cdc_ncm_class.bulkin->wMaxPacketSize)) {
+            USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ncm_rx_length);
+
+            struct cdc_ncm_nth16 *nth16 = (struct cdc_ncm_nth16 *)&g_cdc_ncm_rx_buffer[0];
+            if ((nth16->dwSignature != CDC_NCM_NTH16_SIGNATURE) ||
+                (nth16->wHeaderLength != 12) ||
+                (nth16->wBlockLength != g_cdc_ncm_rx_length)) {
+                USB_LOG_ERR("invalid rx nth16\r\n");
+                g_cdc_ncm_rx_length = 0;
+                continue;
+            }
+
+            struct cdc_ncm_ndp16 *ndp16 = (struct cdc_ncm_ndp16 *)&g_cdc_ncm_rx_buffer[nth16->wNdpIndex];
+            if ((ndp16->dwSignature != CDC_NCM_NDP16_SIGNATURE_NCM0) && (ndp16->dwSignature != CDC_NCM_NDP16_SIGNATURE_NCM1)) {
+                USB_LOG_ERR("invalid rx ndp16\r\n");
+                g_cdc_ncm_rx_length = 0;
+                continue;
+            }
+
+            uint16_t datagram_num = (ndp16->wLength - 8) / 4;
+
+            USB_LOG_DBG("datagram num:%02x\r\n", datagram_num);
+            for (uint16_t i = 0; i < datagram_num; i++) {
+                struct cdc_ncm_ndp16_datagram *ndp16_datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_rx_buffer[nth16->wNdpIndex + 8 + 4 * i];
+                if (ndp16_datagram->wDatagramIndex && ndp16_datagram->wDatagramLength) {
+                    USB_LOG_DBG("ndp16_datagram index:%02x, length:%02x\r\n", ndp16_datagram->wDatagramIndex, ndp16_datagram->wDatagramLength);
+
+                    uint8_t *buf = (uint8_t *)&g_cdc_ncm_rx_buffer[ndp16_datagram->wDatagramIndex];
+                    usbh_cdc_ncm_eth_input(buf, ndp16_datagram->wDatagramLength);
+                }
+            }
+
+            g_cdc_ncm_rx_length = 0;
+
+        } else {
+            if (g_cdc_ncm_rx_length > CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE) {
+                USB_LOG_ERR("Rx packet is overflow\r\n");
+                g_cdc_ncm_rx_length = 0;
+            }
+        }
+    }
+    // clang-format off
+delete:
+    USB_LOG_INFO("Delete cdc ncm rx thread\r\n");
+    usb_osal_thread_delete(NULL);
+    // clang-format on
+}
+
+int usbh_cdc_ncm_eth_output(uint8_t *buf, uint32_t buflen)
+{
+    uint8_t *buffer;
+    struct cdc_ncm_ndp16_datagram *ndp16_datagram;
+
+    if (g_cdc_ncm_class.connect_status == false) {
+        return -USB_ERR_NOTCONN;
+    }
+
+    struct cdc_ncm_nth16 *nth16 = (struct cdc_ncm_nth16 *)&g_cdc_ncm_tx_buffer[0];
+
+    nth16->dwSignature = CDC_NCM_NTH16_SIGNATURE;
+    nth16->wHeaderLength = 12;
+    nth16->wSequence = g_cdc_ncm_class.bulkout_sequence++;
+    nth16->wBlockLength = 16 + 16 + USB_ALIGN_UP(buflen, 4);
+    nth16->wNdpIndex = 16 + USB_ALIGN_UP(buflen, 4);
+
+    struct cdc_ncm_ndp16 *ndp16 = (struct cdc_ncm_ndp16 *)&g_cdc_ncm_tx_buffer[nth16->wNdpIndex];
+
+    ndp16->dwSignature = CDC_NCM_NDP16_SIGNATURE_NCM0;
+    ndp16->wLength = 16;
+    ndp16->wNextNdpIndex = 0;
+
+    ndp16_datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_tx_buffer[nth16->wNdpIndex + 8 + 4 * 0];
+    ndp16_datagram->wDatagramIndex = 16;
+    ndp16_datagram->wDatagramLength = buflen;
+
+    ndp16_datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_tx_buffer[nth16->wNdpIndex + 8 + 4 * 1];
+    ndp16_datagram->wDatagramIndex = 0;
+    ndp16_datagram->wDatagramLength = 0;
+
+    buffer = &g_cdc_ncm_tx_buffer[16];
+    memcpy(buffer, buf, buflen);
+
+    USB_LOG_DBG("txlen:%d\r\n", nth16->wBlockLength);
+
+    usbh_bulk_urb_fill(&g_cdc_ncm_class.bulkout_urb, g_cdc_ncm_class.hport, g_cdc_ncm_class.bulkout, g_cdc_ncm_tx_buffer, nth16->wBlockLength, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+    return usbh_submit_urb(&g_cdc_ncm_class.bulkout_urb);
+}
+
+__WEAK void usbh_cdc_ncm_run(struct usbh_cdc_ncm *cdc_ncm_class)
+{
+}
+
+__WEAK void usbh_cdc_ncm_stop(struct usbh_cdc_ncm *cdc_ncm_class)
+{
+}
+
+const struct usbh_class_driver cdc_ncm_class_driver = {
+    .driver_name = "cdc_ncm",
+    .connect = usbh_cdc_ncm_connect,
+    .disconnect = usbh_cdc_ncm_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info cdc_ncm_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
+    .class = USB_DEVICE_CLASS_CDC,
+    .subclass = CDC_NETWORK_CONTROL_MODEL,
+    .protocol = CDC_COMMON_PROTOCOL_NONE,
+    .id_table = NULL,
+    .class_driver = &cdc_ncm_class_driver
+};

+ 53 - 0
components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ncm.h

@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_CDC_NCM_H
+#define USBH_CDC_NCM_H
+
+#include "usb_cdc.h"
+
+struct usbh_cdc_ncm {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+    struct usb_endpoint_descriptor *intin;   /* Interrupt IN endpoint */
+    struct usbh_urb bulkout_urb;             /* Bulk out endpoint */
+    struct usbh_urb bulkin_urb;              /* Bulk IN endpoint */
+    struct usbh_urb intin_urb;               /* Interrupt IN endpoint */
+
+    uint8_t ctrl_intf; /* Control interface number */
+    uint8_t data_intf; /* Data interface number */
+    uint8_t minor;
+
+    struct cdc_ncm_ntb_parameters ntb_param;
+    uint16_t bulkin_sequence;
+    uint16_t bulkout_sequence;
+
+    uint8_t mac[6];
+    bool connect_status;
+    uint16_t max_segment_size;
+    uint32_t speed[2];
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_cdc_ncm_get_connect_status(struct usbh_cdc_ncm *cdc_ncm_class);
+
+void usbh_cdc_ncm_run(struct usbh_cdc_ncm *cdc_ncm_class);
+void usbh_cdc_ncm_stop(struct usbh_cdc_ncm *cdc_ncm_class);
+
+int usbh_cdc_ncm_eth_output(uint8_t *buf, uint32_t buflen);
+void usbh_cdc_ncm_eth_input(uint8_t *buf, uint32_t buflen);
+void usbh_cdc_ncm_rx_thread(void *argument);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_CDC_NCM_H */

+ 137 - 0
components/drivers/usb/cherryusb/class/dfu/usb_dfu.h

@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_DFU_H
+#define USB_DFU_H
+
+/**\addtogroup USB_MODULE_DFU USB DFU class
+ * \brief This module contains USB Device Firmware Upgrade class definitions.
+ * \details This module based on
+ * + [USB Device Firmware Upgrade Specification, Revision 1.1]
+ * (https://www.usb.org/sites/default/files/DFU_1.1.pdf)
+ * @{ */
+
+/** DFU Specification release */
+#define DFU_VERSION 0x0110
+
+/** DFU Class Subclass */
+#define DFU_SUBCLASS_DFU 0x01
+
+/** DFU Class runtime Protocol */
+#define DFU_PROTOCOL_RUNTIME 0x01
+
+/** DFU Class DFU mode Protocol */
+#define DFU_PROTOCOL_MODE 0x02
+
+/**
+ * @brief DFU Class Specific Requests
+ */
+#define DFU_REQUEST_DETACH    0x00
+#define DFU_REQUEST_DNLOAD    0x01
+#define DFU_REQUEST_UPLOAD    0x02
+#define DFU_REQUEST_GETSTATUS 0x03
+#define DFU_REQUEST_CLRSTATUS 0x04
+#define DFU_REQUEST_GETSTATE  0x05
+#define DFU_REQUEST_ABORT     0x06
+
+/** DFU FUNCTIONAL descriptor type */
+#define DFU_FUNC_DESC 0x21
+
+/** DFU attributes DFU Functional Descriptor */
+#define DFU_ATTR_WILL_DETACH            0x08
+#define DFU_ATTR_MANIFESTATION_TOLERANT 0x04
+#define DFU_ATTR_CAN_UPLOAD             0x02
+#define DFU_ATTR_CAN_DNLOAD             0x01
+
+/** bStatus values for the DFU_GETSTATUS response */
+#define DFU_STATUS_OK               0x00U
+#define DFU_STATUS_ERR_TARGET       0x01U
+#define DFU_STATUS_ERR_FILE         0x02U
+#define DFU_STATUS_ERR_WRITE        0x03U
+#define DFU_STATUS_ERR_ERASE        0x04U
+#define DFU_STATUS_ERR_CHECK_ERASED 0x05U
+#define DFU_STATUS_ERR_PROG         0x06U
+#define DFU_STATUS_ERR_VERIFY       0x07U
+#define DFU_STATUS_ERR_ADDRESS      0x08U
+#define DFU_STATUS_ERR_NOTDONE      0x09U
+#define DFU_STATUS_ERR_FIRMWARE     0x0AU
+#define DFU_STATUS_ERR_VENDOR       0x0BU
+#define DFU_STATUS_ERR_USB          0x0CU
+#define DFU_STATUS_ERR_POR          0x0DU
+#define DFU_STATUS_ERR_UNKNOWN      0x0EU
+#define DFU_STATUS_ERR_STALLEDPKT   0x0FU
+
+/** bState values for the DFU_GETSTATUS response */
+#define DFU_STATE_APP_IDLE                0U
+#define DFU_STATE_APP_DETACH              1U
+#define DFU_STATE_DFU_IDLE                2U
+#define DFU_STATE_DFU_DNLOAD_SYNC         3U
+#define DFU_STATE_DFU_DNLOAD_BUSY         4U
+#define DFU_STATE_DFU_DNLOAD_IDLE         5U
+#define DFU_STATE_DFU_MANIFEST_SYNC       6U
+#define DFU_STATE_DFU_MANIFEST            7U
+#define DFU_STATE_DFU_MANIFEST_WAIT_RESET 8U
+#define DFU_STATE_DFU_UPLOAD_IDLE         9U
+#define DFU_STATE_DFU_ERROR               10U
+
+/** DFU Manifestation State  */
+#define DFU_MANIFEST_COMPLETE    0U
+#define DFU_MANIFEST_IN_PROGRESS 1U
+
+/** Special Commands  with Download Request  */
+#define DFU_CMD_GETCOMMANDS       0U
+#define DFU_CMD_SETADDRESSPOINTER 0x21U
+#define DFU_CMD_ERASE             0x41U
+#define DFU_MEDIA_ERASE           0x00U
+#define DFU_MEDIA_PROGRAM         0x01U
+
+/** Other defines  */
+/* Bit Detach capable = bit 3 in bmAttributes field */
+#define DFU_DETACH_MASK   (1U << 3)
+#define DFU_MANIFEST_MASK (1U << 2)
+
+/** Run-Time Functional Descriptor */
+struct dfu_runtime_descriptor {
+    uint8_t bLength;         /**<\brief Descriptor length in bytes.*/
+    uint8_t bDescriptorType; /**<\brief DFU functional descriptor type.*/
+    uint8_t bmAttributes;    /**<\brief USB DFU capabilities \ref USB_DFU_CAPAB*/
+    uint16_t wDetachTimeout; /**<\brief USB DFU detach timeout in ms.*/
+    uint16_t wTransferSize;  /**<\brief USB DFU maximum transfer block size in bytes.*/
+    uint16_t bcdDFUVersion;  /**<\brief USB DFU version \ref VERSION_BCD utility macro.*/
+} __PACKED;
+
+/**\brief Payload packet to response in DFU_GETSTATUS request */
+struct dfu_info {
+    uint8_t bStatus;       /**<\brief An indication of the status resulting from the
+                                     * execution of the most recent request.*/
+    uint8_t bPollTimeout;  /**<\brief Minimum time (LSB) in ms, that the host should wait
+                                     * before sending a subsequent DFU_GETSTATUS request.*/
+    uint16_t wPollTimeout; /**<\brief Minimum time (MSB) in ms, that the host should wait
+                                     * before sending a subsequent DFU_GETSTATUS request.*/
+    uint8_t bState;        /**<\brief An indication of the state that the device is going
+                                     * to enter immediately following transmission of this response.*/
+    uint8_t iString;       /**<\brief Index of the status string descriptor.*/
+};
+
+// clang-format off
+#define DFU_DESCRIPTOR_INIT()                                                            \
+    0x09,                          /* bLength */                                         \
+    USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */                                 \
+    0x00,                          /* bInterfaceNumber */                                \
+    0x00,                          /* bAlternateSetting */                               \
+    0x00,                          /* bNumEndpoints Default Control Pipe only */         \
+    USB_DEVICE_CLASS_APP_SPECIFIC, /* bInterfaceClass */                                 \
+    0x01,                          /* bInterfaceSubClass Device Firmware Upgrade */      \
+    0x02,                          /* bInterfaceProtocol DFU mode */                     \
+    0x04, /* iInterface */         /*!< Device Firmware Update Functional Descriptor  */ \
+    0x09,                          /* bLength */                                         \
+    0x21,                          /* DFU Functional Descriptor */                       \
+    0x0B,                          /* bmAttributes */                                    \
+    WBVAL(0x00ff),                 /* wDetachTimeOut */                                  \
+    WBVAL(USBD_DFU_XFER_SIZE),     /* wTransferSize */                                   \
+    WBVAL(0x011a)                  /* bcdDFUVersion */
+// clang-format on
+
+#endif /* USB_DFU_H */

+ 505 - 0
components/drivers/usb/cherryusb/class/dfu/usbd_dfu.c

@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_dfu.h"
+
+/** Modify the following three parameters according to different platforms */
+#ifndef USBD_DFU_XFER_SIZE
+#define USBD_DFU_XFER_SIZE 1024
+#endif
+
+#ifndef USBD_DFU_APP_DEFAULT_ADD
+#define USBD_DFU_APP_DEFAULT_ADD 0x8004000
+#endif
+
+#ifndef FLASH_PROGRAM_TIME
+#define FLASH_PROGRAM_TIME 50
+#endif
+
+#ifndef FLASH_ERASE_TIME
+#define FLASH_ERASE_TIME 50
+#endif
+
+struct usbd_dfu_priv {
+    struct dfu_info info;
+    union {
+        uint32_t d32[USBD_DFU_XFER_SIZE / 4U];
+        uint8_t d8[USBD_DFU_XFER_SIZE];
+    } buffer;
+
+    uint32_t wblock_num;
+    uint32_t wlength;
+    uint32_t data_ptr;
+    uint32_t alt_setting;
+
+    uint8_t dev_status[6];
+    uint8_t ReservedForAlign[2];
+    uint8_t dev_state;
+    uint8_t manif_state;
+    uint8_t firmwar_flag;
+} g_usbd_dfu;
+
+static void dfu_reset(void)
+{
+    memset(&g_usbd_dfu, 0, sizeof(g_usbd_dfu));
+
+    g_usbd_dfu.alt_setting = 0U;
+    g_usbd_dfu.data_ptr = USBD_DFU_APP_DEFAULT_ADD;
+    g_usbd_dfu.wblock_num = 0U;
+    g_usbd_dfu.wlength = 0U;
+
+    g_usbd_dfu.manif_state = DFU_MANIFEST_COMPLETE;
+    g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
+
+    g_usbd_dfu.dev_status[0] = DFU_STATUS_OK;
+    g_usbd_dfu.dev_status[1] = 0U;
+    g_usbd_dfu.dev_status[2] = 0U;
+    g_usbd_dfu.dev_status[3] = 0U;
+    g_usbd_dfu.dev_status[4] = DFU_STATE_DFU_IDLE;
+    g_usbd_dfu.dev_status[5] = 0U;
+}
+
+static uint16_t dfu_getstatus(uint32_t add, uint8_t cmd, uint8_t *buffer)
+{
+    switch (cmd) {
+        case DFU_MEDIA_PROGRAM:
+            buffer[1] = (uint8_t)FLASH_PROGRAM_TIME;
+            buffer[2] = (uint8_t)(FLASH_PROGRAM_TIME << 8);
+            buffer[3] = 0;
+            break;
+
+        case DFU_MEDIA_ERASE:
+            buffer[1] = (uint8_t)FLASH_ERASE_TIME;
+            buffer[2] = (uint8_t)(FLASH_ERASE_TIME << 8);
+            buffer[3] = 0;
+        default:
+
+            break;
+    }
+    return (0);
+}
+
+static void dfu_request_detach(void)
+{
+    if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) ||
+        (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_SYNC) ||
+        (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE) ||
+        (g_usbd_dfu.dev_state == DFU_STATE_DFU_MANIFEST_SYNC) ||
+        (g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
+        /* Update the state machine */
+        g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
+        g_usbd_dfu.dev_status[0] = DFU_STATUS_OK;
+        g_usbd_dfu.dev_status[1] = 0U;
+        g_usbd_dfu.dev_status[2] = 0U;
+        g_usbd_dfu.dev_status[3] = 0U; /*bwPollTimeout=0ms*/
+        g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+        g_usbd_dfu.dev_status[5] = 0U; /*iString*/
+        g_usbd_dfu.wblock_num = 0U;
+        g_usbd_dfu.wlength = 0U;
+    }
+}
+
+static void dfu_request_upload(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    struct usb_setup_packet *req = setup;
+    uint32_t addr;
+    uint8_t *phaddr;
+    /* Data setup request */
+    if (req->wLength > 0U) {
+        if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
+            /* Update the global length and block number */
+            g_usbd_dfu.wblock_num = req->wValue;
+            g_usbd_dfu.wlength = MIN(req->wLength, USBD_DFU_XFER_SIZE);
+
+            /* DFU Get Command */
+            if (g_usbd_dfu.wblock_num == 0U) {
+                /* Update the state machine */
+                g_usbd_dfu.dev_state = (g_usbd_dfu.wlength > 3U) ? DFU_STATE_DFU_IDLE : DFU_STATE_DFU_UPLOAD_IDLE;
+
+                g_usbd_dfu.dev_status[1] = 0U;
+                g_usbd_dfu.dev_status[2] = 0U;
+                g_usbd_dfu.dev_status[3] = 0U;
+                g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+
+                /* Store the values of all supported commands */
+                g_usbd_dfu.buffer.d8[0] = DFU_CMD_GETCOMMANDS;
+                g_usbd_dfu.buffer.d8[1] = DFU_CMD_SETADDRESSPOINTER;
+                g_usbd_dfu.buffer.d8[2] = DFU_CMD_ERASE;
+
+                /* Send the status data over EP0 */
+                memcpy(*data, g_usbd_dfu.buffer.d8, 3);
+                *len = 3;
+            } else if (g_usbd_dfu.wblock_num > 1U) {
+                g_usbd_dfu.dev_state = DFU_STATE_DFU_UPLOAD_IDLE;
+
+                g_usbd_dfu.dev_status[1] = 0U;
+                g_usbd_dfu.dev_status[2] = 0U;
+                g_usbd_dfu.dev_status[3] = 0U;
+                g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+
+                addr = ((g_usbd_dfu.wblock_num - 2U) * USBD_DFU_XFER_SIZE) + g_usbd_dfu.data_ptr;
+
+                /* Return the physical address where data are stored */
+                phaddr = dfu_read_flash((uint8_t *)addr, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);
+
+                /* Send the status data over EP0 */
+                memcpy(*data, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);
+                *len = g_usbd_dfu.wlength;
+            } else /* unsupported g_usbd_dfu.wblock_num */
+            {
+                g_usbd_dfu.dev_state = DFU_STATUS_ERR_STALLEDPKT;
+
+                g_usbd_dfu.dev_status[1] = 0U;
+                g_usbd_dfu.dev_status[2] = 0U;
+                g_usbd_dfu.dev_status[3] = 0U;
+                g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+
+                /* Call the error management function (command will be NAKed */
+                USB_LOG_ERR("Dfu_request_upload unsupported g_usbd_dfu.wblock_num\r\n");
+            }
+        }
+        /* Unsupported state */
+        else {
+            g_usbd_dfu.wlength = 0U;
+            g_usbd_dfu.wblock_num = 0U;
+
+            /* Call the error management function (command will be NAKed */
+            USB_LOG_ERR("Dfu_request_upload unsupported state\r\n");
+        }
+    }
+    /* No Data setup request */
+    else {
+        g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
+
+        g_usbd_dfu.dev_status[1] = 0U;
+        g_usbd_dfu.dev_status[2] = 0U;
+        g_usbd_dfu.dev_status[3] = 0U;
+        g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+    }
+}
+
+static void dfu_request_dnload(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    /* Data setup request */
+    struct usb_setup_packet *req = setup;
+    if (req->wLength > 0U) {
+        if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE)) {
+            /* Update the global length and block number */
+            g_usbd_dfu.wblock_num = req->wValue;
+            g_usbd_dfu.wlength = MIN(req->wLength, USBD_DFU_XFER_SIZE);
+
+            /* Update the state machine */
+            g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_SYNC;
+            g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+
+            /*!< Data has received complete */
+            memcpy((uint8_t *)g_usbd_dfu.buffer.d8, (uint8_t *)*data, g_usbd_dfu.wlength);
+            /*!< Set flag = 1 Write the firmware to the flash in the next dfu_request_getstatus */
+            g_usbd_dfu.firmwar_flag = 1;
+        }
+        /* Unsupported state */
+        else {
+            USB_LOG_ERR("Dfu_request_dnload unsupported state\r\n");
+        }
+    }
+    /* 0 Data DNLOAD request */
+    else {
+        /* End of DNLOAD operation*/
+        if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE)) {
+            g_usbd_dfu.manif_state = DFU_MANIFEST_IN_PROGRESS;
+            g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST_SYNC;
+            g_usbd_dfu.dev_status[1] = 0U;
+            g_usbd_dfu.dev_status[2] = 0U;
+            g_usbd_dfu.dev_status[3] = 0U;
+            g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+        } else {
+            /* Call the error management function (command will be NAKed */
+            USB_LOG_ERR("Dfu_request_dnload End of DNLOAD operation but dev_state %02x \r\n", g_usbd_dfu.dev_state);
+        }
+    }
+}
+
+static int8_t dfu_getstatus_special_handler(void)
+{
+    uint32_t addr;
+    if (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_BUSY) {
+        /* Decode the Special Command */
+        if (g_usbd_dfu.wblock_num == 0U) {
+            if (g_usbd_dfu.wlength == 1U) {
+                if (g_usbd_dfu.buffer.d8[0] == DFU_CMD_GETCOMMANDS) {
+                    /* Nothing to do */
+                }
+            } else if (g_usbd_dfu.wlength == 5U) {
+                if (g_usbd_dfu.buffer.d8[0] == DFU_CMD_SETADDRESSPOINTER) {
+                    g_usbd_dfu.data_ptr = g_usbd_dfu.buffer.d8[1];
+                    g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[2] << 8;
+                    g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[3] << 16;
+                    g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[4] << 24;
+                } else if (g_usbd_dfu.buffer.d8[0] == DFU_CMD_ERASE) {
+                    g_usbd_dfu.data_ptr = g_usbd_dfu.buffer.d8[1];
+                    g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[2] << 8;
+                    g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[3] << 16;
+                    g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[4] << 24;
+
+                    USB_LOG_DBG("Erase start add %08x \r\n", g_usbd_dfu.data_ptr);
+                    /*!< Erase */
+                    dfu_erase_flash(g_usbd_dfu.data_ptr);
+                } else {
+                    return -1;
+                }
+            } else {
+                /* Reset the global length and block number */
+                g_usbd_dfu.wlength = 0U;
+                g_usbd_dfu.wblock_num = 0U;
+                /* Call the error management function (command will be NAKed) */
+                USB_LOG_ERR("Reset the global length and block number\r\n");
+            }
+        }
+        /* Regular Download Command */
+        else {
+            if (g_usbd_dfu.wblock_num > 1U) {
+                /* Decode the required address */
+                addr = ((g_usbd_dfu.wblock_num - 2U) * USBD_DFU_XFER_SIZE) + g_usbd_dfu.data_ptr;
+
+                /* Perform the write operation */
+                /* Write flash */
+                USB_LOG_DBG("Write start add %08x length %d\r\n", addr, g_usbd_dfu.wlength);
+                dfu_write_flash(g_usbd_dfu.buffer.d8, (uint8_t *)addr, g_usbd_dfu.wlength);
+            }
+        }
+
+        /* Reset the global length and block number */
+        g_usbd_dfu.wlength = 0U;
+        g_usbd_dfu.wblock_num = 0U;
+
+        /* Update the state machine */
+        g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_SYNC;
+
+        g_usbd_dfu.dev_status[1] = 0U;
+        g_usbd_dfu.dev_status[2] = 0U;
+        g_usbd_dfu.dev_status[3] = 0U;
+        g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+    }
+    return 0;
+}
+
+static void dfu_request_getstatus(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    /*!< Determine whether to leave DFU mode */
+    if (g_usbd_dfu.manif_state == DFU_MANIFEST_IN_PROGRESS &&
+        g_usbd_dfu.dev_state == DFU_STATE_DFU_MANIFEST_SYNC &&
+        g_usbd_dfu.dev_status[1] == 0U &&
+        g_usbd_dfu.dev_status[2] == 0U &&
+        g_usbd_dfu.dev_status[3] == 0U &&
+        g_usbd_dfu.dev_status[4] == g_usbd_dfu.dev_state) {
+        g_usbd_dfu.manif_state = DFU_MANIFEST_COMPLETE;
+
+        if ((0x0B & DFU_MANIFEST_MASK) != 0U) {
+            g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST_SYNC;
+
+            g_usbd_dfu.dev_status[1] = 0U;
+            g_usbd_dfu.dev_status[2] = 0U;
+            g_usbd_dfu.dev_status[3] = 0U;
+            g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+            return;
+        } else {
+            g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST_WAIT_RESET;
+
+            g_usbd_dfu.dev_status[1] = 0U;
+            g_usbd_dfu.dev_status[2] = 0U;
+            g_usbd_dfu.dev_status[3] = 0U;
+            g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+            /* Generate system reset to allow jumping to the user code */
+            dfu_leave();
+        }
+    }
+
+    switch (g_usbd_dfu.dev_state) {
+        case DFU_STATE_DFU_DNLOAD_SYNC:
+            if (g_usbd_dfu.wlength != 0U) {
+                g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_BUSY;
+
+                g_usbd_dfu.dev_status[1] = 0U;
+                g_usbd_dfu.dev_status[2] = 0U;
+                g_usbd_dfu.dev_status[3] = 0U;
+                g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+
+                if ((g_usbd_dfu.wblock_num == 0U) && (g_usbd_dfu.buffer.d8[0] == DFU_CMD_ERASE)) {
+                    dfu_getstatus(g_usbd_dfu.data_ptr, DFU_MEDIA_ERASE, g_usbd_dfu.dev_status);
+                } else {
+                    dfu_getstatus(g_usbd_dfu.data_ptr, DFU_MEDIA_PROGRAM, g_usbd_dfu.dev_status);
+                }
+            } else /* (g_usbd_dfu.wlength==0)*/
+            {
+                g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_IDLE;
+
+                g_usbd_dfu.dev_status[1] = 0U;
+                g_usbd_dfu.dev_status[2] = 0U;
+                g_usbd_dfu.dev_status[3] = 0U;
+                g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+            }
+            break;
+
+        case DFU_STATE_DFU_MANIFEST_SYNC:
+            if (g_usbd_dfu.manif_state == DFU_MANIFEST_IN_PROGRESS) {
+                g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST;
+
+                g_usbd_dfu.dev_status[1] = 1U; /*bwPollTimeout = 1ms*/
+                g_usbd_dfu.dev_status[2] = 0U;
+                g_usbd_dfu.dev_status[3] = 0U;
+                g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+            } else {
+                if ((g_usbd_dfu.manif_state == DFU_MANIFEST_COMPLETE) &&
+                    ((0x0B & DFU_MANIFEST_MASK) != 0U)) {
+                    g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
+
+                    g_usbd_dfu.dev_status[1] = 0U;
+                    g_usbd_dfu.dev_status[2] = 0U;
+                    g_usbd_dfu.dev_status[3] = 0U;
+                    g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+                }
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    /* Send the status data over EP0 */
+    memcpy(*data, g_usbd_dfu.dev_status, 6);
+    *len = 6;
+
+    if (g_usbd_dfu.firmwar_flag == 1) {
+        if (dfu_getstatus_special_handler() != 0) {
+            USB_LOG_ERR("dfu_getstatus_special_handler error \r\n");
+        }
+        g_usbd_dfu.firmwar_flag = 0;
+    }
+}
+
+static void dfu_request_clrstatus(void)
+{
+    if (g_usbd_dfu.dev_state == DFU_STATE_DFU_ERROR) {
+        g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
+        g_usbd_dfu.dev_status[0] = DFU_STATUS_OK; /* bStatus */
+        g_usbd_dfu.dev_status[1] = 0U;
+        g_usbd_dfu.dev_status[2] = 0U;
+        g_usbd_dfu.dev_status[3] = 0U;                     /* bwPollTimeout=0ms */
+        g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state; /* bState */
+        g_usbd_dfu.dev_status[5] = 0U;                     /* iString */
+    } else {
+        /* State Error */
+        g_usbd_dfu.dev_state = DFU_STATE_DFU_ERROR;
+        g_usbd_dfu.dev_status[0] = DFU_STATUS_ERR_UNKNOWN; /* bStatus */
+        g_usbd_dfu.dev_status[1] = 0U;
+        g_usbd_dfu.dev_status[2] = 0U;
+        g_usbd_dfu.dev_status[3] = 0U;                     /* bwPollTimeout=0ms */
+        g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state; /* bState */
+        g_usbd_dfu.dev_status[5] = 0U;                     /* iString */
+    }
+}
+
+static void dfu_request_getstate(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    /* Return the current state of the DFU interface */
+    (*data)[0] = g_usbd_dfu.dev_state;
+    *len = 1;
+}
+
+void dfu_request_abort(void)
+{
+    if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) ||
+        (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_SYNC) ||
+        (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE) ||
+        (g_usbd_dfu.dev_state == DFU_STATE_DFU_MANIFEST_SYNC) ||
+        (g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
+        g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
+        g_usbd_dfu.dev_status[0] = DFU_STATUS_OK;
+        g_usbd_dfu.dev_status[1] = 0U;
+        g_usbd_dfu.dev_status[2] = 0U;
+        g_usbd_dfu.dev_status[3] = 0U; /* bwPollTimeout=0ms */
+        g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
+        g_usbd_dfu.dev_status[5] = 0U; /* iString */
+        g_usbd_dfu.wblock_num = 0U;
+        g_usbd_dfu.wlength = 0U;
+    }
+}
+
+static int dfu_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    USB_LOG_DBG("DFU Class request: "
+                "bRequest 0x%02x\r\n",
+                setup->bRequest);
+
+    switch (setup->bRequest) {
+        case DFU_REQUEST_DETACH:
+            dfu_request_detach();
+            break;
+        case DFU_REQUEST_DNLOAD:
+            dfu_request_dnload(setup, data, len);
+            break;
+        case DFU_REQUEST_UPLOAD:
+            dfu_request_upload(setup, data, len);
+            break;
+        case DFU_REQUEST_GETSTATUS:
+            dfu_request_getstatus(setup, data, len);
+            break;
+        case DFU_REQUEST_CLRSTATUS:
+            dfu_request_clrstatus();
+            break;
+        case DFU_REQUEST_GETSTATE:
+            dfu_request_getstate(setup, data, len);
+            break;
+        case DFU_REQUEST_ABORT:
+            dfu_request_abort();
+            break;
+        default:
+            USB_LOG_WRN("Unhandled DFU Class bRequest 0x%02x\r\n", setup->bRequest);
+            return -1;
+    }
+
+    return 0;
+}
+
+static void dfu_notify_handler(uint8_t busid, uint8_t event, void *arg)
+{
+    switch (event) {
+        case USBD_EVENT_RESET:
+            dfu_reset();
+            break;
+        default:
+            break;
+    }
+}
+
+struct usbd_interface *usbd_dfu_init_intf(struct usbd_interface *intf)
+{
+    intf->class_interface_handler = dfu_class_interface_request_handler;
+    intf->class_endpoint_handler = NULL;
+    intf->vendor_handler = NULL;
+    intf->notify_handler = dfu_notify_handler;
+
+    return intf;
+}
+
+__WEAK uint8_t *dfu_read_flash(uint8_t *src, uint8_t *dest, uint32_t len)
+{
+    return dest;
+}
+
+__WEAK uint16_t dfu_write_flash(uint8_t *src, uint8_t *dest, uint32_t len)
+{
+    return 0;
+}
+
+__WEAK uint16_t dfu_erase_flash(uint32_t add)
+{
+    return 0;
+}
+
+__WEAK void dfu_leave(void)
+{
+}

+ 27 - 0
components/drivers/usb/cherryusb/class/dfu/usbd_dfu.h

@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_DFU_H
+#define USBD_DFU_H
+
+#include "usb_dfu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Init dfu interface driver */
+struct usbd_interface *usbd_dfu_init_intf(struct usbd_interface *intf);
+
+/* Interface functions that need to be implemented by the user */
+uint8_t *dfu_read_flash(uint8_t *src, uint8_t *dest, uint32_t len);
+uint16_t dfu_write_flash(uint8_t *src, uint8_t *dest, uint32_t len);
+uint16_t dfu_erase_flash(uint32_t add);
+void dfu_leave(void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBD_DFU_H */

+ 585 - 0
components/drivers/usb/cherryusb/class/hid/usb_hid.h

@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_HID_H
+#define USB_HID_H
+
+/* Subclass codes (HID 4.2) */
+#define HID_SUBCLASS_NONE   0 /* No subclass */
+#define HID_SUBCLASS_BOOTIF 1 /* Boot Interface Subclass */
+
+/* HID Protocol Codes (HID 4.3) */
+#define HID_PROTOCOL_NONE     0x00
+#define HID_PROTOCOL_BOOT     0x00
+#define HID_PROTOCOL_KEYBOARD 0x01
+#define HID_PROTOCOL_REPORT   0x01
+#define HID_PROTOCOL_MOUSE    0x02
+
+/* HID Class Descriptor Types (HID 7.1) */
+#define HID_DESCRIPTOR_TYPE_HID          0x21
+#define HID_DESCRIPTOR_TYPE_HID_REPORT   0x22
+#define HID_DESCRIPTOR_TYPE_HID_PHYSICAL 0x23
+
+/* HID Class Specific Requests (HID 7.2) */
+#define HID_REQUEST_GET_REPORT   0x01
+#define HID_REQUEST_GET_IDLE     0x02
+#define HID_REQUEST_GET_PROTOCOL 0x03
+#define HID_REQUEST_SET_REPORT   0x09
+#define HID_REQUEST_SET_IDLE     0x0A
+#define HID_REQUEST_SET_PROTOCOL 0x0B
+
+/* Report Type (MS byte of wValue for GET_REPORT) (HID 7.2.1) */
+#define HID_REPORT_INPUT   0x01
+#define HID_REPORT_OUTPUT  0x02
+#define HID_REPORT_FEATURE 0x03
+
+/* HID Descriptor ***********************************************************/
+
+#define HID_COUNTRY_NONE        0x00 /* Not Supported */
+#define HID_COUNTRY_ARABIC      0x01 /* Arabic */
+#define HID_COUNTRY_BELGIAN     0x02 /* Belgian */
+#define HID_COUNTRY_CANADA      0x03 /* Canadian-Bilingual */
+#define HID_COUNTRY_CANADRFR    0x04 /* Canadian-French */
+#define HID_COUNTRY_CZECH       0x05 /* Czech Republic */
+#define HID_COUNTRY_DANISH      0x06 /* Danish */
+#define HID_COUNTRY_FINNISH     0x07 /* Finnish */
+#define HID_COUNTRY_FRENCH      0x08 /* French */
+#define HID_COUNTRY_GERMAN      0x09 /* German */
+#define HID_COUNTRY_GREEK       0x10 /* Greek */
+#define HID_COUNTRY_HEBREW      0x11 /* Hebrew */
+#define HID_COUNTRY_HUNGARY     0x12 /* Hungary */
+#define HID_COUNTRY_ISO         0x13 /* International (ISO) */
+#define HID_COUNTRY_ITALIAN     0x14 /* Italian */
+#define HID_COUNTRY_JAPAN       0x15 /* Japan (Katakana) */
+#define HID_COUNTRY_KOREAN      0x16 /* Korean  */
+#define HID_COUNTRY_LATINAM     0x17 /* Latin American */
+#define HID_COUNTRY_DUTCH       0x18 /* Netherlands/Dutch */
+#define HID_COUNTRY_NORWEGIAN   0x19 /* Norwegian */
+#define HID_COUNTRY_PERSIAN     0x20 /* Persian (Farsi) */
+#define HID_COUNTRY_POLAND      0x21 /* Poland */
+#define HID_COUNTRY_PORTUGUESE  0x22 /* Portuguese */
+#define HID_COUNTRY_RUSSIA      0x23 /* Russia */
+#define HID_COUNTRY_SLOVAKIA    0x24 /* Slovakia */
+#define HID_COUNTRY_SPANISH     0x25 /* Spanish */
+#define HID_COUNTRY_SWEDISH     0x26 /* Swedish */
+#define HID_COUNTRY_SWISSFR     0x27 /* Swiss/French */
+#define HID_COUNTRY_SWISSGR     0x28 /* Swiss/German */
+#define HID_COUNTRY_SWITZERLAND 0x29 /* Switzerland */
+#define HID_COUNTRY_TAIWAN      0x30 /* Taiwan */
+#define HID_COUNTRY_TURKISHQ    0x31 /* Turkish-Q */
+#define HID_COUNTRY_UK          0x32 /* UK */
+#define HID_COUNTRY_US          0x33 /* US */
+#define HID_COUNTRY_YUGOSLAVIA  0x34 /* Yugoslavia */
+#define HID_COUNTRY_TURKISHF    0x35 /* Turkish-F */
+
+/* HID report items */
+#define HID_REPORT_ITEM_SIZE_MASK   0x03
+#define HID_REPORT_ITEM_SIZE_0      0x00 /* No data follows */
+#define HID_REPORT_ITEM_SIZE_1      0x01 /* 1 byte of data follows */
+#define HID_REPORT_ITEM_SIZE_2      0x02 /* 2 bytes of data follow */
+#define HID_REPORT_ITEM_SIZE_4      0x03 /* 4 bytes of data follow */
+#define HID_REPORT_ITEM_TYPE_MASK   0x0c
+#define HID_REPORT_ITEM_TYPE_MAIN   0x00
+#define HID_REPORT_ITEM_TYPE_GLOBAL 0x04
+#define HID_REPORT_ITEM_TYPE_LOCAL  0x08
+#define HID_REPORT_ITEM_TAG_MASK    0xf0
+
+/* Main Items (HID 6.2.2.4) */
+#define HID_MAIN_ITEM_CONSTANT      (1 << 0) /* Constant(1) vs Data(0) */
+#define HID_MAIN_ITEM_VARIABLE      (1 << 1) /* Variable(1) vs Array(0) */
+#define HID_MAIN_ITEM_RELATIVE      (1 << 2) /* Relative(1) vs Absolute(0) */
+#define HID_MAIN_ITEM_WRAP          (1 << 3) /* Wrap(1) vs No Wrap(0) */
+#define HID_MAIN_ITEM_NONLINEAR     (1 << 4) /* Non Linear(1) vs Linear(0) */
+#define HID_MAIN_ITEM_NOPREFERRED   (1 << 5) /* No Preferred (1) vs Preferred State(0) */
+#define HID_MAIN_ITEM_NULLSTATE     (1 << 6) /* Null state(1) vs No Null position(0) */
+#define HID_MAIN_ITEM_VOLATILE      (1 << 7) /* Volatile(1) vs Non volatile(0) */
+#define HID_MAIN_ITEM_BUFFEREDBYTES (1 << 8) /* Buffered Bytes(1) vs Bit Field(0) */
+
+#define HID_MAIN_ITEM_SIZE(pfx)           ((pfx)&HID_REPORT_ITEM_SIZE_MASK)
+#define HID_MAIN_ITEM_INPUT_PREFIX        0x80
+#define HID_MAIN_ITEM_INPUT_CONSTANT      HID_MAIN_ITEM_CONSTANT
+#define HID_MAIN_ITEM_INPUT_VARIABLE      HID_MAIN_ITEM_VARIABLE
+#define HID_MAIN_ITEM_INPUT_RELATIVE      HID_MAIN_ITEM_RELATIVE
+#define HID_MAIN_ITEM_INPUT_WRAP          HID_MAIN_ITEM_WRAP
+#define HID_MAIN_ITEM_INPUT_NONLINEAR     HID_MAIN_ITEM_NONLINEAR
+#define HID_MAIN_ITEM_INPUT_NOPREFERRED   HID_MAIN_ITEM_NOPREFERRED
+#define HID_MAIN_ITEM_INPUT_NULLSTATE     HID_MAIN_ITEM_NULLSTATE
+#define HID_MAIN_ITEM_INPUT_BUFFEREDBYTES HID_MAIN_ITEM_BUFFEREDBYTES
+
+#define HID_MAIN_ITEM_OUTPUT_PREFIX        0x90
+#define HID_MAIN_ITEM_OUTPUT_CONSTANT      HID_MAIN_ITEM_CONSTANT
+#define HID_MAIN_ITEM_OUTPUT_VARIABLE      HID_MAIN_ITEM_VARIABLE
+#define HID_MAIN_ITEM_OUTPUT_RELATIVE      HID_MAIN_ITEM_RELATIVE
+#define HID_MAIN_ITEM_OUTPUT_WRAP          HID_MAIN_ITEM_WRAP
+#define HID_MAIN_ITEM_OUTPUT_NONLINEAR     HID_MAIN_ITEM_NONLINEAR
+#define HID_MAIN_ITEM_OUTPUT_NOPREFERRED   HID_MAIN_ITEM_NOPREFERRED
+#define HID_MAIN_ITEM_OUTPUT_NULLSTATE     HID_MAIN_ITEM_NULLSTATE
+#define HID_MAIN_ITEM_OUTPUT_VOLATILE      HID_MAIN_ITEM_VOLATILE
+#define HID_MAIN_ITEM_OUTPUT_BUFFEREDBYTES HID_MAIN_ITEM_BUFFEREDBYTES
+
+#define HID_MAIN_ITEM_FEATURE_PREFIX        0xb0
+#define HID_MAIN_ITEM_FEATURE_CONSTANT      HID_MAIN_ITEM_CONSTANT
+#define HID_MAIN_ITEM_FEATURE_VARIABLE      HID_MAIN_ITEM_VARIABLE
+#define HID_MAIN_ITEM_FEATURE_RELATIVE      HID_MAIN_ITEM_RELATIVE
+#define HID_MAIN_ITEM_FEATURE_WRAP          HID_MAIN_ITEM_WRAP
+#define HID_MAIN_ITEM_FEATURE_NONLINEAR     HID_MAIN_ITEM_NONLINEAR
+#define HID_MAIN_ITEM_FEATURE_NOPREFERRED   HID_MAIN_ITEM_NOPREFERRED
+#define HID_MAIN_ITEM_FEATURE_NULLSTATE     HID_MAIN_ITEM_NULLSTATE
+#define HID_MAIN_ITEM_FEATURE_VOLATILE      HID_MAIN_ITEM_VOLATILE
+#define HID_MAIN_ITEM_FEATURE_BUFFEREDBYTES HID_MAIN_ITEM_BUFFEREDBYTES
+
+#define HID_MAIN_ITEM_COLLECTION_PREFIX    0xa0
+#define HID_MAIN_ITEM_COLLECTION_PHYSICAL  0x00 /* Physical (group of axes) */
+#define HID_MAIN_ITEM_COLLECTION_APPL      0x01 /* Application (mouse, keyboard) */
+#define HID_MAIN_ITEM_COLLECTION_LOGICAL   0x02 /* Logical (interrelated data) */
+#define HID_MAIN_ITEM_COLLECTION_REPORT    0x03 /* Report */
+#define HID_MAIN_ITEM_COLLECTION_ARRAY     0x04 /* Named Array */
+#define HID_MAIN_ITEM_COLLECTION_SWITCH    0x05 /* Usage Switch */
+#define HID_MAIN_ITEM_COLLECTION_MODIFIER  0x06 /* Usage Modifier */
+#define HID_MAIN_ITEM_ENDCOLLECTION_PREFIX 0xc0
+
+/* Global Items (HID 6.2.2.7) */
+#define HID_GLOBAL_ITEM_SIZE(pfx)          ((pfx)&HID_REPORT_ITEM_SIZE_MASK)
+#define HID_GLOBAL_ITEM_USAGEPAGE_PREFIX   0x04 /* Usage Page */
+#define HID_GLOBAL_ITEM_LOGICALMIN_PREFIX  0x14 /* Logical Minimum */
+#define HID_GLOBAL_ITEM_LOGICALMAX_PREFIX  0x24 /* Logical Maximum */
+#define HID_GLOBAL_ITEM_PHYSICALMIN_PREFIX 0x34 /* Physical Minimum */
+#define HID_GLOBAL_ITEM_PHYSMICALAX_PREFIX 0x44 /* Physical Maximum */
+#define HID_GLOBAL_ITEM_UNITEXP_PREFIX     0x54 /* Unit Exponent */
+#define HID_GLOBAL_ITEM_UNIT_PREFIX        0x64 /* Unit */
+#define HID_GLOBAL_ITEM_REPORTSIZE_PREFIX  0x74 /* Report Size */
+#define HID_GLOBAL_ITEM_REPORTID_PREFIX    0x84 /* Report ID */
+#define HID_GLOBAL_ITEM_REPORTCOUNT_PREFIX 0x94 /* Report Count */
+#define HID_GLOBAL_ITEM_PUSH_PREFIX        0xa4 /* Push */
+#define HID_GLOBAL_ITEM_POP_PREFIX         0xb4 /* Pop */
+
+/* Local Items (HID 6.2.2.8) */
+#define HID_LOCAL_ITEM_SIZE(pfx)            ((pfx)&HID_REPORT_ITEM_SIZE_MASK)
+#define HID_LOCAL_ITEM_USAGE_PREFIX         0x08 /* Usage */
+#define HID_LOCAL_ITEM_USAGEMIN_PREFIX      0x18 /* Usage Minimum */
+#define HID_LOCAL_ITEM_USAGEMAX_PREFIX      0x28 /* Usage Maximum */
+#define HID_LOCAL_ITEM_DESIGNATORIDX_PREFIX 0x38 /* Designator Index  */
+#define HID_LOCAL_ITEM_DESIGNATORMIN_PREFIX 0x48 /* Designator Minimum */
+#define HID_LOCAL_ITEM_DESIGNATORMAX_PREFIX 0x58 /* Designator Maximum */
+#define HID_LOCAL_ITEM_STRINGIDX_PREFIX     0x78 /* String Index */
+#define HID_LOCAL_ITEM_STRINGMIN_PREFIX     0x88 /* String Minimum */
+#define HID_LOCAL_ITEM_STRINGMAX_PREFIX     0x98 /* xx */
+#define HID_LOCAL_ITEM_DELIMITER_PREFIX     0xa8 /* Delimiter */
+
+/* Modifier Keys (HID 8.3) */
+#define HID_MODIFER_LCTRL  (1 << 0) /* Left Ctrl */
+#define HID_MODIFER_LSHIFT (1 << 1) /* Left Shift */
+#define HID_MODIFER_LALT   (1 << 2) /* Left Alt */
+#define HID_MODIFER_LGUI   (1 << 3) /* Left GUI */
+#define HID_MODIFER_RCTRL  (1 << 4) /* Right Ctrl */
+#define HID_MODIFER_RSHIFT (1 << 5) /* Right Shift */
+#define HID_MODIFER_RALT   (1 << 6) /* Right Alt */
+#define HID_MODIFER_RGUI   (1 << 7) /* Right GUI */
+
+/* Keyboard output report (1 byte) (HID B.1) */
+#define HID_KBD_OUTPUT_REPORT_NUMLOCK    (1 << 0)
+#define HID_KBD_OUTPUT_REPORT_CAPSLOCK   (1 << 1)
+#define HID_KBD_OUTPUT_REPORT_SCROLLLOCK (1 << 2)
+#define HID_KBD_OUTPUT_REPORT_COMPOSE    (1 << 3)
+#define HID_KBD_OUTPUT_REPORT_KANA       (1 << 4)
+
+/* Mouse input report (HID B.2) */
+#define HID_MOUSE_INPUT_REPORT_BUTTON1     (1 << 0)
+#define HID_MOUSE_INPUT_REPORT_BUTTON2     (1 << 1)
+#define HID_MOUSE_INPUT_REPORT_BUTTON3     (1 << 2)
+#define HID_MOUSE_INPUT_REPORT_BUTTON_MASK (7)
+
+#define HID_MOUSE_INPUT_BUTTON_LEFT        (1 << 0)
+#define HID_MOUSE_INPUT_BUTTON_RIGHT       (1 << 1)
+#define HID_MOUSE_INPUT_BUTTON_MIDDLE      (1 << 2)
+#define HID_MOUSE_INPUT_BUTTON_BACKWARD    (1 << 3)
+#define HID_MOUSE_INPUT_BUTTON_FORWARD     (1 << 4)
+
+/* Joystick input report (4 bytes) (HID D.1) */
+#define HID_JS_INPUT_REPORT_HATSWITCH_SHIFT (0)
+#define HID_JS_INPUT_REPORT_HATSWITCH_MASK  (15 << HID_JSIN_HATSWITCH_SHIFT)
+#define HID_JS_INPUT_REPORT_BUTTON1         (1 << 4)
+#define HID_JS_INPUT_REPORT_BUTTON2         (1 << 5)
+#define HID_JS_INPUT_REPORT_BUTTON3         (1 << 6)
+#define HID_JS_INPUT_REPORT_BUTTON4         (1 << 7)
+
+/* Usage pages (HuT 3) */
+#define HID_USAGE_PAGE_UNDEFINED       0x00 /* Undefined */
+#define HID_USAGE_PAGE_GENERIC_DCTRL   0x01 /* Generic Desktop Controls */
+#define HID_USAGE_PAGE_SIMCTRL         0x02 /* Simulation Controls */
+#define HID_USAGE_PAGE_VRCTRL          0x03 /* VR Controls */
+#define HID_USAGE_PAGE_SPORTCTRL       0x04 /* Sport Controls */
+#define HID_USAGE_PAGE_GAMECTRL        0x05 /* Game Controls */
+#define HID_USAGE_PAGE_GENERIC_DEVCTRL 0x06 /* Generic Device Controls */
+#define HID_USAGE_PAGE_KBD             0x07 /* Keyboard/Keypad */
+#define HID_USAGE_PAGE_LEDS            0x08 /* LEDs */
+#define HID_USAGE_PAGE_BUTTON          0x09 /* Button */
+#define HID_USAGE_PAGE_ORDINAL         0x0a /* Ordinal */
+#define HID_USAGE_PAGE_TELEPHONY       0x0b /* Telephony */
+#define HID_USAGE_PAGE_CONSUMER        0x0c /* Consumer */
+#define HID_USAGE_PAGE_DIGITIZER       0x0d /* Digitizer */
+                                            /* 0x0e Reserved */
+#define HID_USAGE_PAGE_PIDPAGE 0x0f         /* PID Page  Physical Interface Device */
+#define HID_USAGE_PAGE_UNICODE 0x10         /* Unicode */
+                                            /* 0x11-13 Reserved */
+#define HID_USAGE_PAGE_ALPHA_DISPLAY 0x14   /* Alphanumeric Display */
+                                            /* 0x15-3f Reserved */
+#define HID_USAGE_PAGE_MEDICAL 0x40         /* Medical Instruments */
+                                            /* 0x41-7f Reserved */
+                                            /* 0x80-83 Monitor Devices */
+                                            /* 0x84-87 Power Devices */
+                                            /* 0x88-8b Reserved */
+#define HID_USAGE_PAGE_BARCODE_SCANNER 0x8c /* Bar Code Scanner page */
+#define HID_USAGE_PAGE_SCALE           0x8d /* Scale page */
+#define HID_USAGE_PAGE_MSR             0x8e /* Magnetic Stripe Reading (MSR) Devices */
+#define HID_USAGE_PAGE_POS             0x8f /* Point of Sale devices */
+#define HID_USAGE_PAGE_CAMERA_CTRL     0x90 /* Camera Control Page */
+
+/* Generic Desktop Page Usage IDs (HuT 4) */
+#define HID_DESKTOP_USAGE_UNDEFINED 0x00        /* Undefined */
+#define HID_DESKTOP_USAGE_POINTER   0x01        /* Pointer */
+#define HID_DESKTOP_USAGE_MOUSE     0x02        /* Mouse */
+                                           /* 0x03 Reserved */
+#define HID_DESKTOP_USAGE_JOYSTICK  0x04        /* Joystick */
+#define HID_DESKTOP_USAGE_GAMEPAD   0x05        /* Game Pad */
+#define HID_DESKTOP_USAGE_KEYBOARD  0x06        /* Keyboard */
+#define HID_DESKTOP_USAGE_KEYPAD    0x07        /* Keypad */
+#define HID_DESKTOP_USAGE_MULTIAXIS 0x08        /* Multi-axis Controller */
+#define HID_DESKTOP_USAGE_TABLET    0x09        /* Tablet PC System Controls */
+                                           /* 0x0a-2f Reserved */
+#define HID_DESKTOP_USAGE_X         0x30        /* X */
+#define HID_DESKTOP_USAGE_Y         0x31        /* Y */
+#define HID_DESKTOP_USAGE_Z         0x32        /* Z */
+#define HID_DESKTOP_USAGE_RX        0x33        /* Rx */
+#define HID_DESKTOP_USAGE_RY        0x34        /* Ry */
+#define HID_DESKTOP_USAGE_RZ        0x35        /* Rz */
+#define HID_DESKTOP_USAGE_SLIDER    0x36        /* Slider */
+#define HID_DESKTOP_USAGE_DIAL      0x37        /* Dial */
+#define HID_DESKTOP_USAGE_WHEEL     0x38        /* Wheel */
+#define HID_DESKTOP_USAGE_HATSWITCH 0x39        /* Hat switch */
+#define HID_DESKTOP_USAGE_COUNTED   0x3a        /* Counted Buffer */
+#define HID_DESKTOP_USAGE_BYTECOUNT 0x3b        /* Byte Count */
+#define HID_DESKTOP_USAGE_MOTION    0x3c        /* Motion Wakeup */
+#define HID_DESKTOP_USAGE_START     0x3d        /* Start */
+#define HID_DESKTOP_USAGE_SELECT    0x3e        /* Select */
+                                           /* 0x3f Reserved */
+#define HID_DESKTOP_USAGE_VX         0x40       /* Vx */
+#define HID_DESKTOP_USAGE_VY         0x41       /* Vy */
+#define HID_DESKTOP_USAGE_VZ         0x42       /* Vz */
+#define HID_DESKTOP_USAGE_VBRX       0x43       /* Vbrx */
+#define HID_DESKTOP_USAGE_VBRY       0x44       /* Vbry */
+#define HID_DESKTOP_USAGE_VBRZ       0x45       /* Vbrz */
+#define HID_DESKTOP_USAGE_VNO        0x46       /* Vno */
+#define HID_DESKTOP_USAGE_FEATURE    0x47       /* Feature Notification */
+#define HID_DESKTOP_USAGE_RESOLUTION 0x48       /* Resolution Multiplier */
+                                           /* 0x49-7f Reserved */
+#define HID_DESKTOP_USAGE_CONTROL      0x80     /* System Control */
+#define HID_DESKTOP_USAGE_POWERDOWN    0x81     /* System Power Down */
+#define HID_DESKTOP_USAGE_SLEEP        0x82     /* System Sleep */
+#define HID_DESKTOP_USAGE_WAKEUP       0x83     /* System Wake Up */
+#define HID_DESKTOP_USAGE_CONTEXT_MENU 0x84     /* System Context Menu */
+#define HID_DESKTOP_USAGE_MAIN_MENU    0x85     /* System Main Menu */
+#define HID_DESKTOP_USAGE_APP_MENU     0x86     /* System App Menu */
+#define HID_DESKTOP_USAGE_MENU_HELP    0x87     /* System Menu Help */
+#define HID_DESKTOP_USAGE_MENU_EXIT    0x88     /* System Menu Exit */
+#define HID_DESKTOP_USAGE_MENU_SELECT  0x89     /* System Menu Select */
+#define HID_DESKTOP_USAGE_MENU_RIGHT   0x8a     /* System Menu Right */
+#define HID_DESKTOP_USAGE_MENU_LEFT    0x8b     /* System Menu Left */
+#define HID_DESKTOP_USAGE_MENU_UP      0x8c     /* System Menu Up */
+#define HID_DESKTOP_USAGE_MENU_DOWN    0x8d     /* System Menu Down */
+#define HID_DESKTOP_USAGE_COLD_RESTART 0x8e     /* System Cold Restart */
+#define HID_DESKTOP_USAGE_WARM_RESTART 0x8f     /* System Warm Restart */
+#define HID_DESKTOP_USAGE_DPAD_UP      0x90     /* D-pad Up */
+#define HID_DESKTOP_USAGE_DPAD_DOWN    0x91     /* D-pad Down */
+#define HID_DESKTOP_USAGE_DPAD_RIGHT   0x92     /* D-pad Right */
+#define HID_DESKTOP_USAGE_DPAD_LEFT    0x93     /* D-pad Left */
+                                           /* 0x94-9f Reserved */
+#define HID_DESKTOP_USAGE_DOCK            0xa0  /* System Dock */
+#define HID_DESKTOP_USAGE_UNDOCK          0xa1  /* System Undock */
+#define HID_DESKTOP_USAGE_SETUP           0xa2  /* System Setup */
+#define HID_DESKTOP_USAGE_BREAK           0xa3  /* System Break */
+#define HID_DESKTOP_USAGE_DEBUG_BREAK     0xa4  /* System Debugger Break */
+#define HID_DESKTOP_USAGE_APP_BREAK       0xa5  /* Application Break */
+#define HID_DESKTOP_USAGE_APP_DEBUG_BREAK 0xa6  /* Application Debugger Break */
+#define HID_DESKTOP_USAGE_MUTE            0xa7  /* System Speaker Mute */
+#define HID_DESKTOP_USAGE_HIBERNATE       0xa8  /* System Hibernate */
+                                           /* 0xa9-af Reserved */
+#define HID_DESKTOP_USAGE_DISPLAY_INVERT   0xb0 /* System Display Invert */
+#define HID_DESKTOP_USAGE_DISPALY_INTERNAL 0xb1 /* System Display Internal */
+#define HID_DESKTOP_USAGE_DISPLAY_EXTERNAL 0xb2 /* System Display External */
+#define HID_DESKTOP_USAGE_DISPLAY_BOTH     0xb3 /* System Display Both */
+#define HID_DESKTOP_USAGE_DISPLAY_DUAL     0xb4 /* System Display Dual */
+#define HID_DESKTOP_USAGE_DISPLAY_TOGGLE   0xb5 /* System Display Toggle Int/Ext */
+#define HID_DESKTOP_USAGE_DISPLAY_SWAP     0xb6 /* System Display Swap */
+#define HID_DESKTOP_USAGE_                 0xb7 /* System Display LCD Autoscale */
+                                           /* 0xb8-ffff Reserved */
+
+/* Keyboard usage IDs (HuT 10) */
+#define HID_KBD_USAGE_NONE            0x00 /* Reserved (no event indicated) */
+#define HID_KBD_USAGE_ERRORROLLOVER   0x01 /* Keyboard ErrorRollOver */
+#define HID_KBD_USAGE_POSTFAIL        0x02 /* Keyboard POSTFail */
+#define HID_KBD_USAGE_ERRUNDEF        0x03 /* Keyboard ErrorUndefined */
+#define HID_KBD_USAGE_A               0x04 /* Keyboard a or A (B-Z follow) */
+#define HID_KBD_USAGE_1               0x1e /* Keyboard 1 (2-9 follow) */
+#define HID_KBD_USAGE_EXCLAM          0x1e /* Keyboard 1 and ! */
+#define HID_KBD_USAGE_AT              0x1f /* Keyboard 2 and @ */
+#define HID_KBD_USAGE_POUND           0x20 /* Keyboard 3 and # */
+#define HID_KBD_USAGE_DOLLAR          0x21 /* Keyboard 4 and $ */
+#define HID_KBD_USAGE_PERCENT         0x22 /* Keyboard 5 and % */
+#define HID_KBD_USAGE_CARAT           0x23 /* Keyboard 6 and ^ */
+#define HID_KBD_USAGE_AMPERSAND       0x24 /* Keyboard 7 and & */
+#define HID_KBD_USAGE_ASTERISK        0x25 /* Keyboard 8 and * */
+#define HID_KBD_USAGE_LPAREN          0x26 /* Keyboard 9 and ( */
+#define HID_KBD_USAGE_0               0x27 /* Keyboard 0 and ) */
+#define HID_KBD_USAGE_RPAREN          0x27 /* Keyboard 0 and ) */
+#define HID_KBD_USAGE_ENTER           0x28 /* Keyboard Return (ENTER) */
+#define HID_KBD_USAGE_ESCAPE          0x29 /* Keyboard ESCAPE */
+#define HID_KBD_USAGE_DELETE          0x2a /* Keyboard DELETE (Backspace) */
+#define HID_KBD_USAGE_TAB             0x2b /* Keyboard Tab */
+#define HID_KBD_USAGE_SPACE           0x2c /* Keyboard Spacebar */
+#define HID_KBD_USAGE_HYPHEN          0x2d /* Keyboard - and (underscore) */
+#define HID_KBD_USAGE_UNDERSCORE      0x2d /* Keyboard - and (underscore) */
+#define HID_KBD_USAGE_EQUAL           0x2e /* Keyboard = and + */
+#define HID_KBD_USAGE_PLUS            0x2e /* Keyboard = and + */
+#define HID_KBD_USAGE_LBRACKET        0x2f /* Keyboard [ and { */
+#define HID_KBD_USAGE_LBRACE          0x2f /* Keyboard [ and { */
+#define HID_KBD_USAGE_RBRACKET        0x30 /* Keyboard ] and } */
+#define HID_KBD_USAGE_RBRACE          0x30 /* Keyboard ] and } */
+#define HID_KBD_USAGE_BSLASH          0x31 /* Keyboard \ and | */
+#define HID_KBD_USAGE_VERTBAR         0x31 /* Keyboard \ and | */
+#define HID_KBD_USAGE_NONUSPOUND      0x32 /* Keyboard Non-US # and ~ */
+#define HID_KBD_USAGE_TILDE           0x32 /* Keyboard Non-US # and ~ */
+#define HID_KBD_USAGE_SEMICOLON       0x33 /* Keyboard ; and : */
+#define HID_KBD_USAGE_COLON           0x33 /* Keyboard ; and : */
+#define HID_KBD_USAGE_SQUOTE          0x34 /* Keyboard ' and " */
+#define HID_KBD_USAGE_DQUOUTE         0x34 /* Keyboard ' and " */
+#define HID_KBD_USAGE_GACCENT         0x35 /* Keyboard Grave Accent and Tilde */
+#define HID_KBD_USAGE_GTILDE          0x35 /* Keyboard Grave Accent and Tilde */
+#define HID_KBD_USAGE_COMMON          0x36 /* Keyboard , and < */
+#define HID_KBD_USAGE_LT              0x36 /* Keyboard , and < */
+#define HID_KBD_USAGE_PERIOD          0x37 /* Keyboard . and > */
+#define HID_KBD_USAGE_GT              0x37 /* Keyboard . and > */
+#define HID_KBD_USAGE_DIV             0x38 /* Keyboard / and ? */
+#define HID_KBD_USAGE_QUESTION        0x38 /* Keyboard / and ? */
+#define HID_KBD_USAGE_CAPSLOCK        0x39 /* Keyboard Caps Lock */
+#define HID_KBD_USAGE_F1              0x3a /* Keyboard F1 */
+#define HID_KBD_USAGE_F2              0x3b /* Keyboard F2 */
+#define HID_KBD_USAGE_F3              0x3c /* Keyboard F3 */
+#define HID_KBD_USAGE_F4              0x3d /* Keyboard F4 */
+#define HID_KBD_USAGE_F5              0x3e /* Keyboard F5 */
+#define HID_KBD_USAGE_F6              0x3f /* Keyboard F6 */
+#define HID_KBD_USAGE_F7              0x40 /* Keyboard F7 */
+#define HID_KBD_USAGE_F8              0x41 /* Keyboard F8 */
+#define HID_KBD_USAGE_F9              0x42 /* Keyboard F9 */
+#define HID_KBD_USAGE_F10             0x43 /* Keyboard F10 */
+#define HID_KBD_USAGE_F11             0x44 /* Keyboard F11 */
+#define HID_KBD_USAGE_F12             0x45 /* Keyboard F12 */
+#define HID_KBD_USAGE_PRINTSCN        0x46 /* Keyboard PrintScreen */
+#define HID_KBD_USAGE_SCROLLLOCK      0x47 /* Keyboard Scroll Lock */
+#define HID_KBD_USAGE_PAUSE           0x48 /* Keyboard Pause */
+#define HID_KBD_USAGE_INSERT          0x49 /* Keyboard Insert */
+#define HID_KBD_USAGE_HOME            0x4a /* Keyboard Home */
+#define HID_KBD_USAGE_PAGEUP          0x4b /* Keyboard PageUp */
+#define HID_KBD_USAGE_DELFWD          0x4c /* Keyboard Delete Forward */
+#define HID_KBD_USAGE_END             0x4d /* Keyboard End */
+#define HID_KBD_USAGE_PAGEDOWN        0x4e /* Keyboard PageDown */
+#define HID_KBD_USAGE_RIGHT           0x4f /* eyboard RightArrow */
+#define HID_KBD_USAGE_LEFT            0x50 /* Keyboard LeftArrow */
+#define HID_KBD_USAGE_DOWN            0x51 /* Keyboard DownArrow */
+#define HID_KBD_USAGE_UP              0x52 /* Keyboard UpArrow */
+#define HID_KBD_USAGE_KPDNUMLOCK      0x53 /* Keypad Num Lock and Clear */
+#define HID_KBD_USAGE_KPDNUMLOCKCLEAR 0x53 /* Keypad Num Lock and Clear */
+#define HID_KBD_USAGE_KPDDIV          0x54 /* Keypad / */
+#define HID_KBD_USAGE_KPDMUL          0x55 /* Keypad * */
+#define HID_KBD_USAGE_KPDHMINUS       0x56 /* Keypad - */
+#define HID_KBD_USAGE_KPDPLUS         0x57 /* Keypad + */
+#define HID_KBD_USAGE_KPDEMTER        0x58 /* Keypad ENTER */
+#define HID_KBD_USAGE_KPD1            0x59 /* Keypad 1 (2-9 follow) */
+#define HID_KBD_USAGE_KPDEND          0x59 /* Keypad 1 and End */
+#define HID_KBD_USAGE_KPDDOWN         0x5a /* Keypad 2 and Down Arrow */
+#define HID_KBD_USAGE_KPDPAGEDN       0x5b /* Keypad 3 and PageDn */
+#define HID_KBD_USAGE_KPDLEFT         0x5c /* Keypad 4 and Left Arrow */
+#define HID_KBD_USAGE_KPDRIGHT        0x5e /* Keypad 6 and Right Arrow */
+#define HID_KBD_USAGE_KPDHOME         0x5f /* Keypad 7 and Home */
+#define HID_KBD_USAGE_KPDUP           0x60 /* Keypad 8 and Up Arrow */
+#define HID_KBD_USAGE_KPDPAGEUP       0x61 /* Keypad 9 and PageUp */
+#define HID_KBD_USAGE_KPD0            0x62 /* Keypad 0 and Insert */
+#define HID_KBD_USAGE_KPDINSERT       0x62 /* Keypad 0 and Insert */
+#define HID_KBD_USAGE_KPDDECIMALPT    0x63 /* Keypad . and Delete */
+#define HID_KBD_USAGE_KPDDELETE       0x63 /* Keypad . and Delete */
+#define HID_KBD_USAGE_NONSLASH        0x64 /* Keyboard Non-US \ and | */
+#define HID_KBD_USAGE_NONUSVERT       0x64 /* Keyboard Non-US \ and | */
+#define HID_KBD_USAGE_APPLICATION     0x65 /* Keyboard Application */
+#define HID_KBD_USAGE_POWER           0x66 /* Keyboard Power */
+#define HID_KBD_USAGE_KPDEQUAL        0x67 /* Keypad = */
+#define HID_KBD_USAGE_F13             0x68 /* Keyboard F13 */
+#define HID_KBD_USAGE_F14             0x69 /* Keyboard F14 */
+#define HID_KBD_USAGE_F15             0x6a /* Keyboard F15 */
+#define HID_KBD_USAGE_F16             0x6b /* Keyboard F16 */
+#define HID_KBD_USAGE_F17             0x6c /* Keyboard F17 */
+#define HID_KBD_USAGE_F18             0x6d /* Keyboard F18 */
+#define HID_KBD_USAGE_F19             0x6e /* Keyboard F19 */
+#define HID_KBD_USAGE_F20             0x6f /* Keyboard F20 */
+#define HID_KBD_USAGE_F21             0x70 /* Keyboard F21 */
+#define HID_KBD_USAGE_F22             0x71 /* Keyboard F22 */
+#define HID_KBD_USAGE_F23             0x72 /* Keyboard F23 */
+#define HID_KBD_USAGE_F24             0x73 /* Keyboard F24 */
+#define HID_KBD_USAGE_EXECUTE         0x74 /* Keyboard Execute */
+#define HID_KBD_USAGE_HELP            0x75 /* Keyboard Help */
+#define HID_KBD_USAGE_MENU            0x76 /* Keyboard Menu */
+#define HID_KBD_USAGE_SELECT          0x77 /* Keyboard Select */
+#define HID_KBD_USAGE_STOP            0x78 /* Keyboard Stop */
+#define HID_KBD_USAGE_AGAIN           0x79 /* Keyboard Again */
+#define HID_KBD_USAGE_UNDO            0x7a /* Keyboard Undo */
+#define HID_KBD_USAGE_CUT             0x7b /* Keyboard Cut */
+#define HID_KBD_USAGE_COPY            0x7c /* Keyboard Copy */
+#define HID_KBD_USAGE_PASTE           0x7d /* Keyboard Paste */
+#define HID_KBD_USAGE_FIND            0x7e /* Keyboard Find */
+#define HID_KBD_USAGE_MUTE            0x7f /* Keyboard Mute */
+#define HID_KBD_USAGE_VOLUP           0x80 /* Keyboard Volume Up */
+#define HID_KBD_USAGE_VOLDOWN         0x81 /* Keyboard Volume Down */
+#define HID_KBD_USAGE_LCAPSLOCK       0x82 /* Keyboard Locking Caps Lock */
+#define HID_KBD_USAGE_LNUMLOCK        0x83 /* Keyboard Locking Num Lock */
+#define HID_KBD_USAGE_LSCROLLLOCK     0x84 /* Keyboard Locking Scroll Lock */
+#define HID_KBD_USAGE_KPDCOMMA        0x85 /* Keypad Comma */
+#define HID_KBD_USAGE_KPDEQUALSIGN    0x86 /* Keypad Equal Sign */
+#define HID_KBD_USAGE_INTERNATIONAL1  0x87 /* Keyboard International 1 */
+#define HID_KBD_USAGE_INTERNATIONAL2  0x88 /* Keyboard International 2 */
+#define HID_KBD_USAGE_INTERNATIONAL3  0x89 /* Keyboard International 3 */
+#define HID_KBD_USAGE_INTERNATIONAL4  0x8a /* Keyboard International 4 */
+#define HID_KBD_USAGE_INTERNATIONAL5  0x8b /* Keyboard International 5 */
+#define HID_KBD_USAGE_INTERNATIONAL6  0x8c /* Keyboard International 6 */
+#define HID_KBD_USAGE_INTERNATIONAL7  0x8d /* Keyboard International 7 */
+#define HID_KBD_USAGE_INTERNATIONAL8  0x8e /* Keyboard International 8 */
+#define HID_KBD_USAGE_INTERNATIONAL9  0x8f /* Keyboard International 9 */
+#define HID_KBD_USAGE_LANG1           0x90 /* Keyboard LANG1 */
+#define HID_KBD_USAGE_LANG2           0x91 /* Keyboard LANG2 */
+#define HID_KBD_USAGE_LANG3           0x92 /* Keyboard LANG3 */
+#define HID_KBD_USAGE_LANG4           0x93 /* Keyboard LANG4 */
+#define HID_KBD_USAGE_LANG5           0x94 /* Keyboard LANG5 */
+#define HID_KBD_USAGE_LANG6           0x95 /* Keyboard LANG6 */
+#define HID_KBD_USAGE_LANG7           0x96 /* Keyboard LANG7 */
+#define HID_KBD_USAGE_LANG8           0x97 /* Keyboard LANG8 */
+#define HID_KBD_USAGE_LANG9           0x98 /* Keyboard LANG9 */
+#define HID_KBD_USAGE_ALTERASE        0x99 /* Keyboard Alternate Erase */
+#define HID_KBD_USAGE_SYSREQ          0x9a /* Keyboard SysReq/Attention */
+#define HID_KBD_USAGE_CANCEL          0x9b /* Keyboard Cancel */
+#define HID_KBD_USAGE_CLEAR           0x9c /* Keyboard Clear */
+#define HID_KBD_USAGE_PRIOR           0x9d /* Keyboard Prior */
+#define HID_KBD_USAGE_RETURN          0x9e /* Keyboard Return */
+#define HID_KBD_USAGE_SEPARATOR       0x9f /* Keyboard Separator */
+#define HID_KBD_USAGE_OUT             0xa0 /* Keyboard Out */
+#define HID_KBD_USAGE_OPER            0xa1 /* Keyboard Oper */
+#define HID_KBD_USAGE_CLEARAGAIN      0xa2 /* Keyboard Clear/Again */
+#define HID_KBD_USAGE_CLRSEL          0xa3 /* Keyboard CrSel/Props */
+#define HID_KBD_USAGE_EXSEL           0xa4 /* Keyboard ExSel */
+#define HID_KBD_USAGE_KPD00           0xb0 /* Keypad 00 */
+#define HID_KBD_USAGE_KPD000          0xb1 /* Keypad 000 */
+#define HID_KBD_USAGE_THOUSEPARATOR   0xb2 /* Thousands Separator */
+#define HID_KBD_USAGE_DECSEPARATOR    0xb3 /* Decimal Separator */
+#define HID_KBD_USAGE_CURRUNIT        0xb4 /* Currency Unit */
+#define HID_KBD_USAGE_CURRSUBUNIT     0xb5 /* Currency Sub-unit */
+#define HID_KBD_USAGE_KPDLPAREN       0xb6 /* Keypad ( */
+#define HID_KBD_USAGE_KPDRPAREN       0xb7 /* Keypad ) */
+#define HID_KBD_USAGE_KPDLBRACE       0xb8 /* Keypad { */
+#define HID_KBD_USAGE_KPDRBRACE       0xb9 /* Keypad } */
+#define HID_KBD_USAGE_KPDTAB          0xba /* Keypad Tab */
+#define HID_KBD_USAGE_KPDBACKSPACE    0xbb /* Keypad Backspace */
+#define HID_KBD_USAGE_KPDA            0xbc /* Keypad A (B-F follow) */
+#define HID_KBD_USAGE_KPDXOR          0xc2 /* Keypad XOR */
+#define HID_KBD_USAGE_KPDEXP          0xc3 /* Keypad ^ */
+#define HID_KBD_USAGE_KPDPERCENT      0xc4 /* Keypad % */
+#define HID_KBD_USAGE_KPDLT           0xc5 /* Keypad < */
+#define HID_KBD_USAGE_KPDGT           0xc6 /* Keypad > */
+#define HID_KBD_USAGE_KPDAMPERSAND    0xc7 /* Keypad & */
+#define HID_KBD_USAGE_KPDAND          0xc8 /* Keypad && */
+#define HID_KBD_USAGE_KPDVERT         0xc9 /* Keypad | */
+#define HID_KBD_USAGE_KPDOR           0xca /* Keypad || */
+#define HID_KBD_USAGE_KPDCOLON        0xcb /* Keypad : */
+#define HID_KBD_USAGE_KPDPOUND        0xcc /* Keypad # */
+#define HID_KBD_USAGE_KPDSPACE        0xcd /* Keypad Space */
+#define HID_KBD_USAGE_KPDAT           0xce /* Keypad @ */
+#define HID_KBD_USAGE_KPDEXCLAM       0xcf /* Keypad ! */
+#define HID_KBD_USAGE_KPDMEMSTORE     0xd0 /* Keypad Memory Store */
+#define HID_KBD_USAGE_KPDMEMRECALL    0xd1 /* Keypad Memory Recall */
+#define HID_KBD_USAGE_KPDMEMCLEAR     0xd2 /* Keypad Memory Clear */
+#define HID_KBD_USAGE_KPDMEMADD       0xd3 /* Keypad Memory Add */
+#define HID_KBD_USAGE_KPDMEMSUB       0xd4 /* Keypad Memory Subtract */
+#define HID_KBD_USAGE_KPDMEMMULT      0xd5 /* Keypad Memory Multiply */
+#define HID_KBD_USAGE_KPDMEMDIV       0xd6 /* Keypad Memory Divide */
+#define HID_KBD_USAGE_KPDPLUSMINUS    0xd7 /* Keypad +/- */
+#define HID_KBD_USAGE_KPDCLEAR        0xd8 /* Keypad Clear */
+#define HID_KBD_USAGE_KPDCLEARENTRY   0xd9 /* Keypad Clear Entry */
+#define HID_KBD_USAGE_KPDBINARY       0xda /* Keypad Binary */
+#define HID_KBD_USAGE_KPDOCTAL        0xdb /* Keypad Octal */
+#define HID_KBD_USAGE_KPDDECIMAL      0xdc /* Keypad Decimal */
+#define HID_KBD_USAGE_KPDHEXADECIMAL  0xdd /* Keypad Hexadecimal */
+#define HID_KBD_USAGE_LCTRL           0xe0 /* Keyboard LeftControl */
+#define HID_KBD_USAGE_LSHIFT          0xe1 /* Keyboard LeftShift */
+#define HID_KBD_USAGE_LALT            0xe2 /* Keyboard LeftAlt */
+#define HID_KBD_USAGE_LGUI            0xe3 /* Keyboard Left GUI */
+#define HID_KBD_USAGE_RCTRL           0xe4 /* Keyboard RightControl */
+#define HID_KBD_USAGE_RSHIFT          0xe5 /* Keyboard RightShift */
+#define HID_KBD_USAGE_RALT            0xe6 /* Keyboard RightAlt */
+#define HID_KBD_USAGE_RGUI            0xe7 /* Keyboard Right GUI */
+
+#define HID_KBD_USAGE_MAX 0xe7
+
+/* HID Report Definitions */
+struct usb_hid_class_subdescriptor {
+    uint8_t bDescriptorType;/* Class descriptor type (See 7.1) */
+    uint16_t wDescriptorLength;/* Size of the report descriptor */
+} __PACKED;
+
+struct usb_hid_descriptor {
+    uint8_t bLength; /* Size of the HID descriptor */
+    uint8_t bDescriptorType;/* HID descriptor type */
+    uint16_t bcdHID;/* HID class specification release */
+    uint8_t bCountryCode;/* Country code */
+    uint8_t bNumDescriptors;/* Number of descriptors (>=1) */
+
+    /*
+     * Specification says at least one Class Descriptor needs to
+     * be present (Report Descriptor).
+     */
+    struct usb_hid_class_subdescriptor subdesc[1];
+} __PACKED;
+
+/* Standard Reports *********************************************************/
+
+/* Keyboard input report (8 bytes) (HID B.1) */
+struct usb_hid_kbd_report
+{
+  uint8_t modifier;  /* Modifier keys. See HID_MODIFER_* definitions */
+  uint8_t reserved;
+  uint8_t key[6];    /* Keycode 1-6 */
+};
+
+/* Keyboard output report (1 byte) (HID B.1),
+ * see USBHID_KBDOUT_* definitions
+ */
+
+/* Mouse input report (HID B.2) */
+struct usb_hid_mouse_report
+{
+  uint8_t buttons;   /* See HID_MOUSE_INPUT_BUTTON_* definitions */
+  uint8_t xdisp;     /* X displacement */
+  uint8_t ydisp;     /* y displacement */
+                     /* Device specific additional bytes may follow */
+#ifdef CONFIG_INPUT_MOUSE_WHEEL
+  uint8_t wdisp;     /* Wheel displacement */
+#endif
+};
+
+/* Joystick input report (1 bytes) (HID D.1) */
+struct usb_hid_js_report
+{
+  uint8_t xpos;      /* X position */
+  uint8_t ypos;      /* X position */
+  uint8_t buttons;   /* See USBHID_JSIN_* definitions */
+  uint8_t throttle;  /* Throttle */
+};
+
+#endif /* USB_HID_H */

+ 89 - 0
components/drivers/usb/cherryusb/class/hid/usbd_hid.c

@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_hid.h"
+
+static int hid_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    USB_LOG_DBG("HID Class request: "
+                "bRequest 0x%02x\r\n",
+                setup->bRequest);
+
+    uint8_t intf_num = LO_BYTE(setup->wIndex);
+
+    switch (setup->bRequest) {
+        case HID_REQUEST_GET_REPORT:
+            /* report id ,report type */
+            usbd_hid_get_report(busid, intf_num, LO_BYTE(setup->wValue), HI_BYTE(setup->wValue), data, len);
+            break;
+        case HID_REQUEST_GET_IDLE:
+            (*data)[0] = usbd_hid_get_idle(busid, intf_num, LO_BYTE(setup->wValue));
+            *len = 1;
+            break;
+        case HID_REQUEST_GET_PROTOCOL:
+            (*data)[0] = usbd_hid_get_protocol(busid, intf_num);
+            *len = 1;
+            break;
+        case HID_REQUEST_SET_REPORT:
+            /* report id ,report type, report, report len */
+            usbd_hid_set_report(busid, intf_num, LO_BYTE(setup->wValue), HI_BYTE(setup->wValue), *data, *len);
+            break;
+        case HID_REQUEST_SET_IDLE:
+            /* report id, duration */
+            usbd_hid_set_idle(busid, intf_num, LO_BYTE(setup->wValue), HI_BYTE(setup->wValue));
+            break;
+        case HID_REQUEST_SET_PROTOCOL:
+            /* protocol */
+            usbd_hid_set_protocol(busid, intf_num, LO_BYTE(setup->wValue));
+            break;
+
+        default:
+            USB_LOG_WRN("Unhandled HID Class bRequest 0x%02x\r\n", setup->bRequest);
+            return -1;
+    }
+
+    return 0;
+}
+
+struct usbd_interface *usbd_hid_init_intf(uint8_t busid, struct usbd_interface *intf, const uint8_t *desc, uint32_t desc_len)
+{
+    intf->class_interface_handler = hid_class_interface_request_handler;
+    intf->class_endpoint_handler = NULL;
+    intf->vendor_handler = NULL;
+    intf->notify_handler = NULL;
+
+    intf->hid_report_descriptor = desc;
+    intf->hid_report_descriptor_len = desc_len;
+    return intf;
+}
+
+__WEAK void usbd_hid_get_report(uint8_t busid, uint8_t intf, uint8_t report_id, uint8_t report_type, uint8_t **data, uint32_t *len)
+{
+    (*data[0]) = 0;
+    *len = 1;
+}
+
+__WEAK uint8_t usbd_hid_get_idle(uint8_t busid, uint8_t intf, uint8_t report_id)
+{
+    return 0;
+}
+
+__WEAK uint8_t usbd_hid_get_protocol(uint8_t busid, uint8_t intf)
+{
+    return 0;
+}
+
+__WEAK void usbd_hid_set_report(uint8_t busid, uint8_t intf, uint8_t report_id, uint8_t report_type, uint8_t *report, uint32_t report_len)
+{
+}
+
+__WEAK void usbd_hid_set_idle(uint8_t busid, uint8_t intf, uint8_t report_id, uint8_t duration)
+{
+}
+
+__WEAK void usbd_hid_set_protocol(uint8_t busid, uint8_t intf, uint8_t protocol)
+{
+}

+ 34 - 0
components/drivers/usb/cherryusb/class/hid/usbd_hid.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_HID_H
+#define USBD_HID_H
+
+#include "usb_hid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Init hid interface driver */
+struct usbd_interface *usbd_hid_init_intf(uint8_t busid, struct usbd_interface *intf, const uint8_t *desc, uint32_t desc_len);
+
+/* Register desc api */
+void usbd_hid_descriptor_register(uint8_t busid, uint8_t intf_num, const uint8_t *desc);
+void usbd_hid_report_descriptor_register(uint8_t busid, uint8_t intf_num, const uint8_t *desc, uint32_t desc_len);
+
+/* Setup request command callback api */
+void usbd_hid_get_report(uint8_t busid, uint8_t intf, uint8_t report_id, uint8_t report_type, uint8_t **data, uint32_t *len);
+uint8_t usbd_hid_get_idle(uint8_t busid, uint8_t intf, uint8_t report_id);
+uint8_t usbd_hid_get_protocol(uint8_t busid, uint8_t intf);
+void usbd_hid_set_report(uint8_t busid, uint8_t intf, uint8_t report_id, uint8_t report_type, uint8_t *report, uint32_t report_len);
+void usbd_hid_set_idle(uint8_t busid, uint8_t intf, uint8_t report_id, uint8_t duration);
+void usbd_hid_set_protocol(uint8_t busid, uint8_t intf, uint8_t protocol);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBD_HID_H */

+ 231 - 0
components/drivers/usb/cherryusb/class/hid/usbh_hid.c

@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_hid.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "usbh_hid"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/input%d"
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hid_buf[128];
+
+static struct usbh_hid g_hid_class[CONFIG_USBHOST_MAX_HID_CLASS];
+static uint32_t g_devinuse = 0;
+
+static struct usbh_hid *usbh_hid_class_alloc(void)
+{
+    int devno;
+
+    for (devno = 0; devno < CONFIG_USBHOST_MAX_HID_CLASS; devno++) {
+        if ((g_devinuse & (1 << devno)) == 0) {
+            g_devinuse |= (1 << devno);
+            memset(&g_hid_class[devno], 0, sizeof(struct usbh_hid));
+            g_hid_class[devno].minor = devno;
+            return &g_hid_class[devno];
+        }
+    }
+    return NULL;
+}
+
+static void usbh_hid_class_free(struct usbh_hid *hid_class)
+{
+    int devno = hid_class->minor;
+
+    if (devno >= 0 && devno < 32) {
+        g_devinuse &= ~(1 << devno);
+    }
+    memset(hid_class, 0, sizeof(struct usbh_hid));
+}
+
+static int usbh_hid_get_report_descriptor(struct usbh_hid *hid_class, uint8_t *buffer)
+{
+    struct usb_setup_packet *setup = hid_class->hport->setup;
+    int ret;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
+    setup->wValue = HID_DESCRIPTOR_TYPE_HID_REPORT << 8;
+    setup->wIndex = hid_class->intf;
+    setup->wLength = 128;
+
+    ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf);
+    if (ret < 0) {
+        return ret;
+    }
+    memcpy(buffer, g_hid_buf, ret - 8);
+    return ret;
+}
+
+int usbh_hid_set_idle(struct usbh_hid *hid_class, uint8_t report_id, uint8_t duration)
+{
+    struct usb_setup_packet *setup = hid_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = HID_REQUEST_SET_IDLE;
+    setup->wValue = (duration << 8) | report_id;
+    setup->wIndex = hid_class->intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(hid_class->hport, setup, NULL);
+}
+
+int usbh_hid_get_idle(struct usbh_hid *hid_class, uint8_t *buffer)
+{
+    struct usb_setup_packet *setup = hid_class->hport->setup;
+    int ret;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = HID_REQUEST_GET_IDLE;
+    setup->wValue = 0;
+    setup->wIndex = hid_class->intf;
+    setup->wLength = 1;
+
+    ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf);
+    if (ret < 0) {
+        return ret;
+    }
+    memcpy(buffer, g_hid_buf, 1);
+    return ret;
+}
+
+int usbh_hid_set_protocol(struct usbh_hid *hid_class, uint8_t protocol)
+{
+    struct usb_setup_packet *setup = hid_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = HID_REQUEST_SET_PROTOCOL;
+    setup->wValue = protocol;
+    setup->wIndex = 0;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(hid_class->hport, setup, NULL);
+}
+
+int usbh_hid_set_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t report_id, uint8_t *buffer, uint32_t buflen)
+{
+    struct usb_setup_packet *setup = hid_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = HID_REQUEST_SET_REPORT;
+    setup->wValue = (uint16_t)(((uint32_t)report_type << 8U) | (uint32_t)report_id);
+    setup->wIndex = 0;
+    setup->wLength = buflen;
+
+    return usbh_control_transfer(hid_class->hport, setup, buffer);
+}
+
+int usbh_hid_get_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t report_id, uint8_t *buffer, uint32_t buflen)
+{
+    struct usb_setup_packet *setup = hid_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = HID_REQUEST_GET_REPORT;
+    setup->wValue = (uint16_t)(((uint32_t)report_type << 8U) | (uint32_t)report_id);
+    setup->wIndex = 0;
+    setup->wLength = buflen;
+
+    return usbh_control_transfer(hid_class->hport, setup, buffer);
+}
+
+int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret;
+
+    struct usbh_hid *hid_class = usbh_hid_class_alloc();
+    if (hid_class == NULL) {
+        USB_LOG_ERR("Fail to alloc hid_class\r\n");
+        return -USB_ERR_NOMEM;
+    }
+
+    hid_class->hport = hport;
+    hid_class->intf = intf;
+
+    hport->config.intf[intf].priv = hid_class;
+
+    // /* 0x0 = boot protocol, 0x1 = report protocol */
+    // ret = usbh_hid_set_protocol(hid_class, 0x1);
+    // if (ret < 0) {
+    //     return ret;
+    // }
+
+    ret = usbh_hid_set_idle(hid_class, 0, 0);
+    if (ret < 0) {
+        USB_LOG_WRN("Do not support set idle\r\n");
+    }
+
+    ret = usbh_hid_get_report_descriptor(hid_class, hid_class->report_desc);
+    if (ret < 0) {
+        return ret;
+    }
+
+    for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
+        ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
+        if (ep_desc->bEndpointAddress & 0x80) {
+            USBH_EP_INIT(hid_class->intin, ep_desc);
+        } else {
+            USBH_EP_INIT(hid_class->intout, ep_desc);
+        }
+    }
+
+    snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, hid_class->minor);
+
+    USB_LOG_INFO("Register HID Class:%s\r\n", hport->config.intf[intf].devname);
+
+    usbh_hid_run(hid_class);
+    return ret;
+}
+
+int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_hid *hid_class = (struct usbh_hid *)hport->config.intf[intf].priv;
+
+    if (hid_class) {
+        if (hid_class->intin) {
+            usbh_kill_urb(&hid_class->intin_urb);
+        }
+
+        if (hid_class->intout) {
+            usbh_kill_urb(&hid_class->intout_urb);
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister HID Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_hid_stop(hid_class);
+        }
+
+        usbh_hid_class_free(hid_class);
+    }
+
+    return ret;
+}
+
+__WEAK void usbh_hid_run(struct usbh_hid *hid_class)
+{
+}
+
+__WEAK void usbh_hid_stop(struct usbh_hid *hid_class)
+{
+}
+
+const struct usbh_class_driver hid_class_driver = {
+    .driver_name = "hid",
+    .connect = usbh_hid_connect,
+    .disconnect = usbh_hid_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info hid_custom_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS,
+    .class = USB_DEVICE_CLASS_HID,
+    .subclass = 0x00,
+    .protocol = 0x00,
+    .id_table = NULL,
+    .class_driver = &hid_class_driver
+};

+ 41 - 0
components/drivers/usb/cherryusb/class/hid/usbh_hid.h

@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_HID_H
+#define USBH_HID_H
+
+#include "usb_hid.h"
+
+struct usbh_hid {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *intin;  /* INTR IN endpoint */
+    struct usb_endpoint_descriptor *intout; /* INTR OUT endpoint */
+    struct usbh_urb intin_urb;              /* INTR IN urb */
+    struct usbh_urb intout_urb;             /* INTR OUT urb */
+
+    uint8_t report_desc[256];
+    uint8_t intf; /* interface number */
+    uint8_t minor;
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_hid_set_idle(struct usbh_hid *hid_class, uint8_t report_id, uint8_t duration);
+int usbh_hid_get_idle(struct usbh_hid *hid_class, uint8_t *buffer);
+int usbh_hid_set_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t report_id, uint8_t *buffer, uint32_t buflen);
+int usbh_hid_get_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t report_id, uint8_t *buffer, uint32_t buflen);
+
+void usbh_hid_run(struct usbh_hid *hid_class);
+void usbh_hid_stop(struct usbh_hid *hid_class);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_HID_H */

+ 121 - 0
components/drivers/usb/cherryusb/class/hub/usb_hub.h

@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_HUB_H
+#define USB_HUB_H
+
+/* HUB Class Descriptor Types */
+#define HUB_DESCRIPTOR_TYPE_HUB  0x29
+#define HUB_DESCRIPTOR_TYPE_HUB3 0x2A
+
+/* Hub class requests */
+#define HUB_REQUEST_GET_STATUS      USB_REQUEST_GET_STATUS
+#define HUB_REQUEST_CLEAR_FEATURE   USB_REQUEST_CLEAR_FEATURE
+#define HUB_REQUEST_SET_FEATURE     USB_REQUEST_SET_FEATURE
+#define HUB_REQUEST_GET_DESCRIPTOR  USB_REQUEST_GET_DESCRIPTOR
+#define HUB_REQUEST_SET_DESCRIPTOR  USB_REQUEST_SET_DESCRIPTOR
+#define HUB_REQUEST_CLEAR_TT_BUFFER (0x08)
+#define HUB_REQUEST_RESET_TT        (0x09)
+#define HUB_REQUEST_GET_TT_STATE    (0x0a)
+#define HUB_REQUEST_STOP_TT         (0x0b)
+#define HUB_REQUEST_SET_HUB_DEPTH   (0x0C)
+
+/* Hub class features */
+#define HUB_FEATURE_HUB_C_LOCALPOWER  (0x0)
+#define HUB_FEATURE_HUB_C_OVERCURRENT (0x1)
+
+/* Port features */
+#define HUB_PORT_FEATURE_CONNECTION    (0x00)
+#define HUB_PORT_FEATURE_ENABLE        (0x01)
+#define HUB_PORT_FEATURE_SUSPEND       (0x02)
+#define HUB_PORT_FEATURE_OVERCURRENT   (0x03)
+#define HUB_PORT_FEATURE_RESET         (0x04)
+#define HUB_PORT_FEATURE_L1            (0x05)
+#define HUB_PORT_FEATURE_POWER         (0x08)
+#define HUB_PORT_FEATURE_LOWSPEED      (0x09)
+#define HUB_PORT_FEATURE_HIGHSPEED     (0x0a)
+#define HUB_PORT_FEATURE_C_CONNECTION  (0x10)
+#define HUB_PORT_FEATURE_C_ENABLE      (0x11)
+#define HUB_PORT_FEATURE_C_SUSPEND     (0x12)
+#define HUB_PORT_FEATURE_C_OVER_CURREN (0x13)
+#define HUB_PORT_FEATURE_C_RESET       (0x14)
+#define HUB_PORT_FEATURE_TEST          (0x15)
+#define HUB_PORT_FEATURE_INDICATOR     (0x16)
+#define HUB_PORT_FEATURE_C_PORTL1      (0x17)
+
+/* Hub status */
+#define HUB_STATUS_LOCALPOWER  (1 << 0)
+#define HUB_STATUS_OVERCURRENT (1 << 1)
+
+/* Hub status change */
+#define HUB_STATUS_C_LOCALPOWER  (1 << 0)
+#define HUB_STATUS_C_OVERCURRENT (1 << 1)
+
+/* Hub port status */
+#define HUB_PORT_STATUS_CONNECTION  (1 << 0)
+#define HUB_PORT_STATUS_ENABLE      (1 << 1)
+#define HUB_PORT_STATUS_SUSPEND     (1 << 2)
+#define HUB_PORT_STATUS_OVERCURRENT (1 << 3)
+#define HUB_PORT_STATUS_RESET       (1 << 4)
+#define HUB_PORT_STATUS_L1          (1 << 5)
+#define HUB_PORT_STATUS_POWER       (1 << 8)
+#define HUB_PORT_STATUS_LOW_SPEED   (1 << 9)
+#define HUB_PORT_STATUS_HIGH_SPEED  (1 << 10)
+#define HUB_PORT_STATUS_TEST        (1 << 11)
+#define HUB_PORT_STATUS_INDICATOR   (1 << 12)
+
+/* Hub port status change */
+#define HUB_PORT_STATUS_C_CONNECTION  (1 << 0)
+#define HUB_PORT_STATUS_C_ENABLE      (1 << 1)
+#define HUB_PORT_STATUS_C_SUSPEND     (1 << 2)
+#define HUB_PORT_STATUS_C_OVERCURRENT (1 << 3)
+#define HUB_PORT_STATUS_C_RESET       (1 << 4)
+#define HUB_PORT_STATUS_C_L1          (1 << 5)
+
+/* Hub characteristics */
+#define HUB_CHAR_LPSM_SHIFT      (0) /* Bits 0-1: Logical Power Switching Mode */
+#define HUB_CHAR_LPSM_MASK       (3 << HUB_CHAR_LPSM_SHIFT)
+#define HUB_CHAR_LPSM_GANGED     (0 << HUB_CHAR_LPSM_SHIFT)
+#define HUB_CHAR_LPSM_INDIVIDUAL (1 << HUB_CHAR_LPSM_SHIFT)
+#define HUB_CHAR_COMPOUND        (1 << 2) /* Bit 2: Compound device */
+#define HUB_CHAR_OCPM_SHIFT      (3)      /* Bits 3-4: Over-current Protection Mode */
+#define HUB_CHAR_OCPM_MASK       (3 << HUB_CHAR_OCPM_SHIFT)
+#define HUB_CHAR_OCPM_GLOBAL     (0 << HUB_CHAR_OCPM_SHIFT)
+#define HUB_CHAR_OCPM_INDIVIDUAL (1 << HUB_CHAR_OCPM_SHIFT)
+#define HUB_CHAR_TTTT_SHIFT      (5) /* Bits 5-6: TT Think Time */
+#define HUB_CHAR_TTTT_MASK       (3 << HUB_CHAR_TTTT_SHIFT)
+#define HUB_CHAR_TTTT_8_BITS     (0 << HUB_CHAR_TTTT_SHIFT)
+#define HUB_CHAR_TTTT_16_BITS    (1 << HUB_CHAR_TTTT_SHIFT)
+#define HUB_CHAR_TTTT_24_BITS    (2 << HUB_CHAR_TTTT_SHIFT)
+#define HUB_CHAR_TTTT_32_BITS    (3 << HUB_CHAR_TTTT_SHIFT)
+#define HUB_CHAR_PORTIND         (1 << 7) /* Bit 7: Port Indicators Supported */
+
+/* Hub descriptor */
+struct usb_hub_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bNbrPorts;
+    uint16_t wHubCharacteristics;
+    uint8_t bPwrOn2PwrGood;
+    uint8_t bHubContrCurrent;
+    uint8_t DeviceRemovable;
+    uint8_t PortPwrCtrlMask;
+} __PACKED;
+
+#define USB_SIZEOF_HUB_DESC 9
+
+/* Hub status */
+struct hub_status {
+    uint16_t wPortStatus;
+    uint16_t wPortChange;
+};
+
+/* Hub port status */
+struct hub_port_status {
+    uint16_t wPortStatus;
+    uint16_t wPortChange;
+};
+
+#endif /* USB_HUB_H */

+ 711 - 0
components/drivers/usb/cherryusb/class/hub/usbh_hub.c

@@ -0,0 +1,711 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_hub.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "usbh_hub"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/hub%d"
+
+#define HUB_DEBOUNCE_TIMEOUT   1500
+#define HUB_DEBOUNCE_STEP      25
+#define HUB_DEBOUNCE_STABLE    100
+#define DELAY_TIME_AFTER_RESET 200
+
+#define EXTHUB_FIRST_INDEX 2
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_buf[CONFIG_USBHOST_MAX_BUS][USB_ALIGN_UP(32, CONFIG_USB_ALIGN_SIZE)];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hub_intbuf[CONFIG_USBHOST_MAX_BUS][CONFIG_USBHOST_MAX_EXTHUBS + 1][USB_ALIGN_UP(1, CONFIG_USB_ALIGN_SIZE)];
+
+extern int usbh_enumerate(struct usbh_hubport *hport);
+extern void usbh_hubport_release(struct usbh_hubport *hport);
+
+static const char *speed_table[] = { "error-speed", "low-speed", "full-speed", "high-speed", "wireless-speed", "super-speed", "superplus-speed" };
+
+#ifdef CONFIG_USBHOST_XHCI
+struct usbh_hubport *usbh_get_roothub_port(unsigned int port)
+{
+    return &roothub.child[port - 1];
+}
+#endif
+
+#if CONFIG_USBHOST_MAX_EXTHUBS > 0
+static struct usbh_hub g_hub_class[CONFIG_USBHOST_MAX_EXTHUBS];
+static uint32_t g_devinuse = 0;
+
+static struct usbh_hub *usbh_hub_class_alloc(void)
+{
+    int devno;
+
+    for (devno = 0; devno < CONFIG_USBHOST_MAX_EXTHUBS; devno++) {
+        if ((g_devinuse & (1 << devno)) == 0) {
+            g_devinuse |= (1 << devno);
+            memset(&g_hub_class[devno], 0, sizeof(struct usbh_hub));
+            g_hub_class[devno].index = EXTHUB_FIRST_INDEX + devno;
+            return &g_hub_class[devno];
+        }
+    }
+    return NULL;
+}
+
+static void usbh_hub_class_free(struct usbh_hub *hub_class)
+{
+    int devno = hub_class->index - EXTHUB_FIRST_INDEX;
+
+    if (devno >= 0 && devno < 32) {
+        g_devinuse &= ~(1 << devno);
+    }
+    memset(hub_class, 0, sizeof(struct usbh_hub));
+}
+#endif
+
+#if CONFIG_USBHOST_MAX_EXTHUBS > 0
+static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
+{
+    struct usb_setup_packet *setup;
+    int ret;
+
+    setup = hub->parent->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
+
+    /* TODO: hub descriptor has some difference between USB 2.0 and USB 3.x,
+       and we havn't handle the difference here */
+    if ((hub->parent->speed == USB_SPEED_SUPER) ||
+        (hub->parent->speed == USB_SPEED_SUPER_PLUS)) {
+        setup->wValue = HUB_DESCRIPTOR_TYPE_HUB3 << 8;
+    } else {
+        setup->wValue = HUB_DESCRIPTOR_TYPE_HUB << 8;
+    }
+
+    setup->wIndex = 0;
+    setup->wLength = USB_SIZEOF_HUB_DESC;
+
+    ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
+    if (ret < 0) {
+        return ret;
+    }
+    memcpy(buffer, g_hub_buf[hub->bus->busid], USB_SIZEOF_HUB_DESC);
+    return ret;
+}
+#if 0
+static int _usbh_hub_get_status(struct usbh_hub *hub, uint8_t *buffer)
+{
+    struct usb_setup_packet *setup;
+    int ret;
+
+    setup = hub->parent->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = HUB_REQUEST_GET_STATUS;
+    setup->wValue = 0;
+    setup->wIndex = 0;
+    setup->wLength = 2;
+
+    ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
+    if (ret < 0) {
+        return ret;
+    }
+    memcpy(buffer, g_hub_buf[hub->bus->busid], 2);
+    return ret;
+}
+#endif
+#endif
+
+static int _usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
+{
+    struct usb_setup_packet *setup;
+    int ret;
+
+    setup = hub->parent->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
+    setup->bRequest = HUB_REQUEST_GET_STATUS;
+    setup->wValue = 0;
+    setup->wIndex = port;
+    setup->wLength = 4;
+
+    ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
+    if (ret < 0) {
+        return ret;
+    }
+    memcpy(port_status, g_hub_buf[hub->bus->busid], 4);
+    return ret;
+}
+
+static int _usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
+{
+    struct usb_setup_packet *setup;
+
+    setup = hub->parent->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
+    setup->bRequest = HUB_REQUEST_SET_FEATURE;
+    setup->wValue = feature;
+    setup->wIndex = port;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(hub->parent, setup, NULL);
+}
+
+static int _usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
+{
+    struct usb_setup_packet *setup;
+
+    setup = hub->parent->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
+    setup->bRequest = HUB_REQUEST_CLEAR_FEATURE;
+    setup->wValue = feature;
+    setup->wIndex = port;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(hub->parent, setup, NULL);
+}
+
+static int _usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
+{
+    struct usb_setup_packet *setup;
+
+    setup = hub->parent->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = HUB_REQUEST_SET_HUB_DEPTH;
+    setup->wValue = depth;
+    setup->wIndex = 0;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(hub->parent, setup, NULL);
+}
+
+#if CONFIG_USBHOST_MAX_EXTHUBS > 0
+static int parse_hub_descriptor(struct usb_hub_descriptor *desc, uint16_t length)
+{
+    if (desc->bLength != USB_SIZEOF_HUB_DESC) {
+        USB_LOG_ERR("invalid device bLength 0x%02x\r\n", desc->bLength);
+        return -1;
+    } else if (desc->bDescriptorType != HUB_DESCRIPTOR_TYPE_HUB) {
+        USB_LOG_ERR("unexpected descriptor 0x%02x\r\n", desc->bDescriptorType);
+        return -2;
+    } else {
+        USB_LOG_RAW("Hub Descriptor:\r\n");
+        USB_LOG_RAW("bLength: 0x%02x             \r\n", desc->bLength);
+        USB_LOG_RAW("bDescriptorType: 0x%02x     \r\n", desc->bDescriptorType);
+        USB_LOG_RAW("bNbrPorts: 0x%02x           \r\n", desc->bNbrPorts);
+        USB_LOG_RAW("wHubCharacteristics: 0x%04x \r\n", desc->wHubCharacteristics);
+        USB_LOG_RAW("bPwrOn2PwrGood: 0x%02x      \r\n", desc->bPwrOn2PwrGood);
+        USB_LOG_RAW("bHubContrCurrent: 0x%02x    \r\n", desc->bHubContrCurrent);
+        USB_LOG_RAW("DeviceRemovable: 0x%02x     \r\n", desc->DeviceRemovable);
+        USB_LOG_RAW("PortPwrCtrlMask: 0x%02x     \r\n", desc->PortPwrCtrlMask);
+    }
+    return 0;
+}
+#endif
+
+static int usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
+{
+    struct usb_setup_packet roothub_setup;
+    struct usb_setup_packet *setup;
+
+    if (hub->is_roothub) {
+        setup = &roothub_setup;
+        setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
+        setup->bRequest = HUB_REQUEST_GET_STATUS;
+        setup->wValue = 0;
+        setup->wIndex = port;
+        setup->wLength = 4;
+        return usbh_roothub_control(hub->bus, &roothub_setup, (uint8_t *)port_status);
+    } else {
+        return _usbh_hub_get_portstatus(hub, port, port_status);
+    }
+}
+
+int usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
+{
+    struct usb_setup_packet roothub_setup;
+    struct usb_setup_packet *setup;
+
+    if (hub->is_roothub) {
+        setup = &roothub_setup;
+        setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
+        setup->bRequest = HUB_REQUEST_SET_FEATURE;
+        setup->wValue = feature;
+        setup->wIndex = port;
+        setup->wLength = 0;
+        return usbh_roothub_control(hub->bus, setup, NULL);
+    } else {
+        return _usbh_hub_set_feature(hub, port, feature);
+    }
+}
+
+int usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
+{
+    struct usb_setup_packet roothub_setup;
+    struct usb_setup_packet *setup;
+
+    if (hub->is_roothub) {
+        setup = &roothub_setup;
+        setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_OTHER;
+        setup->bRequest = HUB_REQUEST_CLEAR_FEATURE;
+        setup->wValue = feature;
+        setup->wIndex = port;
+        setup->wLength = 0;
+        return usbh_roothub_control(hub->bus, setup, NULL);
+    } else {
+        return _usbh_hub_clear_feature(hub, port, feature);
+    }
+}
+
+static int usbh_hub_set_depth(struct usbh_hub *hub, uint16_t depth)
+{
+    struct usb_setup_packet roothub_setup;
+    struct usb_setup_packet *setup;
+
+    if (hub->is_roothub) {
+        setup = &roothub_setup;
+        setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
+        setup->bRequest = HUB_REQUEST_SET_HUB_DEPTH;
+        setup->wValue = depth;
+        setup->wIndex = 0;
+        setup->wLength = 0;
+        return usbh_roothub_control(hub->bus, setup, NULL);
+    } else {
+        return _usbh_hub_set_depth(hub, depth);
+    }
+}
+
+#if CONFIG_USBHOST_MAX_EXTHUBS > 0
+static void hub_int_complete_callback(void *arg, int nbytes)
+{
+    struct usbh_hub *hub = (struct usbh_hub *)arg;
+
+    if (nbytes > 0) {
+        usbh_hub_thread_wakeup(hub);
+    } else if (nbytes == -USB_ERR_NAK) {
+        /* Restart timer to submit urb again */
+        USB_LOG_DBG("Restart timer\r\n");
+        usb_osal_timer_start(hub->int_timer);
+    } else {
+    }
+}
+
+static void hub_int_timeout(void *arg)
+{
+    struct usbh_hub *hub = (struct usbh_hub *)arg;
+
+    usbh_int_urb_fill(&hub->intin_urb, hub->parent, hub->intin, hub->int_buffer, 1, 0, hub_int_complete_callback, hub);
+    usbh_submit_urb(&hub->intin_urb);
+}
+
+static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    struct hub_port_status port_status;
+    int ret;
+
+    struct usbh_hub *hub = usbh_hub_class_alloc();
+    if (hub == NULL) {
+        USB_LOG_ERR("Fail to alloc hub_class\r\n");
+        return -USB_ERR_NOMEM;
+    }
+
+    hub->hub_addr = hport->dev_addr;
+    hub->parent = hport;
+    hub->bus = hport->bus;
+
+    hport->config.intf[intf].priv = hub;
+
+    ret = _usbh_hub_get_hub_descriptor(hub, (uint8_t *)&hub->hub_desc);
+    if (ret < 0) {
+        return ret;
+    }
+
+    parse_hub_descriptor(&hub->hub_desc, USB_SIZEOF_HUB_DESC);
+
+    for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+        hub->child[port].port = port + 1;
+        hub->child[port].parent = hub;
+        hub->child[port].bus = hport->bus;
+    }
+
+    ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
+    if (ep_desc->bEndpointAddress & 0x80) {
+        USBH_EP_INIT(hub->intin, ep_desc);
+    } else {
+        return -1;
+    }
+
+    if (hport->speed == USB_SPEED_SUPER) {
+        uint16_t depth = 0;
+        struct usbh_hubport *parent = hport->parent->parent;
+        while (parent) {
+            depth++;
+            parent = parent->parent->parent;
+        }
+
+        ret = usbh_hub_set_depth(hub, depth);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+        ret = usbh_hub_set_feature(hub, port + 1, HUB_PORT_FEATURE_POWER);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+        ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
+        USB_LOG_INFO("port %u, status:0x%02x, change:0x%02x\r\n", port + 1, port_status.wPortStatus, port_status.wPortChange);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    hub->connected = true;
+    snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, hub->index);
+
+    usb_slist_add_tail(&hub->bus->hub_list, &hub->list);
+
+    USB_LOG_INFO("Register HUB Class:%s\r\n", hport->config.intf[intf].devname);
+
+    hub->int_buffer = g_hub_intbuf[hub->bus->busid][hub->index - 1];
+
+    hub->int_timer = usb_osal_timer_create("hubint_tim", USBH_GET_URB_INTERVAL(hub->intin->bInterval, hport->speed), hub_int_timeout, hub, 0);
+    if (hub->int_timer == NULL) {
+        USB_LOG_ERR("No memory to alloc int_timer\r\n");
+        return -USB_ERR_NOMEM;
+    }
+    usb_osal_timer_start(hub->int_timer);
+    return 0;
+}
+
+static int usbh_hub_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usbh_hubport *child;
+    int ret = 0;
+
+    struct usbh_hub *hub = (struct usbh_hub *)hport->config.intf[intf].priv;
+
+    if (hub) {
+        if (hub->intin) {
+            usbh_kill_urb(&hub->intin_urb);
+        }
+
+        if (hub->int_timer) {
+            usb_osal_timer_delete(hub->int_timer);
+        }
+
+        for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+            child = &hub->child[port];
+            usbh_hubport_release(child);
+            child->parent = NULL;
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister HUB Class:%s\r\n", hport->config.intf[intf].devname);
+            usb_slist_remove(&hub->bus->hub_list, &hub->list);
+        }
+
+        usbh_hub_class_free(hub);
+    }
+    return ret;
+}
+#endif
+
+static void usbh_hubport_enumerate_thread(void *argument)
+{
+    struct usbh_hubport *child = (struct usbh_hubport *)argument;
+
+    if (usbh_enumerate(child) < 0) {
+        /** release child sources */
+        usbh_hubport_release(child);
+        USB_LOG_ERR("Port %u enumerate fail\r\n", child->port);
+    }
+    usb_osal_thread_delete(NULL);
+}
+
+static void usbh_hub_events(struct usbh_hub *hub)
+{
+    struct usbh_hubport *child;
+    struct hub_port_status port_status;
+    uint8_t portchange_index;
+    uint16_t portstatus;
+    uint16_t portchange;
+    uint16_t mask;
+    uint16_t feat;
+    uint8_t speed;
+    int ret;
+
+    if (!hub->connected) {
+        return;
+    }
+
+    portchange_index = hub->int_buffer[0];
+    hub->int_buffer[0] &= ~portchange_index;
+
+    for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+        USB_LOG_DBG("Port change:0x%02x\r\n", portchange_index);
+
+        if (!(portchange_index & (1 << (port + 1)))) {
+            continue;
+        }
+        portchange_index &= ~(1 << (port + 1));
+        USB_LOG_DBG("Port %d change\r\n", port + 1);
+
+        /* Read hub port status */
+        ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
+        if (ret < 0) {
+            USB_LOG_ERR("Failed to read port %u status, errorcode: %d\r\n", port + 1, ret);
+            continue;
+        }
+
+        portstatus = port_status.wPortStatus;
+        portchange = port_status.wPortChange;
+
+        USB_LOG_DBG("port %u, status:0x%02x, change:0x%02x\r\n", port + 1, portstatus, portchange);
+
+        /* First, clear all change bits */
+        mask = 1;
+        feat = HUB_PORT_FEATURE_C_CONNECTION;
+        while (portchange) {
+            if (portchange & mask) {
+                ret = usbh_hub_clear_feature(hub, port + 1, feat);
+                if (ret < 0) {
+                    USB_LOG_ERR("Failed to clear port %u, change mask:%04x, errorcode:%d\r\n", port + 1, mask, ret);
+                    continue;
+                }
+                portchange &= (~mask);
+            }
+            mask <<= 1;
+            feat++;
+        }
+
+        portchange = port_status.wPortChange;
+
+        /* Second, if port changes, debounces first */
+        if (portchange & HUB_PORT_STATUS_C_CONNECTION) {
+            uint16_t connection = 0;
+            uint16_t debouncestable = 0;
+            for (uint32_t debouncetime = 0; debouncetime < HUB_DEBOUNCE_TIMEOUT; debouncetime += HUB_DEBOUNCE_STEP) {
+                /* Read hub port status */
+                ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
+                if (ret < 0) {
+                    USB_LOG_ERR("Failed to read port %u status, errorcode: %d\r\n", port + 1, ret);
+                    continue;
+                }
+
+                portstatus = port_status.wPortStatus;
+                portchange = port_status.wPortChange;
+
+                USB_LOG_DBG("Port %u, status:0x%02x, change:0x%02x\r\n", port + 1, portstatus, portchange);
+
+                if (!(portchange & HUB_PORT_STATUS_C_CONNECTION) &&
+                    ((portstatus & HUB_PORT_STATUS_CONNECTION) == connection)) {
+                    debouncestable += HUB_DEBOUNCE_STEP;
+                    if (debouncestable >= HUB_DEBOUNCE_STABLE) {
+                        break;
+                    }
+                } else {
+                    debouncestable = 0;
+                    connection = portstatus & HUB_PORT_STATUS_CONNECTION;
+                }
+
+                if (portchange & HUB_PORT_STATUS_C_CONNECTION) {
+                    usbh_hub_clear_feature(hub, port + 1, HUB_PORT_FEATURE_C_CONNECTION);
+                }
+
+                usb_osal_msleep(HUB_DEBOUNCE_STEP);
+            }
+
+            /** check if debounce ok */
+            if (debouncestable < HUB_DEBOUNCE_STABLE) {
+                USB_LOG_ERR("Failed to debounce port %u\r\n", port + 1);
+                break;
+            }
+
+            /* Last, check connect status */
+            if (portstatus & HUB_PORT_STATUS_CONNECTION) {
+                ret = usbh_hub_set_feature(hub, port + 1, HUB_PORT_FEATURE_RESET);
+                if (ret < 0) {
+                    USB_LOG_ERR("Failed to reset port %u,errorcode:%d\r\n", port, ret);
+                    continue;
+                }
+
+                usb_osal_msleep(DELAY_TIME_AFTER_RESET);
+                /* Read hub port status */
+                ret = usbh_hub_get_portstatus(hub, port + 1, &port_status);
+                if (ret < 0) {
+                    USB_LOG_ERR("Failed to read port %u status, errorcode: %d\r\n", port + 1, ret);
+                    continue;
+                }
+
+                portstatus = port_status.wPortStatus;
+                portchange = port_status.wPortChange;
+                if (!(portstatus & HUB_PORT_STATUS_RESET) && (portstatus & HUB_PORT_STATUS_ENABLE)) {
+                    if (portchange & HUB_PORT_STATUS_C_RESET) {
+                        ret = usbh_hub_clear_feature(hub, port + 1, HUB_PORT_FEATURE_C_RESET);
+                        if (ret < 0) {
+                            USB_LOG_ERR("Failed to clear port %u reset change, errorcode: %d\r\n", port, ret);
+                        }
+                    }
+
+                    if (portstatus & HUB_PORT_STATUS_HIGH_SPEED) {
+                        speed = USB_SPEED_HIGH;
+                    } else if (portstatus & HUB_PORT_STATUS_LOW_SPEED) {
+                        speed = USB_SPEED_LOW;
+                    }
+#ifdef CONFIG_USBHOST_XHCI
+                    else {
+                        extern uint8_t usbh_get_port_speed(struct usbh_hub * hub, const uint8_t port);
+
+                        /* USB3.0 speed cannot get from portstatus, checkout port speed instead */
+                        uint8_t super_speed = usbh_get_port_speed(hub, port + 1);
+                        if (super_speed > USB_SPEED_HIGH) {
+                            /* assert that when using USB 3.0 ports, attached device must also be USB 3.0 speed */
+                            speed = super_speed;
+                        } else {
+                            speed = USB_SPEED_FULL;
+                        }
+                    }
+#else
+                    else {
+                        speed = USB_SPEED_FULL;
+                    }
+#endif
+
+                    child = &hub->child[port];
+                    /** release child sources first */
+                    usbh_hubport_release(child);
+
+                    memset(child, 0, sizeof(struct usbh_hubport));
+                    child->parent = hub;
+                    child->connected = true;
+                    child->port = port + 1;
+                    child->speed = speed;
+                    child->bus = hub->bus;
+                    child->mutex = usb_osal_mutex_create();
+
+                    USB_LOG_INFO("New %s device on Bus %u, Hub %u, Port %u connected\r\n", speed_table[speed], hub->bus->busid, hub->index, port + 1);
+
+                    /* create disposable thread to enumerate device on current hport, do not block hub thread */
+                    usb_osal_thread_create("usbh_enum", CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO + 1, usbh_hubport_enumerate_thread, (void *)child);
+                } else {
+                    child = &hub->child[port];
+                    /** release child sources */
+                    usbh_hubport_release(child);
+
+                    /** some USB 3.0 ip may failed to enable USB 2.0 port for USB 3.0 device */
+                    USB_LOG_WRN("Failed to enable port %u\r\n", port + 1);
+
+                    continue;
+                }
+            } else {
+                child = &hub->child[port];
+                /** release child sources */
+                usbh_hubport_release(child);
+                USB_LOG_INFO("Device on Bus %u, Hub %u, Port %u disconnected\r\n", hub->bus->busid, hub->index, port + 1);
+            }
+        }
+    }
+
+    /* Start next hub int transfer */
+    if (!hub->is_roothub && hub->connected) {
+        usb_osal_timer_start(hub->int_timer);
+    }
+}
+
+static void usbh_hub_thread(void *argument)
+{
+    struct usbh_hub *hub;
+    int ret = 0;
+
+    struct usbh_bus *bus = (struct usbh_bus *)argument;
+
+    usb_hc_init(bus);
+    while (1) {
+        ret = usb_osal_mq_recv(bus->hub_mq, (uintptr_t *)&hub, USB_OSAL_WAITING_FOREVER);
+        if (ret < 0) {
+            continue;
+        }
+        usbh_hub_events(hub);
+    }
+}
+
+void usbh_hub_thread_wakeup(struct usbh_hub *hub)
+{
+    usb_osal_mq_send(hub->bus->hub_mq, (uintptr_t)hub);
+}
+
+int usbh_hub_initialize(struct usbh_bus *bus)
+{
+    char thread_name[32] = { 0 };
+
+    bus->hub_mq = usb_osal_mq_create(7);
+    if (bus->hub_mq == NULL) {
+        USB_LOG_ERR("Failed to create hub mq\r\n");
+        return -1;
+    }
+
+    snprintf(thread_name, 32, "usbh_hub%u", bus->busid);
+    bus->hub_thread = usb_osal_thread_create(thread_name, CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO, usbh_hub_thread, bus);
+    if (bus->hub_thread == NULL) {
+        USB_LOG_ERR("Failed to create hub thread\r\n");
+        return -1;
+    }
+    return 0;
+}
+
+int usbh_hub_deinitialize(struct usbh_bus *bus)
+{
+    usb_slist_t *hub_list;
+    struct usbh_hubport *hport;
+    size_t flags;
+
+    flags = usb_osal_enter_critical_section();
+
+    usb_slist_for_each(hub_list, &bus->hub_list)
+    {
+        struct usbh_hub *hub = usb_slist_entry(hub_list, struct usbh_hub, list);
+
+        for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
+            hport = &hub->child[port];
+
+            usbh_hubport_release(hport);
+        }
+    }
+
+    usb_hc_deinit(bus);
+
+    usb_osal_leave_critical_section(flags);
+
+    usb_osal_mq_delete(bus->hub_mq);
+    usb_osal_thread_delete(bus->hub_thread);
+
+    return 0;
+}
+
+#if CONFIG_USBHOST_MAX_EXTHUBS > 0
+const struct usbh_class_driver hub_class_driver = {
+    .driver_name = "hub",
+    .connect = usbh_hub_connect,
+    .disconnect = usbh_hub_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info hub_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS,
+    .class = USB_DEVICE_CLASS_HUB,
+    .subclass = 0,
+    .protocol = 0,
+    .id_table = NULL,
+    .class_driver = &hub_class_driver
+};
+#endif

+ 33 - 0
components/drivers/usb/cherryusb/class/hub/usbh_hub.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_HUB_H
+#define USBH_HUB_H
+
+#include "usb_hub.h"
+
+struct usbh_hub;
+
+#define USBH_HUB_MAX_PORTS 4
+/* Maximum size of an interrupt IN transfer */
+#define USBH_HUB_INTIN_BUFSIZE ((USBH_HUB_MAX_PORTS + 8) >> 3)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature);
+int usbh_hub_clear_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature);
+
+void usbh_hub_thread_wakeup(struct usbh_hub *hub);
+
+int usbh_hub_initialize(struct usbh_bus *bus);
+int usbh_hub_deinitialize(struct usbh_bus *bus);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_HUB_H */

+ 240 - 0
components/drivers/usb/cherryusb/class/midi/usb_midi.h

@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_MIDI_H
+#define USB_MIDI_H
+
+/* bDescriptorSubType */
+#define MIDI_VC_HEADER_DESCRIPTOR_SUBTYPE     0x01U
+#define MIDI_MS_HEADER_DESCRIPTOR_SUBTYPE     0x01U
+#define MIDI_MS_GENERAL_DESCRIPTOR_SUBTYPE    0x01U
+#define MIDI_MIDI_IN_JACK_DESCRIPTOR_SUBTYPE  0x02U
+#define MIDI_MIDI_OUT_JACK_DESCRIPTOR_SUBTYPE 0x03U
+
+/* bJackType */
+#define MIDI_JACK_TYPE_EMBEDDED 0x01
+#define MIDI_JACK_TYPE_EXTERNAL 0x02
+
+#define MIDI_CHANNEL_OMNI 0
+#define MIDI_CHANNEL_OFF  17
+
+#define MIDI_PITCHBEND_MIN -8192
+#define MIDI_PITCHBEND_MAX 8191
+
+/*! Enumeration of MIDI code index number */
+enum MidiCodeIndexNumber {
+    MIDI_CIN_MISC              = 0,
+    MIDI_CIN_CABLE_EVENT       = 1,
+    MIDI_CIN_SYSCOM_2BYTE      = 2, ///< 2 byte system common message e.g MTC, SongSelect
+    MIDI_CIN_SYSCOM_3BYTE      = 3, ///< 3 byte system common message e.g SPP
+    MIDI_CIN_SYSEX_START       = 4, ///< SysEx starts or continue
+    MIDI_CIN_SYSEX_END_1BYTE   = 5, ///< SysEx ends with 1 data, or 1 byte system common message
+    MIDI_CIN_SYSEX_END_2BYTE   = 6, ///< SysEx ends with 2 data
+    MIDI_CIN_SYSEX_END_3BYTE   = 7, ///< SysEx ends with 3 data
+    MIDI_CIN_NOTE_OFF          = 8,
+    MIDI_CIN_NOTE_ON           = 9,
+    MIDI_CIN_POLY_KEYPRESS     = 10,
+    MIDI_CIN_CONTROL_CHANGE    = 11,
+    MIDI_CIN_PROGRAM_CHANGE    = 12,
+    MIDI_CIN_CHANNEL_PRESSURE  = 13,
+    MIDI_CIN_PITCH_BEND_CHANGE = 14,
+    MIDI_CIN_1BYTE_DATA        = 15
+};
+
+/*! Enumeration of MIDI types */
+enum MidiType {
+    InvalidType = 0x00,          ///< For notifying errors
+    NoteOff = 0x80,              ///< Note Off
+    NoteOn = 0x90,               ///< Note On
+    AfterTouchPoly = 0xA0,       ///< Polyphonic AfterTouch
+    ControlChange = 0xB0,        ///< Control Change / Channel Mode
+    ProgramChange = 0xC0,        ///< Program Change
+    AfterTouchChannel = 0xD0,    ///< Channel (monophonic) AfterTouch
+    PitchBend = 0xE0,            ///< Pitch Bend
+    SystemExclusive = 0xF0,      ///< System Exclusive
+    TimeCodeQuarterFrame = 0xF1, ///< System Common - MIDI Time Code Quarter Frame
+    SongPosition = 0xF2,         ///< System Common - Song Position Pointer
+    SongSelect = 0xF3,           ///< System Common - Song Select
+    TuneRequest = 0xF6,          ///< System Common - Tune Request
+    Clock = 0xF8,                ///< System Real Time - Timing Clock
+    Start = 0xFA,                ///< System Real Time - Start
+    Continue = 0xFB,             ///< System Real Time - Continue
+    Stop = 0xFC,                 ///< System Real Time - Stop
+    ActiveSensing = 0xFE,        ///< System Real Time - Active Sensing
+    SystemReset = 0xFF,          ///< System Real Time - System Reset
+};
+
+/*! Enumeration of Thru filter modes */
+enum MidiFilterMode {
+    Off = 0,              ///< Thru disabled (nothing passes through).
+    Full = 1,             ///< Fully enabled Thru (every incoming message is sent back).
+    SameChannel = 2,      ///< Only the messages on the Input Channel will be sent back.
+    DifferentChannel = 3, ///< All the messages but the ones on the Input Channel will be sent back.
+};
+
+/*! \brief Enumeration of Control Change command numbers.
+ See the detailed controllers numbers & description here:
+ http://www.somascape.org/midi/tech/spec.html#ctrlnums
+ */
+enum MidiControlChangeNumber {
+    // High resolution Continuous Controllers MSB (+32 for LSB) ----------------
+    BankSelect = 0,
+    ModulationWheel = 1,
+    BreathController = 2,
+    // CC3 undefined
+    FootController = 4,
+    PortamentoTime = 5,
+    DataEntry = 6,
+    ChannelVolume = 7,
+    Balance = 8,
+    // CC9 undefined
+    Pan = 10,
+    ExpressionController = 11,
+    EffectControl1 = 12,
+    EffectControl2 = 13,
+    // CC14 undefined
+    // CC15 undefined
+    GeneralPurposeController1 = 16,
+    GeneralPurposeController2 = 17,
+    GeneralPurposeController3 = 18,
+    GeneralPurposeController4 = 19,
+
+    // Switches ----------------------------------------------------------------
+    Sustain = 64,
+    Portamento = 65,
+    Sostenuto = 66,
+    SoftPedal = 67,
+    Legato = 68,
+    Hold = 69,
+
+    // Low resolution continuous controllers -----------------------------------
+    SoundController1 = 70,  ///< Synth: Sound Variation   FX: Exciter On/Off
+    SoundController2 = 71,  ///< Synth: Harmonic Content  FX: Compressor On/Off
+    SoundController3 = 72,  ///< Synth: Release Time      FX: Distortion On/Off
+    SoundController4 = 73,  ///< Synth: Attack Time       FX: EQ On/Off
+    SoundController5 = 74,  ///< Synth: Brightness        FX: Expander On/Off
+    SoundController6 = 75,  ///< Synth: Decay Time        FX: Reverb On/Off
+    SoundController7 = 76,  ///< Synth: Vibrato Rate      FX: Delay On/Off
+    SoundController8 = 77,  ///< Synth: Vibrato Depth     FX: Pitch Transpose On/Off
+    SoundController9 = 78,  ///< Synth: Vibrato Delay     FX: Flange/Chorus On/Off
+    SoundController10 = 79, ///< Synth: Undefined         FX: Special Effects On/Off
+    GeneralPurposeController5 = 80,
+    GeneralPurposeController6 = 81,
+    GeneralPurposeController7 = 82,
+    GeneralPurposeController8 = 83,
+    PortamentoControl = 84,
+    // CC85 to CC90 undefined
+    Effects1 = 91, ///< Reverb send level
+    Effects2 = 92, ///< Tremolo depth
+    Effects3 = 93, ///< Chorus send level
+    Effects4 = 94, ///< Celeste depth
+    Effects5 = 95, ///< Phaser depth
+
+    // Channel Mode messages ---------------------------------------------------
+    AllSoundOff = 120,
+    ResetAllControllers = 121,
+    LocalControl = 122,
+    AllNotesOff = 123,
+    OmniModeOff = 124,
+    OmniModeOn = 125,
+    MonoModeOn = 126,
+    PolyModeOn = 127
+};
+
+struct midi_cs_if_ac_header_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint16_t bcdADC;
+    uint16_t wTotalLength;
+    uint8_t bInCollection;
+    uint8_t baInterfaceNr[];
+} __PACKED;
+
+#define MIDI_SIZEOF_AC_HEADER_DESC(n) (8 + n)
+
+struct midi_cs_if_ms_header_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint16_t bcdMSC;
+    uint16_t wTotalLength;
+} __PACKED;
+
+#define MIDI_SIZEOF_MS_HEADER_DESC (7)
+
+struct midi_cs_if_in_jack_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bJackType;
+    uint8_t bJackId;
+    uint8_t iJack;
+} __PACKED;
+
+#define MIDI_SIZEOF_IN_JACK_DESC (6)
+
+struct midi_cs_if_out_jack_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bJackType;
+    uint8_t bJackId;
+    uint8_t bNrInputPins;
+    uint8_t baSourceId;
+    uint8_t baSourcePin;
+    uint8_t iJack;
+} __PACKED;
+
+#define MIDI_SIZEOF_OUT_JACK_DESC (9)
+
+struct midi_cs_ep_ms_general_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bNumEmbMIDIJack;
+    uint8_t baAssocJackID[];
+} __PACKED;
+
+#define MIDI_SIZEOF_MS_GENERAL_DESC(n) (4 + n)
+
+// clang-format off
+#define MIDI_CS_HEADER_DESCRIPTOR_INIT(wTotalLength)                                              \
+    0x07,                                             /* bLength */                               \
+    USB_CS_DESCRIPTOR_TYPE_INTERFACE,                 /* bDescriptorType */                       \
+    MIDI_MS_HEADER_DESCRIPTOR_SUBTYPE,                /* bDescriptorSubtype */                    \
+    WBVAL(0x0100),                                    /* bcdMSC */                                \
+    WBVAL(wTotalLength)                               /* wTotalLength */
+
+#define MIDI_IN_JACK_DESCRIPTOR_INIT(bJackType, bJackID) \
+    0x06,                                                \
+    0x24,                                                \
+    MIDI_MIDI_IN_JACK_DESCRIPTOR_SUBTYPE,                \
+    bJackType,                                           \
+    bJackID,                                             \
+    0x00
+
+#define MIDI_OUT_JACK_DESCRIPTOR_INIT(bJackType, bJackID, baSourceID) \
+    0x09,                                                             \
+    0x24,                                                             \
+    MIDI_MIDI_OUT_JACK_DESCRIPTOR_SUBTYPE,                            \
+    bJackType,                                                        \
+    bJackID,                                                          \
+    0x01,                                                             \
+    baSourceID,                                                       \
+    0x01,                                                             \
+    0x00
+
+#define MIDI_JACK_DESCRIPTOR_INIT(bJackFirstID)                                                     \
+    MIDI_IN_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EMBEDDED, bJackFirstID),                            \
+    MIDI_IN_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EXTERNAL, (bJackFirstID + 1)),                      \
+    MIDI_OUT_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EMBEDDED, (bJackFirstID + 2), (bJackFirstID + 1)), \
+    MIDI_OUT_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EXTERNAL, (bJackFirstID + 3), (bJackFirstID))
+
+#define MIDI_SIZEOF_JACK_DESC (6 + 6 + 9 + 9)
+
+// clang-format on
+
+#endif /* USB_MIDI_H */

+ 89 - 0
components/drivers/usb/cherryusb/class/msc/usb_msc.h

@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_MSC_H
+#define USB_MSC_H
+
+/* MSC Subclass Codes */
+#define MSC_SUBCLASS_RBC           0x01 /* Reduced block commands (e.g., flash devices) */
+#define MSC_SUBCLASS_SFF8020I_MMC2 0x02 /* SFF-8020i/MMC-2 (ATAPI) (e.g., C/DVD) */
+#define MSC_SUBCLASS_QIC157        0x03 /* QIC-157 (e.g., tape device) */
+#define MSC_SUBCLASS_UFI           0x04 /* e.g. floppy device */
+#define MSC_SUBCLASS_SFF8070I      0x05 /* SFF-8070i (e.g. floppy disk) */
+#define MSC_SUBCLASS_SCSI          0x06 /* SCSI transparent */
+
+/* MSC Protocol Codes */
+#define MSC_PROTOCOL_CBI_INT   0x00 /* CBI transport with command completion interrupt */
+#define MSC_PROTOCOL_CBI_NOINT 0x01 /* CBI transport without command completion interrupt */
+#define MSC_PROTOCOL_BULK_ONLY 0x50 /* Bulk only transport */
+
+/* MSC Request Codes */
+#define MSC_REQUEST_RESET       0xFF
+#define MSC_REQUEST_GET_MAX_LUN 0xFE
+
+/** MSC Command Block Wrapper (CBW) Signature */
+#define MSC_CBW_Signature 0x43425355
+/** Bulk-only Command Status Wrapper (CSW) Signature */
+#define MSC_CSW_Signature 0x53425355
+
+/** MSC Command Block Status Values */
+#define CSW_STATUS_CMD_PASSED  0x00
+#define CSW_STATUS_CMD_FAILED  0x01
+#define CSW_STATUS_PHASE_ERROR 0x02
+
+#define MSC_MAX_CDB_LEN (16) /* Max length of SCSI Command Data Block */
+
+/** MSC Bulk-Only Command Block Wrapper (CBW) */
+struct CBW {
+    uint32_t dSignature;         /* 'USBC' = 0x43425355 */
+    uint32_t dTag;               /* Depends on command id */
+    uint32_t dDataLength;        /* Number of bytes that host expects to transfer */
+    uint8_t bmFlags;             /* Bit 7: Direction=IN (other obsolete or reserved) */
+    uint8_t bLUN;                /* LUN (normally 0) */
+    uint8_t bCBLength;           /* len of cdb[] */
+    uint8_t CB[MSC_MAX_CDB_LEN]; /* Command Data Block */
+} __PACKED;
+
+#define USB_SIZEOF_MSC_CBW 31
+
+/** MSC Bulk-Only Command Status Wrapper (CSW) */
+struct CSW {
+    uint32_t dSignature;   /* 'USBS' = 0x53425355 */
+    uint32_t dTag;         /* Same tag as original command */
+    uint32_t dDataResidue; /* Amount not transferred */
+    uint8_t bStatus;       /* Status of transfer */
+} __PACKED;
+
+#define USB_SIZEOF_MSC_CSW 13
+
+/*Length of template descriptor: 23 bytes*/
+#define MSC_DESCRIPTOR_LEN (9 + 7 + 7)
+// clang-format off
+#define MSC_DESCRIPTOR_INIT(bFirstInterface, out_ep, in_ep, wMaxPacketSize, str_idx) \
+    /* Interface */                                              \
+    0x09,                          /* bLength */                 \
+    USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */         \
+    bFirstInterface,               /* bInterfaceNumber */        \
+    0x00,                          /* bAlternateSetting */       \
+    0x02,                          /* bNumEndpoints */           \
+    USB_DEVICE_CLASS_MASS_STORAGE, /* bInterfaceClass */         \
+    MSC_SUBCLASS_SCSI,             /* bInterfaceSubClass */      \
+    MSC_PROTOCOL_BULK_ONLY,        /* bInterfaceProtocol */      \
+    str_idx,                       /* iInterface */              \
+    0x07,                          /* bLength */                 \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,  /* bDescriptorType */         \
+    out_ep,                        /* bEndpointAddress */        \
+    0x02,                          /* bmAttributes */            \
+    WBVAL(wMaxPacketSize),         /* wMaxPacketSize */          \
+    0x00,                          /* bInterval */               \
+    0x07,                          /* bLength */                 \
+    USB_DESCRIPTOR_TYPE_ENDPOINT,  /* bDescriptorType */         \
+    in_ep,                         /* bEndpointAddress */        \
+    0x02,                          /* bmAttributes */            \
+    WBVAL(wMaxPacketSize),         /* wMaxPacketSize */          \
+    0x00                           /* bInterval */
+// clang-format on
+
+#endif /* USB_MSC_H */

+ 972 - 0
components/drivers/usb/cherryusb/class/msc/usb_scsi.h

@@ -0,0 +1,972 @@
+/*
+ * Apache NuttX
+ * Copyright 2020 The Apache Software Foundation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef __INCLUDE_NUTTX_SCSI_H
+#define __INCLUDE_NUTTX_SCSI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* SCSI commands ************************************************************/
+
+#define SCSI_CMD_TESTUNITREADY                   0x00
+#define SCSI_CMD_REZEROUNIT                      0x01
+#define SCSI_CMD_REQUESTSENSE                    0x03
+#define SCSI_CMD_FORMAT_UNIT                     0x04
+#define SCSI_CMD_REASSIGNBLOCKS                  0x07
+#define SCSI_CMD_READ6                           0x08
+#define SCSI_CMD_WRITE6                          0x0a
+#define SCSI_CMD_SEEK6                           0x0b
+#define SCSI_CMD_SPACE6                          0x11
+#define SCSI_CMD_INQUIRY                         0x12
+#define SCSI_CMD_MODESELECT6                     0x15
+#define SCSI_CMD_RESERVE6                        0x16
+#define SCSI_CMD_RELEASE6                        0x17
+#define SCSI_CMD_COPY                            0x18
+#define SCSI_CMD_MODESENSE6                      0x1a
+#define SCSI_CMD_STARTSTOPUNIT                   0x1b
+#define SCSI_CMD_RECEIVEDIAGNOSTICRESULTS        0x1c
+#define SCSI_CMD_SENDDIAGNOSTIC                  0x1d
+#define SCSI_CMD_PREVENTMEDIAREMOVAL             0x1e
+#define SCSI_CMD_READFORMATCAPACITIES            0x23
+#define SCSI_CMD_READCAPACITY10                  0x25
+#define SCSI_CMD_READ10                          0x28
+#define SCSI_CMD_WRITE10                         0x2a
+#define SCSI_CMD_SEEK10                          0x2b
+#define SCSI_CMD_WRITEANDVERIFY                  0x2e
+#define SCSI_CMD_VERIFY10                        0x2f
+#define SCSI_CMD_SEARCHDATAHIGH                  0x30
+#define SCSI_CMD_SEARCHDATAEQUAL                 0x31
+#define SCSI_CMD_SEARCHDATALOW                   0x32
+#define SCSI_CMD_SETLIMITS10                     0x33
+#define SCSI_CMD_PREFETCH10                      0x34
+#define SCSI_CMD_SYNCHCACHE10                    0x35
+#define SCSI_CMD_LOCKCACHE                       0x36
+#define SCSI_CMD_READDEFECTDATA10                0x37
+#define SCSI_CMD_COMPARE                         0x39
+#define SCSI_CMD_COPYANDVERIFY                   0x3a
+#define SCSI_CMD_WRITEBUFFER                     0x3b
+#define SCSI_CMD_READBUFFER                      0x3c
+#define SCSI_CMD_READLONG10                      0x3e
+#define SCSI_CMD_WRITELONG10                     0x3f
+#define SCSI_CMD_CHANGEDEFINITION                0x40
+#define SCSI_CMD_WRITESAME10                     0x41
+#define SCSI_CMD_LOGSELECT                       0x4c
+#define SCSI_CMD_LOGSENSE                        0x4d
+#define SCSI_CMD_XDWRITE10                       0x50
+#define SCSI_CMD_XPWRITE10                       0x51
+#define SCSI_CMD_XDREAD10                        0x52
+#define SCSI_CMD_MODESELECT10                    0x55
+#define SCSI_CMD_RESERVE10                       0x56
+#define SCSI_CMD_RELEASE10                       0x57
+#define SCSI_CMD_MODESENSE10                     0x5a
+#define SCSI_CMD_PERSISTENTRESERVEIN             0x5e
+#define SCSI_CMD_PERSISTENTRESERVEOUT            0x5f
+#define SCSI_CMD_32                              0x7f
+#define SCSI_CMD_XDWRITEEXTENDED                 0x80
+#define SCSI_CMD_REBUILD                         0x82
+#define SCSI_CMD_REGENERATE                      0x82
+#define SCSI_CMD_EXTENDEDCOPY                    0x83
+#define SCSI_CMD_COPYRESULTS                     0x84
+#define SCSI_CMD_ACCESSCONTROLIN                 0x86
+#define SCSI_CMD_ACCESSCONTROLOUT                0x87
+#define SCSI_CMD_READ16                          0x88
+#define SCSI_CMD_WRITE16                         0x8a
+#define SCSI_CMD_READATTRIBUTE                   0x8c
+#define SCSI_CMD_WRITEATTRIBUTE                  0x8d
+#define SCSI_CMD_WRITEANDVERIFY16                0x8e
+#define SCSI_CMD_PREFETCH16                      0x90
+#define SCSI_CMD_SYNCHCACHE16                    0x91
+#define SCSI_CMD_LOCKUNLOCKACACHE                0x92
+#define SCSI_CMD_WRITESAME16                     0x93
+#define SCSI_CMD_READCAPACITY16                  0x9e
+#define SCSI_CMD_READLONG16                      0x9e
+#define SCSI_CMD_WRITELONG106                    0x9f
+#define SCSI_CMD_REPORTLUNS                      0xa0
+#define SCSI_CMD_MAINTENANCEIN                   0xa3
+#define SCSI_CMD_MAINTENANCEOUT                  0xa4
+#define SCSI_CMD_MOVEMEDIUM                      0xa5
+#define SCSI_CMD_MOVEMEDIUMATTACHED              0xa7
+#define SCSI_CMD_READ12                          0xa8
+#define SCSI_CMD_WRITE12                         0xaa
+#define SCSI_CMD_READMEDIASERIALNUMBER           0xab
+#define SCSI_CMD_WRITEANDVERIFY12                0xae
+#define SCSI_CMD_VERIFY12                        0xaf
+#define SCSI_CMD_SETLIMITS12                     0xb3
+#define SCSI_CMD_READELEMENTSTATUS               0xb4
+#define SCSI_CMD_READDEFECTDATA12                0xb7
+#define SCSI_CMD_REDUNDANCYGROUPIN               0xba
+#define SCSI_CMD_REDUNDANCYGROUPOUT              0xbb
+#define SCSI_CMD_SPAREIN                         0xbc
+#define SCSI_CMD_SPAREOUT                        0xbd
+#define SCSI_CMD_VOLUMESETIN                     0xbe
+#define SCSI_CMD_VOLUMESETOUT                    0xbf
+
+/* Common SCSI KCQ values (sense Key/additional sense Code/ASC Qualifier) ***
+ *
+ *   0xnn0386  Write Fault Data Corruption
+ *   0xnn0500  Illegal request
+ *   0xnn0600  Unit attention
+ *   0xnn0700  Data protect
+ *   0xnn0800  LUN communication failure
+ *   0xnn0801  LUN communication timeout
+ *   0xnn0802  LUN communication parity error
+ *   0xnn0803  LUN communication CRC error
+ *   0xnn0900  vendor specific sense key
+ *   0xnn0901  servo fault
+ *   0xnn0904  head select fault
+ *   0xnn0a00  error log overflow
+ *   0xnn0b00  aborted command
+ *   0xnn0c00  write error
+ *   0xnn0c02  write error - auto-realloc failed
+ *   0xnn0e00  data miscompare
+ *   0xnn1200  address mark not founf for ID field
+ *   0xnn1400  logical block not found
+ *   0xnn1500  random positioning error
+ *   0xnn1501  mechanical positioning error
+ *   0xnn1502  positioning error detected by read of medium
+ *   0xnn2700  write protected
+ *   0xnn2900  POR or bus reset occurred
+ *   0xnn3101  format failed
+ *   0xnn3191  format corrupted
+ *   0xnn3201  defect list update error
+ *   0xnn3202  no spares available
+ *   0xnn3501  unspecified enclosure services failure
+ *   0xnn3700  parameter rounded
+ *   0xnn3d00  invalid bits in identify message
+ *   0xnn3e00  LUN not self-configured yet
+ *   0xnn4001  DRAM parity error
+ *   0xnn4002  DRAM parity error
+ *   0xnn4200  power-on or self-test failure
+ *   0xnn4c00  LUN failed self-configuration
+ *   0xnn5c00  RPL status change
+ *   0xnn5c01  spindles synchronized
+ *   0xnn5c02  spindles not synchronized
+ *   0xnn6500  voltage fault
+ *   0xnn8000  general firmware error
+ */
+
+/* No sense KCQ values */
+
+#define SCSI_KCQ_NOSENSE                         0x000000  /* No error */
+#define SCSI_KCQ_PFATHRESHOLDREACHED             0x005c00  /* No sense - PFA threshold reached */
+
+/* Soft error KCQ values */
+
+#define SCSI_KCQSE_RWENOINDEX                    0x010100  /* Recovered Write error - no index */
+#define SCSI_KCQSE_RECOVEREDNOSEEKCOMPLETION     0x010200  /* Recovered no seek completion */
+#define SCSI_KCQSE_RWEWRITEFAULT                 0x010300  /* Recovered Write error - write fault */
+#define SCSI_KCQSE_TRACKFOLLOWINGERROR           0x010900  /* Track following error */
+#define SCSI_KCQSE_TEMPERATUREWARNING            0x010b01  /* Temperature warning */
+#define SCSI_KCQSE_RWEWARREALLOCATED             0x010c01  /* Recovered Write error with auto-realloc - reallocated */
+#define SCSI_KCQSE_RWERECOMMENDREASSIGN          0x010c03  /* Recovered Write error - recommend reassign */
+#define SCSI_KCQSE_RDWOEUSINGPREVLBI             0x011201  /* Recovered data without ECC using prev logical block ID */
+#define SCSI_KCQSE_RDWEUSINGPREVLBI              0x011202  /* Recovered data with ECC using prev logical block ID */
+#define SCSI_KCQSE_RECOVEREDRECORDNOTFOUND       0x011401  /* Recovered Record Not Found */
+#define SCSI_KCQSE_RWEDSME                       0x011600  /* Recovered Write error - Data Sync Mark Error */
+#define SCSI_KCQSE_RWEDSEDATAREWRITTEN           0x011601  /* Recovered Write error - Data Sync Error - data rewritten */
+#define SCSI_KCQSE_RWEDSERECOMMENDREWRITE        0x011602  /* Recovered Write error - Data Sync Error - recommend rewrite */
+#define SCSI_KCQSE_RWEDSEDATAAUTOREALLOCATED     0x011603  /* Recovered Write error - Data Sync Error - data auto-reallocated */
+#define SCSI_KCQSE_RWEDSERECOMMENDREASSIGNMENT   0x011604  /* Recovered Write error - Data Sync Error - recommend reassignment */
+#define SCSI_KCQSE_RDWNECORRECTIONAPPLIED        0x011700  /* Recovered data with no error correction applied */
+#define SCSI_KCQSE_RREWITHRETRIES                0x011701  /* Recovered Read error - with retries */
+#define SCSI_KCQSE_RDUSINGPOSITIVEOFFSET         0x011702  /* Recovered data using positive offset */
+#define SCSI_KCQSE_RDUSINGNEGATIVEOFFSET         0x011703  /* Recovered data using negative offset */
+#define SCSI_KCQSE_RDUSINGPREVIOUSLBI            0x011705  /* Recovered data using previous logical block ID */
+#define SCSI_KCQSE_RREWOEAUTOREALLOCATED         0x011706  /* Recovered Read error - without ECC, auto reallocated */
+#define SCSI_KCQSE_RREWOERECOMMENDREASSIGN       0x011707  /* Recovered Read error - without ECC, recommend reassign */
+#define SCSI_KCQSE_RREWOERECOMMENDREWRITE        0x011708  /* Recovered Read error - without ECC, recommend rewrite */
+#define SCSI_KCQSE_RREWOEDATAREWRITTEN           0x011709  /* Recovered Read error - without ECC, data rewritten */
+#define SCSI_KCQSE_RREWE                         0x011800  /* Recovered Read error - with ECC */
+#define SCSI_KCQSE_RDWEANDRETRIES                0x011801  /* Recovered data with ECC and retries */
+#define SCSI_KCQSE_RREWEAUTOREALLOCATED          0x011802  /* Recovered Read error - with ECC, auto reallocated */
+#define SCSI_KCQSE_RREWERECOMMENDREASSIGN        0x011805  /* Recovered Read error - with ECC, recommend reassign */
+#define SCSI_KCQSE_RDUSINGECCANDOFFSETS          0x011806  /* Recovered data using ECC and offsets */
+#define SCSI_KCQSE_RREWEDATAREWRITTEN            0x011807  /* Recovered Read error - with ECC, data rewritten */
+#define SCSI_KCQSE_DLNOTFOUND                    0x011c00  /* Defect List not found */
+#define SCSI_KCQSE_PRIMARYDLNOTFOUND             0x011c01  /* Primary defect list not found */
+#define SCSI_KCQSE_GROWNDLNOTFOUND               0x011c02  /* Grown defect list not found */
+#define SCSI_KCQSE_PARTIALDLTRANSFERRED          0x011f00  /* Partial defect list transferred */
+#define SCSI_KCQSE_INTERNALTARGETFAILURE         0x014400  /* Internal target failure */
+#define SCSI_KCQSE_PFATHRESHOLDREACHED           0x015d00  /* PFA threshold reached */
+#define SCSI_KCQSE_PFATESTWARNING                0x015dff  /* PFA test warning */
+#define SCSI_KCQSE_INTERNALLOGICFAILURE          0x018100  /* Internal logic failure */
+
+/* Not Ready / Diagnostic Failure KCQ values */
+
+#define SCSI_KCQNR_CAUSENOTREPORTABLE            0x020400  /* Not Ready - Cause not reportable. */
+#define SCSI_KCQNR_BECOMINGREADY                 0x020401  /* Not Ready - becoming ready */
+#define SCSI_KCQNR_NEEDINITIALIZECOMMAND         0x020402  /* Not Ready - need initialize command (start unit) */
+#define SCSI_KCQNR_MANUALINTERVENTIONREQUIRED    0x020403  /* Not Ready - manual intervention required */
+#define SCSI_KCQNR_FORMATINPROGRESS              0x020404  /* Not Ready - format in progress */
+#define SCSI_KCQNR_SELFTESTINPROGRESS            0x020409  /* Not Ready - self-test in progress */
+#define SCSI_KCQNR_MEDIUMFORMATCORRUPTED         0x023100  /* Not Ready - medium format corrupted */
+#define SCSI_KCQNR_FORMATCOMMANDFAILED           0x023101  /* Not Ready - format command failed */
+#define SCSI_KCQNR_ESUNAVAILABLE                 0x023502  /* Not Ready - enclosure services unavailable */
+#define SCSI_KCQNR_MEDIANOTPRESENT               0x023a00  /* Not Ready - media not present */
+#define SCSI_KCQDF_BRINGUPFAILORDEGRADEDMODE     0x024080  /* Diagnostic Failure - bring-up fail or degraded mode */
+#define SCSI_KCQDF_HARDDISKCONTROLLER            0x024081  /* Diagnostic Failure - Hard Disk Controller */
+#define SCSI_KCQDF_RAMMICROCODENOTLOADED         0x024085  /* Diagnostic Failure - RAM microcode not loaded */
+#define SCSI_KCQDF_RROCALIBRATION                0x024090  /* Diagnostic Failure - RRO Calibration */
+#define SCSI_KCQDF_CHANNELCALIBRATION            0x024091  /* Diagnostic Failure - Channel Calibration */
+#define SCSI_KCQDF_HEADLOAD                      0x024092  /* Diagnostic Failure - Head Load */
+#define SCSI_KCQDF_WRITEAE                       0x024093  /* Diagnostic Failure - Write AE */
+#define SCSI_KCQDF_12VOVERCURRENT                0x024094  /* Diagnostic Failure - 12V over current */
+#define SCSI_KCQDF_OTHERSPINDLEFAILURE           0x024095  /* Diagnostic Failure - Other spindle failure */
+#define SCSI_KCQDF_SELFRESET                     0x0240b0  /* Diagnostic Failure - self-reset */
+#define SCSI_KCQDF_CONFIGNOTLOADED               0x024c00  /* Diagnostic Failure - config not loaded */
+
+/* Medium error KCQ values */
+
+#define SCSI_KCQME_WRITEFAULT                    0x030300  /* Medium Error - write fault */
+#define SCSI_KCQME_WRITEFAULTAUTOREALLOCFAILED   0x030c02  /* Medium Error - write error - auto-realloc failed */
+#define SCSI_KCQME_WRITERTLIMITEXCEEDED          0x030cbb  /* Medium Error - write recovery time limit exceeded */
+#define SCSI_KCQME_IDCRCERROR                    0x031000  /* Medium Error - ID CRC error */
+#define SCSI_KCQME_UNRRE1                        0x031100  /* Medium Error - unrecovered read error */
+#define SCSI_KCQME_READRETRIESEXHAUSTED          0x031101  /* Medium Error - read retries exhausted */
+#define SCSI_KCQME_ERRORTOOLONGTOCORRECT         0x031102  /* Medium Error - error too long to correct */
+#define SCSI_KCQME_UREAUTOREALLOCFAILED          0x031104  /* Medium Error - unrecovered read error - auto re-alloc failed */
+#define SCSI_KCQME_URERECOMMENDREASSIGN          0x03110b  /* Medium Error - unrecovered read error - recommend reassign */
+#define SCSI_KCQME_READRTLIMITEXCEEDED           0x0311ff  /* Medium Error - read recovery time limit exceeded */
+#define SCSI_KCQME_RECORDNOTFOUND                0x031401  /* Medium Error - record not found */
+#define SCSI_KCQME_DSME                          0x031600  /* Medium Error - Data Sync Mark error */
+#define SCSI_KCQME_DSERECOMMENDREASSIGN          0x031604  /* Medium Error - Data Sync Error - recommend reassign */
+#define SCSI_KCQME_DLE                           0x031900  /* Medium Error - defect list error */
+#define SCSI_KCQME_DLNOTAVAILABLE                0x031901  /* Medium Error - defect list not available */
+#define SCSI_KCQME_DLEINPRIMARYLIST              0x031902  /* Medium Error - defect list error in primary list */
+#define SCSI_KCQME_DLEINGROWNLIST                0x031903  /* Medium Error - defect list error in grown list */
+#define SCSI_KCQME_FEWERTHAN50PCTDLCOPIES        0x03190e  /* Medium Error - fewer than 50% defect list copies */
+#define SCSI_KCQME_MEDIUMFORMATCORRUPTED         0x033100  /* Medium Error - medium format corrupted */
+#define SCSI_KCQME_FORMATCOMMANDFAILED           0x033101  /* Medium Error - format command failed */
+#define SCSI_KCQME_DATAAUTOREALLOCATED           0x038000  /* Medium Error - data auto-reallocated */
+
+/* Hardware Error KCQ values */
+
+#define SCSI_KCQHE_NOINDEXORSECTOR               0x040100  /* Hardware Error - no index or sector */
+#define SCSI_KCQHE_NOSEEKCOMPLETE                0x040200  /* Hardware Error - no seek complete */
+#define SCSI_KCQHE_WRITEFAULT                    0x040300  /* Hardware Error - write fault */
+#define SCSI_KCQHE_COMMUNICATIONFAILURE          0x040800  /* Hardware Error - communication failure */
+#define SCSI_KCQHE_TRACKFOLLOWINGERROR           0x040900  /* Hardware Error - track following error */
+#define SCSI_KCQHE_UREINRESERVEDAREA             0x041100  /* Hardware Error - unrecovered read error in reserved area */
+#define SCSI_KCQHE_DSMEINRESERVEDAREA            0x041600  /* Hardware Error - Data Sync Mark error in reserved area */
+#define SCSI_KCQHE_DLE                           0x041900  /* Hardware Error - defect list error */
+#define SCSI_KCQHE_DLEINPRIMARYLIST              0x041902  /* Hardware Error - defect list error in Primary List */
+#define SCSI_KCQHE_DLEINGROWNLIST                0x041903  /* Hardware Error - defect list error in Grown List */
+#define SCSI_KCQHE_REASSIGNFAILED                0x043100  /* Hardware Error - reassign failed */
+#define SCSI_KCQHE_NODEFECTSPAREAVAILABLE        0x043200  /* Hardware Error - no defect spare available */
+#define SCSI_KCQHE_UNSUPPORTEDENCLOSUREFUNCTION  0x043501  /* Hardware Error - unsupported enclosure function */
+#define SCSI_KCQHE_ESUNAVAILABLE                 0x043502  /* Hardware Error - enclosure services unavailable */
+#define SCSI_KCQHE_ESTRANSFERFAILURE             0x043503  /* Hardware Error - enclosure services transfer failure */
+#define SCSI_KCQHE_ESREFUSED                     0x043504  /* Hardware Error - enclosure services refused */
+#define SCSI_KCQHE_SELFTESTFAILED                0x043e03  /* Hardware Error - self-test failed */
+#define SCSI_KCQHE_UNABLETOUPDATESELFTEST        0x043e04  /* Hardware Error - unable to update self-test */
+#define SCSI_KCQHE_DMDIAGNOSTICFAIL              0x044080  /* Hardware Error - Degrade Mode. Diagnostic Fail */
+#define SCSI_KCQHE_DMHWERROR                     0x044081  /* Hardware Error - Degrade Mode. H/W Error */
+#define SCSI_KCQHE_DMRAMMICROCODENOTLOADED       0x044085  /* Hardware Error - Degrade Mode. RAM microcode not loaded */
+#define SCSI_KCQHE_SEEKTESTFAILURE               0x044090  /* Hardware Error - seek test failure */
+#define SCSI_KCQHE_READWRITETESTFAILURE          0x0440a0  /* Hardware Error - read/write test failure */
+#define SCSI_KCQHE_DEVICESELFRESET               0x0440b0  /* Hardware Error - device self-reset */
+#define SCSI_KCQHE_COMPONENTMISMATCH             0x0440d0  /* Hardware Error - component mismatch */
+#define SCSI_KCQHE_INTERNALTARGETFAILURE         0x044400  /* Hardware Error - internal target failure */
+#define SCSI_KCQHE_INTERNALLOGICERROR            0x048100  /* Hardware Error - internal logic error */
+#define SCSI_KCQHE_COMMANDTIMEOUT                0x048200  /* Hardware Error - command timeout */
+
+/* Illegal Request KCQ values */
+
+#define SCSI_KCQIR_PARMLISTLENGTHERROR           0x051a00  /* Illegal Request - parm list length error */
+#define SCSI_KCQIR_INVALIDCOMMAND                0x052000  /* Illegal Request - invalid/unsupported command code */
+#define SCSI_KCQIR_LBAOUTOFRANGE                 0x052100  /* Illegal Request - LBA out of range */
+#define SCSI_KCQIR_INVALIDFIELDINCBA             0x052400  /* Illegal Request - invalid field in CDB (Command Descriptor Block) */
+#define SCSI_KCQIR_INVALIDLUN                    0x052500  /* Illegal Request - invalid LUN */
+#define SCSI_KCQIR_INVALIDFIELDSINPARMLIST       0x052600  /* Illegal Request - invalid fields in parm list */
+#define SCSI_KCQIR_PARAMETERNOTSUPPORTED         0x052601  /* Illegal Request - parameter not supported */
+#define SCSI_KCQIR_INVALIDPARMVALUE              0x052602  /* Illegal Request - invalid parm value */
+#define SCSI_KCQIR_IFPTHRESHOLDPARAMETER         0x052603  /* Illegal Request - invalid field parameter - threshold parameter */
+#define SCSI_KCQIR_INVALIDRELEASEOFPR            0x052604  /* Illegal Request - invalid release of persistent reservation */
+#define SCSI_KCQIR_IFPTMSFIRMWARETAG             0x052697  /* Illegal Request - invalid field parameter - TMS firmware tag */
+#define SCSI_KCQIR_IFPCHECKSUM                   0x052698  /* Illegal Request - invalid field parameter - check sum */
+#define SCSI_KCQIR_IFPFIRMWARETAG                0x052699  /* Illegal Request - invalid field parameter - firmware tag */
+#define SCSI_KCQIR_COMMANDSEQUENCEERROR          0x052c00  /* Illegal Request - command sequence error */
+#define SCSI_KCQIR_UNSUPPORTEDENCLOSUREFUNCTION  0x053501  /* Illegal Request - unsupported enclosure function */
+#define SCSI_KCQIR_SAVINGPARMSNOTSUPPORTED       0x053900  /* Illegal Request - Saving parameters not supported */
+#define SCSI_KCQIR_INVALIDMESSAGE                0x054900  /* Illegal Request - invalid message */
+#define SCSI_KCQIR_MEDIALOADOREJECTFAILED        0x055300  /* Illegal Request - media load or eject failed */
+#define SCSI_KCQIR_UNLOADTAPEFAILURE             0x055301  /* Illegal Request - unload tape failure */
+#define SCSI_KCQIR_MEDIUMREMOVALPREVENTED        0x055302  /* Illegal Request - medium removal prevented */
+#define SCSI_KCQIR_SYSTEMRESOURCEFAILURE         0x055500  /* Illegal Request - system resource failure */
+#define SCSI_KCQIR_SYSTEMBUFFERFULL              0x055501  /* Illegal Request - system buffer full */
+#define SCSI_KCQIR_INSUFFICIENTRR                0x055504  /* Illegal Request - Insufficient Registration Resources */
+
+/* Unit Attention KCQ values */
+
+#define SCSI_KCQUA_NOTREADYTOTRANSITION          0x062800  /* Unit Attention - not-ready to ready transition (format complete) */
+#define SCSI_KCQUA_DEVICERESETOCCURRED           0x062900  /* Unit Attention - POR or device reset occurred */
+#define SCSI_KCQUA_POROCCURRED                   0x062901  /* Unit Attention - POR occurred */
+#define SCSI_KCQUA_SCSIBUSRESETOCCURRED          0x062902  /* Unit Attention - SCSI bus reset occurred */
+#define SCSI_KCQUA_TARGETRESETOCCURRED           0x062903  /* Unit Attention - TARGET RESET occurred */
+#define SCSI_KCQUA_SELFINITIATEDRESETOCCURRED    0x062904  /* Unit Attention - self-initiated-reset occurred */
+#define SCSI_KCQUA_TRANSCEIVERMODECHANGETOSE     0x062905  /* Unit Attention - transceiver mode change to SE */
+#define SCSI_KCQUA_TRANSCEIVERMODECHANGETOLVD    0x062906  /* Unit Attention - transceiver mode change to LVD */
+#define SCSI_KCQUA_PARAMETERSCHANGED             0x062a00  /* Unit Attention - parameters changed */
+#define SCSI_KCQUA_MODEPARAMETERSCHANGED         0x062a01  /* Unit Attention - mode parameters changed */
+#define SCSI_KCQUA_LOGSELECTPARMSCHANGED         0x062a02  /* Unit Attention - log select parms changed */
+#define SCSI_KCQUA_RESERVATIONSPREEMPTED         0x062a03  /* Unit Attention - Reservations pre-empted */
+#define SCSI_KCQUA_RESERVATIONSRELEASED          0x062a04  /* Unit Attention - Reservations released */
+#define SCSI_KCQUA_REGISTRATIONSPREEMPTED        0x062a05  /* Unit Attention - Registrations pre-empted */
+#define SCSI_KCQUA_COMMANDSCLEARED               0x062f00  /* Unit Attention - commands cleared by another initiator */
+#define SCSI_KCQUA_OPERATINGCONDITIONSCHANGED    0x063f00  /* Unit Attention - target operating conditions have changed */
+#define SCSI_KCQUA_MICROCODECHANGED              0x063f01  /* Unit Attention - microcode changed */
+#define SCSI_KCQUA_CHANGEDOPERATINGDEFINITION    0x063f02  /* Unit Attention - changed operating definition */
+#define SCSI_KCQUA_INQUIRYPARAMETERSCHANGED      0x063f03  /* Unit Attention - inquiry parameters changed */
+#define SCSI_KCQUA_DEVICEIDENTIFIERCHANGED       0x063f05  /* Unit Attention - device identifier changed */
+#define SCSI_KCQUA_INVALIDAPMPARAMETERS          0x063f90  /* Unit Attention - invalid APM parameters */
+#define SCSI_KCQUA_WORLDWIDENAMEMISMATCH         0x063f91  /* Unit Attention - world-wide name mismatch */
+#define SCSI_KCQUA_PFATHRESHOLDREACHED           0x065d00  /* Unit Attention - PFA threshold reached */
+#define SCSI_KCQUA_PFATHRESHOLDEXCEEDED          0x065dff  /* Unit Attention - PFA threshold exceeded */
+
+/* Write Protect KCQ values */
+
+#define SCSI_KCQWP_COMMANDNOTALLOWED             0x072700 /* Write Protect - command not allowed */
+
+/* Aborted Command KCQ values */
+
+#define SCSI_KCQAC_NOADDITIONALSENSECODE         0x0b0000  /* Aborted Command - no additional sense code */
+#define SCSI_KCQAC_SYNCDATATRANSFERERROR         0x0b1b00  /* Aborted Command - sync data transfer error (extra ACK) */
+#define SCSI_KCQAC_UNSUPPORTEDLUN                0x0b2500  /* Aborted Command - unsupported LUN */
+#define SCSI_KCQAC_ECHOBUFFEROVERWRITTEN         0x0b3f0f  /* Aborted Command - echo buffer overwritten */
+#define SCSI_KCQAC_MESSAGEREJECTERROR            0x0b4300  /* Aborted Command - message reject error */
+#define SCSI_KCQAC_INTERNALTARGETFAILURE         0x0b4400  /* Aborted Command - internal target failure */
+#define SCSI_KCQAC_SELECTIONFAILURE              0x0b4500  /* Aborted Command - Selection/Reselection failure */
+#define SCSI_KCQAC_SCSIPARITYERROR               0x0b4700  /* Aborted Command - SCSI parity error */
+#define SCSI_KCQAC_INITIATORDETECTEDERRORECEIVED 0x0b4800  /* Aborted Command - initiator-detected error message received */
+#define SCSI_KCQAC_ILLEGALMESSAGE                0x0b4900  /* Aborted Command - inappropriate/illegal message */
+#define SCSI_KCQAC_DATAPHASEERROR                0x0b4b00  /* Aborted Command - data phase error */
+#define SCSI_KCQAC_OVERLAPPEDCOMMANDSATTEMPTED   0x0b4e00  /* Aborted Command - overlapped commands attempted */
+#define SCSI_KCQAC_LOOPINITIALIZATION            0x0b4f00  /* Aborted Command - due to loop initialization */
+
+/* Other KCQ values: */
+
+#define SCSO_KCQOTHER_MISCOMPARE                 0x0e1d00  /* Miscompare - during verify byte check operation */
+
+/* SSCSI Status Codes *******************************************************/
+
+#define SCSI_STATUS_OK                           0x00  /* OK */
+#define SCSI_STATUS_CHECKCONDITION               0x02  /* Check condition */
+#define SCSI_STATUS_CONDITIONMET                 0x04  /* Condition met */
+#define SCSI_STATUS_BUSY                         0x08  /* Busy */
+#define SCSI_STATUS_INTERMEDIATE                 0x10  /* Intermediate */
+#define SCSI_STATUS_DATAOVERUNDERRUN             0x12  /* Data Under/Over Run? */
+#define SCSI_STATUS_INTERMEDIATECONDITIONMET     0x14  /* Intermediate - Condition met */
+#define SCSI_STATUS_RESERVATIONCONFLICT          0x18  /* Reservation conflict */
+#define SCSI_STATUS_COMMANDTERMINATED            0x22  /* Command terminated */
+#define SCSI_STATUS_QUEUEFULL                    0x28  /* Queue (task set) full */
+#define SCSI_STATUS_ACAACTIVE                    0x30  /* ACA active */
+#define SCSI_STATUS_TASKABORTED                  0x40  /* Task aborted */
+
+/* Definitions for selected SCSI commands ***********************************/
+
+/* Inquiry */
+
+#define SCSICMD_INQUIRYFLAGS_EVPD                0x01  /* Bit 0: EVPD */
+                                                       /* Bits 5-7: Peripheral Qualifier */
+#define SCSIRESP_INQUIRYPQ_CONNECTED             0x00  /*   000: Device is connected */
+#define SCSIRESP_INQUIRYPQ_NOTCONNECTED          0x20  /*   001: Device is NOT connected */
+#define SCSIRESP_INQUIRYPQ_NOTCAPABLE            0x60  /*   011: LUN not supported */
+                                                       /* Bits 0-4: Peripheral Device */
+#define SCSIRESP_INQUIRYPD_DIRECTACCESS          0x00  /*   Direct-access block device */
+#define SCSIRESP_INQUIRYPD_SEQUENTIALACCESS      0x01  /*   Sequential-access block device */
+#define SCSIRESP_INQUIRYPD_PRINTER               0x02  /*   Printer device */
+#define SCSIRESP_INQUIRYPD_PROCESSOR             0x03  /*   Processor device */
+#define SCSIRESP_INQUIRYPD_WRONCE                0x04  /*   Write once device */
+#define SCSIRESP_INQUIRYPD_CDDVD                 0x05  /*   CD/DVD device */
+#define SCSIRESP_INQUIRYPD_SCANNER               0x06  /*   Scanner device (obsolete) */
+#define SCSIRESP_INQUIRYPD_OPTICAL               0x07  /*   Optical memory device */
+#define SCSIRESP_INQUIRYPD_MEDIUMCHANGER         0x08  /*   Medium changer device (Jukebox) */
+#define SCSIRESP_INQUIRYPD_COMMUNICATIONS        0x09  /*   Communications device (obsolete) */
+#define SCSIRESP_INQUIRYPD_STORAGEARRAY          0x0c  /*   Storage array controller device */
+#define SCSIRESP_INQUIRYPD_ENCLOSURESERVICES     0x0d  /*   Enclosure services device */
+#define SCSIRESP_INQUIRYPD_RBC                   0x0e  /*   Simplified direct-access device */
+#define SCSIRESP_INQUIRYPD_OCRW                  0x0f  /*   Optical reader/writer device */
+#define SCSIRESP_INQUIRYPD_BCC                   0x10  /*   Bridge controller commands */
+#define SCSIRESP_INQUIRYPD_OSD                   0x11  /*   Object-based storage device */
+#define SCSIRESP_INQUIRYPD_ADC                   0x12  /*   Automation/drive interface */
+#define SCSIRESP_INQUIRYPD_WKLU                  0x1e  /*   Well-known logical unit */
+#define SCSIRESP_INQUIRYPD_UNKNOWN               0x1f  /*   Direct-access block device */
+
+#define SCSIRESP_INQUIRYFLAGS1_RMB               0x80  /* Bit 7: RMB */
+#define SCSIRESP_INQUIRYFLAGS2_NORMACA           0x20  /* Bit 5: NormACA */
+#define SCSIRESP_INQUIRYFLAGS2_HISUP             0x10  /* Bit 4: HiSup */
+#define SCSIRESP_INQUIRYFLAGS2_FMTMASK           0x0f  /* Bits 0-3: Response data format */
+
+#define SCSIRESP_INQUIRYFLAGS3_SCCS              0x80  /* Bit 8: SCCS */
+#define SCSIRESP_INQUIRYFLAGS3_ACC               0x40  /* Bit 7: ACC */
+#define SCSIRESP_INQUIRYFLAGS3_TPGSMASK          0x30  /* Bits 4-5: TPGS */
+#define SCSIRESP_INQUIRYFLAGS3_3PC               0x08  /* Bit 3: 3PC */
+#define SCSIRESP_INQUIRYFLAGS3_PROTECT           0x01  /* Bit 0: Protect */
+
+#define SCSIRESP_INQUIRYFLAGS4_BQUE              0x80  /* Bit 7: BQue */
+#define SCSIRESP_INQUIRYFLAGS4_ENCSERV           0x40  /* Bit 6: EncServ */
+#define SCSIRESP_INQUIRYFLAGS4_VS                0x20  /* Bit 5: VS */
+#define SCSIRESP_INQUIRYFLAGS4_MULTIP            0x10  /* Bit 4: MultIP */
+#define SCSIRESP_INQUIRYFLAGS4_MCHNGR            0x08  /* Bit 3: MChngr */
+#define SCSIRESP_INQUIRYFLAGS4_ADDR16            0x01  /* Bit 0: Addr16 */
+
+#define SCSIRESP_INQUIRYFLAGS5_WBUS16            0x20  /* Bit 5: WBus16 */
+#define SCSIRESP_INQUIRYFLAGS5_SYNC              0x10  /* Bit 4: SYNC */
+#define SCSIRESP_INQUIRYFLAGS5_LINKED            0x08  /* Bit 3: LINKED */
+#define SCSIRESP_INQUIRYFLAGS5_CMDQUEUE          0x02  /* Bit 1: CmdQue */
+#define SCSIRESP_INQUIRYFLAGS5_VS                0x01  /* Bit 0: VS */
+
+#define SCSIRESP_INQUIRYFLAGS6_CLOCKINGMASK      0xc0  /* Bits 2-3: Clocking */
+#define SCSIRESP_INQUIRYFLAGS6_QAS               0x02  /* Bit 1: QAS */
+#define SCSIRESP_INQUIRYFLAGS6_IUS               0x01  /* Bit 0: IUS */
+
+/* Sense data */
+
+/* Sense data response codes */
+
+#define SCSIRESP_SENSEDATA_CURRENTFIXED          0x70 /* Byte 1 is always the response code */
+#define SCSIRESP_SENSEDATA_DEFERREDFIXED         0x71
+#define SCSIRESP_SENSEDATA_CURRENTDESC           0x72
+#define SCSIRESP_SENSEDATA_DEFERREDDESC          0x73
+
+#define SCSIRESP_SENSEDATA_RESPVALID             0x80
+
+/* Fixed sense data flags */
+
+#define SCSIRESP_SENSEDATA_FILEMARK              0x80 /* Bit 7: FileMark */
+#define SCSIRESP_SENSEDATA_EOM                   0x40 /* Bit 6: EOM */
+#define SCSIRESP_SENSEDATA_ILI                   0x20 /* Bit 5: ILI */
+#define SCSIRESP_SENSEDATA_SENSEKEYMASK          0x0f /* Bits 0-3: Sense key */
+#define SCSIRESP_SENSEDATA_NOSENSE               0x00 /*   Nothing to be reported */
+#define SCSIRESP_SENSEDATA_RECOVEREDERROR        0x01 /*   Successful after recovery action */
+#define SCSIRESP_SENSEDATA_NOTREADY              0x02 /*   Logical unit is not accessible */
+#define SCSIRESP_SENSEDATA_MEDIUMERROR           0x03 /*   Error possibly caused by flaw in medium */
+#define SCSIRESP_SENSEDATA_HARDWAREERROR         0x04 /*   Non-recoverable hardware error */
+#define SCSIRESP_SENSEDATA_ILLEGALREQUEST        0x05 /*   Error in received request */
+#define SCSIRESP_SENSEDATA_UNITATTENTION         0x06 /*   Unit attention condition */
+#define SCSIRESP_SENSEDATA_DATAPROTECT           0x07 /*   Action failed, medium protected */
+#define SCSIRESP_SENSEDATA_BLANKCHECK            0x08 /*   Encountered blank media */
+#define SCSIRESP_SENSEDATA_VENDORSPECIFIC        0x09 /*   Vendor specific condition */
+#define SCSIRESP_SENSEDATA_ABORTEDCOMMAND        0x0b /*   Command was aborted */
+
+#define SCSIRESP_SENSEDATA_KEYVALID              0x80 /* Sense-specific data valid */
+
+/* Mode Select 6 */
+
+#define SCSICMD_MODESELECT6_PF                   0x10 /* Bit 4: PF */
+#define SCSICMD_MODESELECT6_SP                   0x01 /* Bit 0: SP */
+
+/* Mode Sense 6 */
+
+#define SCSICMD_MODESENSE6_DBD                   0x08 /* Bit 3: PF */
+
+#define SCSICMD_MODESENSE_PCMASK                 0xc0 /* Bits 6-7: Page control (PC) */
+#define SCSICMD_MODESENSE_PCCURRENT              0x00 /*   Current values */
+#define SCSICMD_MODESENSE_PCCHANGEABLE           0x40 /*   Changeable values */
+#define SCSICMD_MODESENSE_PCDEFAULT              0x80 /*   Default values */
+#define SCSICMD_MODESENSE_PCSAVED                0xc0 /*   Saved values */
+#define SCSICMD_MODESENSE_PGCODEMASK             0x3f /* Bits 0-5: Page code */
+
+#define SCSICMD_MODESENSE6_PCDEFAULT             0x80 /*   Default values */
+                                                      /* Direct-access device page codes */
+#define SCSIRESP_MODESENSE_PGCCODE_VENDOR        0x00 /*   Vendor-specific */
+#define SCSIRESP_MODESENSE_PGCCODE_RWERROR       0x01 /*   Read/Write error recovery mode page */
+#define SCSIRESP_MODESENSE_PGCCODE_RECONNECT     0x02 /*   Disconnect-reconnect mode page */
+#define SCSIRESP_MODESENSE_PGCCODE_FORMATDEV     0x03 /*   Format device mode page (obsolete) */
+#define SCSIRESP_MODESENSE_PGCCODE_RIGID         0x04 /*   Rigid disk geometry mode page (obsolete) */
+#define SCSIRESP_MODESENSE_PGCCODE_FLEXIBLE      0x05 /*   Flexible disk geometry mode page (obsolete) */
+#define SCSIRESP_MODESENSE_PGCCODE_VERIFY        0x07 /*   Verify error recovery mode page */
+#define SCSIRESP_MODESENSE_PGCCODE_CACHING       0x08 /*   Caching mode page */
+#define SCSIRESP_MODESENSE_PGCCODE_CONTROL       0x0a /*   Control mode page (0x0a/0x00) */
+#define SCSIRESP_MODESENSE_PGCCODE_CONTROLEXT    0x0a /*   Control extension mode page (0x0a/0x01) */
+#define SCSIRESP_MODESENSE_PGCCODE_MEDIUMTYPES   0x0b /*   Medum types supported mode page (obsolete) */
+#define SCSIRESP_MODESENSE_PGCCODE_NP            0x0c /*   Notch and partition mode page (obsolete) */
+#define SCSIRESP_MODESENSE_PGCCODE_XOR           0x10 /*   XOR control mode page */
+#define SCSIRESP_MODESENSE_PGCCODE_ES            0x14 /*   Enclosure services mode page */
+#define SCSIRESP_MODESENSE_PGCCODE_PSLUN         0x18 /*   Protocol-specific LUN mode page */
+#define SCSIRESP_MODESENSE_PGCCODE_PSPORT        0x19 /*   Protocol-specific port mode page */
+#define SCSIRESP_MODESENSE_PGCCODE_POWER         0x1a /*   Power condition mode page */
+#define SCSIRESP_MODESENSE_PGCCODE_IE            0x1c /*   Informational exceptions control mode page (0x1c/0x00) */
+#define SCSIRESP_MODESENSE_PGCCODE_BC            0x1c /*   Background control mode page (0x1c/0x01) */
+#define SCSIRESP_MODESENSE_PGCCODE_RETURNALL     0x3f /*   Return all mode pages */
+                                                      /* Direct-access caching mode page */
+#define SCSIRESP_CACHINGMODEPG_PS                0x80 /*   Byte 0, Bit 7: PS */
+#define SCSIRESP_CACHINGMODEPG_SPF               0x60 /*   Byte 0, Bit 6: SPF */
+#define SCSIRESP_CACHINGMODEPG_IC                0x80 /*   Byte 2, Bit 7: IC */
+#define SCSIRESP_CACHINGMODEPG_ABPF              0x40 /*   Byte 2, Bit 6: ABPF */
+#define SCSIRESP_CACHINGMODEPG_CAP               0x20 /*   Byte 2, Bit 5: CAP */
+#define SCSIRESP_CACHINGMODEPG_DISC              0x10 /*   Byte 2, Bit 4: DISC */
+#define SCSIRESP_CACHINGMODEPG_SIZE              0x08 /*   Byte 2, Bit 3: SIZE */
+#define SCSIRESP_CACHINGMODEPG_WCE               0x04 /*   Byte 2, Bit 2: Write cache enable (WCE) */
+#define SCSIRESP_CACHINGMODEPG_MF                0x02 /*   Byte 2, Bit 1: MF */
+#define SCSIRESP_CACHINGMODEPG_RCD               0x01 /*   Byte 2, Bit 0: Read cache disable (RCD) */
+
+#define SCSIRESP_MODEPARMHDR_DAPARM_WP           0x80 /* Bit 7: WP (Direct-access block devices only) */
+#define SCSIRESP_MODEPARMHDR_DAPARM_DBPFUA       0x10 /* Bit 4: DBOFUA (Direct-access block devices only) */
+
+#define SCSIRESP_PAGEFMT_PS                      0x80 /* Bit 7: PS */
+#define SCSIRESP_PAGEFMT_SPF                     0x40 /* Bit 6: SPF */
+#define SCSIRESP_PAGEFMT_PGCODEMASK              0x3f /* Bits 0-5: Page code */
+
+/* Prevent / Allow Medium Removal */
+
+#define SCSICMD_PREVENTMEDIUMREMOVAL_TRANSPORT   0x01 /* Removal prohibited from data transport */
+#define SCSICMD_PREVENTMEDIUMREMOVAL_MCHANGER    0x02 /* Removal prohibited from medium changer */
+
+/* Read format capacities */
+
+#define SCIRESP_RDFMTCAPACITIES_UNFORMATED       0x01 /* Unformatted media */
+#define SCIRESP_RDFMTCAPACITIES_FORMATED         0x02 /* Formatted media */
+#define SCIRESP_RDFMTCAPACITIES_NOMEDIA          0x03 /* No media */
+
+/* Read 6 */
+
+#define SCSICMD_READ6_MSLBAMASK                  0x1f
+
+/* Write 6 */
+
+#define SCSICMD_WRITE6_MSLBAMASK                 0x1f
+
+/* Mode Select 10 */
+
+#define SCSICMD_MODESELECT10_PF                  0x10 /* Bit 4: PF */
+#define SCSICMD_MODESELECT10_SP                  0x01 /* Bit 0: SP */
+
+/* Mode Sense 10 */
+
+#define SCSICMD_MODESENSE10_LLBAA                0x10 /* Bit 4: LLBAA */
+#define SCSICMD_MODESENSE10_DBD                  0x08 /* Bit 3: PF */
+
+/* Read 10 */
+
+#define SCSICMD_READ10FLAGS_RDPROTECTMASK        0xe0
+#define SCSICMD_READ10FLAGS_DPO                  0x10 /* Disable Page Out */
+#define SCSICMD_READ10FLAGS_FUA                  0x08
+#define SCSICMD_READ10FLAGS_FUANV                0x02
+
+/* Write 10 */
+
+#define SCSICMD_WRITE10FLAGS_WRPROTECTMASK       0xe0
+#define SCSICMD_WRITE10FLAGS_DPO                 0x10 /* Disable Page Out */
+#define SCSICMD_WRITE10FLAGS_FUA                 0x08
+#define SCSICMD_WRITE10FLAGS_FUANV               0x02
+
+/* Verify 10 */
+
+#define SCSICMD_VERIFY10_VRPROTECTMASK           0xe0 /* Byte 1: Bits 5-7: VRPROTECT */
+#define SCSICMD_VERIFY10_DPO                     0x10 /* Byte 1: Bit 4: Disable Page Out (DPO) */
+#define SCSICMD_VERIFY10_BYTCHK                  0x02 /* Byte 1: Bit 2: BytChk */
+
+/* Read 12 */
+
+#define SCSICMD_READ12FLAGS_RDPROTECTMASK        0xe0
+#define SCSICMD_READ12FLAGS_DPO                  0x10 /* Disable Page Out */
+#define SCSICMD_READ12FLAGS_FUA                  0x08
+#define SCSICMD_READ12FLAGS_FUANV                0x02
+
+/* Write 12 */
+
+#define SCSICMD_WRITE12FLAGS_WRPROTECTMASK       0xe0
+#define SCSICMD_WRITE12FLAGS_DPO                 0x10 /* Disable Page Out */
+#define SCSICMD_WRITE12FLAGS_FUA                 0x08
+#define SCSICMD_WRITE12FLAGS_FUANV               0x02
+
+/* Verify 12 */
+
+#define SCSICMD_VERIFY12_VRPROTECTMASK           0xe0 /* Byte 1: Bits 5-7: VRPROTECT */
+#define SCSICMD_VERIFY12_DPO                     0x10 /* Byte 1: Bit 4: Disable Page Out (DPO) */
+#define SCSICMD_VERIFY12_BYTCHK                  0x02 /* Byte 1: Bit 2: BytChk */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Format structures for selected SCSI primary commands */
+
+#define SCSICMD_TESTUNITREADY_SIZEOF 6
+
+struct scsicmd_requestsense_s
+{
+  uint8_t opcode;        /* 0: 0x03 */
+  uint8_t flags;         /* 1: See SCSICMD_REQUESTSENSE_FLAGS_* */
+  uint8_t reserved[2];   /* 2-3: Reserved */
+  uint8_t alloclen;      /* 4: Allocation length */
+  uint8_t control;       /* 5: Control */
+};
+#define SCSICMD_REQUESTSENSE_SIZEOF 6
+#define SCSICMD_REQUESTSENSE_MSSIZEOF 12 /* MS-Windows REQUEST SENSE with cbw->cdblen == 12 */
+
+struct scsiresp_fixedsensedata_s
+{
+  uint8_t code;          /* 0: Response code See  SCSIRESP_SENSEDATA_*FIXED defns */
+  uint8_t obsolete;      /* 1: */
+  uint8_t flags;         /* 2: See SCSIRESP_SENSEDATA_* definitions */
+  uint8_t info[4];       /* 3-6: Information */
+  uint8_t len;           /* 7: Additional length */
+  uint8_t cmdinfo[4];    /* 8-11: Command-specific information */
+  uint8_t code2;         /* 12: Additional sense code */
+  uint8_t qual2;         /* 13: Additional sense code qualifier */
+  uint8_t fru;           /* 14: Field replacement unit code */
+  uint8_t key[3];        /* 15-17: Sense key specific */
+                         /* 18-: Additional bytes may follow */
+};
+#define SCSIRESP_FIXEDSENSEDATA_SIZEOF 18 /* Minimum size */
+
+struct scscicmd_inquiry_s
+{
+  uint8_t opcode;        /* 0: 0x12 */
+  uint8_t flags;         /* 1: See SCSICMD_INQUIRY_FLAGS_* */
+  uint8_t pagecode;      /* 2: Page code */
+  uint8_t alloclen[2];   /* 3-4: Allocation length */
+  uint8_t control;       /* 5: Control */
+};
+#define SCSICMD_INQUIRY_SIZEOF 6
+
+struct scsiresp_inquiry_s
+{
+  /* Mandatory */
+
+  uint8_t qualtype;      /* 0: Bits 5-7: Peripheral qualifier; Bits 0-4: Peripheral device type */
+  uint8_t flags1;        /* 1: See SCSIRESP_INQUIRY_FLAGS1_* */
+  uint8_t version;       /* 2: Version */
+  uint8_t flags2;        /* 3: See SCSIRESP_INQUIRY_FLAGS2_* */
+  uint8_t len;           /* 4: Additional length */
+  uint8_t flags3;        /* 5: See SCSIRESP_INQUIRY_FLAGS3_* */
+  uint8_t flags4;        /* 6: See SCSIRESP_INQUIRY_FLAGS4_* */
+  uint8_t flags5;        /* 7: See SCSIRESP_INQUIRY_FLAGS5_* */
+  uint8_t vendorid[8];   /* 8-15: T10 Vendor Identification */
+  uint8_t productid[16]; /* 16-31: Product Identification */
+  uint8_t revision[4];   /* 32-35: Product Revision Level */
+
+  /* Optional */
+
+  uint8_t vendor[20];    /* 36-55: Vendor specific */
+  uint8_t flags6;        /* 56: See SCSIRESP_INQUIRY_FLAGS6_* */
+  uint8_t reserved1;     /* 57: Reserved */
+  uint8_t version1[2];   /* 58-59: Version Descriptor 1 */
+  uint8_t version2[2];   /* 60-61: Version Descriptor 2 */
+  uint8_t version3[2];   /* 62-63: Version Descriptor 3 */
+  uint8_t version4[2];   /* 64-65: Version Descriptor 4 */
+  uint8_t version5[2];   /* 66-67: Version Descriptor 5 */
+  uint8_t version6[2];   /* 68-69: Version Descriptor 6 */
+  uint8_t version7[2];   /* 70-71: Version Descriptor 7 */
+  uint8_t version8[2];   /* 72-73: Version Descriptor 8 */
+  uint8_t reserved2[22]; /* 74-95: Reserved */
+                         /* 96-: Vendor-specific parameters may follow */
+};
+#define SCSIRESP_INQUIRY_SIZEOF 36 /* Minimum size */
+
+struct scsicmd_modeselect6_s
+{
+  uint8_t opcode;        /* 0x15 */
+  uint8_t flags;         /* 1: See SCSICMD_MODESELECT6_FLAGS_* */
+  uint8_t reserved[2];   /* 2-3: Reserved */
+  uint8_t plen;          /* 4: Parameter list length */
+  uint8_t control;       /* 5: Control */
+};
+#define SCSICMD_MODESELECT6_SIZEOF 6
+
+struct scsicmd_modesense6_s
+{
+  uint8_t opcode;        /* 0x1a */
+  uint8_t flags;         /* 1: See SCSICMD_MODESENSE6_FLAGS_* */
+  uint8_t pcpgcode;      /* 2: Bits 6-7: PC, bits 0-5: page code */
+  uint8_t subpgcode;     /* 3: subpage code */
+  uint8_t alloclen;      /* 4: Allocation length */
+  uint8_t control;       /* 5: Control */
+};
+#define SCSICMD_MODESENSE6_SIZEOF 6
+
+struct scsiresp_modeparameterhdr6_s
+{
+  uint8_t mdlen;         /* 0: Mode data length */
+  uint8_t type;          /* 1: Medium type */
+  uint8_t param;         /* 2: Device-specific parameter */
+  uint8_t bdlen;         /* 3: Block descriptor length */
+};
+#define SCSIRESP_MODEPARAMETERHDR6_SIZEOF 4
+
+struct scsiresp_blockdesc_s
+{
+  uint8_t density;       /* 0: density code */
+  uint8_t nblocks[3];    /* 1-3: Number of blocks */
+  uint8_t reserved;      /* 4: reserved */
+  uint8_t blklen[3];     /* 5-7: Block len */
+};
+#define SCSIRESP_BLOCKDESC_SIZEOF 8
+
+struct scsiresp_pageformat_s
+{
+  uint8_t pgcode;       /* 0: See SCSIRESP_PAGEFMT_* definitions */
+  uint8_t pglen;        /* 1: Page length (n-1) */
+  uint8_t parms[1];     /* 2-n: Mode parameters */
+};
+
+struct scsiresp_subpageformat_s
+{
+  uint8_t pgcode;       /* 0: See SCSIRESP_PAGEFMT_* definitions */
+  uint8_t subpgcode;    /* 1: sub-page code */
+  uint8_t pglen[2];     /* 2-3: Page length (n-3) */
+  uint8_t parms[1];     /* 4-n: Mode parameters */
+};
+
+struct scsiresp_cachingmodepage_s
+{
+  uint8_t pgcode;      /* 0: Bit 7: PS; Bit 6: SPF, Bits 0-5: page code == 8 */
+  uint8_t len;         /* 1: Page length (18) */
+  uint8_t flags1;      /* 2: See SCSIRESP_CACHINGMODEPG_* definitions */
+  uint8_t priority;    /* 3: Bits 4-7: Demand read retention priority; Bits 0-3: Write retention priority */
+  uint8_t dpflen[2];   /* 4-5: Disable prefetch transfer length */
+  uint8_t minpf[2];    /* 6-7: Minimum pre-fetch */
+  uint8_t maxpf[2];    /* 8-9: Maximum pre-fetch */
+  uint8_t maxpfc[2];   /* 10-11: Maximum pref-fetch ceiling */
+  uint8_t flags2;      /* 12: See SCSIRESP_CACHINGMODEPG_* definitions */
+  uint8_t nsegments;   /* 13: Number of cache segments */
+  uint8_t segsize[2];  /* 14-15: Cache segment size */
+  uint8_t reserved;    /* 16: Reserved */
+  uint8_t obsolete[3]; /* 17-19: Obsolete */
+};
+
+/* Format structures for selected SCSI block commands */
+
+struct scsicmd_read6_s
+{
+  uint8_t opcode;        /* 0: 0x08 */
+  uint8_t mslba;         /* 1: Bits 5-7: reserved; Bits 0-6: MS Logical Block Address (LBA) */
+  uint8_t lslba[2];      /* 2-3: LS Logical Block Address (LBA) */
+  uint8_t xfrlen;        /* 4: Transfer length (in contiguous logical blocks) */
+  uint8_t control;       /* 5: Control */
+};
+#define SCSICMD_READ6_SIZEOF 6
+
+struct scsicmd_write6_s
+{
+  uint8_t opcode;        /* 0: 0x0a */
+  uint8_t mslba;         /* 1: Bits 5-7: reserved; Bits 0-6: MS Logical Block Address (LBA) */
+  uint8_t lslba[2];      /* 2-3: LS Logical Block Address (LBA) */
+  uint8_t xfrlen;        /* 4: Transfer length (in contiguous logical blocks) */
+  uint8_t control;       /* 5: Control */
+};
+#define SCSICMD_WRITE6_SIZEOF 6
+
+struct scsicmd_startstopunit_s
+{
+  uint8_t opcode;        /* 0: 0x1b */
+  uint8_t immed;         /* 1: Bits 2-7: Reserved, Bit 0: Immed */
+  uint8_t reserved;      /* 2: reserved */
+  uint8_t pcm;           /* 3: Bits 4-7: Reserved, Bits 0-3: Power condition modifier */
+  uint8_t pc;            /* 4: Bits 4-7: Power condition, Bit 2: NO_FLUSH, Bit 1: LOEJ, Bit 0: START */
+  uint8_t control;       /* 5: Control */
+};
+#define SCSICMD_STARTSTOPUNIT_SIZEOF 6
+
+struct scsicmd_preventmediumremoval_s
+{
+  uint8_t opcode;        /* 0: 0x1e */
+  uint8_t reserved[3];   /* 1-3: Reserved */
+  uint8_t prevent;       /* 4: Bits 2-7: Reserved, Bits 0:1: prevent */
+  uint8_t control;       /* 5: Control */
+};
+#define SCSICMD_PREVENTMEDIUMREMOVAL_SIZEOF 6
+
+struct scsicmd_readformatcapcacities_s
+{
+  uint8_t opcode;        /* 0: 0x23 */
+  uint8_t reserved[6];   /* 1-6: Reserved */
+  uint8_t alloclen[2];   /* 7-8: Allocation length */
+  uint8_t control;       /* 9: Control */
+};
+#define SCSICMD_READFORMATCAPACITIES_SIZEOF 10
+
+struct scsiresp_readformatcapacities_s
+{
+  /* Current capacity header */
+
+  uint8_t reserved[3];  /* 0-2: Reserved */
+  uint8_t listlen;      /* 3: Capacity list length */
+
+  /* Current/Maximum Capacity Descriptor (actually a separate structure) */
+
+  uint8_t nblocks[4];   /* 4-7: Number of blocks */
+  uint8_t type;         /* 8: Bits 2-7: Reserved, Bits 0-1: Descriptor type */
+  uint8_t blocklen[3];  /* 9-11: Block length */
+};
+#define SCSIRESP_READFORMATCAPACITIES_SIZEOF 12
+#define SCSIRESP_CURRCAPACITYDESC_SIZEOF 8
+
+struct scsiresp_formattedcapacitydesc_s
+{
+  uint8_t nblocks[4];   /* 0-3: Number of blocks */
+  uint8_t type;         /* 4: Bits 2-7: Type, bits 0-1, reserved */
+  uint8_t param[3];     /* 5-7: Type dependent parameter */
+};
+#define SCSIRESP_FORMATTEDCAPACITYDESC_SIZEOF 8
+
+struct scsicmd_readcapacity10_s
+{
+  uint8_t opcode;        /* 0: 0x25 */
+  uint8_t reserved1;     /* 1: Bits 1-7: Reserved, Bit 0: Obsolete */
+  uint8_t lba[4];        /* 2-5: Logical block address (LBA) */
+  uint8_t reserved2[2];  /* 6-7: Reserved */
+  uint8_t pmi;           /* 8: Bits 1-7 Reserved; Bit 0: PMI */
+  uint8_t control;       /* 9: Control */
+};
+#define SCSICMD_READCAPACITY10_SIZEOF 10
+
+struct scsiresp_readcapacity10_s
+{
+  uint8_t lba[4];        /* 0-3: Returned logical block address (LBA) */
+  uint8_t blklen[4];     /* 4-7: Logical block length (in bytes) */
+};
+#define SCSIRESP_READCAPACITY10_SIZEOF 8
+
+struct scsicmd_read10_s
+{
+  uint8_t opcode;        /* 0: 0x28 */
+  uint8_t flags;         /* 1: See SCSICMD_READ10FLAGS_* */
+  uint8_t lba[4];        /* 2-5: Logical Block Address (LBA) */
+  uint8_t groupno;       /* 6: Bits 5-7: reserved; Bits 0-6: group number */
+  uint8_t xfrlen[2];     /* 7-8: Transfer length (in contiguous logical blocks) */
+  uint8_t control;       /* 9: Control */
+};
+#define SCSICMD_READ10_SIZEOF 10
+
+struct scsicmd_write10_s
+{
+  uint8_t opcode;        /* 0: 0x2a */
+  uint8_t flags;         /* 1: See SCSICMD_WRITE10FLAGS_* */
+  uint8_t lba[4];        /* 2-5: Logical Block Address (LBA) */
+  uint8_t groupno;       /* 6: Bits 5-7: reserved; Bits 0-6: group number */
+  uint8_t xfrlen[2];     /* 7-8: Transfer length (in contiguous logical blocks) */
+  uint8_t control;       /* 9: Control */
+};
+#define SCSICMD_WRITE10_SIZEOF 10
+
+struct scsicmd_verify10_s
+{
+  uint8_t opcode;        /* 0: 0x2f */
+  uint8_t flags;         /* 1: See SCSICMD_VERIFY10_* definitions */
+  uint8_t lba[4];        /* 2-5: Logical block address (LBA) */
+  uint8_t groupno;       /* 6: Bit 7: restricted; Bits 5-6: Reserved, Bits 0-4: Group number */
+  uint8_t len[2];        /* 7-8: Verification length (in blocks) */
+  uint8_t control;       /* 9: Control */
+};
+#define SCSICMD_VERIFY10_SIZEOF 10
+
+struct scsicmd_synchronizecache10_s
+{
+  uint8_t opcode;        /* 0: 0x35 */
+  uint8_t flags;         /* 1: See SCSICMD_SYNCHRONIZECACHE10_* definitions */
+  uint8_t lba[4];        /* 2-5: Logical block address (LBA) */
+  uint8_t groupno;       /* 6: Bit 7: restricted; Bits 5-6: Reserved, Bits 0-4: Group number */
+  uint8_t len[2];        /* 7-8: Number of logical blocks */
+  uint8_t control;       /* 9: Control */
+};
+#define SCSICMD_SYNCHRONIZECACHE10_SIZEOF 10
+
+struct scsicmd_modeselect10_s
+{
+  uint8_t opcode;        /* 0: 0x55 */
+  uint8_t flags;         /* 1: See SCSICMD_MODESELECT10_FLAGS_* */
+  uint8_t reserved[5];   /* 2-6: Reserved */
+  uint8_t parmlen[2];    /* 7-8: Parameter list length */
+  uint8_t control;       /* 9: Control */
+};
+#define SCSICMD_MODESELECT10_SIZEOF 10
+
+struct scsiresp_modeparameterhdr10_s
+{
+  uint8_t mdlen[2];      /* 0-1: Mode data length */
+  uint8_t type;          /* 2: Medium type */
+  uint8_t param;         /* 3: Device-specific parameter */
+  uint8_t reserved[2];   /* 4-5: reserved */
+  uint8_t bdlen[2];      /* 6-7: Block descriptor length */
+};
+#define SCSIRESP_MODEPARAMETERHDR10_SIZEOF 8
+
+struct scsicmd_modesense10_s
+{
+  uint8_t opcode;        /* O: 0x5a */
+  uint8_t flags;         /* 1: See SCSICMD_MODESENSE10_FLAGS_* */
+  uint8_t pcpgcode;      /* 2: Bits 6-7: PC, bits 0-5: page code */
+  uint8_t subpgcode;     /* 3: subpage code */
+  uint8_t reserved[3];   /* 4-6: reserved */
+  uint8_t alloclen[2];   /* 7-8: Allocation length */
+  uint8_t control;       /* 9: Control */
+};
+#define SCSICMD_MODESENSE10_SIZEOF 10
+
+struct scsicmd_readcapacity16_s
+{
+  uint8_t opcode;        /* 0: 0x9e */
+  uint8_t action;        /* 1: Bits 5-7: Reserved, Bits 0-4: Service action */
+  uint8_t lba[8];        /* 2-9: Logical block address (LBA) */
+  uint8_t len[4];        /* 10-13: Allocation length */
+  uint8_t reserved;      /* 14: Reserved */
+  uint8_t control;       /* 15: Control */
+};
+#define SCSICMD_READCAPACITY16_SIZEOF 16
+
+struct scsicmd_read12_s
+{
+  uint8_t opcode;        /* 0: 0xa8 */
+  uint8_t flags;         /* 1: See SCSICMD_READ12FLAGS_* */
+  uint8_t lba[4];        /* 2-5: Logical Block Address (LBA) */
+  uint8_t xfrlen[4];     /* 6-9: Transfer length (in contiguous logical blocks) */
+  uint8_t groupno;       /* 10: Bit 7: restricted; Bits 5-6: reserved; Bits 0-6: group number */
+  uint8_t control;       /* 11: Control */
+};
+#define SCSICMD_READ12_SIZEOF 12
+
+struct scsicmd_write12_s
+{
+  uint8_t opcode;        /* 0: 0xaa */
+  uint8_t flags;         /* 1: See SCSICMD_WRITE12FLAGS_* */
+  uint8_t lba[4];        /* 2-5: Logical Block Address (LBA) */
+  uint8_t xfrlen[4];     /* 6-9: Transfer length (in contiguous logical blocks) */
+  uint8_t groupno;       /* 10: Bit 7: restricted; Bits 5-6: reserved; Bits 0-6: group number */
+  uint8_t control;       /* 11: Control */
+};
+#define SCSICMD_WRITE12_SIZEOF 12
+
+struct scsicmd_verify12_s
+{
+  uint8_t opcode;        /* 0: 0xaf */
+  uint8_t flags;         /* 1: See SCSICMD_VERIFY12_* definitions */
+  uint8_t lba[4];        /* 2-5: Logical block address (LBA) */
+  uint8_t len[4];        /* 6-9: Verification length */
+  uint8_t groupno;       /* 10: Bit 7: restricted; Bits 5-6: Reserved, Bits 0-4: Group number */
+  uint8_t control;       /* 11: Control */
+};
+#define SCSICMD_VERIFY12_SIZEOF 12
+
+/****************************************************************************
+ * Public Functions Definitions
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_SCSI_H */

+ 938 - 0
components/drivers/usb/cherryusb/class/msc/usbd_msc.c

@@ -0,0 +1,938 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ * Copyright (c) 2024, zhihong chen
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_msc.h"
+#include "usb_scsi.h"
+#if defined(CONFIG_USBDEV_MSC_THREAD)
+#include "usb_osal.h"
+#endif
+
+#define MSD_OUT_EP_IDX 0
+#define MSD_IN_EP_IDX  1
+
+/* Describe EndPoints configuration */
+static struct usbd_endpoint mass_ep_data[CONFIG_USBDEV_MAX_BUS][2];
+
+/* MSC Bulk-only Stage */
+enum Stage {
+    MSC_READ_CBW = 0, /* Command Block Wrapper */
+    MSC_DATA_OUT = 1, /* Data Out Phase */
+    MSC_DATA_IN = 2,  /* Data In Phase */
+    MSC_SEND_CSW = 3, /* Command Status Wrapper */
+    MSC_WAIT_CSW = 4, /* Command Status Wrapper */
+};
+
+/* Device data structure */
+USB_NOCACHE_RAM_SECTION struct usbd_msc_priv {
+    /* state of the bulk-only state machine */
+    enum Stage stage;
+    USB_MEM_ALIGNX struct CBW cbw;
+    USB_MEM_ALIGNX struct CSW csw;
+
+    bool readonly;
+    bool popup;
+    uint8_t sKey; /* Sense key */
+    uint8_t ASC;  /* Additional Sense Code */
+    uint8_t ASQ;  /* Additional Sense Qualifier */
+    uint8_t max_lun;
+    uint32_t start_sector;
+    uint32_t nsectors;
+    uint32_t scsi_blk_size[CONFIG_USBDEV_MSC_MAX_LUN];
+    uint32_t scsi_blk_nbr[CONFIG_USBDEV_MSC_MAX_LUN];
+
+    USB_MEM_ALIGNX uint8_t block_buffer[CONFIG_USBDEV_MSC_MAX_BUFSIZE];
+
+#if defined(CONFIG_USBDEV_MSC_THREAD)
+    usb_osal_mq_t usbd_msc_mq;
+    usb_osal_thread_t usbd_msc_thread;
+    uint32_t nbytes;
+#endif
+} g_usbd_msc[CONFIG_USBDEV_MAX_BUS];
+
+#ifdef CONFIG_USBDEV_MSC_THREAD
+static void usbdev_msc_thread(void *argument);
+#endif
+
+static void usdb_msc_set_max_lun(uint8_t busid)
+{
+    g_usbd_msc[busid].max_lun = CONFIG_USBDEV_MSC_MAX_LUN - 1u;
+}
+
+static void usbd_msc_reset(uint8_t busid)
+{
+    g_usbd_msc[busid].stage = MSC_READ_CBW;
+    g_usbd_msc[busid].readonly = false;
+}
+
+static int msc_storage_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    USB_LOG_DBG("MSC Class request: "
+                "bRequest 0x%02x\r\n",
+                setup->bRequest);
+
+    switch (setup->bRequest) {
+        case MSC_REQUEST_RESET:
+            usbd_msc_reset(busid);
+            break;
+
+        case MSC_REQUEST_GET_MAX_LUN:
+            (*data)[0] = g_usbd_msc[busid].max_lun;
+            *len = 1;
+            break;
+
+        default:
+            USB_LOG_WRN("Unhandled MSC Class bRequest 0x%02x\r\n", setup->bRequest);
+            return -1;
+    }
+
+    return 0;
+}
+
+void msc_storage_notify_handler(uint8_t busid, uint8_t event, void *arg)
+{
+    switch (event) {
+        case USBD_EVENT_INIT:
+#ifdef CONFIG_USBDEV_MSC_THREAD
+            g_usbd_msc[busid].usbd_msc_mq = usb_osal_mq_create(1);
+            if (g_usbd_msc[busid].usbd_msc_mq == NULL) {
+                USB_LOG_ERR("No memory to alloc for g_usbd_msc[busid].usbd_msc_mq\r\n");
+            }
+            g_usbd_msc[busid].usbd_msc_thread = usb_osal_thread_create("usbd_msc", CONFIG_USBDEV_MSC_STACKSIZE, CONFIG_USBDEV_MSC_PRIO, usbdev_msc_thread, (void *)busid);
+            if (g_usbd_msc[busid].usbd_msc_thread == NULL) {
+                USB_LOG_ERR("No memory to alloc for g_usbd_msc[busid].usbd_msc_thread\r\n");
+            }
+#endif
+            break;
+        case USBD_EVENT_DEINIT:
+#ifdef CONFIG_USBDEV_MSC_THREAD
+            if (g_usbd_msc[busid].usbd_msc_mq) {
+                usb_osal_mq_delete(g_usbd_msc[busid].usbd_msc_mq);
+            }
+            if (g_usbd_msc[busid].usbd_msc_thread) {
+                usb_osal_thread_delete(g_usbd_msc[busid].usbd_msc_thread);
+            }
+#endif
+            break;
+        case USBD_EVENT_RESET:
+            usbd_msc_reset(busid);
+            break;
+        case USBD_EVENT_CONFIGURED:
+            USB_LOG_DBG("Start reading cbw\r\n");
+            usbd_ep_start_read(busid, mass_ep_data[busid][MSD_OUT_EP_IDX].ep_addr, (uint8_t *)&g_usbd_msc[busid].cbw, USB_SIZEOF_MSC_CBW);
+            break;
+
+        default:
+            break;
+    }
+}
+
+static void usbd_msc_bot_abort(uint8_t busid)
+{
+    if ((g_usbd_msc[busid].cbw.bmFlags == 0) && (g_usbd_msc[busid].cbw.dDataLength != 0)) {
+        usbd_ep_set_stall(busid, mass_ep_data[busid][MSD_OUT_EP_IDX].ep_addr);
+    }
+    usbd_ep_set_stall(busid, mass_ep_data[busid][MSD_IN_EP_IDX].ep_addr);
+    usbd_ep_start_read(busid, mass_ep_data[busid][0].ep_addr, (uint8_t *)&g_usbd_msc[busid].cbw, USB_SIZEOF_MSC_CBW);
+}
+
+static void usbd_msc_send_csw(uint8_t busid, uint8_t CSW_Status)
+{
+    g_usbd_msc[busid].csw.dSignature = MSC_CSW_Signature;
+    g_usbd_msc[busid].csw.bStatus = CSW_Status;
+
+    /* updating the State Machine , so that we wait CSW when this
+	 * transfer is complete, ie when we get a bulk in callback
+	 */
+    g_usbd_msc[busid].stage = MSC_WAIT_CSW;
+
+    USB_LOG_DBG("Send csw\r\n");
+    usbd_ep_start_write(busid, mass_ep_data[busid][MSD_IN_EP_IDX].ep_addr, (uint8_t *)&g_usbd_msc[busid].csw, sizeof(struct CSW));
+}
+
+static void usbd_msc_send_info(uint8_t busid, uint8_t *buffer, uint8_t size)
+{
+    size = MIN(size, g_usbd_msc[busid].cbw.dDataLength);
+
+    /* updating the State Machine , so that we send CSW when this
+	 * transfer is complete, ie when we get a bulk in callback
+	 */
+    g_usbd_msc[busid].stage = MSC_SEND_CSW;
+
+    usbd_ep_start_write(busid, mass_ep_data[busid][MSD_IN_EP_IDX].ep_addr, buffer, size);
+
+    g_usbd_msc[busid].csw.dDataResidue -= size;
+    g_usbd_msc[busid].csw.bStatus = CSW_STATUS_CMD_PASSED;
+}
+
+static bool SCSI_processWrite(uint8_t busid, uint32_t nbytes);
+static bool SCSI_processRead(uint8_t busid);
+
+/**
+* @brief  SCSI_SetSenseData
+*         Load the last error code in the error list
+* @param  sKey: Sense Key
+* @param  ASC: Additional Sense Code
+* @retval none
+
+*/
+static void SCSI_SetSenseData(uint8_t busid, uint32_t KCQ)
+{
+    g_usbd_msc[busid].sKey = (uint8_t)(KCQ >> 16);
+    g_usbd_msc[busid].ASC = (uint8_t)(KCQ >> 8);
+    g_usbd_msc[busid].ASQ = (uint8_t)(KCQ);
+}
+
+/**
+ * @brief SCSI Command list
+ *
+ */
+
+static bool SCSI_testUnitReady(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    if (g_usbd_msc[busid].cbw.dDataLength != 0U) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+    *data = NULL;
+    *len = 0;
+    return true;
+}
+
+static bool SCSI_requestSense(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    uint8_t data_len = SCSIRESP_FIXEDSENSEDATA_SIZEOF;
+    if (g_usbd_msc[busid].cbw.dDataLength == 0U) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+
+    if (g_usbd_msc[busid].cbw.CB[4] < SCSIRESP_FIXEDSENSEDATA_SIZEOF) {
+        data_len = g_usbd_msc[busid].cbw.CB[4];
+    }
+
+    uint8_t request_sense[SCSIRESP_FIXEDSENSEDATA_SIZEOF] = {
+        0x70,
+        0x00,
+        0x00, /* Sense Key */
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        SCSIRESP_FIXEDSENSEDATA_SIZEOF - 8,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00, /* Additional Sense Code */
+        0x00, /* Additional Sense Request */
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+    };
+
+    request_sense[2] = g_usbd_msc[busid].sKey;
+    request_sense[12] = g_usbd_msc[busid].ASC;
+    request_sense[13] = g_usbd_msc[busid].ASQ;
+#if 0
+    request_sense[ 2] = 0x06;           /* UNIT ATTENTION */
+    request_sense[12] = 0x28;           /* Additional Sense Code: Not ready to ready transition */
+    request_sense[13] = 0x00;           /* Additional Sense Code Qualifier */
+#endif
+#if 0
+    request_sense[ 2] = 0x02;           /* NOT READY */
+    request_sense[12] = 0x3A;           /* Additional Sense Code: Medium not present */
+    request_sense[13] = 0x00;           /* Additional Sense Code Qualifier */
+#endif
+#if 0
+    request_sense[ 2] = 0x05;         /* ILLEGAL REQUEST */
+    request_sense[12] = 0x20;         /* Additional Sense Code: Invalid command */
+    request_sense[13] = 0x00;         /* Additional Sense Code Qualifier */
+#endif
+#if 0
+    request_sense[ 2] = 0x00;         /* NO SENSE */
+    request_sense[12] = 0x00;         /* Additional Sense Code: No additional code */
+    request_sense[13] = 0x00;         /* Additional Sense Code Qualifier */
+#endif
+
+    memcpy(*data, (uint8_t *)request_sense, data_len);
+    *len = data_len;
+    return true;
+}
+
+static bool SCSI_inquiry(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    uint8_t data_len = SCSIRESP_INQUIRY_SIZEOF;
+
+    uint8_t inquiry00[6] = {
+        0x00,
+        0x00,
+        0x00,
+        (0x06 - 4U),
+        0x00,
+        0x80
+    };
+
+    /* USB Mass storage VPD Page 0x80 Inquiry Data for Unit Serial Number */
+    uint8_t inquiry80[8] = {
+        0x00,
+        0x80,
+        0x00,
+        0x08,
+        0x20, /* Put Product Serial number */
+        0x20,
+        0x20,
+        0x20
+    };
+
+    uint8_t inquiry[SCSIRESP_INQUIRY_SIZEOF] = {
+        /* 36 */
+
+        /* LUN 0 */
+        0x00,
+        0x80,
+        0x02,
+        0x02,
+        (SCSIRESP_INQUIRY_SIZEOF - 5),
+        0x00,
+        0x00,
+        0x00,
+        ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
+        ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', /* Product      : 16 Bytes */
+        ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+        ' ', ' ', ' ', ' ' /* Version      : 4 Bytes */
+    };
+
+    memcpy(&inquiry[8], CONFIG_USBDEV_MSC_MANUFACTURER_STRING, strlen(CONFIG_USBDEV_MSC_MANUFACTURER_STRING));
+    memcpy(&inquiry[16], CONFIG_USBDEV_MSC_PRODUCT_STRING, strlen(CONFIG_USBDEV_MSC_PRODUCT_STRING));
+    memcpy(&inquiry[32], CONFIG_USBDEV_MSC_VERSION_STRING, strlen(CONFIG_USBDEV_MSC_VERSION_STRING));
+
+    if (g_usbd_msc[busid].cbw.dDataLength == 0U) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+
+    if ((g_usbd_msc[busid].cbw.CB[1] & 0x01U) != 0U) { /* Evpd is set */
+        if (g_usbd_msc[busid].cbw.CB[2] == 0U) {       /* Request for Supported Vital Product Data Pages*/
+            data_len = 0x06;
+            memcpy(*data, (uint8_t *)inquiry00, data_len);
+        } else if (g_usbd_msc[busid].cbw.CB[2] == 0x80U) { /* Request for VPD page 0x80 Unit Serial Number */
+            data_len = 0x08;
+            memcpy(*data, (uint8_t *)inquiry80, data_len);
+        } else { /* Request Not supported */
+            SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDFIELDINCBA);
+            return false;
+        }
+    } else {
+        if (g_usbd_msc[busid].cbw.CB[4] < SCSIRESP_INQUIRY_SIZEOF) {
+            data_len = g_usbd_msc[busid].cbw.CB[4];
+        }
+        memcpy(*data, (uint8_t *)inquiry, data_len);
+    }
+
+    *len = data_len;
+    return true;
+}
+
+static bool SCSI_startStopUnit(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    if (g_usbd_msc[busid].cbw.dDataLength != 0U) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+
+    if ((g_usbd_msc[busid].cbw.CB[4] & 0x3U) == 0x1U) /* START=1 */
+    {
+        //SCSI_MEDIUM_UNLOCKED;
+    } else if ((g_usbd_msc[busid].cbw.CB[4] & 0x3U) == 0x2U) /* START=0 and LOEJ Load Eject=1 */
+    {
+        //SCSI_MEDIUM_EJECTED;
+        g_usbd_msc[busid].popup = true;
+    } else if ((g_usbd_msc[busid].cbw.CB[4] & 0x3U) == 0x3U) /* START=1 and LOEJ Load Eject=1 */
+    {
+        //SCSI_MEDIUM_UNLOCKED;
+    } else {
+    }
+
+    *data = NULL;
+    *len = 0;
+    return true;
+}
+
+static bool SCSI_preventAllowMediaRemoval(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    if (g_usbd_msc[busid].cbw.dDataLength != 0U) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+    if (g_usbd_msc[busid].cbw.CB[4] == 0U) {
+        //SCSI_MEDIUM_UNLOCKED;
+    } else {
+        //SCSI_MEDIUM_LOCKED;
+    }
+    *data = NULL;
+    *len = 0;
+    return true;
+}
+
+static bool SCSI_modeSense6(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    uint8_t data_len = 4;
+    if (g_usbd_msc[busid].cbw.dDataLength == 0U) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+    if (g_usbd_msc[busid].cbw.CB[4] < SCSIRESP_MODEPARAMETERHDR6_SIZEOF) {
+        data_len = g_usbd_msc[busid].cbw.CB[4];
+    }
+
+    uint8_t sense6[SCSIRESP_MODEPARAMETERHDR6_SIZEOF] = { 0x03, 0x00, 0x00, 0x00 };
+
+    if (g_usbd_msc[busid].readonly) {
+        sense6[2] = 0x80;
+    }
+    memcpy(*data, (uint8_t *)sense6, data_len);
+    *len = data_len;
+    return true;
+}
+
+static bool SCSI_modeSense10(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    uint8_t data_len = 27;
+    if (g_usbd_msc[busid].cbw.dDataLength == 0U) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+
+    if (g_usbd_msc[busid].cbw.CB[8] < 27) {
+        data_len = g_usbd_msc[busid].cbw.CB[8];
+    }
+
+    uint8_t sense10[27] = {
+        0x00,
+        0x26,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x08,
+        0x12,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00,
+        0x00
+    };
+
+    memcpy(*data, (uint8_t *)sense10, data_len);
+    *len = data_len;
+    return true;
+}
+
+static bool SCSI_readFormatCapacity(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    if (g_usbd_msc[busid].cbw.dDataLength == 0U) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+    uint8_t format_capacity[SCSIRESP_READFORMATCAPACITIES_SIZEOF] = {
+        0x00,
+        0x00,
+        0x00,
+        0x08, /* Capacity List Length */
+        (uint8_t)((g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN] >> 24) & 0xff),
+        (uint8_t)((g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN] >> 16) & 0xff),
+        (uint8_t)((g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN] >> 8) & 0xff),
+        (uint8_t)((g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN] >> 0) & 0xff),
+
+        0x02, /* Descriptor Code: Formatted Media */
+        0x00,
+        (uint8_t)((g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN] >> 8) & 0xff),
+        (uint8_t)((g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN] >> 0) & 0xff),
+    };
+
+    memcpy(*data, (uint8_t *)format_capacity, SCSIRESP_READFORMATCAPACITIES_SIZEOF);
+    *len = SCSIRESP_READFORMATCAPACITIES_SIZEOF;
+    return true;
+}
+
+static bool SCSI_readCapacity10(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    if (g_usbd_msc[busid].cbw.dDataLength == 0U) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+
+    uint8_t capacity10[SCSIRESP_READCAPACITY10_SIZEOF] = {
+        (uint8_t)(((g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN] - 1) >> 24) & 0xff),
+        (uint8_t)(((g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN] - 1) >> 16) & 0xff),
+        (uint8_t)(((g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN] - 1) >> 8) & 0xff),
+        (uint8_t)(((g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN] - 1) >> 0) & 0xff),
+
+        (uint8_t)((g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN] >> 24) & 0xff),
+        (uint8_t)((g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN] >> 16) & 0xff),
+        (uint8_t)((g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN] >> 8) & 0xff),
+        (uint8_t)((g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN] >> 0) & 0xff),
+    };
+
+    memcpy(*data, (uint8_t *)capacity10, SCSIRESP_READCAPACITY10_SIZEOF);
+    *len = SCSIRESP_READCAPACITY10_SIZEOF;
+    return true;
+}
+
+static bool SCSI_read10(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    if (((g_usbd_msc[busid].cbw.bmFlags & 0x80U) != 0x80U) || (g_usbd_msc[busid].cbw.dDataLength == 0U)) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+
+    g_usbd_msc[busid].start_sector = GET_BE32(&g_usbd_msc[busid].cbw.CB[2]); /* Logical Block Address of First Block */
+    USB_LOG_DBG("lba: 0x%04x\r\n", g_usbd_msc[busid].start_sector);
+
+    g_usbd_msc[busid].nsectors = GET_BE16(&g_usbd_msc[busid].cbw.CB[7]); /* Number of Blocks to transfer */
+    USB_LOG_DBG("nsectors: 0x%02x\r\n", g_usbd_msc[busid].nsectors);
+
+    if ((g_usbd_msc[busid].start_sector + g_usbd_msc[busid].nsectors) > g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN]) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_LBAOUTOFRANGE);
+        USB_LOG_ERR("LBA out of range\r\n");
+        return false;
+    }
+
+    if (g_usbd_msc[busid].cbw.dDataLength != (g_usbd_msc[busid].nsectors * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN])) {
+        USB_LOG_ERR("scsi_blk_len does not match with dDataLength\r\n");
+        return false;
+    }
+    g_usbd_msc[busid].stage = MSC_DATA_IN;
+#ifdef CONFIG_USBDEV_MSC_THREAD
+    usb_osal_mq_send(g_usbd_msc[busid].usbd_msc_mq, MSC_DATA_IN);
+    return true;
+#else
+    return SCSI_processRead(busid);
+#endif
+}
+
+static bool SCSI_read12(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    if (((g_usbd_msc[busid].cbw.bmFlags & 0x80U) != 0x80U) || (g_usbd_msc[busid].cbw.dDataLength == 0U)) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+
+    g_usbd_msc[busid].start_sector = GET_BE32(&g_usbd_msc[busid].cbw.CB[2]); /* Logical Block Address of First Block */
+    USB_LOG_DBG("lba: 0x%04x\r\n", g_usbd_msc[busid].start_sector);
+
+    g_usbd_msc[busid].nsectors = GET_BE32(&g_usbd_msc[busid].cbw.CB[6]); /* Number of Blocks to transfer */
+    USB_LOG_DBG("nsectors: 0x%02x\r\n", g_usbd_msc[busid].nsectors);
+
+    if ((g_usbd_msc[busid].start_sector + g_usbd_msc[busid].nsectors) > g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN]) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_LBAOUTOFRANGE);
+        USB_LOG_ERR("LBA out of range\r\n");
+        return false;
+    }
+
+    if (g_usbd_msc[busid].cbw.dDataLength != (g_usbd_msc[busid].nsectors * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN])) {
+        USB_LOG_ERR("scsi_blk_len does not match with dDataLength\r\n");
+        return false;
+    }
+    g_usbd_msc[busid].stage = MSC_DATA_IN;
+#ifdef CONFIG_USBDEV_MSC_THREAD
+    usb_osal_mq_send(g_usbd_msc[busid].usbd_msc_mq, MSC_DATA_IN);
+    return true;
+#else
+    return SCSI_processRead(busid);
+#endif
+}
+
+static bool SCSI_write10(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    uint32_t data_len = 0;
+    if (((g_usbd_msc[busid].cbw.bmFlags & 0x80U) != 0x00U) || (g_usbd_msc[busid].cbw.dDataLength == 0U)) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+
+    g_usbd_msc[busid].start_sector = GET_BE32(&g_usbd_msc[busid].cbw.CB[2]); /* Logical Block Address of First Block */
+    USB_LOG_DBG("lba: 0x%04x\r\n", g_usbd_msc[busid].start_sector);
+
+    g_usbd_msc[busid].nsectors = GET_BE16(&g_usbd_msc[busid].cbw.CB[7]); /* Number of Blocks to transfer */
+    USB_LOG_DBG("nsectors: 0x%02x\r\n", g_usbd_msc[busid].nsectors);
+
+    data_len = g_usbd_msc[busid].nsectors * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN];
+    if ((g_usbd_msc[busid].start_sector + g_usbd_msc[busid].nsectors) > g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN]) {
+        USB_LOG_ERR("LBA out of range\r\n");
+        return false;
+    }
+
+    if (g_usbd_msc[busid].cbw.dDataLength != data_len) {
+        return false;
+    }
+    g_usbd_msc[busid].stage = MSC_DATA_OUT;
+    data_len = MIN(data_len, CONFIG_USBDEV_MSC_MAX_BUFSIZE);
+    usbd_ep_start_read(busid, mass_ep_data[busid][MSD_OUT_EP_IDX].ep_addr, g_usbd_msc[busid].block_buffer, data_len);
+    return true;
+}
+
+static bool SCSI_write12(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    uint32_t data_len = 0;
+    if (((g_usbd_msc[busid].cbw.bmFlags & 0x80U) != 0x00U) || (g_usbd_msc[busid].cbw.dDataLength == 0U)) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+
+    g_usbd_msc[busid].start_sector = GET_BE32(&g_usbd_msc[busid].cbw.CB[2]); /* Logical Block Address of First Block */
+    USB_LOG_DBG("lba: 0x%04x\r\n", g_usbd_msc[busid].start_sector);
+
+    g_usbd_msc[busid].nsectors = GET_BE32(&g_usbd_msc[busid].cbw.CB[6]); /* Number of Blocks to transfer */
+    USB_LOG_DBG("nsectors: 0x%02x\r\n", g_usbd_msc[busid].nsectors);
+
+    data_len = g_usbd_msc[busid].nsectors * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN];
+    if ((g_usbd_msc[busid].start_sector + g_usbd_msc[busid].nsectors) > g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN]) {
+        USB_LOG_ERR("LBA out of range\r\n");
+        return false;
+    }
+
+    if (g_usbd_msc[busid].cbw.dDataLength != data_len) {
+        return false;
+    }
+    g_usbd_msc[busid].stage = MSC_DATA_OUT;
+    data_len = MIN(data_len, CONFIG_USBDEV_MSC_MAX_BUFSIZE);
+    usbd_ep_start_read(busid, mass_ep_data[busid][MSD_OUT_EP_IDX].ep_addr, g_usbd_msc[busid].block_buffer, data_len);
+    return true;
+}
+/* do not use verify to reduce code size */
+#if 0
+static bool SCSI_verify10(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+    /* Logical Block Address of First Block */
+    uint32_t lba = 0;
+    uint32_t blk_num = 0;
+
+    if ((g_usbd_msc[busid].cbw.CB[1] & 0x02U) == 0x00U) {
+        return true;
+    }
+
+    if (((g_usbd_msc[busid].cbw.bmFlags & 0x80U) != 0x00U) || (g_usbd_msc[busid].cbw.dDataLength == 0U)) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+
+    if ((g_usbd_msc[busid].cbw.CB[1] & 0x02U) == 0x02U) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDFIELDINCBA);
+        return false; /* Error, Verify Mode Not supported*/
+    }
+
+    lba = GET_BE32(&g_usbd_msc[busid].cbw.CB[2]);
+    USB_LOG_DBG("lba: 0x%x\r\n", lba);
+
+    g_usbd_msc[busid].scsi_blk_addr = lba * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN];
+
+    /* Number of Blocks to transfer */
+    blk_num = GET_BE16(&g_usbd_msc[busid].cbw.CB[7]);
+
+    USB_LOG_DBG("num (block) : 0x%x\r\n", blk_num);
+    g_usbd_msc[busid].scsi_blk_len = blk_num * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN];
+
+    if ((lba + blk_num) > g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN]) {
+        USB_LOG_ERR("LBA out of range\r\n");
+        return false;
+    }
+
+    if (g_usbd_msc[busid].cbw.dDataLength != g_usbd_msc[busid].scsi_blk_len) {
+        return false;
+    }
+
+    g_usbd_msc[busid].stage = MSC_DATA_OUT;
+    return true;
+}
+#endif
+
+static bool SCSI_processRead(uint8_t busid)
+{
+    uint32_t transfer_len;
+
+    USB_LOG_DBG("read lba:%d\r\n", g_usbd_msc[busid].start_sector);
+
+    transfer_len = MIN(g_usbd_msc[busid].nsectors * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN], CONFIG_USBDEV_MSC_MAX_BUFSIZE);
+
+    if (usbd_msc_sector_read(busid, g_usbd_msc[busid].cbw.bLUN, g_usbd_msc[busid].start_sector, g_usbd_msc[busid].block_buffer, transfer_len) != 0) {
+        SCSI_SetSenseData(busid, SCSI_KCQHE_UREINRESERVEDAREA);
+        return false;
+    }
+
+    g_usbd_msc[busid].start_sector += (transfer_len / g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN]);
+    g_usbd_msc[busid].nsectors -= (transfer_len / g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN]);
+    g_usbd_msc[busid].csw.dDataResidue -= transfer_len;
+
+    if (g_usbd_msc[busid].nsectors == 0) {
+        g_usbd_msc[busid].stage = MSC_SEND_CSW;
+    }
+
+    usbd_ep_start_write(busid, mass_ep_data[busid][MSD_IN_EP_IDX].ep_addr, g_usbd_msc[busid].block_buffer, transfer_len);
+
+    return true;
+}
+
+static bool SCSI_processWrite(uint8_t busid, uint32_t nbytes)
+{
+    uint32_t data_len = 0;
+    USB_LOG_DBG("write lba:%d\r\n", g_usbd_msc[busid].start_sector);
+
+    if (usbd_msc_sector_write(busid, g_usbd_msc[busid].cbw.bLUN, g_usbd_msc[busid].start_sector, g_usbd_msc[busid].block_buffer, nbytes) != 0) {
+        SCSI_SetSenseData(busid, SCSI_KCQHE_WRITEFAULT);
+        return false;
+    }
+
+    g_usbd_msc[busid].start_sector += (nbytes / g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN]);
+    g_usbd_msc[busid].nsectors -= (nbytes / g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN]);
+    g_usbd_msc[busid].csw.dDataResidue -= nbytes;
+
+    if (g_usbd_msc[busid].nsectors == 0) {
+        usbd_msc_send_csw(busid, CSW_STATUS_CMD_PASSED);
+    } else {
+        data_len = MIN(g_usbd_msc[busid].nsectors * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN], CONFIG_USBDEV_MSC_MAX_BUFSIZE);
+        usbd_ep_start_read(busid, mass_ep_data[busid][MSD_OUT_EP_IDX].ep_addr, g_usbd_msc[busid].block_buffer, data_len);
+    }
+
+    return true;
+}
+
+static bool SCSI_CBWDecode(uint8_t busid, uint32_t nbytes)
+{
+    uint8_t *buf2send = g_usbd_msc[busid].block_buffer;
+    uint32_t len2send = 0;
+    bool ret = false;
+
+    if (nbytes != sizeof(struct CBW)) {
+        USB_LOG_ERR("size != sizeof(cbw)\r\n");
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    }
+
+    g_usbd_msc[busid].csw.dTag = g_usbd_msc[busid].cbw.dTag;
+    g_usbd_msc[busid].csw.dDataResidue = g_usbd_msc[busid].cbw.dDataLength;
+
+    if ((g_usbd_msc[busid].cbw.dSignature != MSC_CBW_Signature) || (g_usbd_msc[busid].cbw.bCBLength < 1) || (g_usbd_msc[busid].cbw.bCBLength > 16)) {
+        SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+        return false;
+    } else {
+        USB_LOG_DBG("Decode CB:0x%02x\r\n", g_usbd_msc[busid].cbw.CB[0]);
+        switch (g_usbd_msc[busid].cbw.CB[0]) {
+            case SCSI_CMD_TESTUNITREADY:
+                ret = SCSI_testUnitReady(busid, &buf2send, &len2send);
+                break;
+            case SCSI_CMD_REQUESTSENSE:
+                ret = SCSI_requestSense(busid, &buf2send, &len2send);
+                break;
+            case SCSI_CMD_INQUIRY:
+                ret = SCSI_inquiry(busid, &buf2send, &len2send);
+                break;
+            case SCSI_CMD_STARTSTOPUNIT:
+                ret = SCSI_startStopUnit(busid, &buf2send, &len2send);
+                break;
+            case SCSI_CMD_PREVENTMEDIAREMOVAL:
+                ret = SCSI_preventAllowMediaRemoval(busid, &buf2send, &len2send);
+                break;
+            case SCSI_CMD_MODESENSE6:
+                ret = SCSI_modeSense6(busid, &buf2send, &len2send);
+                break;
+            case SCSI_CMD_MODESENSE10:
+                ret = SCSI_modeSense10(busid, &buf2send, &len2send);
+                break;
+            case SCSI_CMD_READFORMATCAPACITIES:
+                ret = SCSI_readFormatCapacity(busid, &buf2send, &len2send);
+                break;
+            case SCSI_CMD_READCAPACITY10:
+                ret = SCSI_readCapacity10(busid, &buf2send, &len2send);
+                break;
+            case SCSI_CMD_READ10:
+                ret = SCSI_read10(busid, NULL, 0);
+                break;
+            case SCSI_CMD_READ12:
+                ret = SCSI_read12(busid, NULL, 0);
+                break;
+            case SCSI_CMD_WRITE10:
+                ret = SCSI_write10(busid, NULL, 0);
+                break;
+            case SCSI_CMD_WRITE12:
+                ret = SCSI_write12(busid, NULL, 0);
+                break;
+            case SCSI_CMD_VERIFY10:
+                //ret = SCSI_verify10(NULL, 0);
+                ret = false;
+                break;
+
+            default:
+                SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+                USB_LOG_WRN("unsupported cmd:0x%02x\r\n", g_usbd_msc[busid].cbw.CB[0]);
+                ret = false;
+                break;
+        }
+    }
+    if (ret) {
+        if (g_usbd_msc[busid].stage == MSC_READ_CBW) {
+            if (len2send) {
+                USB_LOG_DBG("Send info len:%d\r\n", len2send);
+                usbd_msc_send_info(busid, buf2send, len2send);
+            } else {
+                usbd_msc_send_csw(busid, CSW_STATUS_CMD_PASSED);
+            }
+        }
+    }
+    return ret;
+}
+
+void mass_storage_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+    switch (g_usbd_msc[busid].stage) {
+        case MSC_READ_CBW:
+            if (SCSI_CBWDecode(busid, nbytes) == false) {
+                USB_LOG_ERR("Command:0x%02x decode err\r\n", g_usbd_msc[busid].cbw.CB[0]);
+                usbd_msc_bot_abort(busid);
+                return;
+            }
+            break;
+        case MSC_DATA_OUT:
+            switch (g_usbd_msc[busid].cbw.CB[0]) {
+                case SCSI_CMD_WRITE10:
+                case SCSI_CMD_WRITE12:
+#ifdef CONFIG_USBDEV_MSC_THREAD
+                    g_usbd_msc[busid].nbytes = nbytes;
+                    usb_osal_mq_send(g_usbd_msc[busid].usbd_msc_mq, MSC_DATA_OUT);
+#else
+                    if (SCSI_processWrite(busid, nbytes) == false) {
+                        usbd_msc_send_csw(busid, CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
+                    }
+#endif
+                    break;
+                default:
+                    break;
+            }
+            break;
+        default:
+            break;
+    }
+}
+
+void mass_storage_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+    switch (g_usbd_msc[busid].stage) {
+        case MSC_DATA_IN:
+            switch (g_usbd_msc[busid].cbw.CB[0]) {
+                case SCSI_CMD_READ10:
+                case SCSI_CMD_READ12:
+#ifdef CONFIG_USBDEV_MSC_THREAD
+                    usb_osal_mq_send(g_usbd_msc[busid].usbd_msc_mq, MSC_DATA_IN);
+#else
+                    if (SCSI_processRead(busid) == false) {
+                        usbd_msc_send_csw(busid, CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
+                        return;
+                    }
+#endif
+                    break;
+                default:
+                    break;
+            }
+            break;
+        /*the device has to send a CSW*/
+        case MSC_SEND_CSW:
+            usbd_msc_send_csw(busid, CSW_STATUS_CMD_PASSED);
+            break;
+
+        /*the host has received the CSW*/
+        case MSC_WAIT_CSW:
+            g_usbd_msc[busid].stage = MSC_READ_CBW;
+            USB_LOG_DBG("Start reading cbw\r\n");
+            usbd_ep_start_read(busid, mass_ep_data[busid][MSD_OUT_EP_IDX].ep_addr, (uint8_t *)&g_usbd_msc[busid].cbw, USB_SIZEOF_MSC_CBW);
+            break;
+
+        default:
+            break;
+    }
+}
+
+#ifdef CONFIG_USBDEV_MSC_THREAD
+static void usbdev_msc_thread(void *argument)
+{
+    uintptr_t event;
+    int ret;
+    uint8_t busid = (uint8_t)argument;
+
+    while (1) {
+        ret = usb_osal_mq_recv(g_usbd_msc[busid].usbd_msc_mq, (uintptr_t *)&event, USB_OSAL_WAITING_FOREVER);
+        if (ret < 0) {
+            continue;
+        }
+        USB_LOG_DBG("%d\r\n", event);
+        if (event == MSC_DATA_OUT) {
+            if (SCSI_processWrite(busid, g_usbd_msc[busid].nbytes) == false) {
+                usbd_msc_send_csw(busid, CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
+            }
+        } else if (event == MSC_DATA_IN) {
+            if (SCSI_processRead(busid) == false) {
+                usbd_msc_send_csw(busid, CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
+            }
+        } else {
+        }
+    }
+}
+#endif
+
+struct usbd_interface *usbd_msc_init_intf(uint8_t busid, struct usbd_interface *intf, const uint8_t out_ep, const uint8_t in_ep)
+{
+    intf->class_interface_handler = msc_storage_class_interface_request_handler;
+    intf->class_endpoint_handler = NULL;
+    intf->vendor_handler = NULL;
+    intf->notify_handler = msc_storage_notify_handler;
+
+    mass_ep_data[busid][MSD_OUT_EP_IDX].ep_addr = out_ep;
+    mass_ep_data[busid][MSD_OUT_EP_IDX].ep_cb = mass_storage_bulk_out;
+    mass_ep_data[busid][MSD_IN_EP_IDX].ep_addr = in_ep;
+    mass_ep_data[busid][MSD_IN_EP_IDX].ep_cb = mass_storage_bulk_in;
+
+    usbd_add_endpoint(busid, &mass_ep_data[busid][MSD_OUT_EP_IDX]);
+    usbd_add_endpoint(busid, &mass_ep_data[busid][MSD_IN_EP_IDX]);
+
+    memset((uint8_t *)&g_usbd_msc[busid], 0, sizeof(struct usbd_msc_priv));
+
+    usdb_msc_set_max_lun(busid);
+    for (uint8_t i = 0u; i <= g_usbd_msc[busid].max_lun; i++) {
+        usbd_msc_get_cap(busid, i, &g_usbd_msc[busid].scsi_blk_nbr[i], &g_usbd_msc[busid].scsi_blk_size[i]);
+
+        if (g_usbd_msc[busid].scsi_blk_size[i] > CONFIG_USBDEV_MSC_MAX_BUFSIZE) {
+            USB_LOG_ERR("msc block buffer overflow\r\n");
+            return NULL;
+        }
+    }
+
+    return intf;
+}
+
+void usbd_msc_set_readonly(uint8_t busid, bool readonly)
+{
+    g_usbd_msc[busid].readonly = readonly;
+}
+
+bool usbd_msc_set_popup(uint8_t busid)
+{
+    return g_usbd_msc[busid].popup;
+}

+ 32 - 0
components/drivers/usb/cherryusb/class/msc/usbd_msc.h

@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ * Copyright (c) 2024, zhihong chen
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_MSC_H
+#define USBD_MSC_H
+
+#include "usb_msc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Init msc interface driver */
+struct usbd_interface *usbd_msc_init_intf(uint8_t busid, struct usbd_interface *intf,
+                                          const uint8_t out_ep,
+                                          const uint8_t in_ep);
+
+void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint32_t *block_size);
+int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length);
+int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length);
+
+void usbd_msc_set_readonly(uint8_t busid, bool readonly);
+bool usbd_msc_set_popup(uint8_t busid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBD_MSC_H */

+ 436 - 0
components/drivers/usb/cherryusb/class/msc/usbh_msc.c

@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_msc.h"
+#include "usb_scsi.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "usbh_msc"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/sd%c"
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_msc_buf[64];
+
+static struct usbh_msc g_msc_class[CONFIG_USBHOST_MAX_MSC_CLASS];
+static uint32_t g_devinuse = 0;
+static struct usbh_msc_modeswitch_config *g_msc_modeswitch_config = NULL;
+
+static struct usbh_msc *usbh_msc_class_alloc(void)
+{
+    int devno;
+
+    for (devno = 0; devno < CONFIG_USBHOST_MAX_MSC_CLASS; devno++) {
+        if ((g_devinuse & (1 << devno)) == 0) {
+            g_devinuse |= (1 << devno);
+            memset(&g_msc_class[devno], 0, sizeof(struct usbh_msc));
+            g_msc_class[devno].sdchar = 'a' + devno;
+            return &g_msc_class[devno];
+        }
+    }
+    return NULL;
+}
+
+static void usbh_msc_class_free(struct usbh_msc *msc_class)
+{
+    int devno = msc_class->sdchar - 'a';
+
+    if (devno >= 0 && devno < 32) {
+        g_devinuse &= ~(1 << devno);
+    }
+    memset(msc_class, 0, sizeof(struct usbh_msc));
+}
+
+static int usbh_msc_get_maxlun(struct usbh_msc *msc_class, uint8_t *buffer)
+{
+    struct usb_setup_packet *setup = msc_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = MSC_REQUEST_GET_MAX_LUN;
+    setup->wValue = 0;
+    setup->wIndex = msc_class->intf;
+    setup->wLength = 1;
+
+    return usbh_control_transfer(msc_class->hport, setup, buffer);
+}
+
+static void usbh_msc_cbw_dump(struct CBW *cbw)
+{
+    int i;
+
+    USB_LOG_DBG("CBW:\r\n");
+    USB_LOG_DBG("  signature: 0x%08x\r\n", (unsigned int)cbw->dSignature);
+    USB_LOG_DBG("  tag:       0x%08x\r\n", (unsigned int)cbw->dTag);
+    USB_LOG_DBG("  datlen:    0x%08x\r\n", (unsigned int)cbw->dDataLength);
+    USB_LOG_DBG("  flags:     0x%02x\r\n", cbw->bmFlags);
+    USB_LOG_DBG("  lun:       0x%02x\r\n", cbw->bLUN);
+    USB_LOG_DBG("  cblen:    0x%02x\r\n", cbw->bCBLength);
+
+    USB_LOG_DBG("CB:\r\n");
+    for (i = 0; i < cbw->bCBLength; i += 8) {
+        USB_LOG_DBG("  0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\r\n",
+                    cbw->CB[i], cbw->CB[i + 1], cbw->CB[i + 2],
+                    cbw->CB[i + 3], cbw->CB[i + 4], cbw->CB[i + 5],
+                    cbw->CB[i + 6], cbw->CB[i + 7]);
+    }
+}
+
+static void usbh_msc_csw_dump(struct CSW *csw)
+{
+    USB_LOG_DBG("CSW:\r\n");
+    USB_LOG_DBG("  signature: 0x%08x\r\n", (unsigned int)csw->dSignature);
+    USB_LOG_DBG("  tag:       0x%08x\r\n", (unsigned int)csw->dTag);
+    USB_LOG_DBG("  residue:   0x%08x\r\n", (unsigned int)csw->dDataResidue);
+    USB_LOG_DBG("  status:    0x%02x\r\n", csw->bStatus);
+}
+
+static inline int usbh_msc_bulk_in_transfer(struct usbh_msc *msc_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+{
+    int ret;
+    struct usbh_urb *urb = &msc_class->bulkin_urb;
+
+    usbh_bulk_urb_fill(urb, msc_class->hport, msc_class->bulkin, buffer, buflen, timeout, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+static inline int usbh_msc_bulk_out_transfer(struct usbh_msc *msc_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+{
+    int ret;
+    struct usbh_urb *urb = &msc_class->bulkout_urb;
+
+    usbh_bulk_urb_fill(urb, msc_class->hport, msc_class->bulkout, buffer, buflen, timeout, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+static int usbh_bulk_cbw_csw_xfer(struct usbh_msc *msc_class, struct CBW *cbw, struct CSW *csw, uint8_t *buffer)
+{
+    int nbytes;
+
+    usbh_msc_cbw_dump(cbw);
+
+    /* Send the CBW */
+    nbytes = usbh_msc_bulk_out_transfer(msc_class, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
+    if (nbytes < 0) {
+        USB_LOG_ERR("cbw transfer error\r\n");
+        goto __err_exit;
+    }
+
+    if (cbw->dDataLength != 0) {
+        if (cbw->CB[0] == SCSI_CMD_WRITE10) {
+            nbytes = usbh_msc_bulk_out_transfer(msc_class, buffer, cbw->dDataLength, CONFIG_USBHOST_MSC_TIMEOUT);
+        } else if (cbw->CB[0] == SCSI_CMD_READCAPACITY10) {
+            nbytes = usbh_msc_bulk_in_transfer(msc_class, buffer, cbw->dDataLength, CONFIG_USBHOST_MSC_TIMEOUT);
+            if (nbytes >= 0) {
+                /* Save the capacity information */
+                msc_class->blocknum = GET_BE32(&buffer[0]) + 1;
+                msc_class->blocksize = GET_BE32(&buffer[4]);
+            }
+        } else {
+            nbytes = usbh_msc_bulk_in_transfer(msc_class, buffer, cbw->dDataLength, CONFIG_USBHOST_MSC_TIMEOUT);
+        }
+
+        if (nbytes < 0) {
+            USB_LOG_ERR("msc data transfer error\r\n");
+            goto __err_exit;
+        }
+    }
+
+    /* Receive the CSW */
+    memset(csw, 0, USB_SIZEOF_MSC_CSW);
+    nbytes = usbh_msc_bulk_in_transfer(msc_class, (uint8_t *)csw, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
+    if (nbytes < 0) {
+        USB_LOG_ERR("csw transfer error\r\n");
+        goto __err_exit;
+    }
+
+    usbh_msc_csw_dump(csw);
+
+    /* check csw status */
+    if (csw->dSignature != MSC_CSW_Signature) {
+        USB_LOG_ERR("csw signature error\r\n");
+        return -USB_ERR_INVAL;
+    }
+
+    if (csw->bStatus != 0) {
+        USB_LOG_ERR("csw bStatus %d\r\n", csw->bStatus);
+        return -USB_ERR_INVAL;
+    }
+__err_exit:
+    return nbytes < 0 ? (int)nbytes : 0;
+}
+
+static inline int usbh_msc_scsi_testunitready(struct usbh_msc *msc_class)
+{
+    struct CBW *cbw;
+
+    /* Construct the CBW */
+    cbw = (struct CBW *)g_msc_buf;
+    memset(cbw, 0, USB_SIZEOF_MSC_CBW);
+    cbw->dSignature = MSC_CBW_Signature;
+
+    cbw->bCBLength = SCSICMD_TESTUNITREADY_SIZEOF;
+    cbw->CB[0] = SCSI_CMD_TESTUNITREADY;
+
+    return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, NULL);
+}
+
+static inline int usbh_msc_scsi_requestsense(struct usbh_msc *msc_class)
+{
+    struct CBW *cbw;
+
+    /* Construct the CBW */
+    cbw = (struct CBW *)g_msc_buf;
+    memset(cbw, 0, USB_SIZEOF_MSC_CBW);
+    cbw->dSignature = MSC_CBW_Signature;
+
+    cbw->bmFlags = 0x80;
+    cbw->dDataLength = SCSIRESP_FIXEDSENSEDATA_SIZEOF;
+    cbw->bCBLength = SCSICMD_REQUESTSENSE_SIZEOF;
+    cbw->CB[0] = SCSI_CMD_REQUESTSENSE;
+    cbw->CB[4] = SCSIRESP_FIXEDSENSEDATA_SIZEOF;
+
+    return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, g_msc_buf);
+}
+
+static inline int usbh_msc_scsi_inquiry(struct usbh_msc *msc_class)
+{
+    struct CBW *cbw;
+
+    /* Construct the CBW */
+    cbw = (struct CBW *)g_msc_buf;
+    memset(cbw, 0, USB_SIZEOF_MSC_CBW);
+    cbw->dSignature = MSC_CBW_Signature;
+
+    cbw->dDataLength = SCSIRESP_INQUIRY_SIZEOF;
+    cbw->bmFlags = 0x80;
+    cbw->bCBLength = SCSICMD_INQUIRY_SIZEOF;
+    cbw->CB[0] = SCSI_CMD_INQUIRY;
+    cbw->CB[4] = SCSIRESP_INQUIRY_SIZEOF;
+
+    return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, g_msc_buf);
+}
+
+static inline int usbh_msc_scsi_readcapacity10(struct usbh_msc *msc_class)
+{
+    struct CBW *cbw;
+
+    /* Construct the CBW */
+    cbw = (struct CBW *)g_msc_buf;
+    memset(cbw, 0, USB_SIZEOF_MSC_CBW);
+    cbw->dSignature = MSC_CBW_Signature;
+
+    cbw->dDataLength = SCSIRESP_READCAPACITY10_SIZEOF;
+    cbw->bmFlags = 0x80;
+    cbw->bCBLength = SCSICMD_READCAPACITY10_SIZEOF;
+    cbw->CB[0] = SCSI_CMD_READCAPACITY10;
+
+    return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, g_msc_buf);
+}
+
+static inline void usbh_msc_modeswitch(struct usbh_msc *msc_class, const uint8_t *message)
+{
+    struct CBW *cbw;
+
+    /* Construct the CBW */
+    cbw = (struct CBW *)g_msc_buf;
+
+    memcpy(g_msc_buf, message, 31);
+
+    usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, NULL);
+}
+
+static int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret;
+    struct usbh_msc_modeswitch_config *config;
+
+    struct usbh_msc *msc_class = usbh_msc_class_alloc();
+    if (msc_class == NULL) {
+        USB_LOG_ERR("Fail to alloc msc_class\r\n");
+        return -USB_ERR_NOMEM;
+    }
+
+    msc_class->hport = hport;
+    msc_class->intf = intf;
+
+    hport->config.intf[intf].priv = msc_class;
+
+    ret = usbh_msc_get_maxlun(msc_class, g_msc_buf);
+    if (ret < 0) {
+        return ret;
+    }
+
+    USB_LOG_INFO("Get max LUN:%u\r\n", g_msc_buf[0] + 1);
+
+    for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
+        ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
+        if (ep_desc->bEndpointAddress & 0x80) {
+            USBH_EP_INIT(msc_class->bulkin, ep_desc);
+        } else {
+            USBH_EP_INIT(msc_class->bulkout, ep_desc);
+        }
+    }
+
+    if (g_msc_modeswitch_config) {
+        uint8_t num = 0;
+        while (1) {
+            config = &g_msc_modeswitch_config[num];
+            if (config && config->name) {
+                if ((hport->device_desc.idVendor == config->vid) &&
+                    (hport->device_desc.idProduct == config->pid)) {
+                    USB_LOG_INFO("%s usb_modeswitch enable\r\n", config->name);
+                    usbh_msc_modeswitch(msc_class, config->message_content);
+                    return 0;
+                }
+                num++;
+            } else {
+                break;
+            }
+        }
+    }
+
+    ret = usbh_msc_scsi_testunitready(msc_class);
+    if (ret < 0) {
+        ret = usbh_msc_scsi_requestsense(msc_class);
+        if (ret < 0) {
+            USB_LOG_ERR("Fail to scsi_testunitready\r\n");
+            return ret;
+        }
+    }
+
+    ret = usbh_msc_scsi_inquiry(msc_class);
+    if (ret < 0) {
+        USB_LOG_ERR("Fail to scsi_inquiry\r\n");
+        return ret;
+    }
+    ret = usbh_msc_scsi_readcapacity10(msc_class);
+    if (ret < 0) {
+        USB_LOG_ERR("Fail to scsi_readcapacity10\r\n");
+        return ret;
+    }
+
+    if (msc_class->blocksize > 0) {
+        USB_LOG_INFO("Capacity info:\r\n");
+        USB_LOG_INFO("Block num:%d,block size:%d\r\n", (unsigned int)msc_class->blocknum, (unsigned int)msc_class->blocksize);
+    } else {
+        USB_LOG_ERR("Invalid block size\r\n");
+        return -USB_ERR_RANGE;
+    }
+
+    snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, msc_class->sdchar);
+
+    USB_LOG_INFO("Register MSC Class:%s\r\n", hport->config.intf[intf].devname);
+
+    usbh_msc_run(msc_class);
+    return ret;
+}
+
+static int usbh_msc_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_msc *msc_class = (struct usbh_msc *)hport->config.intf[intf].priv;
+
+    if (msc_class) {
+        if (msc_class->bulkin) {
+            usbh_kill_urb(&msc_class->bulkin_urb);
+        }
+
+        if (msc_class->bulkout) {
+            usbh_kill_urb(&msc_class->bulkout_urb);
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister MSC Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_msc_stop(msc_class);
+        }
+
+        usbh_msc_class_free(msc_class);
+    }
+
+    return ret;
+}
+
+
+int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors)
+{
+    struct CBW *cbw;
+
+    /* Construct the CBW */
+    cbw = (struct CBW *)g_msc_buf;
+    memset(cbw, 0, USB_SIZEOF_MSC_CBW);
+    cbw->dSignature = MSC_CBW_Signature;
+
+    cbw->dDataLength = (msc_class->blocksize * nsectors);
+    cbw->bCBLength = SCSICMD_WRITE10_SIZEOF;
+    cbw->CB[0] = SCSI_CMD_WRITE10;
+
+    SET_BE32(&cbw->CB[2], start_sector);
+    SET_BE16(&cbw->CB[7], nsectors);
+
+    return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, (uint8_t *)buffer);
+}
+
+int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors)
+{
+    struct CBW *cbw;
+
+    /* Construct the CBW */
+    cbw = (struct CBW *)g_msc_buf;
+    memset(cbw, 0, USB_SIZEOF_MSC_CBW);
+    cbw->dSignature = MSC_CBW_Signature;
+
+    cbw->dDataLength = (msc_class->blocksize * nsectors);
+    cbw->bmFlags = 0x80;
+    cbw->bCBLength = SCSICMD_READ10_SIZEOF;
+    cbw->CB[0] = SCSI_CMD_READ10;
+
+    SET_BE32(&cbw->CB[2], start_sector);
+    SET_BE16(&cbw->CB[7], nsectors);
+
+    return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, (uint8_t *)buffer);
+}
+
+void usbh_msc_modeswitch_enable(struct usbh_msc_modeswitch_config *config)
+{
+    if (config) {
+        g_msc_modeswitch_config = config;
+    } else {
+        g_msc_modeswitch_config = NULL;
+    }
+}
+
+__WEAK void usbh_msc_run(struct usbh_msc *msc_class)
+{
+}
+
+__WEAK void usbh_msc_stop(struct usbh_msc *msc_class)
+{
+}
+
+const struct usbh_class_driver msc_class_driver = {
+    .driver_name = "msc",
+    .connect = usbh_msc_connect,
+    .disconnect = usbh_msc_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info msc_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
+    .class = USB_DEVICE_CLASS_MASS_STORAGE,
+    .subclass = MSC_SUBCLASS_SCSI,
+    .protocol = MSC_PROTOCOL_BULK_ONLY,
+    .id_table = NULL,
+    .class_driver = &msc_class_driver
+};

+ 49 - 0
components/drivers/usb/cherryusb/class/msc/usbh_msc.h

@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_MSC_H
+#define USBH_MSC_H
+
+#include "usb_msc.h"
+#include "usb_scsi.h"
+
+struct usbh_msc {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+    struct usbh_urb bulkin_urb;              /* Bulk IN urb */
+    struct usbh_urb bulkout_urb;             /* Bulk OUT urb */
+
+    uint8_t intf; /* Data interface number */
+    uint8_t sdchar;
+    uint32_t blocknum;  /* Number of blocks on the USB mass storage device */
+    uint16_t blocksize; /* Block size of USB mass storage device */
+
+    void *user_data;
+};
+
+struct usbh_msc_modeswitch_config {
+    const char *name;
+    uint16_t vid; /* Vendor ID (for vendor/product specific devices) */
+    uint16_t pid; /* Product ID (for vendor/product specific devices) */
+    const uint8_t *message_content;
+};
+
+void usbh_msc_modeswitch_enable(struct usbh_msc_modeswitch_config *config);
+int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors);
+int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors);
+
+void usbh_msc_run(struct usbh_msc *msc_class);
+void usbh_msc_stop(struct usbh_msc *msc_class);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_MSC_H */

+ 4 - 0
components/drivers/usb/cherryusb/class/template/usb_xxx.h

@@ -0,0 +1,4 @@
+#ifndef _USB_XXX_H
+#define _USB_XXX_H
+
+#endif

+ 39 - 0
components/drivers/usb/cherryusb/class/template/usbd_xxx.c

@@ -0,0 +1,39 @@
+#include "usbd_core.h"
+#include "usbd_xxx.h"
+
+static int xxx_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    USB_LOG_WRN("XXX Class request: "
+                 "bRequest 0x%02x\r\n",
+                 setup->bRequest);
+
+    switch (setup->bRequest) {
+        default:
+            USB_LOG_WRN("Unhandled XXX Class bRequest 0x%02x\r\n", setup->bRequest);
+            return -1;
+    }
+
+    return 0;
+}
+
+static void xxx_notify_handler(uint8_t busid, uint8_t event, void *arg)
+{
+    switch (event) {
+        case USBD_EVENT_RESET:
+
+            break;
+
+        default:
+            break;
+    }
+}
+
+struct usbd_interface *usbd_xxx_init_intf(uint8_t busid, struct usbd_interface *intf)
+{
+    intf->class_interface_handler = xxx_class_interface_request_handler;
+    intf->class_endpoint_handler = NULL;
+    intf->vendor_handler = NULL;
+    intf->notify_handler = xxx_notify_handler;
+
+    return intf;
+}

+ 16 - 0
components/drivers/usb/cherryusb/class/template/usbd_xxx.h

@@ -0,0 +1,16 @@
+#ifndef _USBD_XXX_H_
+#define _USBD_XXX_H_
+
+#include "usb_xxx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct usbd_interface *usbd_xxx_init_intf(uint8_t busid, struct usbd_interface *intf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _USBD_XXX_H_ */

+ 97 - 0
components/drivers/usb/cherryusb/class/template/usbh_xxx.c

@@ -0,0 +1,97 @@
+#include "usbh_core.h"
+#include "usbh_xxx.h"
+
+#define DEV_FORMAT "/dev/xxx"
+
+#define CONFIG_USBHOST_MAX_CUSTOM_CLASS 1
+static struct usbh_xxx g_xxx_class[CONFIG_USBHOST_MAX_CUSTOM_CLASS];
+static uint32_t g_devinuse = 0;
+
+static struct usbh_xxx *usbh_xxx_class_alloc(void)
+{
+    int devno;
+
+    for (devno = 0; devno < CONFIG_USBHOST_MAX_CUSTOM_CLASS; devno++) {
+        if ((g_devinuse & (1 << devno)) == 0) {
+            g_devinuse |= (1 << devno);
+            memset(&g_xxx_class[devno], 0, sizeof(struct usbh_xxx));
+            g_xxx_class[devno].minor = devno;
+            return &g_xxx_class[devno];
+        }
+    }
+    return NULL;
+}
+
+static void usbh_xxx_class_free(struct usbh_xxx *xxx_class)
+{
+    int devno = xxx_class->minor;
+
+    if (devno >= 0 && devno < 32) {
+        g_devinuse &= ~(1 << devno);
+    }
+    memset(xxx_class, 0, sizeof(struct usbh_xxx));
+}
+
+static int usbh_xxx_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret;
+
+    struct usbh_xxx *xxx_class = usbh_xxx_class_alloc();
+    if (xxx_class == NULL) {
+        USB_LOG_ERR("Fail to alloc xxx_class\r\n");
+        return -USB_ERR_NOMEM;
+    }
+
+    return ret;
+}
+
+
+static int usbh_xxx_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_xxx *xxx_class = (struct usbh_xxx *)hport->config.intf[intf].priv;
+
+    if (xxx_class) {
+        if (xxx_class->xxxin) {
+            usbh_kill_urb(&xxx_class->xxxin_urb);
+        }
+
+        if (xxx_class->xxxout) {
+            usbh_kill_urb(&xxx_class->xxxout_urb);
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister xxx Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_xxx_stop(xxx_class);
+        }
+
+        usbh_xxx_class_free(xxx_class);
+    }
+
+    return ret;
+}
+
+__WEAK void usbh_xxx_run(struct usbh_xxx *xxx_class)
+{
+}
+
+__WEAK void usbh_xxx_stop(struct usbh_xxx *xxx_class)
+{
+}
+
+static const struct usbh_class_driver xxx_class_driver = {
+    .driver_name = "xxx",
+    .connect = usbh_xxx_connect,
+    .disconnect = usbh_xxx_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info xxx_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
+    .class = 0,
+    .subclass = 0,
+    .protocol = 0,
+    .id_table = NULL,
+    .class_driver = &xxx_class_driver
+};

+ 22 - 0
components/drivers/usb/cherryusb/class/template/usbh_xxx.h

@@ -0,0 +1,22 @@
+#ifndef _USBH_XXX_H
+#define _USBH_XXX_H
+
+#include "usb_xxx.h"
+
+struct usbh_xxx {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *xxxin;
+    struct usb_endpoint_descriptor *xxxout;
+    struct usbh_urb xxxin_urb;
+    struct usbh_urb xxxout_urb;
+
+    uint8_t intf; /* interface number */
+    uint8_t minor;
+
+    void *user_data;
+};
+
+void usbh_xxx_run(struct usbh_xxx *xxx_class);
+void usbh_xxx_stop(struct usbh_xxx *xxx_class);
+
+#endif

+ 774 - 0
components/drivers/usb/cherryusb/class/vendor/net/usbh_asix.c

@@ -0,0 +1,774 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_asix.h"
+#include "usb_cdc.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "asix"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/asix"
+
+static struct usbh_asix g_asix_class;
+#define CONFIG_USBHOST_ASIX_ETH_MAX_SIZE (1514U + 8)
+
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_rx_buffer[CONFIG_USBHOST_ASIX_ETH_MAX_SIZE];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_tx_buffer[CONFIG_USBHOST_ASIX_ETH_MAX_SIZE];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_inttx_buffer[16];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_buf[32];
+
+#define ETH_ALEN 6
+
+#define PHY_MODE_MARVELL     0x0000
+#define MII_MARVELL_LED_CTRL 0x0018
+#define MII_MARVELL_STATUS   0x001b
+#define MII_MARVELL_CTRL     0x0014
+
+#define MARVELL_LED_MANUAL 0x0019
+
+#define MARVELL_STATUS_HWCFG 0x0004
+
+#define MARVELL_CTRL_TXDELAY 0x0002
+#define MARVELL_CTRL_RXDELAY 0x0080
+
+#define PHY_MODE_RTL8211CL 0x000C
+
+#define AX88772A_PHY14H         0x14
+#define AX88772A_PHY14H_DEFAULT 0x442C
+
+#define AX88772A_PHY15H         0x15
+#define AX88772A_PHY15H_DEFAULT 0x03C8
+
+#define AX88772A_PHY16H         0x16
+#define AX88772A_PHY16H_DEFAULT 0x4044
+
+#define SPEED_100 0
+#define SPEED_10  1
+
+static int usbh_asix_read_cmd(struct usbh_asix *asix_class,
+                              uint8_t cmd,
+                              uint16_t value,
+                              uint16_t index,
+                              void *data,
+                              uint16_t size)
+{
+    struct usb_setup_packet *setup = asix_class->hport->setup;
+    int ret;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = cmd;
+    setup->wValue = value;
+    setup->wIndex = index;
+    setup->wLength = size;
+
+    ret = usbh_control_transfer(asix_class->hport, setup, g_asix_buf);
+    if (ret < 0) {
+        return ret;
+    }
+    memcpy(data, g_asix_buf, ret - 8);
+
+    return ret;
+}
+
+static int usbh_asix_write_cmd(struct usbh_asix *asix_class,
+                               uint8_t cmd,
+                               uint16_t value,
+                               uint16_t index,
+                               void *data,
+                               uint16_t size)
+{
+    struct usb_setup_packet *setup = asix_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = cmd;
+    setup->wValue = value;
+    setup->wIndex = index;
+    setup->wLength = size;
+
+    memcpy(g_asix_buf, data, size);
+
+    return usbh_control_transfer(asix_class->hport, setup, g_asix_buf);
+}
+
+static int usbh_asix_mdio_write(struct usbh_asix *asix_class, int phy_id, int loc, int val)
+{
+    uint8_t smsr;
+    uint16_t res = (uint16_t)val;
+    int ret;
+
+    for (uint8_t i = 0; i < 10; i++) {
+        ret = usbh_asix_write_cmd(asix_class, AX_CMD_SET_SW_MII, 0, 0, NULL, 0);
+        if (ret < 0) {
+            return ret;
+        }
+        usb_osal_msleep(1);
+        ret = usbh_asix_read_cmd(asix_class, AX_CMD_STATMNGSTS_REG, 0, 0, &smsr, 1);
+        if (ret < 0) {
+            return ret;
+        }
+
+        if (smsr & AX_HOST_EN) {
+            break;
+        }
+    }
+
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_MII_REG, phy_id, loc, &res, 2);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_SET_HW_MII, 0, 0, NULL, 0);
+    if (ret < 0) {
+        return ret;
+    }
+    return 0;
+}
+
+static int usbh_asix_mdio_read(struct usbh_asix *asix_class, int phy_id, int loc)
+{
+    uint8_t smsr;
+    uint16_t res;
+    int ret;
+
+    for (uint8_t i = 0; i < 10; i++) {
+        ret = usbh_asix_write_cmd(asix_class, AX_CMD_SET_SW_MII, 0, 0, NULL, 0);
+        if (ret < 0) {
+            return ret;
+        }
+        usb_osal_msleep(1);
+        ret = usbh_asix_read_cmd(asix_class, AX_CMD_STATMNGSTS_REG, 0, 0, &smsr, 1);
+        if (ret < 0) {
+            return ret;
+        }
+
+        if (smsr & AX_HOST_EN) {
+            break;
+        }
+    }
+
+    ret = usbh_asix_read_cmd(asix_class, AX_CMD_READ_MII_REG, phy_id, loc, &res, 2);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_SET_HW_MII, 0, 0, NULL, 0);
+    if (ret < 0) {
+        return ret;
+    }
+    return res;
+}
+
+static int usbh_asix_read_phy_addr(struct usbh_asix *asix_class, bool internal)
+{
+    int ret, offset;
+    uint8_t buf[2];
+
+    ret = usbh_asix_read_cmd(asix_class, AX_CMD_READ_PHY_ID, 0, 0, buf, 2);
+    if (ret < 0) {
+        return ret;
+    }
+
+    offset = (internal ? 1 : 0);
+    ret = buf[offset];
+
+    USB_LOG_INFO("%s PHY address 0x%x\r\n", internal ? "internal" : "external", ret);
+
+    return ret;
+}
+
+static int usbh_asix_sw_reset(struct usbh_asix *asix_class, uint8_t flags)
+{
+    int ret;
+
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_SW_RESET, flags, 0, NULL, 0);
+    if (ret < 0)
+        USB_LOG_ERR("Failed to send software reset: %d\r\n", ret);
+
+    return ret;
+}
+
+static uint16_t usbh_asix_read_rx_ctl(struct usbh_asix *asix_class)
+{
+    uint16_t v;
+    int ret = usbh_asix_read_cmd(asix_class, AX_CMD_READ_RX_CTL, 0, 0, &v, 2);
+    if (ret < 0) {
+        return ret;
+    }
+    return v;
+}
+
+static int usbh_asix_write_rx_ctl(struct usbh_asix *asix_class, uint16_t mode)
+{
+    int ret;
+
+    USB_LOG_DBG("asix_write_rx_ctl() - mode = 0x%04x\r\n", mode);
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_RX_CTL, mode, 0, NULL, 0);
+    if (ret < 0)
+        USB_LOG_ERR("Failed to write RX_CTL mode to 0x%04x: %02x\r\n",
+                    mode, ret);
+
+    return ret;
+}
+
+static uint16_t usbh_asix_read_medium_status(struct usbh_asix *asix_class)
+{
+    uint16_t v;
+    int ret = usbh_asix_read_cmd(asix_class, AX_CMD_READ_MEDIUM_STATUS, 0, 0, &v, 2);
+
+    if (ret < 0) {
+        USB_LOG_ERR("Error reading Medium Status register: %02x\r\n",
+                    ret);
+        return ret; /* TODO: callers not checking for error ret */
+    }
+
+    return v;
+}
+
+static int usbh_asix_write_medium_mode(struct usbh_asix *asix_class, uint16_t mode)
+{
+    int ret;
+
+    USB_LOG_DBG("asix_write_medium_mode() - mode = 0x%04x\r\n", mode);
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, NULL, 0);
+    if (ret < 0)
+        USB_LOG_ERR("Failed to write Medium Mode mode to 0x%04x: %02x\r\n",
+                    mode, ret);
+
+    return ret;
+}
+
+static int usbh_asix_write_gpio(struct usbh_asix *asix_class, uint16_t value, int sleep)
+{
+    int ret;
+
+    USB_LOG_DBG("asix_write_gpio() - value = 0x%04x\r\n", value);
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_GPIOS, value, 0, NULL, 0);
+    if (ret < 0)
+        USB_LOG_ERR("Failed to write GPIO value 0x%04x: %d\r\n",
+                    value, ret);
+
+    if (sleep)
+        usb_osal_msleep(sleep);
+
+    return ret;
+}
+
+/*
+ * AX88772 & AX88178 have a 16-bit RX_CTL value
+ */
+static void usbh_asix_set_multicast(struct usbh_asix *asix_class)
+{
+    uint16_t rx_ctl = AX_DEFAULT_RX_CTL | AX_RX_CTL_AM;
+    const uint8_t multi_filter[] = { 0x00, 0x00, 0x20, 0x80, 0x00, 0x00, 0x00, 0x40 };
+
+    usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_MULTI_FILTER, 0, 0, (uint8_t *)multi_filter, AX_MCAST_FILTER_SIZE);
+    usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, NULL, 0);
+}
+
+static int usbh_ax88772_hw_reset(struct usbh_asix *asix_class)
+{
+    uint16_t rx_ctl;
+    int ret;
+
+    ret = usbh_asix_write_gpio(asix_class, AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5);
+    if (ret < 0)
+        goto out;
+
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_SW_PHY_SELECT, asix_class->embd_phy,
+                              0, NULL, 0);
+    if (ret < 0) {
+        USB_LOG_ERR("Select PHY #1 failed: %d\r\n", ret);
+        goto out;
+    }
+
+    if (asix_class->embd_phy) {
+        ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_IPPD);
+        if (ret < 0)
+            goto out;
+
+        usb_osal_msleep(10);
+
+        ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_CLEAR);
+        if (ret < 0)
+            goto out;
+
+        usb_osal_msleep(60);
+
+        ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_IPRL | AX_SWRESET_PRL);
+        if (ret < 0)
+            goto out;
+    } else {
+        ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_IPPD | AX_SWRESET_PRL);
+        if (ret < 0)
+            goto out;
+    }
+
+    usb_osal_msleep(150);
+
+    ret = usbh_asix_write_rx_ctl(asix_class, AX_DEFAULT_RX_CTL);
+    if (ret < 0)
+        goto out;
+
+    ret = usbh_asix_write_medium_mode(asix_class, AX88772_MEDIUM_DEFAULT);
+    if (ret < 0)
+        goto out;
+
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_IPG0,
+                              AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
+                              AX88772_IPG2_DEFAULT, NULL, 0);
+    if (ret < 0) {
+        USB_LOG_ERR("Write IPG,IPG1,IPG2 failed: %d\r\n", ret);
+        goto out;
+    }
+
+    /* Rewrite MAC address */
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_NODE_ID, 0, 0, asix_class->mac, ETH_ALEN);
+    if (ret < 0)
+        goto out;
+
+    /* Set RX_CTL to default values with 2k buffer, and enable cactus */
+    ret = usbh_asix_write_rx_ctl(asix_class, AX_DEFAULT_RX_CTL);
+    if (ret < 0)
+        goto out;
+
+    rx_ctl = usbh_asix_read_rx_ctl(asix_class);
+    USB_LOG_INFO("RX_CTL is 0x%04x after all initializations\r\n",
+                 rx_ctl);
+
+    rx_ctl = usbh_asix_read_medium_status(asix_class);
+    USB_LOG_INFO("Medium Status is 0x%04x after all initializations\r\n",
+                 rx_ctl);
+
+    return 0;
+
+out:
+    return ret;
+}
+
+static int usbh_ax88772a_hw_reset(struct usbh_asix *asix_class)
+{
+    uint16_t rx_ctl, phy14h, phy15h, phy16h;
+    int ret;
+
+    ret = usbh_asix_write_gpio(asix_class, AX_GPIO_RSE, 5);
+    if (ret < 0)
+        goto out;
+
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_SW_PHY_SELECT, asix_class->embd_phy | AX_PHYSEL_SSEN, 0, NULL, 0);
+    if (ret < 0) {
+        USB_LOG_ERR("Select PHY #1 failed: %d\r\n", ret);
+        goto out;
+    }
+    usb_osal_msleep(10);
+
+    ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_IPPD | AX_SWRESET_IPRL);
+    if (ret < 0)
+        goto out;
+
+    usb_osal_msleep(10);
+
+    ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_IPRL);
+    if (ret < 0)
+        goto out;
+
+    usb_osal_msleep(160);
+
+    ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_CLEAR);
+    if (ret < 0)
+        goto out;
+
+    ret = usbh_asix_sw_reset(asix_class, AX_SWRESET_IPRL);
+    if (ret < 0)
+        goto out;
+
+    usb_osal_msleep(200);
+
+    if (asix_class->chipcode == AX_AX88772B_CHIPCODE) {
+        ret = usbh_asix_write_cmd(asix_class, AX_QCTCTRL, 0x8000, 0x8001, NULL, 0);
+        if (ret < 0) {
+            USB_LOG_ERR("Write BQ setting failed: %d\r\n", ret);
+            goto out;
+        }
+    } else if (asix_class->chipcode == AX_AX88772A_CHIPCODE) {
+        /* Check if the PHY registers have default settings */
+        phy14h = usbh_asix_mdio_read(asix_class, asix_class->phy_addr,
+                                     AX88772A_PHY14H);
+        phy15h = usbh_asix_mdio_read(asix_class, asix_class->phy_addr,
+                                     AX88772A_PHY15H);
+        phy16h = usbh_asix_mdio_read(asix_class, asix_class->phy_addr,
+                                     AX88772A_PHY16H);
+
+        USB_LOG_DBG("772a_hw_reset: MR20=0x%x MR21=0x%x MR22=0x%x\r\n",
+                    phy14h, phy15h, phy16h);
+
+        /* Restore PHY registers default setting if not */
+        if (phy14h != AX88772A_PHY14H_DEFAULT)
+            usbh_asix_mdio_write(asix_class, asix_class->phy_addr,
+                                 AX88772A_PHY14H,
+                                 AX88772A_PHY14H_DEFAULT);
+        if (phy15h != AX88772A_PHY15H_DEFAULT)
+            usbh_asix_mdio_write(asix_class, asix_class->phy_addr,
+                                 AX88772A_PHY15H,
+                                 AX88772A_PHY15H_DEFAULT);
+        if (phy16h != AX88772A_PHY16H_DEFAULT)
+            usbh_asix_mdio_write(asix_class, asix_class->phy_addr,
+                                 AX88772A_PHY16H,
+                                 AX88772A_PHY16H_DEFAULT);
+    }
+
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_IPG0,
+                              AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
+                              AX88772_IPG2_DEFAULT, NULL, 0);
+    if (ret < 0) {
+        USB_LOG_ERR("Write IPG,IPG1,IPG2 failed: %d\r\n", ret);
+        goto out;
+    }
+
+    /* Rewrite MAC address */
+    ret = usbh_asix_write_cmd(asix_class, AX_CMD_WRITE_NODE_ID, 0, 0, asix_class->mac, ETH_ALEN);
+    if (ret < 0)
+        goto out;
+
+    /* Set RX_CTL to default values with 2k buffer, and enable cactus */
+    ret = usbh_asix_write_rx_ctl(asix_class, AX_DEFAULT_RX_CTL);
+    if (ret < 0)
+        goto out;
+
+    ret = usbh_asix_write_medium_mode(asix_class, AX88772_MEDIUM_DEFAULT);
+    if (ret < 0)
+        return ret;
+
+    /* Set RX_CTL to default values with 2k buffer, and enable cactus */
+    ret = usbh_asix_write_rx_ctl(asix_class, AX_DEFAULT_RX_CTL);
+    if (ret < 0)
+        goto out;
+
+    rx_ctl = usbh_asix_read_rx_ctl(asix_class);
+    USB_LOG_INFO("RX_CTL is 0x%04x after all initializations\r\n", rx_ctl);
+
+    rx_ctl = usbh_asix_read_medium_status(asix_class);
+    USB_LOG_INFO("Medium Status is 0x%04x after all initializations\r\n", rx_ctl);
+
+    return 0;
+
+out:
+    return ret;
+}
+
+static void usbh_ax88772_mac_link_down(struct usbh_asix *asix_class)
+{
+    usbh_asix_write_medium_mode(asix_class, 0);
+}
+
+static void usbh_ax88772_mac_link_up(struct usbh_asix *asix_class, int speed, int duplex, bool tx_pause, bool rx_pause)
+{
+    uint16_t m = AX_MEDIUM_AC | AX_MEDIUM_RE;
+
+    m |= duplex ? AX_MEDIUM_FD : 0;
+
+    switch (speed) {
+        case SPEED_100:
+            m |= AX_MEDIUM_PS;
+            break;
+        case SPEED_10:
+            break;
+        default:
+            return;
+    }
+
+    if (tx_pause)
+        m |= AX_MEDIUM_TFC;
+
+    if (rx_pause)
+        m |= AX_MEDIUM_RFC;
+
+    usbh_asix_write_medium_mode(asix_class, m);
+}
+
+static int usbh_asix_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret;
+
+    struct usbh_asix *asix_class = &g_asix_class;
+
+    memset(asix_class, 0, sizeof(struct usbh_asix));
+
+    asix_class->hport = hport;
+    asix_class->intf = intf;
+
+    hport->config.intf[intf].priv = asix_class;
+
+    if ((hport->device_desc.idVendor == 0x0b95) && (hport->device_desc.idProduct == 0x772b)) {
+        asix_class->name = "ASIX AX88772B";
+    } else if ((hport->device_desc.idVendor == 0x0b95) && (hport->device_desc.idProduct == 0x7720)) {
+        asix_class->name = "ASIX AX88772";
+    } else if ((hport->device_desc.idVendor == 0x0b95) && (hport->device_desc.idProduct == 0x1780)) {
+        asix_class->name = "ASIX AX88178";
+    }
+
+    for (uint8_t i = 0; i < (ETH_ALEN >> 1); i++) {
+        ret = usbh_asix_read_cmd(asix_class, AX_CMD_READ_EEPROM,
+                                 0x04 + i, 0, &asix_class->mac[i * 2], 2);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    USB_LOG_INFO("asix MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
+                 asix_class->mac[0],
+                 asix_class->mac[1],
+                 asix_class->mac[2],
+                 asix_class->mac[3],
+                 asix_class->mac[4],
+                 asix_class->mac[5]);
+
+    ret = usbh_asix_read_phy_addr(asix_class, true);
+    if (ret < 0) {
+        USB_LOG_ERR("Failed to read phy addr: %d\r\n", ret);
+        return ret;
+    }
+    asix_class->phy_addr = ret;
+    asix_class->embd_phy = ((ret & 0x1f) == AX_EMBD_PHY_ADDR);
+
+    ret = usbh_asix_read_cmd(asix_class, AX_CMD_STATMNGSTS_REG, 0, 0, &asix_class->chipcode, 1);
+    if (ret < 0) {
+        USB_LOG_ERR("Failed to read STATMNGSTS_REG: %d\r\n", ret);
+        return ret;
+    }
+
+    asix_class->chipcode &= AX_CHIPCODE_MASK;
+    USB_LOG_INFO("asix chipcode 0x%x\r\n", asix_class->chipcode);
+
+    if (asix_class->chipcode == AX_AX88772_CHIPCODE) {
+        usbh_ax88772_hw_reset(asix_class);
+    } else {
+        usbh_ax88772a_hw_reset(asix_class);
+    }
+    for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
+        ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
+
+        if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(asix_class->intin, ep_desc);
+            } else {
+                return -USB_ERR_NOTSUPP;
+            }
+        } else {
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(asix_class->bulkin, ep_desc);
+            } else {
+                USBH_EP_INIT(asix_class->bulkout, ep_desc);
+            }
+        }
+    }
+
+    if (asix_class->chipcode == AX_AX88772B_CHIPCODE) {
+        usbh_asix_mdio_write(asix_class, asix_class->phy_addr, 0, 0);
+        usbh_asix_mdio_read(asix_class, asix_class->phy_addr, 0);
+
+        usbh_asix_mdio_write(asix_class, asix_class->phy_addr, 0, 0x8200);
+        usbh_asix_mdio_read(asix_class, asix_class->phy_addr, 0);
+
+        usbh_asix_mdio_write(asix_class, asix_class->phy_addr, 0, 0x3900);
+        usbh_asix_mdio_read(asix_class, asix_class->phy_addr, 0);
+
+        usbh_asix_mdio_write(asix_class, asix_class->phy_addr, 0, 0x3100);
+        usbh_asix_mdio_read(asix_class, asix_class->phy_addr, 4);
+
+        usbh_asix_mdio_write(asix_class, asix_class->phy_addr, 4, 0x01e1);
+        usbh_asix_mdio_read(asix_class, asix_class->phy_addr, 1);
+
+        usbh_asix_mdio_write(asix_class, asix_class->phy_addr, 0, 0x3300);
+        usbh_asix_mdio_read(asix_class, asix_class->phy_addr, 0);
+    }
+
+    USB_LOG_INFO("Init %s done\r\n", asix_class->name);
+
+    memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
+
+    USB_LOG_INFO("Register ASIX Class:%s\r\n", hport->config.intf[intf].devname);
+    usbh_asix_run(asix_class);
+    return ret;
+}
+
+static int usbh_asix_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_asix *asix_class = (struct usbh_asix *)hport->config.intf[intf].priv;
+
+    if (asix_class) {
+        if (asix_class->bulkin) {
+            usbh_kill_urb(&asix_class->bulkin_urb);
+        }
+
+        if (asix_class->bulkout) {
+            usbh_kill_urb(&asix_class->bulkout_urb);
+        }
+
+        if (asix_class->intin) {
+            usbh_kill_urb(&asix_class->intin_urb);
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister ASIX Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_asix_stop(asix_class);
+        }
+
+        memset(asix_class, 0, sizeof(struct usbh_asix));
+    }
+
+    return ret;
+}
+
+int usbh_asix_get_connect_status(struct usbh_asix *asix_class)
+{
+    int ret;
+
+    usbh_int_urb_fill(&asix_class->intin_urb, asix_class->hport, asix_class->intin, g_asix_inttx_buffer, 8, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+    ret = usbh_submit_urb(&asix_class->intin_urb);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (g_asix_inttx_buffer[1] == 0x00) {
+        if (g_asix_inttx_buffer[2] & 0x01) {
+            asix_class->connect_status = true;
+            usbh_ax88772_mac_link_up(asix_class, SPEED_100, 1, 1, 1);
+            usbh_asix_set_multicast(asix_class);
+        } else {
+            asix_class->connect_status = false;
+            usbh_ax88772_mac_link_down(asix_class);
+        }
+    }
+    return 0;
+}
+
+void usbh_asix_rx_thread(void *argument)
+{
+    uint32_t g_asix_rx_length;
+    int ret;
+    uint16_t len;
+    uint16_t len_crc;
+
+    USB_LOG_INFO("Create asix rx thread\r\n");
+    // clang-format off
+find_class:
+    // clang-format on
+    g_asix_class.connect_status = false;
+    if (usbh_find_class_instance("/dev/asix") == NULL) {
+        goto delete;
+    }
+
+    while (g_asix_class.connect_status == false) {
+        ret = usbh_asix_get_connect_status(&g_asix_class);
+        if (ret < 0) {
+            usb_osal_msleep(100);
+            goto find_class;
+        }
+    }
+
+    g_asix_rx_length = 0;
+    while (1) {
+        usbh_bulk_urb_fill(&g_asix_class.bulkin_urb, g_asix_class.hport, g_asix_class.bulkin, &g_asix_rx_buffer[g_asix_rx_length], CONFIG_USBHOST_ASIX_ETH_MAX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+        ret = usbh_submit_urb(&g_asix_class.bulkin_urb);
+        if (ret < 0) {
+            goto find_class;
+        }
+
+        g_asix_rx_length += g_asix_class.bulkin_urb.actual_length;
+
+        if (g_asix_rx_length % USB_GET_MAXPACKETSIZE(g_asix_class.bulkin->wMaxPacketSize)) {
+            len = ((uint16_t)g_asix_rx_buffer[0] | ((uint16_t)(g_asix_rx_buffer[1]) << 8)) & 0x7ff;
+            len_crc = g_asix_rx_buffer[2] | ((uint16_t)(g_asix_rx_buffer[3]) << 8);
+
+            if (len != (~len_crc & 0x7ff)) {
+                USB_LOG_ERR("asix rx header error\r\n");
+                continue;
+            }
+
+            USB_LOG_DBG("rxlen:%d\r\n", g_asix_rx_length);
+
+            uint8_t *buf = (uint8_t *)&g_asix_rx_buffer[4];
+            usbh_asix_eth_input(buf, len);
+            g_asix_rx_length = 0;
+        } else {
+            if (g_asix_rx_length > CONFIG_USBHOST_ASIX_ETH_MAX_SIZE) {
+                USB_LOG_ERR("Rx packet is overflow\r\n");
+                g_asix_rx_length = 0;
+            }
+        }
+    }
+    // clang-format off
+delete:
+    USB_LOG_INFO("Delete asix rx thread\r\n");
+    usb_osal_thread_delete(NULL);
+    // clang-format on
+}
+
+int usbh_asix_eth_output(uint8_t *buf, uint32_t buflen)
+{
+    uint16_t actual_len;
+    uint8_t *buffer;
+
+    if (g_asix_class.connect_status == false) {
+        return -USB_ERR_NOTCONN;
+    }
+
+    buffer = &g_asix_tx_buffer[4];
+    memcpy(buffer, buf, buflen);
+
+    g_asix_tx_buffer[0] = buflen & 0xff;
+    g_asix_tx_buffer[1] = (buflen >> 8) & 0xff;
+    g_asix_tx_buffer[2] = ~g_asix_tx_buffer[0];
+    g_asix_tx_buffer[3] = ~g_asix_tx_buffer[1];
+
+    if (!(buflen + 4) % USB_GET_MAXPACKETSIZE(g_asix_class.bulkout->wMaxPacketSize)) {
+        USB_LOG_DBG("txlen:%d\r\n", buflen + 8);
+        g_asix_tx_buffer[buflen + 4 + 0] = 0x00;
+        g_asix_tx_buffer[buflen + 4 + 1] = 0x00;
+        g_asix_tx_buffer[buflen + 4 + 2] = 0xff;
+        g_asix_tx_buffer[buflen + 4 + 3] = 0xff;
+        actual_len = buflen + 8;
+    } else {
+        USB_LOG_DBG("txlen:%d\r\n", buflen + 4);
+        actual_len = buflen + 4;
+    }
+
+    usbh_bulk_urb_fill(&g_asix_class.bulkout_urb, g_asix_class.hport, g_asix_class.bulkout, g_asix_tx_buffer, actual_len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+    return usbh_submit_urb(&g_asix_class.bulkout_urb);
+}
+
+__WEAK void usbh_asix_run(struct usbh_asix *asix_class)
+{
+}
+
+__WEAK void usbh_asix_stop(struct usbh_asix *asix_class)
+{
+}
+
+static const uint16_t asix_id_table[][2] = {
+    { 0x0B95, 0x772B },
+    { 0x0B95, 0x7720 },
+    { 0, 0 },
+};
+
+static const struct usbh_class_driver asix_class_driver = {
+    .driver_name = "asix",
+    .connect = usbh_asix_connect,
+    .disconnect = usbh_asix_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info asix_class_info = {
+    .match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
+    .class = 0xff,
+    .subclass = 0x00,
+    .protocol = 0x00,
+    .id_table = asix_id_table,
+    .class_driver = &asix_class_driver
+};

+ 176 - 0
components/drivers/usb/cherryusb/class/vendor/net/usbh_asix.h

@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_ASIX_H
+#define USBH_ASIX_H
+
+/* ASIX AX8817X based USB 2.0 Ethernet Devices */
+
+#define AX_CMD_SET_SW_MII         0x06
+#define AX_CMD_READ_MII_REG       0x07
+#define AX_CMD_WRITE_MII_REG      0x08
+#define AX_CMD_STATMNGSTS_REG     0x09
+#define AX_CMD_SET_HW_MII         0x0a
+#define AX_CMD_READ_EEPROM        0x0b
+#define AX_CMD_WRITE_EEPROM       0x0c
+#define AX_CMD_WRITE_ENABLE       0x0d
+#define AX_CMD_WRITE_DISABLE      0x0e
+#define AX_CMD_READ_RX_CTL        0x0f
+#define AX_CMD_WRITE_RX_CTL       0x10
+#define AX_CMD_READ_IPG012        0x11
+#define AX_CMD_WRITE_IPG0         0x12
+#define AX_CMD_WRITE_IPG1         0x13
+#define AX_CMD_READ_NODE_ID       0x13
+#define AX_CMD_WRITE_NODE_ID      0x14
+#define AX_CMD_WRITE_IPG2         0x14
+#define AX_CMD_WRITE_MULTI_FILTER 0x16
+#define AX88172_CMD_READ_NODE_ID  0x17
+#define AX_CMD_READ_PHY_ID        0x19
+#define AX_CMD_READ_MEDIUM_STATUS 0x1a
+#define AX_CMD_WRITE_MEDIUM_MODE  0x1b
+#define AX_CMD_READ_MONITOR_MODE  0x1c
+#define AX_CMD_WRITE_MONITOR_MODE 0x1d
+#define AX_CMD_READ_GPIOS         0x1e
+#define AX_CMD_WRITE_GPIOS        0x1f
+#define AX_CMD_SW_RESET           0x20
+#define AX_CMD_SW_PHY_STATUS      0x21
+#define AX_CMD_SW_PHY_SELECT      0x22
+#define AX_QCTCTRL                0x2A
+
+#define AX_CHIPCODE_MASK          0x70
+#define AX_AX88772_CHIPCODE       0x00
+#define AX_AX88772A_CHIPCODE      0x10
+#define AX_AX88772B_CHIPCODE      0x20
+#define AX_HOST_EN                0x01
+
+#define AX_PHYSEL_PSEL            0x01
+#define AX_PHYSEL_SSMII           0
+#define AX_PHYSEL_SSEN            0x10
+
+#define AX_PHY_SELECT_MASK        (BIT(3) | BIT(2))
+#define AX_PHY_SELECT_INTERNAL    0
+#define AX_PHY_SELECT_EXTERNAL    BIT(2)
+
+#define AX_MONITOR_MODE           0x01
+#define AX_MONITOR_LINK           0x02
+#define AX_MONITOR_MAGIC          0x04
+#define AX_MONITOR_HSFS           0x10
+
+/* AX88172 Medium Status Register values */
+#define AX88172_MEDIUM_FD         0x02
+#define AX88172_MEDIUM_TX         0x04
+#define AX88172_MEDIUM_FC         0x10
+#define AX88172_MEDIUM_DEFAULT \
+    (AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC)
+
+#define AX_MCAST_FILTER_SIZE 8
+#define AX_MAX_MCAST         64
+
+#define AX_SWRESET_CLEAR     0x00
+#define AX_SWRESET_RR        0x01
+#define AX_SWRESET_RT        0x02
+#define AX_SWRESET_PRTE      0x04
+#define AX_SWRESET_PRL       0x08
+#define AX_SWRESET_BZ        0x10
+#define AX_SWRESET_IPRL      0x20
+#define AX_SWRESET_IPPD      0x40
+
+#define AX88772_IPG0_DEFAULT 0x15
+#define AX88772_IPG1_DEFAULT 0x0c
+#define AX88772_IPG2_DEFAULT 0x12
+
+/* AX88772 & AX88178 Medium Mode Register */
+#define AX_MEDIUM_PF         0x0080
+#define AX_MEDIUM_JFE        0x0040
+#define AX_MEDIUM_TFC        0x0020
+#define AX_MEDIUM_RFC        0x0010
+#define AX_MEDIUM_ENCK       0x0008
+#define AX_MEDIUM_AC         0x0004
+#define AX_MEDIUM_FD         0x0002
+#define AX_MEDIUM_GM         0x0001
+#define AX_MEDIUM_SM         0x1000
+#define AX_MEDIUM_SBP        0x0800
+#define AX_MEDIUM_PS         0x0200
+#define AX_MEDIUM_RE         0x0100
+
+#define AX88178_MEDIUM_DEFAULT                       \
+    (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC |    \
+     AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \
+     AX_MEDIUM_RE)
+
+#define AX88772_MEDIUM_DEFAULT     \
+    (AX_MEDIUM_FD | AX_MEDIUM_PS | \
+     AX_MEDIUM_AC | AX_MEDIUM_RE)
+
+/* AX88772 & AX88178 RX_CTL values */
+#define AX_RX_CTL_SO        0x0080
+#define AX_RX_CTL_AP        0x0020
+#define AX_RX_CTL_AM        0x0010
+#define AX_RX_CTL_AB        0x0008
+#define AX_RX_CTL_SEP       0x0004
+#define AX_RX_CTL_AMALL     0x0002
+#define AX_RX_CTL_PRO       0x0001
+#define AX_RX_CTL_MFB_2048  0x0000
+#define AX_RX_CTL_MFB_4096  0x0100
+#define AX_RX_CTL_MFB_8192  0x0200
+#define AX_RX_CTL_MFB_16384 0x0300
+
+#define AX_DEFAULT_RX_CTL   (AX_RX_CTL_SO | AX_RX_CTL_AB)
+
+/* GPIO 0 .. 2 toggles */
+#define AX_GPIO_GPO0EN      0x01 /* GPIO0 Output enable */
+#define AX_GPIO_GPO_0       0x02 /* GPIO0 Output value */
+#define AX_GPIO_GPO1EN      0x04 /* GPIO1 Output enable */
+#define AX_GPIO_GPO_1       0x08 /* GPIO1 Output value */
+#define AX_GPIO_GPO2EN      0x10 /* GPIO2 Output enable */
+#define AX_GPIO_GPO_2       0x20 /* GPIO2 Output value */
+#define AX_GPIO_RESERVED    0x40 /* Reserved */
+#define AX_GPIO_RSE         0x80 /* Reload serial EEPROM */
+
+#define AX_EEPROM_MAGIC     0xdeadbeef
+#define AX_EEPROM_LEN       0x200
+
+#define AX_EMBD_PHY_ADDR    0x10
+
+struct usbh_asix {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+    struct usb_endpoint_descriptor *intin;   /* INTR IN endpoint  */
+    struct usbh_urb bulkout_urb;
+    struct usbh_urb bulkin_urb;
+    struct usbh_urb intin_urb;
+
+    uint8_t intf;
+    char *name;
+    uint8_t phy_addr;
+    uint8_t embd_phy;
+    uint8_t chipcode;
+    uint16_t mac_capabilities;
+
+    bool connect_status;
+    uint8_t mac[6];
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_asix_get_connect_status(struct usbh_asix *asix_class);
+
+void usbh_asix_run(struct usbh_asix *asix_class);
+void usbh_asix_stop(struct usbh_asix *asix_class);
+
+int usbh_asix_eth_output(uint8_t *buf, uint32_t buflen);
+void usbh_asix_eth_input(uint8_t *buf, uint32_t buflen);
+void usbh_asix_rx_thread(void *argument);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_ASIX_H */

+ 2249 - 0
components/drivers/usb/cherryusb/class/vendor/net/usbh_rtl8152.c

@@ -0,0 +1,2249 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_rtl8152.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "rtl8152"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/rtl8152"
+
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_rx_buffer[CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_tx_buffer[CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_inttx_buffer[2];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_buf[32];
+
+static struct usbh_rtl8152 g_rtl8152_class;
+
+#define RTL8152_REQ_GET_REGS 0x05
+#define RTL8152_REQ_SET_REGS 0x05
+
+#define BYTE_EN_DWORD      0xff
+#define BYTE_EN_WORD       0x33
+#define BYTE_EN_BYTE       0x11
+#define BYTE_EN_SIX_BYTES  0x3f
+#define BYTE_EN_START_MASK 0x0f
+#define BYTE_EN_END_MASK   0xf0
+
+#define MCU_TYPE_PLA 0x0100
+#define MCU_TYPE_USB 0x0000
+
+/* Define these values to match your device */
+#define VENDOR_ID_REALTEK   0x0bda
+#define VENDOR_ID_MICROSOFT 0x045e
+#define VENDOR_ID_SAMSUNG   0x04e8
+#define VENDOR_ID_LENOVO    0x17ef
+#define VENDOR_ID_LINKSYS   0x13b1
+#define VENDOR_ID_NVIDIA    0x0955
+#define VENDOR_ID_TPLINK    0x2357
+#define VENDOR_ID_DLINK     0x2001
+#define VENDOR_ID_ASUS      0x0b05
+
+#define R8152_PHY_ID 32
+
+#define PLA_IDR              0xc000
+#define PLA_RCR              0xc010
+#define PLA_RCR1             0xc012
+#define PLA_RMS              0xc016
+#define PLA_RXFIFO_CTRL0     0xc0a0
+#define PLA_RXFIFO_FULL      0xc0a2
+#define PLA_RXFIFO_CTRL1     0xc0a4
+#define PLA_RX_FIFO_FULL     0xc0a6
+#define PLA_RXFIFO_CTRL2     0xc0a8
+#define PLA_RX_FIFO_EMPTY    0xc0aa
+#define PLA_DMY_REG0         0xc0b0
+#define PLA_FMC              0xc0b4
+#define PLA_CFG_WOL          0xc0b6
+#define PLA_TEREDO_CFG       0xc0bc
+#define PLA_TEREDO_WAKE_BASE 0xc0c4
+#define PLA_MAR              0xcd00
+#define PLA_BACKUP           0xd000
+#define PLA_BDC_CR           0xd1a0
+#define PLA_TEREDO_TIMER     0xd2cc
+#define PLA_REALWOW_TIMER    0xd2e8
+#define PLA_UPHY_TIMER       0xd388
+#define PLA_SUSPEND_FLAG     0xd38a
+#define PLA_INDICATE_FALG    0xd38c
+#define PLA_MACDBG_PRE       0xd38c /* RTL_VER_04 only */
+#define PLA_MACDBG_POST      0xd38e /* RTL_VER_04 only */
+#define PLA_EXTRA_STATUS     0xd398
+#define PLA_GPHY_CTRL        0xd3ae
+#define PLA_POL_GPIO_CTRL    0xdc6a
+#define PLA_EFUSE_DATA       0xdd00
+#define PLA_EFUSE_CMD        0xdd02
+#define PLA_LEDSEL           0xdd90
+#define PLA_LED_FEATURE      0xdd92
+#define PLA_PHYAR            0xde00
+#define PLA_BOOT_CTRL        0xe004
+#define PLA_LWAKE_CTRL_REG   0xe007
+#define PLA_GPHY_INTR_IMR    0xe022
+#define PLA_EEE_CR           0xe040
+#define PLA_EEE_TXTWSYS      0xe04c
+#define PLA_EEE_TXTWSYS_2P5G 0xe058
+#define PLA_EEEP_CR          0xe080
+#define PLA_MAC_PWR_CTRL     0xe0c0
+#define PLA_MAC_PWR_CTRL2    0xe0ca
+#define PLA_MAC_PWR_CTRL3    0xe0cc
+#define PLA_MAC_PWR_CTRL4    0xe0ce
+#define PLA_WDT6_CTRL        0xe428
+#define PLA_TCR0             0xe610
+#define PLA_TCR1             0xe612
+#define PLA_MTPS             0xe615
+#define PLA_TXFIFO_CTRL      0xe618
+#define PLA_TXFIFO_FULL      0xe61a
+#define PLA_RSTTALLY         0xe800
+#define PLA_CR               0xe813
+#define PLA_CRWECR           0xe81c
+#define PLA_CONFIG12         0xe81e /* CONFIG1, CONFIG2 */
+#define PLA_CONFIG34         0xe820 /* CONFIG3, CONFIG4 */
+#define PLA_CONFIG5          0xe822
+#define PLA_PHY_PWR          0xe84c
+#define PLA_OOB_CTRL         0xe84f
+#define PLA_CPCR             0xe854
+#define PLA_MISC_0           0xe858
+#define PLA_MISC_1           0xe85a
+#define PLA_OCP_GPHY_BASE    0xe86c
+#define PLA_TALLYCNT         0xe890
+#define PLA_SFF_STS_7        0xe8de
+#define PLA_PHYSTATUS        0xe908
+#define PLA_CONFIG6          0xe90a /* CONFIG6 */
+#define PLA_USB_CFG          0xe952
+#define PLA_BP_BA            0xfc26
+#define PLA_BP_0             0xfc28
+#define PLA_BP_1             0xfc2a
+#define PLA_BP_2             0xfc2c
+#define PLA_BP_3             0xfc2e
+#define PLA_BP_4             0xfc30
+#define PLA_BP_5             0xfc32
+#define PLA_BP_6             0xfc34
+#define PLA_BP_7             0xfc36
+#define PLA_BP_EN            0xfc38
+
+#define USB_USB2PHY           0xb41e
+#define USB_SSPHYLINK1        0xb426
+#define USB_SSPHYLINK2        0xb428
+#define USB_L1_CTRL           0xb45e
+#define USB_U2P3_CTRL         0xb460
+#define USB_CSR_DUMMY1        0xb464
+#define USB_CSR_DUMMY2        0xb466
+#define USB_DEV_STAT          0xb808
+#define USB_CONNECT_TIMER     0xcbf8
+#define USB_MSC_TIMER         0xcbfc
+#define USB_BURST_SIZE        0xcfc0
+#define USB_FW_FIX_EN0        0xcfca
+#define USB_FW_FIX_EN1        0xcfcc
+#define USB_LPM_CONFIG        0xcfd8
+#define USB_ECM_OPTION        0xcfee
+#define USB_CSTMR             0xcfef /* RTL8153A */
+#define USB_MISC_2            0xcfff
+#define USB_ECM_OP            0xd26b
+#define USB_GPHY_CTRL         0xd284
+#define USB_SPEED_OPTION      0xd32a
+#define USB_FW_CTRL           0xd334 /* RTL8153B */
+#define USB_FC_TIMER          0xd340
+#define USB_USB_CTRL          0xd406
+#define USB_PHY_CTRL          0xd408
+#define USB_TX_AGG            0xd40a
+#define USB_RX_BUF_TH         0xd40c
+#define USB_USB_TIMER         0xd428
+#define USB_RX_EARLY_TIMEOUT  0xd42c
+#define USB_RX_EARLY_SIZE     0xd42e
+#define USB_PM_CTRL_STATUS    0xd432 /* RTL8153A */
+#define USB_RX_EXTRA_AGGR_TMR 0xd432 /* RTL8153B */
+#define USB_TX_DMA            0xd434
+#define USB_UPT_RXDMA_OWN     0xd437
+#define USB_UPHY3_MDCMDIO     0xd480
+#define USB_TOLERANCE         0xd490
+#define USB_LPM_CTRL          0xd41a
+#define USB_BMU_RESET         0xd4b0
+#define USB_BMU_CONFIG        0xd4b4
+#define USB_U1U2_TIMER        0xd4da
+#define USB_FW_TASK           0xd4e8 /* RTL8153B */
+#define USB_RX_AGGR_NUM       0xd4ee
+#define USB_UPS_CTRL          0xd800
+#define USB_POWER_CUT         0xd80a
+#define USB_MISC_0            0xd81a
+#define USB_MISC_1            0xd81f
+#define USB_AFE_CTRL2         0xd824
+#define USB_UPHY_XTAL         0xd826
+#define USB_UPS_CFG           0xd842
+#define USB_UPS_FLAGS         0xd848
+#define USB_WDT1_CTRL         0xe404
+#define USB_WDT11_CTRL        0xe43c
+#define USB_BP_BA             PLA_BP_BA
+#define USB_BP_0              PLA_BP_0
+#define USB_BP_1              PLA_BP_1
+#define USB_BP_2              PLA_BP_2
+#define USB_BP_3              PLA_BP_3
+#define USB_BP_4              PLA_BP_4
+#define USB_BP_5              PLA_BP_5
+#define USB_BP_6              PLA_BP_6
+#define USB_BP_7              PLA_BP_7
+#define USB_BP_EN             PLA_BP_EN /* RTL8153A */
+#define USB_BP_8              0xfc38    /* RTL8153B */
+#define USB_BP_9              0xfc3a
+#define USB_BP_10             0xfc3c
+#define USB_BP_11             0xfc3e
+#define USB_BP_12             0xfc40
+#define USB_BP_13             0xfc42
+#define USB_BP_14             0xfc44
+#define USB_BP_15             0xfc46
+#define USB_BP2_EN            0xfc48
+
+/* OCP Registers */
+#define OCP_ALDPS_CONFIG   0x2010
+#define OCP_EEE_CONFIG1    0x2080
+#define OCP_EEE_CONFIG2    0x2092
+#define OCP_EEE_CONFIG3    0x2094
+#define OCP_BASE_MII       0xa400
+#define OCP_EEE_AR         0xa41a
+#define OCP_EEE_DATA       0xa41c
+#define OCP_PHY_STATUS     0xa420
+#define OCP_INTR_EN        0xa424
+#define OCP_NCTL_CFG       0xa42c
+#define OCP_POWER_CFG      0xa430
+#define OCP_EEE_CFG        0xa432
+#define OCP_SRAM_ADDR      0xa436
+#define OCP_SRAM_DATA      0xa438
+#define OCP_DOWN_SPEED     0xa442
+#define OCP_EEE_ABLE       0xa5c4
+#define OCP_EEE_ADV        0xa5d0
+#define OCP_EEE_LPABLE     0xa5d2
+#define OCP_10GBT_CTRL     0xa5d4
+#define OCP_10GBT_STAT     0xa5d6
+#define OCP_EEE_ADV2       0xa6d4
+#define OCP_PHY_STATE      0xa708 /* nway state for 8153 */
+#define OCP_PHY_PATCH_STAT 0xb800
+#define OCP_PHY_PATCH_CMD  0xb820
+#define OCP_PHY_LOCK       0xb82e
+#define OCP_ADC_IOFFSET    0xbcfc
+#define OCP_ADC_CFG        0xbc06
+#define OCP_SYSCLK_CFG     0xc416
+
+/* SRAM Register */
+#define SRAM_GREEN_CFG   0x8011
+#define SRAM_LPF_CFG     0x8012
+#define SRAM_GPHY_FW_VER 0x801e
+#define SRAM_10M_AMP1    0x8080
+#define SRAM_10M_AMP2    0x8082
+#define SRAM_IMPEDANCE   0x8084
+#define SRAM_PHY_LOCK    0xb82e
+
+/* PLA_RCR */
+#define RCR_AAP      0x00000001
+#define RCR_APM      0x00000002
+#define RCR_AM       0x00000004
+#define RCR_AB       0x00000008
+#define RCR_ACPT_ALL (RCR_AAP | RCR_APM | RCR_AM | RCR_AB)
+#define SLOT_EN      BIT(11)
+
+/* PLA_RCR1 */
+#define OUTER_VLAN BIT(7)
+#define INNER_VLAN BIT(6)
+
+/* PLA_RXFIFO_CTRL0 */
+#define RXFIFO_THR1_NORMAL 0x00080002
+#define RXFIFO_THR1_OOB    0x01800003
+
+/* PLA_RXFIFO_FULL */
+#define RXFIFO_FULL_MASK 0xfff
+
+/* PLA_RXFIFO_CTRL1 */
+#define RXFIFO_THR2_FULL   0x00000060
+#define RXFIFO_THR2_HIGH   0x00000038
+#define RXFIFO_THR2_OOB    0x0000004a
+#define RXFIFO_THR2_NORMAL 0x00a0
+
+/* PLA_RXFIFO_CTRL2 */
+#define RXFIFO_THR3_FULL   0x00000078
+#define RXFIFO_THR3_HIGH   0x00000048
+#define RXFIFO_THR3_OOB    0x0000005a
+#define RXFIFO_THR3_NORMAL 0x0110
+
+/* PLA_TXFIFO_CTRL */
+#define TXFIFO_THR_NORMAL  0x00400008
+#define TXFIFO_THR_NORMAL2 0x01000008
+
+/* PLA_DMY_REG0 */
+#define ECM_ALDPS 0x0002
+
+/* PLA_FMC */
+#define FMC_FCR_MCU_EN 0x0001
+
+/* PLA_EEEP_CR */
+#define EEEP_CR_EEEP_TX 0x0002
+
+/* PLA_WDT6_CTRL */
+#define WDT6_SET_MODE 0x0010
+
+/* PLA_TCR0 */
+#define TCR0_TX_EMPTY  0x0800
+#define TCR0_AUTO_FIFO 0x0080
+
+/* PLA_TCR1 */
+#define VERSION_MASK 0x7cf0
+#define IFG_MASK     (BIT(3) | BIT(9) | BIT(8))
+#define IFG_144NS    BIT(9)
+#define IFG_96NS     (BIT(9) | BIT(8))
+
+/* PLA_MTPS */
+#define MTPS_JUMBO   (12 * 1024 / 64)
+#define MTPS_DEFAULT (6 * 1024 / 64)
+
+/* PLA_RSTTALLY */
+#define TALLY_RESET 0x0001
+
+/* PLA_CR */
+#define CR_RST 0x10
+#define CR_RE  0x08
+#define CR_TE  0x04
+
+/* PLA_CRWECR */
+#define CRWECR_NORAML 0x00
+#define CRWECR_CONFIG 0xc0
+
+/* PLA_OOB_CTRL */
+#define NOW_IS_OOB      0x80
+#define TXFIFO_EMPTY    0x20
+#define RXFIFO_EMPTY    0x10
+#define LINK_LIST_READY 0x02
+#define DIS_MCU_CLROOB  0x01
+#define FIFO_EMPTY      (TXFIFO_EMPTY | RXFIFO_EMPTY)
+
+/* PLA_MISC_1 */
+#define RXDY_GATED_EN 0x0008
+
+/* PLA_SFF_STS_7 */
+#define RE_INIT_LL  0x8000
+#define MCU_BORW_EN 0x4000
+
+/* PLA_CPCR */
+#define FLOW_CTRL_EN BIT(0)
+#define CPCR_RX_VLAN 0x0040
+
+/* PLA_CFG_WOL */
+#define MAGIC_EN 0x0001
+
+/* PLA_TEREDO_CFG */
+#define TEREDO_SEL           0x8000
+#define TEREDO_WAKE_MASK     0x7f00
+#define TEREDO_RS_EVENT_MASK 0x00fe
+#define OOB_TEREDO_EN        0x0001
+
+/* PLA_BDC_CR */
+#define ALDPS_PROXY_MODE 0x0001
+
+/* PLA_EFUSE_CMD */
+#define EFUSE_READ_CMD   BIT(15)
+#define EFUSE_DATA_BIT16 BIT(7)
+
+/* PLA_CONFIG34 */
+#define LINK_ON_WAKE_EN  0x0010
+#define LINK_OFF_WAKE_EN 0x0008
+
+/* PLA_CONFIG6 */
+#define LANWAKE_CLR_EN BIT(0)
+
+/* PLA_USB_CFG */
+#define EN_XG_LIP BIT(1)
+#define EN_G_LIP  BIT(2)
+
+/* PLA_CONFIG5 */
+#define BWF_EN      0x0040
+#define MWF_EN      0x0020
+#define UWF_EN      0x0010
+#define LAN_WAKE_EN 0x0002
+
+/* PLA_LED_FEATURE */
+#define LED_MODE_MASK 0x0700
+
+/* PLA_PHY_PWR */
+#define TX_10M_IDLE_EN 0x0080
+#define PFM_PWM_SWITCH 0x0040
+#define TEST_IO_OFF    BIT(4)
+
+/* PLA_MAC_PWR_CTRL */
+#define D3_CLK_GATED_EN    0x00004000
+#define MCU_CLK_RATIO      0x07010f07
+#define MCU_CLK_RATIO_MASK 0x0f0f0f0f
+#define ALDPS_SPDWN_RATIO  0x0f87
+
+/* PLA_MAC_PWR_CTRL2 */
+#define EEE_SPDWN_RATIO      0x8007
+#define MAC_CLK_SPDWN_EN     BIT(15)
+#define EEE_SPDWN_RATIO_MASK 0xff
+
+/* PLA_MAC_PWR_CTRL3 */
+#define PLA_MCU_SPDWN_EN   BIT(14)
+#define PKT_AVAIL_SPDWN_EN 0x0100
+#define SUSPEND_SPDWN_EN   0x0004
+#define U1U2_SPDWN_EN      0x0002
+#define L1_SPDWN_EN        0x0001
+
+/* PLA_MAC_PWR_CTRL4 */
+#define PWRSAVE_SPDWN_EN 0x1000
+#define RXDV_SPDWN_EN    0x0800
+#define TX10MIDLE_EN     0x0100
+#define IDLE_SPDWN_EN    BIT(6)
+#define TP100_SPDWN_EN   0x0020
+#define TP500_SPDWN_EN   0x0010
+#define TP1000_SPDWN_EN  0x0008
+#define EEE_SPDWN_EN     0x0001
+
+/* PLA_GPHY_INTR_IMR */
+#define GPHY_STS_MSK      0x0001
+#define SPEED_DOWN_MSK    0x0002
+#define SPDWN_RXDV_MSK    0x0004
+#define SPDWN_LINKCHG_MSK 0x0008
+
+/* PLA_PHYAR */
+#define PHYAR_FLAG 0x80000000
+
+/* PLA_EEE_CR */
+#define EEE_RX_EN 0x0001
+#define EEE_TX_EN 0x0002
+
+/* PLA_BOOT_CTRL */
+#define AUTOLOAD_DONE 0x0002
+
+/* PLA_LWAKE_CTRL_REG */
+#define LANWAKE_PIN BIT(7)
+
+/* PLA_SUSPEND_FLAG */
+#define LINK_CHG_EVENT BIT(0)
+
+/* PLA_INDICATE_FALG */
+#define UPCOMING_RUNTIME_D3 BIT(0)
+
+/* PLA_MACDBG_PRE and PLA_MACDBG_POST */
+#define DEBUG_OE    BIT(0)
+#define DEBUG_LTSSM 0x0082
+
+/* PLA_EXTRA_STATUS */
+#define CUR_LINK_OK      BIT(15)
+#define U3P3_CHECK_EN    BIT(7) /* RTL_VER_05 only */
+#define LINK_CHANGE_FLAG BIT(8)
+#define POLL_LINK_CHG    BIT(0)
+
+/* PLA_GPHY_CTRL */
+#define GPHY_FLASH BIT(1)
+
+/* PLA_POL_GPIO_CTRL */
+#define DACK_DET_EN    BIT(15)
+#define POL_GPHY_PATCH BIT(4)
+
+/* USB_USB2PHY */
+#define USB2PHY_SUSPEND 0x0001
+#define USB2PHY_L1      0x0002
+
+/* USB_SSPHYLINK1 */
+#define DELAY_PHY_PWR_CHG BIT(1)
+
+/* USB_SSPHYLINK2 */
+#define pwd_dn_scale_mask 0x3ffe
+#define pwd_dn_scale(x)   ((x) << 1)
+
+/* USB_CSR_DUMMY1 */
+#define DYNAMIC_BURST 0x0001
+
+/* USB_CSR_DUMMY2 */
+#define EP4_FULL_FC 0x0001
+
+/* USB_DEV_STAT */
+#define STAT_SPEED_MASK 0x0006
+#define STAT_SPEED_HIGH 0x0000
+#define STAT_SPEED_FULL 0x0002
+
+/* USB_FW_FIX_EN0 */
+#define FW_FIX_SUSPEND BIT(14)
+
+/* USB_FW_FIX_EN1 */
+#define FW_IP_RESET_EN BIT(9)
+
+/* USB_LPM_CONFIG */
+#define LPM_U1U2_EN BIT(0)
+
+/* USB_TX_AGG */
+#define TX_AGG_MAX_THRESHOLD 0x03
+
+/* USB_RX_BUF_TH */
+#define RX_THR_SUPPER 0x0c350180
+#define RX_THR_HIGH   0x7a120180
+#define RX_THR_SLOW   0xffff0180
+#define RX_THR_B      0x00010001
+
+/* USB_TX_DMA */
+#define TEST_MODE_DISABLE 0x00000001
+#define TX_SIZE_ADJUST1   0x00000100
+
+/* USB_BMU_RESET */
+#define BMU_RESET_EP_IN  0x01
+#define BMU_RESET_EP_OUT 0x02
+
+/* USB_BMU_CONFIG */
+#define ACT_ODMA BIT(1)
+
+/* USB_UPT_RXDMA_OWN */
+#define OWN_UPDATE BIT(0)
+#define OWN_CLEAR  BIT(1)
+
+/* USB_FW_TASK */
+#define FC_PATCH_TASK BIT(1)
+
+/* USB_RX_AGGR_NUM */
+#define RX_AGGR_NUM_MASK 0x1ff
+
+/* USB_UPS_CTRL */
+#define POWER_CUT 0x0100
+
+/* USB_PM_CTRL_STATUS */
+#define RESUME_INDICATE 0x0001
+
+/* USB_ECM_OPTION */
+#define BYPASS_MAC_RESET BIT(5)
+
+/* USB_CSTMR */
+#define FORCE_SUPER BIT(0)
+
+/* USB_MISC_2 */
+#define UPS_FORCE_PWR_DOWN BIT(0)
+
+/* USB_ECM_OP */
+#define EN_ALL_SPEED BIT(0)
+
+/* USB_GPHY_CTRL */
+#define GPHY_PATCH_DONE BIT(2)
+#define BYPASS_FLASH    BIT(5)
+#define BACKUP_RESTRORE BIT(6)
+
+/* USB_SPEED_OPTION */
+#define RG_PWRDN_EN   BIT(8)
+#define ALL_SPEED_OFF BIT(9)
+
+/* USB_FW_CTRL */
+#define FLOW_CTRL_PATCH_OPT BIT(1)
+#define AUTO_SPEEDUP        BIT(3)
+#define FLOW_CTRL_PATCH_2   BIT(8)
+
+/* USB_FC_TIMER */
+#define CTRL_TIMER_EN BIT(15)
+
+/* USB_USB_CTRL */
+#define CDC_ECM_EN     BIT(3)
+#define RX_AGG_DISABLE 0x0010
+#define RX_ZERO_EN     0x0080
+
+/* USB_U2P3_CTRL */
+#define U2P3_ENABLE 0x0001
+#define RX_DETECT8  BIT(3)
+
+/* USB_POWER_CUT */
+#define PWR_EN      0x0001
+#define PHASE2_EN   0x0008
+#define UPS_EN      BIT(4)
+#define USP_PREWAKE BIT(5)
+
+/* USB_MISC_0 */
+#define PCUT_STATUS 0x0001
+
+/* USB_RX_EARLY_TIMEOUT */
+#define COALESCE_SUPER 85000U
+#define COALESCE_HIGH  250000U
+#define COALESCE_SLOW  524280U
+
+/* USB_WDT1_CTRL */
+#define WTD1_EN BIT(0)
+
+/* USB_WDT11_CTRL */
+#define TIMER11_EN 0x0001
+
+/* USB_LPM_CTRL */
+/* bit 4 ~ 5: fifo empty boundary */
+#define FIFO_EMPTY_1FB 0x30 /* 0x1fb * 64 = 32448 bytes */
+/* bit 2 ~ 3: LMP timer */
+#define LPM_TIMER_MASK  0x0c
+#define LPM_TIMER_500MS 0x04 /* 500 ms */
+#define LPM_TIMER_500US 0x0c /* 500 us */
+#define ROK_EXIT_LPM    0x02
+
+/* USB_AFE_CTRL2 */
+#define SEN_VAL_MASK   0xf800
+#define SEN_VAL_NORMAL 0xa000
+#define SEL_RXIDLE     0x0100
+
+/* USB_UPHY_XTAL */
+#define OOBS_POLLING BIT(8)
+
+/* USB_UPS_CFG */
+#define SAW_CNT_1MS_MASK 0x0fff
+#define MID_REVERSE      BIT(5) /* RTL8156A */
+
+/* USB_UPS_FLAGS */
+#define UPS_FLAGS_R_TUNE          BIT(0)
+#define UPS_FLAGS_EN_10M_CKDIV    BIT(1)
+#define UPS_FLAGS_250M_CKDIV      BIT(2)
+#define UPS_FLAGS_EN_ALDPS        BIT(3)
+#define UPS_FLAGS_CTAP_SHORT_DIS  BIT(4)
+#define UPS_FLAGS_SPEED_MASK      (0xf << 16)
+#define ups_flags_speed(x)        ((x) << 16)
+#define UPS_FLAGS_EN_EEE          BIT(20)
+#define UPS_FLAGS_EN_500M_EEE     BIT(21)
+#define UPS_FLAGS_EN_EEE_CKDIV    BIT(22)
+#define UPS_FLAGS_EEE_PLLOFF_100  BIT(23)
+#define UPS_FLAGS_EEE_PLLOFF_GIGA BIT(24)
+#define UPS_FLAGS_EEE_CMOD_LV_EN  BIT(25)
+#define UPS_FLAGS_EN_GREEN        BIT(26)
+#define UPS_FLAGS_EN_FLOW_CTR     BIT(27)
+
+enum spd_duplex {
+    NWAY_10M_HALF,
+    NWAY_10M_FULL,
+    NWAY_100M_HALF,
+    NWAY_100M_FULL,
+    NWAY_1000M_FULL,
+    FORCE_10M_HALF,
+    FORCE_10M_FULL,
+    FORCE_100M_HALF,
+    FORCE_100M_FULL,
+    FORCE_1000M_FULL,
+    NWAY_2500M_FULL,
+};
+
+/* OCP_ALDPS_CONFIG */
+#define ENPWRSAVE  0x8000
+#define ENPDNPS    0x0200
+#define LINKENA    0x0100
+#define DIS_SDSAVE 0x0010
+
+/* OCP_PHY_STATUS */
+#define PHY_STAT_MASK     0x0007
+#define PHY_STAT_EXT_INIT 2
+#define PHY_STAT_LAN_ON   3
+#define PHY_STAT_PWRDN    5
+
+/* OCP_INTR_EN */
+#define INTR_SPEED_FORCE BIT(3)
+
+/* OCP_NCTL_CFG */
+#define PGA_RETURN_EN BIT(1)
+
+/* OCP_POWER_CFG */
+#define EEE_CLKDIV_EN 0x8000
+#define EN_ALDPS      0x0004
+#define EN_10M_PLLOFF 0x0001
+
+/* OCP_EEE_CONFIG1 */
+#define RG_TXLPI_MSK_HFDUP 0x8000
+#define RG_MATCLR_EN       0x4000
+#define EEE_10_CAP         0x2000
+#define EEE_NWAY_EN        0x1000
+#define TX_QUIET_EN        0x0200
+#define RX_QUIET_EN        0x0100
+#define sd_rise_time_mask  0x0070
+#define sd_rise_time(x)    (MIN(x, 7) << 4) /* bit 4 ~ 6 */
+#define RG_RXLPI_MSK_HFDUP 0x0008
+#define SDFALLTIME         0x0007 /* bit 0 ~ 2 */
+
+/* OCP_EEE_CONFIG2 */
+#define RG_LPIHYS_NUM  0x7000 /* bit 12 ~ 15 */
+#define RG_DACQUIET_EN 0x0400
+#define RG_LDVQUIET_EN 0x0200
+#define RG_CKRSEL      0x0020
+#define RG_EEEPRG_EN   0x0010
+
+/* OCP_EEE_CONFIG3 */
+#define fast_snr_mask 0xff80
+#define fast_snr(x)   (MIN(x, 0x1ff) << 7) /* bit 7 ~ 15 */
+#define RG_LFS_SEL    0x0060               /* bit 6 ~ 5 */
+#define MSK_PH        0x0006               /* bit 0 ~ 3 */
+
+/* OCP_EEE_AR */
+/* bit[15:14] function */
+#define FUN_ADDR 0x0000
+#define FUN_DATA 0x4000
+/* bit[4:0] device addr */
+
+/* OCP_EEE_CFG */
+#define CTAP_SHORT_EN 0x0040
+#define EEE10_EN      0x0010
+
+/* OCP_DOWN_SPEED */
+#define EN_EEE_CMODE  BIT(14)
+#define EN_EEE_1000   BIT(13)
+#define EN_EEE_100    BIT(12)
+#define EN_10M_CLKDIV BIT(11)
+#define EN_10M_BGOFF  0x0080
+
+/* OCP_10GBT_CTRL */
+#define RTL_ADV2_5G_F_R BIT(5) /* Advertise 2.5GBASE-T fast-retrain */
+
+/* OCP_PHY_STATE */
+#define TXDIS_STATE 0x01
+#define ABD_STATE   0x02
+
+/* OCP_PHY_PATCH_STAT */
+#define PATCH_READY BIT(6)
+
+/* OCP_PHY_PATCH_CMD */
+#define PATCH_REQUEST BIT(4)
+
+/* OCP_PHY_LOCK */
+#define PATCH_LOCK BIT(0)
+
+/* OCP_ADC_CFG */
+#define CKADSEL_L 0x0100
+#define ADC_EN    0x0080
+#define EN_EMI_L  0x0040
+
+/* OCP_SYSCLK_CFG */
+#define sysclk_div_expo(x) (MIN(x, 5) << 8)
+#define clk_div_expo(x)    (MIN(x, 5) << 4)
+
+/* SRAM_GREEN_CFG */
+#define GREEN_ETH_EN BIT(15)
+#define R_TUNE_EN    BIT(11)
+
+/* SRAM_LPF_CFG */
+#define LPF_AUTO_TUNE 0x8000
+
+/* SRAM_10M_AMP1 */
+#define GDAC_IB_UPALL 0x0008
+
+/* SRAM_10M_AMP2 */
+#define AMP_DN 0x0200
+
+/* SRAM_IMPEDANCE */
+#define RX_DRIVING_MASK 0x6000
+
+/* SRAM_PHY_LOCK */
+#define PHY_PATCH_LOCK 0x0001
+
+/* MAC PASSTHRU */
+#define AD_MASK        0xfee0
+#define BND_MASK       0x0004
+#define BD_MASK        0x0001
+#define EFUSE          0xcfdb
+#define PASS_THRU_MASK 0x1
+
+#define BP4_SUPER_ONLY 0x1578 /* RTL_VER_04 only */
+
+enum rtl_register_content {
+    _2500bps = BIT(10),
+    _1250bps = BIT(9),
+    _500bps = BIT(8),
+    _tx_flow = BIT(6),
+    _rx_flow = BIT(5),
+    _1000bps = 0x10,
+    _100bps = 0x08,
+    _10bps = 0x04,
+    LINK_STATUS = 0x02,
+    FULL_DUP = 0x01,
+};
+
+#define is_speed_2500(_speed)   (((_speed) & (_2500bps | LINK_STATUS)) == (_2500bps | LINK_STATUS))
+#define is_flow_control(_speed) (((_speed) & (_tx_flow | _rx_flow)) == (_tx_flow | _rx_flow))
+
+#define RTL8152_MAX_TX 4
+#define RTL8152_MAX_RX 10
+#define INTBUFSIZE     2
+#define TX_ALIGN       4
+#define RX_ALIGN       8
+
+#define RTL8152_RX_MAX_PENDING 4096
+#define RTL8152_RXFG_HEADSZ    256
+
+#define INTR_LINK 0x0004
+
+#define VLAN_ETH_HLEN      18
+#define ETH_FCS_LEN        4
+#define VLAN_ETH_FRAME_LEN 1514
+
+#define RTL8152_RMS         (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
+#define RTL8153_RMS         RTL8153_MAX_PACKET
+#define mtu_to_size(m)      ((m) + VLAN_ETH_HLEN + ETH_FCS_LEN)
+#define size_to_mtu(s)      ((s)-VLAN_ETH_HLEN - ETH_FCS_LEN)
+#define rx_reserved_size(x) (mtu_to_size(x) + sizeof(struct rx_desc) + RX_ALIGN)
+
+struct rx_desc {
+    uint32_t opts1;
+#define RD_CRC      BIT(15)
+#define RX_LEN_MASK 0x7fff
+
+    uint32_t opts2;
+#define RD_UDP_CS  BIT(23)
+#define RD_TCP_CS  BIT(22)
+#define RD_IPV6_CS BIT(20)
+#define RD_IPV4_CS BIT(19)
+
+    uint32_t opts3;
+#define IPF         BIT(23) /* IP checksum fail */
+#define UDPF        BIT(22) /* UDP checksum fail */
+#define TCPF        BIT(21) /* TCP checksum fail */
+#define RX_VLAN_TAG BIT(16)
+
+    uint32_t opts4;
+    uint32_t opts5;
+    uint32_t opts6;
+};
+
+struct tx_desc {
+    uint32_t opts1;
+#define TX_FS         BIT(31) /* First segment of a packet */
+#define TX_LS         BIT(30) /* Final segment of a packet */
+#define LGSEND        BIT(29)
+#define GTSENDV4      BIT(28)
+#define GTSENDV6      BIT(27)
+#define GTTCPHO_SHIFT 18
+#define GTTCPHO_MAX   0x7fU
+#define TX_LEN_MAX    0x3ffffU
+
+    uint32_t opts2;
+#define UDP_CS      BIT(31) /* Calculate UDP/IP checksum */
+#define TCP_CS      BIT(30) /* Calculate TCP/IP checksum */
+#define IPV4_CS     BIT(29) /* Calculate IPv4 checksum */
+#define IPV6_CS     BIT(28) /* Calculate IPv6 checksum */
+#define MSS_SHIFT   17
+#define MSS_MAX     0x7ffU
+#define TCPHO_SHIFT 17
+#define TCPHO_MAX   0x7ffU
+#define TX_VLAN_TAG BIT(16)
+};
+
+enum rtl_version {
+    RTL_VER_UNKNOWN = 0,
+    RTL_VER_01,
+    RTL_VER_02,
+    RTL_VER_03,
+    RTL_VER_04,
+    RTL_VER_05,
+    RTL_VER_06,
+    RTL_VER_07,
+    RTL_VER_08,
+    RTL_VER_09,
+
+    RTL_TEST_01,
+    RTL_VER_10,
+    RTL_VER_11,
+    RTL_VER_12,
+    RTL_VER_13,
+    RTL_VER_14,
+    RTL_VER_15,
+
+    RTL_VER_MAX
+};
+
+/* mii.h */
+/* Generic MII registers. */
+#define MII_BMCR        0x00 /* Basic mode control register */
+#define MII_BMSR        0x01 /* Basic mode status register  */
+#define MII_PHYSID1     0x02 /* PHYS ID 1                   */
+#define MII_PHYSID2     0x03 /* PHYS ID 2                   */
+#define MII_ADVERTISE   0x04 /* Advertisement control reg   */
+#define MII_LPA         0x05 /* Link partner ability reg    */
+#define MII_EXPANSION   0x06 /* Expansion register          */
+#define MII_CTRL1000    0x09 /* 1000BASE-T control          */
+#define MII_STAT1000    0x0a /* 1000BASE-T status           */
+#define MII_MMD_CTRL    0x0d /* MMD Access Control Register */
+#define MII_MMD_DATA    0x0e /* MMD Access Data Register */
+#define MII_ESTATUS     0x0f /* Extended Status             */
+#define MII_DCOUNTER    0x12 /* Disconnect counter          */
+#define MII_FCSCOUNTER  0x13 /* False carrier counter       */
+#define MII_NWAYTEST    0x14 /* N-way auto-neg test reg     */
+#define MII_RERRCOUNTER 0x15 /* Receive error counter       */
+#define MII_SREVISION   0x16 /* Silicon revision            */
+#define MII_RESV1       0x17 /* Reserved...                 */
+#define MII_LBRERROR    0x18 /* Lpback, rx, bypass error    */
+#define MII_PHYADDR     0x19 /* PHY address                 */
+#define MII_RESV2       0x1a /* Reserved...                 */
+#define MII_TPISTATUS   0x1b /* TPI status for 10mbps       */
+#define MII_NCONFIG     0x1c /* Network interface config    */
+
+/* Basic mode control register. */
+#define BMCR_RESV      0x003f /* Unused...                   */
+#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000)         */
+#define BMCR_CTST      0x0080 /* Collision test              */
+#define BMCR_FULLDPLX  0x0100 /* Full duplex                 */
+#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart    */
+#define BMCR_ISOLATE   0x0400 /* Isolate data paths from MII */
+#define BMCR_PDOWN     0x0800 /* Enable low power state      */
+#define BMCR_ANENABLE  0x1000 /* Enable auto negotiation     */
+#define BMCR_SPEED100  0x2000 /* Select 100Mbps              */
+#define BMCR_LOOPBACK  0x4000 /* TXD loopback bits           */
+#define BMCR_RESET     0x8000 /* Reset to default state      */
+#define BMCR_SPEED10   0x0000 /* Select 10Mbps               */
+
+/* Basic mode status register. */
+#define BMSR_ERCAP        0x0001 /* Ext-reg capability          */
+#define BMSR_JCD          0x0002 /* Jabber detected             */
+#define BMSR_LSTATUS      0x0004 /* Link status                 */
+#define BMSR_ANEGCAPABLE  0x0008 /* Able to do auto-negotiation */
+#define BMSR_RFAULT       0x0010 /* Remote fault detected       */
+#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete   */
+#define BMSR_RESV         0x00c0 /* Unused...                   */
+#define BMSR_ESTATEN      0x0100 /* Extended Status in R15      */
+#define BMSR_100HALF2     0x0200 /* Can do 100BASE-T2 HDX       */
+#define BMSR_100FULL2     0x0400 /* Can do 100BASE-T2 FDX       */
+#define BMSR_10HALF       0x0800 /* Can do 10mbps, half-duplex  */
+#define BMSR_10FULL       0x1000 /* Can do 10mbps, full-duplex  */
+#define BMSR_100HALF      0x2000 /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL      0x4000 /* Can do 100mbps, full-duplex */
+#define BMSR_100BASE4     0x8000 /* Can do 100mbps, 4k packets  */
+
+/* Advertisement control register. */
+#define ADVERTISE_SLCT          0x001f /* Selector bits               */
+#define ADVERTISE_CSMA          0x0001 /* Only selector supported     */
+#define ADVERTISE_10HALF        0x0020 /* Try for 10mbps half-duplex  */
+#define ADVERTISE_1000XFULL     0x0020 /* Try for 1000BASE-X full-duplex */
+#define ADVERTISE_10FULL        0x0040 /* Try for 10mbps full-duplex  */
+#define ADVERTISE_1000XHALF     0x0040 /* Try for 1000BASE-X half-duplex */
+#define ADVERTISE_100HALF       0x0080 /* Try for 100mbps half-duplex */
+#define ADVERTISE_1000XPAUSE    0x0080 /* Try for 1000BASE-X pause    */
+#define ADVERTISE_100FULL       0x0100 /* Try for 100mbps full-duplex */
+#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
+#define ADVERTISE_100BASE4      0x0200 /* Try for 100mbps 4k packets  */
+#define ADVERTISE_PAUSE_CAP     0x0400 /* Try for pause               */
+#define ADVERTISE_PAUSE_ASYM    0x0800 /* Try for asymetric pause     */
+#define ADVERTISE_RESV          0x1000 /* Unused...                   */
+#define ADVERTISE_RFAULT        0x2000 /* Say we can detect faults    */
+#define ADVERTISE_LPACK         0x4000 /* Ack link partners response  */
+#define ADVERTISE_NPAGE         0x8000 /* Next page bit               */
+
+#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
+                        ADVERTISE_CSMA)
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+                       ADVERTISE_100HALF | ADVERTISE_100FULL)
+
+/* 1000BASE-T Control register */
+#define ADVERTISE_1000FULL    0x0200 /* Advertise 1000BASE-T full duplex */
+#define ADVERTISE_1000HALF    0x0100 /* Advertise 1000BASE-T half duplex */
+#define CTL1000_AS_MASTER     0x0800
+#define CTL1000_ENABLE_MASTER 0x1000
+
+/* ethtool.h */
+/* The forced speed, 10Mb, 100Mb, gigabit. */
+#define SPEED_10   10
+#define SPEED_100  100
+#define SPEED_1000 1000
+
+#define SPEED_UNKNOWN -1
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF    0x00
+#define DUPLEX_FULL    0x01
+#define DUPLEX_UNKNOWN 0xff
+
+/* Enable or disable autonegotiation. */
+#define AUTONEG_DISABLE 0x00
+#define AUTONEG_ENABLE  0x01
+
+static int usbh_rtl8152_read_regs(struct usbh_rtl8152 *rtl8152_class,
+                                  uint16_t value,
+                                  uint16_t index,
+                                  uint16_t size,
+                                  void *data)
+{
+    struct usb_setup_packet *setup = rtl8152_class->hport->setup;
+    int ret;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = RTL8152_REQ_GET_REGS;
+    setup->wValue = value;
+    setup->wIndex = index;
+    setup->wLength = size;
+
+    ret = usbh_control_transfer(rtl8152_class->hport, setup, g_rtl8152_buf);
+    if (ret < 0) {
+        return ret;
+    }
+    memcpy(data, g_rtl8152_buf, ret - 8);
+
+    return ret;
+}
+
+static int usbh_rtl8152_write_regs(struct usbh_rtl8152 *rtl8152_class,
+                                   uint16_t value,
+                                   uint16_t index,
+                                   uint16_t size,
+                                   void *data)
+{
+    struct usb_setup_packet *setup = rtl8152_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = RTL8152_REQ_SET_REGS;
+    setup->wValue = value;
+    setup->wIndex = index;
+    setup->wLength = size;
+
+    memcpy(g_rtl8152_buf, data, size);
+    return usbh_control_transfer(rtl8152_class->hport, setup, g_rtl8152_buf);
+}
+
+static int generic_ocp_read(struct usbh_rtl8152 *tp, uint16_t index, uint16_t size,
+                            void *data, uint16_t type)
+{
+    uint16_t limit = 64;
+    int ret = 0;
+
+    /* both size and indix must be 4 bytes align */
+    if ((size & 3) || !size || (index & 3) || !data)
+        return -USB_ERR_INVAL;
+
+    if ((uint32_t)index + (uint32_t)size > 0xffff)
+        return -USB_ERR_INVAL;
+
+    while (size) {
+        if (size > limit) {
+            ret = usbh_rtl8152_read_regs(tp, index, type, limit, data);
+            if (ret < 0)
+                break;
+
+            index += limit;
+            data += limit;
+            size -= limit;
+        } else {
+            ret = usbh_rtl8152_read_regs(tp, index, type, size, data);
+            if (ret < 0)
+                break;
+
+            index += size;
+            data += size;
+            size = 0;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+static int generic_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_t byteen,
+                             uint16_t size, void *data, uint16_t type)
+{
+    int ret;
+    uint16_t byteen_start, byteen_end, byen;
+    uint16_t limit = 512;
+
+    /* both size and indix must be 4 bytes align */
+    if ((size & 3) || !size || (index & 3) || !data)
+        return -USB_ERR_INVAL;
+
+    if ((uint32_t)index + (uint32_t)size > 0xffff)
+        return -USB_ERR_INVAL;
+
+    byteen_start = byteen & BYTE_EN_START_MASK;
+    byteen_end = byteen & BYTE_EN_END_MASK;
+
+    byen = byteen_start | (byteen_start << 4);
+
+    /* Split the first DWORD if the byte_en is not 0xff */
+    if (byen != BYTE_EN_DWORD) {
+        ret = usbh_rtl8152_write_regs(tp, index, type | byen, 4, data);
+        if (ret < 0)
+            goto error1;
+
+        index += 4;
+        data += 4;
+        size -= 4;
+    }
+
+    if (size) {
+        byen = byteen_end | (byteen_end >> 4);
+
+        /* Split the last DWORD if the byte_en is not 0xff */
+        if (byen != BYTE_EN_DWORD)
+            size -= 4;
+
+        while (size) {
+            if (size > limit) {
+                ret = usbh_rtl8152_write_regs(tp, index,
+                                              type | BYTE_EN_DWORD,
+                                              limit, data);
+                if (ret < 0)
+                    goto error1;
+
+                index += limit;
+                data += limit;
+                size -= limit;
+            } else {
+                ret = usbh_rtl8152_write_regs(tp, index,
+                                              type | BYTE_EN_DWORD,
+                                              size, data);
+                if (ret < 0)
+                    goto error1;
+
+                index += size;
+                data += size;
+                size = 0;
+                break;
+            }
+        }
+
+        /* Set the last DWORD */
+        if (byen != BYTE_EN_DWORD)
+            ret = usbh_rtl8152_write_regs(tp, index, type | byen, 4, data);
+    }
+
+error1:
+
+    return ret;
+}
+
+static inline int pla_ocp_read(struct usbh_rtl8152 *tp, uint16_t index, uint16_t size, void *data)
+{
+    return generic_ocp_read(tp, index, size, data, MCU_TYPE_PLA);
+}
+
+static inline int pla_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_t byteen, uint16_t size, void *data)
+{
+    return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_PLA);
+}
+
+static inline int usb_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_t byteen, uint16_t size, void *data)
+{
+    return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_USB);
+}
+
+static uint32_t ocp_read_dword(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index)
+{
+    uint32_t data;
+
+    generic_ocp_read(tp, index, sizeof(data), &data, type);
+
+    return data;
+}
+
+static void ocp_write_dword(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index, uint32_t data)
+{
+    uint32_t tmp = data;
+
+    generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type);
+}
+
+static uint16_t ocp_read_word(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index)
+{
+    uint32_t data;
+    uint32_t tmp;
+    uint16_t byen = BYTE_EN_WORD;
+    uint8_t shift = index & 2;
+
+    index &= ~3;
+    byen <<= shift;
+
+    generic_ocp_read(tp, index, sizeof(tmp), &tmp, type | byen);
+
+    data = tmp;
+    data >>= (shift * 8);
+    data &= 0xffff;
+
+    return (uint16_t)data;
+}
+
+static void ocp_write_word(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index, uint32_t data)
+{
+    uint32_t mask = 0xffff;
+    uint32_t tmp;
+    uint16_t byen = BYTE_EN_WORD;
+    uint8_t shift = index & 2;
+
+    data &= mask;
+
+    if (index & 2) {
+        byen <<= shift;
+        mask <<= (shift * 8);
+        data <<= (shift * 8);
+        index &= ~3;
+    }
+
+    tmp = data;
+
+    generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
+}
+
+static uint8_t ocp_read_byte(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index)
+{
+    uint32_t data;
+    uint32_t tmp;
+    uint8_t shift = index & 3;
+
+    index &= ~3;
+
+    generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
+
+    data = tmp;
+    data >>= (shift * 8);
+    data &= 0xff;
+
+    return (uint8_t)data;
+}
+
+static void ocp_write_byte(struct usbh_rtl8152 *tp, uint16_t type, uint16_t index, uint32_t data)
+{
+    uint32_t mask = 0xff;
+    uint32_t tmp;
+    uint16_t byen = BYTE_EN_BYTE;
+    uint8_t shift = index & 3;
+
+    data &= mask;
+
+    if (index & 3) {
+        byen <<= shift;
+        mask <<= (shift * 8);
+        data <<= (shift * 8);
+        index &= ~3;
+    }
+
+    tmp = data;
+
+    generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
+}
+
+static uint16_t ocp_reg_read(struct usbh_rtl8152 *tp, uint16_t addr)
+{
+    uint16_t ocp_base, ocp_index;
+
+    ocp_base = addr & 0xf000;
+    if (ocp_base != tp->ocp_base) {
+        ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
+        tp->ocp_base = ocp_base;
+    }
+
+    ocp_index = (addr & 0x0fff) | 0xb000;
+    return ocp_read_word(tp, MCU_TYPE_PLA, ocp_index);
+}
+
+static void ocp_reg_write(struct usbh_rtl8152 *tp, uint16_t addr, uint16_t data)
+{
+    uint16_t ocp_base, ocp_index;
+
+    ocp_base = addr & 0xf000;
+    if (ocp_base != tp->ocp_base) {
+        ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
+        tp->ocp_base = ocp_base;
+    }
+
+    ocp_index = (addr & 0x0fff) | 0xb000;
+    ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data);
+}
+
+static inline void r8152_mdio_write(struct usbh_rtl8152 *tp, uint32_t reg_addr, uint32_t value)
+{
+    ocp_reg_write(tp, OCP_BASE_MII + reg_addr * 2, value);
+}
+
+static inline int r8152_mdio_read(struct usbh_rtl8152 *tp, uint32_t reg_addr)
+{
+    return ocp_reg_read(tp, OCP_BASE_MII + reg_addr * 2);
+}
+
+static uint8_t usbh_rtl8152_get_version(struct usbh_rtl8152 *rtl8152_class)
+{
+    uint8_t version;
+    uint32_t temp;
+    uint32_t ocp_data;
+
+    usbh_rtl8152_read_regs(rtl8152_class, PLA_TCR0, MCU_TYPE_PLA, 4, &temp);
+
+    ocp_data = (temp >> 16) & VERSION_MASK;
+    switch (ocp_data) {
+        case 0x4c00:
+            version = RTL_VER_01;
+            break;
+        case 0x4c10:
+            version = RTL_VER_02;
+            break;
+        case 0x5c00:
+            version = RTL_VER_03;
+            break;
+        case 0x5c10:
+            version = RTL_VER_04;
+            break;
+        case 0x5c20:
+            version = RTL_VER_05;
+            break;
+        case 0x5c30:
+            version = RTL_VER_06;
+            break;
+        case 0x4800:
+            version = RTL_VER_07;
+            break;
+        case 0x6000:
+            version = RTL_VER_08;
+            break;
+        case 0x6010:
+            version = RTL_VER_09;
+            break;
+        case 0x7010:
+            version = RTL_TEST_01;
+            break;
+        case 0x7020:
+            version = RTL_VER_10;
+            break;
+        case 0x7030:
+            version = RTL_VER_11;
+            break;
+        case 0x7400:
+            version = RTL_VER_12;
+            break;
+        case 0x7410:
+            version = RTL_VER_13;
+            break;
+        case 0x6400:
+            version = RTL_VER_14;
+            break;
+        case 0x7420:
+            version = RTL_VER_15;
+            break;
+        default:
+            version = RTL_VER_UNKNOWN;
+            break;
+    }
+
+    return version;
+}
+
+#define WAKE_PHY         (1 << 0)
+#define WAKE_UCAST       (1 << 1)
+#define WAKE_MCAST       (1 << 2)
+#define WAKE_BCAST       (1 << 3)
+#define WAKE_ARP         (1 << 4)
+#define WAKE_MAGIC       (1 << 5)
+#define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */
+#define WAKE_FILTER      (1 << 7)
+
+#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
+
+static uint32_t __rtl_get_wol(struct usbh_rtl8152 *tp)
+{
+    uint32_t ocp_data;
+    uint32_t wolopts = 0;
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
+    if (ocp_data & LINK_ON_WAKE_EN)
+        wolopts |= WAKE_PHY;
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5);
+    if (ocp_data & UWF_EN)
+        wolopts |= WAKE_UCAST;
+    if (ocp_data & BWF_EN)
+        wolopts |= WAKE_BCAST;
+    if (ocp_data & MWF_EN)
+        wolopts |= WAKE_MCAST;
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
+    if (ocp_data & MAGIC_EN)
+        wolopts |= WAKE_MAGIC;
+
+    return wolopts;
+}
+
+static void r8152_aldps_en(struct usbh_rtl8152 *tp, bool enable)
+{
+    if (enable) {
+        ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS | LINKENA | DIS_SDSAVE);
+    } else {
+        ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
+        usb_osal_msleep(20);
+    }
+}
+
+static void r8152_power_cut_en(struct usbh_rtl8152 *tp, bool enable)
+{
+    uint32_t ocp_data;
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
+    if (enable)
+        ocp_data |= POWER_CUT;
+    else
+        ocp_data &= ~POWER_CUT;
+    ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
+    ocp_data &= ~RESUME_INDICATE;
+    ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
+}
+
+static void rtl_tally_reset(struct usbh_rtl8152 *tp)
+{
+    uint32_t ocp_data;
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY);
+    ocp_data |= TALLY_RESET;
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data);
+}
+
+static void r8152b_reset_packet_filter(struct usbh_rtl8152 *tp)
+{
+    uint32_t ocp_data;
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_FMC);
+    ocp_data &= ~FMC_FCR_MCU_EN;
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
+    ocp_data |= FMC_FCR_MCU_EN;
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
+}
+
+static inline void r8153b_rx_agg_chg_indicate(struct usbh_rtl8152 *tp)
+{
+    ocp_write_byte(tp, MCU_TYPE_USB, USB_UPT_RXDMA_OWN,
+                   OWN_UPDATE | OWN_CLEAR);
+}
+
+static void rxdy_gated_en(struct usbh_rtl8152 *tp, bool enable)
+{
+    uint32_t ocp_data;
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
+    if (enable)
+        ocp_data |= RXDY_GATED_EN;
+    else
+        ocp_data &= ~RXDY_GATED_EN;
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+}
+
+static inline uint16_t rtl8152_get_speed(struct usbh_rtl8152 *tp)
+{
+    return ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHYSTATUS);
+}
+
+static void rtl_eee_plus_en(struct usbh_rtl8152 *tp, bool enable)
+{
+    uint32_t ocp_data;
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
+    if (enable)
+        ocp_data |= EEEP_CR_EEEP_TX;
+    else
+        ocp_data &= ~EEEP_CR_EEEP_TX;
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
+}
+
+static void rtl_set_eee_plus(struct usbh_rtl8152 *tp)
+{
+    if (rtl8152_get_speed(tp) & _10bps)
+        rtl_eee_plus_en(tp, true);
+    else
+        rtl_eee_plus_en(tp, false);
+}
+
+static void rtl8152_nic_reset(struct usbh_rtl8152 *tp)
+{
+    uint32_t ocp_data;
+    int i;
+
+    switch (tp->version) {
+        case RTL_TEST_01:
+        case RTL_VER_10:
+        case RTL_VER_11:
+            ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
+            ocp_data &= ~CR_TE;
+            ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
+
+            ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_BMU_RESET);
+            ocp_data &= ~BMU_RESET_EP_IN;
+            ocp_write_word(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
+
+            ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
+            ocp_data |= CDC_ECM_EN;
+            ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+
+            ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
+            ocp_data &= ~CR_RE;
+            ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
+
+            ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_BMU_RESET);
+            ocp_data |= BMU_RESET_EP_IN;
+            ocp_write_word(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data);
+
+            ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
+            ocp_data &= ~CDC_ECM_EN;
+            ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+            break;
+
+        default:
+            ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, CR_RST);
+
+            for (i = 0; i < 1000; i++) {
+                if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & CR_RST))
+                    break;
+                usb_osal_msleep(400);
+            }
+            break;
+    }
+}
+
+static void rtl_disable(struct usbh_rtl8152 *tp)
+{
+    uint32_t ocp_data;
+    int i;
+
+    ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+    ocp_data &= ~RCR_ACPT_ALL;
+    ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+
+    rxdy_gated_en(tp, true);
+
+    for (i = 0; i < 1000; i++) {
+        ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+        if ((ocp_data & FIFO_EMPTY) == FIFO_EMPTY)
+            break;
+        usb_osal_msleep(1);
+    }
+
+    for (i = 0; i < 1000; i++) {
+        if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0) & TCR0_TX_EMPTY)
+            break;
+        usb_osal_msleep(1);
+    }
+
+    rtl8152_nic_reset(tp);
+}
+
+static void rtl_rx_vlan_en(struct usbh_rtl8152 *tp, bool enable)
+{
+    uint32_t ocp_data;
+
+    switch (tp->version) {
+        case RTL_VER_01:
+        case RTL_VER_02:
+        case RTL_VER_03:
+        case RTL_VER_04:
+        case RTL_VER_05:
+        case RTL_VER_06:
+        case RTL_VER_07:
+        case RTL_VER_08:
+        case RTL_VER_09:
+        case RTL_VER_14:
+            ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
+            if (enable)
+                ocp_data |= CPCR_RX_VLAN;
+            else
+                ocp_data &= ~CPCR_RX_VLAN;
+            ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
+            break;
+
+        case RTL_TEST_01:
+        case RTL_VER_10:
+        case RTL_VER_11:
+        case RTL_VER_12:
+        case RTL_VER_13:
+        case RTL_VER_15:
+        default:
+            ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RCR1);
+            if (enable)
+                ocp_data |= OUTER_VLAN | INNER_VLAN;
+            else
+                ocp_data &= ~(OUTER_VLAN | INNER_VLAN);
+            ocp_write_word(tp, MCU_TYPE_PLA, PLA_RCR1, ocp_data);
+            break;
+    }
+}
+
+static void wait_oob_link_list_ready(struct usbh_rtl8152 *tp)
+{
+    uint32_t ocp_data;
+    int i;
+
+    for (i = 0; i < 1000; i++) {
+        ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+        if (ocp_data & LINK_LIST_READY)
+            break;
+        usb_osal_msleep(1);
+    }
+}
+
+static void r8153_teredo_off(struct usbh_rtl8152 *tp)
+{
+    uint32_t ocp_data;
+
+    switch (tp->version) {
+        case RTL_VER_01:
+        case RTL_VER_02:
+        case RTL_VER_03:
+        case RTL_VER_04:
+        case RTL_VER_05:
+        case RTL_VER_06:
+        case RTL_VER_07:
+            ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
+            ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK |
+                          OOB_TEREDO_EN);
+            ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
+            break;
+
+        case RTL_VER_08:
+        case RTL_VER_09:
+        case RTL_TEST_01:
+        case RTL_VER_10:
+        case RTL_VER_11:
+        case RTL_VER_12:
+        case RTL_VER_13:
+        case RTL_VER_14:
+        case RTL_VER_15:
+        default:
+            /* The bit 0 ~ 7 are relative with teredo settings. They are
+		 * W1C (write 1 to clear), so set all 1 to disable it.
+		 */
+            ocp_write_byte(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, 0xff);
+            break;
+    }
+
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE);
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0);
+    ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0);
+}
+
+static void r8152b_exit_oob(struct usbh_rtl8152 *tp)
+{
+    uint32_t ocp_data;
+
+    ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+    ocp_data &= ~RCR_ACPT_ALL;
+    ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+
+    rxdy_gated_en(tp, true);
+    r8153_teredo_off(tp);
+    ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+    ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00);
+
+    ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+    ocp_data &= ~NOW_IS_OOB;
+    ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+    ocp_data &= ~MCU_BORW_EN;
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+    wait_oob_link_list_ready(tp);
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+    ocp_data |= RE_INIT_LL;
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+    wait_oob_link_list_ready(tp);
+
+    rtl8152_nic_reset(tp);
+
+    /* rx share fifo credit full threshold */
+    ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
+
+    if (tp->hport->speed == USB_SPEED_FULL ||
+        tp->hport->speed == USB_SPEED_LOW) {
+        /* rx share fifo credit near full threshold */
+        ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
+                        RXFIFO_THR2_FULL);
+        ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
+                        RXFIFO_THR3_FULL);
+    } else {
+        /* rx share fifo credit near full threshold */
+        ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
+                        RXFIFO_THR2_HIGH);
+        ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
+                        RXFIFO_THR3_HIGH);
+    }
+
+    /* TX share fifo free credit full threshold */
+    ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2);
+
+    ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD);
+    ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH);
+    ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA,
+                    TEST_MODE_DISABLE | TX_SIZE_ADJUST1);
+
+    rtl_rx_vlan_en(tp, true);
+
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
+    ocp_data |= TCR0_AUTO_FIFO;
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data);
+}
+
+static void r8152b_enter_oob(struct usbh_rtl8152 *tp)
+{
+    uint32_t ocp_data;
+
+    ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+    ocp_data &= ~NOW_IS_OOB;
+    ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+    ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB);
+    ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB);
+    ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB);
+
+    rtl_disable(tp);
+
+    wait_oob_link_list_ready(tp);
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+    ocp_data |= RE_INIT_LL;
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+    wait_oob_link_list_ready(tp);
+
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
+
+    rtl_rx_vlan_en(tp, true);
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BDC_CR);
+    ocp_data |= ALDPS_PROXY_MODE;
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_BDC_CR, ocp_data);
+
+    ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+    ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
+    ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+    rxdy_gated_en(tp, false);
+
+    ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+    ocp_data |= RCR_APM | RCR_AM | RCR_AB;
+    ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+}
+
+static void r8152b_init(struct usbh_rtl8152 *tp)
+{
+    uint32_t ocp_data;
+    uint16_t data;
+
+    data = r8152_mdio_read(tp, MII_BMCR);
+    if (data & BMCR_PDOWN) {
+        data &= ~BMCR_PDOWN;
+        r8152_mdio_write(tp, MII_BMCR, data);
+    }
+
+    r8152_aldps_en(tp, false);
+
+    if (tp->version == RTL_VER_01) {
+        ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
+        ocp_data &= ~LED_MODE_MASK;
+        ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
+    }
+
+    r8152_power_cut_en(tp, false);
+
+    ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
+    ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH;
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
+    ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL);
+    ocp_data &= ~MCU_CLK_RATIO_MASK;
+    ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN;
+    ocp_write_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data);
+    ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK |
+               SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK;
+    ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data);
+
+    rtl_tally_reset(tp);
+
+    /* enable rx aggregation */
+    ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
+    ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
+    ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+}
+
+static int rtl_enable(struct usbh_rtl8152 *tp)
+{
+    uint32_t ocp_data;
+
+    r8152b_reset_packet_filter(tp);
+
+    ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
+    ocp_data |= CR_RE | CR_TE;
+    ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
+
+    switch (tp->version) {
+        case RTL_VER_01:
+        case RTL_VER_02:
+        case RTL_VER_03:
+        case RTL_VER_04:
+        case RTL_VER_05:
+        case RTL_VER_06:
+        case RTL_VER_07:
+            break;
+        default:
+            r8153b_rx_agg_chg_indicate(tp);
+            break;
+    }
+
+    rxdy_gated_en(tp, false);
+
+    return 0;
+}
+
+static int rtl8152_enable(struct usbh_rtl8152 *tp)
+{
+    rtl_set_eee_plus(tp);
+
+    return rtl_enable(tp);
+}
+
+static void rtl8152_disable(struct usbh_rtl8152 *tp)
+{
+    r8152_aldps_en(tp, false);
+    rtl_disable(tp);
+    r8152_aldps_en(tp, true);
+}
+
+static void rtl8152_up(struct usbh_rtl8152 *tp)
+{
+    r8152_aldps_en(tp, false);
+    r8152b_exit_oob(tp);
+    r8152_aldps_en(tp, true);
+}
+
+static void rtl8152_down(struct usbh_rtl8152 *tp)
+{
+    r8152_power_cut_en(tp, false);
+    r8152_aldps_en(tp, false);
+    r8152b_enter_oob(tp);
+    r8152_aldps_en(tp, true);
+}
+
+static int rtl_ops_init(struct usbh_rtl8152 *tp)
+{
+    struct rtl_ops *ops = &tp->rtl_ops;
+    int ret = 0;
+
+    switch (tp->version) {
+        case RTL_VER_01:
+        case RTL_VER_02:
+        case RTL_VER_07:
+            ops->init = r8152b_init;
+            ops->enable = rtl8152_enable;
+            ops->disable = rtl8152_disable;
+            ops->up = rtl8152_up;
+            ops->down = rtl8152_down;
+            // ops->unload = rtl8152_unload;
+            // ops->eee_get		= r8152_get_eee;
+            // ops->eee_set		= r8152_set_eee;
+            // ops->in_nway = rtl8152_in_nway;
+            // ops->hw_phy_cfg = r8152b_hw_phy_cfg;
+            // ops->autosuspend_en = rtl_runtime_suspend_enable;
+            tp->rx_buf_sz = 16 * 1024;
+            tp->eee_en = true;
+            //tp->eee_adv		= MDIO_EEE_100TX;
+            break;
+
+            // case RTL_VER_03:
+            // case RTL_VER_04:
+            // case RTL_VER_05:
+            // case RTL_VER_06:
+            //     break;
+
+            // case RTL_VER_08:
+            // case RTL_VER_09:
+            //     break;
+
+            // case RTL_VER_11:
+            // case RTL_VER_10:
+            //     break;
+
+            // case RTL_VER_12:
+            // case RTL_VER_13:
+            // case RTL_VER_15:
+            //     break;
+
+            // case RTL_VER_14:
+            //     break;
+
+        default:
+            ret = -USB_ERR_NODEV;
+            USB_LOG_ERR("Unsupport rtl version:%d\r\n", tp->version);
+            break;
+    }
+
+    return ret;
+}
+
+static void rtl8152_set_rx_mode(struct usbh_rtl8152 *tp)
+{
+    uint32_t ocp_data;
+    uint32_t mc_filter[2];
+
+    ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+    ocp_data &= ~RCR_ACPT_ALL;
+    ocp_data |= RCR_AB | RCR_APM;
+
+    ocp_data |= RCR_AM;
+    mc_filter[1] = 0xffffffff;
+    mc_filter[0] = 0xffffffff;
+
+    pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(mc_filter), mc_filter);
+    ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+}
+
+static int rtl8152_set_speed(struct usbh_rtl8152 *tp, uint8_t autoneg, uint16_t speed, uint8_t duplex)
+{
+    uint16_t bmcr, anar, gbcr;
+
+    anar = r8152_mdio_read(tp, MII_ADVERTISE);
+    anar &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
+              ADVERTISE_100HALF | ADVERTISE_100FULL);
+    if (tp->supports_gmii) {
+        gbcr = r8152_mdio_read(tp, MII_CTRL1000);
+        gbcr &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+    } else {
+        gbcr = 0;
+    }
+
+    if (autoneg == AUTONEG_DISABLE) {
+        if (speed == SPEED_10) {
+            bmcr = 0;
+            anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+        } else if (speed == SPEED_100) {
+            bmcr = BMCR_SPEED100;
+            anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+        } else if (speed == SPEED_1000 && tp->supports_gmii) {
+            bmcr = BMCR_SPEED1000;
+            gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
+        } else {
+            return -USB_ERR_INVAL;
+        }
+
+        if (duplex == DUPLEX_FULL)
+            bmcr |= BMCR_FULLDPLX;
+    } else {
+        if (speed == SPEED_10) {
+            if (duplex == DUPLEX_FULL)
+                anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+            else
+                anar |= ADVERTISE_10HALF;
+        } else if (speed == SPEED_100) {
+            if (duplex == DUPLEX_FULL) {
+                anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+                anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+            } else {
+                anar |= ADVERTISE_10HALF;
+                anar |= ADVERTISE_100HALF;
+            }
+        } else if (speed == SPEED_1000 && tp->supports_gmii) {
+            if (duplex == DUPLEX_FULL) {
+                anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+                anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+                gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
+            } else {
+                anar |= ADVERTISE_10HALF;
+                anar |= ADVERTISE_100HALF;
+                gbcr |= ADVERTISE_1000HALF;
+            }
+        } else {
+            return -USB_ERR_INVAL;
+        }
+
+        bmcr = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET;
+    }
+
+    if (tp->supports_gmii)
+        r8152_mdio_write(tp, MII_CTRL1000, gbcr);
+
+    r8152_mdio_write(tp, MII_ADVERTISE, anar);
+    r8152_mdio_write(tp, MII_BMCR, bmcr);
+
+    return 0;
+}
+
+int r8152_write_hwaddr(struct usbh_rtl8152 *tp, unsigned char *mac)
+{
+    unsigned char enetaddr[8] = { 0 };
+    memcpy(enetaddr, mac, 6);
+    ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
+    pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, enetaddr);
+    ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+    return 0;
+}
+
+int usbh_rtl8152_get_connect_status(struct usbh_rtl8152 *rtl8152_class)
+{
+    int ret;
+
+    usbh_int_urb_fill(&rtl8152_class->intin_urb, rtl8152_class->hport, rtl8152_class->intin, g_rtl8152_inttx_buffer, 2, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+    ret = usbh_submit_urb(&rtl8152_class->intin_urb);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (g_rtl8152_inttx_buffer[0] & INTR_LINK) {
+        rtl8152_class->connect_status = true;
+    } else {
+        rtl8152_class->connect_status = false;
+    }
+    return 0;
+}
+
+static int usbh_rtl8152_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    char mac_buffer[12];
+    int ret;
+
+    struct usbh_rtl8152 *rtl8152_class = &g_rtl8152_class;
+
+    memset(rtl8152_class, 0, sizeof(struct usbh_rtl8152));
+
+    rtl8152_class->hport = hport;
+    rtl8152_class->intf = intf;
+
+    hport->config.intf[intf].priv = rtl8152_class;
+
+    rtl8152_class->version = usbh_rtl8152_get_version(rtl8152_class);
+
+    if (rtl8152_class->version == RTL_VER_UNKNOWN) {
+        USB_LOG_ERR("Unknown version 0x%04x\r\n", rtl8152_class->version);
+        return -USB_ERR_NOTSUPP;
+    } else {
+        USB_LOG_INFO("rtl8152 version 0x%04x\r\n", rtl8152_class->version);
+    }
+
+    /* MTU range: 68 - 1500 or 9194 */
+    rtl8152_class->min_mtu = 68;
+    switch (rtl8152_class->version) {
+        case RTL_VER_03:
+        case RTL_VER_04:
+        case RTL_VER_05:
+        case RTL_VER_06:
+        case RTL_VER_08:
+        case RTL_VER_09:
+        case RTL_VER_14:
+            rtl8152_class->max_mtu = size_to_mtu(9 * 1024);
+            break;
+        case RTL_VER_10:
+        case RTL_VER_11:
+            rtl8152_class->max_mtu = size_to_mtu(15 * 1024);
+            break;
+        case RTL_VER_12:
+        case RTL_VER_13:
+        case RTL_VER_15:
+            rtl8152_class->max_mtu = size_to_mtu(16 * 1024);
+            break;
+        case RTL_VER_01:
+        case RTL_VER_02:
+        case RTL_VER_07:
+        default:
+            rtl8152_class->max_mtu = 1500;
+            break;
+    }
+
+    rtl8152_class->saved_wolopts = __rtl_get_wol(rtl8152_class);
+    if (rtl_ops_init(rtl8152_class) < 0) {
+        return -USB_ERR_NODEV;
+    }
+
+    rtl8152_class->rtl_ops.init(rtl8152_class);
+    rtl8152_class->rtl_ops.up(rtl8152_class);
+
+    if (rtl8152_class->rx_buf_sz > CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE) {
+        USB_LOG_ERR("rx_buf_sz is overflow, default is %d\r\n", CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE);
+        return -USB_ERR_NOMEM;
+    }
+
+    memset(mac_buffer, 0, 12);
+    ret = usbh_get_string_desc(rtl8152_class->hport, 3, (uint8_t *)mac_buffer);
+    if (ret < 0) {
+        return ret;
+    }
+
+    for (int i = 0, j = 0; i < 12; i += 2, j++) {
+        char byte_str[3];
+        byte_str[0] = mac_buffer[i];
+        byte_str[1] = mac_buffer[i + 1];
+        byte_str[2] = '\0';
+
+        uint32_t byte = strtoul(byte_str, NULL, 16);
+        rtl8152_class->mac[j] = (unsigned char)byte;
+    }
+
+    r8152_write_hwaddr(rtl8152_class, rtl8152_class->mac);
+
+    USB_LOG_INFO("RTL8152 MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
+                 rtl8152_class->mac[0],
+                 rtl8152_class->mac[1],
+                 rtl8152_class->mac[2],
+                 rtl8152_class->mac[3],
+                 rtl8152_class->mac[4],
+                 rtl8152_class->mac[5]);
+
+    for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
+        ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
+
+        if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(rtl8152_class->intin, ep_desc);
+            } else {
+                return -USB_ERR_NOTSUPP;
+            }
+        } else {
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(rtl8152_class->bulkin, ep_desc);
+            } else {
+                USBH_EP_INIT(rtl8152_class->bulkout, ep_desc);
+            }
+        }
+    }
+
+    memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
+
+    USB_LOG_INFO("Register RTL8152 Class:%s\r\n", hport->config.intf[intf].devname);
+
+    usbh_rtl8152_run(rtl8152_class);
+    return 0;
+}
+
+static int usbh_rtl8152_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_rtl8152 *rtl8152_class = (struct usbh_rtl8152 *)hport->config.intf[intf].priv;
+
+    if (rtl8152_class) {
+        if (rtl8152_class->bulkin) {
+            usbh_kill_urb(&rtl8152_class->bulkin_urb);
+        }
+
+        if (rtl8152_class->bulkout) {
+            usbh_kill_urb(&rtl8152_class->bulkout_urb);
+        }
+
+        if (rtl8152_class->intin) {
+            usbh_kill_urb(&rtl8152_class->intin_urb);
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister rtl8152 Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_rtl8152_stop(rtl8152_class);
+        }
+
+        memset(rtl8152_class, 0, sizeof(struct usbh_rtl8152));
+    }
+
+    return ret;
+}
+
+void usbh_rtl8152_rx_thread(void *argument)
+{
+    uint32_t g_rtl8152_rx_length;
+    int ret;
+    uint16_t len;
+    uint16_t data_offset;
+
+    USB_LOG_INFO("Create rtl8152 rx thread\r\n");
+    // clang-format off
+find_class:
+    // clang-format on
+    g_rtl8152_class.connect_status = false;
+    if (usbh_find_class_instance("/dev/rtl8152") == NULL) {
+        goto delete;
+    }
+
+    while (g_rtl8152_class.connect_status == false) {
+        ret = usbh_rtl8152_get_connect_status(&g_rtl8152_class);
+        if (ret < 0) {
+            usb_osal_msleep(100);
+            goto find_class;
+        }
+        usb_osal_msleep(128);
+    }
+
+    if (g_rtl8152_class.rtl_ops.enable) {
+        g_rtl8152_class.rtl_ops.enable(&g_rtl8152_class);
+    } else {
+        goto delete;
+    }
+
+    rtl8152_set_rx_mode(&g_rtl8152_class);
+    rtl8152_set_speed(&g_rtl8152_class, AUTONEG_ENABLE, g_rtl8152_class.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL);
+
+    g_rtl8152_rx_length = 0;
+    while (1) {
+        usbh_bulk_urb_fill(&g_rtl8152_class.bulkin_urb, g_rtl8152_class.hport, g_rtl8152_class.bulkin, &g_rtl8152_rx_buffer[g_rtl8152_rx_length], (CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE > (16 * 1024)) ? (16 * 1024) : CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+        ret = usbh_submit_urb(&g_rtl8152_class.bulkin_urb);
+        if (ret < 0) {
+            goto find_class;
+        }
+
+        g_rtl8152_rx_length += g_rtl8152_class.bulkin_urb.actual_length;
+
+        if (g_rtl8152_rx_length % USB_GET_MAXPACKETSIZE(g_rtl8152_class.bulkin->wMaxPacketSize)) {
+            data_offset = 0;
+
+            USB_LOG_DBG("rxlen:%d\r\n", g_rtl8152_rx_length);
+            while (g_rtl8152_rx_length > 0) {
+                struct rx_desc *rx_desc = (struct rx_desc *)&g_rtl8152_rx_buffer[data_offset];
+
+                len = rx_desc->opts1 & RX_LEN_MASK;
+
+                USB_LOG_DBG("data_offset:%d, eth len:%d\r\n", data_offset, len);
+
+                uint8_t *buf = (uint8_t *)&g_rtl8152_rx_buffer[data_offset + sizeof(struct rx_desc)];
+                usbh_rtl8152_eth_input(buf, len);
+
+                data_offset += (len + sizeof(struct rx_desc));
+                g_rtl8152_rx_length -= (len + sizeof(struct rx_desc));
+
+                if (len & (RX_ALIGN - 1)) {
+                    data_offset += (RX_ALIGN - (len & (RX_ALIGN - 1)));
+                    g_rtl8152_rx_length -= (RX_ALIGN - (len & (RX_ALIGN - 1)));
+                }
+            }
+        } else {
+            if (g_rtl8152_rx_length > CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE) {
+                USB_LOG_ERR("Rx packet is overflow\r\n");
+                g_rtl8152_rx_length = 0;
+            }
+        }
+    }
+    // clang-format off
+delete:
+    USB_LOG_INFO("Delete rtl8152 rx thread\r\n");
+    usb_osal_thread_delete(NULL);
+    // clang-format on
+}
+
+int usbh_rtl8152_eth_output(uint8_t *buf, uint32_t buflen)
+{
+    uint8_t *buffer;
+    struct tx_desc *tx_desc;
+
+    if (g_rtl8152_class.connect_status == false) {
+        return -USB_ERR_NOTCONN;
+    }
+
+    tx_desc = (struct tx_desc *)g_rtl8152_tx_buffer;
+    tx_desc->opts1 = buflen | TX_FS | TX_LS;
+    tx_desc->opts2 = 0;
+
+    buffer = g_rtl8152_tx_buffer + sizeof(struct tx_desc);
+    memcpy(buffer, buf, buflen);
+
+    USB_LOG_DBG("txlen:%d\r\n", buflen + sizeof(struct tx_desc));
+
+    usbh_bulk_urb_fill(&g_rtl8152_class.bulkout_urb, g_rtl8152_class.hport, g_rtl8152_class.bulkout, g_rtl8152_tx_buffer, buflen + sizeof(struct tx_desc), USB_OSAL_WAITING_FOREVER, NULL, NULL);
+    return usbh_submit_urb(&g_rtl8152_class.bulkout_urb);
+}
+
+__WEAK void usbh_rtl8152_run(struct usbh_rtl8152 *rtl8152_class)
+{
+}
+
+__WEAK void usbh_rtl8152_stop(struct usbh_rtl8152 *rtl8152_class)
+{
+}
+
+static const uint16_t rtl_id_table[][2] = {
+    { 0x0BDA, 0x8152 },
+    { 0, 0 },
+};
+
+static const struct usbh_class_driver rtl8152_class_driver = {
+    .driver_name = "rtl8152",
+    .connect = usbh_rtl8152_connect,
+    .disconnect = usbh_rtl8152_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info rtl8152_class_info = {
+    .match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
+    .class = 0xff,
+    .subclass = 0x00,
+    .protocol = 0x00,
+    .id_table = rtl_id_table,
+    .class_driver = &rtl8152_class_driver
+};

+ 67 - 0
components/drivers/usb/cherryusb/class/vendor/net/usbh_rtl8152.h

@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_RTL8152_H
+#define USBH_RTL8152_H
+
+struct usbh_rtl8152 {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+    struct usb_endpoint_descriptor *intin;   /* INTR IN endpoint  */
+    struct usbh_urb bulkout_urb;
+    struct usbh_urb bulkin_urb;
+    struct usbh_urb intin_urb;
+
+    uint8_t intf;
+
+    uint8_t mac[6];
+    bool connect_status;
+    uint32_t speed[2];
+
+    uint8_t version;
+    uint8_t eee_adv;
+    uint8_t eee_en;
+    uint8_t supports_gmii;
+    uint16_t min_mtu;
+    uint16_t max_mtu;
+    uint16_t ocp_base;
+    uint32_t saved_wolopts;
+    uint32_t rx_buf_sz;
+
+    struct rtl_ops {
+        void (*init)(struct usbh_rtl8152 *tp);
+        int (*enable)(struct usbh_rtl8152 *tp);
+        void (*disable)(struct usbh_rtl8152 *tp);
+        void (*up)(struct usbh_rtl8152 *tp);
+        void (*down)(struct usbh_rtl8152 *tp);
+        void (*unload)(struct usbh_rtl8152 *tp);
+        bool (*in_nway)(struct usbh_rtl8152 *tp);
+        void (*hw_phy_cfg)(struct usbh_rtl8152 *tp);
+        void (*autosuspend_en)(struct usbh_rtl8152 *tp, bool enable);
+        void (*change_mtu)(struct usbh_rtl8152 *tp);
+    } rtl_ops;
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_rtl8152_get_connect_status(struct usbh_rtl8152 *rtl8152_class);
+
+void usbh_rtl8152_run(struct usbh_rtl8152 *rtl8152_class);
+void usbh_rtl8152_stop(struct usbh_rtl8152 *rtl8152_class);
+
+int usbh_rtl8152_eth_output(uint8_t *buf, uint32_t buflen);
+void usbh_rtl8152_eth_input(uint8_t *buf, uint32_t buflen);
+void usbh_rtl8152_rx_thread(void *argument);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_RTL8152_H */

+ 356 - 0
components/drivers/usb/cherryusb/class/vendor/serial/usbh_ch34x.c

@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_ch34x.h"
+
+#define DEV_FORMAT "/dev/ttyUSB%d"
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_ch34x_buf[64];
+
+#define CONFIG_USBHOST_MAX_CP210X_CLASS 1
+
+static struct usbh_ch34x g_ch34x_class[CONFIG_USBHOST_MAX_CP210X_CLASS];
+static uint32_t g_devinuse = 0;
+
+static struct usbh_ch34x *usbh_ch34x_class_alloc(void)
+{
+    int devno;
+
+    for (devno = 0; devno < CONFIG_USBHOST_MAX_CP210X_CLASS; devno++) {
+        if ((g_devinuse & (1 << devno)) == 0) {
+            g_devinuse |= (1 << devno);
+            memset(&g_ch34x_class[devno], 0, sizeof(struct usbh_ch34x));
+            g_ch34x_class[devno].minor = devno;
+            return &g_ch34x_class[devno];
+        }
+    }
+    return NULL;
+}
+
+static void usbh_ch34x_class_free(struct usbh_ch34x *ch34x_class)
+{
+    int devno = ch34x_class->minor;
+
+    if (devno >= 0 && devno < 32) {
+        g_devinuse &= ~(1 << devno);
+    }
+    memset(ch34x_class, 0, sizeof(struct usbh_ch34x));
+}
+
+static int usbh_ch34x_get_baudrate_div(uint32_t baudrate, uint8_t *factor, uint8_t *divisor)
+{
+    uint8_t a;
+    uint8_t b;
+    uint32_t c;
+
+    switch (baudrate) {
+        case 921600:
+            a = 0xf3;
+            b = 7;
+            break;
+
+        case 307200:
+            a = 0xd9;
+            b = 7;
+            break;
+
+        default:
+            if (baudrate > 6000000 / 255) {
+                b = 3;
+                c = 6000000;
+            } else if (baudrate > 750000 / 255) {
+                b = 2;
+                c = 750000;
+            } else if (baudrate > 93750 / 255) {
+                b = 1;
+                c = 93750;
+            } else {
+                b = 0;
+                c = 11719;
+            }
+            a = (uint8_t)(c / baudrate);
+            if (a == 0 || a == 0xFF) {
+                return -USB_ERR_INVAL;
+            }
+            if ((c / a - baudrate) > (baudrate - c / (a + 1))) {
+                a++;
+            }
+            a = (uint8_t)(256 - a);
+            break;
+    }
+
+    *factor = a;
+    *divisor = b;
+
+    return 0;
+}
+
+static int usbh_ch34x_get_version(struct usbh_ch34x *ch34x_class)
+{
+    struct usb_setup_packet *setup = ch34x_class->hport->setup;
+    int ret;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = CH34X_READ_VERSION;
+    setup->wValue = 0;
+    setup->wIndex = 0;
+    setup->wLength = 2;
+
+    ret = usbh_control_transfer(ch34x_class->hport, setup, g_ch34x_buf);
+    if (ret < 0) {
+        return ret;
+    }
+
+    USB_LOG_INFO("Ch34x chip version %02x:%02x\r\n", g_ch34x_buf[0], g_ch34x_buf[1]);
+    return ret;
+}
+
+static int usbh_ch34x_flow_ctrl(struct usbh_ch34x *ch34x_class)
+{
+    struct usb_setup_packet *setup = ch34x_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = CH34X_WRITE_REG;
+    setup->wValue = 0x2727;
+    setup->wIndex = 0;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(ch34x_class->hport, setup, NULL);
+}
+
+int usbh_ch34x_set_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding)
+{
+    struct usb_setup_packet *setup = ch34x_class->hport->setup;
+    uint16_t reg_value = 0;
+    uint16_t value = 0;
+    uint8_t factor = 0;
+    uint8_t divisor = 0;
+
+    memcpy((uint8_t *)&ch34x_class->line_coding, line_coding, sizeof(struct cdc_line_coding));
+
+    /* refer to https://github.com/WCHSoftGroup/ch341ser_linux/blob/main/driver/ch341.c */
+
+    switch (line_coding->bParityType) {
+        case 0:
+            break;
+        case 1:
+            reg_value |= CH341_L_PO;
+            break;
+        case 2:
+            reg_value |= CH341_L_PE;
+            break;
+        case 3:
+            reg_value |= CH341_L_PM;
+            break;
+        case 4:
+            reg_value |= CH341_L_PS;
+            break;
+        default:
+            return -USB_ERR_INVAL;
+    }
+
+    switch (line_coding->bDataBits) {
+        case 5:
+            reg_value |= CH341_L_D5;
+            break;
+        case 6:
+            reg_value |= CH341_L_D6;
+            break;
+        case 7:
+            reg_value |= CH341_L_D7;
+            break;
+        case 8:
+            reg_value |= CH341_L_D8;
+            break;
+        default:
+            return -USB_ERR_INVAL;
+    }
+
+    if (line_coding->bCharFormat == 2) {
+        reg_value |= CH341_L_SB;
+    }
+
+    reg_value |= 0xC0;
+
+    value |= 0x9c;
+    value |= reg_value << 8;
+
+    usbh_ch34x_get_baudrate_div(line_coding->dwDTERate, &factor, &divisor);
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = CH34X_SERIAL_INIT;
+    setup->wValue = value;
+    setup->wIndex = (factor << 8) | 0x80 | divisor;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(ch34x_class->hport, setup, NULL);
+}
+
+int usbh_ch34x_get_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding)
+{
+    memcpy(line_coding, (uint8_t *)&ch34x_class->line_coding, sizeof(struct cdc_line_coding));
+    return 0;
+}
+
+int usbh_ch34x_set_line_state(struct usbh_ch34x *ch34x_class, bool dtr, bool rts)
+{
+    struct usb_setup_packet *setup = ch34x_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = CH34X_MODEM_CTRL;
+    setup->wValue = 0x0f | (dtr << 5) | (rts << 6);
+    setup->wIndex = 0;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(ch34x_class->hport, setup, NULL);
+}
+
+static int usbh_ch34x_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret = 0;
+
+    struct usbh_ch34x *ch34x_class = usbh_ch34x_class_alloc();
+    if (ch34x_class == NULL) {
+        USB_LOG_ERR("Fail to alloc ch34x_class\r\n");
+        return -USB_ERR_NOMEM;
+    }
+
+    ch34x_class->hport = hport;
+    ch34x_class->intf = intf;
+
+    hport->config.intf[intf].priv = ch34x_class;
+
+    usbh_ch34x_get_version(ch34x_class);
+    usbh_ch34x_flow_ctrl(ch34x_class);
+
+    for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
+        ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
+        if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
+            continue;
+        } else {
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(ch34x_class->bulkin, ep_desc);
+            } else {
+                USBH_EP_INIT(ch34x_class->bulkout, ep_desc);
+            }
+        }
+    }
+
+    snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, ch34x_class->minor);
+
+    USB_LOG_INFO("Register CH34X Class:%s\r\n", hport->config.intf[intf].devname);
+
+#if 0
+    USB_LOG_INFO("Test ch34x rx and tx and rx for 5 times, baudrate is 115200\r\n");
+
+    struct cdc_line_coding linecoding;
+    uint8_t count = 5;
+
+    linecoding.dwDTERate = 115200;
+    linecoding.bDataBits = 8;
+    linecoding.bParityType = 0;
+    linecoding.bCharFormat = 0;
+    usbh_ch34x_set_line_coding(ch34x_class, &linecoding);
+    usbh_ch34x_set_line_state(ch34x_class, true, false);
+
+    memset(g_ch34x_buf, 'a', sizeof(g_ch34x_buf));
+    ret = usbh_ch34x_bulk_out_transfer(ch34x_class, g_ch34x_buf, sizeof(g_ch34x_buf), 0xfffffff);
+    USB_LOG_RAW("out ret:%d\r\n", ret);
+    while (count--) {
+        ret = usbh_ch34x_bulk_in_transfer(ch34x_class, g_ch34x_buf, sizeof(g_ch34x_buf), 0xfffffff);
+        USB_LOG_RAW("in ret:%d\r\n", ret);
+        if (ret > 0) {
+            for (uint32_t i = 0; i < ret; i++) {
+                USB_LOG_RAW("%02x ", g_ch34x_buf[i]);
+            }
+            USB_LOG_RAW("\r\n");
+        }
+    }
+#endif
+    usbh_ch34x_run(ch34x_class);
+    return ret;
+}
+
+static int usbh_ch34x_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_ch34x *ch34x_class = (struct usbh_ch34x *)hport->config.intf[intf].priv;
+
+    if (ch34x_class) {
+        if (ch34x_class->bulkin) {
+            usbh_kill_urb(&ch34x_class->bulkin_urb);
+        }
+
+        if (ch34x_class->bulkout) {
+            usbh_kill_urb(&ch34x_class->bulkout_urb);
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister CH34X Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_ch34x_stop(ch34x_class);
+        }
+
+        usbh_ch34x_class_free(ch34x_class);
+    }
+
+    return ret;
+}
+
+int usbh_ch34x_bulk_in_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+{
+    int ret;
+    struct usbh_urb *urb = &ch34x_class->bulkin_urb;
+
+    usbh_bulk_urb_fill(urb, ch34x_class->hport, ch34x_class->bulkin, buffer, buflen, timeout, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+int usbh_ch34x_bulk_out_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+{
+    int ret;
+    struct usbh_urb *urb = &ch34x_class->bulkout_urb;
+
+    usbh_bulk_urb_fill(urb, ch34x_class->hport, ch34x_class->bulkout, buffer, buflen, timeout, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+__WEAK void usbh_ch34x_run(struct usbh_ch34x *ch34x_class)
+{
+}
+
+__WEAK void usbh_ch34x_stop(struct usbh_ch34x *ch34x_class)
+{
+}
+
+static const uint16_t ch34x_id_table[][2] = {
+    { 0x1A86, 0x7523 },
+    { 0, 0 },
+};
+
+const struct usbh_class_driver ch34x_class_driver = {
+    .driver_name = "ch34x",
+    .connect = usbh_ch34x_connect,
+    .disconnect = usbh_ch34x_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info ch34x_class_info = {
+    .match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
+    .class = 0xff,
+    .subclass = 0x00,
+    .protocol = 0x00,
+    .id_table = ch34x_id_table,
+    .class_driver = &ch34x_class_driver
+};

+ 76 - 0
components/drivers/usb/cherryusb/class/vendor/serial/usbh_ch34x.h

@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_CH34X_H
+#define USBH_CH34X_H
+
+#include "usb_cdc.h"
+
+/* Requests */
+#define CH34X_READ_VERSION 0x5F
+#define CH34X_WRITE_REG    0x9A
+#define CH34X_READ_REG     0x95
+#define CH34X_SERIAL_INIT  0xA1
+#define CH34X_MODEM_CTRL   0xA4
+
+// modem control bits
+#define CH34X_BIT_RTS (1 << 6)
+#define CH34X_BIT_DTR (1 << 5)
+
+#define CH341_CTO_O   0x10
+#define CH341_CTO_D   0x20
+#define CH341_CTO_R   0x40
+#define CH341_CTI_C   0x01
+#define CH341_CTI_DS  0x02
+#define CH341_CTRL_RI 0x04
+#define CH341_CTI_DC  0x08
+#define CH341_CTI_ST  0x0f
+
+#define CH341_L_ER 0x80
+#define CH341_L_ET 0x40
+#define CH341_L_PS 0x38
+#define CH341_L_PM 0x28
+#define CH341_L_PE 0x18
+#define CH341_L_PO 0x08
+#define CH341_L_SB 0x04
+#define CH341_L_D8 0x03
+#define CH341_L_D7 0x02
+#define CH341_L_D6 0x01
+#define CH341_L_D5 0x00
+
+struct usbh_ch34x {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+    struct usbh_urb bulkout_urb;
+    struct usbh_urb bulkin_urb;
+
+    struct cdc_line_coding line_coding;
+
+    uint8_t intf;
+    uint8_t minor;
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_ch34x_set_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding);
+int usbh_ch34x_get_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding);
+int usbh_ch34x_set_line_state(struct usbh_ch34x *ch34x_class, bool dtr, bool rts);
+
+int usbh_ch34x_bulk_in_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
+int usbh_ch34x_bulk_out_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
+
+void usbh_ch34x_run(struct usbh_ch34x *ch34x_class);
+void usbh_ch34x_stop(struct usbh_ch34x *ch34x_class);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_CH34X_H */

+ 295 - 0
components/drivers/usb/cherryusb/class/vendor/serial/usbh_cp210x.c

@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_cp210x.h"
+
+#define DEV_FORMAT "/dev/ttyUSB%d"
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cp210x_buf[64];
+
+#define CONFIG_USBHOST_MAX_CP210X_CLASS 4
+
+static struct usbh_cp210x g_cp210x_class[CONFIG_USBHOST_MAX_CP210X_CLASS];
+static uint32_t g_devinuse = 0;
+
+static struct usbh_cp210x *usbh_cp210x_class_alloc(void)
+{
+    int devno;
+
+    for (devno = 0; devno < CONFIG_USBHOST_MAX_CP210X_CLASS; devno++) {
+        if ((g_devinuse & (1 << devno)) == 0) {
+            g_devinuse |= (1 << devno);
+            memset(&g_cp210x_class[devno], 0, sizeof(struct usbh_cp210x));
+            g_cp210x_class[devno].minor = devno;
+            return &g_cp210x_class[devno];
+        }
+    }
+    return NULL;
+}
+
+static void usbh_cp210x_class_free(struct usbh_cp210x *cp210x_class)
+{
+    int devno = cp210x_class->minor;
+
+    if (devno >= 0 && devno < 32) {
+        g_devinuse &= ~(1 << devno);
+    }
+    memset(cp210x_class, 0, sizeof(struct usbh_cp210x));
+}
+
+static int usbh_cp210x_enable(struct usbh_cp210x *cp210x_class)
+{
+    struct usb_setup_packet *setup = cp210x_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CP210X_IFC_ENABLE;
+    setup->wValue = 1;
+    setup->wIndex = cp210x_class->intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(cp210x_class->hport, setup, NULL);
+}
+
+static int usbh_cp210x_set_flow(struct usbh_cp210x *cp210x_class)
+{
+    struct usb_setup_packet *setup = cp210x_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CP210X_SET_FLOW;
+    setup->wValue = 0;
+    setup->wIndex = cp210x_class->intf;
+    setup->wLength = 16;
+
+    memset(g_cp210x_buf, 0, 16);
+    g_cp210x_buf[13] = 0x20;
+    return usbh_control_transfer(cp210x_class->hport, setup, g_cp210x_buf);
+}
+
+static int usbh_cp210x_set_chars(struct usbh_cp210x *cp210x_class)
+{
+    struct usb_setup_packet *setup = cp210x_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CP210X_SET_CHARS;
+    setup->wValue = 0;
+    setup->wIndex = cp210x_class->intf;
+    setup->wLength = 6;
+
+    memset(g_cp210x_buf, 0, 6);
+    g_cp210x_buf[0] = 0x80;
+    g_cp210x_buf[4] = 0x88;
+    g_cp210x_buf[5] = 0x28;
+    return usbh_control_transfer(cp210x_class->hport, setup, g_cp210x_buf);
+}
+
+static int usbh_cp210x_set_baudrate(struct usbh_cp210x *cp210x_class, uint32_t baudrate)
+{
+    struct usb_setup_packet *setup = cp210x_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CP210X_SET_BAUDRATE;
+    setup->wValue = 0;
+    setup->wIndex = cp210x_class->intf;
+    setup->wLength = 4;
+
+    memcpy(g_cp210x_buf, (uint8_t *)&baudrate, 4);
+    return usbh_control_transfer(cp210x_class->hport, setup, g_cp210x_buf);
+}
+
+static int usbh_cp210x_set_data_format(struct usbh_cp210x *cp210x_class, uint8_t databits, uint8_t parity, uint8_t stopbits)
+{
+    struct usb_setup_packet *setup = cp210x_class->hport->setup;
+    uint16_t value;
+
+    value = ((databits & 0x0F) << 8) | ((parity & 0x0f) << 4) | ((stopbits & 0x03) << 0);
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CP210X_SET_LINE_CTL;
+    setup->wValue = value;
+    setup->wIndex = cp210x_class->intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(cp210x_class->hport, setup, NULL);
+}
+
+static int usbh_cp210x_set_mhs(struct usbh_cp210x *cp210x_class, uint8_t dtr, uint8_t rts, uint8_t dtr_mask, uint8_t rts_mask)
+{
+    struct usb_setup_packet *setup = cp210x_class->hport->setup;
+    uint16_t value;
+
+    value = ((dtr & 0x01) << 0) | ((rts & 0x01) << 1) | ((dtr_mask & 0x01) << 8) | ((rts_mask & 0x01) << 9);
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CP210X_SET_MHS;
+    setup->wValue = value;
+    setup->wIndex = cp210x_class->intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(cp210x_class->hport, setup, NULL);
+}
+
+int usbh_cp210x_set_line_coding(struct usbh_cp210x *cp210x_class, struct cdc_line_coding *line_coding)
+{
+    memcpy((uint8_t *)&cp210x_class->line_coding, line_coding, sizeof(struct cdc_line_coding));
+    usbh_cp210x_set_baudrate(cp210x_class, line_coding->dwDTERate);
+    return usbh_cp210x_set_data_format(cp210x_class, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat);
+}
+
+int usbh_cp210x_get_line_coding(struct usbh_cp210x *cp210x_class, struct cdc_line_coding *line_coding)
+{
+    memcpy(line_coding, (uint8_t *)&cp210x_class->line_coding, sizeof(struct cdc_line_coding));
+    return 0;
+}
+
+int usbh_cp210x_set_line_state(struct usbh_cp210x *cp210x_class, bool dtr, bool rts)
+{
+    return usbh_cp210x_set_mhs(cp210x_class, dtr, rts, 1, 1);
+}
+
+static int usbh_cp210x_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret = 0;
+
+    struct usbh_cp210x *cp210x_class = usbh_cp210x_class_alloc();
+    if (cp210x_class == NULL) {
+        USB_LOG_ERR("Fail to alloc cp210x_class\r\n");
+        return -USB_ERR_NOMEM;
+    }
+
+    cp210x_class->hport = hport;
+    cp210x_class->intf = intf;
+
+    hport->config.intf[intf].priv = cp210x_class;
+
+    usbh_cp210x_enable(cp210x_class);
+    usbh_cp210x_set_flow(cp210x_class);
+    usbh_cp210x_set_chars(cp210x_class);
+
+    for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
+        ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
+
+        if (ep_desc->bEndpointAddress & 0x80) {
+            USBH_EP_INIT(cp210x_class->bulkin, ep_desc);
+        } else {
+            USBH_EP_INIT(cp210x_class->bulkout, ep_desc);
+        }
+    }
+
+    snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, cp210x_class->minor);
+
+    USB_LOG_INFO("Register CP210X Class:%s\r\n", hport->config.intf[intf].devname);
+
+#if 0
+    USB_LOG_INFO("Test cp2102 rx and tx and rx for 5 times, baudrate is 115200\r\n");
+
+    struct cdc_line_coding linecoding;
+    uint8_t count = 5;
+
+    linecoding.dwDTERate = 115200;
+    linecoding.bDataBits = 8;
+    linecoding.bParityType = 0;
+    linecoding.bCharFormat = 0;
+    usbh_cp210x_set_line_coding(cp210x_class, &linecoding);
+    usbh_cp210x_set_line_state(cp210x_class, true, false);
+
+    memset(g_cp210x_buf, 'a', sizeof(g_cp210x_buf));
+    ret = usbh_cp210x_bulk_out_transfer(cp210x_class, g_cp210x_buf, sizeof(g_cp210x_buf), 0xfffffff);
+    USB_LOG_RAW("out ret:%d\r\n", ret);
+    while (count--) {
+        ret = usbh_cp210x_bulk_in_transfer(cp210x_class, g_cp210x_buf, sizeof(g_cp210x_buf), 0xfffffff);
+        USB_LOG_RAW("in ret:%d\r\n", ret);
+        if (ret > 0) {
+            for (uint32_t i = 0; i < ret; i++) {
+                USB_LOG_RAW("%02x ", g_cp210x_buf[i]);
+            }
+            USB_LOG_RAW("\r\n");
+        }
+    }
+#endif
+    usbh_cp210x_run(cp210x_class);
+    return ret;
+}
+
+static int usbh_cp210x_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_cp210x *cp210x_class = (struct usbh_cp210x *)hport->config.intf[intf].priv;
+
+    if (cp210x_class) {
+        if (cp210x_class->bulkin) {
+            usbh_kill_urb(&cp210x_class->bulkin_urb);
+        }
+
+        if (cp210x_class->bulkout) {
+            usbh_kill_urb(&cp210x_class->bulkout_urb);
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister CP210X Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_cp210x_stop(cp210x_class);
+        }
+
+        usbh_cp210x_class_free(cp210x_class);
+    }
+
+    return ret;
+}
+
+int usbh_cp210x_bulk_in_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+{
+    int ret;
+    struct usbh_urb *urb = &cp210x_class->bulkin_urb;
+
+    usbh_bulk_urb_fill(urb, cp210x_class->hport, cp210x_class->bulkin, buffer, buflen, timeout, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+int usbh_cp210x_bulk_out_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+{
+    int ret;
+    struct usbh_urb *urb = &cp210x_class->bulkout_urb;
+
+    usbh_bulk_urb_fill(urb, cp210x_class->hport, cp210x_class->bulkout, buffer, buflen, timeout, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+__WEAK void usbh_cp210x_run(struct usbh_cp210x *cp210x_class)
+{
+}
+
+__WEAK void usbh_cp210x_stop(struct usbh_cp210x *cp210x_class)
+{
+}
+
+static const uint16_t cp210x_id_table[][2] = {
+    { 0x10C4, 0xEA60 },
+    { 0, 0 },
+};
+
+const struct usbh_class_driver cp210x_class_driver = {
+    .driver_name = "cp210x",
+    .connect = usbh_cp210x_connect,
+    .disconnect = usbh_cp210x_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info cp210x_class_info = {
+    .match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
+    .class = 0xff,
+    .subclass = 0x00,
+    .protocol = 0x00,
+    .id_table = cp210x_id_table,
+    .class_driver = &cp210x_class_driver
+};

+ 73 - 0
components/drivers/usb/cherryusb/class/vendor/serial/usbh_cp210x.h

@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_CP210X_H
+#define USBH_CP210X_H
+
+#include "usb_cdc.h"
+
+/* Requests */
+#define CP210X_IFC_ENABLE      0x00
+#define CP210X_SET_BAUDDIV     0x01
+#define CP210X_GET_BAUDDIV     0x02
+#define CP210X_SET_LINE_CTL    0x03 // Set parity, data bits, stop bits
+#define CP210X_GET_LINE_CTL    0x04
+#define CP210X_SET_BREAK       0x05
+#define CP210X_IMM_CHAR        0x06
+#define CP210X_SET_MHS         0x07 // Set DTR, RTS
+#define CP210X_GET_MDMSTS      0x08
+#define CP210X_SET_XON         0x09
+#define CP210X_SET_XOFF        0x0A
+#define CP210X_SET_EVENTMASK   0x0B
+#define CP210X_GET_EVENTMASK   0x0C
+#define CP210X_SET_CHAR        0x0D
+#define CP210X_GET_CHARS       0x0E
+#define CP210X_GET_PROPS       0x0F
+#define CP210X_GET_COMM_STATUS 0x10
+#define CP210X_RESET           0x11
+#define CP210X_PURGE           0x12
+#define CP210X_SET_FLOW        0x13
+#define CP210X_GET_FLOW        0x14
+#define CP210X_EMBED_EVENTS    0x15
+#define CP210X_GET_EVENTSTATE  0x16
+#define CP210X_SET_CHARS       0x19
+#define CP210X_GET_BAUDRATE    0x1D
+#define CP210X_SET_BAUDRATE    0x1E // Set baudrate
+#define CP210X_VENDOR_SPECIFIC 0xFF
+
+struct usbh_cp210x {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+    struct usbh_urb bulkout_urb;
+    struct usbh_urb bulkin_urb;
+
+    struct cdc_line_coding line_coding;
+
+    uint8_t intf;
+    uint8_t minor;
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_cp210x_set_line_coding(struct usbh_cp210x *ftdi_class, struct cdc_line_coding *line_coding);
+int usbh_cp210x_get_line_coding(struct usbh_cp210x *ftdi_class, struct cdc_line_coding *line_coding);
+int usbh_cp210x_set_line_state(struct usbh_cp210x *ftdi_class, bool dtr, bool rts);
+
+int usbh_cp210x_bulk_in_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
+int usbh_cp210x_bulk_out_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
+
+void usbh_cp210x_run(struct usbh_cp210x *cp210x_class);
+void usbh_cp210x_stop(struct usbh_cp210x *cp210x_class);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_CP210X_H */

+ 363 - 0
components/drivers/usb/cherryusb/class/vendor/serial/usbh_ftdi.c

@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_ftdi.h"
+
+#define DEV_FORMAT "/dev/ttyUSB%d"
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_ftdi_buf[64];
+
+#define CONFIG_USBHOST_MAX_FTDI_CLASS 4
+
+static struct usbh_ftdi g_ftdi_class[CONFIG_USBHOST_MAX_FTDI_CLASS];
+static uint32_t g_devinuse = 0;
+
+static struct usbh_ftdi *usbh_ftdi_class_alloc(void)
+{
+    int devno;
+
+    for (devno = 0; devno < CONFIG_USBHOST_MAX_FTDI_CLASS; devno++) {
+        if ((g_devinuse & (1 << devno)) == 0) {
+            g_devinuse |= (1 << devno);
+            memset(&g_ftdi_class[devno], 0, sizeof(struct usbh_ftdi));
+            g_ftdi_class[devno].minor = devno;
+            return &g_ftdi_class[devno];
+        }
+    }
+    return NULL;
+}
+
+static void usbh_ftdi_class_free(struct usbh_ftdi *ftdi_class)
+{
+    int devno = ftdi_class->minor;
+
+    if (devno >= 0 && devno < 32) {
+        g_devinuse &= ~(1 << devno);
+    }
+    memset(ftdi_class, 0, sizeof(struct usbh_ftdi));
+}
+
+static void usbh_ftdi_caculate_baudrate(uint32_t *itdf_divisor, uint32_t actual_baudrate)
+{
+#define FTDI_USB_CLK 48000000
+    int baudrate;
+    uint8_t frac[] = { 0, 8, 4, 2, 6, 10, 12, 14 };
+
+    if (actual_baudrate == 2000000) {
+        *itdf_divisor = 0x01;
+    } else if (actual_baudrate == 3000000) {
+        *itdf_divisor = 0x00;
+    } else {
+        baudrate = actual_baudrate;
+        if (baudrate > 100000 && baudrate < 12000000) {
+            baudrate = (baudrate / 100000) + 100000;
+        }
+        int divisor = FTDI_USB_CLK / baudrate;
+        int frac_bits = 0;
+        for (int i = 0; i < sizeof(frac) / sizeof(frac[0]); i++) {
+            if ((divisor & 0xF) == frac[i]) {
+                frac_bits = i;
+                break;
+            }
+        }
+        divisor >>= 4;
+        divisor &= 0x3FFF;
+        *itdf_divisor = (divisor << 14) | (frac_bits << 8);
+    }
+}
+
+int usbh_ftdi_reset(struct usbh_ftdi *ftdi_class)
+{
+    struct usb_setup_packet *setup = ftdi_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = SIO_RESET_REQUEST;
+    setup->wValue = 0;
+    setup->wIndex = ftdi_class->intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(ftdi_class->hport, setup, NULL);
+}
+
+static int usbh_ftdi_set_modem(struct usbh_ftdi *ftdi_class, uint16_t value)
+{
+    struct usb_setup_packet *setup = ftdi_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = SIO_SET_MODEM_CTRL_REQUEST;
+    setup->wValue = value;
+    setup->wIndex = ftdi_class->intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(ftdi_class->hport, setup, NULL);
+}
+
+static int usbh_ftdi_set_baudrate(struct usbh_ftdi *ftdi_class, uint32_t baudrate)
+{
+    struct usb_setup_packet *setup = ftdi_class->hport->setup;
+    uint32_t itdf_divisor;
+    uint16_t value;
+    uint8_t baudrate_high;
+
+    usbh_ftdi_caculate_baudrate(&itdf_divisor, baudrate);
+    value = itdf_divisor & 0xFFFF;
+    baudrate_high = (itdf_divisor >> 16) & 0xff;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = SIO_SET_BAUDRATE_REQUEST;
+    setup->wValue = value;
+    setup->wIndex = (baudrate_high << 8) | ftdi_class->intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(ftdi_class->hport, setup, NULL);
+}
+
+static int usbh_ftdi_set_data_format(struct usbh_ftdi *ftdi_class, uint8_t databits, uint8_t parity, uint8_t stopbits, uint8_t isbreak)
+{
+    /**
+     * D0-D7 databits  BITS_7=7, BITS_8=8
+     * D8-D10 parity  NONE=0, ODD=1, EVEN=2, MARK=3, SPACE=4
+     * D11-D12 		STOP_BIT_1=0, STOP_BIT_15=1, STOP_BIT_2=2
+     * D14  		BREAK_OFF=0, BREAK_ON=1
+     **/
+
+    uint16_t value = ((isbreak & 0x01) << 14) | ((stopbits & 0x03) << 11) | ((parity & 0x0f) << 8) | (databits & 0x0f);
+
+    struct usb_setup_packet *setup = ftdi_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = SIO_SET_DATA_REQUEST;
+    setup->wValue = value;
+    setup->wIndex = ftdi_class->intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(ftdi_class->hport, setup, NULL);
+}
+
+static int usbh_ftdi_set_latency_timer(struct usbh_ftdi *ftdi_class, uint16_t value)
+{
+    struct usb_setup_packet *setup = ftdi_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = SIO_SET_LATENCY_TIMER_REQUEST;
+    setup->wValue = value;
+    setup->wIndex = ftdi_class->intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(ftdi_class->hport, setup, NULL);
+}
+
+static int usbh_ftdi_set_flow_ctrl(struct usbh_ftdi *ftdi_class, uint16_t value)
+{
+    struct usb_setup_packet *setup = ftdi_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = SIO_SET_FLOW_CTRL_REQUEST;
+    setup->wValue = value;
+    setup->wIndex = ftdi_class->intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(ftdi_class->hport, setup, NULL);
+}
+
+static int usbh_ftdi_read_modem_status(struct usbh_ftdi *ftdi_class)
+{
+    struct usb_setup_packet *setup = ftdi_class->hport->setup;
+    int ret;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = SIO_POLL_MODEM_STATUS_REQUEST;
+    setup->wValue = 0x0000;
+    setup->wIndex = ftdi_class->intf;
+    setup->wLength = 2;
+
+    ret = usbh_control_transfer(ftdi_class->hport, setup, g_ftdi_buf);
+    if (ret < 0) {
+        return ret;
+    }
+    memcpy(ftdi_class->modem_status, g_ftdi_buf, 2);
+    return ret;
+}
+
+int usbh_ftdi_set_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding)
+{
+    memcpy((uint8_t *)&ftdi_class->line_coding, line_coding, sizeof(struct cdc_line_coding));
+    usbh_ftdi_set_baudrate(ftdi_class, line_coding->dwDTERate);
+    return usbh_ftdi_set_data_format(ftdi_class, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat, 0);
+}
+
+int usbh_ftdi_get_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding)
+{
+    memcpy(line_coding, (uint8_t *)&ftdi_class->line_coding, sizeof(struct cdc_line_coding));
+    return 0;
+}
+
+int usbh_ftdi_set_line_state(struct usbh_ftdi *ftdi_class, bool dtr, bool rts)
+{
+    int ret;
+
+    if (dtr) {
+        usbh_ftdi_set_modem(ftdi_class, SIO_SET_DTR_HIGH);
+    } else {
+        usbh_ftdi_set_modem(ftdi_class, SIO_SET_DTR_LOW);
+    }
+
+    if (rts) {
+        ret = usbh_ftdi_set_modem(ftdi_class, SIO_SET_RTS_HIGH);
+    } else {
+        ret = usbh_ftdi_set_modem(ftdi_class, SIO_SET_RTS_LOW);
+    }
+
+    return ret;
+}
+
+static int usbh_ftdi_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret = 0;
+
+    struct usbh_ftdi *ftdi_class = usbh_ftdi_class_alloc();
+    if (ftdi_class == NULL) {
+        USB_LOG_ERR("Fail to alloc ftdi_class\r\n");
+        return -USB_ERR_NOMEM;
+    }
+
+    ftdi_class->hport = hport;
+    ftdi_class->intf = intf;
+
+    hport->config.intf[intf].priv = ftdi_class;
+
+    usbh_ftdi_reset(ftdi_class);
+    usbh_ftdi_set_flow_ctrl(ftdi_class, SIO_DISABLE_FLOW_CTRL);
+    usbh_ftdi_set_latency_timer(ftdi_class, 0x10);
+    usbh_ftdi_read_modem_status(ftdi_class);
+    USB_LOG_INFO("modem status:%02x:%02x\r\n", ftdi_class->modem_status[0], ftdi_class->modem_status[1]);
+
+    for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
+        ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
+
+        if (ep_desc->bEndpointAddress & 0x80) {
+            USBH_EP_INIT(ftdi_class->bulkin, ep_desc);
+        } else {
+            USBH_EP_INIT(ftdi_class->bulkout, ep_desc);
+        }
+    }
+
+    snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, ftdi_class->minor);
+
+    USB_LOG_INFO("Register FTDI Class:%s\r\n", hport->config.intf[intf].devname);
+
+#if 0
+    USB_LOG_INFO("Test ftdi rx and tx and rx for 5 times, baudrate is 115200\r\n");
+
+    struct cdc_line_coding linecoding;
+    uint8_t count = 5;
+
+    linecoding.dwDTERate = 115200;
+    linecoding.bDataBits = 8;
+    linecoding.bParityType = 0;
+    linecoding.bCharFormat = 0;
+    usbh_ftdi_set_line_coding(ftdi_class, &linecoding);
+    usbh_ftdi_set_line_state(ftdi_class, true, false);
+
+    memset(g_ftdi_buf, 'a', sizeof(g_ftdi_buf));
+    ret = usbh_ftdi_bulk_out_transfer(ftdi_class, g_ftdi_buf, sizeof(g_ftdi_buf), 0xfffffff);
+    USB_LOG_RAW("out ret:%d\r\n", ret);
+    while (count--) {
+        ret = usbh_ftdi_bulk_in_transfer(ftdi_class, g_ftdi_buf, sizeof(g_ftdi_buf), 0xfffffff);
+        USB_LOG_RAW("in ret:%d\r\n", ret);
+        if (ret > 0) {
+            for (uint32_t i = 0; i < ret; i++) {
+                USB_LOG_RAW("%02x ", g_ftdi_buf[i]);
+            }
+        }
+        USB_LOG_RAW("\r\n");
+    }
+#endif
+    usbh_ftdi_run(ftdi_class);
+    return ret;
+}
+
+static int usbh_ftdi_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_ftdi *ftdi_class = (struct usbh_ftdi *)hport->config.intf[intf].priv;
+
+    if (ftdi_class) {
+        if (ftdi_class->bulkin) {
+            usbh_kill_urb(&ftdi_class->bulkin_urb);
+        }
+
+        if (ftdi_class->bulkout) {
+            usbh_kill_urb(&ftdi_class->bulkout_urb);
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister FTDI Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_ftdi_stop(ftdi_class);
+        }
+
+        usbh_ftdi_class_free(ftdi_class);
+    }
+
+    return ret;
+}
+
+int usbh_ftdi_bulk_in_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+{
+    int ret;
+    struct usbh_urb *urb = &ftdi_class->bulkin_urb;
+
+    usbh_bulk_urb_fill(urb, ftdi_class->hport, ftdi_class->bulkin, buffer, buflen, timeout, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+int usbh_ftdi_bulk_out_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+{
+    int ret;
+    struct usbh_urb *urb = &ftdi_class->bulkout_urb;
+
+    usbh_bulk_urb_fill(urb, ftdi_class->hport, ftdi_class->bulkout, buffer, buflen, timeout, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+__WEAK void usbh_ftdi_run(struct usbh_ftdi *ftdi_class)
+{
+}
+
+__WEAK void usbh_ftdi_stop(struct usbh_ftdi *ftdi_class)
+{
+}
+
+static const uint16_t ftdi_id_table[][2] = {
+    { 0x0403, 0x6001 },
+    { 0x0403, 0x6010 },
+    { 0, 0 },
+};
+
+const struct usbh_class_driver ftdi_class_driver = {
+    .driver_name = "ftdi",
+    .connect = usbh_ftdi_connect,
+    .disconnect = usbh_ftdi_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info ftdi_class_info = {
+    .match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
+    .class = 0xff,
+    .subclass = 0x00,
+    .protocol = 0x00,
+    .id_table = ftdi_id_table,
+    .class_driver = &ftdi_class_driver
+};

+ 76 - 0
components/drivers/usb/cherryusb/class/vendor/serial/usbh_ftdi.h

@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_FTDI_H
+#define USBH_FTDI_H
+
+#include "usb_cdc.h"
+
+/* Requests */
+#define SIO_RESET_REQUEST             0x00 /* Reset the port */
+#define SIO_SET_MODEM_CTRL_REQUEST    0x01 /* Set the modem control register */
+#define SIO_SET_FLOW_CTRL_REQUEST     0x02 /* Set flow control register */
+#define SIO_SET_BAUDRATE_REQUEST      0x03 /* Set baud rate */
+#define SIO_SET_DATA_REQUEST          0x04 /* Set the data characteristics of the port */
+#define SIO_POLL_MODEM_STATUS_REQUEST 0x05
+#define SIO_SET_EVENT_CHAR_REQUEST    0x06
+#define SIO_SET_ERROR_CHAR_REQUEST    0x07
+#define SIO_SET_LATENCY_TIMER_REQUEST 0x09
+#define SIO_GET_LATENCY_TIMER_REQUEST 0x0A
+#define SIO_SET_BITMODE_REQUEST       0x0B
+#define SIO_READ_PINS_REQUEST         0x0C
+#define SIO_READ_EEPROM_REQUEST       0x90
+#define SIO_WRITE_EEPROM_REQUEST      0x91
+#define SIO_ERASE_EEPROM_REQUEST      0x92
+
+#define SIO_DISABLE_FLOW_CTRL 0x0
+#define SIO_RTS_CTS_HS        (0x1 << 8)
+#define SIO_DTR_DSR_HS        (0x2 << 8)
+#define SIO_XON_XOFF_HS       (0x4 << 8)
+
+#define SIO_SET_DTR_MASK 0x1
+#define SIO_SET_DTR_HIGH (1 | (SIO_SET_DTR_MASK << 8))
+#define SIO_SET_DTR_LOW  (0 | (SIO_SET_DTR_MASK << 8))
+#define SIO_SET_RTS_MASK 0x2
+#define SIO_SET_RTS_HIGH (2 | (SIO_SET_RTS_MASK << 8))
+#define SIO_SET_RTS_LOW  (0 | (SIO_SET_RTS_MASK << 8))
+
+#define SIO_RTS_CTS_HS (0x1 << 8)
+
+struct usbh_ftdi {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+    struct usbh_urb bulkout_urb;
+    struct usbh_urb bulkin_urb;
+
+    struct cdc_line_coding line_coding;
+
+    uint8_t intf;
+    uint8_t minor;
+    uint8_t modem_status[2];
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_ftdi_set_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding);
+int usbh_ftdi_get_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding);
+int usbh_ftdi_set_line_state(struct usbh_ftdi *ftdi_class, bool dtr, bool rts);
+
+int usbh_ftdi_bulk_in_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
+int usbh_ftdi_bulk_out_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
+
+void usbh_ftdi_run(struct usbh_ftdi *ftdi_class);
+void usbh_ftdi_stop(struct usbh_ftdi *ftdi_class);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_FTDI_H */

+ 426 - 0
components/drivers/usb/cherryusb/class/vendor/serial/usbh_pl2303.c

@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ * Copyright (c) 2024, Derek Konigsberg
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_pl2303.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "usbh_pl2303"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/ttyUSB%d"
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_pl2303_buf[64];
+
+#define CONFIG_USBHOST_MAX_PL2303_CLASS 4
+
+#define UT_WRITE_VENDOR_DEVICE   (USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE)
+#define UT_READ_VENDOR_DEVICE    (USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE)
+
+static struct usbh_pl2303 g_pl2303_class[CONFIG_USBHOST_MAX_PL2303_CLASS];
+static uint32_t g_devinuse = 0;
+
+static struct usbh_pl2303 *usbh_pl2303_class_alloc(void)
+{
+    int devno;
+
+    for (devno = 0; devno < CONFIG_USBHOST_MAX_PL2303_CLASS; devno++) {
+        if ((g_devinuse & (1 << devno)) == 0) {
+            g_devinuse |= (1 << devno);
+            memset(&g_pl2303_class[devno], 0, sizeof(struct usbh_pl2303));
+            g_pl2303_class[devno].minor = devno;
+            return &g_pl2303_class[devno];
+        }
+    }
+    return NULL;
+}
+
+static void usbh_pl2303_class_free(struct usbh_pl2303 *pl2303_class)
+{
+    int devno = pl2303_class->minor;
+
+    if (devno >= 0 && devno < 32) {
+        g_devinuse &= ~(1 << devno);
+    }
+    memset(pl2303_class, 0, sizeof(struct usbh_pl2303));
+}
+
+static int usbh_pl2303_get_chiptype(struct usbh_pl2303 *pl2303_class)
+{
+    int ret = 0;
+
+    switch (pl2303_class->hport->device_desc.bcdDevice) {
+        case 0x0300:
+            pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HX;
+            /* or TA, that is HX with external crystal */
+            break;
+        case 0x0400:
+            pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HXD;
+            /* or EA, that is HXD with ESD protection */
+            /* or RA, that has internal voltage level converter that works only up to 1Mbaud (!) */
+            break;
+        case 0x0500:
+            pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HXD;
+            /* in fact it's TB, that is HXD with external crystal */
+            break;
+        default:
+            /* NOTE: I have no info about the bcdDevice for the base PL2303 (up to 1.2Mbaud,
+           only fixed rates) and for PL2303SA (8-pin chip, up to 115200 baud */
+            /* Determine the chip type.  This algorithm is taken from Linux. */
+            if (pl2303_class->hport->device_desc.bDeviceClass == 0x02) {
+                pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303;
+            } else if (pl2303_class->hport->device_desc.bMaxPacketSize0 == 0x40) {
+                pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HX;
+            } else {
+                pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303;
+            }
+            break;
+    }
+
+    /*
+     * The new chip revision PL2303HXN is only compatible with the new
+     * PLCOM_SET_REQUEST_PL2303HXN command. Issuing the old command
+     * PLCOM_SET_REQUEST to the new chip raises an error. Thus, PL2303HX
+     * and PL2303HXN can be distinguished by issuing an old-style request
+     * (on a status register) to the new chip and checking the error.
+     */
+    if (pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303HX) {
+        struct usb_setup_packet *setup = pl2303_class->hport->setup;
+
+        setup->bmRequestType = UT_READ_VENDOR_DEVICE;
+        setup->bRequest = PL2303_SET_REQUEST;
+        setup->wValue = PL2303_STATUS_REG_PL2303HX;
+        setup->wIndex = 0;
+        setup->wLength = 1;
+
+        ret = usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
+        if (ret == -USB_ERR_STALL) {
+            pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HXN;
+            ret = 0;
+        } else if (ret < 0) {
+            USB_LOG_WRN("Error checking chip type: %d\r\n", ret);
+            return ret;
+        }
+    }
+
+    switch (pl2303_class->chiptype) {
+        case USBH_PL2303_TYPE_PL2303:
+            USB_LOG_INFO("chiptype = 2303\r\n");
+            break;
+        case USBH_PL2303_TYPE_PL2303HX:
+            USB_LOG_INFO("chiptype = 2303HX/TA\r\n");
+            break;
+        case USBH_PL2303_TYPE_PL2303HXN:
+            USB_LOG_INFO("chiptype = 2303HXN\r\n");
+            break;
+        case USBH_PL2303_TYPE_PL2303HXD:
+            USB_LOG_INFO("chiptype = 2303HXD/TB/RA/EA\r\n");
+            break;
+        default:
+            USB_LOG_INFO("chiptype = [%d]\r\n", pl2303_class->chiptype);
+            break;
+    }
+
+    return ret;
+}
+
+static int usbh_pl2303_do(struct usbh_pl2303 *pl2303_class,
+                          uint8_t req_type, uint8_t request, uint16_t value, uint16_t index,
+                          uint16_t length)
+{
+    struct usb_setup_packet *setup = pl2303_class->hport->setup;
+
+    setup->bmRequestType = req_type;
+    setup->bRequest = request;
+    setup->wValue = value;
+    setup->wIndex = index;
+    setup->wLength = length;
+
+    return usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
+}
+
+int usbh_pl2303_set_line_coding(struct usbh_pl2303 *pl2303_class, struct cdc_line_coding *line_coding)
+{
+    struct usb_setup_packet *setup = pl2303_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_SET_LINE_CODING;
+    setup->wValue = 0;
+    setup->wIndex = pl2303_class->intf;
+    setup->wLength = 7;
+
+    memcpy(g_pl2303_buf, line_coding, sizeof(struct cdc_line_coding));
+
+    return usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
+}
+
+int usbh_pl2303_get_line_coding(struct usbh_pl2303 *pl2303_class, struct cdc_line_coding *line_coding)
+{
+    struct usb_setup_packet *setup = pl2303_class->hport->setup;
+    int ret;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_GET_LINE_CODING;
+    setup->wValue = 0;
+    setup->wIndex = pl2303_class->intf;
+    setup->wLength = 7;
+
+    ret = usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
+    if (ret < 0) {
+        return ret;
+    }
+    memcpy(line_coding, g_pl2303_buf, sizeof(struct cdc_line_coding));
+    return ret;
+}
+
+int usbh_pl2303_set_line_state(struct usbh_pl2303 *pl2303_class, bool dtr, bool rts)
+{
+    struct usb_setup_packet *setup = pl2303_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE;
+    setup->wValue = (dtr << 0) | (rts << 1);
+    setup->wIndex = pl2303_class->intf;
+    setup->wLength = 0;
+
+    return usbh_control_transfer(pl2303_class->hport, setup, NULL);
+}
+
+static int usbh_pl2303_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret = 0;
+
+    struct usbh_pl2303 *pl2303_class = usbh_pl2303_class_alloc();
+    if (pl2303_class == NULL) {
+        USB_LOG_ERR("Fail to alloc pl2303_class\r\n");
+        return -USB_ERR_NOMEM;
+    }
+
+    pl2303_class->hport = hport;
+    pl2303_class->intf = intf;
+
+    hport->config.intf[intf].priv = pl2303_class;
+
+    do {
+        ret = usbh_pl2303_get_chiptype(pl2303_class);
+        if (ret < 0) {
+            break;
+        }
+
+        /* Startup reset sequence, if necessary for the chip type */
+        if (pl2303_class->chiptype != USBH_PL2303_TYPE_PL2303HXN) {
+            struct usb_setup_packet *setup = pl2303_class->hport->setup;
+
+            setup->bmRequestType = UT_WRITE_VENDOR_DEVICE;
+            setup->bRequest = PL2303_SET_REQUEST;
+            setup->wValue = 0;
+            setup->wIndex = pl2303_class->intf;
+            setup->wLength = 0;
+
+            ret = usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
+            if (ret < 0) {
+                USB_LOG_WRN("Initialization reset failed: %d\r\n", ret);
+                break;
+            }
+        }
+
+        if (pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303) {
+            /* HX variants seem to lock up after a clear stall request. */
+            /*
+             * The FreeBSD code sets the stall flags on the in and out pipes
+             * here. Have no idea exactly how to do this, or if it is necessary.
+             * May just leave this code unwritten until test hardware is available.
+             */
+        } else if (pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303HX || pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303HXD) {
+            /* Reset upstream data pipes */
+            ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 8, 0, 0);
+            if (ret < 0) {
+                USB_LOG_WRN("Could not reset upstream data pipes (8,0): %d\r\n", ret);
+                break;
+            }
+            ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 9, 0, 0);
+            if (ret < 0) {
+                USB_LOG_WRN("Could not reset upstream data pipes (9,0): %d\r\n", ret);
+                break;
+            }
+        } else if (pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303HXN) {
+            /* Reset upstream data pipes */
+            ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST_PL2303HXN, 0x07, 0x03, 0);
+            if (ret < 0) {
+                USB_LOG_WRN("Could not reset upstream data pipes (7,3): %d\r\n", ret);
+                break;
+            }
+        }
+
+        /* Final device initialization, if necessary for the chip type */
+        if (pl2303_class->chiptype != USBH_PL2303_TYPE_PL2303HXN) {
+            if (usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8484, 0, 1) < 0 ||
+                usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x0404, 0, 0) < 0 ||
+                usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8484, 0, 1) < 0 ||
+                usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8383, 0, 1) < 0 ||
+                usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8484, 0, 1) < 0 ||
+                usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x0404, 1, 0) < 0 ||
+                usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8484, 0, 1) < 0 ||
+                usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8383, 0, 1) < 0 ||
+                usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 0, 1, 0) < 0 ||
+                usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 1, 0, 0) < 0) {
+                USB_LOG_WRN("Could not complete init sequence\r\n");
+                ret = -USB_ERR_INVAL;
+                break;
+            }
+
+            if (pl2303_class->chiptype != USBH_PL2303_TYPE_PL2303) {
+                ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 2, 0x44, 0);
+            } else {
+                ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 2, 0x24, 0);
+            }
+            if (ret < 0) {
+                USB_LOG_WRN("Could not complete final init request: %d\r\n", ret);
+                break;
+            }
+        }
+    } while (0);
+
+    if (ret < 0) {
+        USB_LOG_ERR("Failed to initialize PL2303 device: %d\r\n", ret);
+        return ret;
+    }
+
+    for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
+        ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
+        if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
+            continue;
+        } else {
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(pl2303_class->bulkin, ep_desc);
+            } else {
+                USBH_EP_INIT(pl2303_class->bulkout, ep_desc);
+            }
+        }
+    }
+
+    snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, pl2303_class->minor);
+
+    USB_LOG_INFO("Register PL2303 Class:%s\r\n", hport->config.intf[intf].devname);
+
+#if 0
+    USB_LOG_INFO("Test pl2303 rx and tx and rx for 5 times, baudrate is 115200\r\n");
+
+    struct cdc_line_coding linecoding;
+    uint8_t count = 5;
+
+    linecoding.dwDTERate = 115200;
+    linecoding.bDataBits = 8;
+    linecoding.bParityType = 0;
+    linecoding.bCharFormat = 0;
+    usbh_pl2303_set_line_coding(pl2303_class, &linecoding);
+    usbh_pl2303_set_line_state(pl2303_class, true, false);
+
+    memset(g_pl2303_buf, 'a', sizeof(g_pl2303_buf));
+    ret = usbh_pl2303_bulk_out_transfer(pl2303_class, g_pl2303_buf, sizeof(g_pl2303_buf), 0xfffffff);
+    USB_LOG_RAW("out ret:%d\r\n", ret);
+    while (count--) {
+        ret = usbh_pl2303_bulk_in_transfer(pl2303_class, g_pl2303_buf, sizeof(g_pl2303_buf), 0xfffffff);
+        USB_LOG_RAW("in ret:%d\r\n", ret);
+        if (ret > 0) {
+            for (uint32_t i = 0; i < ret; i++) {
+                USB_LOG_RAW("%02x ", g_pl2303_buf[i]);
+            }
+        }
+        USB_LOG_RAW("\r\n");
+    }
+#endif
+
+    usbh_pl2303_run(pl2303_class);
+    return ret;
+}
+
+static int usbh_pl2303_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_pl2303 *pl2303_class = (struct usbh_pl2303 *)hport->config.intf[intf].priv;
+
+    if (pl2303_class) {
+        if (pl2303_class->bulkin) {
+            usbh_kill_urb(&pl2303_class->bulkin_urb);
+        }
+
+        if (pl2303_class->bulkout) {
+            usbh_kill_urb(&pl2303_class->bulkout_urb);
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister PL2303 Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_pl2303_stop(pl2303_class);
+        }
+
+        usbh_pl2303_class_free(pl2303_class);
+    }
+
+    return ret;
+}
+
+int usbh_pl2303_bulk_in_transfer(struct usbh_pl2303 *pl2303_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+{
+    int ret;
+    struct usbh_urb *urb = &pl2303_class->bulkin_urb;
+
+    usbh_bulk_urb_fill(urb, pl2303_class->hport, pl2303_class->bulkin, buffer, buflen, timeout, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+int usbh_pl2303_bulk_out_transfer(struct usbh_pl2303 *pl2303_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+{
+    int ret;
+    struct usbh_urb *urb = &pl2303_class->bulkout_urb;
+
+    usbh_bulk_urb_fill(urb, pl2303_class->hport, pl2303_class->bulkout, buffer, buflen, timeout, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+__WEAK void usbh_pl2303_run(struct usbh_pl2303 *pl2303_class)
+{
+}
+
+__WEAK void usbh_pl2303_stop(struct usbh_pl2303 *pl2303_class)
+{
+}
+
+static const uint16_t pl2303_id_table[][2] = {
+    { 0x067B, 0x2303 }, // PL2303 Serial (ATEN/IOGEAR UC232A)
+    { 0x067B, 0x23A3 }, // PL2303HXN Serial, type GC
+    { 0x067B, 0x23B3 }, // PL2303HXN Serial, type GB
+    { 0x067B, 0x23C3 }, // PL2303HXN Serial, type GT
+    { 0x067B, 0x23D3 }, // PL2303HXN Serial, type GL
+    { 0x067B, 0x23E3 }, // PL2303HXN Serial, type GE
+    { 0x067B, 0x23F3 }, // PL2303HXN Serial, type GS
+    { 0, 0 },
+};
+
+const struct usbh_class_driver pl2303_class_driver = {
+    .driver_name = "pl2303",
+    .connect = usbh_pl2303_connect,
+    .disconnect = usbh_pl2303_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info pl2303_class_info = {
+    .match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
+    .class = 0xff,
+    .subclass = 0x00,
+    .protocol = 0x00,
+    .id_table = pl2303_id_table,
+    .class_driver = &pl2303_class_driver
+};

+ 62 - 0
components/drivers/usb/cherryusb/class/vendor/serial/usbh_pl2303.h

@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_PL2303_H
+#define USBH_PL2303_H
+
+#include "usb_cdc.h"
+
+#define PL2303_SET_REQUEST             0x01
+#define PL2303_SET_REQUEST_PL2303HXN   0x80
+#define PL2303_SET_CRTSCTS             0x41
+#define PL2303_SET_CRTSCTS_PL2303X     0x61
+#define PL2303_SET_CRTSCTS_PL2303HXN   0xFA
+#define PL2303_CLEAR_CRTSCTS_PL2303HXN 0xFF
+#define PL2303_CRTSCTS_REG_PL2303HXN   0x0A
+#define PL2303_STATUS_REG_PL2303HX     0x8080
+
+/* Different PL2303 IC types */
+#define USBH_PL2303_TYPE_UNKNOWN   0
+#define USBH_PL2303_TYPE_PL2303    1
+#define USBH_PL2303_TYPE_PL2303HX  2
+#define USBH_PL2303_TYPE_PL2303HXD 3
+#define USBH_PL2303_TYPE_PL2303HXN 4
+
+struct usbh_pl2303 {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+
+    struct usbh_urb bulkout_urb;
+    struct usbh_urb bulkin_urb;
+
+    struct cdc_line_coding linecoding;
+
+    uint8_t intf;
+    uint8_t minor;
+    uint8_t chiptype;
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_pl2303_set_line_coding(struct usbh_pl2303 *pl2303_class, struct cdc_line_coding *line_coding);
+int usbh_pl2303_get_line_coding(struct usbh_pl2303 *pl2303_class, struct cdc_line_coding *line_coding);
+int usbh_pl2303_set_line_state(struct usbh_pl2303 *pl2303_class, bool dtr, bool rts);
+
+int usbh_pl2303_bulk_in_transfer(struct usbh_pl2303 *pl2303_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
+int usbh_pl2303_bulk_out_transfer(struct usbh_pl2303 *pl2303_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
+
+void usbh_pl2303_run(struct usbh_pl2303 *pl2303_class);
+void usbh_pl2303_stop(struct usbh_pl2303 *pl2303_class);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_PL2303_H */

+ 1198 - 0
components/drivers/usb/cherryusb/class/video/usb_video.h

@@ -0,0 +1,1198 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_VIDEO_H
+#define USB_VIDEO_H
+
+#define USB_DEVICE_VIDEO_CLASS_VERSION_1_5 0
+
+/*! @brief Video device subclass code */
+#define VIDEO_SC_UNDEFINED                  0x00U
+#define VIDEO_SC_VIDEOCONTROL               0x01U
+#define VIDEO_SC_VIDEOSTREAMING             0x02U
+#define VIDEO_SC_VIDEO_INTERFACE_COLLECTION 0x03U
+
+/*! @brief Video device protocol code */
+#define VIDEO_PC_PROTOCOL_UNDEFINED 0x00U
+#define VIDEO_PC_PROTOCOL_15        0x01U
+
+/*! @brief Video device class-specific descriptor type */
+#define VIDEO_CS_UNDEFINED_DESCRIPTOR_TYPE     0x20U
+#define VIDEO_CS_DEVICE_DESCRIPTOR_TYPE        0x21U
+#define VIDEO_CS_CONFIGURATION_DESCRIPTOR_TYPE 0x22U
+#define VIDEO_CS_STRING_DESCRIPTOR_TYPE        0x23U
+#define VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE     0x24U
+#define VIDEO_CS_ENDPOINT_DESCRIPTOR_TYPE      0x25U
+
+/*! @brief Video device class-specific VC interface descriptor subtype */
+#define VIDEO_VC_DESCRIPTOR_UNDEFINED_DESCRIPTOR_SUBTYPE 0x00U
+#define VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE               0x01U
+#define VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE       0x02U
+#define VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE      0x03U
+#define VIDEO_VC_SELECTOR_UNIT_DESCRIPTOR_SUBTYPE        0x04U
+#define VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE      0x05U
+#define VIDEO_VC_EXTENSION_UNIT_DESCRIPTOR_SUBTYPE       0x06U
+#define VIDEO_VC_ENCODING_UNIT_DESCRIPTOR_SUBTYPE        0x07U
+
+/*! @brief Video device class-specific VS interface descriptor subtype */
+#define VIDEO_VS_UNDEFINED_DESCRIPTOR_SUBTYPE             0x00U
+#define VIDEO_VS_INPUT_HEADER_DESCRIPTOR_SUBTYPE          0x01U
+#define VIDEO_VS_OUTPUT_HEADER_DESCRIPTOR_SUBTYPE         0x02U
+#define VIDEO_VS_STILL_IMAGE_FRAME_DESCRIPTOR_SUBTYPE     0x03U
+#define VIDEO_VS_FORMAT_UNCOMPRESSED_DESCRIPTOR_SUBTYPE   0x04U
+#define VIDEO_VS_FRAME_UNCOMPRESSED_DESCRIPTOR_SUBTYPE    0x05U
+#define VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_SUBTYPE          0x06U
+#define VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_SUBTYPE           0x07U
+#define VIDEO_VS_FORMAT_MPEG2TS_DESCRIPTOR_SUBTYPE        0x0AU
+#define VIDEO_VS_FORMAT_DV_DESCRIPTOR_SUBTYPE             0x0CU
+#define VIDEO_VS_COLORFORMAT_DESCRIPTOR_SUBTYPE           0x0DU
+#define VIDEO_VS_FORMAT_FRAME_BASED_DESCRIPTOR_SUBTYPE    0x10U
+#define VIDEO_VS_FRAME_FRAME_BASED_DESCRIPTOR_SUBTYPE     0x11U
+#define VIDEO_VS_FORMAT_STREAM_BASED_DESCRIPTOR_SUBTYPE   0x12U
+#define VIDEO_VS_FORMAT_H264_DESCRIPTOR_SUBTYPE           0x13U
+#define VIDEO_VS_FRAME_H264_DESCRIPTOR_SUBTYPE            0x14U
+#define VIDEO_VS_FORMAT_H264_SIMULCAST_DESCRIPTOR_SUBTYPE 0x15U
+#define VIDEO_VS_FORMAT_VP8_DESCRIPTOR_SUBTYPE            0x16U
+#define VIDEO_VS_FRAME_VP8_DESCRIPTOR_SUBTYPE             0x17U
+#define VIDEO_VS_FORMAT_VP8_SIMULCAST_DESCRIPTOR_SUBTYPE  0x18U
+
+/*! @brief Video device class-specific VC endpoint descriptor subtype */
+#define VIDEO_EP_UNDEFINED_DESCRIPTOR_SUBTYPE 0x00U
+#define VIDEO_EP_GENERAL_DESCRIPTOR_SUBTYPE   0x01U
+#define VIDEO_EP_ENDPOINT_DESCRIPTOR_SUBTYPE  0x02U
+#define VIDEO_EP_INTERRUPT_DESCRIPTOR_SUBTYPE 0x03U
+
+/*! @brief Video device class-specific request code */
+#define VIDEO_REQUEST_UNDEFINED   0x00U
+#define VIDEO_REQUEST_SET_CUR     0x01U
+#define VIDEO_REQUEST_SET_CUR_ALL 0x11U
+#define VIDEO_REQUEST_GET_CUR     0x81U
+#define VIDEO_REQUEST_GET_MIN     0x82U
+#define VIDEO_REQUEST_GET_MAX     0x83U
+#define VIDEO_REQUEST_GET_RES     0x84U
+#define VIDEO_REQUEST_GET_LEN     0x85U
+#define VIDEO_REQUEST_GET_INFO    0x86U
+#define VIDEO_REQUEST_GET_DEF     0x87U
+#define VIDEO_REQUEST_GET_CUR_ALL 0x91U
+#define VIDEO_REQUEST_GET_MIN_ALL 0x92U
+#define VIDEO_REQUEST_GET_MAX_ALL 0x93U
+#define VIDEO_REQUEST_GET_RES_ALL 0x94U
+#define VIDEO_REQUEST_GET_DEF_ALL 0x97U
+
+/*! @brief Video device class-specific VideoControl interface control selector */
+#define VIDEO_VC_CONTROL_UNDEFINED          0x00U
+#define VIDEO_VC_VIDEO_POWER_MODE_CONTROL   0x01U
+#define VIDEO_VC_REQUEST_ERROR_CODE_CONTROL 0x02U
+
+/*! @brief Video device class-specific Terminal control selector */
+#define VIDEO_TE_CONTROL_UNDEFINED 0x00U
+
+/*! @brief Video device class-specific Selector Unit control selector */
+#define VIDEO_SU_CONTROL_UNDEFINED    0x00U
+#define VIDEO_SU_INPUT_SELECT_CONTROL 0x01U
+
+/*! @brief Video device class-specific Camera Terminal control selector */
+#define VIDEO_CT_CONTROL_UNDEFINED              0x00U
+#define VIDEO_CT_SCANNING_MODE_CONTROL          0x01U
+#define VIDEO_CT_AE_MODE_CONTROL                0x02U
+#define VIDEO_CT_AE_PRIORITY_CONTROL            0x03U
+#define VIDEO_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04U
+#define VIDEO_CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05U
+#define VIDEO_CT_FOCUS_ABSOLUTE_CONTROL         0x06U
+#define VIDEO_CT_FOCUS_RELATIVE_CONTROL         0x07U
+#define VIDEO_CT_FOCUS_AUTO_CONTROL             0x08U
+#define VIDEO_CT_IRIS_ABSOLUTE_CONTROL          0x09U
+#define VIDEO_CT_IRIS_RELATIVE_CONTROL          0x0AU
+#define VIDEO_CT_ZOOM_ABSOLUTE_CONTROL          0x0BU
+#define VIDEO_CT_ZOOM_RELATIVE_CONTROL          0x0CU
+#define VIDEO_CT_PANTILT_ABSOLUTE_CONTROL       0x0DU
+#define VIDEO_CT_PANTILT_RELATIVE_CONTROL       0x0EU
+#define VIDEO_CT_ROLL_ABSOLUTE_CONTROL          0x0FU
+#define VIDEO_CT_ROLL_RELATIVE_CONTROL          0x10U
+#define VIDEO_CT_PRIVACY_CONTROL                0x11U
+#define VIDEO_CT_FOCUS_SIMPLE_CONTROL           0x12U
+#define VIDEO_CT_WINDOW_CONTROL                 0x13U
+#define VIDEO_CT_REGION_OF_INTEREST_CONTROL     0x14U
+
+/*! @brief Video device class-specific Processing Unit control selector */
+#define VIDEO_PU_CONTROL_UNDEFINED                      0x00U
+#define VIDEO_PU_BACKLIGHT_COMPENSATION_CONTROL         0x01U
+#define VIDEO_PU_BRIGHTNESS_CONTROL                     0x02U
+#define VIDEO_PU_CONTRAST_CONTROL                       0x03U
+#define VIDEO_PU_GAIN_CONTROL                           0x04U
+#define VIDEO_PU_POWER_LINE_FREQUENCY_CONTROL           0x05U
+#define VIDEO_PU_HUE_CONTROL                            0x06U
+#define VIDEO_PU_SATURATION_CONTROL                     0x07U
+#define VIDEO_PU_SHARPNESS_CONTROL                      0x08U
+#define VIDEO_PU_GAMMA_CONTROL                          0x09U
+#define VIDEO_PU_WHITE_BALANCE_TEMPERATURE_CONTROL      0x0AU
+#define VIDEO_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0BU
+#define VIDEO_PU_WHITE_BALANCE_COMPONENT_CONTROL        0x0CU
+#define VIDEO_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL   0x0DU
+#define VIDEO_PU_DIGITAL_MULTIPLIER_CONTROL             0x0EU
+#define VIDEO_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL       0x0FU
+#define VIDEO_PU_HUE_AUTO_CONTROL                       0x10U
+#define VIDEO_PU_ANALOG_VIDEO_STANDARD_CONTROL          0x11U
+#define VIDEO_PU_ANALOG_LOCK_STATUS_CONTROL             0x12U
+#define VIDEO_PU_CONTRAST_AUTO_CONTROL                  0x13U
+
+/*! @brief Video device class-specific Encoding Unit control selector */
+#define VIDEO_EU_CONTROL_UNDEFINED           0x00U
+#define VIDEO_EU_SELECT_LAYER_CONTROL        0x01U
+#define VIDEO_EU_PROFILE_TOOLSET_CONTROL     0x02U
+#define VIDEO_EU_VIDEO_RESOLUTION_CONTROL    0x03U
+#define VIDEO_EU_MIN_FRAME_INTERVAL_CONTROL  0x04U
+#define VIDEO_EU_SLICE_MODE_CONTROL          0x05U
+#define VIDEO_EU_RATE_CONTROL_MODE_CONTROL   0x06U
+#define VIDEO_EU_AVERAGE_BITRATE_CONTROL     0x07U
+#define VIDEO_EU_CPB_SIZE_CONTROL            0x08U
+#define VIDEO_EU_PEAK_BIT_RATE_CONTROL       0x09U
+#define VIDEO_EU_QUANTIZATION_PARAMS_CONTROL 0x0AU
+#define VIDEO_EU_SYNC_REF_FRAME_CONTROL      0x0BU
+#define VIDEO_EU_LTR_BUFFER_CONTROL          0x0CU
+#define VIDEO_EU_LTR_PICTURE_CONTROL         0x0DU
+#define VIDEO_EU_LTR_VALIDATION_CONTROL      0x0EU
+#define VIDEO_EU_LEVEL_IDC_LIMIT_CONTROL     0x0FU
+#define VIDEO_EU_SEI_PAYLOADTYPE_CONTROL     0x10U
+#define VIDEO_EU_QP_RANGE_CONTROL            0x11U
+#define VIDEO_EU_PRIORITY_CONTROL            0x12U
+#define VIDEO_EU_START_OR_STOP_LAYER_CONTROL 0x13U
+#define VIDEO_EU_ERROR_RESILIENCY_CONTROL    0x14U
+
+/*! @brief Video device class-specific Extension Unit control selector */
+#define VIDEO_XU_CONTROL_UNDEFINED 0x00U
+
+/*! @brief Video device class-specific VideoStreaming Interface control selector */
+#define VIDEO_VS_CONTROL_UNDEFINED            0x00U
+#define VIDEO_VS_PROBE_CONTROL                0x01U
+#define VIDEO_VS_COMMIT_CONTROL               0x02U
+#define VIDEO_VS_STILL_PROBE_CONTROL          0x03U
+#define VIDEO_VS_STILL_COMMIT_CONTROL         0x04U
+#define VIDEO_VS_STILL_IMAGE_TRIGGER_CONTROL  0x05U
+#define VIDEO_VS_STREAM_ERROR_CODE_CONTROL    0x06U
+#define VIDEO_VS_GENERATE_KEY_FRAME_CONTROL   0x07U
+#define VIDEO_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08U
+#define VIDEO_VS_SYNCH_DELAY_CONTROL          0x09U
+
+/*! @}*/
+
+/*!
+ * @name USB Video class terminal types
+ * @{
+ */
+
+/*! @brief Video device USB terminal type */
+#define VIDEO_TT_VENDOR_SPECIFIC 0x0100U
+#define VIDEO_TT_STREAMING       0x0101U
+
+/*! @brief Video device input terminal type */
+#define VIDEO_ITT_VENDOR_SPECIFIC       0x0200U
+#define VIDEO_ITT_CAMERA                0x0201U
+#define VIDEO_ITT_MEDIA_TRANSPORT_INPUT 0x0202U
+
+/*! @brief Video device output terminal type */
+#define VIDEO_OTT_VENDOR_SPECIFIC        0x0300U
+#define VIDEO_OTT_DISPLAY                0x0301U
+#define VIDEO_OTT_MEDIA_TRANSPORT_OUTPUT 0x0302U
+
+/*! @brief Video device external terminal type */
+#define VIDEO_ET_VENDOR_SPECIFIC     0x0400U
+#define VIDEO_ET_COMPOSITE_CONNECTOR 0x0401U
+#define VIDEO_ET_SVIDEO_CONNECTOR    0x0402U
+#define VIDEO_ET_COMPONENT_CONNECTOR 0x0403U
+
+/*! @}*/
+
+/*!
+ * @name USB Video class setup request types
+ * @{
+ */
+
+/*! @brief Video device class setup request set type */
+#define VIDEO_SET_REQUEST_INTERFACE 0x21U
+#define VIDEO_SET_REQUEST_ENDPOINT  0x22U
+
+/*! @brief Video device class setup request get type */
+#define VIDEO_GET_REQUEST_INTERFACE 0xA1U
+#define VIDEO_GET_REQUEST_ENDPOINT  0xA2U
+
+/*! @}*/
+
+/*! @brief Video device still image trigger control */
+#define VIDEO_STILL_IMAGE_TRIGGER_NORMAL_OPERATION                            0x00U
+#define VIDEO_STILL_IMAGE_TRIGGER_TRANSMIT_STILL_IMAGE                        0x01U
+#define VIDEO_STILL_IMAGE_TRIGGER_TRANSMIT_STILL_IMAGE_VS_DEDICATED_BULK_PIPE 0x02U
+#define VIDEO_STILL_IMAGE_TRIGGER_ABORT_STILL_IMAGE_TRANSMISSION              0x03U
+
+/*!
+ * @name USB Video device class-specific request commands
+ * @{
+ */
+
+/*! @brief Video device class-specific request GET CUR COMMAND */
+#define VIDEO_GET_CUR_VC_POWER_MODE_CONTROL 0x8101U
+#define VIDEO_GET_CUR_VC_ERROR_CODE_CONTROL 0x8102U
+
+#define VIDEO_GET_CUR_PU_BACKLIGHT_COMPENSATION_CONTROL         0x8121U
+#define VIDEO_GET_CUR_PU_BRIGHTNESS_CONTROL                     0x8122U
+#define VIDEO_GET_CUR_PU_CONTRACT_CONTROL                       0x8123U
+#define VIDEO_GET_CUR_PU_GAIN_CONTROL                           0x8124U
+#define VIDEO_GET_CUR_PU_POWER_LINE_FREQUENCY_CONTROL           0x8125U
+#define VIDEO_GET_CUR_PU_HUE_CONTROL                            0x8126U
+#define VIDEO_GET_CUR_PU_SATURATION_CONTROL                     0x8127U
+#define VIDEO_GET_CUR_PU_SHARRNESS_CONTROL                      0x8128U
+#define VIDEO_GET_CUR_PU_GAMMA_CONTROL                          0x8129U
+#define VIDEO_GET_CUR_PU_WHITE_BALANCE_TEMPERATURE_CONTROL      0x812AU
+#define VIDEO_GET_CUR_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x812BU
+#define VIDEO_GET_CUR_PU_WHITE_BALANCE_COMPONENT_CONTROL        0x812CU
+#define VIDEO_GET_CUR_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL   0x812DU
+#define VIDEO_GET_CUR_PU_DIGITAL_MULTIPLIER_CONTROL             0x812EU
+#define VIDEO_GET_CUR_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL       0x812FU
+#define VIDEO_GET_CUR_PU_HUE_AUTO_CONTROL                       0x8130U
+#define VIDEO_GET_CUR_PU_ANALOG_VIDEO_STANDARD_CONTROL          0x8131U
+#define VIDEO_GET_CUR_PU_ANALOG_LOCK_STATUS_CONTROL             0x8132U
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_CUR_PU_CONTRAST_AUTO_CONTROL 0x8133U
+#endif
+
+#define VIDEO_GET_CUR_CT_SCANNING_MODE_CONTROL          0x8141U
+#define VIDEO_GET_CUR_CT_AE_MODE_CONTROL                0x8142U
+#define VIDEO_GET_CUR_CT_AE_PRIORITY_CONTROL            0x8143U
+#define VIDEO_GET_CUR_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x8144U
+#define VIDEO_GET_CUR_CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x8145U
+#define VIDEO_GET_CUR_CT_FOCUS_ABSOLUTE_CONTROL         0x8146U
+#define VIDEO_GET_CUR_CT_FOCUS_RELATIVE_CONTROL         0x8147U
+#define VIDEO_GET_CUR_CT_FOCUS_AUTO_CONTROL             0x8148U
+#define VIDEO_GET_CUR_CT_IRIS_ABSOLUTE_CONTROL          0x8149U
+#define VIDEO_GET_CUR_CT_IRIS_RELATIVE_CONTROL          0x814AU
+#define VIDEO_GET_CUR_CT_ZOOM_ABSOLUTE_CONTROL          0x814BU
+#define VIDEO_GET_CUR_CT_ZOOM_RELATIVE_CONTROL          0x814CU
+#define VIDEO_GET_CUR_CT_PANTILT_ABSOLUTE_CONTROL       0x814DU
+#define VIDEO_GET_CUR_CT_PANTILT_RELATIVE_CONTROL       0x814EU
+#define VIDEO_GET_CUR_CT_ROLL_ABSOLUTE_CONTROL          0x814FU
+#define VIDEO_GET_CUR_CT_ROLL_RELATIVE_CONTROL          0x8150U
+#define VIDEO_GET_CUR_CT_PRIVACY_CONTROL                0x8151U
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_CUR_CT_FOCUS_SIMPLE_CONTROL       0x8152U
+#define VIDEO_GET_CUR_CT_DIGITAL_WINDOW_CONTROL     0x8153U
+#define VIDEO_GET_CUR_CT_REGION_OF_INTEREST_CONTROL 0x8154U
+#endif
+
+#define VIDEO_GET_CUR_VS_PROBE_CONTROL                0x8161U
+#define VIDEO_GET_CUR_VS_COMMIT_CONTROL               0x8162U
+#define VIDEO_GET_CUR_VS_STILL_PROBE_CONTROL          0x8163U
+#define VIDEO_GET_CUR_VS_STILL_COMMIT_CONTROL         0x8164U
+#define VIDEO_GET_CUR_VS_STILL_IMAGE_TRIGGER_CONTROL  0x8165U
+#define VIDEO_GET_CUR_VS_STREAM_ERROR_CODE_CONTROL    0x8166U
+#define VIDEO_GET_CUR_VS_GENERATE_KEY_FRAME_CONTROL   0x8167U
+#define VIDEO_GET_CUR_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x8168U
+#define VIDEO_GET_CUR_VS_SYNCH_DELAY_CONTROL          0x8169U
+
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_CUR_EU_SELECT_LAYER_CONTROL        0x8181U
+#define VIDEO_GET_CUR_EU_PROFILE_TOOLSET_CONTROL     0x8182U
+#define VIDEO_GET_CUR_EU_VIDEO_RESOLUTION_CONTROL    0x8183U
+#define VIDEO_GET_CUR_EU_MIN_FRAME_INTERVAL_CONTROL  0x8184U
+#define VIDEO_GET_CUR_EU_SLICE_MODE_CONTROL          0x8185U
+#define VIDEO_GET_CUR_EU_RATE_CONTROL_MODE_CONTROL   0x8186U
+#define VIDEO_GET_CUR_EU_AVERAGE_BITRATE_CONTROL     0x8187U
+#define VIDEO_GET_CUR_EU_CPB_SIZE_CONTROL            0x8188U
+#define VIDEO_GET_CUR_EU_PEAK_BIT_RATE_CONTROL       0x8189U
+#define VIDEO_GET_CUR_EU_QUANTIZATION_PARAMS_CONTROL 0x818AU
+#define VIDEO_GET_CUR_EU_SYNC_REF_FRAME_CONTROL      0x818BU
+#define VIDEO_GET_CUR_EU_LTR_BUFFER_CONTROL          0x818CU
+#define VIDEO_GET_CUR_EU_LTR_PICTURE_CONTROL         0x818DU
+#define VIDEO_GET_CUR_EU_LTR_VALIDATION_CONTROL      0x818EU
+#define VIDEO_GET_CUR_EU_LEVEL_IDC_LIMIT_CONTROL     0x818FU
+#define VIDEO_GET_CUR_EU_SEI_PAYLOADTYPE_CONTROL     0x8190U
+#define VIDEO_GET_CUR_EU_QP_RANGE_CONTROL            0x8191U
+#define VIDEO_GET_CUR_EU_PRIORITY_CONTROL            0x8192U
+#define VIDEO_GET_CUR_EU_START_OR_STOP_LAYER_CONTROL 0x8193U
+#define VIDEO_GET_CUR_EU_ERROR_RESILIENCY_CONTROL    0x8194U
+#endif
+
+/*! @brief Video device class-specific request GET MIN COMMAND */
+#define VIDEO_GET_MIN_PU_BACKLIGHT_COMPENSATION_CONTROL    0x8221U
+#define VIDEO_GET_MIN_PU_BRIGHTNESS_CONTROL                0x8222U
+#define VIDEO_GET_MIN_PU_CONTRACT_CONTROL                  0x8223U
+#define VIDEO_GET_MIN_PU_GAIN_CONTROL                      0x8224U
+#define VIDEO_GET_MIN_PU_HUE_CONTROL                       0x8226U
+#define VIDEO_GET_MIN_PU_SATURATION_CONTROL                0x8227U
+#define VIDEO_GET_MIN_PU_SHARRNESS_CONTROL                 0x8228U
+#define VIDEO_GET_MIN_PU_GAMMA_CONTROL                     0x8229U
+#define VIDEO_GET_MIN_PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x822AU
+#define VIDEO_GET_MIN_PU_WHITE_BALANCE_COMPONENT_CONTROL   0x822CU
+#define VIDEO_GET_MIN_PU_DIGITAL_MULTIPLIER_CONTROL        0x822EU
+#define VIDEO_GET_MIN_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL  0x822FU
+
+#define VIDEO_GET_MIN_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x8244U
+#define VIDEO_GET_MIN_CT_FOCUS_ABSOLUTE_CONTROL         0x8246U
+#define VIDEO_GET_MIN_CT_FOCUS_RELATIVE_CONTROL         0x8247U
+#define VIDEO_GET_MIN_CT_IRIS_ABSOLUTE_CONTROL          0x8249U
+#define VIDEO_GET_MIN_CT_ZOOM_ABSOLUTE_CONTROL          0x824BU
+#define VIDEO_GET_MIN_CT_ZOOM_RELATIVE_CONTROL          0x824CU
+#define VIDEO_GET_MIN_CT_PANTILT_ABSOLUTE_CONTROL       0x824DU
+#define VIDEO_GET_MIN_CT_PANTILT_RELATIVE_CONTROL       0x824EU
+#define VIDEO_GET_MIN_CT_ROLL_ABSOLUTE_CONTROL          0x824FU
+#define VIDEO_GET_MIN_CT_ROLL_RELATIVE_CONTROL          0x8250U
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_MIN_CT_DIGITAL_WINDOW_CONTROL     0x8251U
+#define VIDEO_GET_MIN_CT_REGION_OF_INTEREST_CONTROL 0x8252U
+#endif
+
+#define VIDEO_GET_MIN_VS_PROBE_CONTROL                0x8261U
+#define VIDEO_GET_MIN_VS_STILL_PROBE_CONTROL          0x8263U
+#define VIDEO_GET_MIN_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x8268U
+#define VIDEO_GET_MIN_VS_SYNCH_DELAY_CONTROL          0x8269U
+
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_MIN_EU_VIDEO_RESOLUTION_CONTROL    0x8283U
+#define VIDEO_GET_MIN_EU_MIN_FRAME_INTERVAL_CONTROL  0x8284U
+#define VIDEO_GET_MIN_EU_SLICE_MODE_CONTROL          0x8285U
+#define VIDEO_GET_MIN_EU_AVERAGE_BITRATE_CONTROL     0x8287U
+#define VIDEO_GET_MIN_EU_CPB_SIZE_CONTROL            0x8288U
+#define VIDEO_GET_MIN_EU_PEAK_BIT_RATE_CONTROL       0x8289U
+#define VIDEO_GET_MIN_EU_QUANTIZATION_PARAMS_CONTROL 0x828AU
+#define VIDEO_GET_MIN_EU_SYNC_REF_FRAME_CONTROL      0x828BU
+#define VIDEO_GET_MIN_EU_LEVEL_IDC_LIMIT_CONTROL     0x828FU
+#define VIDEO_GET_MIN_EU_SEI_PAYLOADTYPE_CONTROL     0x8290U
+#define VIDEO_GET_MIN_EU_QP_RANGE_CONTROL            0x8291U
+#endif
+
+/*! @brief Video device class-specific request GET MAX COMMAND */
+#define VIDEO_GET_MAX_PU_BACKLIGHT_COMPENSATION_CONTROL    0x8321U
+#define VIDEO_GET_MAX_PU_BRIGHTNESS_CONTROL                0x8322U
+#define VIDEO_GET_MAX_PU_CONTRACT_CONTROL                  0x8323U
+#define VIDEO_GET_MAX_PU_GAIN_CONTROL                      0x8324U
+#define VIDEO_GET_MAX_PU_HUE_CONTROL                       0x8326U
+#define VIDEO_GET_MAX_PU_SATURATION_CONTROL                0x8327U
+#define VIDEO_GET_MAX_PU_SHARRNESS_CONTROL                 0x8328U
+#define VIDEO_GET_MAX_PU_GAMMA_CONTROL                     0x8329U
+#define VIDEO_GET_MAX_PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x832AU
+#define VIDEO_GET_MAX_PU_WHITE_BALANCE_COMPONENT_CONTROL   0x832CU
+#define VIDEO_GET_MAX_PU_DIGITAL_MULTIPLIER_CONTROL        0x832EU
+#define VIDEO_GET_MAX_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL  0x832FU
+
+#define VIDEO_GET_MAX_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x8344U
+#define VIDEO_GET_MAX_CT_FOCUS_ABSOLUTE_CONTROL         0x8346U
+#define VIDEO_GET_MAX_CT_FOCUS_RELATIVE_CONTROL         0x8347U
+#define VIDEO_GET_MAX_CT_IRIS_ABSOLUTE_CONTROL          0x8349U
+#define VIDEO_GET_MAX_CT_ZOOM_ABSOLUTE_CONTROL          0x834BU
+#define VIDEO_GET_MAX_CT_ZOOM_RELATIVE_CONTROL          0x834CU
+#define VIDEO_GET_MAX_CT_PANTILT_ABSOLUTE_CONTROL       0x834DU
+#define VIDEO_GET_MAX_CT_PANTILT_RELATIVE_CONTROL       0x834EU
+#define VIDEO_GET_MAX_CT_ROLL_ABSOLUTE_CONTROL          0x834FU
+#define VIDEO_GET_MAX_CT_ROLL_RELATIVE_CONTROL          0x8350U
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_MAX_CT_DIGITAL_WINDOW_CONTROL     0x8351U
+#define VIDEO_GET_MAX_CT_REGION_OF_INTEREST_CONTROL 0x8352U
+#endif
+
+#define VIDEO_GET_MAX_VS_PROBE_CONTROL                0x8361U
+#define VIDEO_GET_MAX_VS_STILL_PROBE_CONTROL          0x8363U
+#define VIDEO_GET_MAX_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x8368U
+#define VIDEO_GET_MAX_VS_SYNCH_DELAY_CONTROL          0x8369U
+
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_MAX_EU_VIDEO_RESOLUTION_CONTROL    0x8383U
+#define VIDEO_GET_MAX_EU_MIN_FRAME_INTERVAL_CONTROL  0x8384U
+#define VIDEO_GET_MAX_EU_SLICE_MODE_CONTROL          0x8385U
+#define VIDEO_GET_MAX_EU_AVERAGE_BITRATE_CONTROL     0x8387U
+#define VIDEO_GET_MAX_EU_CPB_SIZE_CONTROL            0x8388U
+#define VIDEO_GET_MAX_EU_PEAK_BIT_RATE_CONTROL       0x8389U
+#define VIDEO_GET_MAX_EU_QUANTIZATION_PARAMS_CONTROL 0x838AU
+#define VIDEO_GET_MAX_EU_SYNC_REF_FRAME_CONTROL      0x838BU
+#define VIDEO_GET_MAX_EU_LTR_BUFFER_CONTROL          0x838CU
+#define VIDEO_GET_MAX_EU_LEVEL_IDC_LIMIT_CONTROL     0x838FU
+#define VIDEO_GET_MAX_EU_SEI_PAYLOADTYPE_CONTROL     0x8390U
+#define VIDEO_GET_MAX_EU_QP_RANGE_CONTROL            0x8391U
+#endif
+
+/*! @brief Video device class-specific request GET RES COMMAND */
+#define VIDEO_GET_RES_PU_BACKLIGHT_COMPENSATION_CONTROL    0x8421U
+#define VIDEO_GET_RES_PU_BRIGHTNESS_CONTROL                0x8422U
+#define VIDEO_GET_RES_PU_CONTRACT_CONTROL                  0x8423U
+#define VIDEO_GET_RES_PU_GAIN_CONTROL                      0x8424U
+#define VIDEO_GET_RES_PU_HUE_CONTROL                       0x8426U
+#define VIDEO_GET_RES_PU_SATURATION_CONTROL                0x8427U
+#define VIDEO_GET_RES_PU_SHARRNESS_CONTROL                 0x8428U
+#define VIDEO_GET_RES_PU_GAMMA_CONTROL                     0x8429U
+#define VIDEO_GET_RES_PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x842AU
+#define VIDEO_GET_RES_PU_WHITE_BALANCE_COMPONENT_CONTROL   0x842CU
+#define VIDEO_GET_RES_PU_DIGITAL_MULTIPLIER_CONTROL        0x842EU
+#define VIDEO_GET_RES_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL  0x842FU
+
+#define VIDEO_GET_RES_CT_AE_MODE_CONTROL                0x8442U
+#define VIDEO_GET_RES_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x8444U
+#define VIDEO_GET_RES_CT_FOCUS_ABSOLUTE_CONTROL         0x8446U
+#define VIDEO_GET_RES_CT_FOCUS_RELATIVE_CONTROL         0x8447U
+#define VIDEO_GET_RES_CT_IRIS_ABSOLUTE_CONTROL          0x8449U
+#define VIDEO_GET_RES_CT_ZOOM_ABSOLUTE_CONTROL          0x844BU
+#define VIDEO_GET_RES_CT_ZOOM_RELATIVE_CONTROL          0x844CU
+#define VIDEO_GET_RES_CT_PANTILT_ABSOLUTE_CONTROL       0x844DU
+#define VIDEO_GET_RES_CT_PANTILT_RELATIVE_CONTROL       0x844EU
+#define VIDEO_GET_RES_CT_ROLL_ABSOLUTE_CONTROL          0x844FU
+#define VIDEO_GET_RES_CT_ROLL_RELATIVE_CONTROL          0x8450U
+
+#define VIDEO_GET_RES_VS_PROBE_CONTROL                0x8461U
+#define VIDEO_GET_RES_VS_STILL_PROBE_CONTROL          0x8463U
+#define VIDEO_GET_RES_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x8468U
+#define VIDEO_GET_RES_VS_SYNCH_DELAY_CONTROL          0x8469U
+
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_RES_EU_AVERAGE_BITRATE_CONTROL     0x8487U
+#define VIDEO_GET_RES_EU_CPB_SIZE_CONTROL            0x8488U
+#define VIDEO_GET_RES_EU_PEAK_BIT_RATE_CONTROL       0x8489U
+#define VIDEO_GET_RES_EU_QUANTIZATION_PARAMS_CONTROL 0x848AU
+#define VIDEO_GET_RES_EU_ERROR_RESILIENCY_CONTROL    0x8494U
+#endif
+
+/*! @brief Video device class-specific request GET LEN COMMAND */
+
+#define VIDEO_GET_LEN_VS_PROBE_CONTROL        0x8561U
+#define VIDEO_GET_LEN_VS_COMMIT_CONTROL       0x8562U
+#define VIDEO_GET_LEN_VS_STILL_PROBE_CONTROL  0x8563U
+#define VIDEO_GET_LEN_VS_STILL_COMMIT_CONTROL 0x8564U
+
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_LEN_EU_SELECT_LAYER_CONTROL        0x8581U
+#define VIDEO_GET_LEN_EU_PROFILE_TOOLSET_CONTROL     0x8582U
+#define VIDEO_GET_LEN_EU_VIDEO_RESOLUTION_CONTROL    0x8583U
+#define VIDEO_GET_LEN_EU_MIN_FRAME_INTERVAL_CONTROL  0x8584U
+#define VIDEO_GET_LEN_EU_SLICE_MODE_CONTROL          0x8585U
+#define VIDEO_GET_LEN_EU_RATE_CONTROL_MODE_CONTROL   0x8586U
+#define VIDEO_GET_LEN_EU_AVERAGE_BITRATE_CONTROL     0x8587U
+#define VIDEO_GET_LEN_EU_CPB_SIZE_CONTROL            0x8588U
+#define VIDEO_GET_LEN_EU_PEAK_BIT_RATE_CONTROL       0x8589U
+#define VIDEO_GET_LEN_EU_QUANTIZATION_PARAMS_CONTROL 0x858AU
+#define VIDEO_GET_LEN_EU_SYNC_REF_FRAME_CONTROL      0x858BU
+#define VIDEO_GET_LEN_EU_LTR_BUFFER_CONTROL          0x858CU
+#define VIDEO_GET_LEN_EU_LTR_PICTURE_CONTROL         0x858DU
+#define VIDEO_GET_LEN_EU_LTR_VALIDATION_CONTROL      0x858EU
+#define VIDEO_GET_LEN_EU_QP_RANGE_CONTROL            0x8591U
+#define VIDEO_GET_LEN_EU_PRIORITY_CONTROL            0x8592U
+#define VIDEO_GET_LEN_EU_START_OR_STOP_LAYER_CONTROL 0x8593U
+#endif
+
+/*! @brief Video device class-specific request GET INFO COMMAND */
+#define VIDEO_GET_INFO_VC_POWER_MODE_CONTROL 0x8601U
+#define VIDEO_GET_INFO_VC_ERROR_CODE_CONTROL 0x8602U
+
+#define VIDEO_GET_INFO_PU_BACKLIGHT_COMPENSATION_CONTROL         0x8621U
+#define VIDEO_GET_INFO_PU_BRIGHTNESS_CONTROL                     0x8622U
+#define VIDEO_GET_INFO_PU_CONTRACT_CONTROL                       0x8623U
+#define VIDEO_GET_INFO_PU_GAIN_CONTROL                           0x8624U
+#define VIDEO_GET_INFO_PU_POWER_LINE_FREQUENCY_CONTROL           0x8625U
+#define VIDEO_GET_INFO_PU_HUE_CONTROL                            0x8626U
+#define VIDEO_GET_INFO_PU_SATURATION_CONTROL                     0x8627U
+#define VIDEO_GET_INFO_PU_SHARRNESS_CONTROL                      0x8628U
+#define VIDEO_GET_INFO_PU_GAMMA_CONTROL                          0x8629U
+#define VIDEO_GET_INFO_PU_WHITE_BALANCE_TEMPERATURE_CONTROL      0x862AU
+#define VIDEO_GET_INFO_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x862BU
+#define VIDEO_GET_INFO_PU_WHITE_BALANCE_COMPONENT_CONTROL        0x862CU
+#define VIDEO_GET_INFO_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL   0x862DU
+#define VIDEO_GET_INFO_PU_DIGITAL_MULTIPLIER_CONTROL             0x862EU
+#define VIDEO_GET_INFO_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL       0x862FU
+#define VIDEO_GET_INFO_PU_HUE_AUTO_CONTROL                       0x8630U
+#define VIDEO_GET_INFO_PU_ANALOG_VIDEO_STANDARD_CONTROL          0x8631U
+#define VIDEO_GET_INFO_PU_ANALOG_LOCK_STATUS_CONTROL             0x8632U
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_INFO_PU_CONTRAST_AUTO_CONTROL 0x8633U
+#endif
+
+#define VIDEO_GET_INFO_CT_SCANNING_MODE_CONTROL          0x8641U
+#define VIDEO_GET_INFO_CT_AE_MODE_CONTROL                0x8642U
+#define VIDEO_GET_INFO_CT_AE_PRIORITY_CONTROL            0x8643U
+#define VIDEO_GET_INFO_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x8644U
+#define VIDEO_GET_INFO_CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x8645U
+#define VIDEO_GET_INFO_CT_FOCUS_ABSOLUTE_CONTROL         0x8646U
+#define VIDEO_GET_INFO_CT_FOCUS_RELATIVE_CONTROL         0x8647U
+#define VIDEO_GET_INFO_CT_FOCUS_AUTO_CONTROL             0x8648U
+#define VIDEO_GET_INFO_CT_IRIS_ABSOLUTE_CONTROL          0x8649U
+#define VIDEO_GET_INFO_CT_IRIS_RELATIVE_CONTROL          0x864AU
+#define VIDEO_GET_INFO_CT_ZOOM_ABSOLUTE_CONTROL          0x864BU
+#define VIDEO_GET_INFO_CT_ZOOM_RELATIVE_CONTROL          0x864CU
+#define VIDEO_GET_INFO_CT_PANTILT_ABSOLUTE_CONTROL       0x864DU
+#define VIDEO_GET_INFO_CT_PANTILT_RELATIVE_CONTROL       0x864EU
+#define VIDEO_GET_INFO_CT_ROLL_ABSOLUTE_CONTROL          0x864FU
+#define VIDEO_GET_INFO_CT_ROLL_RELATIVE_CONTROL          0x8650U
+#define VIDEO_GET_INFO_CT_PRIVACY_CONTROL                0x8651U
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_INFO_CT_FOCUS_SIMPLE_CONTROL 0x8652U
+#endif
+
+#define VIDEO_GET_INFO_VS_PROBE_CONTROL                0x8661U
+#define VIDEO_GET_INFO_VS_COMMIT_CONTROL               0x8662U
+#define VIDEO_GET_INFO_VS_STILL_PROBE_CONTROL          0x8663U
+#define VIDEO_GET_INFO_VS_STILL_COMMIT_CONTROL         0x8664U
+#define VIDEO_GET_INFO_VS_STILL_IMAGE_TRIGGER_CONTROL  0x8665U
+#define VIDEO_GET_INFO_VS_STREAM_ERROR_CODE_CONTROL    0x8666U
+#define VIDEO_GET_INFO_VS_GENERATE_KEY_FRAME_CONTROL   0x8667U
+#define VIDEO_GET_INFO_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x8668U
+#define VIDEO_GET_INFO_VS_SYNCH_DELAY_CONTROL          0x8669U
+
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_INFO_EU_SELECT_LAYER_CONTROL        0x8681U
+#define VIDEO_GET_INFO_EU_PROFILE_TOOLSET_CONTROL     0x8682U
+#define VIDEO_GET_INFO_EU_VIDEO_RESOLUTION_CONTROL    0x8683U
+#define VIDEO_GET_INFO_EU_MIN_FRAME_INTERVAL_CONTROL  0x8684U
+#define VIDEO_GET_INFO_EU_SLICE_MODE_CONTROL          0x8685U
+#define VIDEO_GET_INFO_EU_RATE_CONTROL_MODE_CONTROL   0x8686U
+#define VIDEO_GET_INFO_EU_AVERAGE_BITRATE_CONTROL     0x8687U
+#define VIDEO_GET_INFO_EU_CPB_SIZE_CONTROL            0x8688U
+#define VIDEO_GET_INFO_EU_PEAK_BIT_RATE_CONTROL       0x8689U
+#define VIDEO_GET_INFO_EU_QUANTIZATION_PARAMS_CONTROL 0x868AU
+#define VIDEO_GET_INFO_EU_SYNC_REF_FRAME_CONTROL      0x868BU
+#define VIDEO_GET_INFO_EU_LTR_BUFFER_CONTROL          0x868CU
+#define VIDEO_GET_INFO_EU_LTR_PICTURE_CONTROL         0x868DU
+#define VIDEO_GET_INFO_EU_LTR_VALIDATION_CONTROL      0x868EU
+#define VIDEO_GET_INFO_EU_SEI_PAYLOADTYPE_CONTROL     0x8690U
+#define VIDEO_GET_INFO_EU_QP_RANGE_CONTROL            0x8691U
+#define VIDEO_GET_INFO_EU_PRIORITY_CONTROL            0x8692U
+#define VIDEO_GET_INFO_EU_START_OR_STOP_LAYER_CONTROL 0x8693U
+#endif
+
+/*! @brief Video device class-specific request GET DEF COMMAND */
+#define VIDEO_GET_DEF_PU_BACKLIGHT_COMPENSATION_CONTROL         0x8721U
+#define VIDEO_GET_DEF_PU_BRIGHTNESS_CONTROL                     0x8722U
+#define VIDEO_GET_DEF_PU_CONTRACT_CONTROL                       0x8723U
+#define VIDEO_GET_DEF_PU_GAIN_CONTROL                           0x8724U
+#define VIDEO_GET_DEF_PU_POWER_LINE_FREQUENCY_CONTROL           0x8725U
+#define VIDEO_GET_DEF_PU_HUE_CONTROL                            0x8726U
+#define VIDEO_GET_DEF_PU_SATURATION_CONTROL                     0x8727U
+#define VIDEO_GET_DEF_PU_SHARRNESS_CONTROL                      0x8728U
+#define VIDEO_GET_DEF_PU_GAMMA_CONTROL                          0x8729U
+#define VIDEO_GET_DEF_PU_WHITE_BALANCE_TEMPERATURE_CONTROL      0x872AU
+#define VIDEO_GET_DEF_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x872BU
+#define VIDEO_GET_DEF_PU_WHITE_BALANCE_COMPONENT_CONTROL        0x872CU
+#define VIDEO_GET_DEF_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL   0x872DU
+#define VIDEO_GET_DEF_PU_DIGITAL_MULTIPLIER_CONTROL             0x872EU
+#define VIDEO_GET_DEF_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL       0x872FU
+#define VIDEO_GET_DEF_PU_HUE_AUTO_CONTROL                       0x8730U
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_DEF_PU_CONTRAST_AUTO_CONTROL 0x8731U
+#endif
+
+#define VIDEO_GET_DEF_CT_AE_MODE_CONTROL                0x8742U
+#define VIDEO_GET_DEF_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x8744U
+#define VIDEO_GET_DEF_CT_FOCUS_ABSOLUTE_CONTROL         0x8746U
+#define VIDEO_GET_DEF_CT_FOCUS_RELATIVE_CONTROL         0x8747U
+#define VIDEO_GET_DEF_CT_FOCUS_AUTO_CONTROL             0x8748U
+#define VIDEO_GET_DEF_CT_IRIS_ABSOLUTE_CONTROL          0x8749U
+#define VIDEO_GET_DEF_CT_ZOOM_ABSOLUTE_CONTROL          0x874BU
+#define VIDEO_GET_DEF_CT_ZOOM_RELATIVE_CONTROL          0x874CU
+#define VIDEO_GET_DEF_CT_PANTILT_ABSOLUTE_CONTROL       0x874DU
+#define VIDEO_GET_DEF_CT_PANTILT_RELATIVE_CONTROL       0x874EU
+#define VIDEO_GET_DEF_CT_ROLL_ABSOLUTE_CONTROL          0x874FU
+#define VIDEO_GET_DEF_CT_ROLL_RELATIVE_CONTROL          0x8750U
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_DEF_CT_FOCUS_SIMPLE_CONTROL       0x8751U
+#define VIDEO_GET_DEF_CT_DIGITAL_WINDOW_CONTROL     0x8752U
+#define VIDEO_GET_DEF_CT_REGION_OF_INTEREST_CONTROL 0x8753U
+#endif
+
+#define VIDEO_GET_DEF_VS_PROBE_CONTROL                0x8761U
+#define VIDEO_GET_DEF_VS_STILL_PROBE_CONTROL          0x8763U
+#define VIDEO_GET_DEF_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x8768U
+#define VIDEO_GET_DEF_VS_SYNCH_DELAY_CONTROL          0x8769U
+
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_GET_DEF_EU_PROFILE_TOOLSET_CONTROL     0x8782U
+#define VIDEO_GET_DEF_EU_VIDEO_RESOLUTION_CONTROL    0x8783U
+#define VIDEO_GET_DEF_EU_MIN_FRAME_INTERVAL_CONTROL  0x8784U
+#define VIDEO_GET_DEF_EU_SLICE_MODE_CONTROL          0x8785U
+#define VIDEO_GET_DEF_EU_RATE_CONTROL_MODE_CONTROL   0x8786U
+#define VIDEO_GET_DEF_EU_AVERAGE_BITRATE_CONTROL     0x8787U
+#define VIDEO_GET_DEF_EU_CPB_SIZE_CONTROL            0x8788U
+#define VIDEO_GET_DEF_EU_PEAK_BIT_RATE_CONTROL       0x8789U
+#define VIDEO_GET_DEF_EU_QUANTIZATION_PARAMS_CONTROL 0x878AU
+#define VIDEO_GET_DEF_EU_LTR_BUFFER_CONTROL          0x878CU
+#define VIDEO_GET_DEF_EU_LTR_PICTURE_CONTROL         0x878DU
+#define VIDEO_GET_DEF_EU_LTR_VALIDATION_CONTROL      0x878EU
+#define VIDEO_GET_DEF_EU_LEVEL_IDC_LIMIT_CONTROL     0x878FU
+#define VIDEO_GET_DEF_EU_SEI_PAYLOADTYPE_CONTROL     0x8790U
+#define VIDEO_GET_DEF_EU_QP_RANGE_CONTROL            0x8791U
+#define VIDEO_GET_DEF_EU_ERROR_RESILIENCY_CONTROL    0x8794U
+#endif
+
+/*! @brief Video device class-specific request SET CUR COMMAND */
+#define VIDEO_SET_CUR_VC_POWER_MODE_CONTROL 0x0101U
+
+#define VIDEO_SET_CUR_PU_BACKLIGHT_COMPENSATION_CONTROL         0x0121U
+#define VIDEO_SET_CUR_PU_BRIGHTNESS_CONTROL                     0x0122U
+#define VIDEO_SET_CUR_PU_CONTRACT_CONTROL                       0x0123U
+#define VIDEO_SET_CUR_PU_GAIN_CONTROL                           0x0124U
+#define VIDEO_SET_CUR_PU_POWER_LINE_FREQUENCY_CONTROL           0x0125U
+#define VIDEO_SET_CUR_PU_HUE_CONTROL                            0x0126U
+#define VIDEO_SET_CUR_PU_SATURATION_CONTROL                     0x0127U
+#define VIDEO_SET_CUR_PU_SHARRNESS_CONTROL                      0x0128U
+#define VIDEO_SET_CUR_PU_GAMMA_CONTROL                          0x0129U
+#define VIDEO_SET_CUR_PU_WHITE_BALANCE_TEMPERATURE_CONTROL      0x012AU
+#define VIDEO_SET_CUR_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x012BU
+#define VIDEO_SET_CUR_PU_WHITE_BALANCE_COMPONENT_CONTROL        0x012CU
+#define VIDEO_SET_CUR_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL   0x012DU
+#define VIDEO_SET_CUR_PU_DIGITAL_MULTIPLIER_CONTROL             0x012EU
+#define VIDEO_SET_CUR_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL       0x012FU
+#define VIDEO_SET_CUR_PU_HUE_AUTO_CONTROL                       0x0130U
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_SET_CUR_PU_CONTRAST_AUTO_CONTROL 0x0131U
+#endif
+
+#define VIDEO_SET_CUR_CT_SCANNING_MODE_CONTROL          0x0141U
+#define VIDEO_SET_CUR_CT_AE_MODE_CONTROL                0x0142U
+#define VIDEO_SET_CUR_CT_AE_PRIORITY_CONTROL            0x0143U
+#define VIDEO_SET_CUR_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x0144U
+#define VIDEO_SET_CUR_CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x0145U
+#define VIDEO_SET_CUR_CT_FOCUS_ABSOLUTE_CONTROL         0x0146U
+#define VIDEO_SET_CUR_CT_FOCUS_RELATIVE_CONTROL         0x0147U
+#define VIDEO_SET_CUR_CT_FOCUS_AUTO_CONTROL             0x0148U
+#define VIDEO_SET_CUR_CT_IRIS_ABSOLUTE_CONTROL          0x0149U
+#define VIDEO_SET_CUR_CT_IRIS_RELATIVE_CONTROL          0x014AU
+#define VIDEO_SET_CUR_CT_ZOOM_ABSOLUTE_CONTROL          0x014BU
+#define VIDEO_SET_CUR_CT_ZOOM_RELATIVE_CONTROL          0x014CU
+#define VIDEO_SET_CUR_CT_PANTILT_ABSOLUTE_CONTROL       0x014DU
+#define VIDEO_SET_CUR_CT_PANTILT_RELATIVE_CONTROL       0x014EU
+#define VIDEO_SET_CUR_CT_ROLL_ABSOLUTE_CONTROL          0x014FU
+#define VIDEO_SET_CUR_CT_ROLL_RELATIVE_CONTROL          0x0150U
+#define VIDEO_SET_CUR_CT_PRIVACY_CONTROL                0x0151U
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_SET_CUR_CT_FOCUS_SIMPLE_CONTROL       0x0152U
+#define VIDEO_SET_CUR_CT_DIGITAL_WINDOW_CONTROL     0x0153U
+#define VIDEO_SET_CUR_CT_REGION_OF_INTEREST_CONTROL 0x0154U
+#endif
+
+#define VIDEO_SET_CUR_VS_PROBE_CONTROL                0x0161U
+#define VIDEO_SET_CUR_VS_COMMIT_CONTROL               0x0162U
+#define VIDEO_SET_CUR_VS_STILL_PROBE_CONTROL          0x0163U
+#define VIDEO_SET_CUR_VS_STILL_COMMIT_CONTROL         0x0164U
+#define VIDEO_SET_CUR_VS_STILL_IMAGE_TRIGGER_CONTROL  0x0165U
+#define VIDEO_SET_CUR_VS_STREAM_ERROR_CODE_CONTROL    0x0166U
+#define VIDEO_SET_CUR_VS_GENERATE_KEY_FRAME_CONTROL   0x0167U
+#define VIDEO_SET_CUR_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x0168U
+#define VIDEO_SET_CUR_VS_SYNCH_DELAY_CONTROL          0x0169U
+
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+#define VIDEO_SET_CUR_EU_SELECT_LAYER_CONTROL        0x0181U
+#define VIDEO_SET_CUR_EU_PROFILE_TOOLSET_CONTROL     0x0182U
+#define VIDEO_SET_CUR_EU_VIDEO_RESOLUTION_CONTROL    0x0183U
+#define VIDEO_SET_CUR_EU_MIN_FRAME_INTERVAL_CONTROL  0x0184U
+#define VIDEO_SET_CUR_EU_SLICE_MODE_CONTROL          0x0185U
+#define VIDEO_SET_CUR_EU_RATE_CONTROL_MODE_CONTROL   0x0186U
+#define VIDEO_SET_CUR_EU_AVERAGE_BITRATE_CONTROL     0x0187U
+#define VIDEO_SET_CUR_EU_CPB_SIZE_CONTROL            0x0188U
+#define VIDEO_SET_CUR_EU_PEAK_BIT_RATE_CONTROL       0x0189U
+#define VIDEO_SET_CUR_EU_QUANTIZATION_PARAMS_CONTROL 0x018AU
+#define VIDEO_SET_CUR_EU_SYNC_REF_FRAME_CONTROL      0x018BU
+#define VIDEO_SET_CUR_EU_LTR_BUFFER_CONTROL          0x018CU
+#define VIDEO_SET_CUR_EU_LTR_PICTURE_CONTROL         0x018DU
+#define VIDEO_SET_CUR_EU_LTR_VALIDATION_CONTROL      0x018EU
+#define VIDEO_SET_CUR_EU_LEVEL_IDC_LIMIT_CONTROL     0x018FU
+#define VIDEO_SET_CUR_EU_SEI_PAYLOADTYPE_CONTROL     0x0190U
+#define VIDEO_SET_CUR_EU_QP_RANGE_CONTROL            0x0191U
+#define VIDEO_SET_CUR_EU_PRIORITY_CONTROL            0x0192U
+#define VIDEO_SET_CUR_EU_START_OR_STOP_LAYER_CONTROL 0x0193U
+#define VIDEO_SET_CUR_EU_ERROR_RESILIENCY_CONTROL    0x0194U
+#endif
+
+/*! @brief The payload header structure. */
+struct video_payload_header {
+    uint8_t bHeaderLength; /*!< The payload header length. */
+    union {
+        uint8_t bmheaderInfo; /*!< The payload header bitmap field. */
+        struct
+        {
+            uint8_t frameIdentifier : 1U; /*!< Frame Identifier. This bit toggles at each frame start boundary and stays
+                                             constant for the rest of the frame.*/
+            uint8_t endOfFrame      : 1U; /*!< End of Frame. This bit indicates the end of a video frame and is set in the
+                                        last video sample that belongs to a frame.*/
+            uint8_t
+                presentationTimeStamp    : 1U; /*!< Presentation Time Stamp. This bit, when set, indicates the presence of
+                                               a PTS field.*/
+            uint8_t sourceClockReference : 1U; /*!< Source Clock Reference. This bit, when set, indicates the presence
+                                                  of a SCR field.*/
+            uint8_t reserved             : 1U; /*!< Reserved. Set to 0. */
+            uint8_t stillImage           : 1U; /*!< Still Image. This bit, when set, identifies a video sample that belongs to a
+                                         still image.*/
+            uint8_t errorBit             : 1U; /*!< Error Bit. This bit, when set, indicates an error in the device streaming.*/
+            uint8_t endOfHeader          : 1U; /*!< End of Header. This bit, when set, indicates the end of the BFH fields.*/
+        } headerInfoBits;
+        struct
+        {
+            uint8_t FID : 1U; /*!< Frame Identifier. This bit toggles at each frame start boundary and stays constant
+                                 for the rest of the frame.*/
+            uint8_t EOI : 1U; /*!< End of Frame. This bit indicates the end of a video frame and is set in the last
+                                 video sample that belongs to a frame.*/
+            uint8_t PTS : 1U; /*!< Presentation Time Stamp. This bit, when set, indicates the presence of a PTS field.*/
+            uint8_t SCR : 1U; /*!< Source Clock Reference. This bit, when set, indicates the presence of a SCR field.*/
+            uint8_t RES : 1U; /*!< Reserved. Set to 0. */
+            uint8_t STI : 1U; /*!< Still Image. This bit, when set, identifies a video sample that belongs to a still
+                                 image.*/
+            uint8_t ERR : 1U; /*!< Error Bit. This bit, when set, indicates an error in the device streaming.*/
+            uint8_t EOH : 1U; /*!< End of Header. This bit, when set, indicates the end of the BFH fields.*/
+        } headerInfoBitmap;
+    } headerInfoUnion;
+    uint32_t dwPresentationTime;      /*!< Presentation time stamp (PTS) field.*/
+    uint8_t bSourceClockReference[6]; /*!< Source clock reference (SCR) field.*/
+} __PACKED;
+
+/*! @brief The Video probe and commit controls structure.*/
+struct video_probe_and_commit_controls {
+    union {
+        uint8_t bmHint; /*!< Bit-field control indicating to the function what fields shall be kept fixed. */
+        struct
+        {
+            uint8_t dwFrameInterval : 1U; /*!< dwFrameInterval field.*/
+            uint8_t wKeyFrameRate   : 1U; /*!< wKeyFrameRate field.*/
+            uint8_t wPFrameRate     : 1U; /*!< wPFrameRate field.*/
+            uint8_t wCompQuality    : 1U; /*!< wCompQuality field.*/
+            uint8_t wCompWindowSize : 1U; /*!< wCompWindowSize field.*/
+            uint8_t reserved        : 3U; /*!< Reserved field.*/
+        } hintBitmap;
+    } hintUnion;
+    union {
+        uint8_t bmHint; /*!< Bit-field control indicating to the function what fields shall be kept fixed. */
+        struct
+        {
+            uint8_t reserved : 8U; /*!< Reserved field.*/
+        } hintBitmap;
+    } hintUnion1;
+    uint8_t bFormatIndex;              /*!< Video format index from a format descriptor.*/
+    uint8_t bFrameIndex;               /*!< Video frame index from a frame descriptor.*/
+    uint32_t dwFrameInterval;          /*!< Frame interval in 100ns units.*/
+    uint16_t wKeyFrameRate;            /*!< Key frame rate in key-frame per video-frame units.*/
+    uint16_t wPFrameRate;              /*!< PFrame rate in PFrame/key frame units.*/
+    uint16_t wCompQuality;             /*!< Compression quality control in abstract units 0U (lowest) to 10000U (highest).*/
+    uint16_t wCompWindowSize;          /*!< Window size for average bit rate control.*/
+    uint16_t wDelay;                   /*!< Internal video streaming interface latency in ms from video data capture to presentation on
+                        the USB.*/
+    uint32_t dwMaxVideoFrameSize;      /*!< Maximum video frame or codec-specific segment size in bytes.*/
+    uint32_t dwMaxPayloadTransferSize; /*!< Specifies the maximum number of bytes that the device can transmit or
+                                          receive in a single payload transfer.*/
+    uint32_t dwClockFrequency;         /*!< The device clock frequency in Hz for the specified format. This specifies the
+                                  units used for the time information fields in the Video Payload Headers in the data
+                                  stream.*/
+    uint8_t bmFramingInfo;             /*!< Bit-field control supporting the following values: D0 Frame ID, D1 EOF.*/
+    uint8_t bPreferedVersion;          /*!< The preferred payload format version supported by the host or device for the
+                                  specified bFormatIndex value.*/
+    uint8_t bMinVersion;               /*!< The minimum payload format version supported by the device for the specified bFormatIndex
+                            value.*/
+    uint8_t bMaxVersion;               /*!< The maximum payload format version supported by the device for the specified bFormatIndex
+                            value.*/
+#if defined(USB_DEVICE_VIDEO_CLASS_VERSION_1_5) && USB_DEVICE_VIDEO_CLASS_VERSION_1_5
+    uint8_t bUsage; /*!< This bitmap enables features reported by the bmUsages field of the Video Frame Descriptor.*/
+    uint8_t
+        bBitDepthLuma;                  /*!< Represents bit_depth_luma_minus8 + 8U, which must be the same as bit_depth_chroma_minus8 +
+                           8.*/
+    uint8_t bmSettings;                 /*!< A bitmap of flags that is used to discover and control specific features of a temporally
+                           encoded video stream.*/
+    uint8_t bMaxNumberOfRefFramesPlus1; /*!< Host indicates the maximum number of frames stored for use as references.*/
+    uint16_t bmRateControlModes;        /*!< This field contains 4U sub-fields, each of which is a 4U bit number.*/
+    uint64_t bmLayoutPerStream;         /*!< This field contains 4U sub-fields, each of which is a 2U byte number.*/
+#endif
+} __PACKED;
+
+/*! @brief The Video still probe and still commit controls structure.*/
+struct video_still_probe_and_commit_controls {
+    uint8_t bFormatIndex;              /*!< Video format index from a format descriptor.*/
+    uint8_t bFrameIndex;               /*!< Video frame index from a frame descriptor.*/
+    uint8_t bCompressionIndex;         /*!< Compression index from a frame descriptor.*/
+    uint32_t dwMaxVideoFrameSize;      /*!< Maximum still image size in bytes.*/
+    uint32_t dwMaxPayloadTransferSize; /*!< Specifies the maximum number of bytes that the device can transmit or
+                                          receive in a single payload transfer.*/
+} __PACKED;
+
+struct video_cs_if_vc_header_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint16_t bcdVDC;
+    uint16_t wTotalLength;
+    uint32_t dwClockFrequency;
+    uint8_t bInCollection;
+    uint8_t baInterfaceNr[];
+} __PACKED;
+
+#define VIDEO_SIZEOF_VC_HEADER_DESC(n) (11 + n)
+
+struct video_cs_if_vc_input_terminal_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bTerminalID;
+    uint16_t wTerminalType;
+    uint8_t bAssocTerminal;
+    uint8_t iTerminal;
+    uint16_t wObjectiveFocalLenMin;
+    uint16_t wObjectiveFocalLenMax;
+    uint16_t wOcularFocalLength;
+    uint8_t bControlSize;
+    uint8_t bmaControls[];
+} __PACKED;
+
+#define VIDEO_SIZEOF_VC_INPUT_TERMINAL_DESC(n) (15 + n)
+
+struct video_cs_if_vc_processing_unit_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bUnitID;
+    uint8_t bSourceID;
+    uint16_t wMaxMultiplier;
+    uint8_t bControlSize;
+    // uint8_t bmaControls[];
+    uint8_t iProcessing;
+    uint8_t bmVideoStandards;
+} __PACKED;
+
+#define VIDEO_SIZEOF_VC_PROCESSING_UNIT_DESC(n) (10 + n)
+
+struct video_cs_if_vc_output_terminal_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bTerminalID;
+    uint16_t wTerminalType;
+    uint8_t bAssocTerminal;
+    uint8_t bSourceID;
+    uint8_t iTerminal;
+} __PACKED;
+
+#define VIDEO_SIZEOF_VC_OUTPUT_TERMINAL_DESC 9
+
+struct video_cs_ep_vc_ep_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint16_t wMaxTransferSize;
+} __PACKED;
+
+#define VIDEO_SIZEOF_VC_EP_DESC 5
+
+struct video_cs_if_vs_input_header_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bNumFormats;
+    uint16_t wTotalLength;
+    uint8_t bEndpointAddress;
+    uint8_t bmInfo;
+    uint8_t bTerminalLink;
+    uint8_t bStillCaptureMethod;
+    uint8_t bTriggerSupport;
+    uint8_t bTriggerUsage;
+    uint8_t bControlSize;
+    uint8_t bmaControls[];
+} __PACKED;
+
+#define VIDEO_SIZEOF_VS_INPUT_HEADER_DESC(p, n) (13 + p * n)
+
+struct video_cs_if_vs_output_header_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bNumFormats;
+    uint16_t wTotalLength;
+    uint8_t bEndpointAddress;
+    uint8_t bTerminalLink;
+    uint8_t bControlSize;
+    uint8_t bmaControls[];
+} __PACKED;
+
+#define VIDEO_SIZEOF_VS_OUTPUT_TERMINAL_DESC(p, n) (9 + p * n)
+
+struct video_cs_if_vs_format_uncompressed_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bFormatIndex;
+    uint8_t bNumFrameDescriptors;
+    uint8_t guidFormat[16];
+    uint8_t bBitsPerPixel;
+    uint8_t bDefaultFrameIndex;
+    uint8_t bAspectRatioX;
+    uint8_t bAspectRatioY;
+    uint8_t bmInterlaceFlags;
+    uint8_t bCopyProtect;
+} __PACKED;
+
+#define VIDEO_SIZEOF_VS_FORMAT_UNCOMPRESSED_DESC (27)
+
+struct video_cs_if_vs_frame_uncompressed_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bFormatIndex;
+    uint8_t bmCapabilities;
+    uint16_t wWidth;
+    uint16_t wHeight;
+    uint32_t dwMinBitRate;
+    uint32_t dwMaxBitRate;
+    uint32_t dwMaxVideoFrameBufferSize;
+    uint32_t dwDefaultFrameInterval;
+    uint8_t bFrameIntervalType;
+    uint32_t dwFrameInterval;
+} __PACKED;
+
+#define VIDEO_SIZEOF_VS_FRAME_UNCOMPRESSED_DESC 30
+
+struct video_cs_if_vs_format_mjpeg_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bFormatIndex;
+    uint8_t bNumFrameDescriptors;
+    uint8_t bmFlags;
+    uint8_t bDefaultFrameIndex;
+    uint8_t bAspectRatioX;
+    uint8_t bAspectRatioY;
+    uint8_t bmInterlaceFlags;
+    uint8_t bCopyProtect;
+} __PACKED;
+
+#define VIDEO_SIZEOF_VS_FORMAT_MJPEG_DESC 11
+
+struct video_cs_if_vs_frame_mjpeg_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bFormatIndex;
+    uint8_t bmCapabilities;
+    uint16_t wWidth;
+    uint16_t wHeight;
+    uint32_t dwMinBitRate;
+    uint32_t dwMaxBitRate;
+    uint32_t dwMaxVideoFrameBufferSize;
+    uint32_t dwDefaultFrameInterval;
+    uint8_t bFrameIntervalType;
+    uint32_t dwFrameInterval1;
+    uint32_t dwFrameInterval2;
+} __PACKED;
+
+#define VIDEO_SIZEOF_VS_FRAME_MJPEG_DESC(n) (26 + n)
+
+struct video_cs_if_vs_colorformat_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDescriptorSubType;
+    uint8_t bColorPrimaries;
+    uint8_t bXferCharacteristics;
+    uint8_t bMatrixCoefficients;
+} __PACKED;
+
+#define VIDEO_SIZEOF_VS_COLORFORMAT_DESC 6
+
+struct video_vc_input_terminal_bmcontrol_bitmap {
+    uint32_t scanning_mode          : 1;
+    uint32_t auto_exposure_mode     : 1;
+    uint32_t auto_exposure_priority : 1;
+    uint32_t exposure_time_absolute : 1;
+    uint32_t exposure_time_relative : 1;
+    uint32_t focus_absolute         : 1;
+    uint32_t focus_relative         : 1;
+    uint32_t iris_absolute          : 1;
+    uint32_t iris_relative          : 1;
+    uint32_t zoom_absolute          : 1;
+    uint32_t zoom_relative          : 1;
+    uint32_t pantilt_absolute       : 1;
+    uint32_t pantilt_relative       : 1;
+    uint32_t roll_absolute          : 1;
+    uint32_t roll_relative          : 1;
+    uint32_t reserved               : 2;
+    uint32_t focus_auto             : 1;
+    uint32_t pricvcy                : 1;
+};
+
+struct video_vc_processing_unit_bmcontrol_bitmap {
+    uint16_t brightness          : 1;
+    uint16_t contrast            : 1;
+    uint16_t hue                 : 1;
+    uint16_t saturation          : 1;
+    uint16_t sharpness           : 1;
+    uint16_t gamma               : 1;
+    uint16_t white_bal_temp      : 1;
+    uint16_t white_bal_comp      : 1;
+    uint16_t backlight_comp      : 1;
+    uint16_t gain                : 1;
+    uint16_t power_line_freq     : 1;
+    uint16_t hue_auto            : 1;
+    uint16_t white_bal_temp_auto : 1;
+    uint16_t white_bal_comp_auto : 1;
+    uint16_t digital_mult        : 1;
+    uint16_t digital_mult_limit  : 1;
+};
+
+struct video_camera_capabilities {
+    uint8_t support_get_request        : 1;
+    uint8_t support_set_request        : 1;
+    uint8_t disabled_by_automatic_mode : 1;
+    uint8_t auto_update_control        : 1;
+    uint8_t async_control              : 1;
+    uint8_t reserved                   : 3;
+};
+
+struct video_autoexposure_mode {
+    uint8_t manual_mode            : 1;
+    uint8_t auto_mode              : 1;
+    uint8_t shutter_priority_mode  : 1;
+    uint8_t aperture_priority_mode : 1;
+    uint8_t reserved               : 4;
+};
+
+#define VIDEO_GUID_YUY2 0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71
+#define VIDEO_GUID_NV12 0x4E, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71
+#define VIDEO_GUID_M420 0x4D, 0x34, 0x32, 0x30, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71
+#define VIDEO_GUID_I420 0x49, 0x34, 0x32, 0x30, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71
+
+// clang-format off
+#define VIDEO_VC_DESCRIPTOR_INIT(bFirstInterface, bNumEndpoints, bcdUVC, wTotalLength, dwClockFrequency, stridx)                                                                   \
+    /* Interface Association Descriptor */                                                                                                                                         \
+    0x08,                                                                                                                                                                          \
+    USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION,                                                                                                                                     \
+    bFirstInterface,                                                                                                                                                               \
+    0x02,                                                                                                                                                                          \
+    USB_DEVICE_CLASS_VIDEO,                                                                                                                                                        \
+    VIDEO_SC_VIDEO_INTERFACE_COLLECTION,                                                                                                                                           \
+    0x00,                                                                                                                                                                          \
+    0x00,                                                                                                                                                                          \
+    /* VideoControl Interface Descriptor */                                                                                                                                        \
+    0x09,                                                                                            /* bLength */                                                                 \
+    USB_DESCRIPTOR_TYPE_INTERFACE,                                                                   /* bDescriptorType */                                                         \
+    0x00,                                                                                            /* bInterfaceNumber */                                                        \
+    0x00,                                                                                            /* bAlternateSetting */                                                       \
+    bNumEndpoints,                                                                                   /* bNumEndpoints:1 endpoint (interrupt endpoint) */                           \
+    USB_DEVICE_CLASS_VIDEO,                                                                          /* bInterfaceClass : CC_VIDEO */                                              \
+    VIDEO_SC_VIDEOCONTROL,                                                                           /* bInterfaceSubClass : SC_VIDEOCONTROL */                                    \
+    VIDEO_PC_PROTOCOL_UNDEFINED,                                                                     /* bInterfaceProtocol : PC_PROTOCOL_UNDEFINED */                              \
+    stridx,                                                                                          /* iInterface:Index to string descriptor that contains the string <Your Product Name> */ \
+    /*Class-specific VideoControl Interface Descriptor */                         \
+    0x0d,                                                                                            /* bLength */                                                                 \
+    0x24,                                                                                            /* bDescriptorType : CS_INTERFACE */                                          \
+    VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE,                                                              /* bDescriptorSubType : VC_HEADER subtype */                                  \
+    WBVAL(bcdUVC),                                                                                   /* bcdUVC : Revision of class specification that this device is based upon.*/ \
+    WBVAL(wTotalLength),                                                                             /* wTotalLength  */                                                           \
+    DBVAL(dwClockFrequency),                                                                         /* dwClockFrequency : 0x005b8d80 -> 6,000,000 == 6MHz*/                       \
+    0x01,                                                                                            /* bInCollection : Number of streaming interfaces. */                         \
+    (uint8_t)(bFirstInterface + 1),                                                                  /* baInterfaceNr(0) : VideoStreaming interface 1 belongs to this VideoControl interface.*/ \
+    /* Input Terminal 1 -> Processing Unit 2 -> Output Terminal 3 */              \
+    0x12,                                                                                                                                                                          \
+    0x24,                                                                                                                                                                          \
+    VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE,                                                                                                                                    \
+    0x01,                    /* bTerminalID */                                                                                                                                     \
+    WBVAL(VIDEO_ITT_CAMERA), /* wTerminalType : 0x0201 Camera Sensor*/                                                                                                             \
+    0x00,                    /* bAssocTerminal */                                                                                                                                  \
+    0x00,                    /* iTerminal */                                                                                                                                       \
+    WBVAL(0x0000),           /* wObjectiveFocalLengthMin */                                                                                                                        \
+    WBVAL(0x0000),           /* wObjectiveFocalLengthMax */                                                                                                                        \
+    WBVAL(0x0000),           /* wOcularFocalLength */                                                                                                                              \
+    0x03,                    /* bControlSize */                                                                                                                                    \
+    0x00, 0x00, 0x00,        /* bmControls */                                                                                                                                      \
+    0x0c,                                                                                                                                                                          \
+    0x24,                                                                                                                                                                          \
+    VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE,                                                                                                                                   \
+    0x02,       /* bUnitID  */                                                                                                                                                     \
+    0x01,       /* bSourceID */                                                                                                                                                    \
+    0x00, 0x00, /* wMaxMultiplier  */                                                                                                                                              \
+    0x02,       /* bControlSize   */                                                                                                                                               \
+    0x00, 0x00, /* bmControls */                                                                                                                                                   \
+    0x00,       /* iProcessing */                                                                                                                                                  \
+    0x00,       /* bmVideoStandards */                                                                                                                                             \
+    0x09,                                                                                                                                                                          \
+    0x24,                                                                                                                                                                          \
+    VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE,                                                                                                                                   \
+    0x03, /* bTerminalID */                                                                                                                                                        \
+    WBVAL(VIDEO_TT_STREAMING),                                                                                                                                                     \
+    0x00, /* bAssocTerminal   */                                                                                                                                                   \
+    0x02, /* bSourceID   */                                                                                                                                                        \
+    0x00  /* iTerminal   */
+
+#define VIDEO_VS_DESCRIPTOR_INIT(bInterfaceNumber, bAlternateSetting, bNumEndpoints)        \
+    /* Video Streaming (VS) Interface Descriptor */                                         \
+    0x09,                          /* bLength */                                            \
+    USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType : INTERFACE */                        \
+    bInterfaceNumber,              /* bInterfaceNumber: Index of this interface */          \
+    bAlternateSetting,             /* bAlternateSetting: Index of this alternate setting */ \
+    bNumEndpoints,                 /* bNumEndpoints : 0 endpoints – no bandwidth used*/     \
+    0x0e,                          /* bInterfaceClass : CC_VIDEO */                         \
+    0x02,                          /* bInterfaceSubClass : SC_VIDEOSTREAMING */             \
+    0x00,                          /* bInterfaceProtocol : PC_PROTOCOL_UNDEFINED */         \
+    0x00                           /* iInterface : unused */
+
+#define VIDEO_VS_HEADER_DESCRIPTOR_INIT(bNumFormats, wTotalLength, bEndpointAddress, ...)               \
+    /*Class-specific VideoStream Header Descriptor (Input) */                                           \
+    0x0d + PP_NARG(__VA_ARGS__),                                                                        \
+    0x24,                                                                                               \
+    VIDEO_VS_INPUT_HEADER_DESCRIPTOR_SUBTYPE,                                                           \
+    bNumFormats, /* bNumFormats : One format descriptor follows. */                                     \
+    WBVAL(wTotalLength),                                                                                \
+    bEndpointAddress,                                                                                   \
+    0x00, /* bmInfo : No dynamic format change supported. */                                            \
+    0x03, /* bTerminalLink : This VideoStreaming interface supplies terminal ID 2 (Output Terminal). */ \
+    0x00, /* bStillCaptureMethod : Device supports still image capture method 0. */                     \
+    0x00, /* bTriggerSupport : Hardware trigger supported for still image capture */                    \
+    0x00, /* bTriggerUsage : Hardware trigger should initiate a still image capture. */                 \
+    PP_NARG(__VA_ARGS__), /* bControlSize : Size of the bmaControls field */                            \
+    __VA_ARGS__  /* bmaControls : No VideoStreaming specific controls are supported.*/
+
+#define VIDEO_VS_FORMAT_UNCOMPRESSED_DESCRIPTOR_INIT(bFormatIndex, bNumFrameDescriptors, GUIDFormat)                                                              \
+    /*Payload Format(UNCOMPRESSED) Descriptor */                                                                                                                  \
+    0x1b,                                                                                                                                                         \
+    0x24,                                                                                                                                                         \
+    VIDEO_VS_FORMAT_UNCOMPRESSED_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VS_FORMAT_UNCOMPRESSED subtype */                                                    \
+    bFormatIndex,                                    /* bFormatIndex : First (and only) format descriptor */                                                      \
+    bNumFrameDescriptors,                            /* bNumFrameDescriptors : One frame descriptor for this format follows. */                                   \
+    GUIDFormat,                                      /* GUID Format YUY2 {32595559-0000-0010-8000-00AA00389B71} */                                                \
+    0x0c,                                            /* bBitsPerPixel : Number of bits per pixel used to specify color in the decoded video frame - 16 for yuy2*/ \
+    0x01,                                            /* bDefaultFrameIndex : Default frame index is 1. */                                                         \
+    0x00,                                            /* bAspectRatioX : Non-interlaced stream not required. */                                                    \
+    0x00,                                            /* bAspectRatioY : Non-interlaced stream not required. */                                                    \
+    0x00,                                            /* bmInterlaceFlags : Non-interlaced stream */                                                               \
+    0x00                                             /* bCopyProtect : No restrictions imposed on the duplication of this video stream. */
+
+#define VIDEO_VS_FRAME_UNCOMPRESSED_DESCRIPTOR_INIT(bFrameIndex, wWidth, wHeight, dwMinBitRate, dwMaxBitRate,           \
+                                                    dwMaxVideoFrameBufferSize, dwDefaultFrameInterval, dwFrameInterval) \
+    0x1e,                                                                                                               \
+    0x24,                                                                                                           \
+    VIDEO_VS_FRAME_UNCOMPRESSED_DESCRIPTOR_SUBTYPE,                                                                 \
+    bFrameIndex,                                                                                                    \
+    0x00,                                                                                                           \
+    WBVAL(wWidth),                                                                                                  \
+    WBVAL(wHeight),                                                                                                 \
+    DBVAL(dwMinBitRate),                                                                                            \
+    DBVAL(dwMaxBitRate),                                                                                            \
+    DBVAL(dwMaxVideoFrameBufferSize),                                                                               \
+    DBVAL(dwDefaultFrameInterval),                                                                                  \
+    0x01,                                                                                                           \
+    DBVAL(dwFrameInterval)
+
+#define VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(bFormatIndex, bNumFrameDescriptors)                    \
+    /*Payload Format(MJPEG) Descriptor */                                                            \
+    0x0b,                 /* bLength */                                                              \
+    0x24,                 /* bDescriptorType : CS_INTERFACE */                                       \
+    0x06,                 /* bDescriptorSubType : VS_FORMAT_MJPEG subtype */                         \
+    bFormatIndex,         /* bFormatIndex : First (and only) format descriptor */                    \
+    bNumFrameDescriptors, /* bNumFrameDescriptors : One frame descriptor for this format follows. */ \
+    0x00,                 /* bmFlags : Uses fixed size samples.. */                                  \
+    0x01,                 /* bDefaultFrameIndex : Default frame index is 1. */                       \
+    0x00,                 /* bAspectRatioX : Non-interlaced stream – not required. */                \
+    0x00,                 /* bAspectRatioY : Non-interlaced stream – not required. */                \
+    0x00,                 /* bmInterlaceFlags : Non-interlaced stream */                             \
+    0x00                  /* bCopyProtect : No restrictions imposed on the duplication of this video stream. */
+
+#define VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(bFrameIndex, wWidth, wHeight, dwMinBitRate, dwMaxBitRate,                                                                                          \
+                                             dwMaxVideoFrameBufferSize, dwDefaultFrameInterval, bFrameIntervalType, ...)                                                                        \
+    0x1a + PP_NARG(__VA_ARGS__),             /* bLength */                                                                                                                                      \
+    0x24,                                    /* bDescriptorType : CS_INTERFACE */                                                                                                               \
+    VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VS_FRAME_MJPEG */                                                                                                          \
+    bFrameIndex,                             /* bFrameIndex : First (and only) frame descriptor */                                                                                              \
+    0x00,                                    /* bmCapabilities : Still images using capture method 0 are supported at this frame setting.D1: Fixed frame-rate. */                               \
+    WBVAL(wWidth),                           /* wWidth (2bytes): Width of frame is 128 pixels. */                                                                                               \
+    WBVAL(wHeight),                          /* wHeight (2bytes): Height of frame is 64 pixels. */                                                                                              \
+    DBVAL(dwMinBitRate),                     /* dwMinBitRate (4bytes): Min bit rate in bits/s  */                                                                                               \
+    DBVAL(dwMaxBitRate),                     /* dwMaxBitRate (4bytes): Max bit rate in bits/s  */                                                                                               \
+    DBVAL(dwMaxVideoFrameBufferSize),        /* dwMaxVideoFrameBufSize (4bytes): Maximum video or still frame size, in bytes. */                                                                \
+    dwDefaultFrameInterval,                  /* dwDefaultFrameInterval : 1,000,000 * 100ns -> 10 FPS */                                                                                         \
+    bFrameIntervalType,                      /* bFrameIntervalType : Indicates how the frame interval can be programmed. 0: Continuous frame interval 1..255: The number of discrete frame   */ \
+    __VA_ARGS__
+// clang-format on
+#endif /*USB_VIDEO_H */

+ 789 - 0
components/drivers/usb/cherryusb/class/video/usbd_video.c

@@ -0,0 +1,789 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_video.h"
+
+struct video_entity_info {
+    uint8_t bDescriptorSubtype;
+    uint8_t bEntityId;
+    uint16_t wTerminalType;
+};
+
+struct usbd_video_priv {
+    struct video_probe_and_commit_controls probe;
+    struct video_probe_and_commit_controls commit;
+    uint8_t power_mode;
+    uint8_t error_code;
+    struct video_entity_info info[3];
+} g_usbd_video[CONFIG_USBDEV_MAX_BUS];
+
+static int usbd_video_control_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    uint8_t control_selector = (uint8_t)(setup->wValue >> 8);
+
+    switch (control_selector) {
+        case VIDEO_VC_VIDEO_POWER_MODE_CONTROL:
+            switch (setup->bRequest) {
+                case VIDEO_REQUEST_SET_CUR:
+                    break;
+                case VIDEO_REQUEST_GET_CUR:
+                    break;
+                case VIDEO_REQUEST_GET_INFO:
+                    break;
+                default:
+                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                    return -1;
+            }
+
+            break;
+        case VIDEO_VC_REQUEST_ERROR_CODE_CONTROL:
+            switch (setup->bRequest) {
+                case VIDEO_REQUEST_GET_CUR:
+                    (*data)[0] = 0x06;
+                    *len = 1;
+                    break;
+                case VIDEO_REQUEST_GET_INFO:
+                    break;
+                default:
+                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                    return -1;
+            }
+
+            break;
+        default:
+            break;
+    }
+
+    return 0;
+}
+
+static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    uint8_t entity_id = (uint8_t)(setup->wIndex >> 8);
+    uint8_t control_selector = (uint8_t)(setup->wValue >> 8);
+
+    for (uint8_t i = 0; i < 3; i++) {
+        struct video_entity_info *entity_info = &g_usbd_video[busid].info[i];
+        if (entity_info->bEntityId == entity_id) {
+            switch (entity_info->bDescriptorSubtype) {
+                case VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE:
+                    break;
+                case VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE:
+                    if (entity_info->wTerminalType == VIDEO_ITT_CAMERA) {
+                        switch (control_selector) {
+                            case VIDEO_CT_AE_MODE_CONTROL:
+                                switch (setup->bRequest) {
+                                    case VIDEO_REQUEST_GET_CUR:
+                                        (*data)[0] = 0x08;
+                                        *len = 1;
+                                        break;
+                                    default:
+                                        USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                        return -1;
+                                }
+                                break;
+                            case VIDEO_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL:
+                                switch (setup->bRequest) {
+                                    case VIDEO_REQUEST_GET_CUR: {
+                                        uint32_t dwExposureTimeAbsolute = 2500;
+                                        memcpy(*data, (uint8_t *)&dwExposureTimeAbsolute, 4);
+                                        *len = 4;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_MIN: {
+                                        uint32_t dwExposureTimeAbsolute = 5; //0.0005sec
+                                        memcpy(*data, (uint8_t *)&dwExposureTimeAbsolute, 4);
+                                        *len = 4;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_MAX: {
+                                        uint32_t dwExposureTimeAbsolute = 2500; //0.2500sec
+                                        memcpy(*data, (uint8_t *)&dwExposureTimeAbsolute, 4);
+                                        *len = 4;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_RES: {
+                                        uint32_t dwExposureTimeAbsolute = 5; //0.0005sec
+                                        memcpy(*data, (uint8_t *)&dwExposureTimeAbsolute, 4);
+                                        *len = 4;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_INFO:
+                                        (*data)[0] = 0x03; //struct video_camera_capabilities
+                                        *len = 1;
+                                        break;
+                                    case VIDEO_REQUEST_GET_DEF: {
+                                        uint32_t dwExposureTimeAbsolute = 2500; //0.2500sec
+                                        memcpy(*data, (uint8_t *)&dwExposureTimeAbsolute, 4);
+                                        *len = 4;
+                                    } break;
+                                    default:
+                                        USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                        return -1;
+                                }
+                                break;
+                            case VIDEO_CT_FOCUS_ABSOLUTE_CONTROL:
+                                switch (setup->bRequest) {
+                                    case VIDEO_REQUEST_GET_CUR: {
+                                        uint16_t wFocusAbsolute = 0x0080;
+                                        memcpy(*data, (uint8_t *)&wFocusAbsolute, 2);
+                                        *len = 2;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_MIN: {
+                                        uint16_t wFocusAbsolute = 0;
+                                        memcpy(*data, (uint8_t *)&wFocusAbsolute, 2);
+                                        *len = 2;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_MAX: {
+                                        uint16_t wFocusAbsolute = 0x00ff;
+                                        memcpy(*data, (uint8_t *)&wFocusAbsolute, 2);
+                                        *len = 2;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_RES: {
+                                        uint16_t wFocusAbsolute = 0x0001;
+                                        memcpy(*data, (uint8_t *)&wFocusAbsolute, 2);
+                                        *len = 2;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_INFO:
+                                        (*data)[0] = 0x03; //struct video_camera_capabilities
+                                        *len = 1;
+                                        break;
+                                    case VIDEO_REQUEST_GET_DEF: {
+                                        uint16_t wFocusAbsolute = 0x0080;
+                                        memcpy(*data, (uint8_t *)&wFocusAbsolute, 2);
+                                        *len = 2;
+                                    } break;
+                                    default:
+                                        USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                        return -1;
+                                }
+                                break;
+                            case VIDEO_CT_ZOOM_ABSOLUTE_CONTROL:
+                                switch (setup->bRequest) {
+                                    case VIDEO_REQUEST_GET_CUR: {
+                                        uint16_t wObjectiveFocalLength = 0x0064;
+                                        memcpy(*data, (uint8_t *)&wObjectiveFocalLength, 2);
+                                        *len = 2;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_MIN: {
+                                        uint16_t wObjectiveFocalLength = 0x0064;
+                                        memcpy(*data, (uint8_t *)&wObjectiveFocalLength, 2);
+                                        *len = 2;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_MAX: {
+                                        uint16_t wObjectiveFocalLength = 0x00c8;
+                                        memcpy(*data, (uint8_t *)&wObjectiveFocalLength, 2);
+                                        *len = 2;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_RES: {
+                                        uint16_t wObjectiveFocalLength = 0x0001;
+                                        memcpy(*data, (uint8_t *)&wObjectiveFocalLength, 2);
+                                        *len = 2;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_INFO:
+                                        (*data)[0] = 0x03; //struct video_camera_capabilities
+                                        *len = 1;
+                                        break;
+                                    case VIDEO_REQUEST_GET_DEF: {
+                                        uint16_t wObjectiveFocalLength = 0x0064;
+                                        memcpy(*data, (uint8_t *)&wObjectiveFocalLength, 2);
+                                        *len = 2;
+                                    } break;
+                                    default:
+                                        USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                        return -1;
+                                }
+                                break;
+                            case VIDEO_CT_ROLL_ABSOLUTE_CONTROL:
+                                switch (setup->bRequest) {
+                                    case VIDEO_REQUEST_GET_CUR: {
+                                        uint16_t wRollAbsolute = 0x0000;
+                                        memcpy(*data, (uint8_t *)&wRollAbsolute, 2);
+                                        *len = 2;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_MIN: {
+                                        uint16_t wRollAbsolute = 0x0000;
+                                        memcpy(*data, (uint8_t *)&wRollAbsolute, 2);
+                                        *len = 2;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_MAX: {
+                                        uint16_t wRollAbsolute = 0x00ff;
+                                        memcpy(*data, (uint8_t *)&wRollAbsolute, 2);
+                                        *len = 2;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_RES: {
+                                        uint16_t wRollAbsolute = 0x0001;
+                                        memcpy(*data, (uint8_t *)&wRollAbsolute, 2);
+                                        *len = 2;
+                                    } break;
+                                    case VIDEO_REQUEST_GET_INFO:
+                                        (*data)[0] = 0x03; //struct video_camera_capabilities
+                                        *len = 1;
+                                        break;
+                                    case VIDEO_REQUEST_GET_DEF: {
+                                        uint16_t wRollAbsolute = 0x0000;
+                                        memcpy(*data, (uint8_t *)&wRollAbsolute, 2);
+                                        *len = 2;
+                                    } break;
+                                    default:
+                                        USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                        return -1;
+                                }
+                                break;
+                            case VIDEO_CT_FOCUS_AUTO_CONTROL:
+                                switch (setup->bRequest) {
+                                    case VIDEO_REQUEST_GET_CUR: {
+                                        uint16_t wFocusAuto = 0x0000;
+                                        memcpy(*data, (uint8_t *)&wFocusAuto, 2);
+                                        *len = 2;
+                                    } break;
+                                    default:
+                                        USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                        return -1;
+                                }
+                                break;
+                            default:
+                                USB_LOG_WRN("Unhandled Video Class control selector 0x%02x\r\n", control_selector);
+                                return -1;
+                        }
+                    } else {
+                        USB_LOG_WRN("Unhandled Video Class wTerminalType 0x%02x\r\n", entity_info->wTerminalType);
+                        return -2;
+                    }
+                    break;
+                case VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE:
+                    break;
+                case VIDEO_VC_SELECTOR_UNIT_DESCRIPTOR_SUBTYPE:
+                    break;
+                case VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE:
+                    switch (control_selector) {
+                        case VIDEO_PU_BACKLIGHT_COMPENSATION_CONTROL:
+                            switch (setup->bRequest) {
+                                case VIDEO_REQUEST_GET_CUR: {
+                                    uint16_t wBacklightCompensation = 0x0004;
+                                    memcpy(*data, (uint8_t *)&wBacklightCompensation, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MIN: {
+                                    uint16_t wBacklightCompensation = 0;
+                                    memcpy(*data, (uint8_t *)&wBacklightCompensation, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MAX: {
+                                    uint16_t wBacklightCompensation = 8;
+                                    memcpy(*data, (uint8_t *)&wBacklightCompensation, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_RES: {
+                                    uint16_t wBacklightCompensation = 1;
+                                    memcpy(*data, (uint8_t *)&wBacklightCompensation, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_INFO:
+                                    (*data)[0] = 0x03; //struct video_camera_capabilities
+                                    *len = 1;
+                                    break;
+                                case VIDEO_REQUEST_GET_DEF: {
+                                    uint16_t wBacklightCompensation = 4;
+                                    memcpy(*data, (uint8_t *)&wBacklightCompensation, 2);
+                                    *len = 2;
+                                } break;
+                                default:
+                                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                    return -1;
+                            }
+                            break;
+                        case VIDEO_PU_BRIGHTNESS_CONTROL:
+                            switch (setup->bRequest) {
+                                case VIDEO_REQUEST_SET_CUR: {
+                                    uint16_t wBrightness = (uint16_t)(*data)[1] << 8 | (uint16_t)(*data)[0];
+                                    USB_LOG_INFO("Video set brightness:%d\r\n", wBrightness);
+                                } break;
+                                case VIDEO_REQUEST_GET_CUR: {
+                                    uint16_t wBrightness = 0x0080;
+                                    memcpy(*data, (uint8_t *)&wBrightness, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MIN: {
+                                    uint16_t wBrightness = 0x0001;
+                                    memcpy(*data, (uint8_t *)&wBrightness, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MAX: {
+                                    uint16_t wBrightness = 0x00ff;
+                                    memcpy(*data, (uint8_t *)&wBrightness, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_RES: {
+                                    uint16_t wBrightness = 0x0001;
+                                    memcpy(*data, (uint8_t *)&wBrightness, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_INFO:
+                                    (*data)[0] = 0x03; //struct video_camera_capabilities
+                                    *len = 1;
+                                    break;
+                                case VIDEO_REQUEST_GET_DEF: {
+                                    uint16_t wBrightness = 0x0080;
+                                    memcpy(*data, (uint8_t *)&wBrightness, 2);
+                                    *len = 2;
+                                } break;
+                                default:
+                                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                    return -1;
+                            }
+                            break;
+                        case VIDEO_PU_CONTRAST_CONTROL:
+                            switch (setup->bRequest) {
+                                case VIDEO_REQUEST_GET_CUR: {
+                                    uint16_t wContrast = 0x0080;
+                                    memcpy(*data, (uint8_t *)&wContrast, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MIN: {
+                                    uint16_t wContrast = 0x0001;
+                                    memcpy(*data, (uint8_t *)&wContrast, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MAX: {
+                                    uint16_t wContrast = 0x00ff;
+                                    memcpy(*data, (uint8_t *)&wContrast, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_RES: {
+                                    uint16_t wContrast = 0x0001;
+                                    memcpy(*data, (uint8_t *)&wContrast, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_INFO:
+                                    (*data)[0] = 0x03; //struct video_camera_capabilities
+                                    *len = 1;
+                                    break;
+                                case VIDEO_REQUEST_GET_DEF: {
+                                    uint16_t wContrast = 0x0080;
+                                    memcpy(*data, (uint8_t *)&wContrast, 2);
+                                    *len = 2;
+                                } break;
+                                default:
+                                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                    return -1;
+                            }
+                            break;
+                        case VIDEO_PU_HUE_CONTROL:
+                            switch (setup->bRequest) {
+                                case VIDEO_REQUEST_GET_CUR: {
+                                    uint16_t wHue = 0x0080;
+                                    memcpy(*data, (uint8_t *)&wHue, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MIN: {
+                                    uint16_t wHue = 0x0001;
+                                    memcpy(*data, (uint8_t *)&wHue, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MAX: {
+                                    uint16_t wHue = 0x00ff;
+                                    memcpy(*data, (uint8_t *)&wHue, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_RES: {
+                                    uint16_t wHue = 0x0001;
+                                    memcpy(*data, (uint8_t *)&wHue, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_INFO:
+                                    (*data)[0] = 0x03; //struct video_camera_capabilities
+                                    *len = 1;
+                                    break;
+                                case VIDEO_REQUEST_GET_DEF: {
+                                    uint16_t wHue = 0x0080;
+                                    memcpy(*data, (uint8_t *)&wHue, 2);
+                                    *len = 2;
+                                } break;
+                                default:
+                                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                    return -1;
+                            }
+                            break;
+                        case VIDEO_PU_SATURATION_CONTROL:
+                            switch (setup->bRequest) {
+                                case VIDEO_REQUEST_GET_MIN: {
+                                    uint16_t wSaturation = 0x0001;
+                                    memcpy(*data, (uint8_t *)&wSaturation, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MAX: {
+                                    uint16_t wSaturation = 0x00ff;
+                                    memcpy(*data, (uint8_t *)&wSaturation, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_RES: {
+                                    uint16_t wSaturation = 0x0001;
+                                    memcpy(*data, (uint8_t *)&wSaturation, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_INFO:
+                                    (*data)[0] = 0x03; //struct video_camera_capabilities
+                                    *len = 1;
+                                    break;
+                                case VIDEO_REQUEST_GET_DEF: {
+                                    uint16_t wSaturation = 0x0080;
+                                    memcpy(*data, (uint8_t *)&wSaturation, 2);
+                                    *len = 2;
+                                } break;
+                                default:
+                                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                    return -1;
+                            }
+                            break;
+                        case VIDEO_PU_SHARPNESS_CONTROL:
+                            switch (setup->bRequest) {
+                                case VIDEO_REQUEST_GET_MIN: {
+                                    uint16_t wSharpness = 0x0001;
+                                    memcpy(*data, (uint8_t *)&wSharpness, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MAX: {
+                                    uint16_t wSharpness = 0x00ff;
+                                    memcpy(*data, (uint8_t *)&wSharpness, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_RES: {
+                                    uint16_t wSharpness = 0x0001;
+                                    memcpy(*data, (uint8_t *)&wSharpness, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_INFO:
+                                    (*data)[0] = 0x03; //struct video_camera_capabilities
+                                    *len = 1;
+                                    break;
+                                case VIDEO_REQUEST_GET_DEF: {
+                                    uint16_t wSharpness = 0x0080;
+                                    memcpy(*data, (uint8_t *)&wSharpness, 2);
+                                    *len = 2;
+                                } break;
+                                default:
+                                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                    return -1;
+                            }
+                            break;
+                        case VIDEO_PU_GAIN_CONTROL:
+                            switch (setup->bRequest) {
+                                case VIDEO_REQUEST_GET_MIN: {
+                                    uint16_t wGain = 0;
+                                    memcpy(*data, (uint8_t *)&wGain, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MAX: {
+                                    uint16_t wGain = 255;
+                                    memcpy(*data, (uint8_t *)&wGain, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_RES: {
+                                    uint16_t wGain = 1;
+                                    memcpy(*data, (uint8_t *)&wGain, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_INFO:
+                                    (*data)[0] = 0x03; //struct video_camera_capabilities
+                                    *len = 1;
+                                    break;
+                                case VIDEO_REQUEST_GET_DEF: {
+                                    uint16_t wGain = 255;
+                                    memcpy(*data, (uint8_t *)&wGain, 2);
+                                    *len = 2;
+                                } break;
+                                default:
+                                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                    return -1;
+                            }
+                            break;
+                        case VIDEO_PU_WHITE_BALANCE_TEMPERATURE_CONTROL:
+                            switch (setup->bRequest) {
+                                case VIDEO_REQUEST_GET_CUR: {
+                                    uint16_t wWhiteBalance_Temprature = 417;
+                                    memcpy(*data, (uint8_t *)&wWhiteBalance_Temprature, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MIN: {
+                                    uint16_t wWhiteBalance_Temprature = 300;
+                                    memcpy(*data, (uint8_t *)&wWhiteBalance_Temprature, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_MAX: {
+                                    uint16_t wWhiteBalance_Temprature = 600;
+                                    memcpy(*data, (uint8_t *)&wWhiteBalance_Temprature, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_RES: {
+                                    uint16_t wWhiteBalance_Temprature = 1;
+                                    memcpy(*data, (uint8_t *)&wWhiteBalance_Temprature, 2);
+                                    *len = 2;
+                                } break;
+                                case VIDEO_REQUEST_GET_INFO:
+                                    (*data)[0] = 0x03; //struct video_camera_capabilities
+                                    *len = 1;
+                                    break;
+                                case VIDEO_REQUEST_GET_DEF: {
+                                    uint16_t wWhiteBalance_Temprature = 417;
+                                    memcpy(*data, (uint8_t *)&wWhiteBalance_Temprature, 2);
+                                    *len = 2;
+                                } break;
+                                default:
+                                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                    return -1;
+                            }
+                            break;
+                        case VIDEO_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL:
+                            switch (setup->bRequest) {
+                                case VIDEO_REQUEST_GET_CUR: {
+                                    uint16_t wWhiteBalance_Temprature_Auto = 1;
+                                    memcpy(*data, (uint8_t *)&wWhiteBalance_Temprature_Auto, 1);
+                                    *len = 1;
+                                } break;
+                                default:
+                                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                                    return -1;
+                            }
+                            break;
+                        default:
+                            g_usbd_video[busid].error_code = 0x06;
+                            USB_LOG_WRN("Unhandled Video Class control selector 0x%02x\r\n", control_selector);
+                            return -1;
+                    }
+                    break;
+                case VIDEO_VC_EXTENSION_UNIT_DESCRIPTOR_SUBTYPE:
+                    break;
+                case VIDEO_VC_ENCODING_UNIT_DESCRIPTOR_SUBTYPE:
+                    break;
+
+                default:
+                    break;
+            }
+        }
+    }
+    return 0;
+}
+
+static int usbd_video_stream_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    uint8_t control_selector = (uint8_t)(setup->wValue >> 8);
+
+    switch (control_selector) {
+        case VIDEO_VS_PROBE_CONTROL:
+            switch (setup->bRequest) {
+                case VIDEO_REQUEST_SET_CUR:
+                    //memcpy((uint8_t *)&g_usbd_video[busid].probe, *data, setup->wLength);
+                    break;
+                case VIDEO_REQUEST_GET_CUR:
+                    memcpy(*data, (uint8_t *)&g_usbd_video[busid].probe, setup->wLength);
+                    *len = sizeof(struct video_probe_and_commit_controls);
+                    break;
+
+                case VIDEO_REQUEST_GET_MIN:
+                case VIDEO_REQUEST_GET_MAX:
+                case VIDEO_REQUEST_GET_RES:
+                case VIDEO_REQUEST_GET_DEF:
+                    memcpy(*data, (uint8_t *)&g_usbd_video[busid].probe, setup->wLength);
+                    *len = sizeof(struct video_probe_and_commit_controls);
+                    break;
+                case VIDEO_REQUEST_GET_LEN:
+                    (*data)[0] = sizeof(struct video_probe_and_commit_controls);
+                    *len = 1;
+                    break;
+
+                case VIDEO_REQUEST_GET_INFO:
+                    (*data)[0] = 0x03;
+                    *len = 1;
+                    break;
+
+                default:
+                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                    return -1;
+            }
+            break;
+        case VIDEO_VS_COMMIT_CONTROL:
+            switch (setup->bRequest) {
+                case VIDEO_REQUEST_SET_CUR:
+                    //memcpy((uint8_t *)&g_usbd_video[busid].commit, *data, setup->wLength);
+                    break;
+                case VIDEO_REQUEST_GET_CUR:
+                    memcpy(*data, (uint8_t *)&g_usbd_video[busid].commit, setup->wLength);
+                    *len = sizeof(struct video_probe_and_commit_controls);
+                    break;
+                case VIDEO_REQUEST_GET_MIN:
+                case VIDEO_REQUEST_GET_MAX:
+                case VIDEO_REQUEST_GET_RES:
+                case VIDEO_REQUEST_GET_DEF:
+                    memcpy(*data, (uint8_t *)&g_usbd_video[busid].commit, setup->wLength);
+                    *len = sizeof(struct video_probe_and_commit_controls);
+                    break;
+
+                case VIDEO_REQUEST_GET_LEN:
+                    (*data)[0] = sizeof(struct video_probe_and_commit_controls);
+                    *len = 1;
+                    break;
+
+                case VIDEO_REQUEST_GET_INFO:
+                    (*data)[0] = 0x03;
+                    *len = 1;
+                    break;
+
+                default:
+                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                    return -1;
+            }
+            break;
+        case VIDEO_VS_STREAM_ERROR_CODE_CONTROL:
+            switch (setup->bRequest) {
+                case VIDEO_REQUEST_GET_CUR:
+                    (*data)[0] = g_usbd_video[busid].error_code;
+                    *len = 1;
+                    break;
+                case VIDEO_REQUEST_GET_INFO:
+                    (*data)[0] = 0x01;
+                    *len = 1;
+                    break;
+                default:
+                    USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
+                    return -1;
+            }
+            break;
+        default:
+            break;
+    }
+
+    return 0;
+}
+
+static int video_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    USB_LOG_DBG("Video Class request: "
+                "bRequest 0x%02x\r\n",
+                setup->bRequest);
+
+    uint8_t intf_num = (uint8_t)setup->wIndex;
+    uint8_t entity_id = (uint8_t)(setup->wIndex >> 8);
+
+    if (intf_num == 0) { /* Video Control Interface */
+        if (entity_id == 0) {
+            return usbd_video_control_request_handler(busid, setup, data, len); /* Interface Control Requests */
+        } else {
+            return usbd_video_control_unit_terminal_request_handler(busid, setup, data, len); /* Unit and Terminal Requests */
+        }
+    } else if (intf_num == 1) {                                     /* Video Stream Inteface */
+        return usbd_video_stream_request_handler(busid, setup, data, len); /* Interface Stream Requests */
+    }
+    return -1;
+}
+
+static void video_notify_handler(uint8_t busid, uint8_t event, void *arg)
+{
+    switch (event) {
+        case USBD_EVENT_RESET:
+            g_usbd_video[busid].error_code = 0;
+            g_usbd_video[busid].power_mode = 0;
+            break;
+
+        case USBD_EVENT_SET_INTERFACE: {
+            struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)arg;
+            if (intf->bAlternateSetting == 1) {
+                usbd_video_open(busid, intf->bInterfaceNumber);
+            } else {
+                usbd_video_close(busid, intf->bInterfaceNumber);
+            }
+        }
+
+        break;
+        default:
+            break;
+    }
+}
+
+void usbd_video_probe_and_commit_controls_init(uint8_t busid, uint32_t dwFrameInterval, uint32_t dwMaxVideoFrameSize, uint32_t dwMaxPayloadTransferSize)
+{
+    g_usbd_video[busid].probe.hintUnion.bmHint = 0x01;
+    g_usbd_video[busid].probe.hintUnion1.bmHint = 0;
+    g_usbd_video[busid].probe.bFormatIndex = 1;
+    g_usbd_video[busid].probe.bFrameIndex = 1;
+    g_usbd_video[busid].probe.dwFrameInterval = dwFrameInterval;
+    g_usbd_video[busid].probe.wKeyFrameRate = 0;
+    g_usbd_video[busid].probe.wPFrameRate = 0;
+    g_usbd_video[busid].probe.wCompQuality = 0;
+    g_usbd_video[busid].probe.wCompWindowSize = 0;
+    g_usbd_video[busid].probe.wDelay = 0;
+    g_usbd_video[busid].probe.dwMaxVideoFrameSize = dwMaxVideoFrameSize;
+    g_usbd_video[busid].probe.dwMaxPayloadTransferSize = dwMaxPayloadTransferSize;
+    g_usbd_video[busid].probe.dwClockFrequency = 0;
+    g_usbd_video[busid].probe.bmFramingInfo = 0;
+    g_usbd_video[busid].probe.bPreferedVersion = 0;
+    g_usbd_video[busid].probe.bMinVersion = 0;
+    g_usbd_video[busid].probe.bMaxVersion = 0;
+
+    g_usbd_video[busid].commit.hintUnion.bmHint = 0x01;
+    g_usbd_video[busid].commit.hintUnion1.bmHint = 0;
+    g_usbd_video[busid].commit.bFormatIndex = 1;
+    g_usbd_video[busid].commit.bFrameIndex = 1;
+    g_usbd_video[busid].commit.dwFrameInterval = dwFrameInterval;
+    g_usbd_video[busid].commit.wKeyFrameRate = 0;
+    g_usbd_video[busid].commit.wPFrameRate = 0;
+    g_usbd_video[busid].commit.wCompQuality = 0;
+    g_usbd_video[busid].commit.wCompWindowSize = 0;
+    g_usbd_video[busid].commit.wDelay = 0;
+    g_usbd_video[busid].commit.dwMaxVideoFrameSize = dwMaxVideoFrameSize;
+    g_usbd_video[busid].commit.dwMaxPayloadTransferSize = dwMaxPayloadTransferSize;
+    g_usbd_video[busid].commit.dwClockFrequency = 0;
+    g_usbd_video[busid].commit.bmFramingInfo = 0;
+    g_usbd_video[busid].commit.bPreferedVersion = 0;
+    g_usbd_video[busid].commit.bMinVersion = 0;
+    g_usbd_video[busid].commit.bMaxVersion = 0;
+}
+
+struct usbd_interface *usbd_video_init_intf(uint8_t busid, struct usbd_interface *intf,
+                                            uint32_t dwFrameInterval,
+                                            uint32_t dwMaxVideoFrameSize,
+                                            uint32_t dwMaxPayloadTransferSize)
+{
+    intf->class_interface_handler = video_class_interface_request_handler;
+    intf->class_endpoint_handler = NULL;
+    intf->vendor_handler = NULL;
+    intf->notify_handler = video_notify_handler;
+
+    g_usbd_video[busid].info[0].bDescriptorSubtype = VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE;
+    g_usbd_video[busid].info[0].bEntityId = 0x01;
+    g_usbd_video[busid].info[0].wTerminalType = VIDEO_ITT_CAMERA;
+    g_usbd_video[busid].info[1].bDescriptorSubtype = VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE;
+    g_usbd_video[busid].info[1].bEntityId = 0x03;
+    g_usbd_video[busid].info[1].wTerminalType = 0x00;
+    g_usbd_video[busid].info[2].bDescriptorSubtype = VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE;
+    g_usbd_video[busid].info[2].bEntityId = 0x02;
+    g_usbd_video[busid].info[2].wTerminalType = 0x00;
+
+    usbd_video_probe_and_commit_controls_init(busid, dwFrameInterval, dwMaxVideoFrameSize, dwMaxPayloadTransferSize);
+    return intf;
+}
+
+uint32_t usbd_video_mjpeg_payload_fill(uint8_t busid, uint8_t *input, uint32_t input_len, uint8_t *output, uint32_t *out_len)
+{
+    uint32_t packets;
+    uint32_t last_packet_size;
+    uint32_t picture_pos = 0;
+    static uint8_t uvc_header[2] = { 0x02, 0x80 };
+
+    packets = (input_len + (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2) ) / (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2);
+    last_packet_size = input_len - ((packets - 1) * (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2));
+
+    for (size_t i = 0; i < packets; i++) {
+        output[g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i] = uvc_header[0];
+        output[g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i + 1] = uvc_header[1];
+        if (i == (packets - 1)) {
+            memcpy(&output[2 + g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i], &input[picture_pos], last_packet_size);
+            output[g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i + 1] |= (1 << 1);
+        } else {
+            memcpy(&output[2 + g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i], &input[picture_pos], g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2);
+            picture_pos += g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2;
+        }
+    }
+    uvc_header[1] ^= 1;
+    *out_len = (input_len + 2 * packets);
+    return packets;
+}

+ 29 - 0
components/drivers/usb/cherryusb/class/video/usbd_video.h

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_VIDEO_H
+#define USBD_VIDEO_H
+
+#include "usb_video.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Init video interface driver */
+struct usbd_interface *usbd_video_init_intf(uint8_t busid, struct usbd_interface *intf,
+                                            uint32_t dwFrameInterval,
+                                            uint32_t dwMaxVideoFrameSize,
+                                            uint32_t dwMaxPayloadTransferSize);
+
+void usbd_video_open(uint8_t busid, uint8_t intf);
+void usbd_video_close(uint8_t busid, uint8_t intf);
+uint32_t usbd_video_mjpeg_payload_fill(uint8_t busid, uint8_t *input, uint32_t input_len, uint8_t *output, uint32_t *out_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBD_VIDEO_H */

+ 522 - 0
components/drivers/usb/cherryusb/class/video/usbh_video.c

@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_video.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "usbh_video"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/video%d"
+
+/* general descriptor field offsets */
+#define DESC_bLength              0 /** Length offset */
+#define DESC_bDescriptorType      1 /** Descriptor type offset */
+#define DESC_bDescriptorSubType   2 /** Descriptor subtype offset */
+#define DESC_bNumFormats          3 /** Descriptor numformat offset */
+#define DESC_bNumFrameDescriptors 4 /** Descriptor numframe offset */
+#define DESC_bFormatIndex         3 /** Descriptor format index offset */
+#define DESC_bFrameIndex          3 /** Descriptor frame index offset */
+
+/* interface descriptor field offsets */
+#define INTF_DESC_bInterfaceNumber  2 /** Interface number offset */
+#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_video_buf[128];
+
+static const char *format_type[] = { "uncompressed", "mjpeg" };
+
+static struct usbh_video g_video_class[CONFIG_USBHOST_MAX_VIDEO_CLASS];
+static uint32_t g_devinuse = 0;
+
+static struct usbh_video *usbh_video_class_alloc(void)
+{
+    int devno;
+
+    for (devno = 0; devno < CONFIG_USBHOST_MAX_VIDEO_CLASS; devno++) {
+        if ((g_devinuse & (1 << devno)) == 0) {
+            g_devinuse |= (1 << devno);
+            memset(&g_video_class[devno], 0, sizeof(struct usbh_video));
+            g_video_class[devno].minor = devno;
+            return &g_video_class[devno];
+        }
+    }
+    return NULL;
+}
+
+static void usbh_video_class_free(struct usbh_video *video_class)
+{
+    int devno = video_class->minor;
+
+    if (devno >= 0 && devno < 32) {
+        g_devinuse &= ~(1 << devno);
+    }
+    memset(video_class, 0, sizeof(struct usbh_video));
+}
+
+int usbh_video_get(struct usbh_video *video_class, uint8_t request, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len)
+{
+    struct usb_setup_packet *setup = video_class->hport->setup;
+    int ret;
+    uint8_t retry;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = request;
+    setup->wValue = cs << 8;
+    setup->wIndex = (entity_id << 8) | intf;
+    setup->wLength = len;
+
+    retry = 0;
+    while (1) {
+        ret = usbh_control_transfer(video_class->hport, setup, g_video_buf);
+        if (ret > 0) {
+            break;
+        }
+        retry++;
+
+        if (retry == 3) {
+            return ret;
+        }
+    }
+
+    if (buf) {
+        memcpy(buf, g_video_buf, len);
+    }
+
+    return ret;
+}
+
+int usbh_video_set(struct usbh_video *video_class, uint8_t request, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len)
+{
+    struct usb_setup_packet *setup = video_class->hport->setup;
+    int ret;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = request;
+    setup->wValue = cs << 8;
+    setup->wIndex = (entity_id << 8) | intf;
+    setup->wLength = len;
+
+    memcpy(g_video_buf, buf, len);
+
+    ret = usbh_control_transfer(video_class->hport, setup, g_video_buf);
+    usb_osal_msleep(50);
+    return ret;
+}
+
+int usbh_videostreaming_get_cur_probe(struct usbh_video *video_class)
+{
+    return usbh_video_get(video_class, VIDEO_REQUEST_GET_CUR, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, (uint8_t *)&video_class->probe, 26);
+}
+
+int usbh_videostreaming_set_cur_probe(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex)
+{
+    video_class->probe.bFormatIndex = formatindex;
+    video_class->probe.bFrameIndex = frameindex;
+    video_class->probe.dwMaxPayloadTransferSize = 0;
+    video_class->probe.dwFrameInterval = 333333;
+    return usbh_video_set(video_class, VIDEO_REQUEST_SET_CUR, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, (uint8_t *)&video_class->probe, 26);
+}
+
+int usbh_videostreaming_set_cur_commit(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex)
+{
+    memcpy(&video_class->commit, &video_class->probe, sizeof(struct video_probe_and_commit_controls));
+    video_class->commit.bFormatIndex = formatindex;
+    video_class->commit.bFrameIndex = frameindex;
+    video_class->commit.dwFrameInterval = 333333;
+    return usbh_video_set(video_class, VIDEO_REQUEST_SET_CUR, video_class->data_intf, 0x00, VIDEO_VS_COMMIT_CONTROL, (uint8_t *)&video_class->commit, 26);
+}
+
+int usbh_video_open(struct usbh_video *video_class,
+                    uint8_t format_type,
+                    uint16_t wWidth,
+                    uint16_t wHeight,
+                    uint8_t altsetting)
+{
+    struct usb_setup_packet *setup = video_class->hport->setup;
+    struct usb_endpoint_descriptor *ep_desc;
+    uint8_t mult;
+    uint16_t mps;
+    int ret;
+    bool found = false;
+    uint8_t formatidx = 0;
+    uint8_t frameidx = 0;
+    uint8_t step;
+
+    if (video_class->is_opened) {
+        return 0;
+    }
+
+    for (uint8_t i = 0; i < video_class->num_of_formats; i++) {
+        if (format_type == video_class->format[i].format_type) {
+            formatidx = i + 1;
+            for (uint8_t j = 0; j < video_class->format[i].num_of_frames; j++) {
+                if ((wWidth == video_class->format[i].frame[j].wWidth) &&
+                    (wHeight == video_class->format[i].frame[j].wHeight)) {
+                    frameidx = j + 1;
+                    found = true;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (found == false) {
+        return -USB_ERR_NODEV;
+    }
+
+    if (altsetting > (video_class->num_of_intf_altsettings - 1)) {
+        return -USB_ERR_INVAL;
+    }
+
+    /* Open video step:
+     * Get CUR request (probe)
+     * Set CUR request (probe)
+     * Get CUR request (probe)
+     * Get MAX request (probe)
+     * Get MIN request (probe)
+     * Get CUR request (probe)
+     * Set CUR request (commit)
+     *
+    */
+    step = 0;
+    ret = usbh_videostreaming_get_cur_probe(video_class);
+    if (ret < 0) {
+        goto errout;
+    }
+
+    step = 1;
+    ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx);
+    if (ret < 0) {
+        goto errout;
+    }
+
+    step = 2;
+    ret = usbh_videostreaming_get_cur_probe(video_class);
+    if (ret < 0) {
+        goto errout;
+    }
+
+    step = 3;
+    ret = usbh_video_get(video_class, VIDEO_REQUEST_GET_MAX, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, NULL, 26);
+    if (ret < 0) {
+        goto errout;
+    }
+
+    step = 4;
+    ret = usbh_video_get(video_class, VIDEO_REQUEST_GET_MIN, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, NULL, 26);
+    if (ret < 0) {
+        goto errout;
+    }
+
+    step = 5;
+    ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx);
+    if (ret < 0) {
+        goto errout;
+    }
+
+    step = 6;
+    ret = usbh_videostreaming_get_cur_probe(video_class);
+    if (ret < 0) {
+        goto errout;
+    }
+
+    step = 7;
+    ret = usbh_videostreaming_set_cur_commit(video_class, formatidx, frameidx);
+    if (ret < 0) {
+        goto errout;
+    }
+
+    step = 8;
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = USB_REQUEST_SET_INTERFACE;
+    setup->wValue = altsetting;
+    setup->wIndex = video_class->data_intf;
+    setup->wLength = 0;
+
+    ret = usbh_control_transfer(video_class->hport, setup, NULL);
+    if (ret < 0) {
+        goto errout;
+    }
+
+    ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[altsetting].ep[0].ep_desc;
+    mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
+    mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
+    if (ep_desc->bEndpointAddress & 0x80) {
+        video_class->isoin_mps = mps * (mult + 1);
+        USBH_EP_INIT(video_class->isoin, ep_desc);
+    } else {
+        video_class->isoout_mps = mps * (mult + 1);
+        USBH_EP_INIT(video_class->isoout, ep_desc);
+    }
+
+    USB_LOG_INFO("Open video and select formatidx:%u, frameidx:%u, altsetting:%u\r\n", formatidx, frameidx, altsetting);
+    video_class->is_opened = true;
+    video_class->current_format = format_type;
+    return ret;
+
+errout:
+    USB_LOG_ERR("Fail to open video in step %u\r\n", step);
+    return ret;
+}
+
+int usbh_video_close(struct usbh_video *video_class)
+{
+    struct usb_setup_packet *setup = video_class->hport->setup;
+    int ret = 0;
+
+    USB_LOG_INFO("Close video device\r\n");
+
+    video_class->is_opened = false;
+
+    if (video_class->isoin) {
+        video_class->isoin = NULL;
+    }
+
+    if (video_class->isoout) {
+        video_class->isoout = NULL;
+    }
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = USB_REQUEST_SET_INTERFACE;
+    setup->wValue = 0;
+    setup->wIndex = video_class->data_intf;
+    setup->wLength = 0;
+
+    ret = usbh_control_transfer(video_class->hport, setup, NULL);
+    if (ret < 0) {
+        return ret;
+    }
+    return ret;
+}
+
+void usbh_video_list_info(struct usbh_video *video_class)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    uint8_t mult;
+    uint16_t mps;
+
+    USB_LOG_INFO("============= Video device information ===================\r\n");
+    USB_LOG_RAW("bcdVDC:%04x\r\n", video_class->bcdVDC);
+    USB_LOG_RAW("Num of altsettings:%u\r\n", video_class->num_of_intf_altsettings);
+
+    for (uint8_t i = 0; i < video_class->num_of_intf_altsettings; i++) {
+        if (i == 0) {
+            USB_LOG_RAW("Ingore altsetting 0\r\n");
+            continue;
+        }
+        ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[i].ep[0].ep_desc;
+
+        mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
+        mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
+
+        USB_LOG_RAW("Altsetting:%u, Ep=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
+                     i,
+                     ep_desc->bEndpointAddress,
+                     ep_desc->bmAttributes,
+                     mps,
+                     ep_desc->bInterval,
+                     mult);
+    }
+
+    USB_LOG_RAW("bNumFormats:%u\r\n", video_class->num_of_formats);
+    for (uint8_t i = 0; i < video_class->num_of_formats; i++) {
+        USB_LOG_RAW("  FormatIndex:%u\r\n", i + 1);
+        USB_LOG_RAW("  FormatType:%s\r\n", format_type[video_class->format[i].format_type]);
+        USB_LOG_RAW("  bNumFrames:%u\r\n", video_class->format[i].num_of_frames);
+        USB_LOG_RAW("  Resolution:\r\n");
+        for (uint8_t j = 0; j < video_class->format[i].num_of_frames; j++) {
+            USB_LOG_RAW("      FrameIndex:%u\r\n", j + 1);
+            USB_LOG_RAW("      wWidth: %d, wHeight: %d\r\n",
+                         video_class->format[i].frame[j].wWidth,
+                         video_class->format[i].frame[j].wHeight);
+        }
+    }
+
+    USB_LOG_INFO("============= Video device information ===================\r\n");
+}
+
+static int usbh_video_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret;
+    uint8_t cur_iface = 0xff;
+    // uint8_t cur_alt_setting = 0xff;
+    uint8_t frame_index = 0xff;
+    uint8_t format_index = 0xff;
+    uint8_t num_of_frames = 0xff;
+    uint8_t *p;
+
+    struct usbh_video *video_class = usbh_video_class_alloc();
+    if (video_class == NULL) {
+        USB_LOG_ERR("Fail to alloc video_class\r\n");
+        return -USB_ERR_NOMEM;
+    }
+
+    video_class->hport = hport;
+    video_class->ctrl_intf = intf;
+    video_class->data_intf = intf + 1;
+    video_class->num_of_intf_altsettings = hport->config.intf[intf + 1].altsetting_num;
+
+    hport->config.intf[intf].priv = video_class;
+
+    ret = usbh_video_close(video_class);
+    if (ret < 0) {
+        USB_LOG_ERR("Fail to close video device\r\n");
+        return ret;
+    }
+
+    p = hport->raw_config_desc;
+    while (p[DESC_bLength]) {
+        switch (p[DESC_bDescriptorType]) {
+            case USB_DESCRIPTOR_TYPE_INTERFACE:
+                cur_iface = p[INTF_DESC_bInterfaceNumber];
+                //cur_alt_setting = p[INTF_DESC_bAlternateSetting];
+                break;
+            case USB_DESCRIPTOR_TYPE_ENDPOINT:
+                //ep_desc = (struct usb_endpoint_descriptor *)p;
+                break;
+            case VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE:
+                if (cur_iface == video_class->ctrl_intf) {
+                    switch (p[DESC_bDescriptorSubType]) {
+                        case VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE:
+                            video_class->bcdVDC = ((uint16_t)p[4] << 8) | (uint16_t)p[3];
+                            break;
+                        case VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE:
+                            break;
+                        case VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE:
+                            break;
+                        case VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE:
+                            break;
+
+                        default:
+                            break;
+                    }
+                } else if (cur_iface == video_class->data_intf) {
+                    switch (p[DESC_bDescriptorSubType]) {
+                        case VIDEO_VS_INPUT_HEADER_DESCRIPTOR_SUBTYPE:
+                            video_class->num_of_formats = p[DESC_bNumFormats];
+                            break;
+                        case VIDEO_VS_FORMAT_UNCOMPRESSED_DESCRIPTOR_SUBTYPE:
+                            format_index = p[DESC_bFormatIndex];
+                            num_of_frames = p[DESC_bNumFrameDescriptors];
+
+                            video_class->format[format_index - 1].num_of_frames = num_of_frames;
+                            video_class->format[format_index - 1].format_type = USBH_VIDEO_FORMAT_UNCOMPRESSED;
+                            break;
+                        case VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_SUBTYPE:
+                            format_index = p[DESC_bFormatIndex];
+                            num_of_frames = p[DESC_bNumFrameDescriptors];
+
+                            video_class->format[format_index - 1].num_of_frames = num_of_frames;
+                            video_class->format[format_index - 1].format_type = USBH_VIDEO_FORMAT_MJPEG;
+                            break;
+                        case VIDEO_VS_FRAME_UNCOMPRESSED_DESCRIPTOR_SUBTYPE:
+                            frame_index = p[DESC_bFrameIndex];
+
+                            video_class->format[format_index - 1].frame[frame_index - 1].wWidth = ((struct video_cs_if_vs_frame_uncompressed_descriptor *)p)->wWidth;
+                            video_class->format[format_index - 1].frame[frame_index - 1].wHeight = ((struct video_cs_if_vs_frame_uncompressed_descriptor *)p)->wHeight;
+                            break;
+                        case VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_SUBTYPE:
+                            frame_index = p[DESC_bFrameIndex];
+
+                            video_class->format[format_index - 1].frame[frame_index - 1].wWidth = ((struct video_cs_if_vs_frame_mjpeg_descriptor *)p)->wWidth;
+                            video_class->format[format_index - 1].frame[frame_index - 1].wHeight = ((struct video_cs_if_vs_frame_mjpeg_descriptor *)p)->wHeight;
+                            break;
+                        default:
+                            break;
+                    }
+                }
+
+                break;
+
+            default:
+                break;
+        }
+        /* skip to next descriptor */
+        p += p[DESC_bLength];
+    }
+
+    usbh_video_list_info(video_class);
+
+    snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, video_class->minor);
+
+    USB_LOG_INFO("Register Video Class:%s\r\n", hport->config.intf[intf].devname);
+
+    usbh_video_run(video_class);
+    return ret;
+}
+
+static int usbh_video_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_video *video_class = (struct usbh_video *)hport->config.intf[intf].priv;
+
+    if (video_class) {
+        if (video_class->isoin) {
+        }
+
+        if (video_class->isoout) {
+        }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister Video Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_video_stop(video_class);
+        }
+
+        usbh_video_class_free(video_class);
+    }
+
+    return ret;
+}
+
+static int usbh_video_streaming_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    return 0;
+}
+
+static int usbh_video_streaming_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    return 0;
+}
+
+__WEAK void usbh_video_run(struct usbh_video *video_class)
+{
+}
+
+__WEAK void usbh_video_stop(struct usbh_video *video_class)
+{
+}
+
+const struct usbh_class_driver video_ctrl_class_driver = {
+    .driver_name = "video_ctrl",
+    .connect = usbh_video_ctrl_connect,
+    .disconnect = usbh_video_ctrl_disconnect
+};
+
+const struct usbh_class_driver video_streaming_class_driver = {
+    .driver_name = "video_streaming",
+    .connect = usbh_video_streaming_connect,
+    .disconnect = usbh_video_streaming_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info video_ctrl_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
+    .class = USB_DEVICE_CLASS_VIDEO,
+    .subclass = VIDEO_SC_VIDEOCONTROL,
+    .protocol = VIDEO_PC_PROTOCOL_UNDEFINED,
+    .id_table = NULL,
+    .class_driver = &video_ctrl_class_driver
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info video_streaming_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
+    .class = USB_DEVICE_CLASS_VIDEO,
+    .subclass = VIDEO_SC_VIDEOSTREAMING,
+    .protocol = VIDEO_PC_PROTOCOL_UNDEFINED,
+    .id_table = NULL,
+    .class_driver = &video_streaming_class_driver
+};

+ 85 - 0
components/drivers/usb/cherryusb/class/video/usbh_video.h

@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_VIDEO_H
+#define USBH_VIDEO_H
+
+#include "usb_video.h"
+
+#define USBH_VIDEO_FORMAT_UNCOMPRESSED 0
+#define USBH_VIDEO_FORMAT_MJPEG        1
+
+struct usbh_video_resolution {
+    uint16_t wWidth;
+    uint16_t wHeight;
+};
+
+struct usbh_video_format {
+    struct usbh_video_resolution frame[12];
+    uint8_t format_type;
+    uint8_t num_of_frames;
+};
+
+struct usbh_videoframe {
+    uint8_t *frame_buf;
+    uint32_t frame_bufsize;
+    uint32_t frame_format;
+    uint32_t frame_size;
+};
+
+struct usbh_videostreaming {
+    struct usbh_videoframe *frame;
+    uint32_t frame_format;
+    uint32_t bufoffset;
+    uint16_t width;
+    uint16_t height;
+};
+
+struct usbh_video {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *isoin;  /* ISO IN endpoint */
+    struct usb_endpoint_descriptor *isoout; /* ISO OUT endpoint */
+
+    uint8_t ctrl_intf; /* interface number */
+    uint8_t data_intf; /* interface number */
+    uint8_t minor;
+    struct video_probe_and_commit_controls probe;
+    struct video_probe_and_commit_controls commit;
+    uint16_t isoin_mps;
+    uint16_t isoout_mps;
+    bool is_opened;
+    uint8_t current_format;
+    uint16_t bcdVDC;
+    uint8_t num_of_intf_altsettings;
+    uint8_t num_of_formats;
+    struct usbh_video_format format[3];
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_video_get(struct usbh_video *video_class, uint8_t request, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len);
+int usbh_video_set(struct usbh_video *video_class, uint8_t request, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len);
+
+int usbh_video_open(struct usbh_video *video_class,
+                    uint8_t format_type,
+                    uint16_t wWidth,
+                    uint16_t wHeight,
+                    uint8_t altsetting);
+int usbh_video_close(struct usbh_video *video_class);
+
+void usbh_video_list_info(struct usbh_video *video_class);
+
+void usbh_video_run(struct usbh_video *video_class);
+void usbh_video_stop(struct usbh_video *video_class);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_VIDEO_H */

+ 270 - 0
components/drivers/usb/cherryusb/class/wireless/ndis.h

@@ -0,0 +1,270 @@
+/* This file has been prepared for Doxygen automatic documentation generation.*/
+/*! \file ndis.h ***************************************************************
+ *
+ * \brief
+ *      This file contains the possible external configuration of the USB.
+ *
+ * \addtogroup usbstick
+ *
+ *
+ ******************************************************************************/
+
+/**
+ \ingroup usbstick
+ \defgroup RNDIS RNDIS Support
+ @{
+ */
+
+/*
+ * ndis.h
+ *
+ * Modified by Colin O'Flynn <coflynn@newae.com>
+ * ntddndis.h modified by Benedikt Spranger <b.spranger@pengutronix.de>
+ *
+ * Thanks to the cygwin development team,
+ * espacially to Casper S. Hornstrup <chorns@users.sourceforge.net>
+ *
+ * THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ * This source code is offered for use in the public domain. You may
+ * use, modify or distribute it freely.
+ *
+ * This code is distributed in the hope that it will be useful but
+ * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ * DISCLAIMED. This includes but is not limited to warranties of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef _LINUX_NDIS_H
+#define _LINUX_NDIS_H
+
+#define NDIS_STATUS_MULTICAST_FULL      0xC0010009
+#define NDIS_STATUS_MULTICAST_EXISTS    0xC001000A
+#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B
+
+/* from drivers/net/sk98lin/h/skgepnmi.h */
+#define OID_PNP_CAPABILITIES           0xFD010100
+#define OID_PNP_SET_POWER              0xFD010101
+#define OID_PNP_QUERY_POWER            0xFD010102
+#define OID_PNP_ADD_WAKE_UP_PATTERN    0xFD010103
+#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104
+#define OID_PNP_ENABLE_WAKE_UP         0xFD010106
+
+enum NDIS_DEVICE_POWER_STATE {
+    NdisDeviceStateUnspecified = 0,
+    NdisDeviceStateD0,
+    NdisDeviceStateD1,
+    NdisDeviceStateD2,
+    NdisDeviceStateD3,
+    NdisDeviceStateMaximum
+};
+
+struct NDIS_PM_WAKE_UP_CAPABILITIES {
+    enum NDIS_DEVICE_POWER_STATE MinMagicPacketWakeUp;
+    enum NDIS_DEVICE_POWER_STATE MinPatternWakeUp;
+    enum NDIS_DEVICE_POWER_STATE MinLinkChangeWakeUp;
+};
+
+/* NDIS_PNP_CAPABILITIES.Flags constants */
+#define NDIS_DEVICE_WAKE_UP_ENABLE               0x00000001
+#define NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002
+#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE  0x00000004
+
+/*
+struct NDIS_PNP_CAPABILITIES {
+	__le32					Flags;
+	struct NDIS_PM_WAKE_UP_CAPABILITIES	WakeUpCapabilities;
+};
+
+struct NDIS_PM_PACKET_PATTERN {
+	__le32	Priority;
+	__le32	Reserved;
+	__le32	MaskSize;
+	__le32	PatternOffset;
+	__le32	PatternSize;
+	__le32	PatternFlags;
+};
+*/
+
+/* Required Object IDs (OIDs) */
+#define OID_GEN_SUPPORTED_LIST          0x00010101
+#define OID_GEN_HARDWARE_STATUS         0x00010102
+#define OID_GEN_MEDIA_SUPPORTED         0x00010103
+#define OID_GEN_MEDIA_IN_USE            0x00010104
+#define OID_GEN_MAXIMUM_LOOKAHEAD       0x00010105
+#define OID_GEN_MAXIMUM_FRAME_SIZE      0x00010106
+#define OID_GEN_LINK_SPEED              0x00010107
+#define OID_GEN_TRANSMIT_BUFFER_SPACE   0x00010108
+#define OID_GEN_RECEIVE_BUFFER_SPACE    0x00010109
+#define OID_GEN_TRANSMIT_BLOCK_SIZE     0x0001010A
+#define OID_GEN_RECEIVE_BLOCK_SIZE      0x0001010B
+#define OID_GEN_VENDOR_ID               0x0001010C
+#define OID_GEN_VENDOR_DESCRIPTION      0x0001010D
+#define OID_GEN_CURRENT_PACKET_FILTER   0x0001010E
+#define OID_GEN_CURRENT_LOOKAHEAD       0x0001010F
+#define OID_GEN_DRIVER_VERSION          0x00010110
+#define OID_GEN_MAXIMUM_TOTAL_SIZE      0x00010111
+#define OID_GEN_PROTOCOL_OPTIONS        0x00010112
+#define OID_GEN_MAC_OPTIONS             0x00010113
+#define OID_GEN_MEDIA_CONNECT_STATUS    0x00010114
+#define OID_GEN_MAXIMUM_SEND_PACKETS    0x00010115
+#define OID_GEN_VENDOR_DRIVER_VERSION   0x00010116
+#define OID_GEN_SUPPORTED_GUIDS         0x00010117
+#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118
+#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119
+#define OID_GEN_MACHINE_NAME            0x0001021A
+#define OID_GEN_RNDIS_CONFIG_PARAMETER  0x0001021B
+#define OID_GEN_VLAN_ID                 0x0001021C
+
+/* Optional OIDs */
+#define OID_GEN_MEDIA_CAPABILITIES 0x00010201
+#define OID_GEN_PHYSICAL_MEDIUM    0x00010202
+
+/* Required statistics OIDs */
+#define OID_GEN_XMIT_OK       0x00020101
+#define OID_GEN_RCV_OK        0x00020102
+#define OID_GEN_XMIT_ERROR    0x00020103
+#define OID_GEN_RCV_ERROR     0x00020104
+#define OID_GEN_RCV_NO_BUFFER 0x00020105
+
+/* Optional statistics OIDs */
+#define OID_GEN_DIRECTED_BYTES_XMIT     0x00020201
+#define OID_GEN_DIRECTED_FRAMES_XMIT    0x00020202
+#define OID_GEN_MULTICAST_BYTES_XMIT    0x00020203
+#define OID_GEN_MULTICAST_FRAMES_XMIT   0x00020204
+#define OID_GEN_BROADCAST_BYTES_XMIT    0x00020205
+#define OID_GEN_BROADCAST_FRAMES_XMIT   0x00020206
+#define OID_GEN_DIRECTED_BYTES_RCV      0x00020207
+#define OID_GEN_DIRECTED_FRAMES_RCV     0x00020208
+#define OID_GEN_MULTICAST_BYTES_RCV     0x00020209
+#define OID_GEN_MULTICAST_FRAMES_RCV    0x0002020A
+#define OID_GEN_BROADCAST_BYTES_RCV     0x0002020B
+#define OID_GEN_BROADCAST_FRAMES_RCV    0x0002020C
+#define OID_GEN_RCV_CRC_ERROR           0x0002020D
+#define OID_GEN_TRANSMIT_QUEUE_LENGTH   0x0002020E
+#define OID_GEN_GET_TIME_CAPS           0x0002020F
+#define OID_GEN_GET_NETCARD_TIME        0x00020210
+#define OID_GEN_NETCARD_LOAD            0x00020211
+#define OID_GEN_DEVICE_PROFILE          0x00020212
+#define OID_GEN_INIT_TIME_MS            0x00020213
+#define OID_GEN_RESET_COUNTS            0x00020214
+#define OID_GEN_MEDIA_SENSE_COUNTS      0x00020215
+#define OID_GEN_FRIENDLY_NAME           0x00020216
+#define OID_GEN_MINIPORT_INFO           0x00020217
+#define OID_GEN_RESET_VERIFY_PARAMETERS 0x00020218
+
+/* IEEE 802.3 (Ethernet) OIDs */
+#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001
+
+#define OID_802_3_PERMANENT_ADDRESS      0x01010101
+#define OID_802_3_CURRENT_ADDRESS        0x01010102
+#define OID_802_3_MULTICAST_LIST         0x01010103
+#define OID_802_3_MAXIMUM_LIST_SIZE      0x01010104
+#define OID_802_3_MAC_OPTIONS            0x01010105
+#define OID_802_3_RCV_ERROR_ALIGNMENT    0x01020101
+#define OID_802_3_XMIT_ONE_COLLISION     0x01020102
+#define OID_802_3_XMIT_MORE_COLLISIONS   0x01020103
+#define OID_802_3_XMIT_DEFERRED          0x01020201
+#define OID_802_3_XMIT_MAX_COLLISIONS    0x01020202
+#define OID_802_3_RCV_OVERRUN            0x01020203
+#define OID_802_3_XMIT_UNDERRUN          0x01020204
+#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205
+#define OID_802_3_XMIT_TIMES_CRS_LOST    0x01020206
+#define OID_802_3_XMIT_LATE_COLLISIONS   0x01020207
+
+/* Wireless LAN OIDs */
+/* Mandatory */
+#define OID_802_11_BSSID               0x0D010101 /* Q  S     */
+#define OID_802_11_SSID                0x0D010102 /* Q  S     */
+#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204 /* Q  S     */
+#define OID_802_11_RSSI                0x0D010206 /* Q      I */
+#define OID_802_11_BSSID_LIST          0x0D010217 /* Q        */
+#define OID_802_11_BSSID_LIST_SCAN     0x0D01011A /*    S     */
+#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108 /* Q  S     */
+#define OID_802_11_SUPPORTED_RATES     0x0D01020E /* Q        */
+#define OID_802_11_CONFIGURATION       0x0D010211 /* Q  S     */
+#define OID_802_11_ADD_WEP             0x0D010113 /*    S     */
+#define OID_802_11_WEP_STATUS          0x0D01011B /* Q  S     */
+#define OID_802_11_REMOVE_WEP          0x0D010114 /*    S     */
+#define OID_802_11_DISASSOCIATE        0x0D010115 /*    S     */
+#define OID_802_11_AUTHENTICATION_MODE 0x0D010118 /* Q  S     */
+#define OID_802_11_RELOAD_DEFAULTS     0x0D01011C /*    S     */
+
+/* OID_GEN_MINIPORT_INFO constants */
+#define NDIS_MINIPORT_BUS_MASTER                     0x00000001
+#define NDIS_MINIPORT_WDM_DRIVER                     0x00000002
+#define NDIS_MINIPORT_SG_LIST                        0x00000004
+#define NDIS_MINIPORT_SUPPORTS_MEDIA_QUERY           0x00000008
+#define NDIS_MINIPORT_INDICATES_PACKETS              0x00000010
+#define NDIS_MINIPORT_IGNORE_PACKET_QUEUE            0x00000020
+#define NDIS_MINIPORT_IGNORE_REQUEST_QUEUE           0x00000040
+#define NDIS_MINIPORT_IGNORE_TOKEN_RING_ERRORS       0x00000080
+#define NDIS_MINIPORT_INTERMEDIATE_DRIVER            0x00000100
+#define NDIS_MINIPORT_IS_NDIS_5                      0x00000200
+#define NDIS_MINIPORT_IS_CO                          0x00000400
+#define NDIS_MINIPORT_DESERIALIZE                    0x00000800
+#define NDIS_MINIPORT_REQUIRES_MEDIA_POLLING         0x00001000
+#define NDIS_MINIPORT_SUPPORTS_MEDIA_SENSE           0x00002000
+#define NDIS_MINIPORT_NETBOOT_CARD                   0x00004000
+#define NDIS_MINIPORT_PM_SUPPORTED                   0x00008000
+#define NDIS_MINIPORT_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00010000
+#define NDIS_MINIPORT_USES_SAFE_BUFFER_APIS          0x00020000
+#define NDIS_MINIPORT_HIDDEN                         0x00040000
+#define NDIS_MINIPORT_SWENUM                         0x00080000
+#define NDIS_MINIPORT_SURPRISE_REMOVE_OK             0x00100000
+#define NDIS_MINIPORT_NO_HALT_ON_SUSPEND             0x00200000
+#define NDIS_MINIPORT_HARDWARE_DEVICE                0x00400000
+#define NDIS_MINIPORT_SUPPORTS_CANCEL_SEND_PACKETS   0x00800000
+#define NDIS_MINIPORT_64BITS_DMA                     0x01000000
+
+#define NDIS_MEDIUM_802_3        0x00000000
+#define NDIS_MEDIUM_802_5        0x00000001
+#define NDIS_MEDIUM_FDDI         0x00000002
+#define NDIS_MEDIUM_WAN          0x00000003
+#define NDIS_MEDIUM_LOCAL_TALK   0x00000004
+#define NDIS_MEDIUM_DIX          0x00000005
+#define NDIS_MEDIUM_ARCENT_RAW   0x00000006
+#define NDIS_MEDIUM_ARCENT_878_2 0x00000007
+#define NDIS_MEDIUM_ATM          0x00000008
+#define NDIS_MEDIUM_WIRELESS_LAN 0x00000009
+#define NDIS_MEDIUM_IRDA         0x0000000A
+#define NDIS_MEDIUM_BPC          0x0000000B
+#define NDIS_MEDIUM_CO_WAN       0x0000000C
+#define NDIS_MEDIUM_1394         0x0000000D
+
+#define NDIS_PACKET_TYPE_DIRECTED       0x00000001
+#define NDIS_PACKET_TYPE_MULTICAST      0x00000002
+#define NDIS_PACKET_TYPE_ALL_MULTICAST  0x00000004
+#define NDIS_PACKET_TYPE_BROADCAST      0x00000008
+#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010
+#define NDIS_PACKET_TYPE_PROMISCUOUS    0x00000020
+#define NDIS_PACKET_TYPE_SMT            0x00000040
+#define NDIS_PACKET_TYPE_ALL_LOCAL      0x00000080
+#define NDIS_PACKET_TYPE_GROUP          0x00000100
+#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200
+#define NDIS_PACKET_TYPE_FUNCTIONAL     0x00000400
+#define NDIS_PACKET_TYPE_MAC_FRAME      0x00000800
+
+#define NDIS_MEDIA_STATE_CONNECTED    0x00000000
+#define NDIS_MEDIA_STATE_DISCONNECTED 0x00000001
+
+#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001
+#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED  0x00000002
+#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND  0x00000004
+#define NDIS_MAC_OPTION_NO_LOOPBACK         0x00000008
+#define NDIS_MAC_OPTION_FULL_DUPLEX         0x00000010
+#define NDIS_MAC_OPTION_EOTX_INDICATION     0x00000020
+#define NDIS_MAC_OPTION_8021P_PRIORITY      0x00000040
+#define NDIS_MAC_OPTION_RESERVED            0x80000000
+
+/** Hardware status of the underlying NIC */
+#define NDIS_HW_STS_READY        0x00000000UL
+#define NDIS_HW_STS_INITIALIZING 0x00000001UL
+#define NDIS_HW_STS_RESET        0x00000002UL
+#define NDIS_HW_STS_CLOSING      0x00000003UL
+#define NDIS_HW_STS_NOT_READY    0x00000004UL
+
+#endif /* _LINUX_NDIS_H */
+
+/** @} */

+ 302 - 0
components/drivers/usb/cherryusb/class/wireless/rndis_protocol.h

@@ -0,0 +1,302 @@
+/**
+ * \file rndis_protocol.h
+ *         RNDIS Defines
+ *
+ * \author
+ *         Colin O'Flynn <coflynn@newae.com>
+ *
+ * \addtogroup usbstick
+ */
+
+/* Copyright (c) 2008  Colin O'Flynn
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+   * Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+   * Neither the name of the copyright holders nor the names of
+     contributors may be used to endorse or promote products derived
+     from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _RNDIS_H
+#define _RNDIS_H
+
+/**
+  \addtogroup RNDIS
+  @{
+  */
+
+#include <stdint.h>
+
+#define RNDIS_MAJOR_VERSION 1
+#define RNDIS_MINOR_VERSION 0
+
+#define RNDIS_STATUS_SUCCESS          0X00000000
+#define RNDIS_STATUS_FAILURE          0XC0000001
+#define RNDIS_STATUS_INVALID_DATA     0XC0010015
+#define RNDIS_STATUS_NOT_SUPPORTED    0XC00000BB
+#define RNDIS_STATUS_MEDIA_CONNECT    0X4001000B
+#define RNDIS_STATUS_MEDIA_DISCONNECT 0X4001000C
+
+/* Message set for Connectionless (802.3) Devices */
+#define REMOTE_NDIS_PACKET_MSG          0x00000001
+#define REMOTE_NDIS_INITIALIZE_MSG      0X00000002
+#define REMOTE_NDIS_HALT_MSG            0X00000003
+#define REMOTE_NDIS_QUERY_MSG           0X00000004
+#define REMOTE_NDIS_SET_MSG             0X00000005
+#define REMOTE_NDIS_RESET_MSG           0X00000006
+#define REMOTE_NDIS_INDICATE_STATUS_MSG 0X00000007
+#define REMOTE_NDIS_KEEPALIVE_MSG       0X00000008
+#define REMOTE_NDIS_INITIALIZE_CMPLT    0X80000002
+#define REMOTE_NDIS_QUERY_CMPLT         0X80000004
+#define REMOTE_NDIS_SET_CMPLT           0X80000005
+#define REMOTE_NDIS_RESET_CMPLT         0X80000006
+#define REMOTE_NDIS_KEEPALIVE_CMPLT     0X80000008
+
+typedef uint32_t rndis_MessageType_t;
+typedef uint32_t rndis_MessageLength_t;
+typedef uint32_t rndis_RequestId_t;
+typedef uint32_t rndis_MajorVersion_t;
+typedef uint32_t rndis_MinorVersion_t;
+typedef uint32_t rndis_MaxTransferSize_t;
+typedef uint32_t rndis_Status_t;
+
+/* Device Flags */
+#define RNDIS_DF_CONNECTIONLESS      0x00000001
+#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002
+typedef uint32_t rndis_DeviceFlags_t;
+
+/* Mediums */
+#define RNDIS_MEDIUM_802_3 0x00000000
+typedef uint32_t rndis_Medium_t;
+
+typedef uint32_t rndis_MaxPacketsPerTransfer_t;
+typedef uint32_t rndis_PacketAlignmentFactor_t;
+typedef uint32_t rndis_AfListOffset_t;
+typedef uint32_t rndis_AfListSize_t;
+
+/*** Remote NDIS Generic Message type ***/
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+} rndis_generic_msg_t;
+
+/*** Remote NDIS Initialize Message ***/
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_RequestId_t RequestId;
+    rndis_MajorVersion_t MajorVersion;
+    rndis_MinorVersion_t MinorVersion;
+    rndis_MaxTransferSize_t MaxTransferSize;
+} rndis_initialize_msg_t;
+
+/* Response: */
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_RequestId_t RequestId;
+    rndis_Status_t Status;
+    rndis_MajorVersion_t MajorVersion;
+    rndis_MinorVersion_t MinorVersion;
+    rndis_DeviceFlags_t DeviceFlags;
+    rndis_Medium_t Medium;
+    rndis_MaxPacketsPerTransfer_t MaxPacketsPerTransfer;
+    rndis_MaxTransferSize_t MaxTransferSize;
+    rndis_PacketAlignmentFactor_t PacketAlignmentFactor;
+    rndis_AfListOffset_t AfListOffset;
+    rndis_AfListSize_t AfListSize;
+} rndis_initialize_cmplt_t;
+
+/*** Remote NDIS Halt Message ***/
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_RequestId_t RequestId;
+} rndis_halt_msg_t;
+
+typedef uint32_t rndis_Oid_t;
+typedef uint32_t rndis_InformationBufferLength_t;
+typedef uint32_t rndis_InformationBufferOffset_t;
+typedef uint32_t rndis_DeviceVcHandle_t;
+
+/*** Remote NDIS Query Message ***/
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_RequestId_t RequestId;
+    rndis_Oid_t Oid;
+    rndis_InformationBufferLength_t InformationBufferLength;
+    rndis_InformationBufferOffset_t InformationBufferOffset;
+    rndis_DeviceVcHandle_t DeviceVcHandle;
+} rndis_query_msg_t;
+
+/* Response: */
+
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_RequestId_t RequestId;
+    rndis_Status_t Status;
+    rndis_InformationBufferLength_t InformationBufferLength;
+    rndis_InformationBufferOffset_t InformationBufferOffset;
+} rndis_query_cmplt_t;
+
+/*** Remote NDIS Set Message ***/
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_RequestId_t RequestId;
+    rndis_Oid_t Oid;
+    rndis_InformationBufferLength_t InformationBufferLength;
+    rndis_InformationBufferOffset_t InformationBufferOffset;
+    rndis_DeviceVcHandle_t DeviceVcHandle;
+} rndis_set_msg_t;
+
+/* Response */
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_RequestId_t RequestId;
+    rndis_Status_t Status;
+} rndis_set_cmplt_t;
+
+/* Information buffer layout for OID_GEN_RNDIS_CONFIG_PARAMETER */
+typedef uint32_t rndis_ParameterNameOffset_t;
+typedef uint32_t rndis_ParameterNameLength_t;
+typedef uint32_t rndis_ParameterType_t;
+typedef uint32_t rndis_ParameterValueOffset_t;
+typedef uint32_t rndis_ParameterValueLength_t;
+
+#define PARAMETER_TYPE_STRING    2
+#define PARAMETER_TYPE_NUMERICAL 0
+
+typedef struct {
+    rndis_ParameterNameOffset_t ParameterNameOffset;
+    rndis_ParameterNameLength_t ParameterNameLength;
+    rndis_ParameterType_t ParameterType;
+    rndis_ParameterValueOffset_t ParameterValueOffset;
+    rndis_ParameterValueLength_t ParameterValueLength;
+} rndis_config_parameter_t;
+
+typedef uint32_t rndis_Reserved_t;
+
+/*** Remote NDIS Soft Reset Message ***/
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_Reserved_t Reserved;
+} rndis_reset_msg_t;
+
+typedef uint32_t rndis_AddressingReset_t;
+
+/* Response: */
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_Status_t Status;
+    rndis_AddressingReset_t AddressingReset;
+} rndis_reset_cmplt_t;
+
+/*** Remote NDIS Indicate Status Message ***/
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_Status_t Status;
+    rndis_Status_t StatusBufferLength;
+    rndis_Status_t StatusBufferOffset;
+} rndis_indicate_status_t;
+
+typedef uint32_t rndis_DiagStatus_t;
+typedef uint32_t rndis_ErrorOffset_t;
+
+typedef struct {
+    rndis_DiagStatus_t DiagStatus;
+    rndis_ErrorOffset_t ErrorOffset;
+} rndis_diagnostic_info_t;
+
+/*** Remote NDIS Keepalive Message */
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_RequestId_t RequestId;
+} rndis_keepalive_msg_t;
+
+/* Response: */
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_RequestId_t RequestId;
+    rndis_Status_t Status;
+} rndis_keepalive_cmplt_t;
+
+/*** Remote NDIS Data Packet ***/
+
+typedef uint32_t rndis_DataOffset_t;
+typedef uint32_t rndis_DataLength_t;
+typedef uint32_t rndis_OOBDataOffset_t;
+typedef uint32_t rndis_OOBDataLength_t;
+typedef uint32_t rndis_NumOOBDataElements_t;
+typedef uint32_t rndis_PerPacketInfoOffset_t;
+typedef uint32_t rndis_PerPacketInfoLength_t;
+
+typedef struct {
+    rndis_MessageType_t MessageType;
+    rndis_MessageLength_t MessageLength;
+    rndis_DataOffset_t DataOffset;
+    rndis_DataLength_t DataLength;
+    rndis_OOBDataOffset_t OOBDataOffset;
+    rndis_OOBDataLength_t OOBDataLength;
+    rndis_NumOOBDataElements_t NumOOBDataElements;
+    rndis_PerPacketInfoOffset_t PerPacketInfoOffset;
+    rndis_PerPacketInfoLength_t PerPacketInfoLength;
+    rndis_DeviceVcHandle_t DeviceVcHandle;
+    rndis_Reserved_t Reserved;
+} rndis_data_packet_t;
+
+typedef uint32_t rndis_ClassInformationOffset_t;
+typedef uint32_t rndis_Size_t;
+typedef uint32_t rndis_Type_t;
+
+typedef struct {
+    rndis_Size_t Size;
+    rndis_Type_t Type;
+    rndis_ClassInformationOffset_t ClassInformationType;
+} rndis_OOB_packet_t;
+
+#include "ndis.h"
+
+typedef enum rnids_state_e {
+    rndis_uninitialized,
+    rndis_initialized,
+    rndis_data_initialized
+} rndis_state_t;
+
+typedef struct {
+    uint32_t txok;
+    uint32_t rxok;
+    uint32_t txbad;
+    uint32_t rxbad;
+} usb_eth_stat_t;
+
+#endif /* _RNDIS_H */
+
+/** @} */

+ 566 - 0
components/drivers/usb/cherryusb/class/wireless/usbd_rndis.c

@@ -0,0 +1,566 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_rndis.h"
+#include "rndis_protocol.h"
+
+#define RNDIS_OUT_EP_IDX 0
+#define RNDIS_IN_EP_IDX  1
+#define RNDIS_INT_EP_IDX 2
+
+/* Describe EndPoints configuration */
+static struct usbd_endpoint rndis_ep_data[3];
+
+#define RNDIS_INQUIRY_PUT(src, len)   (memcpy(infomation_buffer, src, len))
+#define RNDIS_INQUIRY_PUT_LE32(value) (*(uint32_t *)infomation_buffer = (value))
+
+/* Device data structure */
+struct usbd_rndis_priv {
+    uint32_t drv_version;
+    uint32_t link_status;
+    uint32_t net_filter;
+    usb_eth_stat_t eth_state;
+    rndis_state_t init_state;
+    uint8_t mac[6];
+} g_usbd_rndis;
+
+#if CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE < 140
+#undef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
+#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
+#endif
+
+#if CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE < 1580
+#undef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
+#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
+#endif
+
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE];
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t rndis_encapsulated_resp_buffer[CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t NOTIFY_RESPONSE_AVAILABLE[8];
+
+volatile uint8_t *g_rndis_rx_data_buffer;
+volatile uint32_t g_rndis_rx_data_length;
+volatile uint32_t g_rndis_tx_data_length;
+
+/* RNDIS options list */
+const uint32_t oid_supported_list[] = {
+    /* General OIDs */
+    OID_GEN_SUPPORTED_LIST,
+    OID_GEN_HARDWARE_STATUS,
+    OID_GEN_MEDIA_SUPPORTED,
+    OID_GEN_MEDIA_IN_USE,
+    OID_GEN_MAXIMUM_FRAME_SIZE,
+    OID_GEN_LINK_SPEED,
+    OID_GEN_TRANSMIT_BLOCK_SIZE,
+    OID_GEN_RECEIVE_BLOCK_SIZE,
+    OID_GEN_VENDOR_ID,
+    OID_GEN_VENDOR_DESCRIPTION,
+    OID_GEN_VENDOR_DRIVER_VERSION,
+    OID_GEN_CURRENT_PACKET_FILTER,
+    OID_GEN_MAXIMUM_TOTAL_SIZE,
+    OID_GEN_MEDIA_CONNECT_STATUS,
+
+    OID_GEN_PHYSICAL_MEDIUM,
+
+    /* General Statistic OIDs */
+    OID_GEN_XMIT_OK,
+    OID_GEN_RCV_OK,
+    OID_GEN_XMIT_ERROR,
+    OID_GEN_RCV_ERROR,
+    OID_GEN_RCV_NO_BUFFER,
+
+    /* Please configure us */
+    OID_GEN_RNDIS_CONFIG_PARAMETER,
+
+    /* 802.3 OIDs */
+    OID_802_3_PERMANENT_ADDRESS,
+    OID_802_3_CURRENT_ADDRESS,
+    OID_802_3_MULTICAST_LIST,
+    OID_802_3_MAXIMUM_LIST_SIZE,
+
+    /* 802.3 Statistic OIDs */
+    OID_802_3_RCV_ERROR_ALIGNMENT,
+    OID_802_3_XMIT_ONE_COLLISION,
+    OID_802_3_XMIT_MORE_COLLISIONS,
+
+    OID_802_3_MAC_OPTIONS,
+};
+
+static int rndis_encapsulated_cmd_handler(uint8_t *data, uint32_t len);
+
+static void rndis_notify_rsp(void)
+{
+    memset(NOTIFY_RESPONSE_AVAILABLE, 0, 8);
+    NOTIFY_RESPONSE_AVAILABLE[0] = 0x01;
+    usbd_ep_start_write(0, rndis_ep_data[RNDIS_INT_EP_IDX].ep_addr, NOTIFY_RESPONSE_AVAILABLE, 8);
+}
+
+static int rndis_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+    switch (setup->bRequest) {
+        case CDC_REQUEST_SEND_ENCAPSULATED_COMMAND:
+            rndis_encapsulated_cmd_handler(*data, setup->wLength);
+            break;
+        case CDC_REQUEST_GET_ENCAPSULATED_RESPONSE:
+            *data = rndis_encapsulated_resp_buffer;
+            *len = ((rndis_generic_msg_t *)rndis_encapsulated_resp_buffer)->MessageLength;
+            break;
+
+        default:
+            return -1;
+    }
+
+    return 0;
+}
+
+static int rndis_init_cmd_handler(uint8_t *data, uint32_t len);
+static int rndis_halt_cmd_handler(uint8_t *data, uint32_t len);
+static int rndis_query_cmd_handler(uint8_t *data, uint32_t len);
+static int rndis_set_cmd_handler(uint8_t *data, uint32_t len);
+static int rndis_reset_cmd_handler(uint8_t *data, uint32_t len);
+static int rndis_keepalive_cmd_handler(uint8_t *data, uint32_t len);
+
+static int rndis_encapsulated_cmd_handler(uint8_t *data, uint32_t len)
+{
+    switch (((rndis_generic_msg_t *)data)->MessageType) {
+        case REMOTE_NDIS_INITIALIZE_MSG:
+            return rndis_init_cmd_handler(data, len);
+        case REMOTE_NDIS_HALT_MSG:
+            return rndis_halt_cmd_handler(data, len);
+        case REMOTE_NDIS_QUERY_MSG:
+            return rndis_query_cmd_handler(data, len);
+        case REMOTE_NDIS_SET_MSG:
+            return rndis_set_cmd_handler(data, len);
+        case REMOTE_NDIS_RESET_MSG:
+            return rndis_reset_cmd_handler(data, len);
+        case REMOTE_NDIS_KEEPALIVE_MSG:
+            return rndis_keepalive_cmd_handler(data, len);
+
+        default:
+            break;
+    }
+    return -1;
+}
+
+static int rndis_init_cmd_handler(uint8_t *data, uint32_t len)
+{
+    rndis_initialize_msg_t *cmd = (rndis_initialize_msg_t *)data;
+    rndis_initialize_cmplt_t *resp;
+
+    resp = ((rndis_initialize_cmplt_t *)rndis_encapsulated_resp_buffer);
+    resp->RequestId = cmd->RequestId;
+    resp->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
+    resp->MessageLength = sizeof(rndis_initialize_cmplt_t);
+    resp->MajorVersion = RNDIS_MAJOR_VERSION;
+    resp->MinorVersion = RNDIS_MINOR_VERSION;
+    resp->Status = RNDIS_STATUS_SUCCESS;
+    resp->DeviceFlags = RNDIS_DF_CONNECTIONLESS;
+    resp->Medium = RNDIS_MEDIUM_802_3;
+    resp->MaxPacketsPerTransfer = CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE / 1580;
+    resp->MaxTransferSize = CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE;
+    resp->PacketAlignmentFactor = 0;
+    resp->AfListOffset = 0;
+    resp->AfListSize = 0;
+
+    g_usbd_rndis.init_state = rndis_initialized;
+
+    rndis_notify_rsp();
+    return 0;
+}
+
+static int rndis_halt_cmd_handler(uint8_t *data, uint32_t len)
+{
+    rndis_halt_msg_t *resp;
+
+    resp = ((rndis_halt_msg_t *)rndis_encapsulated_resp_buffer);
+    resp->MessageLength = 0;
+
+    g_usbd_rndis.init_state = rndis_uninitialized;
+
+    return 0;
+}
+
+static int rndis_query_cmd_handler(uint8_t *data, uint32_t len)
+{
+    rndis_query_msg_t *cmd = (rndis_query_msg_t *)data;
+    rndis_query_cmplt_t *resp;
+    uint8_t *infomation_buffer;
+    uint32_t infomation_len = 0;
+
+    resp = ((rndis_query_cmplt_t *)rndis_encapsulated_resp_buffer);
+    resp->MessageType = REMOTE_NDIS_QUERY_CMPLT;
+    resp->RequestId = cmd->RequestId;
+    resp->InformationBufferOffset = sizeof(rndis_query_cmplt_t) - sizeof(rndis_generic_msg_t);
+    resp->Status = RNDIS_STATUS_SUCCESS;
+
+    infomation_buffer = (uint8_t *)resp + sizeof(rndis_query_cmplt_t);
+
+    switch (cmd->Oid) {
+        case OID_GEN_SUPPORTED_LIST:
+            RNDIS_INQUIRY_PUT(oid_supported_list, sizeof(oid_supported_list));
+            infomation_len = sizeof(oid_supported_list);
+            break;
+        case OID_GEN_HARDWARE_STATUS:
+            RNDIS_INQUIRY_PUT_LE32(NDIS_HW_STS_READY);
+            infomation_len = 4;
+            break;
+        case OID_GEN_MEDIA_SUPPORTED:
+        case OID_GEN_MEDIA_IN_USE:
+            RNDIS_INQUIRY_PUT_LE32(NDIS_MEDIUM_802_3);
+            infomation_len = 4;
+            break;
+        case OID_GEN_MAXIMUM_FRAME_SIZE:
+        case OID_GEN_TRANSMIT_BLOCK_SIZE:
+        case OID_GEN_RECEIVE_BLOCK_SIZE:
+            RNDIS_INQUIRY_PUT_LE32(0x05DC);
+            infomation_len = 4;
+            break;
+        case OID_GEN_VENDOR_ID:
+            RNDIS_INQUIRY_PUT_LE32(CONFIG_USBDEV_RNDIS_VENDOR_ID);
+            infomation_len = 4;
+            break;
+        case OID_GEN_VENDOR_DRIVER_VERSION:
+            RNDIS_INQUIRY_PUT_LE32(0x0001);
+            infomation_len = 4;
+            break;
+        case OID_GEN_VENDOR_DESCRIPTION:
+            RNDIS_INQUIRY_PUT(CONFIG_USBDEV_RNDIS_VENDOR_DESC, strlen(CONFIG_USBDEV_RNDIS_VENDOR_DESC));
+            infomation_len = (strlen(CONFIG_USBDEV_RNDIS_VENDOR_DESC) + 1);
+            break;
+        case OID_802_3_CURRENT_ADDRESS:
+        case OID_802_3_PERMANENT_ADDRESS:
+            RNDIS_INQUIRY_PUT(g_usbd_rndis.mac, 6);
+            infomation_len = 6;
+            break;
+        case OID_GEN_PHYSICAL_MEDIUM:
+            RNDIS_INQUIRY_PUT_LE32(NDIS_MEDIUM_802_3);
+            infomation_len = 4;
+            break;
+        case OID_GEN_LINK_SPEED:
+            if (usbd_get_ep_mps(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr) > 64) {
+                RNDIS_INQUIRY_PUT_LE32(480000000 / 100);
+            } else {
+                RNDIS_INQUIRY_PUT_LE32(12000000 / 100);
+            }
+
+            infomation_len = 4;
+            break;
+        case OID_GEN_CURRENT_PACKET_FILTER:
+            RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.net_filter);
+            infomation_len = 4;
+            break;
+        case OID_GEN_MAXIMUM_TOTAL_SIZE:
+            RNDIS_INQUIRY_PUT_LE32(CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE + CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE);
+            infomation_len = 4;
+            break;
+        case OID_GEN_MEDIA_CONNECT_STATUS:
+            RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.link_status);
+            infomation_len = 4;
+            break;
+        case OID_GEN_RNDIS_CONFIG_PARAMETER:
+            RNDIS_INQUIRY_PUT_LE32(0);
+            infomation_len = 4;
+            break;
+        case OID_802_3_MAXIMUM_LIST_SIZE:
+            RNDIS_INQUIRY_PUT_LE32(1); /* one address */
+            infomation_len = 4;
+            break;
+        case OID_802_3_MULTICAST_LIST:
+            //RNDIS_INQUIRY_PUT_LE32(0xE0000000); /* 224.0.0.0 */
+            resp->Status = RNDIS_STATUS_NOT_SUPPORTED;
+            RNDIS_INQUIRY_PUT_LE32(0);
+            infomation_len = 4;
+            break;
+        case OID_802_3_MAC_OPTIONS:
+            // infomation_len = 0;
+            resp->Status = RNDIS_STATUS_NOT_SUPPORTED;
+            RNDIS_INQUIRY_PUT_LE32(0);
+            infomation_len = 4;
+            break;
+        case OID_GEN_MAC_OPTIONS:
+            RNDIS_INQUIRY_PUT_LE32(0);
+            infomation_len = 4;
+            break;
+        case OID_802_3_RCV_ERROR_ALIGNMENT:
+            RNDIS_INQUIRY_PUT_LE32(0);
+            infomation_len = 4;
+            break;
+        case OID_802_3_XMIT_ONE_COLLISION:
+            RNDIS_INQUIRY_PUT_LE32(0);
+            infomation_len = 4;
+            break;
+        case OID_802_3_XMIT_MORE_COLLISIONS:
+            RNDIS_INQUIRY_PUT_LE32(0);
+            infomation_len = 4;
+            break;
+        case OID_GEN_XMIT_OK:
+            RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.eth_state.txok);
+            infomation_len = 4;
+            break;
+        case OID_GEN_RCV_OK:
+            RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.eth_state.rxok);
+            infomation_len = 4;
+            break;
+        case OID_GEN_RCV_ERROR:
+            RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.eth_state.rxbad);
+            infomation_len = 4;
+            break;
+        case OID_GEN_XMIT_ERROR:
+            RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.eth_state.txbad);
+            infomation_len = 4;
+            break;
+        case OID_GEN_RCV_NO_BUFFER:
+            RNDIS_INQUIRY_PUT_LE32(0);
+            infomation_len = 4;
+            break;
+        default:
+            resp->Status = RNDIS_STATUS_FAILURE;
+            infomation_len = 0;
+            USB_LOG_WRN("Unhandled query for Object ID 0x%x\r\n", cmd->Oid);
+            break;
+    }
+
+    resp->MessageLength = sizeof(rndis_query_cmplt_t) + infomation_len;
+    resp->InformationBufferLength = infomation_len;
+
+    rndis_notify_rsp();
+    return 0;
+}
+
+static int rndis_set_cmd_handler(uint8_t *data, uint32_t len)
+{
+    rndis_set_msg_t *cmd = (rndis_set_msg_t *)data;
+    rndis_set_cmplt_t *resp;
+    rndis_config_parameter_t *param;
+
+    resp = ((rndis_set_cmplt_t *)rndis_encapsulated_resp_buffer);
+    resp->RequestId = cmd->RequestId;
+    resp->MessageType = REMOTE_NDIS_SET_CMPLT;
+    resp->MessageLength = sizeof(rndis_set_cmplt_t);
+    resp->Status = RNDIS_STATUS_SUCCESS;
+
+    switch (cmd->Oid) {
+        case OID_GEN_RNDIS_CONFIG_PARAMETER:
+            param = (rndis_config_parameter_t *)((uint8_t *)&(cmd->RequestId) + cmd->InformationBufferOffset);
+            USB_LOG_WRN("RNDIS cfg param: NameOfs=%d, NameLen=%d, ValueOfs=%d, ValueLen=%d\r\n",
+                        param->ParameterNameOffset, param->ParameterNameLength,
+                        param->ParameterValueOffset, param->ParameterValueLength);
+            break;
+        case OID_GEN_CURRENT_PACKET_FILTER:
+            if (cmd->InformationBufferLength < sizeof(g_usbd_rndis.net_filter)) {
+                USB_LOG_WRN("PACKET_FILTER!\r\n");
+                resp->Status = RNDIS_STATUS_INVALID_DATA;
+            } else {
+                uint32_t *filter;
+                /* Parameter starts at offset buf_offset of the req_id field */
+                filter = (uint32_t *)((uint8_t *)&(cmd->RequestId) + cmd->InformationBufferOffset);
+
+                //g_usbd_rndis.net_filter = param->ParameterNameOffset;
+                g_usbd_rndis.net_filter = *(uint32_t *)filter;
+                if (g_usbd_rndis.net_filter) {
+                    g_usbd_rndis.init_state = rndis_data_initialized;
+                } else {
+                    g_usbd_rndis.init_state = rndis_initialized;
+                }
+            }
+            break;
+        case OID_GEN_CURRENT_LOOKAHEAD:
+            break;
+        case OID_GEN_PROTOCOL_OPTIONS:
+            break;
+        case OID_802_3_MULTICAST_LIST:
+            break;
+        case OID_PNP_ADD_WAKE_UP_PATTERN:
+        case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+        case OID_PNP_ENABLE_WAKE_UP:
+        default:
+            resp->Status = RNDIS_STATUS_FAILURE;
+            USB_LOG_WRN("Unhandled query for Object ID 0x%x\r\n", cmd->Oid);
+            break;
+    }
+
+    rndis_notify_rsp();
+
+    return 0;
+}
+
+static int rndis_reset_cmd_handler(uint8_t *data, uint32_t len)
+{
+    // rndis_reset_msg_t *cmd = (rndis_reset_msg_t *)data;
+    rndis_reset_cmplt_t *resp;
+
+    resp = ((rndis_reset_cmplt_t *)rndis_encapsulated_resp_buffer);
+    resp->MessageType = REMOTE_NDIS_RESET_CMPLT;
+    resp->MessageLength = sizeof(rndis_reset_cmplt_t);
+    resp->Status = RNDIS_STATUS_SUCCESS;
+    resp->AddressingReset = 1;
+
+    g_usbd_rndis.init_state = rndis_uninitialized;
+
+    rndis_notify_rsp();
+
+    return 0;
+}
+
+static int rndis_keepalive_cmd_handler(uint8_t *data, uint32_t len)
+{
+    rndis_keepalive_msg_t *cmd = (rndis_keepalive_msg_t *)data;
+    rndis_keepalive_cmplt_t *resp;
+
+    resp = ((rndis_keepalive_cmplt_t *)rndis_encapsulated_resp_buffer);
+    resp->RequestId = cmd->RequestId;
+    resp->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
+    resp->MessageLength = sizeof(rndis_keepalive_cmplt_t);
+    resp->Status = RNDIS_STATUS_SUCCESS;
+
+    rndis_notify_rsp();
+
+    return 0;
+}
+
+static void rndis_notify_handler(uint8_t busid, uint8_t event, void *arg)
+{
+    switch (event) {
+        case USBD_EVENT_RESET:
+            g_usbd_rndis.link_status = NDIS_MEDIA_STATE_DISCONNECTED;
+            break;
+        case USBD_EVENT_CONFIGURED:
+            g_rndis_rx_data_length = 0;
+            g_rndis_tx_data_length = 0;
+            g_usbd_rndis.link_status = NDIS_MEDIA_STATE_CONNECTED;
+            usbd_ep_start_read(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
+            break;
+
+        default:
+            break;
+    }
+}
+
+void rndis_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+    rndis_data_packet_t *hdr;
+
+    hdr = (rndis_data_packet_t *)g_rndis_rx_buffer;
+    g_rndis_rx_data_buffer = g_rndis_rx_buffer;
+    if ((hdr->MessageType != REMOTE_NDIS_PACKET_MSG) || (nbytes < hdr->MessageLength)) {
+        usbd_ep_start_read(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
+        return;
+    }
+
+    /* Point to the payload and update the message length */
+    g_rndis_rx_data_buffer += hdr->DataOffset + sizeof(rndis_generic_msg_t);
+    g_rndis_rx_data_length = hdr->DataLength;
+
+    usbd_rndis_data_recv_done();
+}
+
+void rndis_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+    if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
+        /* send zlp */
+        usbd_ep_start_write(0, ep, NULL, 0);
+    } else {
+        g_rndis_tx_data_length = 0;
+    }
+}
+
+void rndis_int_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+    //USB_LOG_DBG("len:%d\r\n", nbytes);
+}
+
+#ifdef CONFIG_USBDEV_RNDIS_USING_LWIP
+#include <lwip/pbuf.h>
+
+struct pbuf *usbd_rndis_eth_rx(void)
+{
+    struct pbuf *p;
+
+    if (g_rndis_rx_data_length == 0) {
+        return NULL;
+    }
+    p = pbuf_alloc(PBUF_RAW, g_rndis_rx_data_length, PBUF_POOL);
+    if (p == NULL) {
+        return NULL;
+    }
+    memcpy(p->payload, (uint8_t *)g_rndis_rx_data_buffer, g_rndis_rx_data_length);
+    p->len = g_rndis_rx_data_length;
+
+    USB_LOG_DBG("rxlen:%d\r\n", g_rndis_rx_data_length);
+    g_rndis_rx_data_length = 0;
+    usbd_ep_start_read(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
+
+    return p;
+}
+
+int usbd_rndis_eth_tx(struct pbuf *p)
+{
+    struct pbuf *q;
+    uint8_t *buffer;
+    rndis_data_packet_t *hdr;
+
+    if (g_usbd_rndis.link_status == NDIS_MEDIA_STATE_DISCONNECTED) {
+        return -USB_ERR_NOTCONN;
+    }
+
+    if (g_rndis_tx_data_length > 0) {
+        return -USB_ERR_BUSY;
+    }
+
+    if (p->tot_len > sizeof(g_rndis_tx_buffer)) {
+        p->tot_len = sizeof(g_rndis_tx_buffer);
+    }
+
+    buffer = (uint8_t *)(g_rndis_tx_buffer + sizeof(rndis_data_packet_t));
+    for (q = p; q != NULL; q = q->next) {
+        memcpy(buffer, q->payload, q->len);
+        buffer += q->len;
+    }
+
+    hdr = (rndis_data_packet_t *)g_rndis_tx_buffer;
+
+    memset(hdr, 0, sizeof(rndis_data_packet_t));
+    hdr->MessageType = REMOTE_NDIS_PACKET_MSG;
+    hdr->MessageLength = sizeof(rndis_data_packet_t) + p->tot_len;
+    hdr->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_generic_msg_t);
+    hdr->DataLength = p->tot_len;
+
+    g_rndis_tx_data_length = sizeof(rndis_data_packet_t) + p->tot_len;
+
+    USB_LOG_DBG("txlen:%d\r\n", g_rndis_tx_data_length);
+    return usbd_ep_start_write(0, rndis_ep_data[RNDIS_IN_EP_IDX].ep_addr, g_rndis_tx_buffer, g_rndis_tx_data_length);
+}
+#endif
+struct usbd_interface *usbd_rndis_init_intf(struct usbd_interface *intf,
+                                            const uint8_t out_ep,
+                                            const uint8_t in_ep,
+                                            const uint8_t int_ep, uint8_t mac[6])
+{
+    memcpy(g_usbd_rndis.mac, mac, 6);
+
+    g_usbd_rndis.drv_version = 0x0001;
+    g_usbd_rndis.link_status = NDIS_MEDIA_STATE_DISCONNECTED;
+
+    rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr = out_ep;
+    rndis_ep_data[RNDIS_OUT_EP_IDX].ep_cb = rndis_bulk_out;
+    rndis_ep_data[RNDIS_IN_EP_IDX].ep_addr = in_ep;
+    rndis_ep_data[RNDIS_IN_EP_IDX].ep_cb = rndis_bulk_in;
+    rndis_ep_data[RNDIS_INT_EP_IDX].ep_addr = int_ep;
+    rndis_ep_data[RNDIS_INT_EP_IDX].ep_cb = rndis_int_in;
+
+    usbd_add_endpoint(0, &rndis_ep_data[RNDIS_OUT_EP_IDX]);
+    usbd_add_endpoint(0, &rndis_ep_data[RNDIS_IN_EP_IDX]);
+    usbd_add_endpoint(0, &rndis_ep_data[RNDIS_INT_EP_IDX]);
+
+    intf->class_interface_handler = rndis_class_interface_request_handler;
+    intf->class_endpoint_handler = NULL;
+    intf->vendor_handler = NULL;
+    intf->notify_handler = rndis_notify_handler;
+
+    return intf;
+}

+ 32 - 0
components/drivers/usb/cherryusb/class/wireless/usbd_rndis.h

@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_RNDIS_H
+#define USBD_RNDIS_H
+
+#include "usb_cdc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Init rndis interface driver */
+struct usbd_interface *usbd_rndis_init_intf(struct usbd_interface *intf,
+                                             const uint8_t out_ep,
+                                             const uint8_t in_ep,
+                                             const uint8_t int_ep, uint8_t mac[6]);
+
+void usbd_rndis_data_recv_done(void);
+
+#ifdef CONFIG_USBDEV_RNDIS_USING_LWIP
+struct pbuf *usbd_rndis_eth_rx(void);
+int usbd_rndis_eth_tx(struct pbuf *p);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBD_RNDIS_H */

+ 402 - 0
components/drivers/usb/cherryusb/class/wireless/usbh_bluetooth.c

@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_bluetooth.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "usbh_bluetooth"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/bluetooth"
+
+static struct usbh_bluetooth g_bluetooth_class;
+
+#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_H4
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_tx_buf[1 + CONFIG_USBHOST_BLUETOOTH_TX_SIZE];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_rx_buf[1 + CONFIG_USBHOST_BLUETOOTH_RX_SIZE];
+#else
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_cmd_buf[1 + 256];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_evt_buf[1 + 256];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_tx_buf[1 + CONFIG_USBHOST_BLUETOOTH_TX_SIZE];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_rx_buf[1 + CONFIG_USBHOST_BLUETOOTH_RX_SIZE];
+#endif
+
+static int usbh_bluetooth_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret = 0;
+#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
+    uint8_t mult;
+    uint16_t mps;
+#endif
+
+    struct usbh_bluetooth *bluetooth_class = &g_bluetooth_class;
+
+#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
+    if (intf != 0) {
+        return 0;
+    }
+#endif
+
+    memset(bluetooth_class, 0, sizeof(struct usbh_bluetooth));
+
+    bluetooth_class->hport = hport;
+    bluetooth_class->intf = intf;
+#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
+    bluetooth_class->num_of_intf_altsettings = hport->config.intf[intf + 1].altsetting_num;
+#endif
+    hport->config.intf[intf].priv = bluetooth_class;
+
+    for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
+        ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
+#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
+        if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(bluetooth_class->intin, ep_desc);
+            } else {
+                return -USB_ERR_NOTSUPP;
+            }
+        } else {
+#endif
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(bluetooth_class->bulkin, ep_desc);
+            } else {
+                USBH_EP_INIT(bluetooth_class->bulkout, ep_desc);
+            }
+#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
+        }
+#endif
+    }
+#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
+    USB_LOG_INFO("Num of altsettings:%u\r\n", bluetooth_class->num_of_intf_altsettings);
+
+    for (uint8_t i = 0; i < bluetooth_class->num_of_intf_altsettings; i++) {
+        USB_LOG_INFO("Altsetting:%u\r\n", i);
+        for (uint8_t j = 0; j < hport->config.intf[intf + 1].altsetting[i].intf_desc.bNumEndpoints; j++) {
+            ep_desc = &bluetooth_class->hport->config.intf[intf + 1].altsetting[i].ep[j].ep_desc;
+
+            mult = USB_GET_MULT(ep_desc->wMaxPacketSize);
+            mps = USB_GET_MAXPACKETSIZE(ep_desc->wMaxPacketSize);
+
+            USB_LOG_INFO("\tEp=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
+                         ep_desc->bEndpointAddress,
+                         ep_desc->bmAttributes,
+                         mps,
+                         ep_desc->bInterval,
+                         mult);
+        }
+    }
+
+    ret = usbh_set_interface(hport, intf, 0);
+    if (ret < 0) {
+        return ret;
+    }
+    USB_LOG_INFO("Bluetooth select altsetting 0\r\n");
+#endif
+    snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT);
+    USB_LOG_INFO("Register Bluetooth Class:%s\r\n", hport->config.intf[intf].devname);
+    usbh_bluetooth_run(bluetooth_class);
+    return ret;
+}
+
+static int usbh_bluetooth_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_bluetooth *bluetooth_class = (struct usbh_bluetooth *)hport->config.intf[intf].priv;
+
+    if (hport->config.config_desc.bNumInterfaces == (intf + 1)) {
+        return 0;
+    }
+
+    if (bluetooth_class) {
+        if (bluetooth_class->bulkin) {
+            usbh_kill_urb(&bluetooth_class->bulkin_urb);
+        }
+
+        if (bluetooth_class->bulkout) {
+            usbh_kill_urb(&bluetooth_class->bulkout_urb);
+        }
+#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
+        if (bluetooth_class->intin) {
+            usbh_kill_urb(&bluetooth_class->intin_urb);
+        }
+
+        // if (bluetooth_class->isoin) {
+        //     usbh_kill_urb(&bluetooth_class->isoin_urb);
+        // }
+
+        // if (bluetooth_class->isoin) {
+        //     usbh_kill_urb(&bluetooth_class->isoinin_urb);
+        // }
+#endif
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister Bluetooth Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_bluetooth_stop(bluetooth_class);
+        }
+
+        memset(bluetooth_class, 0, sizeof(struct usbh_bluetooth));
+    }
+
+    return ret;
+}
+
+#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_LOG
+static void usbh_bluetooth_hci_dump(uint8_t *data, uint32_t len)
+{
+    uint32_t i = 0;
+
+    for (i = 0; i < len; i++) {
+        if (i % 16 == 0) {
+            USB_LOG_RAW("\r\n");
+        }
+
+        USB_LOG_RAW("%02x ", data[i]);
+    }
+
+    USB_LOG_RAW("\r\n");
+}
+#else
+#define usbh_bluetooth_hci_dump(data, len)
+#endif
+
+static int usbh_bluetooth_hci_bulk_out(uint8_t *buffer, uint32_t buflen)
+{
+    struct usbh_bluetooth *bluetooth_class = &g_bluetooth_class;
+    struct usbh_urb *urb = &bluetooth_class->bulkout_urb;
+    int ret;
+
+    usbh_bulk_urb_fill(urb, bluetooth_class->hport, bluetooth_class->bulkout, buffer, buflen, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_H4
+int usbh_bluetooth_hci_write(uint8_t hci_type, uint8_t *buffer, uint32_t buflen)
+{
+    int ret;
+
+    g_bluetooth_tx_buf[0] = hci_type;
+    memcpy(&g_bluetooth_tx_buf[1], buffer, buflen);
+    usbh_bluetooth_hci_dump(g_bluetooth_tx_buf, buflen + 1);
+    ret = usbh_bluetooth_hci_bulk_out(g_bluetooth_tx_buf, buflen + 1);
+    return ret;
+}
+
+void usbh_bluetooth_hci_rx_thread(void *argument)
+{
+    int ret;
+    uint32_t ep_mps;
+    uint8_t retry = 0;
+    uint16_t actual_len = 0;
+
+    ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.bulkin->wMaxPacketSize);
+
+    USB_LOG_INFO("Create hc rx thread\r\n");
+    while (1) {
+        usbh_bulk_urb_fill(&g_bluetooth_class.bulkin_urb, g_bluetooth_class.hport, g_bluetooth_class.bulkin, &g_bluetooth_rx_buf[actual_len], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+        ret = usbh_submit_urb(&g_bluetooth_class.bulkin_urb);
+        if (ret < 0) {
+            if (ret == -USB_ERR_SHUTDOWN) {
+                goto delete;
+            } else {
+                retry++;
+                if (retry == 3) {
+                    retry = 0;
+                    goto delete;
+                }
+                continue;
+            }
+        }
+        actual_len += g_bluetooth_class.bulkin_urb.actual_length;
+        if (g_bluetooth_class.bulkin_urb.actual_length != ep_mps) {
+            usbh_bluetooth_hci_dump(g_bluetooth_rx_buf, actual_len);
+            usbh_bluetooth_hci_read_callback(g_bluetooth_rx_buf, actual_len);
+            actual_len = 0;
+        } else {
+            /* read continue util read short packet */
+        }
+    }
+    // clang-format off
+delete :
+    USB_LOG_INFO("Delete hc acl rx thread\r\n");
+    usb_osal_thread_delete(NULL);
+    // clang-format on
+}
+
+#else
+static int usbh_bluetooth_hci_cmd(uint8_t *buffer, uint32_t buflen)
+{
+    struct usbh_bluetooth *bluetooth_class = &g_bluetooth_class;
+    struct usb_setup_packet *setup = bluetooth_class->hport->setup;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = 0x00;
+    setup->wValue = 0;
+    setup->wIndex = bluetooth_class->intf;
+    setup->wLength = buflen;
+
+    return usbh_control_transfer(bluetooth_class->hport, setup, buffer);
+}
+
+int usbh_bluetooth_hci_write(uint8_t hci_type, uint8_t *buffer, uint32_t buflen)
+{
+    int ret;
+
+    if (hci_type == USB_BLUETOOTH_HCI_CMD) {
+        g_bluetooth_cmd_buf[0] = USB_BLUETOOTH_HCI_CMD;
+        memcpy(&g_bluetooth_cmd_buf[1], buffer, buflen);
+        usbh_bluetooth_hci_dump(g_bluetooth_cmd_buf, buflen + 1);
+        ret = usbh_bluetooth_hci_cmd(&g_bluetooth_cmd_buf[1], buflen);
+    } else if (hci_type == USB_BLUETOOTH_HCI_ACL) {
+        g_bluetooth_tx_buf[0] = USB_BLUETOOTH_HCI_ACL;
+        memcpy(&g_bluetooth_tx_buf[1], buffer, buflen);
+        usbh_bluetooth_hci_dump(g_bluetooth_tx_buf, buflen + 1);
+        ret = usbh_bluetooth_hci_bulk_out(&g_bluetooth_tx_buf[1], buflen);
+    } else {
+        ret = -1;
+    }
+
+    return ret;
+}
+
+void usbh_bluetooth_hci_evt_rx_thread(void *argument)
+{
+    int ret;
+    uint32_t ep_mps;
+    uint32_t interval;
+    uint8_t retry = 0;
+    uint16_t actual_len = 0;
+
+    ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.intin->wMaxPacketSize);
+    interval = g_bluetooth_class.intin->bInterval;
+
+    USB_LOG_INFO("Create hc event rx thread\r\n");
+    while (1) {
+        usbh_int_urb_fill(&g_bluetooth_class.intin_urb, g_bluetooth_class.hport, g_bluetooth_class.intin, &g_bluetooth_evt_buf[1 + actual_len], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+        ret = usbh_submit_urb(&g_bluetooth_class.intin_urb);
+        if (ret < 0) {
+            if (ret == -USB_ERR_SHUTDOWN) {
+                goto delete;
+            } else if (ret == -USB_ERR_NAK) {
+                usb_osal_msleep(interval);
+                continue;
+            } else {
+                retry++;
+                if (retry == 3) {
+                    retry = 0;
+                    goto delete;
+                }
+                usb_osal_msleep(interval);
+                continue;
+            }
+        }
+        actual_len += g_bluetooth_class.intin_urb.actual_length;
+        if (g_bluetooth_class.intin_urb.actual_length != ep_mps) {
+            g_bluetooth_evt_buf[0] = USB_BLUETOOTH_HCI_EVT;
+            usbh_bluetooth_hci_dump(g_bluetooth_evt_buf, actual_len + 1);
+            usbh_bluetooth_hci_read_callback(g_bluetooth_evt_buf, actual_len + 1);
+            actual_len = 0;
+        } else {
+            /* read continue util read short packet */
+        }
+        usb_osal_msleep(interval);
+    }
+    // clang-format off
+delete :
+    USB_LOG_INFO("Delete hc event rx thread\r\n");
+    usb_osal_thread_delete(NULL);
+    // clang-format on
+}
+
+void usbh_bluetooth_hci_acl_rx_thread(void *argument)
+{
+    int ret;
+    uint32_t ep_mps;
+    uint8_t retry = 0;
+    uint16_t actual_len = 0;
+
+    ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.bulkin->wMaxPacketSize);
+
+    USB_LOG_INFO("Create hc acl rx thread\r\n");
+    while (1) {
+        usbh_bulk_urb_fill(&g_bluetooth_class.bulkin_urb, g_bluetooth_class.hport, g_bluetooth_class.bulkin, &g_bluetooth_rx_buf[1 + actual_len], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+        ret = usbh_submit_urb(&g_bluetooth_class.bulkin_urb);
+        if (ret < 0) {
+            if (ret == -USB_ERR_SHUTDOWN) {
+                goto delete;
+            } else {
+                retry++;
+                if (retry == 3) {
+                    retry = 0;
+                    goto delete;
+                }
+                continue;
+            }
+        }
+        actual_len += g_bluetooth_class.bulkin_urb.actual_length;
+        if (g_bluetooth_class.bulkin_urb.actual_length != ep_mps) {
+            g_bluetooth_rx_buf[0] = USB_BLUETOOTH_HCI_ACL;
+            usbh_bluetooth_hci_dump(g_bluetooth_rx_buf, actual_len + 1);
+            usbh_bluetooth_hci_read_callback(g_bluetooth_rx_buf, actual_len + 1);
+            actual_len = 0;
+        } else {
+            /* read continue util read short packet */
+        }
+    }
+    // clang-format off
+delete :
+    USB_LOG_INFO("Delete hc acl rx thread\r\n");
+    usb_osal_thread_delete(NULL);
+    // clang-format on
+}
+#endif
+
+__WEAK void usbh_bluetooth_hci_read_callback(uint8_t *data, uint32_t len)
+{
+}
+
+__WEAK void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class)
+{
+}
+
+__WEAK void usbh_bluetooth_stop(struct usbh_bluetooth *bluetooth_class)
+{
+}
+
+static const struct usbh_class_driver bluetooth_class_driver = {
+    .driver_name = "bluetooth",
+    .connect = usbh_bluetooth_connect,
+    .disconnect = usbh_bluetooth_disconnect
+};
+
+#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_H4
+static const uint16_t bluetooth_id_table[][2] = {
+    { 0x2fe3, 0x000c },
+    { 0, 0 },
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info bluetooth_h4_nrf_class_info = {
+    .match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
+    .class = 0xff,
+    .subclass = 0x00,
+    .protocol = 0x00,
+    .id_table = bluetooth_id_table,
+    .class_driver = &bluetooth_class_driver
+};
+#else
+CLASS_INFO_DEFINE const struct usbh_class_info bluetooth_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
+    .class = USB_DEVICE_CLASS_WIRELESS,
+    .subclass = 0x01,
+    .protocol = 0x01,
+    .id_table = NULL,
+    .class_driver = &bluetooth_class_driver
+};
+#endif

+ 56 - 0
components/drivers/usb/cherryusb/class/wireless/usbh_bluetooth.h

@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_BLUETOOTH_H
+#define USBH_BLUETOOTH_H
+
+#define USB_BLUETOOTH_HCI_NONE 0x00
+#define USB_BLUETOOTH_HCI_CMD  0x01
+#define USB_BLUETOOTH_HCI_ACL  0x02
+#define USB_BLUETOOTH_HCI_SCO  0x03
+#define USB_BLUETOOTH_HCI_EVT  0x04
+#define USB_BLUETOOTH_HCI_ISO  0x05
+
+struct usbh_bluetooth {
+    struct usbh_hubport *hport;
+    uint8_t intf;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+    struct usbh_urb bulkin_urb;              /* Bulk IN urb */
+    struct usbh_urb bulkout_urb;             /* Bulk OUT urb */
+#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
+    struct usb_endpoint_descriptor *intin;  /* INTR endpoint */
+    struct usb_endpoint_descriptor *isoin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *isoout; /* Bulk OUT endpoint */
+    struct usbh_urb intin_urb;              /* INTR IN urb */
+    struct usbh_urb *isoin_urb;             /* Bulk IN urb */
+    struct usbh_urb *isoout_urb;            /* Bulk OUT urb */
+    uint8_t num_of_intf_altsettings;
+#endif
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_bluetooth_hci_write(uint8_t hci_type, uint8_t *buffer, uint32_t buflen);
+void usbh_bluetooth_hci_read_callback(uint8_t *data, uint32_t len);
+#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_H4
+void usbh_bluetooth_hci_rx_thread(void *argument);
+#else
+void usbh_bluetooth_hci_evt_rx_thread(void *argument);
+void usbh_bluetooth_hci_acl_rx_thread(void *argument);
+#endif
+
+void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class);
+void usbh_bluetooth_stop(struct usbh_bluetooth *bluetooth_class);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_BLUETOOTH_H */

+ 561 - 0
components/drivers/usb/cherryusb/class/wireless/usbh_rndis.c

@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_rndis.h"
+#include "rndis_protocol.h"
+
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "usbh_rndis"
+#include "usb_log.h"
+
+#define DEV_FORMAT "/dev/rndis"
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_buf[4096];
+
+#define CONFIG_USBHOST_RNDIS_ETH_MAX_FRAME_SIZE 1514
+#define CONFIG_USBHOST_RNDIS_ETH_MSG_SIZE       (CONFIG_USBHOST_RNDIS_ETH_MAX_FRAME_SIZE + 44)
+
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE];
+// static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_inttx_buffer[16];
+
+static struct usbh_rndis g_rndis_class;
+
+static int usbh_rndis_get_notification(struct usbh_rndis *rndis_class)
+{
+    // int ret;
+    // struct usbh_urb *urb = &rndis_class->intin_urb;
+
+    // usbh_int_urb_fill(urb, rndis_class->hport, rndis_class->intin, g_rndis_inttx_buffer, rndis_class->intin->wMaxPacketSize, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+    // ret = usbh_submit_urb(urb);
+    // if (ret == 0) {
+    //     ret = urb->actual_length;
+    // }
+    // return ret;
+    return 0;
+}
+
+static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
+{
+    struct usb_setup_packet *setup = rndis_class->hport->setup;
+    int ret = 0;
+    rndis_initialize_msg_t *cmd;
+    rndis_initialize_cmplt_t *resp;
+
+    cmd = (rndis_initialize_msg_t *)g_rndis_buf;
+
+    cmd->MessageType = REMOTE_NDIS_INITIALIZE_MSG;
+    cmd->MessageLength = sizeof(rndis_initialize_msg_t);
+    cmd->RequestId = rndis_class->request_id++;
+    cmd->MajorVersion = 1;
+    cmd->MinorVersion = 0;
+    cmd->MaxTransferSize = 0x4000;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
+    setup->wValue = 0;
+    setup->wIndex = 0;
+    setup->wLength = sizeof(rndis_initialize_msg_t);
+
+    ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
+    if (ret < 0) {
+        USB_LOG_ERR("rndis_initialize_msg_t send error, ret: %d\r\n", ret);
+        return ret;
+    }
+
+    usbh_rndis_get_notification(rndis_class);
+
+    resp = (rndis_initialize_cmplt_t *)g_rndis_buf;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
+    setup->wValue = 0;
+    setup->wIndex = 0;
+    setup->wLength = 4096;
+
+    ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
+    if (ret < 0) {
+        USB_LOG_ERR("rndis_initialize_cmplt_t recv error, ret: %d\r\n", ret);
+        return ret;
+    }
+
+    return ret;
+}
+
+int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid, uint32_t query_len, uint8_t *info, uint32_t *info_len)
+{
+    struct usb_setup_packet *setup = rndis_class->hport->setup;
+    int ret = 0;
+    rndis_query_msg_t *cmd;
+    rndis_query_cmplt_t *resp;
+
+    cmd = (rndis_query_msg_t *)g_rndis_buf;
+
+    cmd->MessageType = REMOTE_NDIS_QUERY_MSG;
+    cmd->MessageLength = query_len + sizeof(rndis_query_msg_t);
+    cmd->RequestId = rndis_class->request_id++;
+    cmd->Oid = oid;
+    cmd->InformationBufferLength = query_len;
+    cmd->InformationBufferOffset = 20;
+    cmd->DeviceVcHandle = 0;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
+    setup->wValue = 0;
+    setup->wIndex = 0;
+    setup->wLength = query_len + sizeof(rndis_query_msg_t);
+
+    ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
+    if (ret < 0) {
+        USB_LOG_ERR("oid:%08x send error, ret: %d\r\n", (unsigned int)oid, ret);
+        return ret;
+    }
+
+    usbh_rndis_get_notification(rndis_class);
+
+    resp = (rndis_query_cmplt_t *)g_rndis_buf;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
+    setup->wValue = 0;
+    setup->wIndex = 0;
+    setup->wLength = 4096;
+
+    ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
+    if (ret < 0) {
+        USB_LOG_ERR("oid:%08x recv error, ret: %d\r\n", (unsigned int)oid, ret);
+        return ret;
+    }
+
+    memcpy(info, ((uint8_t *)resp + sizeof(rndis_query_cmplt_t)), resp->InformationBufferLength);
+    *info_len = resp->InformationBufferLength;
+
+    return ret;
+}
+
+static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid, uint8_t *info, uint32_t info_len)
+{
+    struct usb_setup_packet *setup = rndis_class->hport->setup;
+    int ret = 0;
+    rndis_set_msg_t *cmd;
+    rndis_set_cmplt_t *resp;
+
+    cmd = (rndis_set_msg_t *)g_rndis_buf;
+
+    cmd->MessageType = REMOTE_NDIS_SET_MSG;
+    cmd->MessageLength = info_len + sizeof(rndis_set_msg_t);
+    cmd->RequestId = rndis_class->request_id++;
+    cmd->Oid = oid;
+    cmd->InformationBufferLength = info_len;
+    cmd->InformationBufferOffset = 20;
+    cmd->DeviceVcHandle = 0;
+
+    memcpy(((uint8_t *)cmd + sizeof(rndis_set_msg_t)), info, info_len);
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
+    setup->wValue = 0;
+    setup->wIndex = 0;
+    setup->wLength = info_len + sizeof(rndis_set_msg_t);
+
+    ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
+    if (ret < 0) {
+        USB_LOG_ERR("oid:%08x send error, ret: %d\r\n", (unsigned int)oid, ret);
+        return ret;
+    }
+
+    usbh_rndis_get_notification(rndis_class);
+
+    resp = (rndis_set_cmplt_t *)g_rndis_buf;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
+    setup->wValue = 0;
+    setup->wIndex = 0;
+    setup->wLength = 4096;
+
+    ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
+    if (ret < 0) {
+        USB_LOG_ERR("oid:%08x recv error, ret: %d\r\n", (unsigned int)oid, ret);
+        return ret;
+    }
+
+    return ret;
+}
+
+int usbh_rndis_get_connect_status(struct usbh_rndis *rndis_class)
+{
+    int ret;
+    uint8_t data[32];
+    uint32_t data_len;
+
+    ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, 4, data, &data_len);
+    if (ret < 0) {
+        return ret;
+    }
+    if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
+        rndis_class->connect_status = true;
+    } else {
+        rndis_class->connect_status = false;
+    }
+    return 0;
+}
+
+int usbh_rndis_keepalive(struct usbh_rndis *rndis_class)
+{
+    struct usb_setup_packet *setup = rndis_class->hport->setup;
+    int ret = 0;
+    rndis_keepalive_msg_t *cmd;
+    rndis_keepalive_cmplt_t *resp;
+
+    cmd = (rndis_keepalive_msg_t *)g_rndis_buf;
+
+    cmd->MessageType = REMOTE_NDIS_KEEPALIVE_MSG;
+    cmd->MessageLength = sizeof(rndis_keepalive_msg_t);
+    cmd->RequestId = rndis_class->request_id++;
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
+    setup->wValue = 0;
+    setup->wIndex = 0;
+    setup->wLength = sizeof(rndis_keepalive_msg_t);
+
+    ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
+    if (ret < 0) {
+        USB_LOG_ERR("keepalive send error, ret: %d\r\n", ret);
+        return ret;
+    }
+
+    usbh_rndis_get_notification(rndis_class);
+
+    resp = (rndis_keepalive_cmplt_t *)g_rndis_buf;
+
+    setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+    setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
+    setup->wValue = 0;
+    setup->wIndex = 0;
+    setup->wLength = 4096;
+
+    ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
+    if (ret < 0) {
+        USB_LOG_ERR("keepalive recv error, ret: %d\r\n", ret);
+        return ret;
+    }
+
+    return ret;
+}
+
+static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret;
+    uint32_t *oid_support_list;
+    unsigned int oid = 0;
+    unsigned int oid_num = 0;
+    uint32_t data_len;
+    uint8_t tmp_buffer[512];
+    uint8_t data[32];
+
+    struct usbh_rndis *rndis_class = &g_rndis_class;
+
+    memset(rndis_class, 0, sizeof(struct usbh_rndis));
+
+    rndis_class->hport = hport;
+    rndis_class->ctrl_intf = intf;
+    rndis_class->data_intf = intf + 1;
+
+    hport->config.intf[intf].priv = rndis_class;
+    hport->config.intf[intf + 1].priv = NULL;
+
+    // ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
+    // USBH_EP_INIT(rndis_class->intin, ep_desc);
+
+    for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[0].intf_desc.bNumEndpoints; i++) {
+        ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
+
+        if (ep_desc->bEndpointAddress & 0x80) {
+            USBH_EP_INIT(rndis_class->bulkin, ep_desc);
+        } else {
+            USBH_EP_INIT(rndis_class->bulkout, ep_desc);
+        }
+    }
+
+    ret = usbh_rndis_init_msg_transfer(rndis_class);
+    if (ret < 0) {
+        return ret;
+    }
+    USB_LOG_INFO("rndis init success\r\n");
+
+    ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_SUPPORTED_LIST, 0, tmp_buffer, &data_len);
+    if (ret < 0) {
+        return ret;
+    }
+    oid_num = (data_len / 4);
+    USB_LOG_INFO("rndis query OID_GEN_SUPPORTED_LIST success,oid num :%d\r\n", oid_num);
+
+    oid_support_list = (uint32_t *)tmp_buffer;
+
+    for (uint8_t i = 0; i < oid_num; i++) {
+        oid = oid_support_list[i];
+        switch (oid) {
+            case OID_GEN_PHYSICAL_MEDIUM:
+                ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_PHYSICAL_MEDIUM, 4, data, &data_len);
+                if (ret < 0) {
+                    goto query_errorout;
+                }
+                break;
+            case OID_GEN_MAXIMUM_FRAME_SIZE:
+                ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MAXIMUM_FRAME_SIZE, 4, data, &data_len);
+                if (ret < 0) {
+                    goto query_errorout;
+                }
+                break;
+            case OID_GEN_LINK_SPEED:
+                ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_LINK_SPEED, 4, data, &data_len);
+                if (ret < 0) {
+                    goto query_errorout;
+                }
+
+                memcpy(&rndis_class->link_speed, data, 4);
+                break;
+            case OID_GEN_MEDIA_CONNECT_STATUS:
+                ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, 4, data, &data_len);
+                if (ret < 0) {
+                    goto query_errorout;
+                }
+                if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
+                    rndis_class->connect_status = true;
+                } else {
+                    rndis_class->connect_status = false;
+                }
+                break;
+            case OID_802_3_MAXIMUM_LIST_SIZE:
+                ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_MAXIMUM_LIST_SIZE, 4, data, &data_len);
+                if (ret < 0) {
+                    goto query_errorout;
+                }
+                break;
+            case OID_802_3_CURRENT_ADDRESS:
+                ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_CURRENT_ADDRESS, 6, data, &data_len);
+                if (ret < 0) {
+                    goto query_errorout;
+                }
+
+                for (uint8_t j = 0; j < 6; j++) {
+                    rndis_class->mac[j] = data[j];
+                }
+                break;
+            case OID_802_3_PERMANENT_ADDRESS:
+                ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_PERMANENT_ADDRESS, 6, data, &data_len);
+                if (ret < 0) {
+                    goto query_errorout;
+                }
+                break;
+            default:
+                USB_LOG_WRN("Ignore rndis query iod:%08x\r\n", oid);
+                continue;
+        }
+        USB_LOG_INFO("rndis query iod:%08x success\r\n", oid);
+    }
+
+    uint32_t packet_filter = 0x0f;
+    usbh_rndis_set_msg_transfer(rndis_class, OID_GEN_CURRENT_PACKET_FILTER, (uint8_t *)&packet_filter, 4);
+    if (ret < 0) {
+        return ret;
+    }
+    USB_LOG_INFO("rndis set OID_GEN_CURRENT_PACKET_FILTER success\r\n");
+
+    uint8_t multicast_list[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x01 };
+    usbh_rndis_set_msg_transfer(rndis_class, OID_802_3_MULTICAST_LIST, multicast_list, 6);
+    if (ret < 0) {
+        return ret;
+    }
+    USB_LOG_INFO("rndis set OID_802_3_MULTICAST_LIST success\r\n");
+
+    USB_LOG_INFO("rndis MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
+                 rndis_class->mac[0],
+                 rndis_class->mac[1],
+                 rndis_class->mac[2],
+                 rndis_class->mac[3],
+                 rndis_class->mac[4],
+                 rndis_class->mac[5]);
+
+    memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
+
+    USB_LOG_INFO("Register RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
+    usbh_rndis_run(rndis_class);
+    return ret;
+query_errorout:
+    USB_LOG_ERR("rndis query iod:%08x error\r\n", oid);
+    return ret;
+}
+
+static int usbh_rndis_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_rndis *rndis_class = (struct usbh_rndis *)hport->config.intf[intf].priv;
+
+    if (rndis_class) {
+        if (rndis_class->bulkin) {
+            usbh_kill_urb(&rndis_class->bulkin_urb);
+        }
+
+        if (rndis_class->bulkout) {
+            usbh_kill_urb(&rndis_class->bulkout_urb);
+        }
+
+        // if (rndis_class->intin) {
+        //     usbh_kill_urb(&rndis_class->intin_urb);
+        // }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_rndis_stop(rndis_class);
+        }
+
+        memset(rndis_class, 0, sizeof(struct usbh_rndis));
+    }
+
+    return ret;
+}
+
+void usbh_rndis_rx_thread(void *argument)
+{
+    uint32_t g_rndis_rx_length;
+    int ret;
+    uint32_t pmg_offset;
+    rndis_data_packet_t *pmsg;
+    rndis_data_packet_t temp;
+
+    USB_LOG_INFO("Create rndis rx thread\r\n");
+    // clang-format off
+find_class:
+    // clang-format on
+    g_rndis_class.connect_status = false;
+    if (usbh_find_class_instance("/dev/rndis") == NULL) {
+        goto delete;
+    }
+
+    while (g_rndis_class.connect_status == false) {
+        ret = usbh_rndis_get_connect_status(&g_rndis_class);
+        if (ret < 0) {
+            usb_osal_msleep(100);
+            goto find_class;
+        }
+    }
+
+    g_rndis_rx_length = 0;
+    while (1) {
+        usbh_bulk_urb_fill(&g_rndis_class.bulkin_urb, g_rndis_class.hport, g_rndis_class.bulkin, g_rndis_rx_buffer, (CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE > (16 * 1024)) ? (16 * 1024) : CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+        ret = usbh_submit_urb(&g_rndis_class.bulkin_urb);
+        if (ret < 0) {
+            goto find_class;
+        }
+
+        g_rndis_rx_length += g_rndis_class.bulkin_urb.actual_length;
+        if (g_rndis_rx_length % USB_GET_MAXPACKETSIZE(g_rndis_class.bulkin->wMaxPacketSize)) {
+            pmg_offset = 0;
+
+            uint32_t total_len = g_rndis_rx_length;
+
+            while (g_rndis_rx_length > 0) {
+                USB_LOG_DBG("rxlen:%d\r\n", g_rndis_rx_length);
+
+                pmsg = (rndis_data_packet_t *)(g_rndis_rx_buffer + pmg_offset);
+
+                /* Not word-aligned case */
+                if (pmg_offset & 0x3) {
+                    memcpy(&temp, pmsg, sizeof(rndis_data_packet_t));
+                    pmsg = &temp;
+                }
+
+                if (pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) {
+                    uint8_t *buf = (uint8_t *)(g_rndis_rx_buffer + pmg_offset + sizeof(rndis_generic_msg_t) + pmsg->DataOffset);
+
+                    usbh_rndis_eth_input(buf, pmsg->DataLength);
+                    pmg_offset += pmsg->MessageLength;
+                    g_rndis_rx_length -= pmsg->MessageLength;
+
+                    /* drop the last dummy byte, it is a short packet to tell us we have received a multiple of wMaxPacketSize */
+                    if (g_rndis_rx_length < 4) {
+                        g_rndis_rx_length = 0;
+                    }
+                } else {
+                    USB_LOG_ERR("offset:%d,remain:%d,total:%d\r\n", pmg_offset, g_rndis_rx_length, total_len);
+                    g_rndis_rx_length = 0;
+                    USB_LOG_ERR("Error rndis packet message\r\n");
+                }
+            }
+        } else {
+            if (g_rndis_rx_length > CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE) {
+                USB_LOG_ERR("Rx packet is overflow\r\n");
+                g_rndis_rx_length = 0;
+            }
+        }
+    }
+
+    // clang-format off
+delete:
+    USB_LOG_INFO("Delete rndis rx thread\r\n");
+    usb_osal_thread_delete(NULL);
+    // clang-format on
+}
+
+int usbh_rndis_eth_output(uint8_t *buf, uint32_t buflen)
+{
+    uint8_t *buffer;
+    rndis_data_packet_t *hdr;
+    uint32_t len;
+
+    if (g_rndis_class.connect_status == false) {
+        return -USB_ERR_NOTCONN;
+    }
+
+    hdr = (rndis_data_packet_t *)g_rndis_tx_buffer;
+    memset(hdr, 0, sizeof(rndis_data_packet_t));
+
+    hdr->MessageType = REMOTE_NDIS_PACKET_MSG;
+    hdr->MessageLength = sizeof(rndis_data_packet_t) + buflen;
+    hdr->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_generic_msg_t);
+    hdr->DataLength = buflen;
+
+    buffer = (uint8_t *)(g_rndis_tx_buffer + sizeof(rndis_data_packet_t));
+    memcpy(buffer, buf, buflen);
+
+    len = hdr->MessageLength;
+    /* if message length is the multiple of wMaxPacketSize, we should add a short packet to tell device transfer is over. */
+    if (!(hdr->MessageLength % g_rndis_class.bulkout->wMaxPacketSize)) {
+        len += 1;
+    }
+
+    USB_LOG_DBG("txlen:%d\r\n", len);
+
+    usbh_bulk_urb_fill(&g_rndis_class.bulkout_urb, g_rndis_class.hport, g_rndis_class.bulkout, g_rndis_tx_buffer, len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+    return usbh_submit_urb(&g_rndis_class.bulkout_urb);
+}
+
+__WEAK void usbh_rndis_run(struct usbh_rndis *rndis_class)
+{
+}
+
+__WEAK void usbh_rndis_stop(struct usbh_rndis *rndis_class)
+{
+}
+
+static const struct usbh_class_driver rndis_class_driver = {
+    .driver_name = "rndis",
+    .connect = usbh_rndis_connect,
+    .disconnect = usbh_rndis_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info rndis_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
+    .class = USB_DEVICE_CLASS_WIRELESS,
+    .subclass = 0x01,
+    .protocol = 0x03,
+    .id_table = NULL,
+    .class_driver = &rndis_class_driver
+};

+ 51 - 0
components/drivers/usb/cherryusb/class/wireless/usbh_rndis.h

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_RNDIS_H
+#define USBH_RNDIS_H
+
+#include "usb_cdc.h"
+
+struct usbh_rndis {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+    struct usb_endpoint_descriptor *intin;   /* INTR endpoint */
+    struct usbh_urb bulkin_urb;              /* Bulk IN urb */
+    struct usbh_urb bulkout_urb;             /* Bulk OUT urb */
+    struct usbh_urb intin_urb;               /* INTR IN urb */
+
+    uint8_t ctrl_intf; /* Control interface number */
+    uint8_t data_intf; /* Data interface number */
+    uint8_t minor;
+
+    uint32_t request_id;
+
+    uint32_t link_speed;
+    bool connect_status;
+    uint8_t mac[6];
+
+    void *user_data;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int usbh_rndis_get_connect_status(struct usbh_rndis *rndis_class);
+int usbh_rndis_keepalive(struct usbh_rndis *rndis_class);
+
+void usbh_rndis_run(struct usbh_rndis *rndis_class);
+void usbh_rndis_stop(struct usbh_rndis *rndis_class);
+
+int usbh_rndis_eth_output(uint8_t *buf, uint32_t buflen);
+void usbh_rndis_eth_input(uint8_t *buf, uint32_t buflen);
+void usbh_rndis_rx_thread(void *argument);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_RNDIS_H */

+ 194 - 0
components/drivers/usb/cherryusb/common/usb_dc.h

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_DC_H
+#define USB_DC_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief init device controller registers.
+ * @return On success will return 0, and others indicate fail.
+ */
+int usb_dc_init(uint8_t busid);
+
+/**
+ * @brief deinit device controller registers.
+ * @return On success will return 0, and others indicate fail.
+ */
+int usb_dc_deinit(uint8_t busid);
+
+/**
+ * @brief Set USB device address
+ *
+ * @param[in] addr Device address
+ *
+ * @return On success will return 0, and others indicate fail.
+ */
+int usbd_set_address(uint8_t busid, const uint8_t addr);
+
+/**
+ * @brief Get USB device speed
+ *
+ * @param[in] busid bus index
+ *
+ * @return port speed, USB_SPEED_LOW or USB_SPEED_FULL or USB_SPEED_HIGH
+ */
+uint8_t usbd_get_port_speed(uint8_t busid);
+
+/**
+ * @brief configure and enable endpoint.
+ *
+ * @param [in]  ep_cfg Endpoint config.
+ *
+ * @return On success will return 0, and others indicate fail.
+ */
+int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep);
+
+/**
+ * @brief Disable the selected endpoint
+ *
+ * @param[in] ep Endpoint address
+ *
+ * @return On success will return 0, and others indicate fail.
+ */
+int usbd_ep_close(uint8_t busid, const uint8_t ep);
+
+/**
+ * @brief Set stall condition for the selected endpoint
+ *
+ * @param[in] ep Endpoint address
+ *
+ *
+ * @return On success will return 0, and others indicate fail.
+ */
+int usbd_ep_set_stall(uint8_t busid, const uint8_t ep);
+
+/**
+ * @brief Clear stall condition for the selected endpoint
+ *
+ * @param[in] ep Endpoint address corresponding to the one
+ *               listed in the device configuration table
+ *
+ * @return On success will return 0, and others indicate fail.
+ */
+int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep);
+
+/**
+ * @brief Check if the selected endpoint is stalled
+ *
+ * @param[in]  ep       Endpoint address
+ *
+ * @param[out] stalled  Endpoint stall status
+ *
+ * @return On success will return 0, and others indicate fail.
+ */
+int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled);
+
+/**
+ * @brief Setup in ep transfer setting and start transfer.
+ *
+ * This function is asynchronous.
+ * This function is similar to uart with tx dma.
+ *
+ * This function is called to write data to the specified endpoint. The
+ * supplied usbd_endpoint_callback function will be called when data is transmitted
+ * out.
+ *
+ * @param[in]  ep        Endpoint address corresponding to the one
+ *                       listed in the device configuration table
+ * @param[in]  data      Pointer to data to write
+ * @param[in]  data_len  Length of the data requested to write. This may
+ *                       be zero for a zero length status packet.
+ * @return 0 on success, negative errno code on fail.
+ */
+int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len);
+
+/**
+ * @brief Setup out ep transfer setting and start transfer.
+ *
+ * This function is asynchronous.
+ * This function is similar to uart with rx dma.
+ *
+ * This function is called to read data to the specified endpoint. The
+ * supplied usbd_endpoint_callback function will be called when data is received
+ * in.
+ *
+ * @param[in]  ep        Endpoint address corresponding to the one
+ *                       listed in the device configuration table
+ * @param[in]  data      Pointer to data to read
+ * @param[in]  data_len  Max length of the data requested to read.
+ *
+ * @return 0 on success, negative errno code on fail.
+ */
+int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len);
+
+/* usb dcd irq callback */
+
+/**
+ * @brief Usb connect irq callback.
+ */
+void usbd_event_connect_handler(uint8_t busid);
+
+/**
+ * @brief Usb disconnect irq callback.
+ */
+void usbd_event_disconnect_handler(uint8_t busid);
+
+/**
+ * @brief Usb resume irq callback.
+ */
+void usbd_event_resume_handler(uint8_t busid);
+
+/**
+ * @brief Usb suspend irq callback.
+ */
+void usbd_event_suspend_handler(uint8_t busid);
+
+/**
+ * @brief Usb reset irq callback.
+ */
+void usbd_event_reset_handler(uint8_t busid);
+
+/**
+ * @brief Usb setup packet recv irq callback.
+ * @param[in]  psetup  setup packet.
+ */
+void usbd_event_ep0_setup_complete_handler(uint8_t busid, uint8_t *psetup);
+
+/**
+ * @brief In ep transfer complete irq callback.
+ * @param[in]  ep        Endpoint address corresponding to the one
+ *                       listed in the device configuration table
+ * @param[in]  nbytes    How many nbytes have transferred.
+ */
+void usbd_event_ep_in_complete_handler(uint8_t busid, uint8_t ep, uint32_t nbytes);
+
+/**
+ * @brief Out ep transfer complete irq callback.
+ * @param[in]  ep        Endpoint address corresponding to the one
+ *                       listed in the device configuration table
+ * @param[in]  nbytes    How many nbytes have transferred.
+ */
+void usbd_event_ep_out_complete_handler(uint8_t busid, uint8_t ep, uint32_t nbytes);
+
+#ifdef CONFIG_USBDEV_TEST_MODE
+/**
+ * @brief Usb execute test mode
+ * @param[in]  busid     device busid
+ * @param[in]  test_mode usb test mode
+ */
+void usbd_execute_test_mode(uint8_t busid, uint8_t test_mode);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USB_DC_H */

+ 724 - 0
components/drivers/usb/cherryusb/common/usb_def.h

@@ -0,0 +1,724 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_DEF_H
+#define USB_DEF_H
+
+/* Useful define */
+#define USB_1_1 0x0110
+#define USB_2_0 0x0200
+/* Set USB version to 2.1 so that the host will request the BOS descriptor */
+#define USB_2_1 0x0210
+#define USB_3_0 0x0300
+#define USB_3_1 0x0310
+#define USB_3_2 0x0320
+
+/* Device speeds */
+#define USB_SPEED_UNKNOWN    0 /* Transfer rate not yet set */
+#define USB_SPEED_LOW        1 /* USB 1.1 */
+#define USB_SPEED_FULL       2 /* USB 1.1 */
+#define USB_SPEED_HIGH       3 /* USB 2.0 */
+#define USB_SPEED_WIRELESS   4 /* Wireless USB 2.5 */
+#define USB_SPEED_SUPER      5 /* USB 3.0 */
+#define USB_SPEED_SUPER_PLUS 6 /* USB 3.1 */
+
+/* Maximum number of devices per controller */
+#define USB_MAX_DEVICES (127)
+
+/* Default USB control EP, always 0 and 0x80 */
+#define USB_CONTROL_OUT_EP0 0
+#define USB_CONTROL_IN_EP0  0x80
+
+/**< maximum packet size (MPS) for EP 0 */
+#define USB_CTRL_EP_MPS 64
+
+/**< maximum packet size (MPS) for bulk EP */
+#define USB_BULK_EP_MPS_HS 512
+#define USB_BULK_EP_MPS_FS 64
+
+/* USB PID Types */
+#define USB_PID_OUT   (0x01) /* Tokens */
+#define USB_PID_IN    (0x09)
+#define USB_PID_SOF   (0x05)
+#define USB_PID_SETUP (0x0d)
+
+#define USB_PID_DATA0 (0x03) /* Data */
+#define USB_PID_DATA1 (0x0b)
+#define USB_PID_DATA2 (0x07)
+#define USB_PID_MDATA (0x0f)
+
+#define USB_PID_ACK   (0x02) /* Handshake */
+#define USB_PID_NAK   (0x0a)
+#define USB_PID_STALL (0x0e)
+#define USB_PID_NYET  (0x06)
+
+#define USB_PID_PRE      (0x0c) /* Special */
+#define USB_PID_ERR      (0x0c)
+#define USB_PID_SPLIT    (0x08)
+#define USB_PID_PING     (0x04)
+#define USB_PID_RESERVED (0x00)
+
+#define USB_REQUEST_DIR_SHIFT 7U                            /* Bits 7: Request dir */
+#define USB_REQUEST_DIR_OUT   (0U << USB_REQUEST_DIR_SHIFT) /* Bit 7=0: Host-to-device */
+#define USB_REQUEST_DIR_IN    (1U << USB_REQUEST_DIR_SHIFT) /* Bit 7=1: Device-to-host */
+#define USB_REQUEST_DIR_MASK  (1U << USB_REQUEST_DIR_SHIFT) /* Bit 7=1: Direction bit */
+
+#define USB_REQUEST_TYPE_SHIFT 5U /* Bits 5:6: Request type */
+#define USB_REQUEST_STANDARD   (0U << USB_REQUEST_TYPE_SHIFT)
+#define USB_REQUEST_CLASS      (1U << USB_REQUEST_TYPE_SHIFT)
+#define USB_REQUEST_VENDOR     (2U << USB_REQUEST_TYPE_SHIFT)
+#define USB_REQUEST_RESERVED   (3U << USB_REQUEST_TYPE_SHIFT)
+#define USB_REQUEST_TYPE_MASK  (3U << USB_REQUEST_TYPE_SHIFT)
+
+#define USB_REQUEST_RECIPIENT_SHIFT     0U /* Bits 0:4: Recipient */
+#define USB_REQUEST_RECIPIENT_DEVICE    (0U << USB_REQUEST_RECIPIENT_SHIFT)
+#define USB_REQUEST_RECIPIENT_INTERFACE (1U << USB_REQUEST_RECIPIENT_SHIFT)
+#define USB_REQUEST_RECIPIENT_ENDPOINT  (2U << USB_REQUEST_RECIPIENT_SHIFT)
+#define USB_REQUEST_RECIPIENT_OTHER     (3U << USB_REQUEST_RECIPIENT_SHIFT)
+#define USB_REQUEST_RECIPIENT_MASK      (3U << USB_REQUEST_RECIPIENT_SHIFT)
+
+/* USB Standard Request Codes */
+#define USB_REQUEST_GET_STATUS          0x00
+#define USB_REQUEST_CLEAR_FEATURE       0x01
+#define USB_REQUEST_SET_FEATURE         0x03
+#define USB_REQUEST_SET_ADDRESS         0x05
+#define USB_REQUEST_GET_DESCRIPTOR      0x06
+#define USB_REQUEST_SET_DESCRIPTOR      0x07
+#define USB_REQUEST_GET_CONFIGURATION   0x08
+#define USB_REQUEST_SET_CONFIGURATION   0x09
+#define USB_REQUEST_GET_INTERFACE       0x0A
+#define USB_REQUEST_SET_INTERFACE       0x0B
+#define USB_REQUEST_SYNCH_FRAME         0x0C
+#define USB_REQUEST_SET_ENCRYPTION      0x0D
+#define USB_REQUEST_GET_ENCRYPTION      0x0E
+#define USB_REQUEST_RPIPE_ABORT         0x0E
+#define USB_REQUEST_SET_HANDSHAKE       0x0F
+#define USB_REQUEST_RPIPE_RESET         0x0F
+#define USB_REQUEST_GET_HANDSHAKE       0x10
+#define USB_REQUEST_SET_CONNECTION      0x11
+#define USB_REQUEST_SET_SECURITY_DATA   0x12
+#define USB_REQUEST_GET_SECURITY_DATA   0x13
+#define USB_REQUEST_SET_WUSB_DATA       0x14
+#define USB_REQUEST_LOOPBACK_DATA_WRITE 0x15
+#define USB_REQUEST_LOOPBACK_DATA_READ  0x16
+#define USB_REQUEST_SET_INTERFACE_DS    0x17
+
+/* USB Standard Feature selectors */
+#define USB_FEATURE_ENDPOINT_HALT  0
+#define USB_FEATURE_SELF_POWERED   0
+#define USB_FEATURE_REMOTE_WAKEUP  1
+#define USB_FEATURE_TEST_MODE      2
+#define USB_FEATURE_BATTERY        2
+#define USB_FEATURE_BHNPENABLE     3
+#define USB_FEATURE_WUSBDEVICE     3
+#define USB_FEATURE_AHNPSUPPORT    4
+#define USB_FEATURE_AALTHNPSUPPORT 5
+#define USB_FEATURE_DEBUGMODE      6
+
+/* USB GET_STATUS Bit Values */
+#define USB_GETSTATUS_ENDPOINT_HALT 0x01
+#define USB_GETSTATUS_SELF_POWERED  0x01
+#define USB_GETSTATUS_REMOTE_WAKEUP 0x02
+
+/* USB Descriptor Types */
+#define USB_DESCRIPTOR_TYPE_DEVICE                0x01U
+#define USB_DESCRIPTOR_TYPE_CONFIGURATION         0x02U
+#define USB_DESCRIPTOR_TYPE_STRING                0x03U
+#define USB_DESCRIPTOR_TYPE_INTERFACE             0x04U
+#define USB_DESCRIPTOR_TYPE_ENDPOINT              0x05U
+#define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER      0x06U
+#define USB_DESCRIPTOR_TYPE_OTHER_SPEED           0x07U
+#define USB_DESCRIPTOR_TYPE_INTERFACE_POWER       0x08U
+#define USB_DESCRIPTOR_TYPE_OTG                   0x09U
+#define USB_DESCRIPTOR_TYPE_DEBUG                 0x0AU
+#define USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION 0x0BU
+#define USB_DESCRIPTOR_TYPE_BINARY_OBJECT_STORE   0x0FU
+#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY     0x10U
+#define USB_DESCRIPTOR_TYPE_WIRELESS_ENDPOINTCOMP 0x11U
+
+/* Class Specific Descriptor */
+#define USB_CS_DESCRIPTOR_TYPE_DEVICE        0x21U
+#define USB_CS_DESCRIPTOR_TYPE_CONFIGURATION 0x22U
+#define USB_CS_DESCRIPTOR_TYPE_STRING        0x23U
+#define USB_CS_DESCRIPTOR_TYPE_INTERFACE     0x24U
+#define USB_CS_DESCRIPTOR_TYPE_ENDPOINT      0x25U
+
+#define USB_DESCRIPTOR_TYPE_SUPERSPEED_ENDPOINT_COMPANION     0x30U
+#define USB_DESCRIPTOR_TYPE_SUPERSPEED_ISO_ENDPOINT_COMPANION 0x31U
+
+/* USB Device Classes */
+#define USB_DEVICE_CLASS_RESERVED      0x00
+#define USB_DEVICE_CLASS_AUDIO         0x01
+#define USB_DEVICE_CLASS_CDC           0x02
+#define USB_DEVICE_CLASS_HID           0x03
+#define USB_DEVICE_CLASS_MONITOR       0x04
+#define USB_DEVICE_CLASS_PHYSICAL      0x05
+#define USB_DEVICE_CLASS_IMAGE         0x06
+#define USB_DEVICE_CLASS_PRINTER       0x07
+#define USB_DEVICE_CLASS_MASS_STORAGE  0x08
+#define USB_DEVICE_CLASS_HUB           0x09
+#define USB_DEVICE_CLASS_CDC_DATA      0x0a
+#define USB_DEVICE_CLASS_SMART_CARD    0x0b
+#define USB_DEVICE_CLASS_SECURITY      0x0d
+#define USB_DEVICE_CLASS_VIDEO         0x0e
+#define USB_DEVICE_CLASS_HEALTHCARE    0x0f
+#define USB_DEVICE_CLASS_DIAG_DEVICE   0xdc
+#define USB_DEVICE_CLASS_WIRELESS      0xe0
+#define USB_DEVICE_CLASS_MISC          0xef
+#define USB_DEVICE_CLASS_APP_SPECIFIC  0xfe
+#define USB_DEVICE_CLASS_VEND_SPECIFIC 0xff
+
+/* usb string index define */
+#define USB_STRING_LANGID_INDEX    0x00
+#define USB_STRING_MFC_INDEX       0x01
+#define USB_STRING_PRODUCT_INDEX   0x02
+#define USB_STRING_SERIAL_INDEX    0x03
+#define USB_STRING_CONFIG_INDEX    0x04
+#define USB_STRING_INTERFACE_INDEX 0x05
+#define USB_STRING_OS_INDEX        0x06
+#define USB_STRING_MAX             USB_STRING_OS_INDEX
+/*
+ * Devices supporting Microsoft OS Descriptors store special string
+ * descriptor at fixed index (0xEE). It is read when a new device is
+ * attached to a computer for the first time.
+ */
+#define USB_OSDESC_STRING_DESC_INDEX 0xEE
+
+/* bmAttributes in Configuration Descriptor */
+#define USB_CONFIG_REMOTE_WAKEUP 0x20
+#define USB_CONFIG_POWERED_MASK  0x40
+#define USB_CONFIG_BUS_POWERED   0x80
+#define USB_CONFIG_SELF_POWERED  0xC0
+
+/* bMaxPower in Configuration Descriptor */
+#define USB_CONFIG_POWER_MA(mA) ((mA) / 2)
+
+/* bEndpointAddress in Endpoint Descriptor */
+#define USB_ENDPOINT_DIRECTION_MASK 0x80
+#define USB_ENDPOINT_OUT(addr)      ((addr) | 0x00)
+#define USB_ENDPOINT_IN(addr)       ((addr) | 0x80)
+
+/**
+ * USB endpoint direction and number.
+ */
+#define USB_EP_DIR_MASK 0x80U
+#define USB_EP_DIR_IN   0x80U
+#define USB_EP_DIR_OUT  0x00U
+
+/** Get endpoint index (number) from endpoint address */
+#define USB_EP_GET_IDX(ep) ((ep) & ~USB_EP_DIR_MASK)
+/** Get direction from endpoint address */
+#define USB_EP_GET_DIR(ep) ((ep)&USB_EP_DIR_MASK)
+/** Get endpoint address from endpoint index and direction */
+#define USB_EP_GET_ADDR(idx, dir) ((idx) | ((dir)&USB_EP_DIR_MASK))
+/** True if the endpoint is an IN endpoint */
+#define USB_EP_DIR_IS_IN(ep) (USB_EP_GET_DIR(ep) == USB_EP_DIR_IN)
+/** True if the endpoint is an OUT endpoint */
+#define USB_EP_DIR_IS_OUT(ep) (USB_EP_GET_DIR(ep) == USB_EP_DIR_OUT)
+
+/* bmAttributes in Endpoint Descriptor */
+#define USB_ENDPOINT_TYPE_SHIFT       0
+#define USB_ENDPOINT_TYPE_CONTROL     (0 << USB_ENDPOINT_TYPE_SHIFT)
+#define USB_ENDPOINT_TYPE_ISOCHRONOUS (1 << USB_ENDPOINT_TYPE_SHIFT)
+#define USB_ENDPOINT_TYPE_BULK        (2 << USB_ENDPOINT_TYPE_SHIFT)
+#define USB_ENDPOINT_TYPE_INTERRUPT   (3 << USB_ENDPOINT_TYPE_SHIFT)
+#define USB_ENDPOINT_TYPE_MASK        (3 << USB_ENDPOINT_TYPE_SHIFT)
+#define USB_GET_ENDPOINT_TYPE(x)      ((x & USB_ENDPOINT_TYPE_MASK) >> USB_ENDPOINT_TYPE_SHIFT)
+
+#define USB_ENDPOINT_SYNC_SHIFT              2
+#define USB_ENDPOINT_SYNC_NO_SYNCHRONIZATION (0 << USB_ENDPOINT_SYNC_SHIFT)
+#define USB_ENDPOINT_SYNC_ASYNCHRONOUS       (1 << USB_ENDPOINT_SYNC_SHIFT)
+#define USB_ENDPOINT_SYNC_ADAPTIVE           (2 << USB_ENDPOINT_SYNC_SHIFT)
+#define USB_ENDPOINT_SYNC_SYNCHRONOUS        (3 << USB_ENDPOINT_SYNC_SHIFT)
+#define USB_ENDPOINT_SYNC_MASK               (3 << USB_ENDPOINT_SYNC_SHIFT)
+
+#define USB_ENDPOINT_USAGE_SHIFT             4
+#define USB_ENDPOINT_USAGE_DATA              (0 << USB_ENDPOINT_USAGE_SHIFT)
+#define USB_ENDPOINT_USAGE_FEEDBACK          (1 << USB_ENDPOINT_USAGE_SHIFT)
+#define USB_ENDPOINT_USAGE_IMPLICIT_FEEDBACK (2 << USB_ENDPOINT_USAGE_SHIFT)
+#define USB_ENDPOINT_USAGE_MASK              (3 << USB_ENDPOINT_USAGE_SHIFT)
+
+#define USB_ENDPOINT_MAX_ADJUSTABLE (1 << 7)
+
+/* wMaxPacketSize in Endpoint Descriptor */
+#define USB_MAXPACKETSIZE_SHIFT                        0
+#define USB_MAXPACKETSIZE_MASK                         (0x7ff << USB_MAXPACKETSIZE_SHIFT)
+#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT 11
+#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_NONE  (0 << USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
+#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_ONE   (1 << USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
+#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_TWO   (2 << USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
+#define USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK  (3 << USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
+#define USB_GET_MAXPACKETSIZE(x)                       ((x & USB_MAXPACKETSIZE_MASK) >> USB_MAXPACKETSIZE_SHIFT)
+#define USB_GET_MULT(x)                                ((x & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT)
+
+/* bDevCapabilityType in Device Capability Descriptor */
+#define USB_DEVICE_CAPABILITY_WIRELESS_USB                1
+#define USB_DEVICE_CAPABILITY_USB_2_0_EXTENSION           2
+#define USB_DEVICE_CAPABILITY_SUPERSPEED_USB              3
+#define USB_DEVICE_CAPABILITY_CONTAINER_ID                4
+#define USB_DEVICE_CAPABILITY_PLATFORM                    5
+#define USB_DEVICE_CAPABILITY_POWER_DELIVERY_CAPABILITY   6
+#define USB_DEVICE_CAPABILITY_BATTERY_INFO_CAPABILITY     7
+#define USB_DEVICE_CAPABILITY_PD_CONSUMER_PORT_CAPABILITY 8
+#define USB_DEVICE_CAPABILITY_PD_PROVIDER_PORT_CAPABILITY 9
+#define USB_DEVICE_CAPABILITY_SUPERSPEED_PLUS             10
+#define USB_DEVICE_CAPABILITY_PRECISION_TIME_MEASUREMENT  11
+#define USB_DEVICE_CAPABILITY_WIRELESS_USB_EXT            12
+
+#define USB_BOS_CAPABILITY_EXTENSION 0x02
+#define USB_BOS_CAPABILITY_PLATFORM  0x05
+
+/* OTG SET FEATURE Constants */
+#define USB_OTG_FEATURE_B_HNP_ENABLE      3 /* Enable B device to perform HNP */
+#define USB_OTG_FEATURE_A_HNP_SUPPORT     4 /* A device supports HNP */
+#define USB_OTG_FEATURE_A_ALT_HNP_SUPPORT 5 /* Another port on the A device supports HNP */
+
+/* WinUSB Microsoft OS 2.0 descriptor request codes */
+#define WINUSB_REQUEST_GET_DESCRIPTOR_SET 0x07
+#define WINUSB_REQUEST_SET_ALT_ENUM       0x08
+
+/* WinUSB Microsoft OS 2.0 descriptor sizes */
+#define WINUSB_DESCRIPTOR_SET_HEADER_SIZE  10
+#define WINUSB_FUNCTION_SUBSET_HEADER_SIZE 8
+#define WINUSB_FEATURE_COMPATIBLE_ID_SIZE  20
+
+/* WinUSB Microsoft OS 2.0 Descriptor Types */
+#define WINUSB_SET_HEADER_DESCRIPTOR_TYPE       0x00
+#define WINUSB_SUBSET_HEADER_CONFIGURATION_TYPE 0x01
+#define WINUSB_SUBSET_HEADER_FUNCTION_TYPE      0x02
+#define WINUSB_FEATURE_COMPATIBLE_ID_TYPE       0x03
+#define WINUSB_FEATURE_REG_PROPERTY_TYPE        0x04
+#define WINUSB_FEATURE_MIN_RESUME_TIME_TYPE     0x05
+#define WINUSB_FEATURE_MODEL_ID_TYPE            0x06
+#define WINUSB_FEATURE_CCGP_DEVICE_TYPE         0x07
+
+#define WINUSB_PROP_DATA_TYPE_REG_SZ       0x01
+#define WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ 0x07
+
+/* WebUSB Descriptor Types */
+#define WEBUSB_DESCRIPTOR_SET_HEADER_TYPE       0x00
+#define WEBUSB_CONFIGURATION_SUBSET_HEADER_TYPE 0x01
+#define WEBUSB_FUNCTION_SUBSET_HEADER_TYPE      0x02
+#define WEBUSB_URL_TYPE                         0x03
+
+/* WebUSB Request Codes */
+#define WEBUSB_REQUEST_GET_URL 0x02
+
+/* bScheme in URL descriptor */
+#define WEBUSB_URL_SCHEME_HTTP  0x00
+#define WEBUSB_URL_SCHEME_HTTPS 0x01
+
+/* WebUSB Descriptor sizes */
+#define WEBUSB_DESCRIPTOR_SET_HEADER_SIZE       5
+#define WEBUSB_CONFIGURATION_SUBSET_HEADER_SIZE 4
+#define WEBUSB_FUNCTION_SUBSET_HEADER_SIZE      3
+
+/* Setup packet definition used to read raw data from USB line */
+struct usb_setup_packet {
+    /** Request type. Bits 0:4 determine recipient, see
+	 * \ref usb_request_recipient. Bits 5:6 determine type, see
+	 * \ref usb_request_type. Bit 7 determines data transfer direction, see
+	 * \ref usb_endpoint_direction.
+	 */
+    uint8_t bmRequestType;
+
+    /** Request. If the type bits of bmRequestType are equal to
+	 * \ref usb_request_type::LIBUSB_REQUEST_TYPE_STANDARD
+	 * "USB_REQUEST_TYPE_STANDARD" then this field refers to
+	 * \ref usb_standard_request. For other cases, use of this field is
+	 * application-specific. */
+    uint8_t bRequest;
+
+    /** Value. Varies according to request */
+    uint16_t wValue;
+
+    /** Index. Varies according to request, typically used to pass an index
+	 * or offset */
+    uint16_t wIndex;
+
+    /** Number of bytes to transfer */
+    uint16_t wLength;
+} __PACKED;
+
+#define USB_SIZEOF_SETUP_PACKET 8
+
+/** Standard Device Descriptor */
+struct usb_device_descriptor {
+    uint8_t bLength;            /* Descriptor size in bytes = 18 */
+    uint8_t bDescriptorType;    /* DEVICE descriptor type = 1 */
+    uint16_t bcdUSB;            /* USB spec in BCD, e.g. 0x0200 */
+    uint8_t bDeviceClass;       /* Class code, if 0 see interface */
+    uint8_t bDeviceSubClass;    /* Sub-Class code, 0 if class = 0 */
+    uint8_t bDeviceProtocol;    /* Protocol, if 0 see interface */
+    uint8_t bMaxPacketSize0;    /* Endpoint 0 max. size */
+    uint16_t idVendor;          /* Vendor ID per USB-IF */
+    uint16_t idProduct;         /* Product ID per manufacturer */
+    uint16_t bcdDevice;         /* Device release # in BCD */
+    uint8_t iManufacturer;      /* Index to manufacturer string */
+    uint8_t iProduct;           /* Index to product string */
+    uint8_t iSerialNumber;      /* Index to serial number string */
+    uint8_t bNumConfigurations; /* Number of possible configurations */
+} __PACKED;
+
+#define USB_SIZEOF_DEVICE_DESC 18
+
+/** Standard Configuration Descriptor */
+struct usb_configuration_descriptor {
+    uint8_t bLength;             /* Descriptor size in bytes = 9 */
+    uint8_t bDescriptorType;     /* CONFIGURATION type = 2 or 7 */
+    uint16_t wTotalLength;       /* Length of concatenated descriptors */
+    uint8_t bNumInterfaces;      /* Number of interfaces, this config. */
+    uint8_t bConfigurationValue; /* Value to set this config. */
+    uint8_t iConfiguration;      /* Index to configuration string */
+    uint8_t bmAttributes;        /* Config. characteristics */
+    uint8_t bMaxPower;           /* Max.power from bus, 2mA units */
+} __PACKED;
+
+#define USB_SIZEOF_CONFIG_DESC 9
+
+/** Standard Interface Descriptor */
+struct usb_interface_descriptor {
+    uint8_t bLength;            /* Descriptor size in bytes = 9 */
+    uint8_t bDescriptorType;    /* INTERFACE descriptor type = 4 */
+    uint8_t bInterfaceNumber;   /* Interface no.*/
+    uint8_t bAlternateSetting;  /* Value to select this IF */
+    uint8_t bNumEndpoints;      /* Number of endpoints excluding 0 */
+    uint8_t bInterfaceClass;    /* Class code, 0xFF = vendor */
+    uint8_t bInterfaceSubClass; /* Sub-Class code, 0 if class = 0 */
+    uint8_t bInterfaceProtocol; /* Protocol, 0xFF = vendor */
+    uint8_t iInterface;         /* Index to interface string */
+} __PACKED;
+
+#define USB_SIZEOF_INTERFACE_DESC 9
+
+/** Standard Endpoint Descriptor */
+struct usb_endpoint_descriptor {
+    uint8_t bLength;          /* Descriptor size in bytes = 7 */
+    uint8_t bDescriptorType;  /* ENDPOINT descriptor type = 5 */
+    uint8_t bEndpointAddress; /* Endpoint # 0 - 15 | IN/OUT */
+    uint8_t bmAttributes;     /* Transfer type */
+    uint16_t wMaxPacketSize;  /* Bits 10:0 = max. packet size */
+    uint8_t bInterval;        /* Polling interval in (micro) frames */
+} __PACKED;
+
+#define USB_SIZEOF_ENDPOINT_DESC 7
+
+/** Unicode (UTF16LE) String Descriptor */
+struct usb_string_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint16_t bString;
+} __PACKED;
+
+#define USB_SIZEOF_STRING_LANGID_DESC 4
+
+/* USB Interface Association Descriptor */
+struct usb_interface_association_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bFirstInterface;
+    uint8_t bInterfaceCount;
+    uint8_t bFunctionClass;
+    uint8_t bFunctionSubClass;
+    uint8_t bFunctionProtocol;
+    uint8_t iFunction;
+} __PACKED;
+
+#define USB_SIZEOF_IAD_DESC 8
+
+/** USB device_qualifier descriptor */
+struct usb_device_qualifier_descriptor {
+    uint8_t bLength;            /* Descriptor size in bytes = 10 */
+    uint8_t bDescriptorType;    /* DEVICE QUALIFIER type = 6 */
+    uint16_t bcdUSB;            /* USB spec in BCD, e.g. 0x0200 */
+    uint8_t bDeviceClass;       /* Class code, if 0 see interface */
+    uint8_t bDeviceSubClass;    /* Sub-Class code, 0 if class = 0 */
+    uint8_t bDeviceProtocol;    /* Protocol, if 0 see interface */
+    uint8_t bMaxPacketSize;     /* Endpoint 0 max. size */
+    uint8_t bNumConfigurations; /* Number of possible configurations */
+    uint8_t bReserved;          /* Reserved = 0 */
+} __PACKED;
+
+#define USB_SIZEOF_DEVICE_QUALIFIER_DESC 10
+
+/* Microsoft OS function descriptor.
+ * This can be used to request a specific driver (such as WINUSB) to be
+ * loaded on Windows. Unlike other descriptors, it is requested by a special
+ * request USB_REQ_GETMSFTOSDESCRIPTOR.
+ * More details:
+ *       https://msdn.microsoft.com/en-us/windows/hardware/gg463179
+ * And excellent explanation:
+ *       https://github.com/pbatard/libwdi/wiki/WCID-Devices
+ *
+ * The device will have exactly one "Extended Compat ID Feature Descriptor",
+ * which may contain multiple "Function Descriptors" associated with
+ * different interfaces.
+ */
+
+/* MS OS 1.0 string descriptor */
+struct usb_msosv1_string_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bString[14];
+    uint8_t bMS_VendorCode; /* Vendor Code, used for a control request */
+    uint8_t bPad;           /* Padding byte for VendorCode look as UTF16 */
+} __PACKED;
+
+/* MS OS 1.0 Header descriptor */
+struct usb_msosv1_compat_id_header_descriptor {
+    uint32_t dwLength;
+    uint16_t bcdVersion;
+    uint16_t wIndex;
+    uint8_t bCount;
+    uint8_t reserved[7];
+} __PACKED;
+
+/* MS OS 1.0 Function descriptor */
+struct usb_msosv1_comp_id_function_descriptor {
+    uint8_t bFirstInterfaceNumber;
+    uint8_t reserved1;
+    uint8_t compatibleID[8];
+    uint8_t subCompatibleID[8];
+    uint8_t reserved2[6];
+} __PACKED;
+
+#define usb_msosv1_comp_id_create(x)                                         \
+    struct usb_msosv1_comp_id {                                              \
+        struct usb_msosv1_compat_id_header_descriptor compat_id_header;      \
+        struct usb_msosv1_comp_id_function_descriptor compat_id_function[x]; \
+    };
+
+struct usb_msosv1_descriptor {
+    const uint8_t *string;
+    uint8_t vendor_code;
+    const uint8_t *compat_id;
+    const uint8_t **comp_id_property;
+};
+
+/* MS OS 2.0 Header descriptor */
+struct usb_msosv2_header_descriptor {
+    uint32_t dwLength;
+    uint16_t bcdVersion;
+    uint16_t wIndex;
+    uint8_t bCount;
+} __PACKED;
+
+/*Microsoft OS 2.0 set header descriptor*/
+struct usb_msosv2_set_header_descriptor {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint32_t dwWindowsVersion;
+    uint16_t wDescriptorSetTotalLength;
+} __PACKED;
+
+/* Microsoft OS 2.0 compatibleID descriptor*/
+struct usb_msosv2_comp_id_descriptor {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint8_t compatibleID[8];
+    uint8_t subCompatibleID[8];
+} __PACKED;
+
+/* MS OS 2.0 property descriptor */
+struct usb_msosv2_property_descriptor {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint32_t dwPropertyDataType;
+    uint16_t wPropertyNameLength;
+    const char *bPropertyName;
+    uint32_t dwPropertyDataLength;
+    const char *bPropertyData;
+};
+
+/* Microsoft OS 2.0 subset function descriptor  */
+struct usb_msosv2_subset_function_descriptor {
+    uint16_t wLength;
+    uint16_t wDescriptorType;
+    uint8_t bFirstInterface;
+    uint8_t bReserved;
+    uint16_t wSubsetLength;
+} __PACKED;
+
+struct usb_msosv2_descriptor {
+    const uint8_t *compat_id;
+    uint16_t compat_id_len;
+    uint8_t vendor_code;
+};
+
+/* BOS header Descriptor */
+struct usb_bos_header_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint16_t wTotalLength;
+    uint8_t bNumDeviceCaps;
+} __PACKED;
+
+/* BOS Capability platform Descriptor */
+struct usb_bos_capability_platform_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDevCapabilityType;
+    uint8_t bReserved;
+    uint8_t PlatformCapabilityUUID[16];
+} __PACKED;
+
+/* BOS Capability MS OS Descriptors version 2 */
+struct usb_bos_capability_msosv2_descriptor {
+    uint32_t dwWindowsVersion;
+    uint16_t wMSOSDescriptorSetTotalLength;
+    uint8_t bVendorCode;
+    uint8_t bAltEnumCode;
+} __PACKED;
+
+/* BOS Capability webusb */
+struct usb_bos_capability_webusb_descriptor {
+    uint16_t bcdVersion;
+    uint8_t bVendorCode;
+    uint8_t iLandingPage;
+} __PACKED;
+
+/* BOS Capability extension Descriptor*/
+struct usb_bos_capability_extension_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDevCapabilityType;
+    uint32_t bmAttributes;
+} __PACKED;
+
+/* Microsoft OS 2.0 Platform Capability Descriptor
+* See https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/
+* microsoft-defined-usb-descriptors
+* Adapted from the source:
+* https://github.com/sowbug/weblight/blob/master/firmware/webusb.c
+* (BSD-2) Thanks http://janaxelson.com/files/ms_os_20_descriptors.c
+*/
+struct usb_bos_capability_platform_msosv2_descriptor {
+    struct usb_bos_capability_platform_descriptor platform_msos;
+    struct usb_bos_capability_msosv2_descriptor data_msosv2;
+} __PACKED;
+
+/* WebUSB Platform Capability Descriptor:
+* https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
+*/
+struct usb_bos_capability_platform_webusb_descriptor {
+    struct usb_bos_capability_platform_descriptor platform_webusb;
+    struct usb_bos_capability_webusb_descriptor data_webusb;
+} __PACKED;
+
+struct usb_webusb_url_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bScheme;
+    char URL[];
+} __PACKED;
+
+struct usb_webusb_url_ex_descriptor {
+    uint8_t vendor_code;
+    const uint8_t *string;
+    uint32_t string_len;
+} __PACKED;
+
+struct usb_bos_descriptor {
+    const uint8_t *string;
+    uint32_t string_len;
+};
+
+/* USB Device Capability Descriptor */
+struct usb_device_capability_descriptor {
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+    uint8_t bDevCapabilityType;
+} __PACKED;
+
+/** USB descriptor header */
+struct usb_desc_header {
+    uint8_t bLength;         /**< descriptor length */
+    uint8_t bDescriptorType; /**< descriptor type */
+};
+// clang-format off
+#define USB_DEVICE_DESCRIPTOR_INIT(bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct, bcdDevice, bNumConfigurations) \
+    0x12,                       /* bLength */                                                                                              \
+    USB_DESCRIPTOR_TYPE_DEVICE, /* bDescriptorType */                                                                                      \
+    WBVAL(bcdUSB),              /* bcdUSB */                                                                                               \
+    bDeviceClass,               /* bDeviceClass */                                                                                         \
+    bDeviceSubClass,            /* bDeviceSubClass */                                                                                      \
+    bDeviceProtocol,            /* bDeviceProtocol */                                                                                      \
+    0x40,                       /* bMaxPacketSize */                                                                                       \
+    WBVAL(idVendor),            /* idVendor */                                                                                             \
+    WBVAL(idProduct),           /* idProduct */                                                                                            \
+    WBVAL(bcdDevice),           /* bcdDevice */                                                                                            \
+    USB_STRING_MFC_INDEX,       /* iManufacturer */                                                                                        \
+    USB_STRING_PRODUCT_INDEX,   /* iProduct */                                                                                             \
+    USB_STRING_SERIAL_INDEX,    /* iSerial */                                                                                              \
+    bNumConfigurations          /* bNumConfigurations */
+
+#define USB_CONFIG_DESCRIPTOR_INIT(wTotalLength, bNumInterfaces, bConfigurationValue, bmAttributes, bMaxPower) \
+    0x09,                              /* bLength */                                                       \
+    USB_DESCRIPTOR_TYPE_CONFIGURATION, /* bDescriptorType */                                               \
+    WBVAL(wTotalLength),               /* wTotalLength */                                                  \
+    bNumInterfaces,                    /* bNumInterfaces */                                                \
+    bConfigurationValue,               /* bConfigurationValue */                                           \
+    0x00,                              /* iConfiguration */                                                \
+    bmAttributes,                      /* bmAttributes */                                                  \
+    USB_CONFIG_POWER_MA(bMaxPower)     /* bMaxPower */
+
+#define USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, bNumConfigurations) \
+    0x0A,                                 /* bLength */                                                    \
+    USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, /* bDescriptorType */                                            \
+    WBVAL(bcdUSB),              /* bcdUSB */                                                               \
+    bDeviceClass,               /* bDeviceClass */                                                         \
+    bDeviceSubClass,            /* bDeviceSubClass */                                                      \
+    bDeviceProtocol,            /* bDeviceProtocol */                                                      \
+    0x40,                       /* bMaxPacketSize */                                                       \
+    bNumConfigurations,         /* bNumConfigurations */                                                   \
+    0x00                        /* bReserved */
+
+#define USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(wTotalLength, bNumInterfaces, bConfigurationValue, bmAttributes, bMaxPower) \
+    0x09,                              /* bLength */                                                       \
+    USB_DESCRIPTOR_TYPE_OTHER_SPEED,   /* bDescriptorType */                                               \
+    WBVAL(wTotalLength),               /* wTotalLength */                                                  \
+    bNumInterfaces,                    /* bNumInterfaces */                                                \
+    bConfigurationValue,               /* bConfigurationValue */                                           \
+    0x00,                              /* iConfiguration */                                                \
+    bmAttributes,                      /* bmAttributes */                                                  \
+    USB_CONFIG_POWER_MA(bMaxPower)     /* bMaxPower */
+
+#define USB_INTERFACE_DESCRIPTOR_INIT(bInterfaceNumber, bAlternateSetting, bNumEndpoints,                  \
+                                      bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol, iInterface) \
+    0x09,                          /* bLength */                                                       \
+    USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */                                               \
+    bInterfaceNumber,              /* bInterfaceNumber */                                              \
+    bAlternateSetting,             /* bAlternateSetting */                                             \
+    bNumEndpoints,                 /* bNumEndpoints */                                                 \
+    bInterfaceClass,               /* bInterfaceClass */                                               \
+    bInterfaceSubClass,            /* bInterfaceSubClass */                                            \
+    bInterfaceProtocol,            /* bInterfaceProtocol */                                            \
+    iInterface                     /* iInterface */
+
+#define USB_ENDPOINT_DESCRIPTOR_INIT(bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval) \
+    0x07,                         /* bLength */                                             \
+    USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */                                     \
+    bEndpointAddress,             /* bEndpointAddress */                                    \
+    bmAttributes,                 /* bmAttributes */                                        \
+    WBVAL(wMaxPacketSize),        /* wMaxPacketSize */                                      \
+    bInterval                     /* bInterval */
+
+#define USB_IAD_INIT(bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass, bFunctionProtocol) \
+    0x08,                                      /* bLength */                                             \
+    USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */                                     \
+    bFirstInterface,                           /* bFirstInterface */                                     \
+    bInterfaceCount,                           /* bInterfaceCount */                                     \
+    bFunctionClass,                            /* bFunctionClass */                                      \
+    bFunctionSubClass,                         /* bFunctionSubClass */                                   \
+    bFunctionProtocol,                         /* bFunctionProtocol */                                   \
+    0x00                                       /* iFunction */
+
+#define USB_LANGID_INIT(id)                           \
+    0x04,                           /* bLength */     \
+    USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ \
+    WBVAL(id)                   /* wLangID0 */
+// clang-format on
+
+#endif /* USB_DEF_H */

+ 24 - 0
components/drivers/usb/cherryusb/common/usb_errno.h

@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2023, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_ERRNO_H
+#define USB_ERRNO_H
+
+#define USB_ERR_NOMEM    1
+#define USB_ERR_INVAL    2
+#define USB_ERR_NODEV    3
+#define USB_ERR_NOTCONN  4
+#define USB_ERR_NOTSUPP  5
+#define USB_ERR_BUSY     6
+#define USB_ERR_RANGE    7
+#define USB_ERR_STALL    8
+#define USB_ERR_BABBLE   9
+#define USB_ERR_NAK      10
+#define USB_ERR_DT       11
+#define USB_ERR_IO       12
+#define USB_ERR_SHUTDOWN 13
+#define USB_ERR_TIMEOUT  14
+
+#endif /* USB_ERRNO_H */

+ 114 - 0
components/drivers/usb/cherryusb/common/usb_hc.h

@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_HC_H
+#define USB_HC_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*usbh_complete_callback_t)(void *arg, int nbytes);
+
+struct usbh_bus;
+
+/**
+ * @brief USB Iso Configuration.
+ *
+ * Structure containing the USB Iso configuration.
+ */
+struct usbh_iso_frame_packet {
+    uint8_t *transfer_buffer;
+    uint32_t transfer_buffer_length;
+    uint32_t actual_length;
+    int errorcode;
+};
+
+/**
+ * @brief USB Urb Configuration.
+ *
+ * Structure containing the USB Urb configuration.
+ */
+struct usbh_urb {
+    void *hcpriv;
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *ep;
+    uint8_t data_toggle;
+    uint8_t interval;
+    struct usb_setup_packet *setup;
+    uint8_t *transfer_buffer;
+    uint32_t transfer_buffer_length;
+    int transfer_flags;
+    uint32_t actual_length;
+    uint32_t timeout;
+    int errorcode;
+    uint32_t num_of_iso_packets;
+    uint32_t start_frame;
+    usbh_complete_callback_t complete;
+    void *arg;
+#if defined(__ICCARM__) || defined(__ICCRISCV__) || defined(__ICCRX__)
+    struct usbh_iso_frame_packet *iso_packet;
+#else
+    struct usbh_iso_frame_packet iso_packet[0];
+#endif
+};
+
+/**
+ * @brief usb host controller hardware init.
+ *
+ * @return On success will return 0, and others indicate fail.
+ */
+int usb_hc_init(struct usbh_bus *bus);
+
+/**
+ * @brief usb host controller hardware deinit.
+ *
+ * @return On success will return 0, and others indicate fail.
+ */
+int usb_hc_deinit(struct usbh_bus *bus);
+
+/**
+ * @brief Get frame number.
+ *
+ * @return frame number.
+ */
+uint16_t usbh_get_frame_number(struct usbh_bus *bus);
+/**
+ * @brief control roothub.
+ *
+ * @param setup setup request buffer.
+ * @param buf buf for reading response or write data.
+ * @return On success will return 0, and others indicate fail.
+ */
+int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf);
+
+/**
+ * @brief Submit a usb transfer request to an endpoint.
+ *
+ * If timeout is not zero, this function will be in poll transfer mode,
+ * otherwise will be in async transfer mode.
+ *
+ * @param urb Usb request block.
+ * @return  On success will return 0, and others indicate fail.
+ */
+int usbh_submit_urb(struct usbh_urb *urb);
+
+/**
+ * @brief Cancel a transfer request.
+ *
+ * This function will call When calls usbh_submit_urb and return -USB_ERR_TIMEOUT or -USB_ERR_SHUTDOWN.
+ *
+ * @param urb Usb request block.
+ * @return  On success will return 0, and others indicate fail.
+ */
+int usbh_kill_urb(struct usbh_urb *urb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USB_HC_H */

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.