mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-02-06 00:45:22 +08:00
update(cherryusb): update to v1.6.0
Some checks failed
ToolsCI / Tools (push) Has been cancelled
RT-Thread BSP Static Build Check / 🔍 Summary of Git Diff Changes (push) Has been cancelled
RT-Thread BSP Static Build Check / ${{ matrix.legs.RTT_BSP }} (push) Has been cancelled
RT-Thread BSP Static Build Check / collect-artifacts (push) Has been cancelled
pkgs_test / change (push) Has been cancelled
utest_auto_run / A9 :components/dfs.cfg (push) Has been cancelled
utest_auto_run / A9 :components/lwip.cfg (push) Has been cancelled
utest_auto_run / A9 :components/netdev.cfg (push) Has been cancelled
utest_auto_run / A9 :components/sal.cfg (push) Has been cancelled
utest_auto_run / A9 :cpp11/cpp11.cfg (push) Has been cancelled
utest_auto_run / AARCH64-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / A9-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / XUANTIE-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64 :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :default.cfg (push) Has been cancelled
utest_auto_run / A9-smp :default.cfg (push) Has been cancelled
utest_auto_run / RISCV :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / RISCV :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/ipc.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/kernel_basic.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/mem.cfg (push) Has been cancelled
Some checks failed
ToolsCI / Tools (push) Has been cancelled
RT-Thread BSP Static Build Check / 🔍 Summary of Git Diff Changes (push) Has been cancelled
RT-Thread BSP Static Build Check / ${{ matrix.legs.RTT_BSP }} (push) Has been cancelled
RT-Thread BSP Static Build Check / collect-artifacts (push) Has been cancelled
pkgs_test / change (push) Has been cancelled
utest_auto_run / A9 :components/dfs.cfg (push) Has been cancelled
utest_auto_run / A9 :components/lwip.cfg (push) Has been cancelled
utest_auto_run / A9 :components/netdev.cfg (push) Has been cancelled
utest_auto_run / A9 :components/sal.cfg (push) Has been cancelled
utest_auto_run / A9 :cpp11/cpp11.cfg (push) Has been cancelled
utest_auto_run / AARCH64-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / A9-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / XUANTIE-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64 :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :default.cfg (push) Has been cancelled
utest_auto_run / A9-smp :default.cfg (push) Has been cancelled
utest_auto_run / RISCV :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / RISCV :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/ipc.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/kernel_basic.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/mem.cfg (push) Has been cancelled
Signed-off-by: sakumisu <1203593632@qq.com>
This commit is contained in:
@@ -1 +1 @@
|
||||
rsource "cherryusb/Kconfig.rtt"
|
||||
rsource "cherryusb/Kconfig"
|
||||
|
||||
1
components/drivers/usb/cherryusb/.gitignore
vendored
1
components/drivers/usb/cherryusb/.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
.vscode
|
||||
build
|
||||
**/Drivers/**
|
||||
**/MDK-ARM/DebugConfig/**
|
||||
**/MDK-ARM/RTE/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,462 +0,0 @@
|
||||
# Kconfig file for package CherryUSB
|
||||
menuconfig RT_USING_CHERRYUSB
|
||||
bool "Using USB with CherryUSB"
|
||||
default n
|
||||
|
||||
if RT_USING_CHERRYUSB
|
||||
|
||||
menuconfig RT_CHERRYUSB_DEVICE
|
||||
bool "Enable usb device mode"
|
||||
default n
|
||||
|
||||
if RT_CHERRYUSB_DEVICE
|
||||
choice
|
||||
prompt "Select usb device speed"
|
||||
default RT_CHERRYUSB_DEVICE_SPEED_FS
|
||||
config RT_CHERRYUSB_DEVICE_SPEED_FS
|
||||
bool "FS"
|
||||
config RT_CHERRYUSB_DEVICE_SPEED_HS
|
||||
bool "HS"
|
||||
config RT_CHERRYUSB_DEVICE_SPEED_AUTO
|
||||
bool "AUTO"
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Select usb device ip, and some ip need config in usb_config.h, please check"
|
||||
default RT_CHERRYUSB_DEVICE_CUSTOM
|
||||
config RT_CHERRYUSB_DEVICE_CUSTOM
|
||||
bool "CUSTOM (Implement it yourself)"
|
||||
config RT_CHERRYUSB_DEVICE_FSDEV_ST
|
||||
bool "fsdev_st"
|
||||
config RT_CHERRYUSB_DEVICE_FSDEV_CUSTOM
|
||||
bool "fsdev_custom"
|
||||
config RT_CHERRYUSB_DEVICE_DWC2_ST
|
||||
bool "dwc2_st"
|
||||
config RT_CHERRYUSB_DEVICE_DWC2_ESP
|
||||
bool "dwc2_esp"
|
||||
config RT_CHERRYUSB_DEVICE_DWC2_KENDRYTE
|
||||
bool "dwc2_kendryte"
|
||||
config RT_CHERRYUSB_DEVICE_DWC2_AT
|
||||
bool "dwc2_at"
|
||||
config RT_CHERRYUSB_DEVICE_DWC2_HC
|
||||
bool "dwc2_hc"
|
||||
config RT_CHERRYUSB_DEVICE_DWC2_NATION
|
||||
bool "dwc2_nation"
|
||||
config RT_CHERRYUSB_DEVICE_DWC2_GD
|
||||
bool "dwc2_gd"
|
||||
config RT_CHERRYUSB_DEVICE_DWC2_CUSTOM
|
||||
bool "dwc2_custom"
|
||||
config RT_CHERRYUSB_DEVICE_MUSB_ES
|
||||
bool "musb_es"
|
||||
config RT_CHERRYUSB_DEVICE_MUSB_SUNXI
|
||||
bool "musb_sunxi"
|
||||
config RT_CHERRYUSB_DEVICE_MUSB_BK
|
||||
bool "musb_bk"
|
||||
config RT_CHERRYUSB_DEVICE_MUSB_SIFLI
|
||||
bool "musb_sifli"
|
||||
config RT_CHERRYUSB_DEVICE_MUSB_CUSTOM
|
||||
bool "musb_custom"
|
||||
config RT_CHERRYUSB_DEVICE_CHIPIDEA_MCX
|
||||
bool "chipidea_mcx"
|
||||
config RT_CHERRYUSB_DEVICE_CHIPIDEA_CUSTOM
|
||||
bool "chipidea_custom"
|
||||
config RT_CHERRYUSB_DEVICE_KINETIS_MCX
|
||||
bool "kinetis_mcx"
|
||||
config RT_CHERRYUSB_DEVICE_KINETIS_MM32
|
||||
bool "kinetis_mm32"
|
||||
config RT_CHERRYUSB_DEVICE_KINETIS_CUSTOM
|
||||
bool "kinetis_custom"
|
||||
config RT_CHERRYUSB_DEVICE_BL
|
||||
bool "bouffalo"
|
||||
config RT_CHERRYUSB_DEVICE_HPM
|
||||
bool "hpm"
|
||||
config RT_CHERRYUSB_DEVICE_AIC
|
||||
bool "aic"
|
||||
config RT_CHERRYUSB_DEVICE_RP2040
|
||||
bool "rp2040"
|
||||
config RT_CHERRYUSB_DEVICE_CH32
|
||||
bool "ch32"
|
||||
config RT_CHERRYUSB_DEVICE_PUSB2
|
||||
bool "pusb2"
|
||||
config RT_CHERRYUSB_DEVICE_NRF5X
|
||||
bool "nrf5x"
|
||||
endchoice
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_CDC_ACM
|
||||
bool
|
||||
prompt "Enable usb cdc acm device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_HID
|
||||
bool
|
||||
prompt "Enable usb hid device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_MSC
|
||||
bool
|
||||
prompt "Enable usb msc device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_AUDIO
|
||||
bool
|
||||
prompt "Enable usb audio device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_VIDEO
|
||||
bool
|
||||
prompt "Enable usb video device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_CDC_RNDIS
|
||||
bool
|
||||
prompt "Enable usb cdc rndis device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_CDC_ECM
|
||||
bool
|
||||
prompt "Enable usb cdc ecm device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_CDC_NCM
|
||||
bool
|
||||
prompt "Enable usb cdc ncm device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_MTP
|
||||
bool
|
||||
prompt "Enable usb mtp device, it is commercial charge"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_ADB
|
||||
bool
|
||||
prompt "Enable usb adb device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_DFU
|
||||
bool
|
||||
prompt "Enable usb dfu device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
|
||||
bool
|
||||
prompt "Enable chardev for cdc acm device"
|
||||
default n
|
||||
|
||||
config CONFIG_USBDEV_REQUEST_BUFFER_LEN
|
||||
int
|
||||
prompt "Set device control transfer max buffer size"
|
||||
default 512
|
||||
|
||||
config CONFIG_USBDEV_MSC_MAX_BUFSIZE
|
||||
int
|
||||
prompt "Set usb msc device max buffer size"
|
||||
default 512
|
||||
help
|
||||
Set the maximum buffer size for usb msc device, it is used to transfer data.
|
||||
you can change it to a larger value if you need larger speed but must be a power of blocksize.
|
||||
|
||||
config CONFIG_USBDEV_RNDIS_USING_LWIP
|
||||
bool
|
||||
prompt "Enable usb rndis device with lwip for lan"
|
||||
default n
|
||||
|
||||
config CONFIG_USBDEV_CDC_ECM_USING_LWIP
|
||||
bool
|
||||
prompt "Enable usb cdc ecm device with lwip for lan"
|
||||
default n
|
||||
|
||||
choice
|
||||
prompt "Select usb device template, please select class driver first"
|
||||
default RT_CHERRYUSB_DEVICE_TEMPLATE_NONE
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_NONE
|
||||
bool
|
||||
prompt "none (Implement it yourself)"
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM
|
||||
bool
|
||||
prompt "cdc_acm"
|
||||
depends on RT_CHERRYUSB_DEVICE_CDC_ACM
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_MSC
|
||||
bool
|
||||
prompt "msc_ram"
|
||||
depends on RT_CHERRYUSB_DEVICE_MSC
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_MSC_BLKDEV
|
||||
bool
|
||||
prompt "msc_blkdev"
|
||||
depends on RT_CHERRYUSB_DEVICE_MSC
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_HID_KEYBOARD
|
||||
bool
|
||||
prompt "hid_keyboard"
|
||||
depends on RT_CHERRYUSB_DEVICE_HID
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_HID_MOUSE
|
||||
bool
|
||||
prompt "hid_mouse"
|
||||
depends on RT_CHERRYUSB_DEVICE_HID
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_HID_CUSTOM
|
||||
bool
|
||||
prompt "hid_custom"
|
||||
depends on RT_CHERRYUSB_DEVICE_HID
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_VIDEO
|
||||
bool
|
||||
prompt "video"
|
||||
depends on RT_CHERRYUSB_DEVICE_VIDEO
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V1_MIC_SPEAKER
|
||||
bool
|
||||
prompt "audio_v1_mic_speaker_multichan"
|
||||
depends on RT_CHERRYUSB_DEVICE_AUDIO
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_AUDIO_V2_MIC_SPEAKER
|
||||
bool
|
||||
prompt "audio_v2_mic_speaker_multichan"
|
||||
depends on RT_CHERRYUSB_DEVICE_AUDIO
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_RNDIS
|
||||
bool
|
||||
prompt "cdc_rndis"
|
||||
depends on RT_CHERRYUSB_DEVICE_CDC_RNDIS
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ECM
|
||||
bool
|
||||
prompt "cdc_ecm"
|
||||
depends on RT_CHERRYUSB_DEVICE_CDC_ECM
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM
|
||||
bool
|
||||
prompt "cdc_ncm"
|
||||
depends on RT_CHERRYUSB_DEVICE_CDC_NCM
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
|
||||
bool
|
||||
prompt "cdc_acm_msc"
|
||||
depends on RT_CHERRYUSB_DEVICE_CDC_ACM && RT_CHERRYUSB_DEVICE_MSC
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID
|
||||
bool
|
||||
prompt "cdc_acm_msc_hid"
|
||||
depends on RT_CHERRYUSB_DEVICE_CDC_ACM && RT_CHERRYUSB_DEVICE_MSC && RT_CHERRYUSB_DEVICE_HID
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1
|
||||
bool
|
||||
prompt "winusbv1"
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC
|
||||
bool
|
||||
prompt "winusbv2_cdc"
|
||||
depends on RT_CHERRYUSB_DEVICE_CDC_ACM
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_HID
|
||||
bool
|
||||
prompt "winusbv2_hid"
|
||||
depends on RT_CHERRYUSB_DEVICE_HID
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_ADB
|
||||
bool
|
||||
prompt "adb"
|
||||
depends on RT_CHERRYUSB_DEVICE_ADB
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_CHARDEV
|
||||
bool
|
||||
prompt "cdc_acm_chardev"
|
||||
depends on RT_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
|
||||
endchoice
|
||||
|
||||
config CONFIG_USBDEV_MSC_BLOCK_DEV_NAME
|
||||
string "usb device msc block device name"
|
||||
depends on RT_CHERRYUSB_DEVICE_TEMPLATE_MSC_BLKDEV
|
||||
default "sd0"
|
||||
|
||||
endif
|
||||
|
||||
menuconfig RT_CHERRYUSB_HOST
|
||||
bool "Enable usb host mode"
|
||||
default n
|
||||
|
||||
if RT_CHERRYUSB_HOST
|
||||
choice
|
||||
prompt "Select usb host ip, and some ip need config in usb_config.h, please check"
|
||||
default RT_CHERRYUSB_HOST_CUSTOM
|
||||
config RT_CHERRYUSB_HOST_CUSTOM
|
||||
bool "CUSTOM (Implement it yourself)"
|
||||
config RT_CHERRYUSB_HOST_EHCI_BL
|
||||
bool "ehci_bouffalo"
|
||||
config RT_CHERRYUSB_HOST_EHCI_HPM
|
||||
bool "ehci_hpm"
|
||||
config RT_CHERRYUSB_HOST_EHCI_AIC
|
||||
bool "ehci_aic"
|
||||
config RT_CHERRYUSB_HOST_EHCI_MCX
|
||||
bool "ehci_mcx"
|
||||
config RT_CHERRYUSB_HOST_EHCI_NUC980
|
||||
bool "ehci_nuc980"
|
||||
config RT_CHERRYUSB_HOST_EHCI_MA35D0
|
||||
bool "ehci_ma35d0"
|
||||
config RT_CHERRYUSB_HOST_EHCI_CUSTOM
|
||||
bool "ehci_custom"
|
||||
config RT_CHERRYUSB_HOST_DWC2_ST
|
||||
bool "dwc2_st"
|
||||
config RT_CHERRYUSB_HOST_DWC2_ESP
|
||||
bool "dwc2_esp"
|
||||
config RT_CHERRYUSB_HOST_DWC2_KENDRYTE
|
||||
bool "dwc2_kendryte"
|
||||
config RT_CHERRYUSB_HOST_DWC2_HC
|
||||
bool "dwc2_hc"
|
||||
config RT_CHERRYUSB_HOST_DWC2_NATION
|
||||
bool "dwc2_nation"
|
||||
config RT_CHERRYUSB_HOST_DWC2_CUSTOM
|
||||
bool "dwc2_custom"
|
||||
config RT_CHERRYUSB_HOST_MUSB_ES
|
||||
bool "musb_es"
|
||||
config RT_CHERRYUSB_HOST_MUSB_SUNXI
|
||||
bool "musb_sunxi"
|
||||
config RT_CHERRYUSB_HOST_MUSB_BK
|
||||
bool "musb_bk"
|
||||
config RT_CHERRYUSB_HOST_MUSB_SIFLI
|
||||
bool "musb_sifli"
|
||||
config RT_CHERRYUSB_HOST_MUSB_CUSTOM
|
||||
bool "musb_custom"
|
||||
config RT_CHERRYUSB_HOST_PUSB2
|
||||
bool "pusb2"
|
||||
config RT_CHERRYUSB_HOST_XHCI
|
||||
bool "xhci"
|
||||
config RT_CHERRYUSB_HOST_RP2040
|
||||
bool "rp2040"
|
||||
endchoice
|
||||
|
||||
config RT_CHERRYUSB_HOST_CDC_ACM
|
||||
bool
|
||||
prompt "Enable usb cdc acm driver"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_HID
|
||||
bool
|
||||
prompt "Enable usb hid driver"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_MSC
|
||||
bool
|
||||
prompt "Enable usb msc driver"
|
||||
default n
|
||||
select RT_USING_DFS
|
||||
select RT_USING_DFS_ELMFAT
|
||||
|
||||
config RT_CHERRYUSB_HOST_CDC_ECM
|
||||
bool
|
||||
prompt "Enable usb cdc ecm driver"
|
||||
select RT_USING_LWIP
|
||||
select CONFIG_USBHOST_PLATFORM_CDC_ECM
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_CDC_RNDIS
|
||||
bool
|
||||
prompt "Enable usb rndis driver"
|
||||
select RT_USING_LWIP
|
||||
select CONFIG_USBHOST_PLATFORM_CDC_RNDIS
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_CDC_NCM
|
||||
bool
|
||||
prompt "Enable usb cdc ncm driver"
|
||||
select RT_USING_LWIP
|
||||
select CONFIG_USBHOST_PLATFORM_CDC_NCM
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_VIDEO
|
||||
bool
|
||||
prompt "Enable usb video driver, it is commercial charge"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_AUDIO
|
||||
bool
|
||||
prompt "Enable usb audio driver, it is commercial charge"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_BLUETOOTH
|
||||
bool
|
||||
prompt "Enable usb bluetooth driver"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_ASIX
|
||||
bool
|
||||
prompt "Enable usb asix driver"
|
||||
select RT_USING_LWIP
|
||||
select CONFIG_USBHOST_PLATFORM_ASIX
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_RTL8152
|
||||
bool
|
||||
prompt "Enable usb rtl8152 driver"
|
||||
select RT_USING_LWIP
|
||||
select CONFIG_USBHOST_PLATFORM_RTL8152
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_FTDI
|
||||
bool
|
||||
prompt "Enable usb ftdi driver"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_CH34X
|
||||
bool
|
||||
prompt "Enable usb ch34x driver"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_CP210X
|
||||
bool
|
||||
prompt "Enable usb cp210x driver"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_PL2303
|
||||
bool
|
||||
prompt "Enable usb pl2303 driver"
|
||||
default n
|
||||
|
||||
config CONFIG_USBHOST_PLATFORM_CDC_ECM
|
||||
bool
|
||||
|
||||
config CONFIG_USBHOST_PLATFORM_CDC_RNDIS
|
||||
bool
|
||||
|
||||
config CONFIG_USBHOST_PLATFORM_CDC_NCM
|
||||
bool
|
||||
|
||||
config CONFIG_USBHOST_PLATFORM_ASIX
|
||||
bool
|
||||
|
||||
config CONFIG_USBHOST_PLATFORM_RTL8152
|
||||
bool
|
||||
|
||||
config CONFIG_USBHOST_PSC_PRIO
|
||||
int
|
||||
prompt "Set hubport change thread priority, 0 is the max priority"
|
||||
default 0
|
||||
|
||||
config CONFIG_USBHOST_PSC_STACKSIZE
|
||||
int
|
||||
prompt "Set hubport change thread stacksize"
|
||||
default 4096
|
||||
|
||||
config CONFIG_USBHOST_REQUEST_BUFFER_LEN
|
||||
int
|
||||
prompt "Set host control transfer max buffer size"
|
||||
default 512
|
||||
|
||||
config CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
|
||||
int
|
||||
prompt "Set host control transfer timeout, unit is ms"
|
||||
default 500
|
||||
|
||||
config RT_LWIP_PBUF_POOL_BUFSIZE
|
||||
int "The size of each pbuf in the pbuf pool"
|
||||
range 1500 2000
|
||||
default 1600
|
||||
|
||||
config CONFIG_USB_DFS_MOUNT_POINT
|
||||
string "usb host dfs mount point"
|
||||
depends on RT_CHERRYUSB_HOST_MSC
|
||||
default "/"
|
||||
|
||||
menu "Select USB host template, please select class driver first"
|
||||
config CONFIG_TEST_USBH_CDC_ACM
|
||||
int
|
||||
prompt "demo for test cdc acm, cannot enable this demo, we have used serial framework instead"
|
||||
default 0
|
||||
depends on RT_CHERRYUSB_HOST_CDC_ACM
|
||||
config CONFIG_TEST_USBH_HID
|
||||
int
|
||||
prompt "demo for test hid"
|
||||
default 0
|
||||
depends on RT_CHERRYUSB_HOST_HID
|
||||
config CONFIG_TEST_USBH_MSC
|
||||
int
|
||||
prompt "demo for test msc, cannot enable this demo, we have used dfs instead"
|
||||
default 0
|
||||
depends on RT_CHERRYUSB_HOST_MSC
|
||||
endmenu
|
||||
endif
|
||||
endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,8 @@ Taking into account USB performance issues and trying to achieve the theoretical
|
||||
- Unlimited length make it easier to interface with hardware DMA and take advantage of DMA
|
||||
- Packetization is handled in interrupt
|
||||
|
||||
Performance show:https://cherryusb.cherry-embedded.org/show/
|
||||
|
||||
## Directory Structure
|
||||
|
||||
| Directory | Description |
|
||||
@@ -103,14 +105,15 @@ CherryUSB Host Stack has the following functions:
|
||||
- Support blocking transfers and asynchronous transfers
|
||||
- Support Composite Device
|
||||
- Multi-level HUB support, expandable up to 7 levels(Testing hub with 10 ports works well,only support dwc2/ehci/xhci/rp2040)
|
||||
- Support Communication Device Class (CDC_ACM, CDC_ECM)
|
||||
- Support Communication Device Class (CDC_ACM, CDC_ECM, CDC_NCM)
|
||||
- Support Human Interface Device (HID)
|
||||
- Support Mass Storage Class (MSC)
|
||||
- Support USB Video CLASS (UVC1.0, UVC1.5)
|
||||
- Support USB Audio CLASS (UAC1.0)
|
||||
- Support Remote NDIS (RNDIS)
|
||||
- Support USB Bluetooth class (support nimble and zephyr bluetooth stack, support **CLASS:0xE0** or vendor class like cdc acm)
|
||||
- Support Vendor class (serial, net, wifi)
|
||||
- Support Vendor Serial Class(CH34X、CP210X、PL2303、FTDI、GSM)
|
||||
- Support Vendor network Class(RTL8152、AX88772)
|
||||
- Support USB modeswitch
|
||||
- Support Android Open Accessory
|
||||
- Support multi host with the same USB IP
|
||||
@@ -141,14 +144,14 @@ Among them, `sizeof(struct usbh_hub)` and `sizeof(struct usbh_hubport)` are affe
|
||||
#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_INTF_ALTSETTINGS 2
|
||||
#define CONFIG_USBHOST_MAX_ENDPOINTS 4
|
||||
```
|
||||
|
||||
x is affected by the following macros:
|
||||
|
||||
```
|
||||
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_SERIAL_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_HID_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
|
||||
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
|
||||
@@ -179,32 +182,33 @@ Quickly start, USB basic concepts, API manual, Class basic concepts and examples
|
||||
|
||||
## Video Tutorial
|
||||
|
||||
CherryUSB Cheese (based V1.4.3): https://www.bilibili.com/cheese/play/ss707687201 .
|
||||
CherryUSB Cheese (>= V1.4.3): https://www.bilibili.com/cheese/play/ss707687201 .
|
||||
|
||||
## Descriptor Generator Tool
|
||||
|
||||
TODO
|
||||
Cherry Descriptor: https://desc.cherry-embedded.org/en
|
||||
|
||||
## Demo Repo
|
||||
|
||||
| Manufacturer | CHIP or Series | USB IP| Repo Url | Support version | Support status |
|
||||
| Manufacturer | CHIP or Series | USB IP| Repo Url | Support version | Note |
|
||||
|:--------------------:|:------------------:|:-----:|:--------:|:------------------:|:-------------:|
|
||||
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/bouffalo_sdk)|<= latest | Long-term |
|
||||
|ST | STM32F1x/STM32F4/STM32H7 | fsdev/dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Long-term |
|
||||
|HPMicro | HPM6000/HPM5000 | 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)|>=1.4.0 | Long-term |
|
||||
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Long-term |
|
||||
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | Long-term |
|
||||
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Long-term |
|
||||
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/k230_sdk)|v1.2.0 | Long-term |
|
||||
|Actionstech | ATS30xx | dwc2 |[action_zephyr_repo](https://github.com/CherryUSB/lv_port_actions_technology/tree/master/action_technology_sdk)|>=1.4.0 | Long-term |
|
||||
|Nationstech | n32h4x | dwc2 |[nation_repo](https://github.com/CherryUSB/cherryusb_nation)|>=1.5.0 | Long-term |
|
||||
|Raspberry pi | rp2040/rp2350 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|<= latest | Long-term |
|
||||
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with musb |
|
||||
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | the same with musb |
|
||||
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | TBD |
|
||||
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2/>=v1.5.0 | TBD |
|
||||
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/bouffalo_sdk)|<= latest | Official |
|
||||
|ST | STM32F1x/STM32F4/STM32H7 | fsdev/dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Community |
|
||||
|HPMicro | HPM6000/HPM5000 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/hpm_sdk)|<= latest | Official |
|
||||
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Official |
|
||||
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|>=1.4.0 | Official |
|
||||
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Official |
|
||||
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)/[espressif](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb)|<= latest | Official |
|
||||
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/k230_sdk)|v1.2.0 | Official |
|
||||
|Actionstech | ATS30xx | dwc2 |[action_zephyr_repo](https://github.com/CherryUSB/lv_port_actions_technology/tree/master/action_technology_sdk)|>=1.4.0 | Official |
|
||||
|SiFli | SF32LB5x | musb |[SiFli_sdk](https://github.com/OpenSiFli/SiFli-SDK)|>=1.5.0 | Official |
|
||||
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Community |
|
||||
|Nationstech | n32h4x | dwc2 |[nation_repo](https://github.com/CherryUSB/cherryusb_nation)|>=1.5.0 | Official ongoing |
|
||||
|Raspberry pi | rp2040/rp2350 | rp2040 |[pico-sdk](https://github.com/CherryUSB/pico-sdk)|<= latest | Official ongoing |
|
||||
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | no more update |
|
||||
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | Official |
|
||||
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | Official |
|
||||
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2/>=v1.5.0 | no more update |
|
||||
|
||||
## Package Support
|
||||
|
||||
@@ -226,5 +230,4 @@ CherryUSB discord: https://discord.com/invite/wFfvrSAey8.
|
||||
|
||||
Thanks to the following companies for their support (in no particular order):
|
||||
|
||||
<img src="docs/assets/bouffalolab.jpg" width="100" height="80"/> <img src="docs/assets/hpmicro.jpg" width="100" height="80" /> <img src="docs/assets/eastsoft.jpg" width="100" height="80" /> <img src="docs/assets/rtthread.jpg" width="100" height="80" /> <img src="docs/assets/sophgo.jpg" width="100" height="80" /> <img src="docs/assets/phytium.jpg" width="100" height="80" /> <img src="docs/assets/thead.jpg" width="100" height="80" /> <img src="docs/assets/nuvoton.jpg" width="100" height="80" /> <img src="docs/assets/artinchip.jpg" width="100" height="80" /> <img src="docs/assets/bekencorp.jpg" width="100" height="80" /> <img src="docs/assets/nxp.png" width="100" height="80" /> <img src="docs/assets/espressif.png" width="100" height="80" /> <img src="docs/assets/canaan.jpg" width="100" height="80" />
|
||||
<img src="docs/assets/actions.jpg" width="100" height="80" /> <img src="docs/assets/nationstech.jpg" width="100" height="80" />
|
||||
<img src="docs/assets/bouffalolab.jpg" width="100" height="80"/> <img src="docs/assets/hpmicro.jpg" width="100" height="80" /> <img src="docs/assets/eastsoft.jpg" width="100" height="80" /> <img src="docs/assets/rtthread.jpg" width="100" height="80" /> <img src="docs/assets/sophgo.jpg" width="100" height="80" /> <img src="docs/assets/phytium.jpg" width="100" height="80" /> <img src="docs/assets/thead.jpg" width="100" height="80" /> <img src="docs/assets/nuvoton.jpg" width="100" height="80" /> <img src="docs/assets/artinchip.jpg" width="100" height="80" /> <img src="docs/assets/bekencorp.jpg" width="100" height="80" /> <img src="docs/assets/nxp.png" width="100" height="80" /> <img src="docs/assets/espressif.png" width="100" height="80" /> <img src="docs/assets/canaan.jpg" width="100" height="80" /> <img src="docs/assets/actions.jpg" width="100" height="80" /> <img src="docs/assets/sifli.jpg" width="100" height="80" /> <img src="docs/assets/nationstech.jpg" width="100" height="80" />
|
||||
|
||||
@@ -112,7 +112,8 @@ CherryUSB Host 协议栈当前实现以下功能:
|
||||
- Support USB Audio CLASS (UAC1.0)
|
||||
- 支持 Remote NDIS (RNDIS)
|
||||
- 支持 USB Bluetooth (支持 nimble and zephyr bluetooth 协议栈,支持 **CLASS: 0xE0** 或者厂家自定义类,类似于 cdc acm 功能)
|
||||
- 支持 Vendor 类 class (serial, net, wifi)
|
||||
- 支持 Vendor Serial 类(CH34X、CP210X、PL2303、FTDI、GSM)
|
||||
- 支持 Vendor network 类(RTL8152、AX88772)
|
||||
- 支持 USB modeswitch
|
||||
- 支持 Android Open Accessory
|
||||
- 支持相同 USB IP 的多主机
|
||||
@@ -150,7 +151,7 @@ CherryUSB Host 协议栈资源占用说明(GCC 10.2 with -O2,关闭 log)
|
||||
x 受以下宏影响:
|
||||
|
||||
```
|
||||
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_SERIAL_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_HID_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
|
||||
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
|
||||
@@ -181,11 +182,11 @@ CherryUSB 快速入门、USB 基本概念、API 手册、Class 基本概念和
|
||||
|
||||
## 视频教程
|
||||
|
||||
CherryUSB 课程(基于 V1.4.3):https://www.bilibili.com/cheese/play/ss707687201 。
|
||||
CherryUSB 课程(>= V1.4.3):https://www.bilibili.com/cheese/play/ss707687201 。
|
||||
|
||||
## 描述符生成工具
|
||||
|
||||
TODO
|
||||
Cherry Descriptor: https://desc.cherry-embedded.org/zh
|
||||
|
||||
## 示例仓库
|
||||
|
||||
@@ -197,7 +198,7 @@ TODO
|
||||
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Official |
|
||||
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|>=1.4.0 | Official |
|
||||
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Official |
|
||||
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | Official ongoing |
|
||||
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)/[espressif](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb)|<= latest | Official |
|
||||
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/k230_sdk)|v1.2.0 | Official |
|
||||
|Actionstech | ATS30xx | dwc2 |[action_zephyr_repo](https://github.com/CherryUSB/lv_port_actions_technology/tree/master/action_technology_sdk)|>=1.4.0 | Official |
|
||||
|SiFli | SF32LB5x | musb |[SiFli_sdk](https://github.com/OpenSiFli/SiFli-SDK)|>=1.5.0 | Official |
|
||||
|
||||
@@ -14,9 +14,8 @@ path += [cwd + '/class/wireless']
|
||||
path += [cwd + '/class/midi']
|
||||
path += [cwd + '/class/adb']
|
||||
path += [cwd + '/class/dfu']
|
||||
path += [cwd + '/class/midi']
|
||||
path += [cwd + '/class/serial']
|
||||
path += [cwd + '/class/vendor/net']
|
||||
path += [cwd + '/class/vendor/serial']
|
||||
path += [cwd + '/class/vendor/wifi']
|
||||
src = []
|
||||
|
||||
@@ -47,6 +46,9 @@ if GetDepend(['RT_CHERRYUSB_DEVICE']):
|
||||
if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_KENDRYTE']):
|
||||
src += Glob('port/dwc2/usb_dc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_kendryte.c')
|
||||
if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_INFINEON']):
|
||||
src += Glob('port/dwc2/usb_dc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_infineon.c')
|
||||
if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_AT']):
|
||||
src += Glob('port/dwc2/usb_dc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_at.c')
|
||||
@@ -112,6 +114,9 @@ if GetDepend(['RT_CHERRYUSB_DEVICE']):
|
||||
LIBS = ['libpusb2_dc_a32_softfp_neon.a']
|
||||
if GetDepend(['RT_CHERRYUSB_DEVICE_NRF5X']):
|
||||
src += Glob('port/nrf5x/usb_dc_nrf5x.c')
|
||||
if GetDepend(['RT_CHERRYUSB_DEVICE_RP2040']):
|
||||
path += [cwd + '/port/rp2040']
|
||||
src += Glob('port/rp2040/usb_dc_rp2040.c')
|
||||
|
||||
if GetDepend(['RT_CHERRYUSB_DEVICE_CDC_ACM']):
|
||||
src += Glob('class/cdc/usbd_cdc_acm.c')
|
||||
@@ -166,10 +171,12 @@ if GetDepend(['RT_CHERRYUSB_DEVICE']):
|
||||
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']):
|
||||
src += Glob('demo/winusb2.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')
|
||||
if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_WEBUSB_HID']):
|
||||
src += Glob('demo/webusb_hid_template.c')
|
||||
if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_ADB']):
|
||||
src += Glob('demo/adb/usbd_adb_template.c')
|
||||
if GetDepend(['RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_CHARDEV']):
|
||||
@@ -216,6 +223,12 @@ if GetDepend(['RT_CHERRYUSB_HOST']):
|
||||
if GetDepend(['RT_CHERRYUSB_HOST_DWC2_KENDRYTE']):
|
||||
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_kendryte.c')
|
||||
if GetDepend(['RT_CHERRYUSB_HOST_DWC2_INFINEON']):
|
||||
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_infineon.c')
|
||||
if GetDepend(['RT_CHERRYUSB_HOST_DWC2_AT']):
|
||||
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_at.c')
|
||||
if GetDepend(['RT_CHERRYUSB_HOST_DWC2_HC']):
|
||||
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_hc.c')
|
||||
@@ -266,8 +279,12 @@ if GetDepend(['RT_CHERRYUSB_HOST']):
|
||||
LIBPATH = [cwd + '/port/xhci/phytium']
|
||||
LIBS = ['libxhci_a32_softfp_neon.a']
|
||||
|
||||
if GetDepend(['RT_CHERRYUSB_HOST_RP2040']):
|
||||
path += [cwd + '/port/rp2040']
|
||||
src += Glob('port/rp2040/usb_hc_rp2040.c')
|
||||
|
||||
if GetDepend(['RT_CHERRYUSB_HOST_CDC_ACM']):
|
||||
src += Glob('class/cdc/usbh_cdc_acm.c')
|
||||
src += Glob('class/serial/usbh_cdc_acm.c')
|
||||
if GetDepend(['RT_CHERRYUSB_HOST_HID']):
|
||||
src += Glob('class/hid/usbh_hid.c')
|
||||
if GetDepend(['RT_CHERRYUSB_HOST_MSC']):
|
||||
@@ -289,23 +306,26 @@ if GetDepend(['RT_CHERRYUSB_HOST']):
|
||||
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')
|
||||
src += Glob('class/serial/usbh_ftdi.c')
|
||||
if GetDepend(['RT_CHERRYUSB_HOST_CH34X']):
|
||||
src += Glob('class/vendor/serial/usbh_ch34x.c')
|
||||
src += Glob('class/serial/usbh_ch34x.c')
|
||||
if GetDepend(['RT_CHERRYUSB_HOST_CP210X']):
|
||||
src += Glob('class/vendor/serial/usbh_cp210x.c')
|
||||
src += Glob('class/serial/usbh_cp210x.c')
|
||||
if GetDepend(['RT_CHERRYUSB_HOST_PL2303']):
|
||||
src += Glob('class/vendor/serial/usbh_pl2303.c')
|
||||
src += Glob('class/serial/usbh_pl2303.c')
|
||||
|
||||
if GetDepend(['CONFIG_TEST_USBH_HID']):
|
||||
if GetDepend(['RT_TEST_USBH_HID']):
|
||||
CPPDEFINES+=['CONFIG_TEST_USBH_HID']
|
||||
src += Glob('demo/usb_host.c')
|
||||
|
||||
if GetDepend(['RT_CHERRYUSB_HOST_CDC_ACM']) \
|
||||
or GetDepend(['RT_CHERRYUSB_HOST_FTDI']) \
|
||||
or GetDepend(['RT_CHERRYUSB_HOST_CH34X']) \
|
||||
or GetDepend(['RT_CHERRYUSB_HOST_CP210X']) \
|
||||
or GetDepend(['RT_CHERRYUSB_HOST_PL2303']):
|
||||
src += Glob('platform/rtthread/usbh_serial.c')
|
||||
or GetDepend(['RT_CHERRYUSB_HOST_PL2303']) \
|
||||
or GetDepend(['RT_CHERRYUSB_HOST_GSM']):
|
||||
src += Glob('class/serial/usbh_serial.c')
|
||||
src += Glob('platform/rtthread/usbh_rtserial.c')
|
||||
|
||||
if GetDepend('RT_USING_DFS') and GetDepend(['RT_CHERRYUSB_HOST_MSC']):
|
||||
src += Glob('platform/rtthread/usbh_dfs.c')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 5
|
||||
PATCHLEVEL = 2
|
||||
VERSION_MINOR = 6
|
||||
PATCHLEVEL = 0
|
||||
VERSION_TWEAK = 0
|
||||
EXTRAVERSION = 0
|
||||
|
||||
@@ -47,10 +47,11 @@ list(
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/midi
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/adb
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/dfu
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/serial
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/vendor/net
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/aoa
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/gamepad
|
||||
)
|
||||
|
||||
if(CONFIG_CHERRYUSB_DEVICE)
|
||||
@@ -85,6 +86,9 @@ if(CONFIG_CHERRYUSB_DEVICE)
|
||||
if(CONFIG_CHERRYUSB_DEVICE_ADB)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/adb/usbd_adb.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_DEVICE_GAMEPAD)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/gamepad/usbd_gamepad.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_CHERRYUSB_DEVICE_FSDEV_ST)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/fsdev/usb_dc_fsdev.c)
|
||||
@@ -156,7 +160,7 @@ if(CONFIG_CHERRYUSB_HOST)
|
||||
)
|
||||
|
||||
if(CONFIG_CHERRYUSB_HOST_CDC_ACM)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbh_cdc_acm.c)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/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)
|
||||
@@ -235,30 +239,39 @@ if(CONFIG_CHERRYUSB_HOST)
|
||||
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)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_ch34x.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_CP210X)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_cp210x.c)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_cp210x.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_FTDI)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_ftdi.c)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_ftdi.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_PL2303)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_pl2303.c)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_pl2303.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_BL616)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi/usbh_bl616.c)
|
||||
if(CONFIG_CHERRYUSB_HOST_GSM)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_gsm.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_AOA)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/aoa/usbh_aoa.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_CHERRYUSB_HOST_CDC_ACM
|
||||
OR CONFIG_CHERRYUSB_HOST_CH34X
|
||||
OR CONFIG_CHERRYUSB_HOST_CP210X
|
||||
OR CONFIG_CHERRYUSB_HOST_FTDI
|
||||
OR CONFIG_CHERRYUSB_HOST_PL2303
|
||||
OR CONFIG_CHERRYUSB_HOST_GSM
|
||||
)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_serial.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_CHERRYUSB_HOST_CDC_ECM
|
||||
OR CONFIG_CHERRYUSB_HOST_CDC_RNDIS
|
||||
OR CONFIG_CHERRYUSB_HOST_CDC_NCM
|
||||
OR CONFIG_CHERRYUSB_HOST_ASIX
|
||||
OR CONFIG_CHERRYUSB_HOST_RTL8152
|
||||
OR CONFIG_CHERRYUSB_HOST_BL616
|
||||
)
|
||||
if("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "idf")
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/platform/idf/usbh_net.c)
|
||||
@@ -335,11 +348,15 @@ if(CONFIG_CHERRYUSB_HOST)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/rp2040/usb_hc_rp2040.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_TEST_USBH_CDC_ACM OR CONFIG_TEST_USBH_HID OR CONFIG_TEST_USBH_MSC)
|
||||
if(CONFIG_TEST_USBH_SERIAL OR CONFIG_TEST_USBH_HID OR CONFIG_TEST_USBH_MSC)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/demo/usb_host.c)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CONFIG_CHERRYUSB_DEVICE AND CONFIG_CHERRYUSB_HOST)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/core/usbotg_core.c)
|
||||
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)
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 2
|
||||
#define CONFIG_USBHOST_MAX_ENDPOINTS 4
|
||||
|
||||
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_SERIAL_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_HID_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
|
||||
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
|
||||
@@ -188,6 +188,10 @@
|
||||
#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBHOST_SERIAL_RX_SIZE
|
||||
#define CONFIG_USBHOST_SERIAL_RX_SIZE 2048
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBHOST_MSC_TIMEOUT
|
||||
#define CONFIG_USBHOST_MSC_TIMEOUT 5000
|
||||
#endif
|
||||
@@ -301,6 +305,7 @@
|
||||
/* ---------------- MUSB Configuration ---------------- */
|
||||
#define CONFIG_USB_MUSB_PIPE_NUM 8
|
||||
// #define CONFIG_USB_MUSB_SUNXI
|
||||
// #define CONFIG_USB_MUSB_WITHOUT_MULTIPOINT
|
||||
|
||||
/* When your chip hardware supports high-speed and wants to initialize it in high-speed mode,
|
||||
* the relevant IP will configure the internal or external high-speed PHY according to CONFIG_USB_HS.
|
||||
@@ -317,4 +322,7 @@
|
||||
#define usb_ramaddr2phyaddr(addr) (addr)
|
||||
#endif
|
||||
|
||||
/* Enable OTG support, only support hpmicro now */
|
||||
// #define CONFIG_USB_OTG_ENABLE
|
||||
|
||||
#endif
|
||||
|
||||
@@ -176,9 +176,6 @@ int usbh_aoa_register_hid(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *repo
|
||||
int usbh_aoa_send_hid_event(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *event, uint32_t event_len)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
int ret;
|
||||
uint8_t len;
|
||||
uint32_t offset;
|
||||
|
||||
if (!aoa_class || !aoa_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
@@ -198,7 +195,6 @@ int usbh_aoa_send_hid_event(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *ev
|
||||
static int usbh_aoa_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret = 0;
|
||||
|
||||
struct usbh_aoa *aoa_class = &g_aoa_class;
|
||||
|
||||
|
||||
@@ -88,18 +88,6 @@
|
||||
#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
|
||||
@@ -245,22 +233,34 @@
|
||||
#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)
|
||||
/* 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
|
||||
|
||||
#define AUDIO_V2_CONTROL_UNDEF 0x00
|
||||
#define AUDIO_V2_CONTROL_MUTE (0x03 << 0)
|
||||
#define AUDIO_V2_CONTROL_VOLUME (0x03 << 2)
|
||||
#define AUDIO_V2_CONTROL_BASS (0x03 << 4)
|
||||
#define AUDIO_V2_CONTROL_MID (0x03 << 6)
|
||||
#define AUDIO_V2_CONTROL_TREBLE (0x03 << 8)
|
||||
#define AUDIO_V2_CONTROL_EQUALIZER (0x03 << 10)
|
||||
#define AUDIO_V2_CONTROL_AGC (0x03 << 12)
|
||||
#define AUDIO_V2_CONTROL_DELAY (0x03 << 14)
|
||||
#define AUDIO_V2_CONTROL_BASS_BOOST (0x03 << 16)
|
||||
#define AUDIO_V2_CONTROL_LOUDNESS (0x03 << 18)
|
||||
#define AUDIO_V2_CONTROL_INP_GAIN (0x03 << 20)
|
||||
#define AUDIO_V2_CONTROL_INP_GAIN_PAD (0x03 << 22)
|
||||
#define AUDIO_V2_CONTROL_PHASE_INVERT (0x03 << 24)
|
||||
#define AUDIO_V2_CONTROL_UNDERFLOW (0x03 << 26)
|
||||
#define AUDIO_V2_CONTROL_OVERFLOW (0x03 << 28)
|
||||
|
||||
/* Parametric Equalizer Section Effect Unit Control Selectors */
|
||||
#define AUDIO_PE_CONTROL_UNDEF 0x00
|
||||
@@ -605,7 +605,7 @@ struct audio_cs_if_ac_header_descriptor {
|
||||
uint8_t baInterfaceNr[];
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_SIZEOF_AC_HEADER_DESC(n) (8 + n)
|
||||
#define AUDIO_SIZEOF_AC_HEADER_DESC(bInCollection) (8 + (bInCollection))
|
||||
|
||||
struct audio_cs_if_ac_input_terminal_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -646,7 +646,7 @@ struct audio_cs_if_ac_feature_unit_descriptor {
|
||||
uint8_t iFeature;
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(ch, n) (7 + (ch + 1) * n)
|
||||
#define AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(bNrChannels, bControlSize) (7 + ((bNrChannels) + 1) * (bControlSize))
|
||||
|
||||
struct audio_cs_if_ac_selector_unit_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -658,7 +658,7 @@ struct audio_cs_if_ac_selector_unit_descriptor {
|
||||
uint8_t iSelector;
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_SIZEOF_AC_SELECTOR_UNIT_DESC(n) (6 + n)
|
||||
#define AUDIO_SIZEOF_AC_SELECTOR_UNIT_DESC(bNrInPins) (6 + (bNrInPins))
|
||||
|
||||
struct audio_cs_if_as_general_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -683,7 +683,7 @@ struct audio_cs_if_as_format_type_descriptor {
|
||||
uint8_t tSamFreq[3];
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_SIZEOF_FORMAT_TYPE_DESC(n) (8 + 3 * n)
|
||||
#define AUDIO_SIZEOF_FORMAT_TYPE_DESC(bSamFreqType) (8 + 3 * (bSamFreqType))
|
||||
|
||||
struct audio_ep_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -738,7 +738,7 @@ struct audio_cs_ep_ep_general_descriptor {
|
||||
PP_NARG(__VA_ARGS__), /* bInCollection */ \
|
||||
__VA_ARGS__ /* baInterfaceNr */
|
||||
|
||||
#define AUDIO_AC_DESCRIPTOR_INIT_LEN(n) (0x08 + 0x09 + 0x08 + n)
|
||||
#define AUDIO_AC_DESCRIPTOR_LEN(bInCollection) (0x08 + 0x09 + 0x08 + bInCollection)
|
||||
|
||||
#define AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(bTerminalID, wTerminalType, bNrChannels, wChannelConfig) \
|
||||
0x0C, /* bLength */ \
|
||||
@@ -880,8 +880,8 @@ struct audio_cs_ep_ep_general_descriptor {
|
||||
0x03, /* bRefresh, 8ms */ \
|
||||
0x00 /* bSynchAddress */
|
||||
|
||||
#define AUDIO_AS_DESCRIPTOR_INIT_LEN(n) (0x09 + 0x09 + 0x07 + 0x08 + 3 * n + 0x09 + 0x07)
|
||||
#define AUDIO_AS_FEEDBACK_DESCRIPTOR_INIT_LEN(n) (0x09 + 0x09 + 0x07 + 0x08 + 3 * n + 0x09 + 0x07 + 0x09)
|
||||
#define AUDIO_AS_DESCRIPTOR_LEN(bSamFreqType) (0x09 + 0x09 + 0x07 + 0x08 + 3 * (bSamFreqType) + 0x09 + 0x07)
|
||||
#define AUDIO_AS_FEEDBACK_DESCRIPTOR_LEN(bSamFreqType) (0x09 + 0x09 + 0x07 + 0x08 + 3 * (bSamFreqType) + 0x09 + 0x07 + 0x09)
|
||||
|
||||
#define AUDIO_AS_ALTSETTING_DESCRIPTOR_INIT(bInterfaceNumber, bAlternateSetting, bTerminalLink, bNrChannels, bSubFrameSize, bBitResolution, bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval, ...) \
|
||||
0x09, /* bLength */ \
|
||||
@@ -924,9 +924,9 @@ struct audio_cs_ep_ep_general_descriptor {
|
||||
0x00, /* wLockDelay */ \
|
||||
0x00
|
||||
|
||||
#define AUDIO_AS_ALTSETTING_DESCRIPTOR_INIT_LEN(n) (0x09 + 0x07 + 0x08 + 3 * n + 0x09 + 0x07)
|
||||
#define AUDIO_AS_ALTSETTING_DESCRIPTOR_LEN(bSamFreqType) (0x09 + 0x07 + 0x08 + 3 * (bSamFreqType) + 0x09 + 0x07)
|
||||
|
||||
#define AUDIO_AS_ALTSETTING0_DESCRIPTOR_INIT(bInterfaceNumber) \
|
||||
#define AUDIO_AS_ALTSETTING0_DESCRIPTOR_INIT(bInterfaceNumber) \
|
||||
0x09, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||
bInterfaceNumber, /* bInterfaceNumber */ \
|
||||
@@ -937,19 +937,6 @@ struct audio_cs_ep_ep_general_descriptor {
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ \
|
||||
0x00 /* iInterface */
|
||||
|
||||
#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;
|
||||
@@ -993,7 +980,7 @@ struct audio_v2_cs_if_ac_clock_selector_descriptor {
|
||||
uint8_t iClockSelector;
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_SIZEOF_AC_CLOCK_SELECTOR_DESC(n) (7 + n)
|
||||
#define AUDIO_SIZEOF_AC_CLOCK_SELECTOR_DESC(bNrInPins) (7 + (bNrInPins))
|
||||
|
||||
struct audio_v2_cs_if_ac_clock_multiplier_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -1005,7 +992,7 @@ struct audio_v2_cs_if_ac_clock_multiplier_descriptor {
|
||||
uint8_t iClockMultiplier;
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_SIZEOF_AC_CLOCK_MULTIPLIER_DESC() (7)
|
||||
#define AUDIO_SIZEOF_AC_CLOCK_MULTIPLIER_DESC (7)
|
||||
|
||||
struct audio_v2_cs_if_ac_input_terminal_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -1049,7 +1036,7 @@ struct audio_v2_cs_if_ac_feature_unit_descriptor {
|
||||
uint8_t iFeature;
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(ch) (6 + (ch + 1) * 4)
|
||||
#define AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(bNrChannels) (6 + ((bNrChannels) + 1) * 4)
|
||||
|
||||
struct audio_v2_cs_if_as_general_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -1124,7 +1111,7 @@ struct audio_v2_control_range3_param_block {
|
||||
WBVAL(wTotalLength), /* wTotalLength */ \
|
||||
bmControls /* bmControls */ \
|
||||
|
||||
#define AUDIO_V2_AC_DESCRIPTOR_INIT_LEN (0x08 + 0x09 + 0x09)
|
||||
#define AUDIO_V2_AC_DESCRIPTOR_LEN (0x08 + 0x09 + 0x09)
|
||||
|
||||
#define AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(bClockID, bmAttributes, bmControls) \
|
||||
0x08, /* bLength */ \
|
||||
@@ -1262,7 +1249,7 @@ struct audio_v2_control_range3_param_block {
|
||||
0x00, /* wLockDelay */ \
|
||||
0x00
|
||||
|
||||
#define AUDIO_V2_AS_ALTSETTING0_DESCRIPTOR_INIT(bInterfaceNumber) \
|
||||
#define AUDIO_V2_AS_ALTSETTING0_DESCRIPTOR_INIT(bInterfaceNumber) \
|
||||
0x09, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||
bInterfaceNumber, /* bInterfaceNumber */ \
|
||||
@@ -1331,9 +1318,10 @@ struct audio_v2_control_range3_param_block {
|
||||
|
||||
// clang-format on
|
||||
|
||||
#define AUDIO_V2_AS_DESCRIPTOR_INIT_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08)
|
||||
#define AUDIO_V2_AS_ALTSETTING_DESCRIPTOR_INIT_LEN (0x09 + 0x10 + 0x06 + 0x07 + 0x08)
|
||||
#define AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08 + 0x07)
|
||||
#define AUDIO_V2_AS_DESCRIPTOR_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08)
|
||||
#define AUDIO_V2_AS_ALTSETTING0_DESCRIPTOR_LEN (0x09)
|
||||
#define AUDIO_V2_AS_ALTSETTING_DESCRIPTOR_LEN (0x09 + 0x10 + 0x06 + 0x07 + 0x08)
|
||||
#define AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_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))
|
||||
|
||||
@@ -217,12 +217,12 @@
|
||||
#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_SERIAL_STATE_DSR (1 << 1) /* state of transmission carrier */
|
||||
#define CDC_SERIAL_STATE_DSR_Pos (1)
|
||||
#define CDC_SERIAL_STATE_DSR_Msk (1 << CDC_SERIAL_STATE_DSR_Pos)
|
||||
#define CDC_SERIAL_STATE_DCD (1 << 0) /* state of receiver carrier */
|
||||
#define CDC_SERIAL_STATE_DCD_Pos (0)
|
||||
#define CDC_SERIAL_STATE_DCD_Msk (1 << CDC_SERIAL_STATE_DCD_Pos)
|
||||
|
||||
#define CDC_ECM_XMIT_OK (1 << 0)
|
||||
#define CDC_ECM_RVC_OK (1 << 1)
|
||||
@@ -551,10 +551,9 @@ struct cdc_ncm_ndp16 {
|
||||
#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)
|
||||
#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) \
|
||||
#define CDC_ECM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, str_idx) \
|
||||
/* Interface Associate */ \
|
||||
0x08, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
|
||||
@@ -587,10 +586,10 @@ eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx)
|
||||
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(wMaxSegmentSize),/* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
|
||||
WBVAL(wNumberMCFilters), /* wNumberMCFilters: the number of multicast filters */\
|
||||
bNumberPowerFilters, /* bNumberPowerFilters: the number of wakeup power filters */\
|
||||
DBVAL_BE(0x00000000), /* Ethernet statistics (bitmap) */\
|
||||
WBVAL(1514), /* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
|
||||
WBVAL(0), /* wNumberMCFilters: the number of multicast filters */ \
|
||||
0, /* bNumberPowerFilters: the number of wakeup power filters */ \
|
||||
0x07, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
|
||||
int_ep, /* bEndpointAddress */ \
|
||||
@@ -621,10 +620,9 @@ eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx)
|
||||
// clang-format on
|
||||
|
||||
/*Length of template descriptor: 77 bytes*/
|
||||
#define CDC_NCM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 13 + 6 + 7 + 9 + 7 + 7)
|
||||
#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) \
|
||||
#define CDC_NCM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, str_idx) \
|
||||
/* Interface Associate */ \
|
||||
0x08, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
|
||||
@@ -657,10 +655,10 @@ eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx)
|
||||
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 */\
|
||||
DBVAL_BE(0x00000000), /* Ethernet statistics (bitmap) */\
|
||||
WBVAL(1514), /* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
|
||||
WBVAL(0), /* wNumberMCFilters: the number of multicast filters */ \
|
||||
0, /* bNumberPowerFilters: the number of wakeup power filters */ \
|
||||
0x06, \
|
||||
CDC_CS_INTERFACE, \
|
||||
CDC_FUNC_DESC_NCM, \
|
||||
|
||||
@@ -1,285 +0,0 @@
|
||||
/*
|
||||
* 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[CONFIG_USBHOST_MAX_CDC_ACM_CLASS][USB_ALIGN_UP(64, CONFIG_USB_ALIGN_SIZE)];
|
||||
|
||||
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)
|
||||
{
|
||||
uint8_t devno;
|
||||
|
||||
for (devno = 0; devno < CONFIG_USBHOST_MAX_CDC_ACM_CLASS; devno++) {
|
||||
if ((g_devinuse & (1U << devno)) == 0) {
|
||||
g_devinuse |= (1U << 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)
|
||||
{
|
||||
uint8_t devno = cdc_acm_class->minor;
|
||||
|
||||
if (devno < 32) {
|
||||
g_devinuse &= ~(1U << 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;
|
||||
|
||||
if (!cdc_acm_class || !cdc_acm_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
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[cdc_acm_class->minor], line_coding, sizeof(struct cdc_line_coding));
|
||||
|
||||
return usbh_control_transfer(cdc_acm_class->hport, setup, g_cdc_acm_buf[cdc_acm_class->minor]);
|
||||
}
|
||||
|
||||
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;
|
||||
int ret;
|
||||
|
||||
if (!cdc_acm_class || !cdc_acm_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = cdc_acm_class->hport->setup;
|
||||
|
||||
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[cdc_acm_class->minor]);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
memcpy(line_coding, g_cdc_acm_buf[cdc_acm_class->minor], 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;
|
||||
|
||||
if (!cdc_acm_class || !cdc_acm_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
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_osal_thread_schedule_other();
|
||||
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)
|
||||
{
|
||||
(void)hport;
|
||||
(void)intf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbh_cdc_data_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
(void)hport;
|
||||
(void)intf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__WEAK void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class)
|
||||
{
|
||||
(void)cdc_acm_class;
|
||||
}
|
||||
|
||||
__WEAK void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class)
|
||||
{
|
||||
(void)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,
|
||||
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
|
||||
.bInterfaceSubClass = CDC_ABSTRACT_CONTROL_MODEL,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.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,
|
||||
.bInterfaceClass = USB_DEVICE_CLASS_CDC_DATA,
|
||||
.bInterfaceSubClass = 0x00,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.id_table = NULL,
|
||||
.class_driver = &cdc_data_class_driver
|
||||
};
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
||||
@@ -306,16 +306,6 @@ int usbh_cdc_ecm_eth_output(uint32_t buflen)
|
||||
return usbh_submit_urb(&g_cdc_ecm_class.bulkout_urb);
|
||||
}
|
||||
|
||||
__WEAK void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
|
||||
{
|
||||
(void)cdc_ecm_class;
|
||||
}
|
||||
|
||||
__WEAK void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
|
||||
{
|
||||
(void)cdc_ecm_class;
|
||||
}
|
||||
|
||||
const struct usbh_class_driver cdc_ecm_class_driver = {
|
||||
.driver_name = "cdc_ecm",
|
||||
.connect = usbh_cdc_ecm_connect,
|
||||
|
||||
@@ -386,16 +386,6 @@ int usbh_cdc_ncm_eth_output(uint32_t buflen)
|
||||
return usbh_submit_urb(&g_cdc_ncm_class.bulkout_urb);
|
||||
}
|
||||
|
||||
__WEAK void usbh_cdc_ncm_run(struct usbh_cdc_ncm *cdc_ncm_class)
|
||||
{
|
||||
(void)cdc_ncm_class;
|
||||
}
|
||||
|
||||
__WEAK void usbh_cdc_ncm_stop(struct usbh_cdc_ncm *cdc_ncm_class)
|
||||
{
|
||||
(void)cdc_ncm_class;
|
||||
}
|
||||
|
||||
const struct usbh_class_driver cdc_ncm_class_driver = {
|
||||
.driver_name = "cdc_ncm",
|
||||
.connect = usbh_cdc_ncm_connect,
|
||||
|
||||
@@ -106,7 +106,6 @@ static void dfu_request_upload(struct usb_setup_packet *setup, uint8_t **data, u
|
||||
{
|
||||
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)) {
|
||||
@@ -143,7 +142,7 @@ static void dfu_request_upload(struct usb_setup_packet *setup, uint8_t **data, u
|
||||
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);
|
||||
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);
|
||||
|
||||
224
components/drivers/usb/cherryusb/class/gamepad/usb_gamepad.h
Normal file
224
components/drivers/usb/cherryusb/class/gamepad/usb_gamepad.h
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (c) 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USB_GAMEPAD_H
|
||||
#define USB_GAMEPAD_H
|
||||
|
||||
#include "usb_hid.h"
|
||||
|
||||
/*
|
||||
* GAMEPAD BUTTON LAYOUT
|
||||
*
|
||||
* ____________________________ __
|
||||
* / [__L2__] [__R2__] \ |
|
||||
* / [__ L1 __] [__ R1 __] \ | Triggers
|
||||
* __/________________________________\__ __|
|
||||
* / _ \ |
|
||||
* / /\ __ (B4) \ |
|
||||
* / || __ |A1| __ _ _ \ | Main Pad
|
||||
* | <===DP===> |S1| |S2| (B3) -|- (B2)| |
|
||||
* \ || ¯¯ ¯¯ _ / |
|
||||
* /\ \/ / \ / \ (B1) /\ __|
|
||||
* / \________ | LS | ____ | RS | _______/ \ |
|
||||
* | / \ \___/ / \ \___/ / \ | | Sticks
|
||||
* | / \_____/ \_____/ \ | __|
|
||||
* | / L3 R3 \ |
|
||||
* \_____/ \_____/
|
||||
*
|
||||
* |________|______| |______|___________|
|
||||
* D-Pad Left Right Face
|
||||
* Stick Stick Buttons
|
||||
*
|
||||
* Extended: A2=Touchpad/Capture A3=Mute L4/R4=Paddles
|
||||
*/
|
||||
|
||||
// W3C Gamepad API standard button order
|
||||
// Bit position = W3C button index (trivial conversion: 1 << index)
|
||||
//
|
||||
// Gamepad XInput Switch PS3/4/5 DInput
|
||||
// ------ ------ ------ ------- ------
|
||||
|
||||
// Face buttons (right cluster)
|
||||
#define USB_GAMEPAD_BUTTON_B1 (1 << 0) // A B Cross 2
|
||||
#define USB_GAMEPAD_BUTTON_B2 (1 << 1) // B A Circle 3
|
||||
#define USB_GAMEPAD_BUTTON_B3 (1 << 2) // X Y Square 1
|
||||
#define USB_GAMEPAD_BUTTON_B4 (1 << 3) // Y X Triangle 4
|
||||
|
||||
// Shoulder buttons
|
||||
#define USB_GAMEPAD_BUTTON_L1 (1 << 4) // LB L L1 5
|
||||
#define USB_GAMEPAD_BUTTON_R1 (1 << 5) // RB R R1 6
|
||||
#define USB_GAMEPAD_BUTTON_L2 (1 << 6) // LT ZL L2 7
|
||||
#define USB_GAMEPAD_BUTTON_R2 (1 << 7) // RT ZR R2 8
|
||||
|
||||
// Center cluster
|
||||
#define USB_GAMEPAD_BUTTON_S1 (1 << 8) // Back - Select 9
|
||||
#define USB_GAMEPAD_BUTTON_S2 (1 << 9) // Start + Start 10
|
||||
|
||||
// Stick clicks
|
||||
#define USB_GAMEPAD_BUTTON_L3 (1 << 10) // LS LS L3 11
|
||||
#define USB_GAMEPAD_BUTTON_R3 (1 << 11) // RS RS R3 12
|
||||
|
||||
// D-pad
|
||||
#define USB_GAMEPAD_BUTTON_DU (1 << 12) // D-Up D-Up D-Up Hat
|
||||
#define USB_GAMEPAD_BUTTON_DD (1 << 13) // D-Down D-Down D-Down Hat
|
||||
#define USB_GAMEPAD_BUTTON_DL (1 << 14) // D-Left D-Left D-Left Hat
|
||||
#define USB_GAMEPAD_BUTTON_DR (1 << 15) // D-Right D-Right D-Right Hat
|
||||
|
||||
// Auxiliary
|
||||
#define USB_GAMEPAD_BUTTON_A1 (1 << 16) // Guide Home PS 13
|
||||
#define USB_GAMEPAD_BUTTON_A2 (1 << 17) // - Capture Touchpad 14
|
||||
#define USB_GAMEPAD_BUTTON_A3 (1 << 18) // - - Mute -
|
||||
#define USB_GAMEPAD_BUTTON_A4 (1 << 19) // - - - -
|
||||
|
||||
// Paddles (extended)
|
||||
#define USB_GAMEPAD_BUTTON_L4 (1 << 20) // P1 - - -
|
||||
#define USB_GAMEPAD_BUTTON_R4 (1 << 21) // P2 - - -
|
||||
|
||||
#define XINPUT_VID 0x045E // Microsoft
|
||||
#define XINPUT_PID 0x028E // Xbox 360 Controller
|
||||
#define XINPUT_BCD_DEVICE 0x0114 // v1.14
|
||||
|
||||
/* XInput (Xbox 360) USB */
|
||||
|
||||
// XInput Interface Class/Subclass/Protocol
|
||||
#define XINPUT_INTERFACE_CLASS 0xFF
|
||||
#define XINPUT_INTERFACE_SUBCLASS 0x5D
|
||||
#define XINPUT_INTERFACE_PROTOCOL 0x01
|
||||
|
||||
#define XINPUT_BUTTON_MASK_UP (1U << 0)
|
||||
#define XINPUT_BUTTON_MASK_DOWN (1U << 1)
|
||||
#define XINPUT_BUTTON_MASK_LEFT (1U << 2)
|
||||
#define XINPUT_BUTTON_MASK_RIGHT (1U << 3)
|
||||
#define XINPUT_BUTTON_MASK_START (1U << 4)
|
||||
#define XINPUT_BUTTON_MASK_BACK (1U << 5)
|
||||
#define XINPUT_BUTTON_MASK_L3 (1U << 6)
|
||||
#define XINPUT_BUTTON_MASK_R3 (1U << 7)
|
||||
#define XINPUT_BUTTON_MASK_LB (1U << 8)
|
||||
#define XINPUT_BUTTON_MASK_RB (1U << 9)
|
||||
#define XINPUT_BUTTON_MASK_GUIDE (1U << 10)
|
||||
//#define XINPUT_BUTTON_MASK_UNUSED (1U << 11)
|
||||
#define XINPUT_BUTTON_MASK_A (1U << 12)
|
||||
#define XINPUT_BUTTON_MASK_B (1U << 13)
|
||||
#define XINPUT_BUTTON_MASK_X (1U << 14)
|
||||
#define XINPUT_BUTTON_MASK_Y (1U << 15)
|
||||
|
||||
// LED patterns for report_id 0x01
|
||||
#define XINPUT_LED_OFF 0x00
|
||||
#define XINPUT_LED_BLINK 0x01
|
||||
#define XINPUT_LED_FLASH_1 0x02
|
||||
#define XINPUT_LED_FLASH_2 0x03
|
||||
#define XINPUT_LED_FLASH_3 0x04
|
||||
#define XINPUT_LED_FLASH_4 0x05
|
||||
#define XINPUT_LED_ON_1 0x06
|
||||
#define XINPUT_LED_ON_2 0x07
|
||||
#define XINPUT_LED_ON_3 0x08
|
||||
#define XINPUT_LED_ON_4 0x09
|
||||
#define XINPUT_LED_ROTATE 0x0A
|
||||
#define XINPUT_LED_BLINK_SLOW 0x0B
|
||||
#define XINPUT_LED_BLINK_SLOW_1 0x0C
|
||||
#define XINPUT_LED_BLINK_SLOW_2 0x0D
|
||||
|
||||
struct xinput_in_report {
|
||||
uint8_t report_id; /* Always 0x00 */
|
||||
uint8_t report_size; /* Always 0x14 (20) */
|
||||
uint16_t buttons; /* DPAD, Start, Back, L3, R3, LB, RB, Guide, A, B, X, Y */
|
||||
uint8_t lt; /* Left trigger (0-255) */
|
||||
uint8_t rt; /* Right trigger (0-255) */
|
||||
int16_t lx; /* Left stick X (-32768 to 32767) */
|
||||
int16_t ly; /* Left stick Y (-32768 to 32767) */
|
||||
int16_t rx; /* Right stick X (-32768 to 32767) */
|
||||
int16_t ry; /* Right stick Y (-32768 to 32767) */
|
||||
uint8_t reserved[6]; /* Reserved/padding */
|
||||
} __PACKED;
|
||||
|
||||
struct xinput_out_report {
|
||||
uint8_t report_id; // 0x00 = rumble, 0x01 = LED
|
||||
uint8_t report_size; // 0x08
|
||||
uint8_t led; // LED pattern (0x00 for rumble)
|
||||
uint8_t rumble_l; // Left motor (large, 0-255)
|
||||
uint8_t rumble_r; // Right motor (small, 0-255)
|
||||
uint8_t reserved[3]; // Padding
|
||||
} __PACKED;
|
||||
|
||||
// clang-format off
|
||||
#define XINPUT_DESCRIPTOR_LEN (9 + 16 + 7 + 7)
|
||||
|
||||
#define XINPUT_DESCRIPTOR_INIT(bInterfaceNumber, out_ep, in_ep) \
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(bInterfaceNumber, 0x00, 0x02, 0xff, 0x5d, 0x01, 0x00), /* XInput proprietary descriptor (0x21) */ \
|
||||
16, 0x21, 0x00, 0x01, 0x01, 0x24, in_ep, 0x14, 0x03, 0x00, 0x03, 0x13, out_ep, 0x00, 0x03, 0x00, \
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(in_ep, 0x03, 32, 0x01), \
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(out_ep, 0x03, 32, 0x08)
|
||||
// clang-format on
|
||||
|
||||
#define SWITCH_VID 0x0F0D // 0x057E Nintendo Pro Controller
|
||||
#define SWITCH_PID 0x0092 // 0x2009
|
||||
#define SWITCH_BCD_DEVICE 0x0100 // v1.00
|
||||
|
||||
// Button masks (16-bit)
|
||||
#define SWITCH_MASK_Y (1U << 0)
|
||||
#define SWITCH_MASK_B (1U << 1)
|
||||
#define SWITCH_MASK_A (1U << 2)
|
||||
#define SWITCH_MASK_X (1U << 3)
|
||||
#define SWITCH_MASK_L (1U << 4)
|
||||
#define SWITCH_MASK_R (1U << 5)
|
||||
#define SWITCH_MASK_ZL (1U << 6)
|
||||
#define SWITCH_MASK_ZR (1U << 7)
|
||||
#define SWITCH_MASK_MINUS (1U << 8)
|
||||
#define SWITCH_MASK_PLUS (1U << 9)
|
||||
#define SWITCH_MASK_L3 (1U << 10)
|
||||
#define SWITCH_MASK_R3 (1U << 11)
|
||||
#define SWITCH_MASK_HOME (1U << 12)
|
||||
#define SWITCH_MASK_CAPTURE (1U << 13)
|
||||
|
||||
// D-pad / Hat switch values
|
||||
#define SWITCH_HAT_UP 0x00
|
||||
#define SWITCH_HAT_UP_RIGHT 0x01
|
||||
#define SWITCH_HAT_RIGHT 0x02
|
||||
#define SWITCH_HAT_DOWN_RIGHT 0x03
|
||||
#define SWITCH_HAT_DOWN 0x04
|
||||
#define SWITCH_HAT_DOWN_LEFT 0x05
|
||||
#define SWITCH_HAT_LEFT 0x06
|
||||
#define SWITCH_HAT_UP_LEFT 0x07
|
||||
#define SWITCH_HAT_CENTER 0x08
|
||||
|
||||
// Analog stick range
|
||||
#define SWITCH_JOYSTICK_MIN 0x00
|
||||
#define SWITCH_JOYSTICK_MID 0x80
|
||||
#define SWITCH_JOYSTICK_MAX 0xFF
|
||||
|
||||
struct switch_in_report {
|
||||
uint16_t buttons; // 16 button bits
|
||||
uint8_t hat; // D-pad (hat switch, 0-8)
|
||||
uint8_t lx; // Left stick X (0-255, 128 = center)
|
||||
uint8_t ly; // Left stick Y (0-255, 128 = center)
|
||||
uint8_t rx; // Right stick X (0-255, 128 = center)
|
||||
uint8_t ry; // Right stick Y (0-255, 128 = center)
|
||||
uint8_t vendor; // Vendor-specific byte
|
||||
} __PACKED;
|
||||
|
||||
struct switch_out_report {
|
||||
uint8_t data[8]; // Vendor-specific rumble data
|
||||
} __PACKED;
|
||||
|
||||
#define HID_SWITCH_REPORT_DESC_SIZE 86
|
||||
|
||||
// clang-format off
|
||||
#define SWITCH_DESCRIPTOR_LEN HID_CUSTOM_INOUT_DESCRIPTOR_LEN
|
||||
|
||||
#define SWITCH_DESCRIPTOR_INIT(bInterfaceNumber, out_ep, in_ep) \
|
||||
HID_CUSTOM_INOUT_DESCRIPTOR_INIT(bInterfaceNumber, 0x00, HID_SWITCH_REPORT_DESC_SIZE, out_ep, in_ep, 64, 0x01)
|
||||
// clang-format on
|
||||
|
||||
struct usb_gamepad_report {
|
||||
uint32_t buttons;
|
||||
uint8_t lt;
|
||||
uint8_t rt;
|
||||
uint8_t lx;
|
||||
uint8_t ly;
|
||||
uint8_t rx;
|
||||
uint8_t ry;
|
||||
};
|
||||
|
||||
#endif /* USB_GAMEPAD_H */
|
||||
209
components/drivers/usb/cherryusb/class/gamepad/usbd_gamepad.c
Normal file
209
components/drivers/usb/cherryusb/class/gamepad/usbd_gamepad.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (c) 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_hid.h"
|
||||
#include "usbd_gamepad.h"
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t gamepad_report_buffer[64];
|
||||
|
||||
static int xinput_vendor_class_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
struct xinput_in_report xinput_report;
|
||||
|
||||
memset(&xinput_report, 0, sizeof(xinput_report));
|
||||
xinput_report.report_size = 20;
|
||||
|
||||
memcpy(*data, &xinput_report, sizeof(xinput_report));
|
||||
*len = sizeof(xinput_report);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_gamepad_xinput_send_report(uint8_t ep, struct usb_gamepad_report *report)
|
||||
{
|
||||
struct xinput_in_report *xinput_report;
|
||||
|
||||
xinput_report = (struct xinput_in_report *)gamepad_report_buffer;
|
||||
memset(xinput_report, 0, sizeof(xinput_report));
|
||||
xinput_report->report_size = 20;
|
||||
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_DU)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_UP;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_DD)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_DOWN;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_DL)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_LEFT;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_DR)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_RIGHT;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_S2)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_START;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_S1)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_BACK;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_L3)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_L3;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_R3)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_R3;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_L1)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_LB;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_R1)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_RB;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_A1)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_GUIDE;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_B1)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_A;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_B2)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_B;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_B3)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_X;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_B4)
|
||||
xinput_report->buttons |= XINPUT_BUTTON_MASK_Y;
|
||||
|
||||
// Analog triggers (0-255), fall back to digital if analog is 0 but button pressed
|
||||
xinput_report->lt = report->lt;
|
||||
xinput_report->rt = report->rt;
|
||||
if (xinput_report->lt == 0 && (report->buttons & USB_GAMEPAD_BUTTON_L2))
|
||||
xinput_report->lt = 0xFF;
|
||||
if (xinput_report->rt == 0 && (report->buttons & USB_GAMEPAD_BUTTON_R2))
|
||||
xinput_report->rt = 0xFF;
|
||||
|
||||
return usbd_ep_start_write(0, ep, gamepad_report_buffer, sizeof(struct xinput_in_report));
|
||||
}
|
||||
|
||||
// Convert gamepad dpad mask to switch hat value
|
||||
static uint8_t convert_dpad_to_switch_hat(uint32_t buttons)
|
||||
{
|
||||
// Joypad uses active-high (1 = pressed)
|
||||
uint8_t up = (buttons & USB_GAMEPAD_BUTTON_DU) ? 1 : 0;
|
||||
uint8_t down = (buttons & USB_GAMEPAD_BUTTON_DD) ? 1 : 0;
|
||||
uint8_t left = (buttons & USB_GAMEPAD_BUTTON_DL) ? 1 : 0;
|
||||
uint8_t right = (buttons & USB_GAMEPAD_BUTTON_DR) ? 1 : 0;
|
||||
|
||||
if (up && right)
|
||||
return SWITCH_HAT_UP_RIGHT;
|
||||
if (up && left)
|
||||
return SWITCH_HAT_UP_LEFT;
|
||||
if (down && right)
|
||||
return SWITCH_HAT_DOWN_RIGHT;
|
||||
if (down && left)
|
||||
return SWITCH_HAT_DOWN_LEFT;
|
||||
if (up)
|
||||
return SWITCH_HAT_UP;
|
||||
if (down)
|
||||
return SWITCH_HAT_DOWN;
|
||||
if (left)
|
||||
return SWITCH_HAT_LEFT;
|
||||
if (right)
|
||||
return SWITCH_HAT_RIGHT;
|
||||
|
||||
return SWITCH_HAT_CENTER;
|
||||
}
|
||||
|
||||
int usbd_gamepad_switch_send_report(uint8_t ep, struct usb_gamepad_report *report)
|
||||
{
|
||||
struct switch_in_report *switch_report;
|
||||
|
||||
switch_report = (struct switch_in_report *)gamepad_report_buffer;
|
||||
memset(switch_report, 0, sizeof(switch_report));
|
||||
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_S1)
|
||||
switch_report->buttons |= SWITCH_MASK_MINUS;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_S2)
|
||||
switch_report->buttons |= SWITCH_MASK_PLUS;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_L1)
|
||||
switch_report->buttons |= SWITCH_MASK_L;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_R1)
|
||||
switch_report->buttons |= SWITCH_MASK_R;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_L2)
|
||||
switch_report->buttons |= SWITCH_MASK_ZL;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_R2)
|
||||
switch_report->buttons |= SWITCH_MASK_ZR;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_L3)
|
||||
switch_report->buttons |= SWITCH_MASK_L3;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_R3)
|
||||
switch_report->buttons |= SWITCH_MASK_R3;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_A1)
|
||||
switch_report->buttons |= SWITCH_MASK_HOME;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_A2)
|
||||
switch_report->buttons |= SWITCH_MASK_CAPTURE;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_B1)
|
||||
switch_report->buttons |= SWITCH_MASK_B;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_B2)
|
||||
switch_report->buttons |= SWITCH_MASK_A;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_B3)
|
||||
switch_report->buttons |= SWITCH_MASK_Y;
|
||||
if (report->buttons & USB_GAMEPAD_BUTTON_B4)
|
||||
switch_report->buttons |= SWITCH_MASK_X;
|
||||
|
||||
switch_report->hat = convert_dpad_to_switch_hat(report->buttons);
|
||||
|
||||
// Analog sticks (HID convention: 0=up, 255=down - no inversion needed)
|
||||
switch_report->lx = report->lx;
|
||||
switch_report->ly = report->ly;
|
||||
switch_report->rx = report->rx;
|
||||
switch_report->ry = report->ry;
|
||||
|
||||
switch_report->vendor = 0;
|
||||
|
||||
return usbd_ep_start_write(0, ep, gamepad_report_buffer, sizeof(struct switch_in_report));
|
||||
}
|
||||
|
||||
struct usbd_interface *usbd_gamepad_xinput_init_intf(struct usbd_interface *intf)
|
||||
{
|
||||
intf->class_interface_handler = NULL;
|
||||
intf->class_endpoint_handler = NULL;
|
||||
intf->vendor_handler = xinput_vendor_class_request_handler;
|
||||
intf->notify_handler = NULL;
|
||||
|
||||
return intf;
|
||||
}
|
||||
|
||||
static const uint8_t hid_switch_report_desc[HID_SWITCH_REPORT_DESC_SIZE] = {
|
||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||
0x09, 0x05, // Usage (Game Pad)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x01, // Logical Maximum (1)
|
||||
0x35, 0x00, // Physical Minimum (0)
|
||||
0x45, 0x01, // Physical Maximum (1)
|
||||
0x75, 0x01, // Report Size (1)
|
||||
0x95, 0x10, // Report Count (16)
|
||||
0x05, 0x09, // Usage Page (Button)
|
||||
0x19, 0x01, // Usage Minimum (Button 1)
|
||||
0x29, 0x10, // Usage Maximum (Button 16)
|
||||
0x81, 0x02, // Input (Data,Var,Abs)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||
0x25, 0x07, // Logical Maximum (7)
|
||||
0x46, 0x3B, 0x01, // Physical Maximum (315)
|
||||
0x75, 0x04, // Report Size (4)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x65, 0x14, // Unit (Eng Rot:Angular Pos)
|
||||
0x09, 0x39, // Usage (Hat switch)
|
||||
0x81, 0x42, // Input (Data,Var,Abs,Null)
|
||||
0x65, 0x00, // Unit (None)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x81, 0x01, // Input (Const) - 4-bit padding
|
||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||
0x46, 0xFF, 0x00, // Physical Maximum (255)
|
||||
0x09, 0x30, // Usage (X) - Left Stick X
|
||||
0x09, 0x31, // Usage (Y) - Left Stick Y
|
||||
0x09, 0x32, // Usage (Z) - Right Stick X
|
||||
0x09, 0x35, // Usage (Rz) - Right Stick Y
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x04, // Report Count (4)
|
||||
0x81, 0x02, // Input (Data,Var,Abs)
|
||||
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined)
|
||||
0x09, 0x20, // Usage (0x20)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x81, 0x02, // Input (Data,Var,Abs) - Vendor byte
|
||||
0x0A, 0x21, 0x26, // Usage (0x2621)
|
||||
0x95, 0x08, // Report Count (8)
|
||||
0x91, 0x02, // Output (Data,Var,Abs) - Rumble
|
||||
0xC0, // End Collection
|
||||
};
|
||||
|
||||
struct usbd_interface *usbd_gamepad_switch_init_intf(struct usbd_interface *intf)
|
||||
{
|
||||
return usbd_hid_init_intf(0, intf, hid_switch_report_desc, HID_SWITCH_REPORT_DESC_SIZE);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBD_GAMEPAD_H
|
||||
#define USBD_GAMEPAD_H
|
||||
|
||||
#include "usb_gamepad.h"
|
||||
|
||||
#define USBD_GAMEPAD_MODE_XINPUT 0
|
||||
#define USBD_GAMEPAD_MODE_SWITCH 1
|
||||
#define USBD_GAMEPAD_MODE_XBOXONE 2
|
||||
#define USBD_GAMEPAD_MODE_PS4 3
|
||||
|
||||
struct usbd_interface *usbd_gamepad_xinput_init_intf(struct usbd_interface *intf);
|
||||
struct usbd_interface *usbd_gamepad_switch_init_intf(struct usbd_interface *intf);
|
||||
|
||||
int usbd_gamepad_xinput_send_report(uint8_t ep, struct usb_gamepad_report *report);
|
||||
int usbd_gamepad_switch_send_report(uint8_t ep, struct usb_gamepad_report *report);
|
||||
|
||||
#endif /* USBD_GAMEPAD_H */
|
||||
@@ -35,7 +35,7 @@
|
||||
#define HID_REPORT_OUTPUT 0x02
|
||||
#define HID_REPORT_FEATURE 0x03
|
||||
|
||||
/* HID Descriptor ***********************************************************/
|
||||
/* HID Descriptor */
|
||||
|
||||
#define HID_COUNTRY_NONE 0x00 /* Not Supported */
|
||||
#define HID_COUNTRY_ARABIC 0x01 /* Arabic */
|
||||
@@ -74,99 +74,114 @@
|
||||
#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
|
||||
/* HID report See specification at
|
||||
* https://www.usb.org/sites/default/files/hid1_11.pdf
|
||||
* https://www.usb.org/sites/default/files/hut1_22.pdf
|
||||
*/
|
||||
|
||||
#define HID_SIZE_MASK (0x3 << 0)
|
||||
#define HID_TYPE_MASK (0x3 << 2)
|
||||
#define HID_TAG_MASK (0xF << 4)
|
||||
|
||||
#define HID_ITEMTYPE_MAIN (0x0 << 2)
|
||||
#define HID_ITEMTYPE_GLOBAL (0x1 << 2)
|
||||
#define HID_ITEMTYPE_LOCAL (0x2 << 2)
|
||||
#define HID_ITEMTYPE_LONG (0x3 << 2)
|
||||
|
||||
/* 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_MAINITEM_TAG_INPUT (0x08 << 4)
|
||||
#define HID_MAINITEM_TAG_OUTPUT (0x09 << 4)
|
||||
#define HID_MAINITEM_TAG_COLLECTION (0x0a << 4)
|
||||
#define HID_MAINITEM_TAG_FEATURE (0x0b << 4)
|
||||
#define HID_MAINITEM_TAG_ENDCOLLECTION (0x0c << 4)
|
||||
|
||||
#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_MAINITEM_CONSTANT (1 << 0) /* Constant(1) vs Data(0) */
|
||||
#define HID_MAINITEM_VARIABLE (1 << 1) /* Variable(1) vs Array(0) */
|
||||
#define HID_MAINITEM_RELATIVE (1 << 2) /* Relative(1) vs Absolute(0) */
|
||||
#define HID_MAINITEM_WRAP (1 << 3) /* Wrap(1) vs No Wrap(0) */
|
||||
#define HID_MAINITEM_NONLINEAR (1 << 4) /* Non Linear(1) vs Linear(0) */
|
||||
#define HID_MAINITEM_NOPREFERRED (1 << 5) /* No Preferred (1) vs Preferred State(0) */
|
||||
#define HID_MAINITEM_NULLSTATE (1 << 6) /* Null state(1) vs No Null position(0) */
|
||||
#define HID_MAINITEM_VOLATILE (1 << 7) /* Volatile(1) vs Non volatile(0) */
|
||||
#define HID_MAINITEM_BUFFEREDBYTES (1 << 8) /* Buffered Bytes(1) vs Bit Field(0) */
|
||||
|
||||
#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
|
||||
#define HID_MAINITEM_COLLECTION_PHYSICAL 0x00 /* Physical (group of axes) */
|
||||
#define HID_MAINITEM_COLLECTION_APPL 0x01 /* Application (mouse, keyboard) */
|
||||
#define HID_MAINITEM_COLLECTION_LOGICAL 0x02 /* Logical (interrelated data) */
|
||||
#define HID_MAINITEM_COLLECTION_REPORT 0x03 /* Report */
|
||||
#define HID_MAINITEM_COLLECTION_ARRAY 0x04 /* Named Array */
|
||||
#define HID_MAINITEM_COLLECTION_SWITCH 0x05 /* Usage Switch */
|
||||
#define HID_MAINITEM_COLLECTION_MODIFIER 0x06 /* Usage Modifier */
|
||||
|
||||
/* 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 */
|
||||
#define HID_GLOBALITEM_TAG_USAGE_PAGE (0x00 << 4)
|
||||
#define HID_GLOBALITEM_TAG_LOGICAL_MIN (0x01 << 4)
|
||||
#define HID_GLOBALITEM_TAG_LOGICAL_MAX (0x02 << 4)
|
||||
#define HID_GLOBALITEM_TAG_PHYSICAL_MIN (0x03 << 4)
|
||||
#define HID_GLOBALITEM_TAG_PHYSICAL_MAX (0x04 << 4)
|
||||
#define HID_GLOBALITEM_TAG_UNIT_EXP (0x05 << 4)
|
||||
#define HID_GLOBALITEM_TAG_UNIT (0x06 << 4)
|
||||
#define HID_GLOBALITEM_TAG_REPORT_SIZE (0x07 << 4)
|
||||
#define HID_GLOBALITEM_TAG_REPORT_ID (0x08 << 4)
|
||||
#define HID_GLOBALITEM_TAG_REPORT_COUNT (0x09 << 4)
|
||||
#define HID_GLOBALITEM_TAG_PUSH (0x0a << 4)
|
||||
#define HID_GLOBALITEM_TAG_POP (0x0b << 4)
|
||||
|
||||
/* 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 */
|
||||
#define HID_LOCALITEM_TAG_USAGE (0x00 << 4)
|
||||
#define HID_LOCALITEM_TAG_USAGE_MIN (0x01 << 4)
|
||||
#define HID_LOCALITEM_TAG_USAGE_MAX (0x02 << 4)
|
||||
#define HID_LOCALITEM_TAG_DESIG_INDEX (0x03 << 4)
|
||||
#define HID_LOCALITEM_TAG_DESIG_MIN (0x04 << 4)
|
||||
#define HID_LOCALITEM_TAG_DESIG_MAX (0x05 << 4)
|
||||
/* No 6 in spec */
|
||||
#define HID_LOCALITEM_TAG_STRING_INDEX (0x07 << 4)
|
||||
#define HID_LOCALITEM_TAG_STRING_MIN (0x08 << 4)
|
||||
#define HID_LOCALITEM_TAG_STRING_MAX (0x09 << 4)
|
||||
#define HID_LOCALITEM_TAG_DELIMITER (0x0a << 4) /* Also listed as reserved in spec! */
|
||||
|
||||
/* Usage pages (HuT 3) */
|
||||
#define HID_USAGE_PAGE_UNDEFINED 0x00 /* Undefined */
|
||||
#define HID_USAGE_PAGE_GENERIC_DESKTOP_CONTROLS 0x01 /* Generic Desktop Controls */
|
||||
#define HID_USAGE_PAGE_SIMULATION_CONTROLS 0x02 /* Simulation Controls */
|
||||
#define HID_USAGE_PAGE_VR_CONTROLS 0x03 /* VR Controls */
|
||||
#define HID_USAGE_PAGE_SPORT_CONTROLS 0x04 /* Sport Controls */
|
||||
#define HID_USAGE_PAGE_GAME_CONTROLS 0x05 /* Game Controls */
|
||||
#define HID_USAGE_PAGE_GENERIC_DEVICE_CONTROLS 0x06 /* Generic Device Controls */
|
||||
#define HID_USAGE_PAGE_KEYBOARD_KEYPAD 0x07 /* Keyboard/Keypad */
|
||||
#define HID_USAGE_PAGE_LED 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 */
|
||||
#define HID_USAGE_PAGE_HAPTICS /* 0x0e Reserved */
|
||||
#define HID_USAGE_PAGE_PID 0x0f /* PID Page Physical Interface Device */
|
||||
#define HID_USAGE_PAGE_UNICODE 0x10 /* Unicode */
|
||||
#define HID_USAGE_PAGE_SOC 0x11 /* Sensor Orientation Category */
|
||||
#define HID_USAGE_PAGE_EYE_AND_HEAD_TRACKER 0x12 /* Eye and Head Tracker */
|
||||
/* 0x13 Reserved */
|
||||
#define HID_USAGE_PAGE_ALPHA_DISPLAY 0x14 /* Alphanumeric Display */
|
||||
/* 0x15-3f Reserved */
|
||||
#define HID_USAGE_PAGE_MEDICAL 0x40 /* Medical Instruments */
|
||||
#define HID_USAGE_PAGE_BRAILLE_DISPLAY 0x41 /* Braille Display */
|
||||
/* 0x42-0x58 Reserved */
|
||||
#define HID_USAGE_PAGE_LIGHTING_AND_ILLUMINATION 0x59 /* Lighting and Illumination */
|
||||
/* 0x5a-0x7f Reserved */
|
||||
#define HID_USAGE_PAGE_USB_MONITOR 0x80 /* USB Monitor */
|
||||
#define HID_USAGE_PAGE_USB_ENUMERATED_VALUES 0x81 /* USB Enumerated Values */
|
||||
#define HID_USAGE_PAGE_VESA_VIRTUAL_CONTROLS 0x82 /* VESA Virtual Controls */
|
||||
#define HID_USAGE_PAGE_POWER_DEVICE 0x84 /* Power Device */
|
||||
#define HID_USAGE_PAGE_BATTERY_SYSTEM 0x85 /* Battery System */
|
||||
#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_CONTROL 0x90 /* Camera Control Page */
|
||||
#define HID_USAGE_PAGE_ARCADE 0x91
|
||||
#define HID_USAGE_PAGE_GAMING_DEVICE 0x92
|
||||
#define HID_USAGE_PAGE_FIDO_ALLIANCE 0xF1D0
|
||||
#define HID_USAGE_PAGE_VENDOR_PAGE_HBYTE 0xFF00
|
||||
|
||||
/* Modifier Keys (HID 8.3) */
|
||||
#define HID_MODIFIER_LCTRL (1 << 0) /* Left Ctrl */
|
||||
@@ -205,38 +220,6 @@
|
||||
#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 */
|
||||
@@ -634,7 +617,7 @@ struct usb_hid_js_report {
|
||||
|
||||
#define HID_CUSTOM_INOUT_DESCRIPTOR_LEN (9 + 9 + 7 + 7)
|
||||
|
||||
#define HID_CUSTOM_INOUT_DESCRIPTOR_INIT(bInterfaceNumber, bInterfaceSubClass, wItemLength, in_ep, out_ep,wMaxPacketSize, bInterval) \
|
||||
#define HID_CUSTOM_INOUT_DESCRIPTOR_INIT(bInterfaceNumber, bInterfaceSubClass, wItemLength, out_ep, in_ep, wMaxPacketSize, bInterval) \
|
||||
0x09, /* bLength: Interface Descriptor size */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */ \
|
||||
bInterfaceNumber, /* bInterfaceNumber: Number of Interface */ \
|
||||
@@ -654,13 +637,13 @@ struct usb_hid_js_report {
|
||||
WBVAL(wItemLength), /* wItemLength: Total length of Report descriptor */ \
|
||||
0x07, /* bLength: Endpoint Descriptor size */ \
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ \
|
||||
in_ep, /* bEndpointAddress: Endpoint Address (IN) */ \
|
||||
out_ep, /* bEndpointAddress: Endpoint Address (OUT) */ \
|
||||
0x03, /* bmAttributes: Interrupt endpoint */ \
|
||||
WBVAL(wMaxPacketSize), /* wMaxPacketSize: x Byte max */ \
|
||||
bInterval, /* bInterval: Polling Interval */ \
|
||||
0x07, /* bLength: Endpoint Descriptor size */ \
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ \
|
||||
out_ep, /* bEndpointAddress: Endpoint Address (IN) */ \
|
||||
in_ep, /* bEndpointAddress: Endpoint Address (IN) */ \
|
||||
0x03, /* bmAttributes: Interrupt endpoint */ \
|
||||
WBVAL(wMaxPacketSize), /* wMaxPacketSize: x Byte max */ \
|
||||
bInterval /* bInterval: Polling Interval */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,82 @@
|
||||
|
||||
#include "usb_hid.h"
|
||||
|
||||
/* local items */
|
||||
#define HID_REPORT_FLAG_USAGE_MIN (1 << 0)
|
||||
#define HID_REPORT_FLAG_USAGE_MAX (1 << 1)
|
||||
|
||||
/* global items */
|
||||
#define HID_REPORT_FLAG_REPORT_ID (1 << 2)
|
||||
#define HID_REPORT_FLAG_REPORT_COUNT (1 << 3)
|
||||
#define HID_REPORT_FLAG_REPORT_SIZE (1 << 4)
|
||||
#define HID_REPORT_FLAG_LOGICAL_MIN (1 << 5)
|
||||
#define HID_REPORT_FLAG_LOGICAL_MAX (1 << 6)
|
||||
#define HID_REPORT_FLAG_USAGE_PAGE (1 << 7)
|
||||
|
||||
/* main items */
|
||||
#define HID_REPORT_FLAG_INPUT (1 << 8)
|
||||
#define HID_REPORT_FLAG_OUTPUT (1 << 9)
|
||||
#define HID_REPORT_FLAG_FEATURE (1 << 10)
|
||||
|
||||
#define HID_REPORT_FLAG_EXTENDED_USAGE (1 << 11)
|
||||
|
||||
/* masks */
|
||||
|
||||
#define HID_REPORT_FLAG_GLOBAL_MASK (HID_REPORT_FLAG_REPORT_ID | \
|
||||
HID_REPORT_FLAG_REPORT_COUNT | \
|
||||
HID_REPORT_FLAG_REPORT_SIZE | \
|
||||
HID_REPORT_FLAG_LOGICAL_MIN | \
|
||||
HID_REPORT_FLAG_LOGICAL_MAX | \
|
||||
HID_REPORT_FLAG_USAGE_PAGE)
|
||||
|
||||
#define HID_REPORT_FLAG_REQUIRED_MASK (HID_REPORT_FLAG_REPORT_COUNT | \
|
||||
HID_REPORT_FLAG_REPORT_SIZE | \
|
||||
HID_REPORT_FLAG_LOGICAL_MIN | \
|
||||
HID_REPORT_FLAG_LOGICAL_MAX)
|
||||
|
||||
#define USAGE_ID(usage) (usage & 0x0000FFFF)
|
||||
#define USAGE_PAGE(usage) ((usage & 0xFFFF0000) >> 16)
|
||||
|
||||
#ifndef CONFIG_USBHOST_HID_MAX_INPUT
|
||||
#define CONFIG_USBHOST_HID_MAX_INPUT 16
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBHOST_HID_MAX_OUTPUT
|
||||
#define CONFIG_USBHOST_HID_MAX_OUTPUT 16
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBHOST_HID_MAX_FEATURE
|
||||
#define CONFIG_USBHOST_HID_MAX_FEATURE 16
|
||||
#endif
|
||||
|
||||
struct hid_report_field {
|
||||
uint32_t *usages; /* usage page + usage */
|
||||
uint32_t usage_count;
|
||||
uint32_t usage_page;
|
||||
|
||||
uint32_t report_id; /* optional */
|
||||
uint32_t report_count;
|
||||
uint32_t report_size;
|
||||
int32_t logical_min;
|
||||
int32_t logical_max;
|
||||
uint32_t properties;
|
||||
|
||||
uint32_t usage_min;
|
||||
uint32_t usage_max;
|
||||
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct hid_report {
|
||||
bool uses_report_id;
|
||||
uint32_t input_count;
|
||||
struct hid_report_field input_fields[CONFIG_USBHOST_HID_MAX_INPUT];
|
||||
uint32_t output_count;
|
||||
struct hid_report_field output_fields[CONFIG_USBHOST_HID_MAX_OUTPUT];
|
||||
uint32_t feature_count;
|
||||
struct hid_report_field feature_fields[CONFIG_USBHOST_HID_MAX_FEATURE];
|
||||
};
|
||||
|
||||
struct usbh_hid {
|
||||
struct usbh_hubport *hport;
|
||||
struct usb_endpoint_descriptor *intin; /* INTR IN endpoint */
|
||||
@@ -36,9 +112,14 @@ int usbh_hid_get_protocol(struct usbh_hid *hid_class, uint8_t *protocol);
|
||||
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);
|
||||
|
||||
struct hid_report *usbh_hid_report_parse(const uint8_t *data, uint32_t report_len, uint32_t max_usages);
|
||||
void usbh_hid_report_free(struct hid_report *hid_report);
|
||||
|
||||
void usbh_hid_run(struct usbh_hid *hid_class);
|
||||
void usbh_hid_stop(struct usbh_hid *hid_class);
|
||||
|
||||
int lshid(int argc, char **argv);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -238,6 +238,7 @@ 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;
|
||||
int ret;
|
||||
|
||||
if (hub->is_roothub) {
|
||||
setup = &roothub_setup;
|
||||
@@ -246,9 +247,22 @@ int usbh_hub_set_feature(struct usbh_hub *hub, uint8_t port, uint8_t feature)
|
||||
setup->wValue = feature;
|
||||
setup->wIndex = port;
|
||||
setup->wLength = 0;
|
||||
return usbh_roothub_control(hub->bus, setup, NULL);
|
||||
|
||||
ret = usbh_roothub_control(hub->bus, setup, NULL);
|
||||
|
||||
if ((feature == HUB_PORT_FEATURE_RESET) && (ret >= 0)) {
|
||||
hub->bus->event_handler(hub->bus->busid, hub->index, port, USB_INTERFACE_ANY, USBH_EVENT_DEVICE_RESET);
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
return _usbh_hub_set_feature(hub, port, feature);
|
||||
ret = _usbh_hub_set_feature(hub, port, feature);
|
||||
|
||||
if ((feature == HUB_PORT_FEATURE_RESET) && (ret >= 0)) {
|
||||
hub->bus->event_handler(hub->bus->busid, hub->index, port, USB_INTERFACE_ANY, USBH_EVENT_DEVICE_RESET);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,11 +351,11 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
}
|
||||
|
||||
/*
|
||||
* Super-Speed hubs need to know their depth to be able to
|
||||
* parse the bits of the route-string that correspond to
|
||||
* their downstream port number.
|
||||
*
|
||||
*/
|
||||
* Super-Speed hubs need to know their depth to be able to
|
||||
* parse the bits of the route-string that correspond to
|
||||
* their downstream port number.
|
||||
*
|
||||
*/
|
||||
if ((hport->depth != 0) && (hport->speed == USB_SPEED_SUPER)) {
|
||||
ret = usbh_hub_set_depth(hub, hport->depth - 1);
|
||||
if (ret < 0) {
|
||||
@@ -373,6 +387,11 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
hub->tt_think = ((hub->hub_desc.wHubCharacteristics & HUB_CHAR_TTTT_MASK) >> 5);
|
||||
}
|
||||
|
||||
if (hub->nports > CONFIG_USBHOST_MAX_EHPORTS) {
|
||||
USB_LOG_ERR("Hub nports %u overflow\r\n", hub->nports);
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
for (uint8_t port = 0; port < hub->nports; port++) {
|
||||
hub->child[port].port = port + 1;
|
||||
hub->child[port].parent = hub;
|
||||
@@ -470,6 +489,8 @@ static void usbh_hub_events(struct usbh_hub *hub)
|
||||
int ret;
|
||||
size_t flags;
|
||||
|
||||
(void)speed_table;
|
||||
|
||||
if (!hub->connected) {
|
||||
return;
|
||||
}
|
||||
@@ -560,6 +581,8 @@ static void usbh_hub_events(struct usbh_hub *hub)
|
||||
|
||||
/* Last, check connect status */
|
||||
if (portstatus & HUB_PORT_STATUS_CONNECTION) {
|
||||
hub->bus->event_handler(hub->bus->busid, hub->index, port + 1, USB_INTERFACE_ANY, USBH_EVENT_DEVICE_CONNECTED);
|
||||
|
||||
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 + 1, ret);
|
||||
@@ -641,7 +664,6 @@ static void usbh_hub_events(struct usbh_hub *hub)
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -660,12 +682,15 @@ static void usbh_hub_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
|
||||
struct usbh_bus *bus = (struct usbh_bus *)CONFIG_USB_OSAL_THREAD_GET_ARGV;
|
||||
|
||||
usb_hc_init(bus);
|
||||
bus->event_handler(bus->busid, USB_HUB_INDEX_ANY, USB_HUB_PORT_ANY, USB_INTERFACE_ANY, USBH_EVENT_INIT);
|
||||
while (1) {
|
||||
ret = usb_osal_mq_recv(bus->hub_mq, (uintptr_t *)&hub, USB_OSAL_WAITING_FOREVER);
|
||||
if (ret < 0) {
|
||||
continue;
|
||||
}
|
||||
usb_osal_mutex_take(bus->mutex);
|
||||
usbh_hub_events(hub);
|
||||
usb_osal_mutex_give(bus->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -695,6 +720,12 @@ int usbh_hub_initialize(struct usbh_bus *bus)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bus->mutex = usb_osal_mutex_create();
|
||||
if (bus->mutex == NULL) {
|
||||
USB_LOG_ERR("Failed to create bus mutex\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) {
|
||||
@@ -708,8 +739,8 @@ int usbh_hub_deinitialize(struct usbh_bus *bus)
|
||||
{
|
||||
struct usbh_hubport *hport;
|
||||
struct usbh_hub *hub;
|
||||
size_t flags;
|
||||
|
||||
usb_osal_mutex_take(bus->mutex);
|
||||
hub = &bus->hcd.roothub;
|
||||
for (uint8_t port = 0; port < hub->nports; port++) {
|
||||
hport = &hub->child[port];
|
||||
@@ -717,15 +748,13 @@ int usbh_hub_deinitialize(struct usbh_bus *bus)
|
||||
usbh_hubport_release(hport);
|
||||
}
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
|
||||
usb_hc_deinit(bus);
|
||||
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
usb_osal_mq_delete(bus->hub_mq);
|
||||
usb_osal_thread_delete(bus->hub_thread);
|
||||
usb_osal_mq_delete(bus->hub_mq);
|
||||
|
||||
usb_osal_mutex_give(bus->mutex);
|
||||
usb_osal_mutex_delete(bus->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#ifndef USB_MIDI_H
|
||||
#define USB_MIDI_H
|
||||
|
||||
#include "usb_audio.h"
|
||||
|
||||
/* bDescriptorSubType */
|
||||
#define MIDI_VC_HEADER_DESCRIPTOR_SUBTYPE 0x01U
|
||||
#define MIDI_MS_HEADER_DESCRIPTOR_SUBTYPE 0x01U
|
||||
@@ -201,6 +203,19 @@ struct midi_cs_ep_ms_general_descriptor {
|
||||
#define MIDI_SIZEOF_MS_GENERAL_DESC(n) (4 + n)
|
||||
|
||||
// clang-format off
|
||||
#define MIDI_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 MIDI_STANDARD_DESCRIPTOR_LEN 0x09
|
||||
|
||||
#define MIDI_CS_HEADER_DESCRIPTOR_INIT(wTotalLength) \
|
||||
0x07, /* bLength */ \
|
||||
USB_CS_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||
|
||||
266
components/drivers/usb/cherryusb/class/serial/usbh_cdc_acm.c
Normal file
266
components/drivers/usb/cherryusb/class/serial/usbh_cdc_acm.c
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (c) 2022 ~ 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_serial.h"
|
||||
#include "usbh_cdc_acm.h"
|
||||
|
||||
#undef USB_DBG_TAG
|
||||
#define USB_DBG_TAG "usbh_cdc_acm"
|
||||
#include "usb_log.h"
|
||||
|
||||
struct usbh_cdc_acm {
|
||||
struct usb_endpoint_descriptor *intin;
|
||||
struct usbh_urb intin_urb;
|
||||
struct usb_osal_timer *modem_timer;
|
||||
uint16_t modem_status;
|
||||
};
|
||||
|
||||
static int usbh_cdc_acm_attach(struct usbh_serial *serial)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret;
|
||||
|
||||
struct usbh_cdc_acm *cdc_acm_class = usb_osal_malloc(sizeof(struct usbh_cdc_acm));
|
||||
if (!cdc_acm_class) {
|
||||
USB_LOG_ERR("No memory for cdc_acm_class\r\n");
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
memset(cdc_acm_class, 0, sizeof(struct usbh_cdc_acm));
|
||||
serial->priv = cdc_acm_class;
|
||||
|
||||
for (uint8_t i = 0; i < serial->hport->config.intf[serial->intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
||||
ep_desc = &serial->hport->config.intf[serial->intf].altsetting[0].ep[i].ep_desc;
|
||||
|
||||
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
|
||||
if (ep_desc->bEndpointAddress & 0x80) {
|
||||
USBH_EP_INIT(cdc_acm_class->intin, ep_desc);
|
||||
break;
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cdc_acm_class->intin) {
|
||||
USB_LOG_ERR("Failed to find interrupt endpoint\r\n");
|
||||
ret = -USB_ERR_NODEV;
|
||||
goto errout;
|
||||
}
|
||||
return 0;
|
||||
errout:
|
||||
serial->priv = NULL;
|
||||
usb_osal_free(cdc_acm_class);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usbh_cdc_acm_detach(struct usbh_serial *serial)
|
||||
{
|
||||
struct usbh_cdc_acm *cdc_acm_class;
|
||||
|
||||
if (!serial || !serial->priv) {
|
||||
return;
|
||||
}
|
||||
|
||||
cdc_acm_class = (struct usbh_cdc_acm *)serial->priv;
|
||||
if (cdc_acm_class->intin) {
|
||||
usbh_kill_urb(&cdc_acm_class->intin_urb);
|
||||
}
|
||||
serial->priv = NULL;
|
||||
usb_osal_free(cdc_acm_class);
|
||||
}
|
||||
|
||||
static int usbh_cdc_acm_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->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 = serial->intf;
|
||||
setup->wLength = 7;
|
||||
|
||||
memcpy(serial->iobuffer, line_coding, sizeof(struct cdc_line_coding));
|
||||
|
||||
return usbh_control_transfer(serial->hport, setup, serial->iobuffer);
|
||||
}
|
||||
|
||||
static int usbh_cdc_acm_get_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
int ret;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->hport->setup;
|
||||
|
||||
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 = serial->intf;
|
||||
setup->wLength = 7;
|
||||
|
||||
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
memcpy(line_coding, serial->iobuffer, sizeof(struct cdc_line_coding));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_cdc_acm_set_line_state(struct usbh_serial *serial, bool dtr, bool rts)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->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 = serial->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(serial->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_cdc_acm_get_modem_status(struct usbh_serial *serial)
|
||||
{
|
||||
struct usbh_cdc_acm *cdc_acm_class;
|
||||
uintptr_t flags;
|
||||
uint16_t status;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
|
||||
cdc_acm_class = (struct usbh_cdc_acm *)serial->priv;
|
||||
|
||||
status = (cdc_acm_class->modem_status & CDC_SERIAL_STATE_DSR ? USBH_SERIAL_TIOCM_DSR : 0) |
|
||||
(cdc_acm_class->modem_status & CDC_SERIAL_STATE_RING ? USBH_SERIAL_TIOCM_RI : 0) |
|
||||
(cdc_acm_class->modem_status & CDC_SERIAL_STATE_DCD ? USBH_SERIAL_TIOCM_CD : 0) |
|
||||
(serial->line_state & USBH_SERIAL_TIOCM_DTR ? USBH_SERIAL_TIOCM_DTR : 0) |
|
||||
(serial->line_state & USBH_SERIAL_TIOCM_RTS ? USBH_SERIAL_TIOCM_RTS : 0);
|
||||
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBH_SERIAL_GET_MODEM_STATUS
|
||||
static int __usbh_cdc_acm_get_modem_status(struct usbh_serial *serial)
|
||||
{
|
||||
struct usbh_cdc_acm *cdc_acm_class;
|
||||
struct cdc_acm_notification *notification;
|
||||
uint16_t difference;
|
||||
uintptr_t flags;
|
||||
int ret;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
cdc_acm_class = (struct usbh_cdc_acm *)serial->priv;
|
||||
|
||||
usbh_int_urb_fill(&cdc_acm_class->intin_urb, serial->hport, cdc_acm_class->intin, &serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET], cdc_acm_class->intin->wMaxPacketSize, 0xffffffff, NULL, NULL);
|
||||
ret = usbh_submit_urb(&cdc_acm_class->intin_urb);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cdc_acm_class->intin_urb.actual_length < sizeof(struct cdc_acm_notification)) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
notification = (struct cdc_acm_notification *)&serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET];
|
||||
if (notification->bNotificationType != CDC_NOTIFICATION_SERIAL_STATE) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
|
||||
difference = cdc_acm_class->modem_status ^ notification->data;
|
||||
cdc_acm_class->modem_status = notification->data;
|
||||
|
||||
if (difference & CDC_SERIAL_STATE_DSR)
|
||||
serial->iocount.dsr++;
|
||||
if (difference & CDC_SERIAL_STATE_DCD)
|
||||
serial->iocount.dcd++;
|
||||
if (notification->data & CDC_SERIAL_STATE_BREAK)
|
||||
serial->iocount.brk++;
|
||||
if (notification->data & CDC_SERIAL_STATE_FRAMING)
|
||||
serial->iocount.frame++;
|
||||
if (notification->data & CDC_SERIAL_STATE_PARITY)
|
||||
serial->iocount.parity++;
|
||||
if (notification->data & CDC_SERIAL_STATE_OVERRUN)
|
||||
serial->iocount.overrun++;
|
||||
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct usbh_serial_driver cdc_acm_driver = {
|
||||
.driver_name = "cdc_acm",
|
||||
|
||||
.ignore_rx_header = 0,
|
||||
.ignore_tx_header = 0,
|
||||
|
||||
.attach = usbh_cdc_acm_attach,
|
||||
.detach = usbh_cdc_acm_detach,
|
||||
.set_flow_control = NULL,
|
||||
.set_line_coding = usbh_cdc_acm_set_line_coding,
|
||||
.get_line_coding = usbh_cdc_acm_get_line_coding,
|
||||
.set_line_state = usbh_cdc_acm_set_line_state,
|
||||
.get_modem_status = usbh_cdc_acm_get_modem_status,
|
||||
};
|
||||
|
||||
static int usbh_cdc_acm_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
return usbh_serial_probe(hport, intf, &cdc_acm_driver) ? 0 : -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
static int usbh_cdc_acm_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usbh_serial *serial = (struct usbh_serial *)hport->config.intf[intf].priv;
|
||||
|
||||
if (serial) {
|
||||
usbh_serial_remove(serial);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct usbh_class_driver cdc_acm_class_driver = {
|
||||
.driver_name = "cdc_acm",
|
||||
.connect = usbh_cdc_acm_connect,
|
||||
.disconnect = usbh_cdc_acm_disconnect
|
||||
};
|
||||
|
||||
CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_none_class_info = {
|
||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
||||
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
|
||||
.bInterfaceSubClass = CDC_ABSTRACT_CONTROL_MODEL,
|
||||
.bInterfaceProtocol = CDC_COMMON_PROTOCOL_NONE,
|
||||
.id_table = NULL,
|
||||
.class_driver = &cdc_acm_class_driver
|
||||
};
|
||||
|
||||
CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_at_class_info = {
|
||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
||||
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
|
||||
.bInterfaceSubClass = CDC_ABSTRACT_CONTROL_MODEL,
|
||||
.bInterfaceProtocol = CDC_COMMON_PROTOCOL_AT_COMMANDS,
|
||||
.id_table = NULL,
|
||||
.class_driver = &cdc_acm_class_driver
|
||||
};
|
||||
19
components/drivers/usb/cherryusb/class/serial/usbh_cdc_acm.h
Normal file
19
components/drivers/usb/cherryusb/class/serial/usbh_cdc_acm.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2022 ~ 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBH_CDC_ACM_H
|
||||
#define USBH_CDC_ACM_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_CDC_ACM_H */
|
||||
409
components/drivers/usb/cherryusb/class/serial/usbh_ch34x.c
Normal file
409
components/drivers/usb/cherryusb/class/serial/usbh_ch34x.c
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ~ 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_serial.h"
|
||||
#include "usbh_ch34x.h"
|
||||
|
||||
#undef USB_DBG_TAG
|
||||
#define USB_DBG_TAG "usbh_ch43x"
|
||||
#include "usb_log.h"
|
||||
|
||||
struct usbh_ch34x {
|
||||
struct usb_endpoint_descriptor *intin;
|
||||
struct usbh_urb intin_urb;
|
||||
struct usb_osal_timer *modem_timer;
|
||||
uint16_t modem_status;
|
||||
};
|
||||
|
||||
/* refer to https://github.com/WCHSoftGroup/ch341ser_linux/blob/main/driver/ch341.c */
|
||||
|
||||
static int usbh_ch34x_get_baudrate_div(uint32_t baudrate, uint8_t *factor, uint8_t *divisor)
|
||||
{
|
||||
uint8_t a;
|
||||
uint8_t b;
|
||||
uint32_t c;
|
||||
|
||||
switch (baudrate) {
|
||||
case 921600:
|
||||
a = 0xf3;
|
||||
b = 7;
|
||||
break;
|
||||
|
||||
case 307200:
|
||||
a = 0xd9;
|
||||
b = 7;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (baudrate > 6000000 / 255) {
|
||||
b = 3;
|
||||
c = 6000000;
|
||||
} else if (baudrate > 750000 / 255) {
|
||||
b = 2;
|
||||
c = 750000;
|
||||
} else if (baudrate > 93750 / 255) {
|
||||
b = 1;
|
||||
c = 93750;
|
||||
} else {
|
||||
b = 0;
|
||||
c = 11719;
|
||||
}
|
||||
a = (uint8_t)(c / baudrate);
|
||||
if (a == 0 || a == 0xFF) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
if ((c / a - baudrate) > (baudrate - c / (a + 1))) {
|
||||
a++;
|
||||
}
|
||||
a = (uint8_t)(256 - a);
|
||||
break;
|
||||
}
|
||||
|
||||
*factor = a;
|
||||
*divisor = b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbh_ch34x_control_out(struct usbh_serial *serial, uint8_t bRequest, uint16_t wValue, uint16_t wIndex)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = bRequest;
|
||||
setup->wValue = wValue;
|
||||
setup->wIndex = wIndex;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(serial->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ch34x_control_in(struct usbh_serial *serial, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t *data, uint16_t size)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
int ret;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = bRequest;
|
||||
setup->wValue = wValue;
|
||||
setup->wIndex = wIndex;
|
||||
setup->wLength = size;
|
||||
|
||||
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
memcpy(data, serial->iobuffer, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_ch34x_get_version(struct usbh_serial *serial)
|
||||
{
|
||||
int ret;
|
||||
uint8_t buf[2];
|
||||
|
||||
ret = usbh_ch34x_control_in(serial, CH34X_READ_VERSION, 0, 0, buf, 2);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
USB_LOG_INFO("chip version: 0x%02x\r\n", buf[0]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_ch34x_attach(struct usbh_serial *serial)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret;
|
||||
|
||||
struct usbh_ch34x *ch34x_class = usb_osal_malloc(sizeof(struct usbh_ch34x));
|
||||
if (!ch34x_class) {
|
||||
USB_LOG_ERR("No memory for ch34x_class\r\n");
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
memset(ch34x_class, 0, sizeof(struct usbh_ch34x));
|
||||
serial->priv = ch34x_class;
|
||||
|
||||
for (uint8_t i = 0; i < serial->hport->config.intf[serial->intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
||||
ep_desc = &serial->hport->config.intf[serial->intf].altsetting[0].ep[i].ep_desc;
|
||||
|
||||
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
|
||||
if (ep_desc->bEndpointAddress & 0x80) {
|
||||
USBH_EP_INIT(ch34x_class->intin, ep_desc);
|
||||
break;
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ch34x_class->intin) {
|
||||
USB_LOG_ERR("Failed to find interrupt endpoint\r\n");
|
||||
ret = -USB_ERR_NODEV;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = usbh_ch34x_get_version(serial);
|
||||
ret |= usbh_ch34x_control_out(serial, CH34X_SERIAL_INIT, 0, 0);
|
||||
ret |= usbh_ch34x_control_out(serial, CH34X_WRITE_REG, 0x1312, 0xd982);
|
||||
ret |= usbh_ch34x_control_out(serial, CH34X_WRITE_REG, 0x0f2c, 0x0007);
|
||||
if (ret < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
serial->priv = NULL;
|
||||
usb_osal_free(ch34x_class);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usbh_ch34x_detach(struct usbh_serial *serial)
|
||||
{
|
||||
struct usbh_ch34x *ch34x_class;
|
||||
|
||||
if (!serial || !serial->priv) {
|
||||
return;
|
||||
}
|
||||
|
||||
ch34x_class = (struct usbh_ch34x *)serial->priv;
|
||||
if (ch34x_class->intin) {
|
||||
usbh_kill_urb(&ch34x_class->intin_urb);
|
||||
}
|
||||
serial->priv = NULL;
|
||||
usb_osal_free(ch34x_class);
|
||||
}
|
||||
|
||||
static int usbh_ch34x_set_flow_ctrl(struct usbh_serial *serial, bool hardctrl)
|
||||
{
|
||||
return usbh_ch34x_control_out(serial, CH34X_WRITE_REG, 0x2727, hardctrl ? 0x0101 : 0x0000);
|
||||
}
|
||||
|
||||
static int usbh_ch34x_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
uint16_t reg_value = 0;
|
||||
uint16_t value = 0;
|
||||
uint16_t index = 0;
|
||||
uint8_t factor = 0;
|
||||
uint8_t divisor = 0;
|
||||
|
||||
switch (line_coding->bParityType) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
reg_value |= CH341_L_PO;
|
||||
break;
|
||||
case 2:
|
||||
reg_value |= CH341_L_PE;
|
||||
break;
|
||||
case 3:
|
||||
reg_value |= CH341_L_PM;
|
||||
break;
|
||||
case 4:
|
||||
reg_value |= CH341_L_PS;
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
switch (line_coding->bDataBits) {
|
||||
case 5:
|
||||
reg_value |= CH341_L_D5;
|
||||
break;
|
||||
case 6:
|
||||
reg_value |= CH341_L_D6;
|
||||
break;
|
||||
case 7:
|
||||
reg_value |= CH341_L_D7;
|
||||
break;
|
||||
case 8:
|
||||
reg_value |= CH341_L_D8;
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
if (line_coding->bCharFormat == 2) {
|
||||
reg_value |= CH341_L_SB;
|
||||
}
|
||||
|
||||
usbh_ch34x_get_baudrate_div(line_coding->dwDTERate, &factor, &divisor);
|
||||
|
||||
reg_value |= 0xC0;
|
||||
value |= 0x9c;
|
||||
value |= reg_value << 8;
|
||||
index |= 0x80 | divisor;
|
||||
index |= (uint16_t)factor << 8;
|
||||
|
||||
return usbh_ch34x_control_out(serial, CH34X_SERIAL_INIT, value, index);
|
||||
}
|
||||
|
||||
static int usbh_ch34x_set_line_state(struct usbh_serial *serial, bool dtr, bool rts)
|
||||
{
|
||||
uint16_t value = 0;
|
||||
uint8_t control = 0;
|
||||
|
||||
control = (dtr << 5) | (rts << 6);
|
||||
value = (uint8_t)~control;
|
||||
|
||||
return usbh_ch34x_control_out(serial, CH34X_MODEM_CTRL, value, 0x0000);
|
||||
}
|
||||
|
||||
static int usbh_ch34x_get_modem_status(struct usbh_serial *serial)
|
||||
{
|
||||
struct usbh_ch34x *ch34x_class;
|
||||
uintptr_t flags;
|
||||
uint16_t status;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
|
||||
ch34x_class = (struct usbh_ch34x *)serial->priv;
|
||||
|
||||
status = (ch34x_class->modem_status & CH341_CTI_DS ? USBH_SERIAL_TIOCM_DSR : 0) |
|
||||
(ch34x_class->modem_status & CH341_CTI_C ? USBH_SERIAL_TIOCM_CTS : 0) |
|
||||
(ch34x_class->modem_status & CH341_CTRL_RI ? USBH_SERIAL_TIOCM_RI : 0) |
|
||||
(ch34x_class->modem_status & CH341_CTI_DC ? USBH_SERIAL_TIOCM_CD : 0) |
|
||||
(serial->line_state & USBH_SERIAL_TIOCM_DTR ? USBH_SERIAL_TIOCM_DTR : 0) |
|
||||
(serial->line_state & USBH_SERIAL_TIOCM_RTS ? USBH_SERIAL_TIOCM_RTS : 0);
|
||||
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBH_SERIAL_GET_MODEM_STATUS
|
||||
static int __usbh_ch34x_get_modem_status(struct usbh_serial *serial, uint16_t *status)
|
||||
{
|
||||
struct usbh_ch34x *ch34x_class;
|
||||
uint8_t type = 0;
|
||||
uint8_t data = 0;
|
||||
uint16_t difference;
|
||||
uintptr_t flags;
|
||||
int ret;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
ch34x_class = (struct usbh_ch34x *)serial->priv;
|
||||
|
||||
usbh_int_urb_fill(&ch34x_class->intin_urb, serial->hport, ch34x_class->intin, &serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET], ch34x_class->intin->wMaxPacketSize, 0xffffffff, NULL, NULL);
|
||||
ret = usbh_submit_urb(&ch34x_class->intin_urb);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret < 4) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
|
||||
type = serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET];
|
||||
if (type & CH341_CTT_M) {
|
||||
data = ~serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET + 2] & CH341_CTI_ST;
|
||||
difference = data ^ (ch34x_class->modem_status & CH341_CTI_ST);
|
||||
ch34x_class->modem_status = data;
|
||||
|
||||
if (difference) {
|
||||
if (difference & CH341_CTI_C) {
|
||||
serial->iocount.cts++;
|
||||
}
|
||||
if (difference & CH341_CTI_DS) {
|
||||
serial->iocount.dsr++;
|
||||
}
|
||||
if (difference & CH341_CTRL_RI) {
|
||||
serial->iocount.rng++;
|
||||
}
|
||||
if (difference & CH341_CTI_DC) {
|
||||
serial->iocount.dcd++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type & CH341_CTT_O) {
|
||||
serial->iocount.overrun++;
|
||||
}
|
||||
if ((type & CH341_CTT_F) == CH341_CTT_F) {
|
||||
serial->iocount.frame++;
|
||||
}
|
||||
if (type & CH341_CTT_P) {
|
||||
serial->iocount.parity++;
|
||||
}
|
||||
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct usbh_serial_driver ch34x_driver = {
|
||||
.driver_name = "ch34x",
|
||||
|
||||
.ignore_rx_header = 0,
|
||||
.ignore_tx_header = 0,
|
||||
|
||||
.attach = usbh_ch34x_attach,
|
||||
.detach = usbh_ch34x_detach,
|
||||
.set_flow_control = usbh_ch34x_set_flow_ctrl,
|
||||
.set_line_coding = usbh_ch34x_set_line_coding,
|
||||
.get_line_coding = NULL,
|
||||
.set_line_state = usbh_ch34x_set_line_state,
|
||||
.get_modem_status = usbh_ch34x_get_modem_status,
|
||||
};
|
||||
|
||||
static int usbh_ch34x_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
return usbh_serial_probe(hport, intf, &ch34x_driver) ? 0 : -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
static int usbh_ch34x_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usbh_serial *serial = (struct usbh_serial *)hport->config.intf[intf].priv;
|
||||
|
||||
if (serial) {
|
||||
usbh_serial_remove(serial);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const uint16_t ch34x_id_table[][2] = {
|
||||
{ 0x1A86, 0x7523 }, /* ch340 chip */
|
||||
{ 0x1A86, 0x7522 }, /* ch340k chip */
|
||||
{ 0x1A86, 0x5523 }, /* ch341 chip */
|
||||
{ 0x1A86, 0xe523 }, /* ch330 chip */
|
||||
{ 0x4348, 0x5523 }, /* ch340 custom chip */
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
const struct usbh_class_driver ch34x_class_driver = {
|
||||
.driver_name = "ch34x",
|
||||
.connect = usbh_ch34x_connect,
|
||||
.disconnect = usbh_ch34x_disconnect
|
||||
};
|
||||
|
||||
CLASS_INFO_DEFINE const struct usbh_class_info ch34x_class_info = {
|
||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||
.bInterfaceClass = 0xff,
|
||||
.bInterfaceSubClass = 0x00,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.id_table = ch34x_id_table,
|
||||
.class_driver = &ch34x_class_driver
|
||||
};
|
||||
56
components/drivers/usb/cherryusb/class/serial/usbh_ch34x.h
Normal file
56
components/drivers/usb/cherryusb/class/serial/usbh_ch34x.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ~ 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBH_CH34X_H
|
||||
#define USBH_CH34X_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
|
||||
/* Requests */
|
||||
#define CH34X_READ_VERSION 0x5F
|
||||
#define CH34X_WRITE_REG 0x9A
|
||||
#define CH34X_READ_REG 0x95
|
||||
#define CH34X_SERIAL_INIT 0xA1
|
||||
#define CH34X_MODEM_CTRL 0xA4
|
||||
|
||||
// modem control bits
|
||||
#define CH34X_BIT_RTS (1 << 6)
|
||||
#define CH34X_BIT_DTR (1 << 5)
|
||||
|
||||
#define CH341_CTO_O 0x10
|
||||
#define CH341_CTO_D 0x20
|
||||
#define CH341_CTO_R 0x40
|
||||
#define CH341_CTI_C 0x01
|
||||
#define CH341_CTI_DS 0x02
|
||||
#define CH341_CTRL_RI 0x04
|
||||
#define CH341_CTI_DC 0x08
|
||||
#define CH341_CTI_ST 0x0f
|
||||
|
||||
#define CH341_CTT_M BIT(3)
|
||||
#define CH341_CTT_F (BIT(2) | BIT(6))
|
||||
#define CH341_CTT_P BIT(2)
|
||||
#define CH341_CTT_O BIT(1)
|
||||
|
||||
#define CH341_L_ER 0x80
|
||||
#define CH341_L_ET 0x40
|
||||
#define CH341_L_PS 0x38
|
||||
#define CH341_L_PM 0x28
|
||||
#define CH341_L_PE 0x18
|
||||
#define CH341_L_PO 0x08
|
||||
#define CH341_L_SB 0x04
|
||||
#define CH341_L_D8 0x03
|
||||
#define CH341_L_D7 0x02
|
||||
#define CH341_L_D6 0x01
|
||||
#define CH341_L_D5 0x00
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_CH34X_H */
|
||||
507
components/drivers/usb/cherryusb/class/serial/usbh_cp210x.c
Normal file
507
components/drivers/usb/cherryusb/class/serial/usbh_cp210x.c
Normal file
File diff suppressed because it is too large
Load Diff
187
components/drivers/usb/cherryusb/class/serial/usbh_cp210x.h
Normal file
187
components/drivers/usb/cherryusb/class/serial/usbh_cp210x.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ~ 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBH_CP210X_H
|
||||
#define USBH_CP210X_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
|
||||
/* Requests */
|
||||
#define CP210X_IFC_ENABLE 0x00
|
||||
#define CP210X_SET_BAUDDIV 0x01
|
||||
#define CP210X_GET_BAUDDIV 0x02
|
||||
#define CP210X_SET_LINE_CTL 0x03 // Set parity, data bits, stop bits
|
||||
#define CP210X_GET_LINE_CTL 0x04
|
||||
#define CP210X_SET_BREAK 0x05
|
||||
#define CP210X_IMM_CHAR 0x06
|
||||
#define CP210X_SET_MHS 0x07 // Set DTR, RTS
|
||||
#define CP210X_GET_MDMSTS 0x08
|
||||
#define CP210X_SET_XON 0x09
|
||||
#define CP210X_SET_XOFF 0x0A
|
||||
#define CP210X_SET_EVENTMASK 0x0B
|
||||
#define CP210X_GET_EVENTMASK 0x0C
|
||||
#define CP210X_SET_CHAR 0x0D
|
||||
#define CP210X_GET_CHARS 0x0E
|
||||
#define CP210X_GET_PROPS 0x0F
|
||||
#define CP210X_GET_COMM_STATUS 0x10
|
||||
#define CP210X_RESET 0x11
|
||||
#define CP210X_PURGE 0x12
|
||||
#define CP210X_SET_FLOW 0x13
|
||||
#define CP210X_GET_FLOW 0x14
|
||||
#define CP210X_EMBED_EVENTS 0x15
|
||||
#define CP210X_GET_EVENTSTATE 0x16
|
||||
#define CP210X_SET_CHARS 0x19
|
||||
#define CP210X_GET_BAUDRATE 0x1D
|
||||
#define CP210X_SET_BAUDRATE 0x1E // Set baudrate
|
||||
#define CP210X_VENDOR_SPECIFIC 0xFF
|
||||
|
||||
/* CP210X_VENDOR_SPECIFIC values */
|
||||
#define CP210X_GET_FW_VER 0x000E
|
||||
#define CP210X_READ_2NCONFIG 0x000E
|
||||
#define CP210X_GET_FW_VER_2N 0x0010
|
||||
#define CP210X_READ_LATCH 0x00C2
|
||||
#define CP210X_GET_PARTNUM 0x370B
|
||||
#define CP210X_GET_PORTCONFIG 0x370C
|
||||
#define CP210X_GET_DEVICEMODE 0x3711
|
||||
#define CP210X_WRITE_LATCH 0x37E1
|
||||
|
||||
/* CP210X_IFC_ENABLE */
|
||||
#define CP210X_UART_ENABLE 0x0001
|
||||
#define CP210X_UART_DISABLE 0x0000
|
||||
|
||||
/* CP210X_(SET|GET)_BAUDDIV */
|
||||
#define CP210X_BAUD_RATE_GEN_FREQ 0x384000
|
||||
|
||||
/* CP210X_(SET|GET)_LINE_CTL */
|
||||
#define CP210X_BITS_DATA_MASK 0X0f00
|
||||
#define CP210X_BITS_DATA_5 0X0500
|
||||
#define CP210X_BITS_DATA_6 0X0600
|
||||
#define CP210X_BITS_DATA_7 0X0700
|
||||
#define CP210X_BITS_DATA_8 0X0800
|
||||
#define CP210X_BITS_DATA_9 0X0900
|
||||
|
||||
#define CP210X_BITS_PARITY_MASK 0x00f0
|
||||
#define CP210X_BITS_PARITY_NONE 0x0000
|
||||
#define CP210X_BITS_PARITY_ODD 0x0010
|
||||
#define CP210X_BITS_PARITY_EVEN 0x0020
|
||||
#define CP210X_BITS_PARITY_MARK 0x0030
|
||||
#define CP210X_BITS_PARITY_SPACE 0x0040
|
||||
|
||||
#define CP210X_BITS_STOP_MASK 0x000f
|
||||
#define CP210X_BITS_STOP_1 0x0000
|
||||
#define CP210X_BITS_STOP_1_5 0x0001
|
||||
#define CP210X_BITS_STOP_2 0x0002
|
||||
|
||||
/* CP210X_SET_BREAK */
|
||||
#define CP210X_BREAK_ON 0x0001
|
||||
#define CP210X_BREAK_OFF 0x0000
|
||||
|
||||
/* CP210X_(SET_MHS|GET_MDMSTS) */
|
||||
#define CP210X_CONTROL_DTR 0x0001
|
||||
#define CP210X_CONTROL_RTS 0x0002
|
||||
#define CP210X_CONTROL_CTS 0x0010
|
||||
#define CP210X_CONTROL_DSR 0x0020
|
||||
#define CP210X_CONTROL_RING 0x0040
|
||||
#define CP210X_CONTROL_DCD 0x0080
|
||||
#define CP210X_CONTROL_WRITE_DTR 0x0100
|
||||
#define CP210X_CONTROL_WRITE_RTS 0x0200
|
||||
|
||||
/* CP210X_(GET|SET)_CHARS */
|
||||
struct cp210x_special_chars {
|
||||
uint8_t bEofChar;
|
||||
uint8_t bErrorChar;
|
||||
uint8_t bBreakChar;
|
||||
uint8_t bEventChar;
|
||||
uint8_t bXonChar;
|
||||
uint8_t bXoffChar;
|
||||
};
|
||||
|
||||
/* CP210X_GET_COMM_STATUS returns these 0x13 bytes */
|
||||
struct cp210x_comm_status {
|
||||
uint32_t ulErrors;
|
||||
uint32_t ulHoldReasons;
|
||||
uint32_t ulAmountInInQueue;
|
||||
uint32_t ulAmountInOutQueue;
|
||||
uint8_t bEofReceived;
|
||||
uint8_t bWaitForImmediate;
|
||||
uint8_t bReserved;
|
||||
} __PACKED;
|
||||
|
||||
/*
|
||||
* CP210X_PURGE - 16 bits passed in wValue of USB request.
|
||||
* SiLabs app note AN571 gives a strange description of the 4 bits:
|
||||
* bit 0 or bit 2 clears the transmit queue and 1 or 3 receive.
|
||||
* writing 1 to all, however, purges cp2108 well enough to avoid the hang.
|
||||
*/
|
||||
#define PURGE_ALL 0x000f
|
||||
|
||||
/* CP210X_EMBED_EVENTS */
|
||||
#define CP210X_ESCCHAR 0xec
|
||||
|
||||
#define CP210X_LSR_OVERRUN BIT(1)
|
||||
#define CP210X_LSR_PARITY BIT(2)
|
||||
#define CP210X_LSR_FRAME BIT(3)
|
||||
#define CP210X_LSR_BREAK BIT(4)
|
||||
|
||||
/* CP210X_GET_FLOW/CP210X_SET_FLOW read/write these 0x10 bytes */
|
||||
struct cp210x_flow_ctl {
|
||||
uint32_t lControlHandshake;
|
||||
uint32_t lFlowReplace;
|
||||
uint32_t lXonLimit;
|
||||
uint32_t lXoffLimit;
|
||||
};
|
||||
|
||||
/* cp210x_flow_ctl::ulControlHandshake */
|
||||
#define CP210X_SERIAL_DTR_MASK (0x03 << 0)
|
||||
#define CP210X_SERIAL_DTR_INACTIVE (0 << 0)
|
||||
#define CP210X_SERIAL_DTR_ACTIVE (1 << 0)
|
||||
#define CP210X_SERIAL_DTR_FLOW_CTL (2 << 0)
|
||||
#define CP210X_SERIAL_CTS_HANDSHAKE BIT(3)
|
||||
#define CP210X_SERIAL_DSR_HANDSHAKE BIT(4)
|
||||
#define CP210X_SERIAL_DCD_HANDSHAKE BIT(5)
|
||||
#define CP210X_SERIAL_DSR_SENSITIVITY BIT(6)
|
||||
|
||||
/* cp210x_flow_ctl::ulFlowReplace */
|
||||
#define CP210X_SERIAL_AUTO_TRANSMIT BIT(0)
|
||||
#define CP210X_SERIAL_AUTO_RECEIVE BIT(1)
|
||||
#define CP210X_SERIAL_ERROR_CHAR BIT(2)
|
||||
#define CP210X_SERIAL_NULL_STRIPPING BIT(3)
|
||||
#define CP210X_SERIAL_BREAK_CHAR BIT(4)
|
||||
#define CP210X_SERIAL_RTS_MASK (0x03 << 6)
|
||||
#define CP210X_SERIAL_RTS_INACTIVE (0 << 6)
|
||||
#define CP210X_SERIAL_RTS_ACTIVE (1 << 6)
|
||||
#define CP210X_SERIAL_RTS_FLOW_CTL (2 << 6)
|
||||
#define CP210X_SERIAL_XOFF_CONTINUE BIT(31)
|
||||
|
||||
/* CP210X_VENDOR_SPECIFIC, CP210X_GET_DEVICEMODE call reads these 0x2 bytes. */
|
||||
struct cp210x_pin_mode {
|
||||
uint8_t eci;
|
||||
uint8_t sci;
|
||||
};
|
||||
|
||||
#define CP210X_PIN_MODE_MODEM 0
|
||||
#define CP210X_PIN_MODE_GPIO BIT(0)
|
||||
|
||||
/* Part number definitions */
|
||||
#define CP210X_PARTNUM_CP2101 0x01
|
||||
#define CP210X_PARTNUM_CP2102 0x02
|
||||
#define CP210X_PARTNUM_CP2103 0x03
|
||||
#define CP210X_PARTNUM_CP2104 0x04
|
||||
#define CP210X_PARTNUM_CP2105 0x05
|
||||
#define CP210X_PARTNUM_CP2108 0x08
|
||||
#define CP210X_PARTNUM_CP2102N_QFN28 0x20
|
||||
#define CP210X_PARTNUM_CP2102N_QFN24 0x21
|
||||
#define CP210X_PARTNUM_CP2102N_QFN20 0x22
|
||||
#define CP210X_PARTNUM_UNKNOWN 0xFF
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_CP210X_H */
|
||||
407
components/drivers/usb/cherryusb/class/serial/usbh_ftdi.c
Normal file
407
components/drivers/usb/cherryusb/class/serial/usbh_ftdi.c
Normal file
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ~ 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_serial.h"
|
||||
#include "usbh_ftdi.h"
|
||||
|
||||
#undef USB_DBG_TAG
|
||||
#define USB_DBG_TAG "usbh_ftdi"
|
||||
#include "usb_log.h"
|
||||
|
||||
enum ftdi_chip_type {
|
||||
SIO,
|
||||
FT232A,
|
||||
FT232B,
|
||||
FT2232C,
|
||||
FT232R,
|
||||
FT232H,
|
||||
FT2232H,
|
||||
FT4232H,
|
||||
FT4232HA,
|
||||
FT232HP,
|
||||
FT233HP,
|
||||
FT2232HP,
|
||||
FT2233HP,
|
||||
FT4232HP,
|
||||
FT4233HP,
|
||||
FTX,
|
||||
};
|
||||
|
||||
static const char *ftdi_chip_name[] = {
|
||||
[SIO] = "SIO", /* the serial part of FT8U100AX */
|
||||
[FT232A] = "FT232A",
|
||||
[FT232B] = "FT232B",
|
||||
[FT2232C] = "FT2232C/D",
|
||||
[FT232R] = "FT232R",
|
||||
[FT232H] = "FT232H",
|
||||
[FT2232H] = "FT2232H",
|
||||
[FT4232H] = "FT4232H",
|
||||
[FT4232HA] = "FT4232HA",
|
||||
[FT232HP] = "FT232HP",
|
||||
[FT233HP] = "FT233HP",
|
||||
[FT2232HP] = "FT2232HP",
|
||||
[FT2233HP] = "FT2233HP",
|
||||
[FT4232HP] = "FT4232HP",
|
||||
[FT4233HP] = "FT4233HP",
|
||||
[FTX] = "FT-X",
|
||||
};
|
||||
|
||||
struct usbh_ftdi {
|
||||
enum ftdi_chip_type chip_type;
|
||||
};
|
||||
|
||||
static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, int base)
|
||||
{
|
||||
static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
|
||||
uint32_t divisor;
|
||||
/* divisor shifted 3 bits to the left */
|
||||
int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud);
|
||||
divisor = divisor3 >> 3;
|
||||
divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14;
|
||||
/* Deal with special cases for highest baud rates. */
|
||||
if (divisor == 1) /* 1.0 */
|
||||
divisor = 0;
|
||||
else if (divisor == 0x4001) /* 1.5 */
|
||||
divisor = 1;
|
||||
return divisor;
|
||||
}
|
||||
|
||||
static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud)
|
||||
{
|
||||
return ftdi_232bm_baud_base_to_divisor(baud, 48000000);
|
||||
}
|
||||
|
||||
static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, int base)
|
||||
{
|
||||
static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
|
||||
uint32_t divisor;
|
||||
int divisor3;
|
||||
|
||||
/* hi-speed baud rate is 10-bit sampling instead of 16-bit */
|
||||
divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud);
|
||||
|
||||
divisor = divisor3 >> 3;
|
||||
divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14;
|
||||
/* Deal with special cases for highest baud rates. */
|
||||
if (divisor == 1) /* 1.0 */
|
||||
divisor = 0;
|
||||
else if (divisor == 0x4001) /* 1.5 */
|
||||
divisor = 1;
|
||||
/*
|
||||
* Set this bit to turn off a divide by 2.5 on baud rate generator
|
||||
* This enables baud rates up to 12Mbaud but cannot reach below 1200
|
||||
* baud with this bit set
|
||||
*/
|
||||
divisor |= 0x00020000;
|
||||
return divisor;
|
||||
}
|
||||
|
||||
static uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud)
|
||||
{
|
||||
return ftdi_2232h_baud_base_to_divisor(baud, 120000000);
|
||||
}
|
||||
|
||||
int usbh_ftdi_reset(struct usbh_serial *serial)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = FTDI_SIO_RESET;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = serial->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(serial->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_set_baudrate(struct usbh_serial *serial, uint32_t baudrate)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
struct usbh_ftdi *ftdi_class;
|
||||
uint32_t div_value;
|
||||
uint16_t value;
|
||||
uint8_t baudrate_high;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->hport->setup;
|
||||
ftdi_class = (struct usbh_ftdi *)serial->priv;
|
||||
|
||||
switch (ftdi_class->chip_type) {
|
||||
case FT232B:
|
||||
case FT2232C:
|
||||
case FT232R:
|
||||
if (baudrate > 3000000) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
div_value = ftdi_232bm_baud_to_divisor(baudrate);
|
||||
break;
|
||||
default:
|
||||
if ((baudrate <= 12000000) && (baudrate >= 1200)) {
|
||||
div_value = ftdi_2232h_baud_to_divisor(baudrate);
|
||||
} else if (baudrate < 1200) {
|
||||
div_value = ftdi_232bm_baud_to_divisor(baudrate);
|
||||
} else {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
value = div_value & 0xFFFF;
|
||||
baudrate_high = (div_value >> 16) & 0xff;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = FTDI_SIO_SET_BAUDRATE;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = (baudrate_high << 8) | serial->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(serial->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_set_data_format(struct usbh_serial *serial, uint8_t databits, uint8_t parity, uint8_t stopbits, uint8_t isbreak)
|
||||
{
|
||||
/**
|
||||
* D0-D7 databits BITS_7=7, BITS_8=8
|
||||
* D8-D10 parity NONE=0, ODD=1, EVEN=2, MARK=3, SPACE=4
|
||||
* D11-D12 STOP_BIT_1=0, STOP_BIT_15=1, STOP_BIT_2=2
|
||||
* D14 BREAK_OFF=0, BREAK_ON=1
|
||||
**/
|
||||
struct usb_setup_packet *setup;
|
||||
uint16_t value;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->hport->setup;
|
||||
|
||||
value = ((isbreak & 0x01) << 14) | ((stopbits & 0x03) << 11) | ((parity & 0x0f) << 8) | (databits & 0x0f);
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = FTDI_SIO_SET_DATA;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = serial->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(serial->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_set_latency_timer(struct usbh_serial *serial, uint16_t value)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = FTDI_SIO_SET_LATENCY_TIMER;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = serial->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(serial->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_attach(struct usbh_serial *serial)
|
||||
{
|
||||
uint16_t version;
|
||||
uint8_t chip_type;
|
||||
int ret;
|
||||
|
||||
version = serial->hport->device_desc.bcdDevice;
|
||||
|
||||
switch (version) {
|
||||
case 0x400:
|
||||
chip_type = FT232B;
|
||||
break;
|
||||
case 0x500:
|
||||
chip_type = FT2232C;
|
||||
break;
|
||||
case 0x600:
|
||||
chip_type = FT232R;
|
||||
break;
|
||||
case 0x700:
|
||||
chip_type = FT2232H;
|
||||
break;
|
||||
case 0x900:
|
||||
chip_type = FT232H;
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_ERR("Unsupported FTDI chip version: 0x%04x\r\n", version);
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
|
||||
USB_LOG_INFO("chip name: %s\r\n", ftdi_chip_name[chip_type]);
|
||||
|
||||
struct usbh_ftdi *ftdi_class = usb_osal_malloc(sizeof(struct usbh_ftdi));
|
||||
if (!ftdi_class) {
|
||||
USB_LOG_ERR("No memory for ftdi_class\r\n");
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
memset(ftdi_class, 0, sizeof(struct usbh_ftdi));
|
||||
serial->priv = ftdi_class;
|
||||
|
||||
ftdi_class->chip_type = chip_type;
|
||||
ret = usbh_ftdi_set_latency_timer(serial, 0x10);
|
||||
if (ret < 0) {
|
||||
goto errout;
|
||||
}
|
||||
return 0;
|
||||
errout:
|
||||
serial->priv = NULL;
|
||||
usb_osal_free(ftdi_class);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usbh_ftdi_detach(struct usbh_serial *serial)
|
||||
{
|
||||
if (serial && serial->priv) {
|
||||
serial->priv = NULL;
|
||||
usb_osal_free(serial->priv);
|
||||
}
|
||||
}
|
||||
|
||||
static int usbh_ftdi_set_flow_ctrl(struct usbh_serial *serial, bool hardctrl)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = FTDI_SIO_SET_FLOW_CTRL;
|
||||
setup->wValue = hardctrl ? FTDI_SIO_RTS_CTS_HS : FTDI_SIO_DISABLE_FLOW_CTRL;
|
||||
setup->wIndex = serial->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(serial->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
int ret = usbh_ftdi_set_baudrate(serial, line_coding->dwDTERate);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return usbh_ftdi_set_data_format(serial, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat, 0);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_set_line_state(struct usbh_serial *serial, bool dtr, bool rts)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
uint16_t value = 0;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->hport->setup;
|
||||
|
||||
value = ((dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | (rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW));
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = FTDI_SIO_SET_MODEM_CTRL;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = serial->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(serial->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_get_modem_status(struct usbh_serial *serial)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
uint16_t status = 0;
|
||||
int ret;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
setup = serial->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = FTDI_SIO_GET_MODEM_STATUS;
|
||||
setup->wValue = 0x0000;
|
||||
setup->wIndex = serial->intf;
|
||||
setup->wLength = 2;
|
||||
|
||||
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
|
||||
if (ret < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = (serial->iobuffer[0] & FTDI_SIO_DSR_MASK ? USBH_SERIAL_TIOCM_DSR : 0) |
|
||||
(serial->iobuffer[0] & FTDI_SIO_CTS_MASK ? USBH_SERIAL_TIOCM_CTS : 0) |
|
||||
(serial->iobuffer[0] & FTDI_SIO_RI_MASK ? USBH_SERIAL_TIOCM_RI : 0) |
|
||||
(serial->iobuffer[0] & FTDI_SIO_RLSD_MASK ? USBH_SERIAL_TIOCM_CD : 0) |
|
||||
(serial->line_state & USBH_SERIAL_TIOCM_DTR ? USBH_SERIAL_TIOCM_DTR : 0) |
|
||||
(serial->line_state & USBH_SERIAL_TIOCM_RTS ? USBH_SERIAL_TIOCM_RTS : 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static const struct usbh_serial_driver ftdi_driver = {
|
||||
.driver_name = "ftdi",
|
||||
|
||||
.ignore_rx_header = 2,
|
||||
.ignore_tx_header = 0,
|
||||
|
||||
.attach = usbh_ftdi_attach,
|
||||
.detach = usbh_ftdi_detach,
|
||||
.set_flow_control = usbh_ftdi_set_flow_ctrl,
|
||||
.set_line_coding = usbh_ftdi_set_line_coding,
|
||||
.get_line_coding = NULL,
|
||||
.set_line_state = usbh_ftdi_set_line_state,
|
||||
.get_modem_status = usbh_ftdi_get_modem_status,
|
||||
};
|
||||
|
||||
static int usbh_ftdi_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
return usbh_serial_probe(hport, intf, &ftdi_driver) ? 0 : -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
static int usbh_ftdi_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usbh_serial *serial = (struct usbh_serial *)hport->config.intf[intf].priv;
|
||||
|
||||
if (serial) {
|
||||
usbh_serial_remove(serial);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const uint16_t ftdi_id_table[][2] = {
|
||||
{ 0x0403, 0x6001 },
|
||||
{ 0x0403, 0x6010 },
|
||||
{ 0x0403, 0x6014 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
const struct usbh_class_driver ftdi_class_driver = {
|
||||
.driver_name = "ftdi",
|
||||
.connect = usbh_ftdi_connect,
|
||||
.disconnect = usbh_ftdi_disconnect
|
||||
};
|
||||
|
||||
CLASS_INFO_DEFINE const struct usbh_class_info ftdi_class_info = {
|
||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||
.bInterfaceClass = 0xff,
|
||||
.bInterfaceSubClass = 0x00,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.id_table = ftdi_id_table,
|
||||
.class_driver = &ftdi_class_driver
|
||||
};
|
||||
341
components/drivers/usb/cherryusb/class/serial/usbh_ftdi.h
Normal file
341
components/drivers/usb/cherryusb/class/serial/usbh_ftdi.h
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ~ 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBH_FTDI_H
|
||||
#define USBH_FTDI_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
|
||||
#define FTDI_VID 0x0403 /* Vendor Id */
|
||||
|
||||
/* FTDI device PIDs */
|
||||
#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
|
||||
#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
|
||||
#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
|
||||
#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
|
||||
#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */
|
||||
#define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */
|
||||
#define FTDI_FT2233HP_PID 0x6040 /* Dual channel hi-speed device with PD */
|
||||
#define FTDI_FT4233HP_PID 0x6041 /* Quad channel hi-speed device with PD */
|
||||
#define FTDI_FT2232HP_PID 0x6042 /* Dual channel hi-speed device with PD */
|
||||
#define FTDI_FT4232HP_PID 0x6043 /* Quad channel hi-speed device with PD */
|
||||
#define FTDI_FT233HP_PID 0x6044 /* Dual channel hi-speed device with PD */
|
||||
#define FTDI_FT232HP_PID 0x6045 /* Dual channel hi-speed device with PD */
|
||||
#define FTDI_FT4232HA_PID 0x6048 /* Quad channel automotive grade hi-speed device */
|
||||
#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
|
||||
#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */
|
||||
|
||||
/* Requests */
|
||||
#define FTDI_SIO_RESET 0x00 /* Reset the port */
|
||||
#define FTDI_SIO_SET_MODEM_CTRL 0x01 /* Set the modem control register */
|
||||
#define FTDI_SIO_SET_FLOW_CTRL 0x02 /* Set flow control register */
|
||||
#define FTDI_SIO_SET_BAUDRATE 0x03 /* Set baud rate */
|
||||
#define FTDI_SIO_SET_DATA 0x04 /* Set the data characteristics of the port */
|
||||
#define FTDI_SIO_GET_MODEM_STATUS 0x05
|
||||
#define FTDI_SIO_SET_EVENT_CHAR 0x06
|
||||
#define FTDI_SIO_SET_ERROR_CHAR 0x07
|
||||
#define FTDI_SIO_SET_LATENCY_TIMER 0x09
|
||||
#define FTDI_SIO_GET_LATENCY_TIMER 0x0A
|
||||
#define FTDI_SIO_SET_BITMODE 0x0B
|
||||
#define FTDI_SIO_READ_PINS 0x0C
|
||||
#define FTDI_SIO_READ_EEPROM 0x90
|
||||
#define FTDI_SIO_WRITE_EEPROM 0x91
|
||||
#define FTDI_SIO_ERASE_EEPROM 0x92
|
||||
|
||||
/* Channel indices for FT2232, FT2232H and FT4232H devices */
|
||||
#define FTDI_SIO_CHANNEL_A 1
|
||||
#define FTDI_SIO_CHANNEL_B 2
|
||||
#define FTDI_SIO_CHANNEL_C 3
|
||||
#define FTDI_SIO_CHANNEL_D 4
|
||||
|
||||
/*
|
||||
* BmRequestType: 0100 0000B
|
||||
* bRequest: FTDI_SIO_RESET
|
||||
* wValue: Control Value
|
||||
* 0 = Reset SIO
|
||||
* 1 = Purge RX buffer
|
||||
* 2 = Purge TX buffer
|
||||
* wIndex: Port
|
||||
* wLength: 0
|
||||
* Data: None
|
||||
*
|
||||
* The Reset SIO command has this effect:
|
||||
*
|
||||
* Sets flow control set to 'none'
|
||||
* Event char = $0D
|
||||
* Event trigger = disabled
|
||||
* Purge RX buffer
|
||||
* Purge TX buffer
|
||||
* Clear DTR
|
||||
* Clear RTS
|
||||
* baud and data format not reset
|
||||
*
|
||||
* The Purge RX and TX buffer commands affect nothing except the buffers
|
||||
*
|
||||
*/
|
||||
|
||||
#define FTDI_SIO_RESET_SIO 0
|
||||
#define FTDI_SIO_RESET_PURGE_RX 1
|
||||
#define FTDI_SIO_RESET_PURGE_TX 2
|
||||
|
||||
/*
|
||||
* BmRequestType: 0100 0000B
|
||||
* bRequest: FTDI_SIO_SET_BAUDRATE
|
||||
* wValue: BaudDivisor value - see below
|
||||
* wIndex: Port
|
||||
* wLength: 0
|
||||
* Data: None
|
||||
* The BaudDivisor values are calculated as follows:
|
||||
* - BaseClock is either 12000000 or 48000000 depending on the device.
|
||||
* FIXME: I wish I knew how to detect old chips to select proper base clock!
|
||||
* - BaudDivisor is a fixed point number encoded in a funny way.
|
||||
* (--WRONG WAY OF THINKING--)
|
||||
* BaudDivisor is a fixed point number encoded with following bit weighs:
|
||||
* (-2)(-1)(13..0). It is a radical with a denominator of 4, so values
|
||||
* end with 0.0 (00...), 0.25 (10...), 0.5 (01...), and 0.75 (11...).
|
||||
* (--THE REALITY--)
|
||||
* The both-bits-set has quite different meaning from 0.75 - the chip
|
||||
* designers have decided it to mean 0.125 instead of 0.75.
|
||||
* This info looked up in FTDI application note "FT8U232 DEVICES \ Data Rates
|
||||
* and Flow Control Consideration for USB to RS232".
|
||||
* - BaudDivisor = (BaseClock / 16) / BaudRate, where the (=) operation should
|
||||
* automagically re-encode the resulting value to take fractions into
|
||||
* consideration.
|
||||
* As all values are integers, some bit twiddling is in order:
|
||||
* BaudDivisor = (BaseClock / 16 / BaudRate) |
|
||||
* (((BaseClock / 2 / BaudRate) & 4) ? 0x4000 // 0.5
|
||||
* : ((BaseClock / 2 / BaudRate) & 2) ? 0x8000 // 0.25
|
||||
* : ((BaseClock / 2 / BaudRate) & 1) ? 0xc000 // 0.125
|
||||
* : 0)
|
||||
*
|
||||
* For the FT232BM, a 17th divisor bit was introduced to encode the multiples
|
||||
* of 0.125 missing from the FT8U232AM. Bits 16 to 14 are coded as follows
|
||||
* (the first four codes are the same as for the FT8U232AM, where bit 16 is
|
||||
* always 0):
|
||||
* 000 - add .000 to divisor
|
||||
* 001 - add .500 to divisor
|
||||
* 010 - add .250 to divisor
|
||||
* 011 - add .125 to divisor
|
||||
* 100 - add .375 to divisor
|
||||
* 101 - add .625 to divisor
|
||||
* 110 - add .750 to divisor
|
||||
* 111 - add .875 to divisor
|
||||
* Bits 15 to 0 of the 17-bit divisor are placed in the urb value. Bit 16 is
|
||||
* placed in bit 0 of the urb index.
|
||||
*
|
||||
* Note that there are a couple of special cases to support the highest baud
|
||||
* rates. If the calculated divisor value is 1, this needs to be replaced with
|
||||
* 0. Additionally for the FT232BM, if the calculated divisor value is 0x4001
|
||||
* (1.5), this needs to be replaced with 0x0001 (1) (but this divisor value is
|
||||
* not supported by the FT8U232AM).
|
||||
*/
|
||||
|
||||
enum ftdi_sio_baudrate {
|
||||
ftdi_sio_b300 = 0,
|
||||
ftdi_sio_b600 = 1,
|
||||
ftdi_sio_b1200 = 2,
|
||||
ftdi_sio_b2400 = 3,
|
||||
ftdi_sio_b4800 = 4,
|
||||
ftdi_sio_b9600 = 5,
|
||||
ftdi_sio_b19200 = 6,
|
||||
ftdi_sio_b38400 = 7,
|
||||
ftdi_sio_b57600 = 8,
|
||||
ftdi_sio_b115200 = 9
|
||||
};
|
||||
|
||||
/*
|
||||
* BmRequestType: 0100 0000B
|
||||
* bRequest: FTDI_SIO_SET_DATA
|
||||
* wValue: Data characteristics (see below)
|
||||
* wIndex: Port
|
||||
* wLength: 0
|
||||
* Data: No
|
||||
*
|
||||
* Data characteristics
|
||||
*
|
||||
* B0..7 Number of data bits
|
||||
* B8..10 Parity
|
||||
* 0 = None
|
||||
* 1 = Odd
|
||||
* 2 = Even
|
||||
* 3 = Mark
|
||||
* 4 = Space
|
||||
* B11..13 Stop Bits
|
||||
* 0 = 1
|
||||
* 1 = 1.5
|
||||
* 2 = 2
|
||||
* B14
|
||||
* 1 = TX ON (break)
|
||||
* 0 = TX OFF (normal state)
|
||||
* B15 Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8)
|
||||
#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8)
|
||||
#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8)
|
||||
#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8)
|
||||
#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8)
|
||||
#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11)
|
||||
#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11)
|
||||
#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11)
|
||||
#define FTDI_SIO_SET_BREAK (0x1 << 14)
|
||||
|
||||
/*
|
||||
* BmRequestType: 0100 0000B
|
||||
* bRequest: FTDI_SIO_MODEM_CTRL
|
||||
* wValue: ControlValue (see below)
|
||||
* wIndex: Port
|
||||
* wLength: 0
|
||||
* Data: None
|
||||
*
|
||||
* NOTE: If the device is in RTS/CTS flow control, the RTS set by this
|
||||
* command will be IGNORED without an error being returned
|
||||
* Also - you can not set DTR and RTS with one control message
|
||||
*
|
||||
* ControlValue
|
||||
* B0 DTR state
|
||||
* 0 = reset
|
||||
* 1 = set
|
||||
* B1 RTS state
|
||||
* 0 = reset
|
||||
* 1 = set
|
||||
* B2..7 Reserved
|
||||
* B8 DTR state enable
|
||||
* 0 = ignore
|
||||
* 1 = use DTR state
|
||||
* B9 RTS state enable
|
||||
* 0 = ignore
|
||||
* 1 = use RTS state
|
||||
* B10..15 Reserved
|
||||
*
|
||||
*/
|
||||
|
||||
#define FTDI_SIO_SET_DTR_MASK 0x1
|
||||
#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1)
|
||||
#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0)
|
||||
#define FTDI_SIO_SET_RTS_MASK 0x2
|
||||
#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2)
|
||||
#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0)
|
||||
|
||||
/*
|
||||
* BmRequestType: 0100 0000b
|
||||
* bRequest: FTDI_SIO_SET_FLOW_CTRL
|
||||
* wValue: Xoff/Xon
|
||||
* wIndex: Protocol/Port - hIndex is protocol / lIndex is port
|
||||
* wLength: 0
|
||||
* Data: None
|
||||
*
|
||||
* hIndex protocol is:
|
||||
* B0 Output handshaking using RTS/CTS
|
||||
* 0 = disabled
|
||||
* 1 = enabled
|
||||
* B1 Output handshaking using DTR/DSR
|
||||
* 0 = disabled
|
||||
* 1 = enabled
|
||||
* B2 Xon/Xoff handshaking
|
||||
* 0 = disabled
|
||||
* 1 = enabled
|
||||
*
|
||||
* A value of zero in the hIndex field disables handshaking
|
||||
*
|
||||
* If Xon/Xoff handshaking is specified, the hValue field should contain the
|
||||
* XOFF character and the lValue field contains the XON character.
|
||||
*/
|
||||
|
||||
#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
|
||||
#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
|
||||
#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
|
||||
#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
|
||||
|
||||
/*
|
||||
* BmRequestType: 1100 0000b
|
||||
* bRequest: FTDI_SIO_GET_MODEM_STATUS
|
||||
* wValue: zero
|
||||
* wIndex: Port
|
||||
* wLength: 1
|
||||
* Data: Status
|
||||
*
|
||||
* One byte of data is returned
|
||||
* B0..3 0
|
||||
* B4 CTS
|
||||
* 0 = inactive
|
||||
* 1 = active
|
||||
* B5 DSR
|
||||
* 0 = inactive
|
||||
* 1 = active
|
||||
* B6 Ring Indicator (RI)
|
||||
* 0 = inactive
|
||||
* 1 = active
|
||||
* B7 Receive Line Signal Detect (RLSD)
|
||||
* 0 = inactive
|
||||
* 1 = active
|
||||
*/
|
||||
|
||||
#define FTDI_SIO_CTS_MASK 0x10
|
||||
#define FTDI_SIO_DSR_MASK 0x20
|
||||
#define FTDI_SIO_RI_MASK 0x40
|
||||
#define FTDI_SIO_RLSD_MASK 0x80
|
||||
|
||||
/* Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST */
|
||||
#define FTDI_SIO_BITMODE_RESET 0x00
|
||||
#define FTDI_SIO_BITMODE_CBUS 0x20
|
||||
|
||||
/*
|
||||
* IN Endpoint
|
||||
*
|
||||
* The device reserves the first two bytes of data on this endpoint to contain
|
||||
* the current values of the modem and line status registers. In the absence of
|
||||
* data, the device generates a message consisting of these two status bytes
|
||||
* every 40 ms
|
||||
*
|
||||
* Byte 0: Modem Status
|
||||
*
|
||||
* Offset Description
|
||||
* B0 Reserved - must be 1
|
||||
* B1 Reserved - must be 0
|
||||
* B2 Reserved - must be 0
|
||||
* B3 Reserved - must be 0
|
||||
* B4 Clear to Send (CTS)
|
||||
* B5 Data Set Ready (DSR)
|
||||
* B6 Ring Indicator (RI)
|
||||
* B7 Receive Line Signal Detect (RLSD)
|
||||
*
|
||||
* Byte 1: Line Status
|
||||
*
|
||||
* Offset Description
|
||||
* B0 Data Ready (DR)
|
||||
* B1 Overrun Error (OE)
|
||||
* B2 Parity Error (PE)
|
||||
* B3 Framing Error (FE)
|
||||
* B4 Break Interrupt (BI)
|
||||
* B5 Transmitter Holding Register (THRE)
|
||||
* B6 Transmitter Empty (TEMT)
|
||||
* B7 Error in RCVR FIFO
|
||||
*
|
||||
*/
|
||||
#define FTDI_RS0_CTS (1 << 4)
|
||||
#define FTDI_RS0_DSR (1 << 5)
|
||||
#define FTDI_RS0_RI (1 << 6)
|
||||
#define FTDI_RS0_RLSD (1 << 7)
|
||||
|
||||
#define FTDI_RS_DR 1
|
||||
#define FTDI_RS_OE (1 << 1)
|
||||
#define FTDI_RS_PE (1 << 2)
|
||||
#define FTDI_RS_FE (1 << 3)
|
||||
#define FTDI_RS_BI (1 << 4)
|
||||
#define FTDI_RS_THRE (1 << 5)
|
||||
#define FTDI_RS_TEMT (1 << 6)
|
||||
#define FTDI_RS_FIFO (1 << 7)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_FTDI_H */
|
||||
131
components/drivers/usb/cherryusb/class/serial/usbh_gsm.c
Normal file
131
components/drivers/usb/cherryusb/class/serial/usbh_gsm.c
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_serial.h"
|
||||
|
||||
#undef USB_DBG_TAG
|
||||
#define USB_DBG_TAG "usbh_gsm"
|
||||
#include "usb_log.h"
|
||||
|
||||
struct usbh_gsm {
|
||||
struct usb_endpoint_descriptor *intin;
|
||||
struct usbh_urb intin_urb;
|
||||
struct usb_osal_timer *modem_timer;
|
||||
uint16_t modem_status;
|
||||
};
|
||||
|
||||
static int usbh_gsm_attach(struct usbh_serial *serial)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
|
||||
struct usbh_gsm *gsm_class = usb_osal_malloc(sizeof(struct usbh_gsm));
|
||||
if (!gsm_class) {
|
||||
USB_LOG_ERR("No memory for gsm_class\r\n");
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
memset(gsm_class, 0, sizeof(struct usbh_gsm));
|
||||
serial->priv = gsm_class;
|
||||
|
||||
for (uint8_t i = 0; i < serial->hport->config.intf[serial->intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
||||
ep_desc = &serial->hport->config.intf[serial->intf].altsetting[0].ep[i].ep_desc;
|
||||
|
||||
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
|
||||
if (ep_desc->bEndpointAddress & 0x80) {
|
||||
USBH_EP_INIT(gsm_class->intin, ep_desc);
|
||||
break;
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!gsm_class->intin) {
|
||||
USB_LOG_WRN("Do not find interrupt endpoint, so disable modem status monitor\r\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usbh_gsm_detach(struct usbh_serial *serial)
|
||||
{
|
||||
struct usbh_gsm *gsm_class;
|
||||
|
||||
if (!serial || !serial->priv) {
|
||||
return;
|
||||
}
|
||||
|
||||
gsm_class = (struct usbh_gsm *)serial->priv;
|
||||
if (gsm_class->intin) {
|
||||
usbh_kill_urb(&gsm_class->intin_urb);
|
||||
}
|
||||
serial->priv = NULL;
|
||||
usb_osal_free(gsm_class);
|
||||
}
|
||||
|
||||
static int usbh_gsm_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbh_gsm_set_line_state(struct usbh_serial *serial, bool dtr, bool rts)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct usbh_serial_driver gsm_driver = {
|
||||
.driver_name = "gsm",
|
||||
|
||||
.ignore_rx_header = 0,
|
||||
.ignore_tx_header = 0,
|
||||
|
||||
.attach = usbh_gsm_attach,
|
||||
.detach = usbh_gsm_detach,
|
||||
.set_flow_control = NULL,
|
||||
.set_line_coding = usbh_gsm_set_line_coding,
|
||||
.get_line_coding = NULL,
|
||||
.set_line_state = usbh_gsm_set_line_state,
|
||||
.get_modem_status = NULL,
|
||||
};
|
||||
|
||||
static int usbh_gsm_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
return usbh_serial_probe(hport, intf, &gsm_driver) ? 0 : -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
static int usbh_gsm_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usbh_serial *serial = (struct usbh_serial *)hport->config.intf[intf].priv;
|
||||
|
||||
if (serial) {
|
||||
usbh_serial_remove(serial);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct usbh_class_driver gsm_class_driver = {
|
||||
.driver_name = "gsm",
|
||||
.connect = usbh_gsm_connect,
|
||||
.disconnect = usbh_gsm_disconnect
|
||||
};
|
||||
|
||||
static const uint16_t gsm_id_table[][2] = {
|
||||
{ 0x2C7C, 0x0120 }, /* Quectel EC20 */
|
||||
{ 0x2C7C, 0x0121 }, /* Quectel EC21 */
|
||||
{ 0x2C7C, 0x0125 }, /* Quectel EC25 */
|
||||
{ 0x2C7C, 0x0191 }, /* Quectel EG91 */
|
||||
{ 0x2C7C, 0x0195 }, /* Quectel EG95 */
|
||||
{ 0x2C7C, 0x6002 }, /* Quectel EC200/EC600/EC800/EG91x */
|
||||
{ 0x1E0E, 0x9001 }, /* SIMCOM SIM7600 */
|
||||
{ 0x2ECC, 0x3012 }, /* Chinamobile ML307R */
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
CLASS_INFO_DEFINE const struct usbh_class_info gsm_class_info = {
|
||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
||||
.bInterfaceClass = 0xff,
|
||||
.bInterfaceSubClass = 0x00,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.id_table = gsm_id_table,
|
||||
.class_driver = &gsm_class_driver
|
||||
};
|
||||
726
components/drivers/usb/cherryusb/class/serial/usbh_pl2303.c
Normal file
726
components/drivers/usb/cherryusb/class/serial/usbh_pl2303.c
Normal file
File diff suppressed because it is too large
Load Diff
43
components/drivers/usb/cherryusb/class/serial/usbh_pl2303.h
Normal file
43
components/drivers/usb/cherryusb/class/serial/usbh_pl2303.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ~ 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBH_PL2303_H
|
||||
#define USBH_PL2303_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
|
||||
#define PL2303_VENDOR_WRITE_REQUEST 0x01
|
||||
#define PL2303_VENDOR_WRITE_NREQUEST 0x80
|
||||
#define PL2303_VENDOR_READ_REQUEST 0x01
|
||||
#define PL2303_VENDOR_READ_NREQUEST 0x81
|
||||
|
||||
#define PL2303_FLOWCTRL_MASK 0xf0
|
||||
|
||||
#define PL2303_READ_TYPE_HX_STATUS 0x8080
|
||||
|
||||
#define PL2303_HXN_RESET_REG 0x07
|
||||
#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02
|
||||
#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01
|
||||
|
||||
#define PL2303_HXN_FLOWCTRL_REG 0x0a
|
||||
#define PL2303_HXN_FLOWCTRL_MASK 0x1c
|
||||
#define PL2303_HXN_FLOWCTRL_NONE 0x1c
|
||||
#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18
|
||||
#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c
|
||||
|
||||
#define PL2303_QUIRK_UART_STATE_IDX0 BIT(0)
|
||||
#define PL2303_QUIRK_LEGACY BIT(1)
|
||||
#define PL2303_QUIRK_ENDPOINT_HACK BIT(2)
|
||||
#define PL2303_QUIRK_NO_BREAK_GETLINE BIT(3)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_PL2303_H */
|
||||
743
components/drivers/usb/cherryusb/class/serial/usbh_serial.c
Normal file
743
components/drivers/usb/cherryusb/class/serial/usbh_serial.c
Normal file
File diff suppressed because it is too large
Load Diff
182
components/drivers/usb/cherryusb/class/serial/usbh_serial.h
Normal file
182
components/drivers/usb/cherryusb/class/serial/usbh_serial.h
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) 2025, sakumisu
|
||||
* Copyright (c) 2025, MDLZCOOL
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBH_SERIAL_H
|
||||
#define USBH_SERIAL_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
|
||||
#define USBH_SERIAL_CTRL_NOCACHE_OFFSET 0
|
||||
#define USBH_SERIAL_CTRL_NOCACHE_SIZE 32
|
||||
#define USBH_SERIAL_INT_NOCACHE_OFFSET USB_ALIGN_UP(USBH_SERIAL_CTRL_NOCACHE_SIZE, CONFIG_USB_ALIGN_SIZE)
|
||||
#define USBH_SERIAL_INT_NOCACHE_SIZE 32
|
||||
#define USBH_SERIAL_RX_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_INT_NOCACHE_OFFSET + USBH_SERIAL_INT_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)
|
||||
#define USBH_SERIAL_RX_NOCACHE_SIZE 512
|
||||
#define USBH_SERIAL_RX2_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_RX_NOCACHE_OFFSET + USBH_SERIAL_RX_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)
|
||||
#define USBH_SERIAL_RX2_NOCACHE_SIZE 512
|
||||
|
||||
#define USBH_SERIAL_DATABITS_5 5
|
||||
#define USBH_SERIAL_DATABITS_6 6
|
||||
#define USBH_SERIAL_DATABITS_7 7
|
||||
#define USBH_SERIAL_DATABITS_8 8
|
||||
|
||||
#define USBH_SERIAL_PARITY_NONE 0
|
||||
#define USBH_SERIAL_PARITY_ODD 1
|
||||
#define USBH_SERIAL_PARITY_EVEN 2
|
||||
#define USBH_SERIAL_PARITY_MARK 3
|
||||
#define USBH_SERIAL_PARITY_SPACE 4
|
||||
|
||||
#define USBH_SERIAL_STOPBITS_1 0
|
||||
#define USBH_SERIAL_STOPBITS_1_5 1
|
||||
#define USBH_SERIAL_STOPBITS_2 2
|
||||
|
||||
/* modem lines */
|
||||
#define USBH_SERIAL_TIOCM_LE 0x001 /* line enable */
|
||||
#define USBH_SERIAL_TIOCM_DTR 0x002 /* data terminal ready */
|
||||
#define USBH_SERIAL_TIOCM_RTS 0x004 /* request to send */
|
||||
#define USBH_SERIAL_TIOCM_ST 0x010 /* secondary transmit */
|
||||
#define USBH_SERIAL_TIOCM_SR 0x020 /* secondary receive */
|
||||
#define USBH_SERIAL_TIOCM_CTS 0x040 /* clear to send */
|
||||
#define USBH_SERIAL_TIOCM_CAR 0x100 /* carrier detect */
|
||||
#define USBH_SERIAL_TIOCM_CD USBH_SERIAL_TIOCM_CAR
|
||||
#define USBH_SERIAL_TIOCM_RNG 0x200 /* ring */
|
||||
#define USBH_SERIAL_TIOCM_RI USBH_SERIAL_TIOCM_RNG
|
||||
#define USBH_SERIAL_TIOCM_DSR 0x400 /* data set ready */
|
||||
#define USBH_SERIAL_TIOCM_OUT1 0x2000
|
||||
#define USBH_SERIAL_TIOCM_OUT2 0x4000
|
||||
#define USBH_SERIAL_TIOCM_LOOP 0x8000
|
||||
|
||||
#define USBH_SERIAL_O_RDONLY 0x0000 /* open for reading only */
|
||||
#define USBH_SERIAL_O_WRONLY 0x0001 /* open for writing only */
|
||||
#define USBH_SERIAL_O_RDWR 0x0002 /* open for reading and writing */
|
||||
|
||||
#define USBH_SERIAL_O_ACCMODE 0x0003 /* mask for above modes, from 4.4BSD https://minnie.tuhs.org/cgi-bin/utree.pl?file=4.4BSD/usr/include/sys/fcntl.h */
|
||||
#define USBH_SERIAL_O_NONBLOCK 0x0004 /* non-blocking I/O, from BSD apple https://opensource.apple.com/source/xnu/xnu-1228.0.2/bsd/sys/fcntl.h */
|
||||
|
||||
#define USBH_SERIAL_CMD_SET_ATTR 0
|
||||
#define USBH_SERIAL_CMD_GET_ATTR 1
|
||||
#define USBH_SERIAL_CMD_IOCMBIS 2
|
||||
#define USBH_SERIAL_CMD_IOCMBIC 3
|
||||
#define USBH_SERIAL_CMD_TIOCMSET 4
|
||||
#define USBH_SERIAL_CMD_TIOCMGET 5
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t in; /*!< Define the write pointer. */
|
||||
uint32_t out; /*!< Define the read pointer. */
|
||||
uint32_t mask; /*!< Define the write and read pointer mask. */
|
||||
void *pool; /*!< Define the memory pointer. */
|
||||
} usbh_serial_ringbuf_t;
|
||||
|
||||
/*
|
||||
* Counters of the input lines (CTS, DSR, RI, CD) interrupts
|
||||
*/
|
||||
|
||||
struct usbh_serial_async_icount {
|
||||
uint32_t cts, dsr, rng, dcd, tx, rx;
|
||||
uint32_t frame, parity, overrun, brk;
|
||||
uint32_t buf_overrun;
|
||||
};
|
||||
|
||||
struct usbh_serial_termios {
|
||||
uint32_t baudrate;
|
||||
uint8_t databits;
|
||||
uint8_t parity;
|
||||
uint8_t stopbits;
|
||||
bool rtscts; /* hardware flow control */
|
||||
uint32_t rx_timeout;
|
||||
};
|
||||
|
||||
struct usbh_serial;
|
||||
|
||||
typedef void (*usbh_serial_rx_complete_callback_t)(struct usbh_serial *serial, int nbytes);
|
||||
|
||||
/**
|
||||
* @brief Serial Driver Operations
|
||||
*/
|
||||
struct usbh_serial_driver {
|
||||
const char *driver_name;
|
||||
|
||||
uint8_t ignore_tx_header;
|
||||
uint8_t ignore_rx_header;
|
||||
|
||||
int (*attach)(struct usbh_serial *serial);
|
||||
void (*detach)(struct usbh_serial *serial);
|
||||
|
||||
int (*open)(struct usbh_serial *serial);
|
||||
void (*close)(struct usbh_serial *serial);
|
||||
int (*set_flow_control)(struct usbh_serial *serial, bool enable);
|
||||
int (*set_line_coding)(struct usbh_serial *serial, struct cdc_line_coding *line_coding);
|
||||
int (*get_line_coding)(struct usbh_serial *serial, struct cdc_line_coding *line_coding);
|
||||
int (*set_line_state)(struct usbh_serial *serial, bool dtr, bool rts);
|
||||
int (*get_modem_status)(struct usbh_serial *serial);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Serial Instance
|
||||
*/
|
||||
struct usbh_serial {
|
||||
struct usbh_hubport *hport;
|
||||
uint8_t intf; /* Interface Number */
|
||||
int minor; /* Serial Port Number (/dev/ttyUSBx or /dev/ttyACMx) */
|
||||
int cdc_minor; /* Serial Port Number (/dev/ttyACMx) */
|
||||
uint8_t *iobuffer; /* I/O buffer for serial transfers */
|
||||
uint8_t ref_count; /* Reference Count */
|
||||
uint32_t open_flags;
|
||||
uint32_t rx_timeout_ms;
|
||||
|
||||
struct cdc_line_coding line_coding;
|
||||
uint16_t line_state;
|
||||
bool rtscts; /* hardware flow control */
|
||||
struct usbh_serial_async_icount iocount;
|
||||
|
||||
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
|
||||
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
|
||||
struct usbh_urb bulkout_urb;
|
||||
struct usbh_urb bulkin_urb;
|
||||
|
||||
const struct usbh_serial_driver *driver;
|
||||
|
||||
usbh_serial_ringbuf_t rx_rb;
|
||||
uint8_t rx_rb_pool[CONFIG_USBHOST_SERIAL_RX_SIZE];
|
||||
usb_osal_sem_t rx_complete_sem;
|
||||
uint8_t rx_buf_index;
|
||||
int rx_errorcode;
|
||||
usbh_serial_rx_complete_callback_t rx_complete_callback;
|
||||
|
||||
void *priv; /* Private Data */
|
||||
void *user_data; /* User Data */
|
||||
};
|
||||
|
||||
/* internal api */
|
||||
struct usbh_serial *usbh_serial_probe(struct usbh_hubport *hport, uint8_t intf, const struct usbh_serial_driver *driver);
|
||||
void usbh_serial_remove(struct usbh_serial *serial);
|
||||
|
||||
/* public api */
|
||||
struct usbh_serial *usbh_serial_open(const char *devname, uint32_t open_flags);
|
||||
int usbh_serial_close(struct usbh_serial *serial);
|
||||
int usbh_serial_control(struct usbh_serial *serial, int cmd, void *arg);
|
||||
int usbh_serial_write(struct usbh_serial *serial, const void *buffer, uint32_t buflen);
|
||||
int usbh_serial_read(struct usbh_serial *serial, void *buffer, uint32_t buflen);
|
||||
|
||||
/* cdc only api */
|
||||
int usbh_serial_cdc_write_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg);
|
||||
int usbh_serial_cdc_read_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg);
|
||||
|
||||
/* public weak api */
|
||||
void usbh_serial_run(struct usbh_serial *serial);
|
||||
void usbh_serial_stop(struct usbh_serial *serial);
|
||||
|
||||
int usbh_serial(int argc, char **argv);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_SERIAL_H */
|
||||
@@ -795,16 +795,6 @@ int usbh_asix_eth_output(uint32_t buflen)
|
||||
return usbh_submit_urb(&g_asix_class.bulkout_urb);
|
||||
}
|
||||
|
||||
__WEAK void usbh_asix_run(struct usbh_asix *asix_class)
|
||||
{
|
||||
(void)asix_class;
|
||||
}
|
||||
|
||||
__WEAK void usbh_asix_stop(struct usbh_asix *asix_class)
|
||||
{
|
||||
(void)asix_class;
|
||||
}
|
||||
|
||||
static const uint16_t asix_id_table[][2] = {
|
||||
{ 0x0B95, 0x772B },
|
||||
{ 0x0B95, 0x7720 },
|
||||
|
||||
@@ -1034,17 +1034,17 @@ static int generic_ocp_read(struct usbh_rtl8152 *tp, uint16_t index, uint16_t si
|
||||
static int generic_ocp_write(struct usbh_rtl8152 *tp, uint16_t index, uint16_t byteen,
|
||||
uint16_t size, void *data, uint16_t type)
|
||||
{
|
||||
int ret;
|
||||
int ret = -USB_ERR_INVAL;
|
||||
uint16_t byteen_start, byteen_end, byen;
|
||||
uint16_t limit = 512;
|
||||
uint8_t *buf = data;
|
||||
|
||||
/* both size and indix must be 4 bytes align */
|
||||
if ((size & 3) || !size || (index & 3) || !buf)
|
||||
return -USB_ERR_INVAL;
|
||||
return ret;
|
||||
|
||||
if ((uint32_t)index + (uint32_t)size > 0xffff)
|
||||
return -USB_ERR_INVAL;
|
||||
return ret;
|
||||
|
||||
byteen_start = byteen & BYTE_EN_START_MASK;
|
||||
byteen_end = byteen & BYTE_EN_END_MASK;
|
||||
@@ -1596,8 +1596,8 @@ static void r8153_teredo_off(struct usbh_rtl8152 *tp)
|
||||
case RTL_VER_15:
|
||||
default:
|
||||
/* The bit 0 ~ 7 are relative with teredo settings. They are
|
||||
* W1C (write 1 to clear), so set all 1 to disable it.
|
||||
*/
|
||||
* W1C (write 1 to clear), so set all 1 to disable it.
|
||||
*/
|
||||
ocp_write_byte(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, 0xff);
|
||||
break;
|
||||
}
|
||||
@@ -2251,16 +2251,6 @@ int usbh_rtl8152_eth_output(uint32_t buflen)
|
||||
return usbh_submit_urb(&g_rtl8152_class.bulkout_urb);
|
||||
}
|
||||
|
||||
__WEAK void usbh_rtl8152_run(struct usbh_rtl8152 *rtl8152_class)
|
||||
{
|
||||
(void)rtl8152_class;
|
||||
}
|
||||
|
||||
__WEAK void usbh_rtl8152_stop(struct usbh_rtl8152 *rtl8152_class)
|
||||
{
|
||||
(void)rtl8152_class;
|
||||
}
|
||||
|
||||
static const uint16_t rtl_id_table[][2] = {
|
||||
{ 0x0BDA, 0x8152 },
|
||||
{ 0, 0 },
|
||||
|
||||
@@ -1,379 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_ch34x.h"
|
||||
|
||||
#define DEV_FORMAT "/dev/ttyUSB%d"
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_ch34x_buf[USB_ALIGN_UP(64, CONFIG_USB_ALIGN_SIZE)];
|
||||
|
||||
#define CONFIG_USBHOST_MAX_CP210X_CLASS 1
|
||||
|
||||
static struct usbh_ch34x g_ch34x_class[CONFIG_USBHOST_MAX_CP210X_CLASS];
|
||||
static uint32_t g_devinuse = 0;
|
||||
|
||||
static struct usbh_ch34x *usbh_ch34x_class_alloc(void)
|
||||
{
|
||||
uint8_t devno;
|
||||
|
||||
for (devno = 0; devno < CONFIG_USBHOST_MAX_CP210X_CLASS; devno++) {
|
||||
if ((g_devinuse & (1U << devno)) == 0) {
|
||||
g_devinuse |= (1U << devno);
|
||||
memset(&g_ch34x_class[devno], 0, sizeof(struct usbh_ch34x));
|
||||
g_ch34x_class[devno].minor = devno;
|
||||
return &g_ch34x_class[devno];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void usbh_ch34x_class_free(struct usbh_ch34x *ch34x_class)
|
||||
{
|
||||
uint8_t devno = ch34x_class->minor;
|
||||
|
||||
if (devno < 32) {
|
||||
g_devinuse &= ~(1U << devno);
|
||||
}
|
||||
memset(ch34x_class, 0, sizeof(struct usbh_ch34x));
|
||||
}
|
||||
|
||||
static int usbh_ch34x_get_baudrate_div(uint32_t baudrate, uint8_t *factor, uint8_t *divisor)
|
||||
{
|
||||
uint8_t a;
|
||||
uint8_t b;
|
||||
uint32_t c;
|
||||
|
||||
switch (baudrate) {
|
||||
case 921600:
|
||||
a = 0xf3;
|
||||
b = 7;
|
||||
break;
|
||||
|
||||
case 307200:
|
||||
a = 0xd9;
|
||||
b = 7;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (baudrate > 6000000 / 255) {
|
||||
b = 3;
|
||||
c = 6000000;
|
||||
} else if (baudrate > 750000 / 255) {
|
||||
b = 2;
|
||||
c = 750000;
|
||||
} else if (baudrate > 93750 / 255) {
|
||||
b = 1;
|
||||
c = 93750;
|
||||
} else {
|
||||
b = 0;
|
||||
c = 11719;
|
||||
}
|
||||
a = (uint8_t)(c / baudrate);
|
||||
if (a == 0 || a == 0xFF) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
if ((c / a - baudrate) > (baudrate - c / (a + 1))) {
|
||||
a++;
|
||||
}
|
||||
a = (uint8_t)(256 - a);
|
||||
break;
|
||||
}
|
||||
|
||||
*factor = a;
|
||||
*divisor = b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbh_ch34x_get_version(struct usbh_ch34x *ch34x_class)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
int ret;
|
||||
|
||||
if (!ch34x_class || !ch34x_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = ch34x_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = CH34X_READ_VERSION;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = 0;
|
||||
setup->wLength = 2;
|
||||
|
||||
ret = usbh_control_transfer(ch34x_class->hport, setup, g_ch34x_buf);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
USB_LOG_INFO("Ch34x chip version %02x:%02x\r\n", g_ch34x_buf[0], g_ch34x_buf[1]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_ch34x_flow_ctrl(struct usbh_ch34x *ch34x_class)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!ch34x_class || !ch34x_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = ch34x_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = CH34X_WRITE_REG;
|
||||
setup->wValue = 0x2727;
|
||||
setup->wIndex = 0;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(ch34x_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
int usbh_ch34x_set_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
uint16_t reg_value = 0;
|
||||
uint16_t value = 0;
|
||||
uint8_t factor = 0;
|
||||
uint8_t divisor = 0;
|
||||
|
||||
if (!ch34x_class || !ch34x_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = ch34x_class->hport->setup;
|
||||
|
||||
memcpy((uint8_t *)&ch34x_class->line_coding, line_coding, sizeof(struct cdc_line_coding));
|
||||
|
||||
/* refer to https://github.com/WCHSoftGroup/ch341ser_linux/blob/main/driver/ch341.c */
|
||||
|
||||
switch (line_coding->bParityType) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
reg_value |= CH341_L_PO;
|
||||
break;
|
||||
case 2:
|
||||
reg_value |= CH341_L_PE;
|
||||
break;
|
||||
case 3:
|
||||
reg_value |= CH341_L_PM;
|
||||
break;
|
||||
case 4:
|
||||
reg_value |= CH341_L_PS;
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
switch (line_coding->bDataBits) {
|
||||
case 5:
|
||||
reg_value |= CH341_L_D5;
|
||||
break;
|
||||
case 6:
|
||||
reg_value |= CH341_L_D6;
|
||||
break;
|
||||
case 7:
|
||||
reg_value |= CH341_L_D7;
|
||||
break;
|
||||
case 8:
|
||||
reg_value |= CH341_L_D8;
|
||||
break;
|
||||
default:
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
if (line_coding->bCharFormat == 2) {
|
||||
reg_value |= CH341_L_SB;
|
||||
}
|
||||
|
||||
reg_value |= 0xC0;
|
||||
|
||||
value |= 0x9c;
|
||||
value |= reg_value << 8;
|
||||
|
||||
usbh_ch34x_get_baudrate_div(line_coding->dwDTERate, &factor, &divisor);
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = CH34X_SERIAL_INIT;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = (factor << 8) | 0x80 | divisor;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(ch34x_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
int usbh_ch34x_get_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
memcpy(line_coding, (uint8_t *)&ch34x_class->line_coding, sizeof(struct cdc_line_coding));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbh_ch34x_set_line_state(struct usbh_ch34x *ch34x_class, bool dtr, bool rts)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!ch34x_class || !ch34x_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = ch34x_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = CH34X_MODEM_CTRL;
|
||||
setup->wValue = 0x0f | (dtr << 5) | (rts << 6);
|
||||
setup->wIndex = 0;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(ch34x_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ch34x_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret = 0;
|
||||
|
||||
struct usbh_ch34x *ch34x_class = usbh_ch34x_class_alloc();
|
||||
if (ch34x_class == NULL) {
|
||||
USB_LOG_ERR("Fail to alloc ch34x_class\r\n");
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
ch34x_class->hport = hport;
|
||||
ch34x_class->intf = intf;
|
||||
|
||||
hport->config.intf[intf].priv = ch34x_class;
|
||||
|
||||
usbh_ch34x_get_version(ch34x_class);
|
||||
usbh_ch34x_flow_ctrl(ch34x_class);
|
||||
|
||||
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
||||
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
|
||||
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
|
||||
continue;
|
||||
} else {
|
||||
if (ep_desc->bEndpointAddress & 0x80) {
|
||||
USBH_EP_INIT(ch34x_class->bulkin, ep_desc);
|
||||
} else {
|
||||
USBH_EP_INIT(ch34x_class->bulkout, ep_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, ch34x_class->minor);
|
||||
|
||||
USB_LOG_INFO("Register CH34X Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
|
||||
#if 0
|
||||
USB_LOG_INFO("Test ch34x rx and tx and rx for 5 times, baudrate is 115200\r\n");
|
||||
|
||||
struct cdc_line_coding linecoding;
|
||||
uint8_t count = 5;
|
||||
|
||||
linecoding.dwDTERate = 115200;
|
||||
linecoding.bDataBits = 8;
|
||||
linecoding.bParityType = 0;
|
||||
linecoding.bCharFormat = 0;
|
||||
usbh_ch34x_set_line_coding(ch34x_class, &linecoding);
|
||||
usbh_ch34x_set_line_state(ch34x_class, true, false);
|
||||
|
||||
memset(g_ch34x_buf, 'a', sizeof(g_ch34x_buf));
|
||||
ret = usbh_ch34x_bulk_out_transfer(ch34x_class, g_ch34x_buf, sizeof(g_ch34x_buf), 0xfffffff);
|
||||
USB_LOG_RAW("out ret:%d\r\n", ret);
|
||||
while (count--) {
|
||||
ret = usbh_ch34x_bulk_in_transfer(ch34x_class, g_ch34x_buf, sizeof(g_ch34x_buf), 0xfffffff);
|
||||
USB_LOG_RAW("in ret:%d\r\n", ret);
|
||||
if (ret > 0) {
|
||||
for (uint32_t i = 0; i < ret; i++) {
|
||||
USB_LOG_RAW("%02x ", g_ch34x_buf[i]);
|
||||
}
|
||||
USB_LOG_RAW("\r\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
usbh_ch34x_run(ch34x_class);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_ch34x_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct usbh_ch34x *ch34x_class = (struct usbh_ch34x *)hport->config.intf[intf].priv;
|
||||
|
||||
if (ch34x_class) {
|
||||
if (ch34x_class->bulkin) {
|
||||
usbh_kill_urb(&ch34x_class->bulkin_urb);
|
||||
}
|
||||
|
||||
if (ch34x_class->bulkout) {
|
||||
usbh_kill_urb(&ch34x_class->bulkout_urb);
|
||||
}
|
||||
|
||||
if (hport->config.intf[intf].devname[0] != '\0') {
|
||||
usb_osal_thread_schedule_other();
|
||||
USB_LOG_INFO("Unregister CH34X Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
usbh_ch34x_stop(ch34x_class);
|
||||
}
|
||||
|
||||
usbh_ch34x_class_free(ch34x_class);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_ch34x_bulk_in_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &ch34x_class->bulkin_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, ch34x_class->hport, ch34x_class->bulkin, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_ch34x_bulk_out_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &ch34x_class->bulkout_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, ch34x_class->hport, ch34x_class->bulkout, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
__WEAK void usbh_ch34x_run(struct usbh_ch34x *ch34x_class)
|
||||
{
|
||||
(void)ch34x_class;
|
||||
}
|
||||
|
||||
__WEAK void usbh_ch34x_stop(struct usbh_ch34x *ch34x_class)
|
||||
{
|
||||
(void)ch34x_class;
|
||||
}
|
||||
|
||||
static const uint16_t ch34x_id_table[][2] = {
|
||||
{ 0x1A86, 0x7523 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
const struct usbh_class_driver ch34x_class_driver = {
|
||||
.driver_name = "ch34x",
|
||||
.connect = usbh_ch34x_connect,
|
||||
.disconnect = usbh_ch34x_disconnect
|
||||
};
|
||||
|
||||
CLASS_INFO_DEFINE const struct usbh_class_info ch34x_class_info = {
|
||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||
.bInterfaceClass = 0xff,
|
||||
.bInterfaceSubClass = 0x00,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.id_table = ch34x_id_table,
|
||||
.class_driver = &ch34x_class_driver
|
||||
};
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBH_CH34X_H
|
||||
#define USBH_CH34X_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
|
||||
/* Requests */
|
||||
#define CH34X_READ_VERSION 0x5F
|
||||
#define CH34X_WRITE_REG 0x9A
|
||||
#define CH34X_READ_REG 0x95
|
||||
#define CH34X_SERIAL_INIT 0xA1
|
||||
#define CH34X_MODEM_CTRL 0xA4
|
||||
|
||||
// modem control bits
|
||||
#define CH34X_BIT_RTS (1 << 6)
|
||||
#define CH34X_BIT_DTR (1 << 5)
|
||||
|
||||
#define CH341_CTO_O 0x10
|
||||
#define CH341_CTO_D 0x20
|
||||
#define CH341_CTO_R 0x40
|
||||
#define CH341_CTI_C 0x01
|
||||
#define CH341_CTI_DS 0x02
|
||||
#define CH341_CTRL_RI 0x04
|
||||
#define CH341_CTI_DC 0x08
|
||||
#define CH341_CTI_ST 0x0f
|
||||
|
||||
#define CH341_L_ER 0x80
|
||||
#define CH341_L_ET 0x40
|
||||
#define CH341_L_PS 0x38
|
||||
#define CH341_L_PM 0x28
|
||||
#define CH341_L_PE 0x18
|
||||
#define CH341_L_PO 0x08
|
||||
#define CH341_L_SB 0x04
|
||||
#define CH341_L_D8 0x03
|
||||
#define CH341_L_D7 0x02
|
||||
#define CH341_L_D6 0x01
|
||||
#define CH341_L_D5 0x00
|
||||
|
||||
struct usbh_ch34x {
|
||||
struct usbh_hubport *hport;
|
||||
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
|
||||
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
|
||||
struct usbh_urb bulkout_urb;
|
||||
struct usbh_urb bulkin_urb;
|
||||
|
||||
struct cdc_line_coding line_coding;
|
||||
|
||||
uint8_t intf;
|
||||
uint8_t minor;
|
||||
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int usbh_ch34x_set_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding);
|
||||
int usbh_ch34x_get_line_coding(struct usbh_ch34x *ch34x_class, struct cdc_line_coding *line_coding);
|
||||
int usbh_ch34x_set_line_state(struct usbh_ch34x *ch34x_class, bool dtr, bool rts);
|
||||
|
||||
int usbh_ch34x_bulk_in_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
|
||||
int usbh_ch34x_bulk_out_transfer(struct usbh_ch34x *ch34x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
|
||||
|
||||
void usbh_ch34x_run(struct usbh_ch34x *ch34x_class);
|
||||
void usbh_ch34x_stop(struct usbh_ch34x *ch34x_class);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_CH34X_H */
|
||||
@@ -1,328 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_cp210x.h"
|
||||
|
||||
#define DEV_FORMAT "/dev/ttyUSB%d"
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cp210x_buf[USB_ALIGN_UP(64, CONFIG_USB_ALIGN_SIZE)];
|
||||
|
||||
#define CONFIG_USBHOST_MAX_CP210X_CLASS 1
|
||||
|
||||
static struct usbh_cp210x g_cp210x_class[CONFIG_USBHOST_MAX_CP210X_CLASS];
|
||||
static uint32_t g_devinuse = 0;
|
||||
|
||||
static struct usbh_cp210x *usbh_cp210x_class_alloc(void)
|
||||
{
|
||||
uint8_t devno;
|
||||
|
||||
for (devno = 0; devno < CONFIG_USBHOST_MAX_CP210X_CLASS; devno++) {
|
||||
if ((g_devinuse & (1U << devno)) == 0) {
|
||||
g_devinuse |= (1U << devno);
|
||||
memset(&g_cp210x_class[devno], 0, sizeof(struct usbh_cp210x));
|
||||
g_cp210x_class[devno].minor = devno;
|
||||
return &g_cp210x_class[devno];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void usbh_cp210x_class_free(struct usbh_cp210x *cp210x_class)
|
||||
{
|
||||
uint8_t devno = cp210x_class->minor;
|
||||
|
||||
if (devno < 32) {
|
||||
g_devinuse &= ~(1U << devno);
|
||||
}
|
||||
memset(cp210x_class, 0, sizeof(struct usbh_cp210x));
|
||||
}
|
||||
|
||||
static int usbh_cp210x_enable(struct usbh_cp210x *cp210x_class)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!cp210x_class || !cp210x_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = cp210x_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = CP210X_IFC_ENABLE;
|
||||
setup->wValue = 1;
|
||||
setup->wIndex = cp210x_class->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(cp210x_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_cp210x_set_flow(struct usbh_cp210x *cp210x_class)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!cp210x_class || !cp210x_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = cp210x_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = CP210X_SET_FLOW;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = cp210x_class->intf;
|
||||
setup->wLength = 16;
|
||||
|
||||
memset(g_cp210x_buf, 0, 16);
|
||||
g_cp210x_buf[13] = 0x20;
|
||||
return usbh_control_transfer(cp210x_class->hport, setup, g_cp210x_buf);
|
||||
}
|
||||
|
||||
static int usbh_cp210x_set_chars(struct usbh_cp210x *cp210x_class)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!cp210x_class || !cp210x_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = cp210x_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = CP210X_SET_CHARS;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = cp210x_class->intf;
|
||||
setup->wLength = 6;
|
||||
|
||||
memset(g_cp210x_buf, 0, 6);
|
||||
g_cp210x_buf[0] = 0x80;
|
||||
g_cp210x_buf[4] = 0x88;
|
||||
g_cp210x_buf[5] = 0x28;
|
||||
return usbh_control_transfer(cp210x_class->hport, setup, g_cp210x_buf);
|
||||
}
|
||||
|
||||
static int usbh_cp210x_set_baudrate(struct usbh_cp210x *cp210x_class, uint32_t baudrate)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!cp210x_class || !cp210x_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = cp210x_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = CP210X_SET_BAUDRATE;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = cp210x_class->intf;
|
||||
setup->wLength = 4;
|
||||
|
||||
memcpy(g_cp210x_buf, (uint8_t *)&baudrate, 4);
|
||||
return usbh_control_transfer(cp210x_class->hport, setup, g_cp210x_buf);
|
||||
}
|
||||
|
||||
static int usbh_cp210x_set_data_format(struct usbh_cp210x *cp210x_class, uint8_t databits, uint8_t parity, uint8_t stopbits)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
uint16_t value;
|
||||
|
||||
if (!cp210x_class || !cp210x_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = cp210x_class->hport->setup;
|
||||
|
||||
value = ((databits & 0x0F) << 8) | ((parity & 0x0f) << 4) | ((stopbits & 0x03) << 0);
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = CP210X_SET_LINE_CTL;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = cp210x_class->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(cp210x_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_cp210x_set_mhs(struct usbh_cp210x *cp210x_class, uint8_t dtr, uint8_t rts, uint8_t dtr_mask, uint8_t rts_mask)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
uint16_t value;
|
||||
|
||||
if (!cp210x_class || !cp210x_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = cp210x_class->hport->setup;
|
||||
|
||||
value = ((dtr & 0x01) << 0) | ((rts & 0x01) << 1) | ((dtr_mask & 0x01) << 8) | ((rts_mask & 0x01) << 9);
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = CP210X_SET_MHS;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = cp210x_class->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(cp210x_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
int usbh_cp210x_set_line_coding(struct usbh_cp210x *cp210x_class, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
memcpy((uint8_t *)&cp210x_class->line_coding, line_coding, sizeof(struct cdc_line_coding));
|
||||
usbh_cp210x_set_baudrate(cp210x_class, line_coding->dwDTERate);
|
||||
return usbh_cp210x_set_data_format(cp210x_class, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat);
|
||||
}
|
||||
|
||||
int usbh_cp210x_get_line_coding(struct usbh_cp210x *cp210x_class, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
memcpy(line_coding, (uint8_t *)&cp210x_class->line_coding, sizeof(struct cdc_line_coding));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbh_cp210x_set_line_state(struct usbh_cp210x *cp210x_class, bool dtr, bool rts)
|
||||
{
|
||||
return usbh_cp210x_set_mhs(cp210x_class, dtr, rts, 1, 1);
|
||||
}
|
||||
|
||||
static int usbh_cp210x_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret = 0;
|
||||
|
||||
struct usbh_cp210x *cp210x_class = usbh_cp210x_class_alloc();
|
||||
if (cp210x_class == NULL) {
|
||||
USB_LOG_ERR("Fail to alloc cp210x_class\r\n");
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
cp210x_class->hport = hport;
|
||||
cp210x_class->intf = intf;
|
||||
|
||||
hport->config.intf[intf].priv = cp210x_class;
|
||||
|
||||
usbh_cp210x_enable(cp210x_class);
|
||||
usbh_cp210x_set_flow(cp210x_class);
|
||||
usbh_cp210x_set_chars(cp210x_class);
|
||||
|
||||
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
||||
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
|
||||
|
||||
if (ep_desc->bEndpointAddress & 0x80) {
|
||||
USBH_EP_INIT(cp210x_class->bulkin, ep_desc);
|
||||
} else {
|
||||
USBH_EP_INIT(cp210x_class->bulkout, ep_desc);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, cp210x_class->minor);
|
||||
|
||||
USB_LOG_INFO("Register CP210X Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
|
||||
#if 0
|
||||
USB_LOG_INFO("Test cp2102 rx and tx and rx for 5 times, baudrate is 115200\r\n");
|
||||
|
||||
struct cdc_line_coding linecoding;
|
||||
uint8_t count = 5;
|
||||
|
||||
linecoding.dwDTERate = 115200;
|
||||
linecoding.bDataBits = 8;
|
||||
linecoding.bParityType = 0;
|
||||
linecoding.bCharFormat = 0;
|
||||
usbh_cp210x_set_line_coding(cp210x_class, &linecoding);
|
||||
usbh_cp210x_set_line_state(cp210x_class, true, false);
|
||||
|
||||
memset(g_cp210x_buf, 'a', sizeof(g_cp210x_buf));
|
||||
ret = usbh_cp210x_bulk_out_transfer(cp210x_class, g_cp210x_buf, sizeof(g_cp210x_buf), 0xfffffff);
|
||||
USB_LOG_RAW("out ret:%d\r\n", ret);
|
||||
while (count--) {
|
||||
ret = usbh_cp210x_bulk_in_transfer(cp210x_class, g_cp210x_buf, sizeof(g_cp210x_buf), 0xfffffff);
|
||||
USB_LOG_RAW("in ret:%d\r\n", ret);
|
||||
if (ret > 0) {
|
||||
for (uint32_t i = 0; i < ret; i++) {
|
||||
USB_LOG_RAW("%02x ", g_cp210x_buf[i]);
|
||||
}
|
||||
USB_LOG_RAW("\r\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
usbh_cp210x_run(cp210x_class);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_cp210x_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct usbh_cp210x *cp210x_class = (struct usbh_cp210x *)hport->config.intf[intf].priv;
|
||||
|
||||
if (cp210x_class) {
|
||||
if (cp210x_class->bulkin) {
|
||||
usbh_kill_urb(&cp210x_class->bulkin_urb);
|
||||
}
|
||||
|
||||
if (cp210x_class->bulkout) {
|
||||
usbh_kill_urb(&cp210x_class->bulkout_urb);
|
||||
}
|
||||
|
||||
if (hport->config.intf[intf].devname[0] != '\0') {
|
||||
usb_osal_thread_schedule_other();
|
||||
USB_LOG_INFO("Unregister CP210X Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
usbh_cp210x_stop(cp210x_class);
|
||||
}
|
||||
|
||||
usbh_cp210x_class_free(cp210x_class);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_cp210x_bulk_in_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &cp210x_class->bulkin_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, cp210x_class->hport, cp210x_class->bulkin, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_cp210x_bulk_out_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &cp210x_class->bulkout_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, cp210x_class->hport, cp210x_class->bulkout, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
__WEAK void usbh_cp210x_run(struct usbh_cp210x *cp210x_class)
|
||||
{
|
||||
(void)cp210x_class;
|
||||
}
|
||||
|
||||
__WEAK void usbh_cp210x_stop(struct usbh_cp210x *cp210x_class)
|
||||
{
|
||||
(void)cp210x_class;
|
||||
}
|
||||
|
||||
static const uint16_t cp210x_id_table[][2] = {
|
||||
{ 0x10C4, 0xEA60 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
const struct usbh_class_driver cp210x_class_driver = {
|
||||
.driver_name = "cp210x",
|
||||
.connect = usbh_cp210x_connect,
|
||||
.disconnect = usbh_cp210x_disconnect
|
||||
};
|
||||
|
||||
CLASS_INFO_DEFINE const struct usbh_class_info cp210x_class_info = {
|
||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||
.bInterfaceClass = 0xff,
|
||||
.bInterfaceSubClass = 0x00,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.id_table = cp210x_id_table,
|
||||
.class_driver = &cp210x_class_driver
|
||||
};
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBH_CP210X_H
|
||||
#define USBH_CP210X_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
|
||||
/* Requests */
|
||||
#define CP210X_IFC_ENABLE 0x00
|
||||
#define CP210X_SET_BAUDDIV 0x01
|
||||
#define CP210X_GET_BAUDDIV 0x02
|
||||
#define CP210X_SET_LINE_CTL 0x03 // Set parity, data bits, stop bits
|
||||
#define CP210X_GET_LINE_CTL 0x04
|
||||
#define CP210X_SET_BREAK 0x05
|
||||
#define CP210X_IMM_CHAR 0x06
|
||||
#define CP210X_SET_MHS 0x07 // Set DTR, RTS
|
||||
#define CP210X_GET_MDMSTS 0x08
|
||||
#define CP210X_SET_XON 0x09
|
||||
#define CP210X_SET_XOFF 0x0A
|
||||
#define CP210X_SET_EVENTMASK 0x0B
|
||||
#define CP210X_GET_EVENTMASK 0x0C
|
||||
#define CP210X_SET_CHAR 0x0D
|
||||
#define CP210X_GET_CHARS 0x0E
|
||||
#define CP210X_GET_PROPS 0x0F
|
||||
#define CP210X_GET_COMM_STATUS 0x10
|
||||
#define CP210X_RESET 0x11
|
||||
#define CP210X_PURGE 0x12
|
||||
#define CP210X_SET_FLOW 0x13
|
||||
#define CP210X_GET_FLOW 0x14
|
||||
#define CP210X_EMBED_EVENTS 0x15
|
||||
#define CP210X_GET_EVENTSTATE 0x16
|
||||
#define CP210X_SET_CHARS 0x19
|
||||
#define CP210X_GET_BAUDRATE 0x1D
|
||||
#define CP210X_SET_BAUDRATE 0x1E // Set baudrate
|
||||
#define CP210X_VENDOR_SPECIFIC 0xFF
|
||||
|
||||
struct usbh_cp210x {
|
||||
struct usbh_hubport *hport;
|
||||
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
|
||||
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
|
||||
struct usbh_urb bulkout_urb;
|
||||
struct usbh_urb bulkin_urb;
|
||||
|
||||
struct cdc_line_coding line_coding;
|
||||
|
||||
uint8_t intf;
|
||||
uint8_t minor;
|
||||
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int usbh_cp210x_set_line_coding(struct usbh_cp210x *ftdi_class, struct cdc_line_coding *line_coding);
|
||||
int usbh_cp210x_get_line_coding(struct usbh_cp210x *ftdi_class, struct cdc_line_coding *line_coding);
|
||||
int usbh_cp210x_set_line_state(struct usbh_cp210x *ftdi_class, bool dtr, bool rts);
|
||||
|
||||
int usbh_cp210x_bulk_in_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
|
||||
int usbh_cp210x_bulk_out_transfer(struct usbh_cp210x *cp210x_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
|
||||
|
||||
void usbh_cp210x_run(struct usbh_cp210x *cp210x_class);
|
||||
void usbh_cp210x_stop(struct usbh_cp210x *cp210x_class);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_CP210X_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBH_FTDI_H
|
||||
#define USBH_FTDI_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
|
||||
/* Requests */
|
||||
#define SIO_RESET_REQUEST 0x00 /* Reset the port */
|
||||
#define SIO_SET_MODEM_CTRL_REQUEST 0x01 /* Set the modem control register */
|
||||
#define SIO_SET_FLOW_CTRL_REQUEST 0x02 /* Set flow control register */
|
||||
#define SIO_SET_BAUDRATE_REQUEST 0x03 /* Set baud rate */
|
||||
#define SIO_SET_DATA_REQUEST 0x04 /* Set the data characteristics of the port */
|
||||
#define SIO_POLL_MODEM_STATUS_REQUEST 0x05
|
||||
#define SIO_SET_EVENT_CHAR_REQUEST 0x06
|
||||
#define SIO_SET_ERROR_CHAR_REQUEST 0x07
|
||||
#define SIO_SET_LATENCY_TIMER_REQUEST 0x09
|
||||
#define SIO_GET_LATENCY_TIMER_REQUEST 0x0A
|
||||
#define SIO_SET_BITMODE_REQUEST 0x0B
|
||||
#define SIO_READ_PINS_REQUEST 0x0C
|
||||
#define SIO_READ_EEPROM_REQUEST 0x90
|
||||
#define SIO_WRITE_EEPROM_REQUEST 0x91
|
||||
#define SIO_ERASE_EEPROM_REQUEST 0x92
|
||||
|
||||
#define SIO_DISABLE_FLOW_CTRL 0x0
|
||||
#define SIO_RTS_CTS_HS (0x1 << 8)
|
||||
#define SIO_DTR_DSR_HS (0x2 << 8)
|
||||
#define SIO_XON_XOFF_HS (0x4 << 8)
|
||||
|
||||
#define SIO_SET_DTR_MASK 0x1
|
||||
#define SIO_SET_DTR_HIGH (1 | (SIO_SET_DTR_MASK << 8))
|
||||
#define SIO_SET_DTR_LOW (0 | (SIO_SET_DTR_MASK << 8))
|
||||
#define SIO_SET_RTS_MASK 0x2
|
||||
#define SIO_SET_RTS_HIGH (2 | (SIO_SET_RTS_MASK << 8))
|
||||
#define SIO_SET_RTS_LOW (0 | (SIO_SET_RTS_MASK << 8))
|
||||
|
||||
#define SIO_RTS_CTS_HS (0x1 << 8)
|
||||
|
||||
enum ftdi_chip_type {
|
||||
SIO,
|
||||
FT232A,
|
||||
FT232B,
|
||||
FT2232C,
|
||||
FT232R,
|
||||
FT232H,
|
||||
FT2232H,
|
||||
FT4232H,
|
||||
FT4232HA,
|
||||
FT232HP,
|
||||
FT233HP,
|
||||
FT2232HP,
|
||||
FT2233HP,
|
||||
FT4232HP,
|
||||
FT4233HP,
|
||||
FTX,
|
||||
};
|
||||
|
||||
struct usbh_ftdi {
|
||||
struct usbh_hubport *hport;
|
||||
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
|
||||
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
|
||||
struct usbh_urb bulkout_urb;
|
||||
struct usbh_urb bulkin_urb;
|
||||
|
||||
struct cdc_line_coding line_coding;
|
||||
|
||||
uint8_t intf;
|
||||
uint8_t minor;
|
||||
uint8_t modem_status[2];
|
||||
enum ftdi_chip_type chip_type;
|
||||
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int usbh_ftdi_set_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding);
|
||||
int usbh_ftdi_get_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding);
|
||||
int usbh_ftdi_set_line_state(struct usbh_ftdi *ftdi_class, bool dtr, bool rts);
|
||||
|
||||
int usbh_ftdi_bulk_in_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
|
||||
int usbh_ftdi_bulk_out_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
|
||||
|
||||
void usbh_ftdi_run(struct usbh_ftdi *ftdi_class);
|
||||
void usbh_ftdi_stop(struct usbh_ftdi *ftdi_class);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_FTDI_H */
|
||||
@@ -1,449 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
* Copyright (c) 2024, Derek Konigsberg
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_pl2303.h"
|
||||
|
||||
#undef USB_DBG_TAG
|
||||
#define USB_DBG_TAG "usbh_pl2303"
|
||||
#include "usb_log.h"
|
||||
|
||||
#define DEV_FORMAT "/dev/ttyUSB%d"
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_pl2303_buf[USB_ALIGN_UP(64, CONFIG_USB_ALIGN_SIZE)];
|
||||
|
||||
#define CONFIG_USBHOST_MAX_PL2303_CLASS 1
|
||||
|
||||
#define UT_WRITE_VENDOR_DEVICE (USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE)
|
||||
#define UT_READ_VENDOR_DEVICE (USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE)
|
||||
|
||||
static struct usbh_pl2303 g_pl2303_class[CONFIG_USBHOST_MAX_PL2303_CLASS];
|
||||
static uint32_t g_devinuse = 0;
|
||||
|
||||
static struct usbh_pl2303 *usbh_pl2303_class_alloc(void)
|
||||
{
|
||||
uint8_t devno;
|
||||
|
||||
for (devno = 0; devno < CONFIG_USBHOST_MAX_PL2303_CLASS; devno++) {
|
||||
if ((g_devinuse & (1U << devno)) == 0) {
|
||||
g_devinuse |= (1U << devno);
|
||||
memset(&g_pl2303_class[devno], 0, sizeof(struct usbh_pl2303));
|
||||
g_pl2303_class[devno].minor = devno;
|
||||
return &g_pl2303_class[devno];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void usbh_pl2303_class_free(struct usbh_pl2303 *pl2303_class)
|
||||
{
|
||||
uint8_t devno = pl2303_class->minor;
|
||||
|
||||
if (devno < 32) {
|
||||
g_devinuse &= ~(1U << devno);
|
||||
}
|
||||
memset(pl2303_class, 0, sizeof(struct usbh_pl2303));
|
||||
}
|
||||
|
||||
static int usbh_pl2303_get_chiptype(struct usbh_pl2303 *pl2303_class)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (pl2303_class->hport->device_desc.bcdDevice) {
|
||||
case 0x0300:
|
||||
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HX;
|
||||
/* or TA, that is HX with external crystal */
|
||||
break;
|
||||
case 0x0400:
|
||||
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HXD;
|
||||
/* or EA, that is HXD with ESD protection */
|
||||
/* or RA, that has internal voltage level converter that works only up to 1Mbaud (!) */
|
||||
break;
|
||||
case 0x0500:
|
||||
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HXD;
|
||||
/* in fact it's TB, that is HXD with external crystal */
|
||||
break;
|
||||
default:
|
||||
/* NOTE: I have no info about the bcdDevice for the base PL2303 (up to 1.2Mbaud,
|
||||
only fixed rates) and for PL2303SA (8-pin chip, up to 115200 baud */
|
||||
/* Determine the chip type. This algorithm is taken from Linux. */
|
||||
if (pl2303_class->hport->device_desc.bDeviceClass == 0x02) {
|
||||
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303;
|
||||
} else if (pl2303_class->hport->device_desc.bMaxPacketSize0 == 0x40) {
|
||||
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HX;
|
||||
} else {
|
||||
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* The new chip revision PL2303HXN is only compatible with the new
|
||||
* PLCOM_SET_REQUEST_PL2303HXN command. Issuing the old command
|
||||
* PLCOM_SET_REQUEST to the new chip raises an error. Thus, PL2303HX
|
||||
* and PL2303HXN can be distinguished by issuing an old-style request
|
||||
* (on a status register) to the new chip and checking the error.
|
||||
*/
|
||||
if (pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303HX) {
|
||||
struct usb_setup_packet *setup = pl2303_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = UT_READ_VENDOR_DEVICE;
|
||||
setup->bRequest = PL2303_SET_REQUEST;
|
||||
setup->wValue = PL2303_STATUS_REG_PL2303HX;
|
||||
setup->wIndex = 0;
|
||||
setup->wLength = 1;
|
||||
|
||||
ret = usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
|
||||
if (ret == -USB_ERR_STALL) {
|
||||
pl2303_class->chiptype = USBH_PL2303_TYPE_PL2303HXN;
|
||||
ret = 0;
|
||||
} else if (ret < 0) {
|
||||
USB_LOG_WRN("Error checking chip type: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
switch (pl2303_class->chiptype) {
|
||||
case USBH_PL2303_TYPE_PL2303:
|
||||
USB_LOG_INFO("chiptype = 2303\r\n");
|
||||
break;
|
||||
case USBH_PL2303_TYPE_PL2303HX:
|
||||
USB_LOG_INFO("chiptype = 2303HX/TA\r\n");
|
||||
break;
|
||||
case USBH_PL2303_TYPE_PL2303HXN:
|
||||
USB_LOG_INFO("chiptype = 2303HXN\r\n");
|
||||
break;
|
||||
case USBH_PL2303_TYPE_PL2303HXD:
|
||||
USB_LOG_INFO("chiptype = 2303HXD/TB/RA/EA\r\n");
|
||||
break;
|
||||
default:
|
||||
USB_LOG_INFO("chiptype = [%d]\r\n", pl2303_class->chiptype);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_pl2303_do(struct usbh_pl2303 *pl2303_class,
|
||||
uint8_t req_type, uint8_t request, uint16_t value, uint16_t index,
|
||||
uint16_t length)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!pl2303_class || !pl2303_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = pl2303_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = req_type;
|
||||
setup->bRequest = request;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = index;
|
||||
setup->wLength = length;
|
||||
|
||||
return usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
|
||||
}
|
||||
|
||||
int usbh_pl2303_set_line_coding(struct usbh_pl2303 *pl2303_class, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!pl2303_class || !pl2303_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = pl2303_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = CDC_REQUEST_SET_LINE_CODING;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = pl2303_class->intf;
|
||||
setup->wLength = 7;
|
||||
|
||||
memcpy(g_pl2303_buf, line_coding, sizeof(struct cdc_line_coding));
|
||||
|
||||
return usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
|
||||
}
|
||||
|
||||
int usbh_pl2303_get_line_coding(struct usbh_pl2303 *pl2303_class, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
int ret;
|
||||
|
||||
if (!pl2303_class || !pl2303_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = pl2303_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = CDC_REQUEST_GET_LINE_CODING;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = pl2303_class->intf;
|
||||
setup->wLength = 7;
|
||||
|
||||
ret = usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
memcpy(line_coding, g_pl2303_buf, sizeof(struct cdc_line_coding));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_pl2303_set_line_state(struct usbh_pl2303 *pl2303_class, bool dtr, bool rts)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!pl2303_class || !pl2303_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = pl2303_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE;
|
||||
setup->wValue = (dtr << 0) | (rts << 1);
|
||||
setup->wIndex = pl2303_class->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(pl2303_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_pl2303_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret = 0;
|
||||
|
||||
struct usbh_pl2303 *pl2303_class = usbh_pl2303_class_alloc();
|
||||
if (pl2303_class == NULL) {
|
||||
USB_LOG_ERR("Fail to alloc pl2303_class\r\n");
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
pl2303_class->hport = hport;
|
||||
pl2303_class->intf = intf;
|
||||
|
||||
hport->config.intf[intf].priv = pl2303_class;
|
||||
|
||||
do {
|
||||
ret = usbh_pl2303_get_chiptype(pl2303_class);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Startup reset sequence, if necessary for the chip type */
|
||||
if (pl2303_class->chiptype != USBH_PL2303_TYPE_PL2303HXN) {
|
||||
struct usb_setup_packet *setup = pl2303_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = UT_WRITE_VENDOR_DEVICE;
|
||||
setup->bRequest = PL2303_SET_REQUEST;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = pl2303_class->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
ret = usbh_control_transfer(pl2303_class->hport, setup, g_pl2303_buf);
|
||||
if (ret < 0) {
|
||||
USB_LOG_WRN("Initialization reset failed: %d\r\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303) {
|
||||
/* HX variants seem to lock up after a clear stall request. */
|
||||
/*
|
||||
* The FreeBSD code sets the stall flags on the in and out pipes
|
||||
* here. Have no idea exactly how to do this, or if it is necessary.
|
||||
* May just leave this code unwritten until test hardware is available.
|
||||
*/
|
||||
} else if (pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303HX || pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303HXD) {
|
||||
/* Reset upstream data pipes */
|
||||
ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 8, 0, 0);
|
||||
if (ret < 0) {
|
||||
USB_LOG_WRN("Could not reset upstream data pipes (8,0): %d\r\n", ret);
|
||||
break;
|
||||
}
|
||||
ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 9, 0, 0);
|
||||
if (ret < 0) {
|
||||
USB_LOG_WRN("Could not reset upstream data pipes (9,0): %d\r\n", ret);
|
||||
break;
|
||||
}
|
||||
} else if (pl2303_class->chiptype == USBH_PL2303_TYPE_PL2303HXN) {
|
||||
/* Reset upstream data pipes */
|
||||
ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST_PL2303HXN, 0x07, 0x03, 0);
|
||||
if (ret < 0) {
|
||||
USB_LOG_WRN("Could not reset upstream data pipes (7,3): %d\r\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Final device initialization, if necessary for the chip type */
|
||||
if (pl2303_class->chiptype != USBH_PL2303_TYPE_PL2303HXN) {
|
||||
if (usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8484, 0, 1) < 0 ||
|
||||
usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x0404, 0, 0) < 0 ||
|
||||
usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8484, 0, 1) < 0 ||
|
||||
usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8383, 0, 1) < 0 ||
|
||||
usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8484, 0, 1) < 0 ||
|
||||
usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x0404, 1, 0) < 0 ||
|
||||
usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8484, 0, 1) < 0 ||
|
||||
usbh_pl2303_do(pl2303_class, UT_READ_VENDOR_DEVICE, PL2303_SET_REQUEST, 0x8383, 0, 1) < 0 ||
|
||||
usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 0, 1, 0) < 0 ||
|
||||
usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 1, 0, 0) < 0) {
|
||||
USB_LOG_WRN("Could not complete init sequence\r\n");
|
||||
ret = -USB_ERR_INVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pl2303_class->chiptype != USBH_PL2303_TYPE_PL2303) {
|
||||
ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 2, 0x44, 0);
|
||||
} else {
|
||||
ret = usbh_pl2303_do(pl2303_class, UT_WRITE_VENDOR_DEVICE, PL2303_SET_REQUEST, 2, 0x24, 0);
|
||||
}
|
||||
if (ret < 0) {
|
||||
USB_LOG_WRN("Could not complete final init request: %d\r\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (ret < 0) {
|
||||
USB_LOG_ERR("Failed to initialize PL2303 device: %d\r\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
||||
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
|
||||
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
|
||||
continue;
|
||||
} else {
|
||||
if (ep_desc->bEndpointAddress & 0x80) {
|
||||
USBH_EP_INIT(pl2303_class->bulkin, ep_desc);
|
||||
} else {
|
||||
USBH_EP_INIT(pl2303_class->bulkout, ep_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, pl2303_class->minor);
|
||||
|
||||
USB_LOG_INFO("Register PL2303 Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
|
||||
#if 0
|
||||
USB_LOG_INFO("Test pl2303 rx and tx and rx for 5 times, baudrate is 115200\r\n");
|
||||
|
||||
struct cdc_line_coding linecoding;
|
||||
uint8_t count = 5;
|
||||
|
||||
linecoding.dwDTERate = 115200;
|
||||
linecoding.bDataBits = 8;
|
||||
linecoding.bParityType = 0;
|
||||
linecoding.bCharFormat = 0;
|
||||
usbh_pl2303_set_line_coding(pl2303_class, &linecoding);
|
||||
usbh_pl2303_set_line_state(pl2303_class, true, false);
|
||||
|
||||
memset(g_pl2303_buf, 'a', sizeof(g_pl2303_buf));
|
||||
ret = usbh_pl2303_bulk_out_transfer(pl2303_class, g_pl2303_buf, sizeof(g_pl2303_buf), 0xfffffff);
|
||||
USB_LOG_RAW("out ret:%d\r\n", ret);
|
||||
while (count--) {
|
||||
ret = usbh_pl2303_bulk_in_transfer(pl2303_class, g_pl2303_buf, sizeof(g_pl2303_buf), 0xfffffff);
|
||||
USB_LOG_RAW("in ret:%d\r\n", ret);
|
||||
if (ret > 0) {
|
||||
for (uint32_t i = 0; i < ret; i++) {
|
||||
USB_LOG_RAW("%02x ", g_pl2303_buf[i]);
|
||||
}
|
||||
}
|
||||
USB_LOG_RAW("\r\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
usbh_pl2303_run(pl2303_class);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_pl2303_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct usbh_pl2303 *pl2303_class = (struct usbh_pl2303 *)hport->config.intf[intf].priv;
|
||||
|
||||
if (pl2303_class) {
|
||||
if (pl2303_class->bulkin) {
|
||||
usbh_kill_urb(&pl2303_class->bulkin_urb);
|
||||
}
|
||||
|
||||
if (pl2303_class->bulkout) {
|
||||
usbh_kill_urb(&pl2303_class->bulkout_urb);
|
||||
}
|
||||
|
||||
if (hport->config.intf[intf].devname[0] != '\0') {
|
||||
usb_osal_thread_schedule_other();
|
||||
USB_LOG_INFO("Unregister PL2303 Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
usbh_pl2303_stop(pl2303_class);
|
||||
}
|
||||
|
||||
usbh_pl2303_class_free(pl2303_class);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_pl2303_bulk_in_transfer(struct usbh_pl2303 *pl2303_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &pl2303_class->bulkin_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, pl2303_class->hport, pl2303_class->bulkin, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_pl2303_bulk_out_transfer(struct usbh_pl2303 *pl2303_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &pl2303_class->bulkout_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, pl2303_class->hport, pl2303_class->bulkout, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
__WEAK void usbh_pl2303_run(struct usbh_pl2303 *pl2303_class)
|
||||
{
|
||||
(void)pl2303_class;
|
||||
}
|
||||
|
||||
__WEAK void usbh_pl2303_stop(struct usbh_pl2303 *pl2303_class)
|
||||
{
|
||||
(void)pl2303_class;
|
||||
}
|
||||
|
||||
static const uint16_t pl2303_id_table[][2] = {
|
||||
{ 0x067B, 0x2303 }, // PL2303 Serial (ATEN/IOGEAR UC232A)
|
||||
{ 0x067B, 0x23A3 }, // PL2303HXN Serial, type GC
|
||||
{ 0x067B, 0x23B3 }, // PL2303HXN Serial, type GB
|
||||
{ 0x067B, 0x23C3 }, // PL2303HXN Serial, type GT
|
||||
{ 0x067B, 0x23D3 }, // PL2303HXN Serial, type GL
|
||||
{ 0x067B, 0x23E3 }, // PL2303HXN Serial, type GE
|
||||
{ 0x067B, 0x23F3 }, // PL2303HXN Serial, type GS
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
const struct usbh_class_driver pl2303_class_driver = {
|
||||
.driver_name = "pl2303",
|
||||
.connect = usbh_pl2303_connect,
|
||||
.disconnect = usbh_pl2303_disconnect
|
||||
};
|
||||
|
||||
CLASS_INFO_DEFINE const struct usbh_class_info pl2303_class_info = {
|
||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||
.bInterfaceClass = 0xff,
|
||||
.bInterfaceSubClass = 0x00,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.id_table = pl2303_id_table,
|
||||
.class_driver = &pl2303_class_driver
|
||||
};
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBH_PL2303_H
|
||||
#define USBH_PL2303_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
|
||||
#define PL2303_SET_REQUEST 0x01
|
||||
#define PL2303_SET_REQUEST_PL2303HXN 0x80
|
||||
#define PL2303_SET_CRTSCTS 0x41
|
||||
#define PL2303_SET_CRTSCTS_PL2303X 0x61
|
||||
#define PL2303_SET_CRTSCTS_PL2303HXN 0xFA
|
||||
#define PL2303_CLEAR_CRTSCTS_PL2303HXN 0xFF
|
||||
#define PL2303_CRTSCTS_REG_PL2303HXN 0x0A
|
||||
#define PL2303_STATUS_REG_PL2303HX 0x8080
|
||||
|
||||
/* Different PL2303 IC types */
|
||||
#define USBH_PL2303_TYPE_UNKNOWN 0
|
||||
#define USBH_PL2303_TYPE_PL2303 1
|
||||
#define USBH_PL2303_TYPE_PL2303HX 2
|
||||
#define USBH_PL2303_TYPE_PL2303HXD 3
|
||||
#define USBH_PL2303_TYPE_PL2303HXN 4
|
||||
|
||||
struct usbh_pl2303 {
|
||||
struct usbh_hubport *hport;
|
||||
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
|
||||
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
|
||||
|
||||
struct usbh_urb bulkout_urb;
|
||||
struct usbh_urb bulkin_urb;
|
||||
|
||||
struct cdc_line_coding linecoding;
|
||||
|
||||
uint8_t intf;
|
||||
uint8_t minor;
|
||||
uint8_t chiptype;
|
||||
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int usbh_pl2303_set_line_coding(struct usbh_pl2303 *pl2303_class, struct cdc_line_coding *line_coding);
|
||||
int usbh_pl2303_get_line_coding(struct usbh_pl2303 *pl2303_class, struct cdc_line_coding *line_coding);
|
||||
int usbh_pl2303_set_line_state(struct usbh_pl2303 *pl2303_class, bool dtr, bool rts);
|
||||
|
||||
int usbh_pl2303_bulk_in_transfer(struct usbh_pl2303 *pl2303_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
|
||||
int usbh_pl2303_bulk_out_transfer(struct usbh_pl2303 *pl2303_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
|
||||
|
||||
void usbh_pl2303_run(struct usbh_pl2303 *pl2303_class);
|
||||
void usbh_pl2303_stop(struct usbh_pl2303 *pl2303_class);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_PL2303_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user