\ No newline at end of file
diff --git a/components/drivers/usb/cherryusb/README_zh.md b/components/drivers/usb/cherryusb/README_zh.md
new file mode 100644
index 0000000000..a59649e0bb
--- /dev/null
+++ b/components/drivers/usb/cherryusb/README_zh.md
@@ -0,0 +1,198 @@
+# CherryUSB
+
+[English](./README.md)
+
+CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统(带 USB IP)的 USB 主从协议栈。
+
+
+
+## 为什么选择
+
+### 易于学习 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 微信群:与我联系后邀请加入
+
+## 支持企业
+
+感谢以下企业支持(顺序不分先后)。
+
+
diff --git a/components/drivers/usb/cherryusb/SConscript b/components/drivers/usb/cherryusb/SConscript
new file mode 100644
index 0000000000..1bdb16d503
--- /dev/null
+++ b/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')
+
diff --git a/components/drivers/usb/cherryusb/VERSION b/components/drivers/usb/cherryusb/VERSION
new file mode 100644
index 0000000000..f976d5d979
--- /dev/null
+++ b/components/drivers/usb/cherryusb/VERSION
@@ -0,0 +1,5 @@
+VERSION_MAJOR = 1
+VERSION_MINOR = 3
+PATCHLEVEL = 0
+VERSION_TWEAK = 0
+EXTRAVERSION = 0
diff --git a/components/drivers/usb/cherryusb/cherryusb.cmake b/components/drivers/usb/cherryusb/cherryusb.cmake
new file mode 100644
index 0000000000..6a78e9dc47
--- /dev/null
+++ b/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()
\ No newline at end of file
diff --git a/components/drivers/usb/cherryusb/cherryusb_config_template.h b/components/drivers/usb/cherryusb/cherryusb_config_template.h
new file mode 100644
index 0000000000..cba9fc4dbf
--- /dev/null
+++ b/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
diff --git a/components/drivers/usb/cherryusb/class/audio/usb_audio.h b/components/drivers/usb/cherryusb/class/audio/usb_audio.h
new file mode 100644
index 0000000000..2b3cdaffa8
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/audio/usbd_audio.c b/components/drivers/usb/cherryusb/class/audio/usbd_audio.c
new file mode 100644
index 0000000000..c78c8ed751
--- /dev/null
+++ b/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)
+{
+}
diff --git a/components/drivers/usb/cherryusb/class/audio/usbd_audio.h b/components/drivers/usb/cherryusb/class/audio/usbd_audio.h
new file mode 100644
index 0000000000..442405a2f9
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/audio/usbh_audio.c b/components/drivers/usb/cherryusb/class/audio/usbh_audio.c
new file mode 100644
index 0000000000..8687e9a4a6
--- /dev/null
+++ b/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
+};
diff --git a/components/drivers/usb/cherryusb/class/audio/usbh_audio.h b/components/drivers/usb/cherryusb/class/audio/usbh_audio.h
new file mode 100644
index 0000000000..038a8f7e93
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/cdc/usb_cdc.h b/components/drivers/usb/cherryusb/class/cdc/usb_cdc.h
new file mode 100644
index 0000000000..b8a544f3f3
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/cdc/usbd_cdc.c b/components/drivers/usb/cherryusb/class/cdc/usbd_cdc.c
new file mode 100644
index 0000000000..50d13d7d53
--- /dev/null
+++ b/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)
+{
+}
diff --git a/components/drivers/usb/cherryusb/class/cdc/usbd_cdc.h b/components/drivers/usb/cherryusb/class/cdc/usbd_cdc.h
new file mode 100644
index 0000000000..ebf3d029e6
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/cdc/usbd_cdc_ecm.c b/components/drivers/usb/cherryusb/class/cdc/usbd_cdc_ecm.c
new file mode 100644
index 0000000000..1fca9cadce
--- /dev/null
+++ b/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)
+{
+}
\ No newline at end of file
diff --git a/components/drivers/usb/cherryusb/class/cdc/usbd_cdc_ecm.h b/components/drivers/usb/cherryusb/class/cdc/usbd_cdc_ecm.h
new file mode 100644
index 0000000000..8d9e5c9fe0
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/cdc/usbh_cdc_acm.c b/components/drivers/usb/cherryusb/class/cdc/usbh_cdc_acm.c
new file mode 100644
index 0000000000..05184af81c
--- /dev/null
+++ b/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
+};
diff --git a/components/drivers/usb/cherryusb/class/cdc/usbh_cdc_acm.h b/components/drivers/usb/cherryusb/class/cdc/usbh_cdc_acm.h
new file mode 100644
index 0000000000..80800bf9f2
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ecm.c b/components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ecm.c
new file mode 100644
index 0000000000..5e3ae7bc71
--- /dev/null
+++ b/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
+};
\ No newline at end of file
diff --git a/components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ecm.h b/components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ecm.h
new file mode 100644
index 0000000000..d965ac88a5
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ncm.c b/components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ncm.c
new file mode 100644
index 0000000000..4f13f791ea
--- /dev/null
+++ b/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
+};
diff --git a/components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ncm.h b/components/drivers/usb/cherryusb/class/cdc/usbh_cdc_ncm.h
new file mode 100644
index 0000000000..5f069401fa
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/dfu/usb_dfu.h b/components/drivers/usb/cherryusb/class/dfu/usb_dfu.h
new file mode 100644
index 0000000000..f1ccba88cf
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/dfu/usbd_dfu.c b/components/drivers/usb/cherryusb/class/dfu/usbd_dfu.c
new file mode 100644
index 0000000000..a870aee3a9
--- /dev/null
+++ b/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)
+{
+}
diff --git a/components/drivers/usb/cherryusb/class/dfu/usbd_dfu.h b/components/drivers/usb/cherryusb/class/dfu/usbd_dfu.h
new file mode 100644
index 0000000000..9081d0dda1
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/hid/usb_hid.h b/components/drivers/usb/cherryusb/class/hid/usb_hid.h
new file mode 100644
index 0000000000..5a88a34be4
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/hid/usbd_hid.c b/components/drivers/usb/cherryusb/class/hid/usbd_hid.c
new file mode 100644
index 0000000000..d98b82eb84
--- /dev/null
+++ b/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)
+{
+}
\ No newline at end of file
diff --git a/components/drivers/usb/cherryusb/class/hid/usbd_hid.h b/components/drivers/usb/cherryusb/class/hid/usbd_hid.h
new file mode 100644
index 0000000000..d5c3484f2f
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/hid/usbh_hid.c b/components/drivers/usb/cherryusb/class/hid/usbh_hid.c
new file mode 100644
index 0000000000..f3b2546f22
--- /dev/null
+++ b/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
+};
diff --git a/components/drivers/usb/cherryusb/class/hid/usbh_hid.h b/components/drivers/usb/cherryusb/class/hid/usbh_hid.h
new file mode 100644
index 0000000000..17caaba277
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/hub/usb_hub.h b/components/drivers/usb/cherryusb/class/hub/usb_hub.h
new file mode 100644
index 0000000000..7956b163e7
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/hub/usbh_hub.c b/components/drivers/usb/cherryusb/class/hub/usbh_hub.c
new file mode 100644
index 0000000000..6755b8594c
--- /dev/null
+++ b/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
diff --git a/components/drivers/usb/cherryusb/class/hub/usbh_hub.h b/components/drivers/usb/cherryusb/class/hub/usbh_hub.h
new file mode 100644
index 0000000000..1f34c53ba7
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/midi/usb_midi.h b/components/drivers/usb/cherryusb/class/midi/usb_midi.h
new file mode 100644
index 0000000000..3e7a846f4e
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/msc/usb_msc.h b/components/drivers/usb/cherryusb/class/msc/usb_msc.h
new file mode 100644
index 0000000000..75187f5ee6
--- /dev/null
+++ b/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 */
diff --git a/components/drivers/usb/cherryusb/class/msc/usb_scsi.h b/components/drivers/usb/cherryusb/class/msc/usb_scsi.h
new file mode 100644
index 0000000000..7eeb50a72c
--- /dev/null
+++ b/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