Compare commits
109 Commits
v1.5.3-rc2
...
v1.6.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76b3720445 | ||
|
|
bad94dfc67 | ||
|
|
2783329509 | ||
|
|
3181819214 | ||
|
|
12b3eca447 | ||
|
|
1a3343bc11 | ||
|
|
0c86f1f5ff | ||
|
|
e44d44f5b6 | ||
|
|
0ca521a1d0 | ||
|
|
309aa2ffd8 | ||
|
|
013f51312a | ||
|
|
2a20e074b3 | ||
|
|
1528b533cf | ||
|
|
e414833589 | ||
|
|
1de6b93045 | ||
|
|
43cf82642c | ||
|
|
8d7a98fc9d | ||
|
|
ce32f73100 | ||
|
|
44d92be013 | ||
|
|
d172c89eef | ||
|
|
9cbe4502e7 | ||
|
|
d50159638d | ||
|
|
fb6dbb442e | ||
|
|
7a2089f032 | ||
|
|
be5ba641dd | ||
|
|
7317913efa | ||
|
|
94d1c6b1be | ||
|
|
3f23af5ad7 | ||
|
|
34166b361a | ||
|
|
a5f765d46e | ||
|
|
43b8237713 | ||
|
|
20199f08c4 | ||
|
|
8c01a6ea46 | ||
|
|
55ef0f6309 | ||
|
|
587339b733 | ||
|
|
a6ffbd3600 | ||
|
|
baf2a56c93 | ||
|
|
7b9b396ab4 | ||
|
|
3a1f3c3ba4 | ||
|
|
1cbe3c5957 | ||
|
|
11b91a0283 | ||
|
|
b1ca0406a5 | ||
|
|
799ae48f7c | ||
|
|
da2263728a | ||
|
|
707e865627 | ||
|
|
e951fd01c8 | ||
|
|
bf1d9db9a1 | ||
|
|
a20f53c6de | ||
|
|
006123c296 | ||
|
|
670bde3671 | ||
|
|
7098d42b87 | ||
|
|
e257e6ce5c | ||
|
|
41ffa44a3f | ||
|
|
9efc8af07b | ||
|
|
3e28c528a4 | ||
|
|
e10b44f64e | ||
|
|
b1bbc9d39d | ||
|
|
31b79434ce | ||
|
|
f9a8b29b8a | ||
|
|
a8939d5d7b | ||
|
|
5641a2b882 | ||
|
|
1cc9877b39 | ||
|
|
62fbc1ffee | ||
|
|
d68064e4e3 | ||
|
|
47cc574730 | ||
|
|
510b34aa3c | ||
|
|
5917aff5f5 | ||
|
|
449ea2664e | ||
|
|
21633d2138 | ||
|
|
9ebc004aa4 | ||
|
|
9433ed3da5 | ||
|
|
729136ea80 | ||
|
|
a2352bffdb | ||
|
|
9a1ead9e8a | ||
|
|
bb2a50712b | ||
|
|
eec89fd768 | ||
|
|
e453e72bf1 | ||
|
|
316c46e797 | ||
|
|
5a4b68608b | ||
|
|
cddc373eb2 | ||
|
|
cf85c8851a | ||
|
|
39bff0fb10 | ||
|
|
d0a8f5b2d0 | ||
|
|
d482b7c738 | ||
|
|
1d3b7fb203 | ||
|
|
0c220ea127 | ||
|
|
922ff0be42 | ||
|
|
855898d134 | ||
|
|
dd46b8ce39 | ||
|
|
76e7c1e163 | ||
|
|
3e3b08b152 | ||
|
|
2e37b620b4 | ||
|
|
31fcee272d | ||
|
|
3aa8420342 | ||
|
|
498ba9b4e1 | ||
|
|
825e5b1f9e | ||
|
|
ec82b8a36c | ||
|
|
5fcbbcd93a | ||
|
|
c25171d69f | ||
|
|
bfb55eeb36 | ||
|
|
5ea75a14d0 | ||
|
|
e748e55f4d | ||
|
|
55ce05f270 | ||
|
|
5d5b61a606 | ||
|
|
257b1d4d20 | ||
|
|
8c47395904 | ||
|
|
5130d22766 | ||
|
|
6256260203 | ||
|
|
f0d93dcdc1 |
@@ -10,6 +10,7 @@ if(BL_SDK_BASE)
|
||||
set(CONFIG_CHERRYUSB_DEVICE_MSC 1)
|
||||
set(CONFIG_CHERRYUSB_DEVICE_AUDIO 1)
|
||||
set(CONFIG_CHERRYUSB_DEVICE_VIDEO 1)
|
||||
set(CONFIG_CHERRYUSB_DEVICE_GAMEPAD 1)
|
||||
|
||||
set(CONFIG_CHERRYUSB_HOST_CDC_ACM 1)
|
||||
set(CONFIG_CHERRYUSB_HOST_CDC_ECM 1)
|
||||
@@ -26,6 +27,7 @@ if(BL_SDK_BASE)
|
||||
set(CONFIG_CHERRYUSB_HOST_CP210X 1)
|
||||
set(CONFIG_CHERRYUSB_HOST_FTDI 1)
|
||||
set(CONFIG_CHERRYUSB_HOST_PL2303 1)
|
||||
set(CONFIG_CHERRYUSB_HOST_GSM 1)
|
||||
|
||||
set(CONFIG_CHERRYUSB_DEVICE_BL 1)
|
||||
set(CONFIG_CHERRYUSB_HOST_EHCI_BL 1)
|
||||
@@ -139,6 +141,9 @@ elseif(ESP_PLATFORM)
|
||||
if(CONFIG_CHERRYUSB_HOST_PL2303)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u pl2303_class_info")
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_GSM)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u gsm_class_info")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CONFIG_CHERRYUSB)
|
||||
@@ -178,6 +183,7 @@ elseif(HPM_SDK_BASE)
|
||||
set(CONFIG_CHERRYUSB_DEVICE_MSC 1)
|
||||
set(CONFIG_CHERRYUSB_DEVICE_AUDIO 1)
|
||||
set(CONFIG_CHERRYUSB_DEVICE_VIDEO 1)
|
||||
set(CONFIG_CHERRYUSB_DEVICE_GAMEPAD 1)
|
||||
|
||||
set(CONFIG_CHERRYUSB_HOST_CDC_ACM 1)
|
||||
set(CONFIG_CHERRYUSB_HOST_CDC_ECM 1)
|
||||
@@ -194,6 +200,7 @@ elseif(HPM_SDK_BASE)
|
||||
set(CONFIG_CHERRYUSB_HOST_CP210X 1)
|
||||
set(CONFIG_CHERRYUSB_HOST_FTDI 1)
|
||||
set(CONFIG_CHERRYUSB_HOST_PL2303 1)
|
||||
set(CONFIG_CHERRYUSB_HOST_GSM 1)
|
||||
|
||||
set(CONFIG_CHERRYUSB_DEVICE_HPM 1)
|
||||
set(CONFIG_CHERRYUSB_HOST_EHCI_HPM 1)
|
||||
|
||||
56
Kconfig
56
Kconfig
@@ -10,7 +10,7 @@ if CHERRYUSB
|
||||
default n
|
||||
|
||||
if CHERRYUSB_DEVICE
|
||||
choice
|
||||
choice CHERRYUSB_DEVICE_SPEED
|
||||
prompt "Select usb device speed"
|
||||
default CHERRYUSB_DEVICE_SPEED_FS
|
||||
config CHERRYUSB_DEVICE_SPEED_FS
|
||||
@@ -21,7 +21,7 @@ if CHERRYUSB
|
||||
bool "AUTO"
|
||||
endchoice
|
||||
|
||||
choice
|
||||
choice CHERRYUSB_DEVICE_IP
|
||||
prompt "Select usb device ip, and some ip need config in usb_config.h, please check"
|
||||
default CHERRYUSB_DEVICE_CUSTOM
|
||||
config CHERRYUSB_DEVICE_CUSTOM
|
||||
@@ -36,6 +36,8 @@ if CHERRYUSB
|
||||
bool "dwc2_esp"
|
||||
config CHERRYUSB_DEVICE_DWC2_KENDRYTE
|
||||
bool "dwc2_kendryte"
|
||||
config CHERRYUSB_DEVICE_DWC2_INFINEON
|
||||
bool "dwc2_infineon"
|
||||
config CHERRYUSB_DEVICE_DWC2_AT
|
||||
bool "dwc2_at"
|
||||
config CHERRYUSB_DEVICE_DWC2_HC
|
||||
@@ -159,7 +161,7 @@ if CHERRYUSB
|
||||
prompt "Enable usb cdc ecm device with lwip for lan"
|
||||
default n
|
||||
|
||||
choice
|
||||
choice CHERRYUSB_DEVICE_TEMPLATE
|
||||
prompt "Select usb device template, please select class driver first"
|
||||
default CHERRYUSB_DEVICE_TEMPLATE_NONE
|
||||
config CHERRYUSB_DEVICE_TEMPLATE_NONE
|
||||
@@ -239,7 +241,7 @@ if CHERRYUSB
|
||||
default n
|
||||
|
||||
if CHERRYUSB_HOST
|
||||
choice
|
||||
choice CHERRYUSB_HOST_IP
|
||||
prompt "Select usb host ip, and some ip need config in usb_config.h, please check"
|
||||
default CHERRYUSB_HOST_CUSTOM
|
||||
config CHERRYUSB_HOST_CUSTOM
|
||||
@@ -264,6 +266,10 @@ if CHERRYUSB
|
||||
bool "dwc2_esp"
|
||||
config CHERRYUSB_HOST_DWC2_KENDRYTE
|
||||
bool "dwc2_kendryte"
|
||||
config CHERRYUSB_HOST_DWC2_INFINEON
|
||||
bool "dwc2_infineon"
|
||||
config CHERRYUSB_HOST_DWC2_AT
|
||||
bool "dwc2_at, f405 only"
|
||||
config CHERRYUSB_HOST_DWC2_HC
|
||||
bool "dwc2_hc"
|
||||
config CHERRYUSB_HOST_DWC2_NATION
|
||||
@@ -299,6 +305,7 @@ if CHERRYUSB
|
||||
config CHERRYUSB_HOST_CDC_ACM
|
||||
bool
|
||||
prompt "Enable usb cdc acm driver"
|
||||
select USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config CHERRYUSB_HOST_HID
|
||||
@@ -360,21 +367,31 @@ if CHERRYUSB
|
||||
config CHERRYUSB_HOST_FTDI
|
||||
bool
|
||||
prompt "Enable usb ftdi driver"
|
||||
select USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config CHERRYUSB_HOST_CH34X
|
||||
bool
|
||||
prompt "Enable usb ch34x driver"
|
||||
select USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config CHERRYUSB_HOST_CP210X
|
||||
bool
|
||||
prompt "Enable usb cp210x driver"
|
||||
select USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config CHERRYUSB_HOST_PL2303
|
||||
bool
|
||||
prompt "Enable usb pl2303 driver"
|
||||
select USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config CHERRYUSB_HOST_GSM
|
||||
bool
|
||||
prompt "Enable usb gsm driver for 4g module"
|
||||
select USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config CHERRYUSB_HOST_AOA
|
||||
@@ -382,6 +399,9 @@ if CHERRYUSB
|
||||
prompt "Enable usb aoa driver"
|
||||
default n
|
||||
|
||||
config USBHOST_SERIAL
|
||||
bool
|
||||
|
||||
config USBHOST_PLATFORM_CDC_ECM
|
||||
bool
|
||||
|
||||
@@ -417,22 +437,32 @@ if CHERRYUSB
|
||||
prompt "Set host control transfer timeout, unit is ms"
|
||||
default 500
|
||||
|
||||
config USBHOST_SERIAL_RX_SIZE
|
||||
int
|
||||
prompt "Set host serial rx max buffer size"
|
||||
default 2048
|
||||
|
||||
menu "Select USB host template, please select class driver first"
|
||||
config TEST_USBH_CDC_ACM
|
||||
int
|
||||
prompt "demo for test cdc acm"
|
||||
default 0
|
||||
depends on CHERRYUSB_HOST_CDC_ACM
|
||||
config TEST_USBH_SERIAL
|
||||
bool
|
||||
prompt "demo for test serial"
|
||||
default n
|
||||
depends on CHERRYUSB_HOST_CDC_ACM || CHERRYUSB_HOST_FTDI || CHERRYUSB_HOST_CH34X || CHERRYUSB_HOST_CP210X || CHERRYUSB_HOST_PL2303
|
||||
config TEST_USBH_HID
|
||||
int
|
||||
bool
|
||||
prompt "demo for test hid"
|
||||
default 0
|
||||
default n
|
||||
depends on CHERRYUSB_HOST_HID
|
||||
config TEST_USBH_MSC
|
||||
int
|
||||
bool
|
||||
prompt "demo for test msc"
|
||||
default 0
|
||||
default n
|
||||
depends on CHERRYUSB_HOST_MSC
|
||||
config TEST_USBH_NET
|
||||
bool
|
||||
prompt "demo for test net, no demo for this, you can use lwip api to test"
|
||||
default n
|
||||
depends on CHERRYUSB_HOST_CDC_ECM || CHERRYUSB_HOST_CDC_RNDIS || CHERRYUSB_HOST_CDC_NCM || CHERRYUSB_HOST_ASIX || CHERRYUSB_HOST_RTL8152
|
||||
endmenu
|
||||
endif
|
||||
endif
|
||||
|
||||
58
Kconfig.rtt
58
Kconfig.rtt
@@ -10,7 +10,7 @@ if RT_USING_CHERRYUSB
|
||||
default n
|
||||
|
||||
if RT_CHERRYUSB_DEVICE
|
||||
choice
|
||||
choice CHERRYUSB_DEVICE_SPEED
|
||||
prompt "Select usb device speed"
|
||||
default RT_CHERRYUSB_DEVICE_SPEED_FS
|
||||
config RT_CHERRYUSB_DEVICE_SPEED_FS
|
||||
@@ -21,7 +21,7 @@ if RT_USING_CHERRYUSB
|
||||
bool "AUTO"
|
||||
endchoice
|
||||
|
||||
choice
|
||||
choice CHERRYUSB_DEVICE_IP
|
||||
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
|
||||
@@ -36,6 +36,8 @@ if RT_USING_CHERRYUSB
|
||||
bool "dwc2_esp"
|
||||
config RT_CHERRYUSB_DEVICE_DWC2_KENDRYTE
|
||||
bool "dwc2_kendryte"
|
||||
config RT_CHERRYUSB_DEVICE_DWC2_INFINEON
|
||||
bool "dwc2_infineon"
|
||||
config RT_CHERRYUSB_DEVICE_DWC2_AT
|
||||
bool "dwc2_at"
|
||||
config RT_CHERRYUSB_DEVICE_DWC2_HC
|
||||
@@ -165,7 +167,7 @@ if RT_USING_CHERRYUSB
|
||||
prompt "Enable usb cdc ecm device with lwip for lan"
|
||||
default n
|
||||
|
||||
choice
|
||||
choice CHERRYUSB_DEVICE_TEMPLATE
|
||||
prompt "Select usb device template, please select class driver first"
|
||||
default RT_CHERRYUSB_DEVICE_TEMPLATE_NONE
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_NONE
|
||||
@@ -263,7 +265,7 @@ if RT_USING_CHERRYUSB
|
||||
default n
|
||||
|
||||
if RT_CHERRYUSB_HOST
|
||||
choice
|
||||
choice CHERRYUSB_HOST_IP
|
||||
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
|
||||
@@ -288,6 +290,10 @@ if RT_USING_CHERRYUSB
|
||||
bool "dwc2_esp"
|
||||
config RT_CHERRYUSB_HOST_DWC2_KENDRYTE
|
||||
bool "dwc2_kendryte"
|
||||
config RT_CHERRYUSB_HOST_DWC2_INFINEON
|
||||
bool "dwc2_infineon"
|
||||
config RT_CHERRYUSB_HOST_DWC2_AT
|
||||
bool "dwc2_at, f405 only"
|
||||
config RT_CHERRYUSB_HOST_DWC2_HC
|
||||
bool "dwc2_hc"
|
||||
config RT_CHERRYUSB_HOST_DWC2_NATION
|
||||
@@ -315,6 +321,7 @@ if RT_USING_CHERRYUSB
|
||||
config RT_CHERRYUSB_HOST_CDC_ACM
|
||||
bool
|
||||
prompt "Enable usb cdc acm driver"
|
||||
select CONFIG_USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_HID
|
||||
@@ -382,23 +389,36 @@ if RT_USING_CHERRYUSB
|
||||
config RT_CHERRYUSB_HOST_FTDI
|
||||
bool
|
||||
prompt "Enable usb ftdi driver"
|
||||
select CONFIG_USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_CH34X
|
||||
bool
|
||||
prompt "Enable usb ch34x driver"
|
||||
select CONFIG_USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_CP210X
|
||||
bool
|
||||
prompt "Enable usb cp210x driver"
|
||||
select CONFIG_USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_PL2303
|
||||
bool
|
||||
prompt "Enable usb pl2303 driver"
|
||||
select CONFIG_USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_HOST_GSM
|
||||
bool
|
||||
prompt "Enable usb gsm driver for 4g module"
|
||||
select CONFIG_USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config CONFIG_USBHOST_SERIAL
|
||||
bool
|
||||
|
||||
config CONFIG_USBHOST_PLATFORM_CDC_ECM
|
||||
bool
|
||||
|
||||
@@ -434,6 +454,11 @@ if RT_USING_CHERRYUSB
|
||||
prompt "Set host control transfer timeout, unit is ms"
|
||||
default 500
|
||||
|
||||
config CONFIG_USBHOST_SERIAL_RX_SIZE
|
||||
int
|
||||
prompt "Set host serial rx max buffer size"
|
||||
default 2048
|
||||
|
||||
config RT_LWIP_PBUF_POOL_BUFSIZE
|
||||
int "The size of each pbuf in the pbuf pool"
|
||||
range 1500 2000
|
||||
@@ -445,21 +470,26 @@ if RT_USING_CHERRYUSB
|
||||
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
|
||||
config RT_TEST_USBH_SERIAL
|
||||
bool
|
||||
prompt "demo for test seial, cannot enable this demo, you can use rt-thread device api to test"
|
||||
default n
|
||||
depends on CONFIG_USBHOST_SERIAL
|
||||
config RT_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
|
||||
config RT_TEST_USBH_MSC
|
||||
bool
|
||||
prompt "demo for test msc, cannot enable this demo, you can use rt-thread dfs api to test"
|
||||
default n
|
||||
depends on RT_CHERRYUSB_HOST_MSC
|
||||
config RT_TEST_USBH_NET
|
||||
bool
|
||||
prompt "demo for test net, cannot enable this demo, you can use lwip api to test"
|
||||
default n
|
||||
depends on RT_CHERRYUSB_HOST_CDC_ECM || RT_CHERRYUSB_HOST_CDC_RNDIS || RT_CHERRYUSB_HOST_CDC_NCM || RT_CHERRYUSB_HOST_ASIX || RT_CHERRYUSB_HOST_RTL8152
|
||||
endmenu
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -11,7 +11,7 @@ if PKG_USING_CHERRYUSB
|
||||
default n
|
||||
|
||||
if PKG_CHERRYUSB_DEVICE
|
||||
choice
|
||||
choice CHERRYUSB_DEVICE_SPEED
|
||||
prompt "Select usb device speed"
|
||||
default PKG_CHERRYUSB_DEVICE_SPEED_FS
|
||||
config PKG_CHERRYUSB_DEVICE_SPEED_FS
|
||||
@@ -22,7 +22,7 @@ if PKG_USING_CHERRYUSB
|
||||
bool "AUTO"
|
||||
endchoice
|
||||
|
||||
choice
|
||||
choice CHERRYUSB_DEVICE_IP
|
||||
prompt "Select usb device ip, and some ip need config in usb_config.h, please check"
|
||||
default PKG_CHERRYUSB_DEVICE_CUSTOM
|
||||
config PKG_CHERRYUSB_DEVICE_CUSTOM
|
||||
@@ -37,6 +37,8 @@ if PKG_USING_CHERRYUSB
|
||||
bool "dwc2_esp"
|
||||
config PKG_CHERRYUSB_DEVICE_DWC2_KENDRYTE
|
||||
bool "dwc2_kendryte"
|
||||
config PKG_CHERRYUSB_DEVICE_DWC2_INFINEON
|
||||
bool "dwc2_infineon"
|
||||
config PKG_CHERRYUSB_DEVICE_DWC2_AT
|
||||
bool "dwc2_at"
|
||||
config PKG_CHERRYUSB_DEVICE_DWC2_HC
|
||||
@@ -164,7 +166,7 @@ if PKG_USING_CHERRYUSB
|
||||
prompt "Enable usb cdc ecm device with lwip for lan"
|
||||
default n
|
||||
|
||||
choice
|
||||
choice CHERRYUSB_DEVICE_TEMPLATE
|
||||
prompt "Select usb device template, please select class driver first"
|
||||
default PKG_CHERRYUSB_DEVICE_TEMPLATE_NONE
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_NONE
|
||||
@@ -262,7 +264,7 @@ if PKG_USING_CHERRYUSB
|
||||
default n
|
||||
|
||||
if PKG_CHERRYUSB_HOST
|
||||
choice
|
||||
choice CHERRYUSB_HOST_IP
|
||||
prompt "Select usb host ip, and some ip need config in usb_config.h, please check"
|
||||
default PKG_CHERRYUSB_HOST_CUSTOM
|
||||
config PKG_CHERRYUSB_HOST_CUSTOM
|
||||
@@ -287,6 +289,10 @@ if PKG_USING_CHERRYUSB
|
||||
bool "dwc2_esp"
|
||||
config PKG_CHERRYUSB_HOST_DWC2_KENDRYTE
|
||||
bool "dwc2_kendryte"
|
||||
config PKG_CHERRYUSB_HOST_DWC2_INFINEON
|
||||
bool "dwc2_infineon"
|
||||
config PKG_CHERRYUSB_HOST_DWC2_AT
|
||||
bool "dwc2_at, f405 only"
|
||||
config PKG_CHERRYUSB_HOST_DWC2_HC
|
||||
bool "dwc2_hc"
|
||||
config PKG_CHERRYUSB_HOST_DWC2_NATION
|
||||
@@ -314,6 +320,7 @@ if PKG_USING_CHERRYUSB
|
||||
config PKG_CHERRYUSB_HOST_CDC_ACM
|
||||
bool
|
||||
prompt "Enable usb cdc acm driver"
|
||||
select CONFIG_USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config PKG_CHERRYUSB_HOST_HID
|
||||
@@ -381,23 +388,36 @@ if PKG_USING_CHERRYUSB
|
||||
config PKG_CHERRYUSB_HOST_FTDI
|
||||
bool
|
||||
prompt "Enable usb ftdi driver"
|
||||
select CONFIG_USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config PKG_CHERRYUSB_HOST_CH34X
|
||||
bool
|
||||
prompt "Enable usb ch34x driver"
|
||||
select CONFIG_USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config PKG_CHERRYUSB_HOST_CP210X
|
||||
bool
|
||||
prompt "Enable usb cp210x driver"
|
||||
select CONFIG_USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config PKG_CHERRYUSB_HOST_PL2303
|
||||
bool
|
||||
prompt "Enable usb pl2303 driver"
|
||||
select CONFIG_USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config PKG_CHERRYUSB_HOST_GSM
|
||||
bool
|
||||
prompt "Enable usb gsm driver for 4g module"
|
||||
select CONFIG_USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config CONFIG_USBHOST_SERIAL
|
||||
bool
|
||||
|
||||
config CONFIG_USBHOST_PLATFORM_CDC_ECM
|
||||
bool
|
||||
|
||||
@@ -433,6 +453,11 @@ if PKG_USING_CHERRYUSB
|
||||
prompt "Set host control transfer timeout, unit is ms"
|
||||
default 500
|
||||
|
||||
config CONFIG_USBHOST_SERIAL_RX_SIZE
|
||||
int
|
||||
prompt "Set host serial rx max buffer size"
|
||||
default 2048
|
||||
|
||||
config RT_LWIP_PBUF_POOL_BUFSIZE
|
||||
int "The size of each pbuf in the pbuf pool"
|
||||
range 1500 2000
|
||||
@@ -444,21 +469,26 @@ if PKG_USING_CHERRYUSB
|
||||
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 PKG_CHERRYUSB_HOST_CDC_ACM
|
||||
config CONFIG_TEST_USBH_HID
|
||||
config PKG_TEST_USBH_SERIAL
|
||||
bool
|
||||
prompt "demo for test seial, cannot enable this demo, you can use rt-thread device api to test"
|
||||
default n
|
||||
depends on CONFIG_USBHOST_SERIAL
|
||||
config PKG_TEST_USBH_HID
|
||||
int
|
||||
prompt "demo for test hid"
|
||||
default 0
|
||||
depends on PKG_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
|
||||
config PKG_TEST_USBH_MSC
|
||||
bool
|
||||
prompt "demo for test msc, cannot enable this demo, you can use rt-thread dfs api to test"
|
||||
default n
|
||||
depends on PKG_CHERRYUSB_HOST_MSC
|
||||
config PKG_TEST_USBH_NET
|
||||
bool
|
||||
prompt "demo for test net, cannot enable this demo, you can use lwip api to test"
|
||||
default n
|
||||
depends on PKG_CHERRYUSB_HOST_CDC_ECM || PKG_CHERRYUSB_HOST_CDC_RNDIS || PKG_CHERRYUSB_HOST_CDC_NCM || PKG_CHERRYUSB_HOST_ASIX || PKG_CHERRYUSB_HOST_RTL8152
|
||||
endmenu
|
||||
endif
|
||||
|
||||
@@ -474,12 +504,12 @@ if PKG_USING_CHERRYUSB
|
||||
|
||||
config PKG_USING_CHERRYUSB_LATEST_VERSION
|
||||
bool "latest"
|
||||
config PKG_USING_CHERRYUSB_V010502
|
||||
bool "v1.5.3"
|
||||
config PKG_USING_CHERRYUSB_V010600
|
||||
bool "v1.6.0"
|
||||
config PKG_USING_CHERRYUSB_V010503
|
||||
bool "v1.5.3.99"
|
||||
config PKG_USING_CHERRYUSB_V010502
|
||||
bool "v1.5.2"
|
||||
config PKG_USING_CHERRYUSB_V010501
|
||||
bool "v1.5.1"
|
||||
config PKG_USING_CHERRYUSB_V010500
|
||||
bool "v1.5.0"
|
||||
config PKG_USING_CHERRYUSB_V010403
|
||||
@@ -495,9 +525,9 @@ if PKG_USING_CHERRYUSB
|
||||
config PKG_CHERRYUSB_VER
|
||||
string
|
||||
default "latest" if PKG_USING_CHERRYUSB_LATEST_VERSION
|
||||
default "v1.5.3" if PKG_USING_CHERRYUSB_V010503
|
||||
default "v1.6.0" if PKG_USING_CHERRYUSB_V010600
|
||||
default "v1.5.3.99" if PKG_USING_CHERRYUSB_V010503
|
||||
default "v1.5.2" if PKG_USING_CHERRYUSB_V010502
|
||||
default "v1.5.1" if PKG_USING_CHERRYUSB_V010501
|
||||
default "v1.5.0" if PKG_USING_CHERRYUSB_V010500
|
||||
default "v1.4.3" if PKG_USING_CHERRYUSB_V010403
|
||||
default "v1.3.1" if PKG_USING_CHERRYUSB_V010301
|
||||
|
||||
@@ -112,7 +112,8 @@ CherryUSB Host Stack has the following functions:
|
||||
- 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
|
||||
@@ -150,7 +151,7 @@ Among them, `sizeof(struct usbh_hub)` and `sizeof(struct usbh_hubport)` are affe
|
||||
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
|
||||
@@ -181,11 +182,11 @@ 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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
## 示例仓库
|
||||
|
||||
|
||||
38
SConscript
38
SConscript
@@ -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(['PKG_CHERRYUSB_DEVICE']):
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_KENDRYTE']):
|
||||
src += Glob('port/dwc2/usb_dc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_kendryte.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_DWC2_INFINEON']):
|
||||
src += Glob('port/dwc2/usb_dc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_infineon.c')
|
||||
if GetDepend(['PKG_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(['PKG_CHERRYUSB_DEVICE']):
|
||||
LIBS = ['libpusb2_dc_a32_softfp_neon.a']
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_NRF5X']):
|
||||
src += Glob('port/nrf5x/usb_dc_nrf5x.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_RP2040']):
|
||||
path += [cwd + '/port/rp2040']
|
||||
src += Glob('port/rp2040/usb_dc_rp2040.c')
|
||||
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_CDC_ACM']):
|
||||
src += Glob('class/cdc/usbd_cdc_acm.c')
|
||||
@@ -218,6 +223,12 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_KENDRYTE']):
|
||||
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_kendryte.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_INFINEON']):
|
||||
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_infineon.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_AT']):
|
||||
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_at.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_HC']):
|
||||
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
||||
src += Glob('port/dwc2/usb_glue_hc.c')
|
||||
@@ -268,8 +279,12 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
|
||||
LIBPATH = [cwd + '/port/xhci/phytium']
|
||||
LIBS = ['libxhci_a32_softfp_neon.a']
|
||||
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_RP2040']):
|
||||
path += [cwd + '/port/rp2040']
|
||||
src += Glob('port/rp2040/usb_hc_rp2040.c')
|
||||
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_CDC_ACM']):
|
||||
src += Glob('class/cdc/usbh_cdc_acm.c')
|
||||
src += Glob('class/serial/usbh_cdc_acm.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_HID']):
|
||||
src += Glob('class/hid/usbh_hid.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_MSC']):
|
||||
@@ -291,23 +306,26 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_RTL8152']):
|
||||
src += Glob('class/vendor/net/usbh_rtl8152.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_FTDI']):
|
||||
src += Glob('class/vendor/serial/usbh_ftdi.c')
|
||||
src += Glob('class/serial/usbh_ftdi.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_CH34X']):
|
||||
src += Glob('class/vendor/serial/usbh_ch34x.c')
|
||||
src += Glob('class/serial/usbh_ch34x.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_CP210X']):
|
||||
src += Glob('class/vendor/serial/usbh_cp210x.c')
|
||||
src += Glob('class/serial/usbh_cp210x.c')
|
||||
if GetDepend(['PKG_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(['PKG_TEST_USBH_HID']):
|
||||
CPPDEFINES+=['CONFIG_TEST_USBH_HID']
|
||||
src += Glob('demo/usb_host.c')
|
||||
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_CDC_ACM']) \
|
||||
or GetDepend(['PKG_CHERRYUSB_HOST_FTDI']) \
|
||||
or GetDepend(['PKG_CHERRYUSB_HOST_CH34X']) \
|
||||
or GetDepend(['PKG_CHERRYUSB_HOST_CP210X']) \
|
||||
or GetDepend(['PKG_CHERRYUSB_HOST_PL2303']):
|
||||
src += Glob('platform/rtthread/usbh_serial.c')
|
||||
or GetDepend(['PKG_CHERRYUSB_HOST_PL2303']) \
|
||||
or GetDepend(['PKG_CHERRYUSB_HOST_GSM']):
|
||||
src += Glob('class/serial/usbh_serial.c')
|
||||
src += Glob('platform/rtthread/usbh_rtserial.c')
|
||||
|
||||
if GetDepend('RT_USING_DFS') and GetDepend(['PKG_CHERRYUSB_HOST_MSC']):
|
||||
src += Glob('platform/rtthread/usbh_dfs.c')
|
||||
|
||||
4
VERSION
4
VERSION
@@ -1,5 +1,5 @@
|
||||
VERSION_MAJOR = 1
|
||||
VERSION_MINOR = 5
|
||||
PATCHLEVEL = 3
|
||||
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,21 +239,34 @@ 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_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
|
||||
@@ -331,7 +348,7 @@ 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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,294 +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_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
|
||||
};
|
||||
|
||||
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,
|
||||
|
||||
224
class/gamepad/usb_gamepad.h
Normal file
224
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
class/gamepad/usbd_gamepad.c
Normal file
209
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);
|
||||
}
|
||||
22
class/gamepad/usbd_gamepad.h
Normal file
22
class/gamepad/usbd_gamepad.h
Normal file
@@ -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 */
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
|
||||
#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hid_buf[CONFIG_USBHOST_MAX_HID_CLASS][USB_ALIGN_UP(64, CONFIG_USB_ALIGN_SIZE)];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hid_buf[CONFIG_USBHOST_MAX_HID_CLASS][USB_ALIGN_UP(32, CONFIG_USB_ALIGN_SIZE)];
|
||||
|
||||
static struct usbh_hid g_hid_class[CONFIG_USBHOST_MAX_HID_CLASS];
|
||||
static uint32_t g_devinuse = 0;
|
||||
@@ -173,7 +173,6 @@ int usbh_hid_set_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t
|
||||
int usbh_hid_get_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t report_id, uint8_t *buffer, uint32_t buflen)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
int ret;
|
||||
|
||||
if (!hid_class || !hid_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
@@ -186,18 +185,12 @@ int usbh_hid_get_report(struct usbh_hid *hid_class, uint8_t report_type, uint8_t
|
||||
setup->wIndex = 0;
|
||||
setup->wLength = buflen;
|
||||
|
||||
ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf[hid_class->minor]);
|
||||
if (ret < 8) {
|
||||
return ret;
|
||||
}
|
||||
memcpy(buffer, g_hid_buf[hid_class->minor], MIN((uint32_t)ret - 8, buflen));
|
||||
return ret;
|
||||
return usbh_control_transfer(hid_class->hport, setup, buffer);
|
||||
}
|
||||
|
||||
int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret;
|
||||
uint8_t cur_iface = 0xff;
|
||||
uint8_t *p;
|
||||
bool found = false;
|
||||
@@ -249,23 +242,6 @@ int usbh_hid_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
found:
|
||||
// /* 0x0 = boot protocol, 0x1 = report protocol */
|
||||
// ret = usbh_hid_set_protocol(hid_class, 0x1);
|
||||
// if (ret < 0) {
|
||||
// return ret;
|
||||
// }
|
||||
|
||||
ret = usbh_hid_set_idle(hid_class, 0, 0);
|
||||
if (ret < 0) {
|
||||
USB_LOG_WRN("Do not support set idle\r\n");
|
||||
}
|
||||
|
||||
/* We read report desc but do nothing (because of too much memory usage for parsing report desc, parsed by users) */
|
||||
ret = usbh_hid_get_report_descriptor(hid_class, g_hid_buf[hid_class->minor], MIN(sizeof(g_hid_buf[hid_class->minor]), hid_class->report_size));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
||||
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
|
||||
if (ep_desc->bEndpointAddress & 0x80) {
|
||||
@@ -280,7 +256,7 @@ found:
|
||||
USB_LOG_INFO("Register HID Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
|
||||
usbh_hid_run(hid_class);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
@@ -310,6 +286,427 @@ int usbh_hid_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t hid_get_itemval(const uint8_t *data, unsigned int idx, unsigned int size)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
|
||||
for (unsigned int i = 1; i <= size; i++)
|
||||
value |= data[idx + i] << (8 * (i - 1));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
struct hid_report *usbh_hid_report_parse(const uint8_t *data, uint32_t report_len, uint32_t max_usages)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t itemtag, itemtype, itemsize;
|
||||
uint32_t itemval;
|
||||
struct hid_report_field field;
|
||||
uint32_t usage_page = 0, usage = 0, usage_min = 0, usage_max = 0, flags = 0;
|
||||
uint32_t *usages;
|
||||
struct hid_report *hid_report;
|
||||
|
||||
hid_report = usb_osal_malloc(sizeof(struct hid_report));
|
||||
if (!hid_report) {
|
||||
USB_LOG_ERR("hid report malloc failed\r\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
usages = usb_osal_malloc(sizeof(uint32_t) * max_usages);
|
||||
if (!usages) {
|
||||
USB_LOG_ERR("hid usages malloc failed\r\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
memset(hid_report, 0, sizeof(struct hid_report));
|
||||
memset(&field, 0, sizeof(struct hid_report_field));
|
||||
|
||||
while (i < report_len) {
|
||||
itemtag = data[i] & HID_TAG_MASK;
|
||||
itemtype = data[i] & HID_TYPE_MASK;
|
||||
itemsize = data[i] & HID_SIZE_MASK;
|
||||
|
||||
if (itemsize == 3) /* HID spec: 6.2.2.2 - Short Items */
|
||||
itemsize = 4;
|
||||
|
||||
itemval = hid_get_itemval(data, i, itemsize);
|
||||
|
||||
USB_LOG_DBG("itemtype 0x%02x, itemtag 0x%02x, itemsize %d, itemval 0x%08x\r\n",
|
||||
itemtype, itemtag, itemsize, itemval);
|
||||
|
||||
switch (itemtype) {
|
||||
case HID_ITEMTYPE_MAIN:
|
||||
switch (itemtag) {
|
||||
case HID_MAINITEM_TAG_INPUT:
|
||||
if ((flags & HID_REPORT_FLAG_REQUIRED_MASK) != HID_REPORT_FLAG_REQUIRED_MASK)
|
||||
goto err;
|
||||
|
||||
if (hid_report->input_count >= CONFIG_USBHOST_HID_MAX_INPUT) {
|
||||
USB_LOG_ERR("hid input fields exceed max limit\r\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
field.flags = flags;
|
||||
field.properties = itemval;
|
||||
field.usage_page = usage_page;
|
||||
memcpy(&hid_report->input_fields[hid_report->input_count], &field, sizeof(struct hid_report_field));
|
||||
if (field.usage_count > 0) {
|
||||
hid_report->input_fields[hid_report->input_count].usages = usb_osal_malloc(sizeof(uint32_t) * field.usage_count);
|
||||
if (!hid_report->input_fields[hid_report->input_count].usages) {
|
||||
USB_LOG_ERR("hid input usages malloc failed\r\n");
|
||||
goto err;
|
||||
}
|
||||
memcpy(hid_report->input_fields[hid_report->input_count].usages, usages, sizeof(uint32_t) * field.usage_count);
|
||||
}
|
||||
|
||||
hid_report->input_count++;
|
||||
|
||||
/* only keep the global items */
|
||||
flags &= HID_REPORT_FLAG_GLOBAL_MASK;
|
||||
memset(&field, 0, sizeof(struct hid_report_field));
|
||||
break;
|
||||
case HID_MAINITEM_TAG_OUTPUT:
|
||||
if ((flags & HID_REPORT_FLAG_REQUIRED_MASK) != HID_REPORT_FLAG_REQUIRED_MASK)
|
||||
goto err;
|
||||
|
||||
if (hid_report->output_count >= CONFIG_USBHOST_HID_MAX_OUTPUT) {
|
||||
USB_LOG_ERR("hid output fields exceed max limit\r\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
field.flags = flags;
|
||||
field.properties = itemval;
|
||||
field.usage_page = usage_page;
|
||||
memcpy(&hid_report->output_fields[hid_report->output_count], &field, sizeof(struct hid_report_field));
|
||||
if (field.usage_count > 0) {
|
||||
hid_report->output_fields[hid_report->output_count].usages = usb_osal_malloc(sizeof(uint32_t) * field.usage_count);
|
||||
if (!hid_report->output_fields[hid_report->output_count].usages) {
|
||||
USB_LOG_ERR("hid output usages malloc failed\r\n");
|
||||
goto err;
|
||||
}
|
||||
memcpy(hid_report->output_fields[hid_report->output_count].usages, usages, sizeof(uint32_t) * field.usage_count);
|
||||
}
|
||||
|
||||
hid_report->output_count++;
|
||||
|
||||
/* only keep the global items */
|
||||
flags &= HID_REPORT_FLAG_GLOBAL_MASK;
|
||||
memset(&field, 0, sizeof(struct hid_report_field));
|
||||
break;
|
||||
case HID_MAINITEM_TAG_COLLECTION:
|
||||
memset(&field, 0, sizeof(struct hid_report_field));
|
||||
break;
|
||||
case HID_MAINITEM_TAG_FEATURE:
|
||||
|
||||
if (hid_report->feature_count >= CONFIG_USBHOST_HID_MAX_FEATURE) {
|
||||
USB_LOG_ERR("hid feature fields exceed max limit\r\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
field.flags = flags;
|
||||
field.properties = itemval;
|
||||
field.usage_page = usage_page;
|
||||
memcpy(&hid_report->feature_fields[hid_report->feature_count], &field, sizeof(struct hid_report_field));
|
||||
if (field.usage_count > 0) {
|
||||
hid_report->feature_fields[hid_report->feature_count].usages = usb_osal_malloc(sizeof(uint32_t) * field.usage_count);
|
||||
if (!hid_report->feature_fields[hid_report->feature_count].usages) {
|
||||
USB_LOG_ERR("hid feature usages malloc failed\r\n");
|
||||
goto err;
|
||||
}
|
||||
memcpy(hid_report->feature_fields[hid_report->feature_count].usages, usages, sizeof(uint32_t) * field.usage_count);
|
||||
}
|
||||
|
||||
hid_report->feature_count++;
|
||||
|
||||
memset(&field, 0, sizeof(struct hid_report_field));
|
||||
|
||||
break;
|
||||
case HID_MAINITEM_TAG_ENDCOLLECTION:
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case HID_ITEMTYPE_GLOBAL:
|
||||
switch (itemtag) {
|
||||
case HID_GLOBALITEM_TAG_USAGE_PAGE:
|
||||
usage_page = itemval;
|
||||
|
||||
if (usage_page > UINT16_MAX)
|
||||
goto err;
|
||||
|
||||
flags |= HID_REPORT_FLAG_USAGE_PAGE;
|
||||
break;
|
||||
case HID_GLOBALITEM_TAG_LOGICAL_MIN:
|
||||
field.logical_min = (int32_t)itemval;
|
||||
flags |= HID_REPORT_FLAG_LOGICAL_MIN;
|
||||
break;
|
||||
case HID_GLOBALITEM_TAG_LOGICAL_MAX:
|
||||
field.logical_max = (int32_t)itemval;
|
||||
flags |= HID_REPORT_FLAG_LOGICAL_MAX;
|
||||
break;
|
||||
case HID_GLOBALITEM_TAG_REPORT_SIZE:
|
||||
field.report_size = itemval;
|
||||
flags |= HID_REPORT_FLAG_REPORT_SIZE;
|
||||
break;
|
||||
case HID_GLOBALITEM_TAG_REPORT_COUNT:
|
||||
field.report_count = itemval;
|
||||
flags |= HID_REPORT_FLAG_REPORT_COUNT;
|
||||
break;
|
||||
case HID_GLOBALITEM_TAG_REPORT_ID:
|
||||
hid_report->uses_report_id = true;
|
||||
field.report_id = itemval;
|
||||
flags |= HID_REPORT_FLAG_REPORT_ID;
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case HID_ITEMTYPE_LOCAL:
|
||||
switch (itemtag) {
|
||||
case HID_LOCALITEM_TAG_USAGE:
|
||||
usage = itemval;
|
||||
/* Extended usage (size 4) combines both usage page and id */
|
||||
if (itemsize != 4) {
|
||||
if (!(flags & HID_REPORT_FLAG_USAGE_PAGE))
|
||||
goto err;
|
||||
usage |= usage_page << 16;
|
||||
}
|
||||
|
||||
usages[field.usage_count++] = usage;
|
||||
|
||||
break;
|
||||
case HID_LOCALITEM_TAG_USAGE_MIN:
|
||||
usage_min = itemval;
|
||||
if (itemsize == 4) {
|
||||
/* Usage max must be extended as well */
|
||||
flags |= HID_REPORT_FLAG_EXTENDED_USAGE;
|
||||
} else {
|
||||
if (!(flags & HID_REPORT_FLAG_USAGE_PAGE))
|
||||
goto err;
|
||||
usage_min |= usage_page << 16;
|
||||
}
|
||||
field.usage_min = usage_min;
|
||||
flags |= HID_REPORT_FLAG_USAGE_MIN;
|
||||
break;
|
||||
case HID_LOCALITEM_TAG_USAGE_MAX:
|
||||
if (!(flags & HID_REPORT_FLAG_USAGE_MIN))
|
||||
goto err;
|
||||
|
||||
usage_max = itemval;
|
||||
if (flags & HID_REPORT_FLAG_EXTENDED_USAGE) {
|
||||
/* Fail if max is not extended usage (HID spec 6.2.2.8) */
|
||||
if (itemsize != 4)
|
||||
goto err;
|
||||
} else if (itemsize == 4) {
|
||||
/* Fail because min wasn't extended, but max is */
|
||||
goto err;
|
||||
} else {
|
||||
if (!(flags & HID_REPORT_FLAG_USAGE_PAGE))
|
||||
goto err;
|
||||
usage_max |= usage_page << 16;
|
||||
}
|
||||
|
||||
/* Usage min and max must be on the same page */
|
||||
if (USAGE_PAGE(usage_min) != USAGE_PAGE(usage_max)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (usage_min > usage_max) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (uint32_t j = usage_min; j <= usage_max; j++) {
|
||||
usages[field.usage_count++] = j;
|
||||
}
|
||||
|
||||
field.usage_max = usage_max;
|
||||
flags |= HID_REPORT_FLAG_USAGE_MAX;
|
||||
flags &= ~(HID_REPORT_FLAG_USAGE_MIN | HID_REPORT_FLAG_EXTENDED_USAGE);
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
|
||||
i += (1 + itemsize);
|
||||
}
|
||||
usb_osal_free(usages);
|
||||
return hid_report;
|
||||
err:
|
||||
if (hid_report) {
|
||||
usb_osal_free(hid_report);
|
||||
|
||||
for (uint32_t j = 0; j < hid_report->input_count; j++)
|
||||
usb_osal_free(hid_report->input_fields[j].usages);
|
||||
|
||||
for (uint32_t j = 0; j < hid_report->output_count; j++)
|
||||
usb_osal_free(hid_report->output_fields[j].usages);
|
||||
|
||||
for (uint32_t j = 0; j < hid_report->feature_count; j++)
|
||||
usb_osal_free(hid_report->feature_fields[j].usages);
|
||||
}
|
||||
|
||||
if (usages)
|
||||
usb_osal_free(usages);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void usbh_hid_report_free(struct hid_report *hid_report)
|
||||
{
|
||||
if (hid_report) {
|
||||
for (uint32_t j = 0; j < hid_report->input_count; j++)
|
||||
usb_osal_free(hid_report->input_fields[j].usages);
|
||||
|
||||
for (uint32_t j = 0; j < hid_report->output_count; j++)
|
||||
usb_osal_free(hid_report->output_fields[j].usages);
|
||||
|
||||
for (uint32_t j = 0; j < hid_report->feature_count; j++)
|
||||
usb_osal_free(hid_report->feature_fields[j].usages);
|
||||
|
||||
usb_osal_free(hid_report);
|
||||
}
|
||||
}
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_hid_report_buf[2048];
|
||||
|
||||
static const char *hid_property_string(uint32_t value)
|
||||
{
|
||||
uint32_t off = 0;
|
||||
static char buffer[160];
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
if (value & HID_MAINITEM_CONSTANT)
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "Constant, ");
|
||||
else
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "Data, ");
|
||||
|
||||
if (value & HID_MAINITEM_VARIABLE)
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "Variable, ");
|
||||
else
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "Array, ");
|
||||
|
||||
if (value & HID_MAINITEM_RELATIVE)
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "Relative, ");
|
||||
else
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "Absolute, ");
|
||||
|
||||
if (value & HID_MAINITEM_WRAP)
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "Wrap, ");
|
||||
else
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "NoWrap, ");
|
||||
|
||||
if (value & HID_MAINITEM_NONLINEAR)
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "NonLinear, ");
|
||||
else
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "Linear, ");
|
||||
|
||||
if (value & HID_MAINITEM_NOPREFERRED)
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "NoPreferred, ");
|
||||
else
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "Preferred, ");
|
||||
|
||||
if (value & HID_MAINITEM_NULLSTATE)
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "NullState, ");
|
||||
else
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "NoNullState, ");
|
||||
|
||||
if (value & HID_MAINITEM_VOLATILE)
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "Volatile, ");
|
||||
else
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "NonVolatile, ");
|
||||
|
||||
if (value & HID_MAINITEM_BUFFEREDBYTES)
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "BufferedBytes");
|
||||
else
|
||||
off += snprintf(buffer + off, sizeof(buffer) - off, "BitField");
|
||||
|
||||
return buffer;
|
||||
|
||||
}
|
||||
|
||||
static void usbh_hid_field_info_print(uint32_t idx, struct hid_report_field *field)
|
||||
{
|
||||
USB_LOG_RAW(" Field %u:\r\n", idx);
|
||||
USB_LOG_RAW(" Usage Page: 0x%04x\r\n", (unsigned int)field->usage_page);
|
||||
USB_LOG_RAW(" Report ID: %u\r\n", (unsigned int)field->report_id);
|
||||
USB_LOG_RAW(" Report Size: %ubit\r\n", (unsigned int)field->report_size);
|
||||
USB_LOG_RAW(" Report Count: %u\r\n", (unsigned int)field->report_count);
|
||||
USB_LOG_RAW(" Logical Min: %d\r\n", field->logical_min);
|
||||
USB_LOG_RAW(" Logical Max: %d\r\n", field->logical_max);
|
||||
USB_LOG_RAW(" Usage Count: %u\r\n", (unsigned int)field->usage_count);
|
||||
if (field->usage_count > 0) {
|
||||
if (field->usage_count == 1) {
|
||||
USB_LOG_RAW(" Usage: 0x%04x\r\n", USAGE_ID(field->usages[0]));
|
||||
} else {
|
||||
USB_LOG_RAW(" Usages(0x%04x ~ 0x%04x)\r\n", USAGE_ID(field->usage_min), USAGE_ID(field->usage_max));
|
||||
}
|
||||
}
|
||||
USB_LOG_RAW(" Flags: 0x%04x\r\n", (unsigned int)field->flags);
|
||||
USB_LOG_RAW(" Properties: 0x%04x(%s)\r\n", (unsigned int)field->properties, hid_property_string(field->properties));
|
||||
}
|
||||
|
||||
int lshid(int argc, char **argv)
|
||||
{
|
||||
struct usbh_hid *hid_class;
|
||||
struct hid_report *hid_report;
|
||||
int ret;
|
||||
|
||||
if (argc < 2) {
|
||||
USB_LOG_ERR("please input correct command: lshid path\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hid_class = usbh_find_class_instance(argv[1]);
|
||||
if (!hid_class) {
|
||||
USB_LOG_ERR("cannot find hid device\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hid_class->report_size > sizeof(g_hid_report_buf)) {
|
||||
USB_LOG_ERR("hid report buffer is too small\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = usbh_hid_get_report_descriptor(hid_class, g_hid_report_buf, hid_class->report_size);
|
||||
if (ret < 0) {
|
||||
USB_LOG_ERR("get hid report descriptor failed, errcode: %d\r\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hid_report = usbh_hid_report_parse(g_hid_report_buf, hid_class->report_size, 1024);
|
||||
if (hid_report) {
|
||||
USB_LOG_RAW("HID report parsed successfully\r\n");
|
||||
|
||||
USB_LOG_RAW("Input fields: %u\r\n", (unsigned int)hid_report->input_count);
|
||||
for (uint32_t i = 0; i < hid_report->input_count; i++) {
|
||||
struct hid_report_field *field = &hid_report->input_fields[i];
|
||||
usbh_hid_field_info_print(i, field);
|
||||
}
|
||||
|
||||
USB_LOG_RAW("Output fields: %u\r\n", (unsigned int)hid_report->output_count);
|
||||
for (uint32_t i = 0; i < hid_report->output_count; i++) {
|
||||
struct hid_report_field *field = &hid_report->output_fields[i];
|
||||
usbh_hid_field_info_print(i, field);
|
||||
}
|
||||
|
||||
USB_LOG_RAW("Feature fields: %u\r\n", (unsigned int)hid_report->feature_count);
|
||||
for (uint32_t i = 0; i < hid_report->feature_count; i++) {
|
||||
struct hid_report_field *field = &hid_report->feature_fields[i];
|
||||
usbh_hid_field_info_print(i, field);
|
||||
}
|
||||
|
||||
usbh_hid_report_free(hid_report);
|
||||
} else {
|
||||
USB_LOG_ERR("HID report parsed failed\r\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__WEAK void usbh_hid_run(struct usbh_hid *hid_class)
|
||||
{
|
||||
(void)hid_class;
|
||||
|
||||
@@ -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) {
|
||||
@@ -475,6 +489,8 @@ static void usbh_hub_events(struct usbh_hub *hub)
|
||||
int ret;
|
||||
size_t flags;
|
||||
|
||||
(void)speed_table;
|
||||
|
||||
if (!hub->connected) {
|
||||
return;
|
||||
}
|
||||
@@ -565,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);
|
||||
@@ -646,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -665,6 +682,7 @@ 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) {
|
||||
|
||||
266
class/serial/usbh_cdc_acm.c
Normal file
266
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
class/serial/usbh_cdc_acm.h
Normal file
19
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
class/serial/usbh_ch34x.c
Normal file
409
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
class/serial/usbh_ch34x.h
Normal file
56
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
class/serial/usbh_cp210x.c
Normal file
507
class/serial/usbh_cp210x.c
Normal file
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ~ 2025, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_serial.h"
|
||||
#include "usbh_cp210x.h"
|
||||
|
||||
#undef USB_DBG_TAG
|
||||
#define USB_DBG_TAG "usbh_cp210x"
|
||||
#include "usb_log.h"
|
||||
|
||||
struct usbh_cp210x {
|
||||
uint8_t partnum;
|
||||
uint32_t fw_version;
|
||||
uint32_t min_speed;
|
||||
uint32_t max_speed;
|
||||
bool use_actual_rate;
|
||||
bool no_flow_control;
|
||||
bool no_event_mode;
|
||||
};
|
||||
|
||||
struct cp210x_rate {
|
||||
uint32_t rate;
|
||||
uint32_t high;
|
||||
};
|
||||
|
||||
static const struct cp210x_rate cp210x_an205_table1[] = {
|
||||
{ 300, 300 },
|
||||
{ 600, 600 },
|
||||
{ 1200, 1200 },
|
||||
{ 1800, 1800 },
|
||||
{ 2400, 2400 },
|
||||
{ 4000, 4000 },
|
||||
{ 4800, 4803 },
|
||||
{ 7200, 7207 },
|
||||
{ 9600, 9612 },
|
||||
{ 14400, 14428 },
|
||||
{ 16000, 16062 },
|
||||
{ 19200, 19250 },
|
||||
{ 28800, 28912 },
|
||||
{ 38400, 38601 },
|
||||
{ 51200, 51558 },
|
||||
{ 56000, 56280 },
|
||||
{ 57600, 58053 },
|
||||
{ 64000, 64111 },
|
||||
{ 76800, 77608 },
|
||||
{ 115200, 117028 },
|
||||
{ 128000, 129347 },
|
||||
{ 153600, 156868 },
|
||||
{ 230400, 237832 },
|
||||
{ 250000, 254234 },
|
||||
{ 256000, 273066 },
|
||||
{ 460800, 491520 },
|
||||
{ 500000, 567138 },
|
||||
{ 576000, 670254 },
|
||||
{ 921600, 0xffffffff }
|
||||
};
|
||||
|
||||
/*
|
||||
* Quantises the baud rate as per AN205 Table 1
|
||||
*/
|
||||
static uint32_t cp210x_get_an205_rate(uint32_t baud)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cp210x_an205_table1); ++i) {
|
||||
if (baud <= cp210x_an205_table1[i].high)
|
||||
break;
|
||||
}
|
||||
|
||||
return cp210x_an205_table1[i].rate;
|
||||
}
|
||||
|
||||
static uint32_t cp210x_get_actual_rate(uint32_t baud)
|
||||
{
|
||||
unsigned int prescale = 1;
|
||||
unsigned int div;
|
||||
|
||||
if (baud <= 365)
|
||||
prescale = 4;
|
||||
|
||||
div = DIV_ROUND_CLOSEST(48000000, 2 * prescale * baud);
|
||||
baud = 48000000 / (2 * prescale * div);
|
||||
|
||||
return baud;
|
||||
}
|
||||
|
||||
static void usbh_cp210x_init_max_speed(struct usbh_serial *serial)
|
||||
{
|
||||
struct usbh_cp210x *cp210x_class;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return;
|
||||
}
|
||||
|
||||
cp210x_class = (struct usbh_cp210x *)serial->priv;
|
||||
|
||||
bool use_actual_rate = false;
|
||||
uint32_t min = 300;
|
||||
uint32_t max;
|
||||
|
||||
switch (cp210x_class->partnum) {
|
||||
case CP210X_PARTNUM_CP2101:
|
||||
max = 921600;
|
||||
break;
|
||||
case CP210X_PARTNUM_CP2102:
|
||||
case CP210X_PARTNUM_CP2103:
|
||||
max = 1000000;
|
||||
break;
|
||||
case CP210X_PARTNUM_CP2104:
|
||||
use_actual_rate = true;
|
||||
max = 2000000;
|
||||
break;
|
||||
case CP210X_PARTNUM_CP2108:
|
||||
max = 2000000;
|
||||
break;
|
||||
case CP210X_PARTNUM_CP2105:
|
||||
if (serial->intf == 0) {
|
||||
use_actual_rate = true;
|
||||
max = 2000000; /* ECI */
|
||||
} else {
|
||||
min = 2400;
|
||||
max = 921600; /* SCI */
|
||||
}
|
||||
break;
|
||||
case CP210X_PARTNUM_CP2102N_QFN28:
|
||||
case CP210X_PARTNUM_CP2102N_QFN24:
|
||||
case CP210X_PARTNUM_CP2102N_QFN20:
|
||||
use_actual_rate = true;
|
||||
max = 3000000;
|
||||
break;
|
||||
default:
|
||||
max = 2000000;
|
||||
break;
|
||||
}
|
||||
|
||||
cp210x_class->min_speed = min;
|
||||
cp210x_class->max_speed = max;
|
||||
cp210x_class->use_actual_rate = use_actual_rate;
|
||||
}
|
||||
|
||||
static int usbh_cp210x_control_out(struct usbh_serial *serial, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint8_t *data, uint16_t size)
|
||||
{
|
||||
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 = size;
|
||||
|
||||
if (data && size) {
|
||||
memcpy(serial->iobuffer, data, size);
|
||||
return usbh_control_transfer(serial->hport, setup, serial->iobuffer);
|
||||
} else {
|
||||
return usbh_control_transfer(serial->hport, setup, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int usbh_cp210x_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_cp210x_get_partnum(struct usbh_serial *serial)
|
||||
{
|
||||
uint8_t version[3];
|
||||
struct usbh_cp210x *cp210x_class;
|
||||
int ret;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
cp210x_class = (struct usbh_cp210x *)serial->priv;
|
||||
|
||||
ret = usbh_cp210x_control_in(serial, CP210X_VENDOR_SPECIFIC, CP210X_GET_PARTNUM, serial->intf, (uint8_t *)&cp210x_class->partnum, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
USB_LOG_INFO("chip partnum: 0x%02x\r\n", cp210x_class->partnum);
|
||||
|
||||
switch (cp210x_class->partnum) {
|
||||
case CP210X_PARTNUM_CP2102:
|
||||
break;
|
||||
case CP210X_PARTNUM_CP2105:
|
||||
case CP210X_PARTNUM_CP2108:
|
||||
ret = usbh_cp210x_control_in(serial, CP210X_VENDOR_SPECIFIC, CP210X_GET_FW_VER_2N, serial->intf, version, 3);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
cp210x_class->fw_version = version[0] << 16 | version[1] << 8 | version[2];
|
||||
break;
|
||||
case CP210X_PARTNUM_CP2102N_QFN28:
|
||||
case CP210X_PARTNUM_CP2102N_QFN24:
|
||||
case CP210X_PARTNUM_CP2102N_QFN20:
|
||||
ret = usbh_cp210x_control_in(serial, CP210X_VENDOR_SPECIFIC, CP210X_GET_FW_VER_2N, serial->intf, version, 3);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
cp210x_class->fw_version = version[0] << 16 | version[1] << 8 | version[2];
|
||||
if (cp210x_class->fw_version <= 0x10004)
|
||||
cp210x_class->no_flow_control = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_cp210x_enable(struct usbh_serial *serial)
|
||||
{
|
||||
return usbh_cp210x_control_out(serial, CP210X_IFC_ENABLE, 1, serial->intf, NULL, 0);
|
||||
}
|
||||
|
||||
static int usbh_cp210x_set_chars(struct usbh_serial *serial)
|
||||
{
|
||||
struct cp210x_special_chars chars = { 0 };
|
||||
|
||||
return usbh_cp210x_control_out(serial, CP210X_SET_CHARS, 0, serial->intf, (uint8_t *)&chars, sizeof(struct cp210x_special_chars));
|
||||
}
|
||||
|
||||
// static int usbh_cp210x_get_common_status(struct usbh_serial *serial, struct cp210x_comm_status *status)
|
||||
// {
|
||||
// return usbh_cp210x_control_in(serial, CP210X_GET_COMM_STATUS, 0, serial->intf, (uint8_t *)status, sizeof(struct cp210x_comm_status));
|
||||
// }
|
||||
|
||||
static int usbh_cp210x_set_baudrate(struct usbh_serial *serial, uint32_t baudrate)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
struct usbh_cp210x *cp210x_class;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->hport->setup;
|
||||
cp210x_class = (struct usbh_cp210x *)serial->priv;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = CP210X_SET_BAUDRATE;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = serial->intf;
|
||||
setup->wLength = 4;
|
||||
|
||||
if (cp210x_class->use_actual_rate)
|
||||
baudrate = cp210x_get_actual_rate(baudrate);
|
||||
else if (baudrate < 1000000)
|
||||
baudrate = cp210x_get_an205_rate(baudrate);
|
||||
|
||||
memcpy(serial->iobuffer, (uint8_t *)&baudrate, 4);
|
||||
return usbh_control_transfer(serial->hport, setup, serial->iobuffer);
|
||||
}
|
||||
|
||||
static int usbh_cp210x_set_data_format(struct usbh_serial *serial, uint8_t databits, uint8_t parity, uint8_t stopbits)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
uint16_t value;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->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 = serial->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(serial->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_cp210x_attach(struct usbh_serial *serial)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct usbh_cp210x *cp210x_class = usb_osal_malloc(sizeof(struct usbh_cp210x));
|
||||
if (!cp210x_class) {
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
memset(cp210x_class, 0, sizeof(struct usbh_cp210x));
|
||||
serial->priv = cp210x_class;
|
||||
|
||||
ret = usbh_cp210x_get_partnum(serial);
|
||||
usbh_cp210x_init_max_speed(serial);
|
||||
ret |= usbh_cp210x_enable(serial);
|
||||
ret |= usbh_cp210x_set_chars(serial);
|
||||
if (ret < 0) {
|
||||
goto errout;
|
||||
}
|
||||
return 0;
|
||||
errout:
|
||||
serial->priv = NULL;
|
||||
usb_osal_free(cp210x_class);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usbh_cp210x_detach(struct usbh_serial *serial)
|
||||
{
|
||||
if (serial && serial->priv) {
|
||||
serial->priv = NULL;
|
||||
usb_osal_free(serial->priv);
|
||||
}
|
||||
}
|
||||
|
||||
int usbh_cp210x_set_flow_ctrl(struct usbh_serial *serial, bool enable)
|
||||
{
|
||||
struct cp210x_flow_ctl flow_ctl = { 0 };
|
||||
uint32_t flow_repl;
|
||||
uint32_t ctl_hs;
|
||||
int ret;
|
||||
|
||||
ret = usbh_cp210x_control_in(serial, CP210X_GET_FLOW, 0, serial->intf, (uint8_t *)&flow_ctl, sizeof(struct cp210x_flow_ctl));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctl_hs = flow_ctl.lControlHandshake;
|
||||
flow_repl = flow_ctl.lFlowReplace;
|
||||
|
||||
ctl_hs &= ~CP210X_SERIAL_DSR_HANDSHAKE;
|
||||
ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE;
|
||||
ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
|
||||
ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
|
||||
ctl_hs |= CP210X_SERIAL_DTR_INACTIVE;
|
||||
|
||||
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
|
||||
flow_repl &= ~CP210X_SERIAL_AUTO_RECEIVE;
|
||||
flow_repl &= ~CP210X_SERIAL_AUTO_TRANSMIT;
|
||||
flow_repl |= CP210X_SERIAL_RTS_INACTIVE;
|
||||
|
||||
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
|
||||
if (enable) {
|
||||
ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
|
||||
} else {
|
||||
ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
|
||||
}
|
||||
flow_ctl.lControlHandshake = ctl_hs;
|
||||
flow_ctl.lFlowReplace = flow_repl;
|
||||
|
||||
return usbh_cp210x_control_out(serial, CP210X_SET_FLOW, 0, serial->intf, (uint8_t *)&flow_ctl, sizeof(struct cp210x_flow_ctl));
|
||||
}
|
||||
|
||||
int usbh_cp210x_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usbh_cp210x_set_baudrate(serial, line_coding->dwDTERate);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return usbh_cp210x_set_data_format(serial, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat);
|
||||
}
|
||||
|
||||
int usbh_cp210x_set_line_state(struct usbh_serial *serial, bool dtr, bool rts)
|
||||
{
|
||||
struct cp210x_flow_ctl flow_ctl = { 0 };
|
||||
uint32_t flow_repl;
|
||||
uint32_t ctl_hs;
|
||||
uint16_t control = 0;
|
||||
int ret;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
if (serial->rtscts) {
|
||||
ret = usbh_cp210x_control_in(serial, CP210X_GET_FLOW, 0, serial->intf, (uint8_t *)&flow_ctl, sizeof(struct cp210x_flow_ctl));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ctl_hs = flow_ctl.lControlHandshake;
|
||||
flow_repl = flow_ctl.lFlowReplace;
|
||||
|
||||
ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
|
||||
if (dtr)
|
||||
ctl_hs |= CP210X_SERIAL_DTR_ACTIVE;
|
||||
else
|
||||
ctl_hs |= CP210X_SERIAL_DTR_INACTIVE;
|
||||
|
||||
flow_repl &= ~CP210X_SERIAL_RTS_MASK;
|
||||
if (rts)
|
||||
flow_repl |= CP210X_SERIAL_RTS_FLOW_CTL;
|
||||
else
|
||||
flow_repl |= CP210X_SERIAL_RTS_INACTIVE;
|
||||
|
||||
flow_ctl.lControlHandshake = ctl_hs;
|
||||
flow_ctl.lFlowReplace = flow_repl;
|
||||
|
||||
return usbh_cp210x_control_out(serial, CP210X_SET_FLOW, 0, serial->intf, (uint8_t *)&flow_ctl, sizeof(struct cp210x_flow_ctl));
|
||||
} else {
|
||||
if (dtr) {
|
||||
control |= CP210X_CONTROL_DTR;
|
||||
}
|
||||
if (rts) {
|
||||
control |= CP210X_CONTROL_RTS;
|
||||
}
|
||||
control |= CP210X_CONTROL_WRITE_DTR;
|
||||
control |= CP210X_CONTROL_WRITE_RTS;
|
||||
return usbh_cp210x_control_out(serial, CP210X_SET_MHS, control, serial->intf, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int usbh_cp210x_get_modem_status(struct usbh_serial *serial)
|
||||
{
|
||||
int ret;
|
||||
uint8_t control;
|
||||
uint16_t status;
|
||||
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
ret = usbh_cp210x_control_in(serial, CP210X_GET_MDMSTS, 0, serial->intf, (uint8_t *)&control, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
status = ((control & CP210X_CONTROL_DTR) ? USBH_SERIAL_TIOCM_DTR : 0) |
|
||||
((control & CP210X_CONTROL_RTS) ? USBH_SERIAL_TIOCM_RTS : 0) |
|
||||
((control & CP210X_CONTROL_CTS) ? USBH_SERIAL_TIOCM_CTS : 0) |
|
||||
((control & CP210X_CONTROL_DSR) ? USBH_SERIAL_TIOCM_DSR : 0) |
|
||||
((control & CP210X_CONTROL_RING) ? USBH_SERIAL_TIOCM_RI : 0) |
|
||||
((control & CP210X_CONTROL_DCD) ? USBH_SERIAL_TIOCM_CD : 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static const struct usbh_serial_driver cp210x_driver = {
|
||||
.driver_name = "cp210x",
|
||||
|
||||
.ignore_rx_header = 0,
|
||||
.ignore_tx_header = 0,
|
||||
|
||||
.attach = usbh_cp210x_attach,
|
||||
.detach = usbh_cp210x_detach,
|
||||
.set_flow_control = usbh_cp210x_set_flow_ctrl,
|
||||
.set_line_coding = usbh_cp210x_set_line_coding,
|
||||
.get_line_coding = NULL,
|
||||
.set_line_state = usbh_cp210x_set_line_state,
|
||||
.get_modem_status = usbh_cp210x_get_modem_status,
|
||||
};
|
||||
|
||||
static int usbh_cp210x_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
return usbh_serial_probe(hport, intf, &cp210x_driver) ? 0 : -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
static int usbh_cp210x_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 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
|
||||
};
|
||||
187
class/serial/usbh_cp210x.h
Normal file
187
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
class/serial/usbh_ftdi.c
Normal file
407
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
class/serial/usbh_ftdi.h
Normal file
341
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
class/serial/usbh_gsm.c
Normal file
131
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
class/serial/usbh_pl2303.c
Normal file
726
class/serial/usbh_pl2303.c
Normal file
@@ -0,0 +1,726 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ~ 2025, sakumisu
|
||||
* Copyright (c) 2024, Derek Konigsberg
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_serial.h"
|
||||
#include "usbh_pl2303.h"
|
||||
|
||||
#undef USB_DBG_TAG
|
||||
#define USB_DBG_TAG "usbh_pl2303"
|
||||
#include "usb_log.h"
|
||||
|
||||
#define UART_STATE_INDEX 8
|
||||
#define UART_STATE_MSR_MASK 0x8b
|
||||
#define UART_STATE_TRANSIENT_MASK 0x74
|
||||
#define UART_DCD 0x01
|
||||
#define UART_DSR 0x02
|
||||
#define UART_BREAK_ERROR 0x04
|
||||
#define UART_RING 0x08
|
||||
#define UART_FRAME_ERROR 0x10
|
||||
#define UART_PARITY_ERROR 0x20
|
||||
#define UART_OVERRUN_ERROR 0x40
|
||||
#define UART_CTS 0x80
|
||||
|
||||
struct pl2303_type_data {
|
||||
const char *name;
|
||||
uint32_t max_baud_rate;
|
||||
unsigned long quirks;
|
||||
unsigned int no_autoxonxoff : 1;
|
||||
unsigned int no_divisors : 1;
|
||||
unsigned int alt_divisors : 1;
|
||||
};
|
||||
|
||||
enum pl2303_type {
|
||||
TYPE_H,
|
||||
TYPE_HX,
|
||||
TYPE_TA,
|
||||
TYPE_TB,
|
||||
TYPE_HXD,
|
||||
TYPE_HXN,
|
||||
TYPE_COUNT
|
||||
};
|
||||
|
||||
struct usbh_pl2303 {
|
||||
enum pl2303_type chip_type;
|
||||
uint32_t quirks;
|
||||
struct usb_endpoint_descriptor *intin;
|
||||
struct usbh_urb intin_urb;
|
||||
struct usb_osal_timer *modem_timer;
|
||||
uint16_t modem_status;
|
||||
};
|
||||
|
||||
static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
|
||||
[TYPE_H] = {
|
||||
.name = "PL2303H",
|
||||
.max_baud_rate = 1228800,
|
||||
.quirks = PL2303_QUIRK_LEGACY,
|
||||
.no_autoxonxoff = true,
|
||||
},
|
||||
[TYPE_HX] = {
|
||||
.name = "PL2303HX",
|
||||
.max_baud_rate = 6000000,
|
||||
},
|
||||
[TYPE_TA] = {
|
||||
.name = "PL2303TA",
|
||||
.max_baud_rate = 6000000,
|
||||
.alt_divisors = true,
|
||||
},
|
||||
[TYPE_TB] = {
|
||||
.name = "PL2303TB",
|
||||
.max_baud_rate = 12000000,
|
||||
.alt_divisors = true,
|
||||
},
|
||||
[TYPE_HXD] = {
|
||||
.name = "PL2303HXD",
|
||||
.max_baud_rate = 12000000,
|
||||
},
|
||||
[TYPE_HXN] = {
|
||||
.name = "PL2303G",
|
||||
.max_baud_rate = 12000000,
|
||||
.no_divisors = true,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns the nearest supported baud rate that can be set directly without
|
||||
* using divisors.
|
||||
*/
|
||||
static uint32_t pl2303_get_supported_baud_rate(uint32_t baud)
|
||||
{
|
||||
static const uint32_t baud_sup[] = {
|
||||
75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600,
|
||||
14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800,
|
||||
614400, 921600, 1228800, 2457600, 3000000, 6000000
|
||||
};
|
||||
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {
|
||||
if (baud_sup[i] > baud)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(baud_sup))
|
||||
baud = baud_sup[i - 1];
|
||||
else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))
|
||||
baud = baud_sup[i - 1];
|
||||
else
|
||||
baud = baud_sup[i];
|
||||
|
||||
return baud;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: If unsupported baud rates are set directly, the PL2303 seems to
|
||||
* use 9600 baud.
|
||||
*/
|
||||
static uint32_t pl2303_encode_baud_rate_direct(unsigned char buf[4],
|
||||
uint32_t baud)
|
||||
{
|
||||
memcpy(buf, &baud, 4);
|
||||
|
||||
return baud;
|
||||
}
|
||||
|
||||
static uint32_t pl2303_encode_baud_rate_divisor_alt(unsigned char buf[4],
|
||||
uint32_t baud)
|
||||
{
|
||||
unsigned int baseline, mantissa, exponent;
|
||||
|
||||
/*
|
||||
* Apparently, for the TA version the formula is:
|
||||
* baudrate = 12M * 32 / (mantissa * 2^exponent)
|
||||
* where
|
||||
* mantissa = buf[10:0]
|
||||
* exponent = buf[15:13 16]
|
||||
*/
|
||||
baseline = 12000000 * 32;
|
||||
mantissa = baseline / baud;
|
||||
if (mantissa == 0)
|
||||
mantissa = 1; /* Avoid dividing by zero if baud > 32*12M. */
|
||||
exponent = 0;
|
||||
while (mantissa >= 2048) {
|
||||
if (exponent < 15) {
|
||||
mantissa >>= 1; /* divide by 2 */
|
||||
exponent++;
|
||||
} else {
|
||||
/* Exponent is maxed. Trim mantissa and leave. */
|
||||
mantissa = 2047;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
buf[3] = 0x80;
|
||||
buf[2] = exponent & 0x01;
|
||||
buf[1] = (exponent & ~0x01) << 4 | mantissa >> 8;
|
||||
buf[0] = mantissa & 0xff;
|
||||
|
||||
/* Calculate and return the exact baud rate. */
|
||||
baud = (baseline / mantissa) >> exponent;
|
||||
|
||||
return baud;
|
||||
}
|
||||
|
||||
static uint32_t pl2303_encode_baud_rate_divisor(unsigned char buf[4],
|
||||
uint32_t baud)
|
||||
{
|
||||
unsigned int baseline, mantissa, exponent;
|
||||
|
||||
/*
|
||||
* Apparently the formula is:
|
||||
* baudrate = 12M * 32 / (mantissa * 4^exponent)
|
||||
* where
|
||||
* mantissa = buf[8:0]
|
||||
* exponent = buf[11:9]
|
||||
*/
|
||||
baseline = 12000000 * 32;
|
||||
mantissa = baseline / baud;
|
||||
if (mantissa == 0)
|
||||
mantissa = 1; /* Avoid dividing by zero if baud > 32*12M. */
|
||||
exponent = 0;
|
||||
while (mantissa >= 512) {
|
||||
if (exponent < 7) {
|
||||
mantissa >>= 2; /* divide by 4 */
|
||||
exponent++;
|
||||
} else {
|
||||
/* Exponent is maxed. Trim mantissa and leave. */
|
||||
mantissa = 511;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
buf[3] = 0x80;
|
||||
buf[2] = 0;
|
||||
buf[1] = exponent << 1 | mantissa >> 8;
|
||||
buf[0] = mantissa & 0xff;
|
||||
|
||||
/* Calculate and return the exact baud rate. */
|
||||
baud = (baseline / mantissa) >> (exponent << 1);
|
||||
|
||||
return baud;
|
||||
}
|
||||
|
||||
static int pl2303_vendor_write(struct usbh_serial *serial, uint16_t wValue, uint16_t wIndex)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
struct usbh_pl2303 *pl2303_class;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->hport->setup;
|
||||
pl2303_class = (struct usbh_pl2303 *)serial->priv;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = pl2303_class->chip_type == TYPE_HXN ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST;
|
||||
setup->wValue = wValue;
|
||||
setup->wIndex = wIndex;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(serial->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int pl2303_vendor_read(struct usbh_serial *serial, uint16_t wValue, uint8_t *data)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
struct usbh_pl2303 *pl2303_class;
|
||||
int ret;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = serial->hport->setup;
|
||||
pl2303_class = (struct usbh_pl2303 *)serial->priv;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = pl2303_class->chip_type == TYPE_HXN ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST;
|
||||
setup->wValue = wValue;
|
||||
setup->wIndex = 0;
|
||||
setup->wLength = 1;
|
||||
|
||||
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
memcpy(data, serial->iobuffer, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool pl2303_supports_hx_status(struct usbh_serial *serial)
|
||||
{
|
||||
int ret;
|
||||
uint8_t buf;
|
||||
|
||||
ret = pl2303_vendor_read(serial, PL2303_READ_TYPE_HX_STATUS, &buf);
|
||||
if (ret < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool pl2303_is_hxd_clone(struct usbh_serial *serial)
|
||||
{
|
||||
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_DEVICE;
|
||||
setup->bRequest = CDC_REQUEST_GET_LINE_CODING;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = 0;
|
||||
setup->wLength = 7;
|
||||
|
||||
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
|
||||
if (ret < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int pl2303_update_reg(struct usbh_serial *serial, uint8_t reg, uint8_t mask, uint8_t val)
|
||||
{
|
||||
int ret;
|
||||
uint8_t buf[1];
|
||||
struct usbh_pl2303 *pl2303_class;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
pl2303_class = (struct usbh_pl2303 *)serial->priv;
|
||||
|
||||
if (pl2303_class->chip_type == TYPE_HXN)
|
||||
ret = pl2303_vendor_read(serial, reg, buf);
|
||||
else
|
||||
ret = pl2303_vendor_read(serial, reg | 0x80, buf);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
*buf &= ~mask;
|
||||
*buf |= val & mask;
|
||||
|
||||
return pl2303_vendor_write(serial, reg, *buf);
|
||||
}
|
||||
|
||||
static int usbh_pl2303_get_chiptype(struct usbh_serial *serial)
|
||||
{
|
||||
if (serial->hport->device_desc.bDeviceClass == 0x02) {
|
||||
return TYPE_H; /* variant 0 */
|
||||
}
|
||||
|
||||
if (serial->hport->device_desc.bMaxPacketSize0 != 0x40) {
|
||||
if (serial->hport->device_desc.bDeviceClass == 0x00 || serial->hport->device_desc.bDeviceClass == 0xff)
|
||||
return TYPE_H; /* variant 1 */
|
||||
|
||||
return TYPE_H; /* variant 0 */
|
||||
}
|
||||
|
||||
switch (serial->hport->device_desc.bcdUSB) {
|
||||
case 0x101:
|
||||
/* USB 1.0.1? Let's assume they meant 1.1... */
|
||||
case 0x110:
|
||||
switch (serial->hport->device_desc.bcdDevice) {
|
||||
case 0x300:
|
||||
return TYPE_HX;
|
||||
case 0x400:
|
||||
return TYPE_HXD;
|
||||
default:
|
||||
return TYPE_HX;
|
||||
}
|
||||
break;
|
||||
case 0x200:
|
||||
switch (serial->hport->device_desc.bcdDevice) {
|
||||
case 0x100: /* GC */
|
||||
case 0x105:
|
||||
return TYPE_HXN;
|
||||
case 0x300: /* GT / TA */
|
||||
if (pl2303_supports_hx_status(serial))
|
||||
return TYPE_TA;
|
||||
__attribute__((fallthrough));
|
||||
case 0x305:
|
||||
case 0x400: /* GL */
|
||||
case 0x405:
|
||||
return TYPE_HXN;
|
||||
case 0x500: /* GE / TB */
|
||||
if (pl2303_supports_hx_status(serial))
|
||||
return TYPE_TB;
|
||||
__attribute__((fallthrough));
|
||||
case 0x505:
|
||||
case 0x600: /* GS */
|
||||
case 0x605:
|
||||
case 0x700: /* GR */
|
||||
case 0x705:
|
||||
case 0x905: /* GT-2AB */
|
||||
case 0x1005: /* GC-Q20 */
|
||||
return TYPE_HXN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
USB_LOG_ERR("Unsupported PL2303 Device\r\n");
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
|
||||
static int usbh_pl2303_attach(struct usbh_serial *serial)
|
||||
{
|
||||
struct usbh_pl2303 *pl2303_class;
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
uint8_t type;
|
||||
int ret;
|
||||
|
||||
ret = usbh_pl2303_get_chiptype(serial);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
pl2303_class = usb_osal_malloc(sizeof(struct usbh_pl2303));
|
||||
if (pl2303_class == NULL) {
|
||||
USB_LOG_ERR("Fail to alloc pl2303_class\r\n");
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
memset(pl2303_class, 0, sizeof(struct usbh_pl2303));
|
||||
serial->priv = pl2303_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(pl2303_class->intin, ep_desc);
|
||||
break;
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pl2303_class->intin) {
|
||||
USB_LOG_ERR("Failed to find interrupt endpoint\r\n");
|
||||
ret = -USB_ERR_NODEV;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
type = (uint8_t)ret;
|
||||
pl2303_class->chip_type = type;
|
||||
pl2303_class->quirks = pl2303_type_data[pl2303_class->chip_type].quirks;
|
||||
|
||||
USB_LOG_INFO("chip type: %s\r\n", pl2303_type_data[pl2303_class->chip_type].name);
|
||||
|
||||
if (type == TYPE_HXD && pl2303_is_hxd_clone(serial)) {
|
||||
pl2303_class->quirks |= PL2303_QUIRK_NO_BREAK_GETLINE;
|
||||
}
|
||||
|
||||
if (type != TYPE_HXN) {
|
||||
uint8_t buf[1];
|
||||
ret = pl2303_vendor_read(serial, 0x8484, buf);
|
||||
ret |= pl2303_vendor_write(serial, 0x0404, 0);
|
||||
ret |= pl2303_vendor_read(serial, 0x8484, buf);
|
||||
ret |= pl2303_vendor_read(serial, 0x8383, buf);
|
||||
ret |= pl2303_vendor_read(serial, 0x8484, buf);
|
||||
ret |= pl2303_vendor_write(serial, 0x0404, 1);
|
||||
ret |= pl2303_vendor_read(serial, 0x8484, buf);
|
||||
ret |= pl2303_vendor_read(serial, 0x8383, buf);
|
||||
ret |= pl2303_vendor_write(serial, 0, 1);
|
||||
ret |= pl2303_vendor_write(serial, 1, 0);
|
||||
if (pl2303_class->quirks & PL2303_QUIRK_LEGACY)
|
||||
ret |= pl2303_vendor_write(serial, 2, 0x24);
|
||||
else
|
||||
ret |= pl2303_vendor_write(serial, 2, 0x44);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
USB_LOG_ERR("pl2303 init failed\r\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
serial->priv = NULL;
|
||||
usb_osal_free(pl2303_class);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usbh_pl2303_detach(struct usbh_serial *serial)
|
||||
{
|
||||
struct usbh_pl2303 *pl2303_class;
|
||||
|
||||
if (!serial || !serial->priv) {
|
||||
return;
|
||||
}
|
||||
|
||||
pl2303_class = (struct usbh_pl2303 *)serial->priv;
|
||||
if (pl2303_class->intin) {
|
||||
usbh_kill_urb(&pl2303_class->intin_urb);
|
||||
}
|
||||
serial->priv = NULL;
|
||||
usb_osal_free(pl2303_class);
|
||||
}
|
||||
|
||||
static int usbh_pl2303_set_flow_ctrl(struct usbh_serial *serial, bool hardctrl)
|
||||
{
|
||||
struct usbh_pl2303 *pl2303_class;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
pl2303_class = (struct usbh_pl2303 *)serial->priv;
|
||||
|
||||
if (hardctrl) {
|
||||
if (pl2303_class->quirks & PL2303_QUIRK_LEGACY) {
|
||||
return pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x40);
|
||||
} else if (pl2303_class->chip_type == TYPE_HXN) {
|
||||
return pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
|
||||
PL2303_HXN_FLOWCTRL_MASK,
|
||||
PL2303_HXN_FLOWCTRL_RTS_CTS);
|
||||
} else {
|
||||
return pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x60);
|
||||
}
|
||||
} else {
|
||||
if (pl2303_class->chip_type == TYPE_HXN) {
|
||||
return pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
|
||||
PL2303_HXN_FLOWCTRL_MASK,
|
||||
PL2303_HXN_FLOWCTRL_NONE);
|
||||
} else {
|
||||
return pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int usbh_pl2303_set_line_coding(struct usbh_serial *serial, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
struct usbh_pl2303 *pl2303_class;
|
||||
uint32_t baud;
|
||||
uint32_t baud_sup;
|
||||
uint8_t buf[7];
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
setup = serial->hport->setup;
|
||||
pl2303_class = (struct usbh_pl2303 *)serial->priv;
|
||||
|
||||
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;
|
||||
|
||||
baud = line_coding->dwDTERate;
|
||||
if (pl2303_type_data[pl2303_class->chip_type].max_baud_rate) {
|
||||
baud = MIN(baud, pl2303_type_data[pl2303_class->chip_type].max_baud_rate);
|
||||
}
|
||||
/*
|
||||
* Use direct method for supported baud rates, otherwise use divisors.
|
||||
* Newer chip types do not support divisor encoding.
|
||||
*/
|
||||
if (pl2303_type_data[pl2303_class->chip_type].no_divisors)
|
||||
baud_sup = baud;
|
||||
else
|
||||
baud_sup = pl2303_get_supported_baud_rate(baud);
|
||||
|
||||
if (baud == baud_sup)
|
||||
baud = pl2303_encode_baud_rate_direct(buf, baud);
|
||||
else if (pl2303_type_data[pl2303_class->chip_type].alt_divisors)
|
||||
baud = pl2303_encode_baud_rate_divisor_alt(buf, baud);
|
||||
else
|
||||
baud = pl2303_encode_baud_rate_divisor(buf, baud);
|
||||
|
||||
buf[4] = line_coding->bCharFormat;
|
||||
buf[5] = line_coding->bParityType;
|
||||
buf[6] = line_coding->bDataBits;
|
||||
|
||||
memcpy(serial->iobuffer, buf, sizeof(struct cdc_line_coding));
|
||||
|
||||
return usbh_control_transfer(serial->hport, setup, serial->iobuffer);
|
||||
}
|
||||
|
||||
static int usbh_pl2303_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_pl2303_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_pl2303_get_modem_status(struct usbh_serial *serial)
|
||||
{
|
||||
struct usbh_pl2303 *pl2303_class;
|
||||
uintptr_t flags;
|
||||
uint16_t status;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
pl2303_class = (struct usbh_pl2303 *)serial->priv;
|
||||
|
||||
status = (pl2303_class->modem_status & UART_DSR ? USBH_SERIAL_TIOCM_DSR : 0) |
|
||||
(pl2303_class->modem_status & UART_CTS ? USBH_SERIAL_TIOCM_CTS : 0) |
|
||||
(pl2303_class->modem_status & UART_RING ? USBH_SERIAL_TIOCM_RI : 0) |
|
||||
(pl2303_class->modem_status & UART_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_pl2303_get_modem_status(struct usbh_serial *serial)
|
||||
{
|
||||
struct usbh_pl2303 *pl2303_class;
|
||||
uint8_t status = 0;
|
||||
uint16_t difference;
|
||||
uintptr_t flags;
|
||||
int ret;
|
||||
|
||||
if (!serial || !serial->hport || !serial->priv) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
pl2303_class = (struct usbh_pl2303 *)serial->priv;
|
||||
|
||||
usbh_int_urb_fill(&pl2303_class->intin_urb, serial->hport, pl2303_class->intin, &serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET], pl2303_class->intin->wMaxPacketSize, 0xffffffff, NULL, NULL);
|
||||
ret = usbh_submit_urb(&pl2303_class->intin_urb);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret < 1) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
|
||||
status = serial->iobuffer[USBH_SERIAL_INT_NOCACHE_OFFSET];
|
||||
difference = pl2303_class->modem_status ^ status;
|
||||
pl2303_class->modem_status = status;
|
||||
|
||||
if (status & UART_BREAK_ERROR)
|
||||
serial->iocount.brk++;
|
||||
|
||||
if (difference & UART_STATE_MSR_MASK) {
|
||||
if (difference & UART_CTS)
|
||||
serial->iocount.cts++;
|
||||
if (difference & UART_DSR)
|
||||
serial->iocount.dsr++;
|
||||
if (difference & UART_RING)
|
||||
serial->iocount.rng++;
|
||||
if (difference & UART_DCD) {
|
||||
serial->iocount.dcd++;
|
||||
}
|
||||
}
|
||||
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct usbh_serial_driver pl2303_driver = {
|
||||
.driver_name = "pl2303",
|
||||
|
||||
.ignore_rx_header = 0,
|
||||
.ignore_tx_header = 0,
|
||||
|
||||
.attach = usbh_pl2303_attach,
|
||||
.detach = usbh_pl2303_detach,
|
||||
.set_flow_control = usbh_pl2303_set_flow_ctrl,
|
||||
.set_line_coding = usbh_pl2303_set_line_coding,
|
||||
.get_line_coding = usbh_pl2303_get_line_coding,
|
||||
.set_line_state = usbh_pl2303_set_line_state,
|
||||
.get_modem_status = usbh_pl2303_get_modem_status,
|
||||
};
|
||||
|
||||
static int usbh_pl2303_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
return usbh_serial_probe(hport, intf, &pl2303_driver) ? 0 : -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
static int usbh_pl2303_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 pl2303_id_table[][2] = {
|
||||
{ 0x067B, 0x2303 }, // PL2303 Serial (ATEN/IOGEAR UC232A)
|
||||
{ 0x067B, 0x2304 }, // PL2303HXN Serial, type TB
|
||||
{ 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
|
||||
};
|
||||
43
class/serial/usbh_pl2303.h
Normal file
43
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
class/serial/usbh_serial.c
Normal file
743
class/serial/usbh_serial.c
Normal file
@@ -0,0 +1,743 @@
|
||||
/*
|
||||
* Copyright (c) 2025, sakumisu
|
||||
* Copyright (c) 2025, MDLZCOOL
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_serial.h"
|
||||
|
||||
#undef USB_DBG_TAG
|
||||
#define USB_DBG_TAG "usbh_serial"
|
||||
#include "usb_log.h"
|
||||
|
||||
#define DEV_FORMAT_VENDOR "/dev/ttyUSB%d"
|
||||
#define DEV_FORMAT_CDC_ACM "/dev/ttyACM%d"
|
||||
|
||||
#define CONFIG_USBHOST_MAX_SERIAL_CLASS 4
|
||||
|
||||
static struct usbh_serial g_serial_class[CONFIG_USBHOST_MAX_SERIAL_CLASS];
|
||||
|
||||
static uint32_t g_devinuse = 0;
|
||||
static uint32_t g_cdcacm_devinuse = 0;
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_serial_iobuffer[CONFIG_USBHOST_MAX_SERIAL_CLASS][USB_ALIGN_UP((USBH_SERIAL_RX2_NOCACHE_OFFSET + USBH_SERIAL_RX2_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)];
|
||||
|
||||
/* refer to cherryrb */
|
||||
static int usbh_serial_ringbuffer_init(usbh_serial_ringbuf_t *rb, void *pool, uint32_t size)
|
||||
{
|
||||
if (NULL == rb) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NULL == pool) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((size < 2) || (size & (size - 1))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rb->in = 0;
|
||||
rb->out = 0;
|
||||
rb->mask = size - 1;
|
||||
rb->pool = pool;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usbh_serial_ringbuffer_reset(usbh_serial_ringbuf_t *rb)
|
||||
{
|
||||
rb->in = 0;
|
||||
rb->out = 0;
|
||||
}
|
||||
|
||||
static uint32_t usbh_serial_ringbuffer_get_used(usbh_serial_ringbuf_t *rb)
|
||||
{
|
||||
return rb->in - rb->out;
|
||||
}
|
||||
|
||||
static uint32_t usbh_serial_ringbuffer_write(usbh_serial_ringbuf_t *rb, void *data, uint32_t size)
|
||||
{
|
||||
uint32_t unused;
|
||||
uint32_t offset;
|
||||
uint32_t remain;
|
||||
|
||||
unused = (rb->mask + 1) - (rb->in - rb->out);
|
||||
|
||||
if (size > unused) {
|
||||
size = unused;
|
||||
}
|
||||
|
||||
offset = rb->in & rb->mask;
|
||||
|
||||
remain = rb->mask + 1 - offset;
|
||||
remain = remain > size ? size : remain;
|
||||
|
||||
memcpy(((uint8_t *)(rb->pool)) + offset, data, remain);
|
||||
memcpy(rb->pool, (uint8_t *)data + remain, size - remain);
|
||||
|
||||
rb->in += size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static uint32_t usbh_serial_ringbuffer_peek(usbh_serial_ringbuf_t *rb, void *data, uint32_t size)
|
||||
{
|
||||
uint32_t used;
|
||||
uint32_t offset;
|
||||
uint32_t remain;
|
||||
|
||||
used = rb->in - rb->out;
|
||||
if (size > used) {
|
||||
size = used;
|
||||
}
|
||||
|
||||
offset = rb->out & rb->mask;
|
||||
|
||||
remain = rb->mask + 1 - offset;
|
||||
remain = remain > size ? size : remain;
|
||||
|
||||
memcpy(data, ((uint8_t *)(rb->pool)) + offset, remain);
|
||||
memcpy((uint8_t *)data + remain, rb->pool, size - remain);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static uint32_t usbh_serial_ringbuffer_read(usbh_serial_ringbuf_t *rb, void *data, uint32_t size)
|
||||
{
|
||||
size = usbh_serial_ringbuffer_peek(rb, data, size);
|
||||
rb->out += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
static struct usbh_serial *usbh_serial_alloc(bool is_cdcacm)
|
||||
{
|
||||
uint8_t devno;
|
||||
uint8_t devno2;
|
||||
|
||||
for (devno = 0; devno < CONFIG_USBHOST_MAX_SERIAL_CLASS; devno++) {
|
||||
if ((g_devinuse & (1U << devno)) == 0) {
|
||||
g_devinuse |= (1U << devno);
|
||||
memset(&g_serial_class[devno], 0, sizeof(struct usbh_serial));
|
||||
g_serial_class[devno].minor = devno;
|
||||
g_serial_class[devno].cdc_minor = -1;
|
||||
g_serial_class[devno].iobuffer = g_serial_iobuffer[devno];
|
||||
g_serial_class[devno].rx_complete_sem = usb_osal_sem_create(0);
|
||||
|
||||
if (is_cdcacm) {
|
||||
for (devno2 = 0; devno2 < CONFIG_USBHOST_MAX_SERIAL_CLASS; devno2++) {
|
||||
if ((g_cdcacm_devinuse & (1U << devno2)) == 0) {
|
||||
g_cdcacm_devinuse |= (1U << devno2);
|
||||
g_serial_class[devno].cdc_minor = devno2;
|
||||
return &g_serial_class[devno];
|
||||
}
|
||||
}
|
||||
|
||||
g_devinuse &= ~(1U << devno);
|
||||
return NULL;
|
||||
} else {
|
||||
return &g_serial_class[devno];
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void usbh_serial_free(struct usbh_serial *serial)
|
||||
{
|
||||
uint8_t devno = serial->minor;
|
||||
if (devno < 32) {
|
||||
g_devinuse &= ~(1U << devno);
|
||||
}
|
||||
|
||||
if (serial->cdc_minor >= 0) {
|
||||
g_cdcacm_devinuse &= ~(1U << serial->cdc_minor);
|
||||
}
|
||||
|
||||
if (g_serial_class[devno].rx_complete_sem) {
|
||||
usb_osal_sem_delete(g_serial_class[devno].rx_complete_sem);
|
||||
}
|
||||
}
|
||||
|
||||
static void usbh_serial_callback(void *arg, int nbytes)
|
||||
{
|
||||
struct usbh_serial *serial = (struct usbh_serial *)arg;
|
||||
int ret;
|
||||
|
||||
if (nbytes < 0) {
|
||||
if (nbytes != -USB_ERR_SHUTDOWN) {
|
||||
USB_LOG_ERR("serial transfer error: %d\n", nbytes);
|
||||
}
|
||||
serial->rx_errorcode = nbytes;
|
||||
usb_osal_sem_give(serial->rx_complete_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nbytes < serial->driver->ignore_rx_header) {
|
||||
USB_LOG_ERR("serial rx short packet: %d\n", nbytes);
|
||||
serial->rx_errorcode = -USB_ERR_IO;
|
||||
usb_osal_sem_give(serial->rx_complete_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nbytes >= serial->driver->ignore_rx_header) {
|
||||
/* resubmit the read urb */
|
||||
usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX_NOCACHE_OFFSET : USBH_SERIAL_RX2_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
|
||||
0, usbh_serial_callback, serial);
|
||||
ret = usbh_submit_urb(&serial->bulkin_urb);
|
||||
if (ret < 0) {
|
||||
USB_LOG_ERR("serial submit failed: %d\n", ret);
|
||||
serial->rx_errorcode = ret;
|
||||
usb_osal_sem_give(serial->rx_complete_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
usbh_serial_ringbuffer_write(&serial->rx_rb,
|
||||
&serial->iobuffer[(serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET) + serial->driver->ignore_rx_header],
|
||||
(nbytes - serial->driver->ignore_rx_header));
|
||||
|
||||
if (serial->rx_complete_callback) {
|
||||
serial->rx_complete_callback(serial, nbytes - serial->driver->ignore_rx_header);
|
||||
}
|
||||
serial->rx_buf_index ^= 1;
|
||||
serial->rx_errorcode = 0;
|
||||
usb_osal_sem_give(serial->rx_complete_sem);
|
||||
}
|
||||
}
|
||||
|
||||
struct usbh_serial *usbh_serial_probe(struct usbh_hubport *hport, uint8_t intf,
|
||||
const struct usbh_serial_driver *driver)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
struct usbh_serial *serial;
|
||||
bool is_cdcacm = false;
|
||||
int ret;
|
||||
|
||||
if (strcmp(driver->driver_name, "cdc_acm") == 0) {
|
||||
is_cdcacm = true;
|
||||
}
|
||||
|
||||
serial = usbh_serial_alloc(is_cdcacm);
|
||||
if (serial == NULL) {
|
||||
USB_LOG_ERR("Fail to alloc serial class\r\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
serial->hport = hport;
|
||||
serial->intf = intf;
|
||||
serial->driver = driver;
|
||||
|
||||
if (driver->attach) {
|
||||
ret = driver->attach(serial);
|
||||
if (ret < 0) {
|
||||
USB_LOG_ERR("Serial attach failed: %d\r\n", ret);
|
||||
usbh_serial_free(serial);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_cdcacm) {
|
||||
intf = intf + 1; /* data interface */
|
||||
}
|
||||
|
||||
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_BULK) {
|
||||
if (ep_desc->bEndpointAddress & 0x80) {
|
||||
USBH_EP_INIT(serial->bulkin, ep_desc);
|
||||
} else {
|
||||
USBH_EP_INIT(serial->bulkout, ep_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_cdcacm) {
|
||||
intf = intf - 1; /* data interface */
|
||||
}
|
||||
|
||||
if (!serial->bulkin || !serial->bulkout) {
|
||||
USB_LOG_ERR("Serial bulk in/out endpoint not found\r\n");
|
||||
usbh_serial_free(serial);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (is_cdcacm) {
|
||||
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT_CDC_ACM, serial->cdc_minor);
|
||||
} else {
|
||||
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT_VENDOR, serial->minor);
|
||||
}
|
||||
|
||||
hport->config.intf[intf].priv = serial;
|
||||
USB_LOG_INFO("Register Serial Class: %s (%s)\r\n", hport->config.intf[intf].devname, driver->driver_name);
|
||||
|
||||
usbh_serial_run(serial);
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
void usbh_serial_remove(struct usbh_serial *serial)
|
||||
{
|
||||
if (!serial || !serial->hport)
|
||||
return;
|
||||
|
||||
usbh_serial_close(serial);
|
||||
|
||||
if (serial->driver && serial->driver->detach) {
|
||||
serial->driver->detach(serial);
|
||||
}
|
||||
|
||||
if (serial->hport->config.intf[serial->intf].priv) {
|
||||
usb_osal_thread_schedule_other();
|
||||
USB_LOG_INFO("Unregister Serial Class: %s (%s)\r\n", serial->hport->config.intf[serial->intf].devname, serial->driver->driver_name);
|
||||
usbh_serial_stop(serial);
|
||||
}
|
||||
|
||||
usbh_serial_free(serial);
|
||||
}
|
||||
|
||||
struct usbh_serial *usbh_serial_open(const char *devname, uint32_t open_flags)
|
||||
{
|
||||
struct usbh_serial *serial;
|
||||
int ret;
|
||||
|
||||
serial = usbh_find_class_instance(devname);
|
||||
if (!serial) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (serial->ref_count != 0) {
|
||||
USB_LOG_ERR("Device busy: %s\r\n", devname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (serial && serial->driver && serial->driver->open) {
|
||||
ret = serial->driver->open(serial);
|
||||
if (ret < 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
usbh_serial_ringbuffer_init(&serial->rx_rb, serial->rx_rb_pool, CONFIG_USBHOST_SERIAL_RX_SIZE);
|
||||
|
||||
serial->ref_count++;
|
||||
serial->open_flags = open_flags;
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
int usbh_serial_close(struct usbh_serial *serial)
|
||||
{
|
||||
if (!serial || !serial->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
if (serial->ref_count == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (serial->bulkin) {
|
||||
usbh_kill_urb(&serial->bulkin_urb);
|
||||
}
|
||||
if (serial->bulkout) {
|
||||
usbh_kill_urb(&serial->bulkout_urb);
|
||||
}
|
||||
|
||||
if (serial && serial->driver && serial->driver->set_flow_control && serial->rtscts) {
|
||||
serial->driver->set_flow_control(serial, false);
|
||||
}
|
||||
|
||||
if (serial && serial->driver && serial->driver->close) {
|
||||
serial->driver->close(serial);
|
||||
}
|
||||
|
||||
serial->ref_count--;
|
||||
serial->rtscts = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbh_serial_tiocmset(struct usbh_serial *serial, uint32_t set, uint32_t clear)
|
||||
{
|
||||
int ret;
|
||||
uint16_t line_state;
|
||||
bool dtr;
|
||||
bool rts;
|
||||
|
||||
if (!serial || !serial->hport || !serial->hport->connected) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
if (serial->ref_count == 0) {
|
||||
return -USB_ERR_NODEV;
|
||||
}
|
||||
|
||||
line_state = serial->line_state;
|
||||
clear &= ~set; /* 'set' takes precedence over 'clear' */
|
||||
|
||||
if (set & USBH_SERIAL_TIOCM_DTR) {
|
||||
line_state |= USBH_SERIAL_TIOCM_DTR;
|
||||
}
|
||||
if (set & USBH_SERIAL_TIOCM_RTS) {
|
||||
line_state |= USBH_SERIAL_TIOCM_RTS;
|
||||
}
|
||||
if (clear & USBH_SERIAL_TIOCM_DTR) {
|
||||
line_state &= ~USBH_SERIAL_TIOCM_DTR;
|
||||
}
|
||||
if (clear & USBH_SERIAL_TIOCM_RTS) {
|
||||
line_state &= ~USBH_SERIAL_TIOCM_RTS;
|
||||
}
|
||||
|
||||
dtr = (line_state & USBH_SERIAL_TIOCM_DTR) ? true : false;
|
||||
rts = (line_state & USBH_SERIAL_TIOCM_RTS) ? true : false;
|
||||
|
||||
if (serial && serial->driver && serial->driver->set_line_state) {
|
||||
ret = serial->driver->set_line_state(serial, dtr, rts);
|
||||
} else {
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
serial->line_state = line_state;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_serial_control(struct usbh_serial *serial, int cmd, void *arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!serial || !serial->hport || !serial->hport->connected) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
if (serial->ref_count == 0) {
|
||||
return -USB_ERR_NODEV;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case USBH_SERIAL_CMD_SET_ATTR: {
|
||||
struct usbh_serial_termios *termios = (struct usbh_serial_termios *)arg;
|
||||
struct cdc_line_coding line_coding;
|
||||
|
||||
line_coding.dwDTERate = termios->baudrate;
|
||||
line_coding.bCharFormat = termios->stopbits;
|
||||
line_coding.bParityType = termios->parity;
|
||||
line_coding.bDataBits = termios->databits;
|
||||
|
||||
if (serial->bulkin) {
|
||||
usbh_kill_urb(&serial->bulkin_urb);
|
||||
}
|
||||
if (serial->bulkout) {
|
||||
usbh_kill_urb(&serial->bulkout_urb);
|
||||
}
|
||||
|
||||
if (serial && serial->driver && serial->driver->set_line_coding) {
|
||||
ret = serial->driver->set_line_coding(serial, &line_coding);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
|
||||
memcpy(&serial->line_coding, &line_coding, sizeof(struct cdc_line_coding));
|
||||
|
||||
if (serial && serial->driver && serial->driver->set_flow_control) {
|
||||
ret = serial->driver->set_flow_control(serial, termios->rtscts);
|
||||
}
|
||||
|
||||
serial->rtscts = termios->rtscts;
|
||||
serial->rx_timeout_ms = termios->rx_timeout;
|
||||
|
||||
ret = usbh_serial_tiocmset(serial, USBH_SERIAL_TIOCM_DTR | USBH_SERIAL_TIOCM_RTS, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
usbh_serial_ringbuffer_reset(&serial->rx_rb);
|
||||
usb_osal_sem_reset(serial->rx_complete_sem);
|
||||
serial->rx_buf_index = 0;
|
||||
usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
|
||||
0, usbh_serial_callback, serial);
|
||||
ret = usbh_submit_urb(&serial->bulkin_urb);
|
||||
|
||||
return ret;
|
||||
} break;
|
||||
case USBH_SERIAL_CMD_GET_ATTR: {
|
||||
struct usbh_serial_termios *termios = (struct usbh_serial_termios *)arg;
|
||||
struct cdc_line_coding line_coding;
|
||||
|
||||
if (serial && serial->driver && serial->driver->get_line_coding) {
|
||||
return serial->driver->get_line_coding(serial, &line_coding);
|
||||
} else {
|
||||
memcpy(&line_coding, &serial->line_coding, sizeof(struct cdc_line_coding));
|
||||
}
|
||||
|
||||
termios->baudrate = line_coding.dwDTERate;
|
||||
termios->stopbits = line_coding.bCharFormat;
|
||||
termios->parity = line_coding.bParityType;
|
||||
termios->databits = line_coding.bDataBits;
|
||||
termios->rtscts = serial->rtscts;
|
||||
termios->rx_timeout = serial->rx_timeout_ms;
|
||||
return 0;
|
||||
} break;
|
||||
case USBH_SERIAL_CMD_IOCMBIS: {
|
||||
uint32_t flags = *(uint32_t *)arg;
|
||||
|
||||
return usbh_serial_tiocmset(serial, flags, 0);
|
||||
} break;
|
||||
case USBH_SERIAL_CMD_IOCMBIC: {
|
||||
uint32_t flags = *(uint32_t *)arg;
|
||||
|
||||
return usbh_serial_tiocmset(serial, 0, flags);
|
||||
} break;
|
||||
case USBH_SERIAL_CMD_TIOCMSET: {
|
||||
uint32_t flags = *(uint32_t *)arg;
|
||||
|
||||
uint32_t set = 0;
|
||||
uint32_t clear = 0;
|
||||
|
||||
set |= (flags & USBH_SERIAL_TIOCM_DTR) ? USBH_SERIAL_TIOCM_DTR : 0;
|
||||
set |= (flags & USBH_SERIAL_TIOCM_RTS) ? USBH_SERIAL_TIOCM_RTS : 0;
|
||||
clear |= !(flags & USBH_SERIAL_TIOCM_DTR) ? USBH_SERIAL_TIOCM_DTR : 0;
|
||||
clear |= !(flags & USBH_SERIAL_TIOCM_RTS) ? USBH_SERIAL_TIOCM_RTS : 0;
|
||||
|
||||
return usbh_serial_tiocmset(serial, set, clear);
|
||||
} break;
|
||||
case USBH_SERIAL_CMD_TIOCMGET: {
|
||||
uint32_t *flags = (uint32_t *)arg;
|
||||
int status;
|
||||
|
||||
if (serial && serial->driver && serial->driver->get_modem_status) {
|
||||
status = serial->driver->get_modem_status(serial);
|
||||
if (status < 0) {
|
||||
return status;
|
||||
}
|
||||
} else {
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
*flags = status;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
|
||||
int usbh_serial_write(struct usbh_serial *serial, const void *buffer, uint32_t buflen)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb;
|
||||
|
||||
if (!serial || !serial->hport || !serial->hport->connected || !serial->bulkout) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
if (serial->ref_count == 0) {
|
||||
return -USB_ERR_NODEV;
|
||||
}
|
||||
|
||||
urb = &serial->bulkout_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, serial->hport, serial->bulkout, (uint8_t *)buffer, buflen, 0xffffffff, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_serial_read(struct usbh_serial *serial, void *buffer, uint32_t buflen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!serial || !serial->hport || !serial->hport->connected || !serial->bulkin || !serial->line_coding.dwDTERate) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
if (serial->ref_count == 0) {
|
||||
return -USB_ERR_NODEV;
|
||||
}
|
||||
|
||||
if (serial->open_flags & USBH_SERIAL_O_NONBLOCK) {
|
||||
return usbh_serial_ringbuffer_read(&serial->rx_rb, buffer, buflen);
|
||||
} else {
|
||||
if (usbh_serial_ringbuffer_get_used(&serial->rx_rb) == 0) {
|
||||
ret = usb_osal_sem_take(serial->rx_complete_sem, serial->rx_timeout_ms == 0 ? USB_OSAL_WAITING_FOREVER : serial->rx_timeout_ms);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (serial->rx_errorcode < 0) {
|
||||
return serial->rx_errorcode;
|
||||
}
|
||||
}
|
||||
return usbh_serial_ringbuffer_read(&serial->rx_rb, buffer, buflen);
|
||||
}
|
||||
}
|
||||
|
||||
int usbh_serial_cdc_write_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg)
|
||||
{
|
||||
struct usbh_urb *urb;
|
||||
|
||||
if (!serial || !serial->hport || !serial->hport->connected || !serial->bulkout || !complete || serial->line_coding.dwDTERate) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
if (serial->ref_count == 0) {
|
||||
return -USB_ERR_NODEV;
|
||||
}
|
||||
|
||||
urb = &serial->bulkout_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, serial->hport, serial->bulkout, buffer, buflen,
|
||||
0, complete, serial);
|
||||
return usbh_submit_urb(urb);
|
||||
}
|
||||
|
||||
int usbh_serial_cdc_read_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg)
|
||||
{
|
||||
struct usbh_urb *urb;
|
||||
|
||||
if (!serial || !serial->hport || !serial->hport->connected || !serial->bulkin || !complete || serial->line_coding.dwDTERate) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
if (serial->ref_count == 0) {
|
||||
return -USB_ERR_NODEV;
|
||||
}
|
||||
|
||||
if (buflen % serial->bulkin->wMaxPacketSize) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
|
||||
urb = &serial->bulkin_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, serial->hport, serial->bulkin, buffer, MIN(buflen, serial->bulkin->wMaxPacketSize),
|
||||
0, complete, serial);
|
||||
return usbh_submit_urb(urb);
|
||||
}
|
||||
|
||||
void usbh_serial_help(void)
|
||||
{
|
||||
USB_LOG_RAW("USB host serial test\r\n"
|
||||
"Usage: usbh_serial <ttypath> [options]...\r\n"
|
||||
"\r\n"
|
||||
"-b <baud> set serial baudrate\r\n"
|
||||
"-t <dtr> <rts> set rts and dtr\r\n"
|
||||
"-w string write string\r\n"
|
||||
"-r read data and dump\r\n"
|
||||
"-x close serial device\r\n"
|
||||
"\r\n");
|
||||
}
|
||||
|
||||
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_serial_testbuffer[512];
|
||||
|
||||
int usbh_serial(int argc, char **argv)
|
||||
{
|
||||
static struct usbh_serial *serial;
|
||||
int ret;
|
||||
|
||||
if (argc < 3) {
|
||||
usbh_serial_help();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (serial) {
|
||||
if (!serial->hport || !serial->hport->connected) {
|
||||
serial = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!serial) {
|
||||
serial = usbh_serial_open(argv[1], USBH_SERIAL_O_RDWR | USBH_SERIAL_O_NONBLOCK);
|
||||
if (!serial) {
|
||||
USB_LOG_ERR("Fail to open serial device: %s\r\n", argv[1]);
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(argv[2], "-b", 2) == 0 && argc >= 4) {
|
||||
struct usbh_serial_termios termios;
|
||||
|
||||
memset(&termios, 0, sizeof(termios));
|
||||
termios.baudrate = atoi(argv[3]);
|
||||
termios.stopbits = 0;
|
||||
termios.parity = 0;
|
||||
termios.databits = 8;
|
||||
termios.rtscts = false;
|
||||
termios.rx_timeout = 0;
|
||||
usbh_serial_control(serial, USBH_SERIAL_CMD_SET_ATTR, &termios);
|
||||
} else if (strncmp(argv[2], "-t", 2) == 0 && argc >= 5) {
|
||||
uint32_t flags;
|
||||
|
||||
flags = atoi(argv[3]) ? USBH_SERIAL_TIOCM_DTR : 0;
|
||||
flags |= atoi(argv[4]) ? USBH_SERIAL_TIOCM_RTS : 0;
|
||||
|
||||
usbh_serial_control(serial, USBH_SERIAL_CMD_TIOCMSET, &flags);
|
||||
USB_LOG_INFO("Set DTR: %d, RTS: %d\r\n", atoi(argv[3]), atoi(argv[4]));
|
||||
} else if (strncmp(argv[2], "-w", 2) == 0 && argc >= 4) {
|
||||
memcpy(g_serial_testbuffer, argv[3], MIN(strlen(argv[3]), sizeof(g_serial_testbuffer)));
|
||||
uint32_t len = snprintf((char *)g_serial_testbuffer, sizeof(g_serial_testbuffer), "%s\r\n", argv[3]);
|
||||
ret = usbh_serial_write(serial, g_serial_testbuffer, len);
|
||||
if (ret >= 0) {
|
||||
USB_LOG_INFO("Write %d bytes\r\n", ret);
|
||||
} else {
|
||||
USB_LOG_ERR("Write failed: %d\r\n", ret);
|
||||
}
|
||||
} else if (strncmp(argv[2], "-r", 2) == 0) {
|
||||
ret = usbh_serial_read(serial, g_serial_testbuffer, sizeof(g_serial_testbuffer));
|
||||
if (ret >= 0) {
|
||||
usb_hexdump(g_serial_testbuffer, ret);
|
||||
USB_LOG_INFO("Read %d bytes\r\n", ret);
|
||||
} else {
|
||||
USB_LOG_ERR("Read failed: %d\r\n", ret);
|
||||
}
|
||||
} else if (strncmp(argv[2], "-x", 2) == 0) {
|
||||
usbh_serial_close(serial);
|
||||
serial = NULL;
|
||||
} else {
|
||||
usbh_serial_help();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__WEAK void usbh_serial_run(struct usbh_serial *serial)
|
||||
{
|
||||
(void)serial;
|
||||
}
|
||||
|
||||
__WEAK void usbh_serial_stop(struct usbh_serial *serial)
|
||||
{
|
||||
(void)serial;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_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
|
||||
};
|
||||
182
class/serial/usbh_serial.h
Normal file
182
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 */
|
||||
10
class/vendor/net/usbh_asix.c
vendored
10
class/vendor/net/usbh_asix.c
vendored
@@ -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 },
|
||||
|
||||
14
class/vendor/net/usbh_rtl8152.c
vendored
14
class/vendor/net/usbh_rtl8152.c
vendored
@@ -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 },
|
||||
|
||||
379
class/vendor/serial/usbh_ch34x.c
vendored
379
class/vendor/serial/usbh_ch34x.c
vendored
@@ -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
|
||||
};
|
||||
76
class/vendor/serial/usbh_ch34x.h
vendored
76
class/vendor/serial/usbh_ch34x.h
vendored
@@ -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 */
|
||||
328
class/vendor/serial/usbh_cp210x.c
vendored
328
class/vendor/serial/usbh_cp210x.c
vendored
@@ -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
|
||||
};
|
||||
73
class/vendor/serial/usbh_cp210x.h
vendored
73
class/vendor/serial/usbh_cp210x.h
vendored
@@ -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 */
|
||||
510
class/vendor/serial/usbh_ftdi.c
vendored
510
class/vendor/serial/usbh_ftdi.c
vendored
@@ -1,510 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_ftdi.h"
|
||||
|
||||
#define DEV_FORMAT "/dev/ttyUSB%d"
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_ftdi_buf[USB_ALIGN_UP(64, CONFIG_USB_ALIGN_SIZE)];
|
||||
|
||||
#define CONFIG_USBHOST_MAX_FTDI_CLASS 1
|
||||
|
||||
static struct usbh_ftdi g_ftdi_class[CONFIG_USBHOST_MAX_FTDI_CLASS];
|
||||
static uint32_t g_devinuse = 0;
|
||||
|
||||
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",
|
||||
};
|
||||
|
||||
static struct usbh_ftdi *usbh_ftdi_class_alloc(void)
|
||||
{
|
||||
uint8_t devno;
|
||||
|
||||
for (devno = 0; devno < CONFIG_USBHOST_MAX_FTDI_CLASS; devno++) {
|
||||
if ((g_devinuse & (1U << devno)) == 0) {
|
||||
g_devinuse |= (1U << devno);
|
||||
memset(&g_ftdi_class[devno], 0, sizeof(struct usbh_ftdi));
|
||||
g_ftdi_class[devno].minor = devno;
|
||||
return &g_ftdi_class[devno];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void usbh_ftdi_class_free(struct usbh_ftdi *ftdi_class)
|
||||
{
|
||||
uint8_t devno = ftdi_class->minor;
|
||||
|
||||
if (devno < 32) {
|
||||
g_devinuse &= ~(1U << devno);
|
||||
}
|
||||
memset(ftdi_class, 0, sizeof(struct usbh_ftdi));
|
||||
}
|
||||
|
||||
/*
|
||||
* Divide positive or negative dividend by positive or negative divisor
|
||||
* and round to closest integer. Result is undefined for negative
|
||||
* divisors if the dividend variable type is unsigned and for negative
|
||||
* dividends if the divisor variable type is unsigned.
|
||||
*/
|
||||
#define DIV_ROUND_CLOSEST(x, divisor) ( \
|
||||
{ \
|
||||
typeof(x) __x = x; \
|
||||
typeof(divisor) __d = divisor; \
|
||||
(((typeof(x))-1) > 0 || \
|
||||
((typeof(divisor))-1) > 0 || \
|
||||
(((__x) > 0) == ((__d) > 0))) ? \
|
||||
(((__x) + ((__d) / 2)) / (__d)) : \
|
||||
(((__x) - ((__d) / 2)) / (__d)); \
|
||||
})
|
||||
|
||||
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_ftdi *ftdi_class)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!ftdi_class || !ftdi_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = ftdi_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = SIO_RESET_REQUEST;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = ftdi_class->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(ftdi_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_set_modem(struct usbh_ftdi *ftdi_class, uint16_t value)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!ftdi_class || !ftdi_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = ftdi_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = SIO_SET_MODEM_CTRL_REQUEST;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = ftdi_class->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(ftdi_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_set_baudrate(struct usbh_ftdi *ftdi_class, uint32_t baudrate)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
uint32_t div_value;
|
||||
uint16_t value;
|
||||
uint8_t baudrate_high;
|
||||
|
||||
if (!ftdi_class || !ftdi_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = ftdi_class->hport->setup;
|
||||
|
||||
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 {
|
||||
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 = SIO_SET_BAUDRATE_REQUEST;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = (baudrate_high << 8) | ftdi_class->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(ftdi_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_set_data_format(struct usbh_ftdi *ftdi_class, uint8_t databits, uint8_t parity, uint8_t stopbits, uint8_t isbreak)
|
||||
{
|
||||
/**
|
||||
* D0-D7 databits BITS_7=7, BITS_8=8
|
||||
* D8-D10 parity NONE=0, ODD=1, EVEN=2, MARK=3, SPACE=4
|
||||
* D11-D12 STOP_BIT_1=0, STOP_BIT_15=1, STOP_BIT_2=2
|
||||
* D14 BREAK_OFF=0, BREAK_ON=1
|
||||
**/
|
||||
struct usb_setup_packet *setup;
|
||||
uint16_t value;
|
||||
|
||||
if (!ftdi_class || !ftdi_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = ftdi_class->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 = SIO_SET_DATA_REQUEST;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = ftdi_class->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(ftdi_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_set_latency_timer(struct usbh_ftdi *ftdi_class, uint16_t value)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!ftdi_class || !ftdi_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = ftdi_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = SIO_SET_LATENCY_TIMER_REQUEST;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = ftdi_class->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(ftdi_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_set_flow_ctrl(struct usbh_ftdi *ftdi_class, uint16_t value)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
|
||||
if (!ftdi_class || !ftdi_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = ftdi_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = SIO_SET_FLOW_CTRL_REQUEST;
|
||||
setup->wValue = value;
|
||||
setup->wIndex = ftdi_class->intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(ftdi_class->hport, setup, NULL);
|
||||
}
|
||||
|
||||
static int usbh_ftdi_read_modem_status(struct usbh_ftdi *ftdi_class)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
int ret;
|
||||
|
||||
if (!ftdi_class || !ftdi_class->hport) {
|
||||
return -USB_ERR_INVAL;
|
||||
}
|
||||
setup = ftdi_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = SIO_POLL_MODEM_STATUS_REQUEST;
|
||||
setup->wValue = 0x0000;
|
||||
setup->wIndex = ftdi_class->intf;
|
||||
setup->wLength = 2;
|
||||
|
||||
ret = usbh_control_transfer(ftdi_class->hport, setup, g_ftdi_buf);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
memcpy(ftdi_class->modem_status, g_ftdi_buf, 2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_ftdi_set_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
memcpy((uint8_t *)&ftdi_class->line_coding, line_coding, sizeof(struct cdc_line_coding));
|
||||
|
||||
int ret = usbh_ftdi_set_baudrate(ftdi_class, line_coding->dwDTERate);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return usbh_ftdi_set_data_format(ftdi_class, line_coding->bDataBits, line_coding->bParityType, line_coding->bCharFormat, 0);
|
||||
}
|
||||
|
||||
int usbh_ftdi_get_line_coding(struct usbh_ftdi *ftdi_class, struct cdc_line_coding *line_coding)
|
||||
{
|
||||
memcpy(line_coding, (uint8_t *)&ftdi_class->line_coding, sizeof(struct cdc_line_coding));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbh_ftdi_set_line_state(struct usbh_ftdi *ftdi_class, bool dtr, bool rts)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (dtr) {
|
||||
usbh_ftdi_set_modem(ftdi_class, SIO_SET_DTR_HIGH);
|
||||
} else {
|
||||
usbh_ftdi_set_modem(ftdi_class, SIO_SET_DTR_LOW);
|
||||
}
|
||||
|
||||
if (rts) {
|
||||
ret = usbh_ftdi_set_modem(ftdi_class, SIO_SET_RTS_HIGH);
|
||||
} else {
|
||||
ret = usbh_ftdi_set_modem(ftdi_class, SIO_SET_RTS_LOW);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_ftdi_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret = 0;
|
||||
uint16_t version;
|
||||
|
||||
struct usbh_ftdi *ftdi_class = usbh_ftdi_class_alloc();
|
||||
if (ftdi_class == NULL) {
|
||||
USB_LOG_ERR("Fail to alloc ftdi_class\r\n");
|
||||
return -USB_ERR_NOMEM;
|
||||
}
|
||||
|
||||
ftdi_class->hport = hport;
|
||||
ftdi_class->intf = intf;
|
||||
|
||||
hport->config.intf[intf].priv = ftdi_class;
|
||||
|
||||
version = hport->device_desc.bcdDevice;
|
||||
|
||||
switch (version) {
|
||||
case 0x400:
|
||||
ftdi_class->chip_type = FT232B;
|
||||
break;
|
||||
case 0x500:
|
||||
ftdi_class->chip_type = FT2232C;
|
||||
break;
|
||||
case 0x600:
|
||||
ftdi_class->chip_type = FT232R;
|
||||
break;
|
||||
case 0x700:
|
||||
ftdi_class->chip_type = FT2232H;
|
||||
break;
|
||||
case 0x800:
|
||||
ftdi_class->chip_type = FT4232H;
|
||||
break;
|
||||
case 0x900:
|
||||
ftdi_class->chip_type = FT232H;
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_ERR("Unknown FTDI chip version:%04x\r\n", version);
|
||||
return -USB_ERR_NOTSUPP;
|
||||
}
|
||||
|
||||
USB_LOG_INFO("FTDI chip name:%s\r\n", ftdi_chip_name[ftdi_class->chip_type]);
|
||||
|
||||
usbh_ftdi_reset(ftdi_class);
|
||||
usbh_ftdi_set_flow_ctrl(ftdi_class, SIO_DISABLE_FLOW_CTRL);
|
||||
usbh_ftdi_set_latency_timer(ftdi_class, 0x10);
|
||||
usbh_ftdi_read_modem_status(ftdi_class);
|
||||
USB_LOG_INFO("modem status:%02x:%02x\r\n", ftdi_class->modem_status[0], ftdi_class->modem_status[1]);
|
||||
|
||||
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
||||
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
|
||||
|
||||
if (ep_desc->bEndpointAddress & 0x80) {
|
||||
USBH_EP_INIT(ftdi_class->bulkin, ep_desc);
|
||||
} else {
|
||||
USBH_EP_INIT(ftdi_class->bulkout, ep_desc);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, ftdi_class->minor);
|
||||
|
||||
USB_LOG_INFO("Register FTDI Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
|
||||
#if 0
|
||||
USB_LOG_INFO("Test ftdi rx and tx and rx for 5 times, baudrate is 115200\r\n");
|
||||
|
||||
struct cdc_line_coding linecoding;
|
||||
uint8_t count = 5;
|
||||
|
||||
linecoding.dwDTERate = 115200;
|
||||
linecoding.bDataBits = 8;
|
||||
linecoding.bParityType = 0;
|
||||
linecoding.bCharFormat = 0;
|
||||
usbh_ftdi_set_line_coding(ftdi_class, &linecoding);
|
||||
usbh_ftdi_set_line_state(ftdi_class, true, false);
|
||||
|
||||
memset(g_ftdi_buf, 'a', sizeof(g_ftdi_buf));
|
||||
ret = usbh_ftdi_bulk_out_transfer(ftdi_class, g_ftdi_buf, sizeof(g_ftdi_buf), 0xfffffff);
|
||||
USB_LOG_RAW("out ret:%d\r\n", ret);
|
||||
while (count--) {
|
||||
ret = usbh_ftdi_bulk_in_transfer(ftdi_class, g_ftdi_buf, sizeof(g_ftdi_buf), 0xfffffff);
|
||||
USB_LOG_RAW("in ret:%d\r\n", ret);
|
||||
if (ret > 0) {
|
||||
for (uint32_t i = 0; i < ret; i++) {
|
||||
USB_LOG_RAW("%02x ", g_ftdi_buf[i]);
|
||||
}
|
||||
}
|
||||
USB_LOG_RAW("\r\n");
|
||||
}
|
||||
#endif
|
||||
usbh_ftdi_run(ftdi_class);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_ftdi_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct usbh_ftdi *ftdi_class = (struct usbh_ftdi *)hport->config.intf[intf].priv;
|
||||
|
||||
if (ftdi_class) {
|
||||
if (ftdi_class->bulkin) {
|
||||
usbh_kill_urb(&ftdi_class->bulkin_urb);
|
||||
}
|
||||
|
||||
if (ftdi_class->bulkout) {
|
||||
usbh_kill_urb(&ftdi_class->bulkout_urb);
|
||||
}
|
||||
|
||||
if (hport->config.intf[intf].devname[0] != '\0') {
|
||||
usb_osal_thread_schedule_other();
|
||||
USB_LOG_INFO("Unregister FTDI Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
usbh_ftdi_stop(ftdi_class);
|
||||
}
|
||||
|
||||
usbh_ftdi_class_free(ftdi_class);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_ftdi_bulk_in_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &ftdi_class->bulkin_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, ftdi_class->hport, ftdi_class->bulkin, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_ftdi_bulk_out_transfer(struct usbh_ftdi *ftdi_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &ftdi_class->bulkout_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, ftdi_class->hport, ftdi_class->bulkout, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
__WEAK void usbh_ftdi_run(struct usbh_ftdi *ftdi_class)
|
||||
{
|
||||
(void)ftdi_class;
|
||||
}
|
||||
|
||||
__WEAK void usbh_ftdi_stop(struct usbh_ftdi *ftdi_class)
|
||||
{
|
||||
(void)ftdi_class;
|
||||
}
|
||||
|
||||
static const uint16_t ftdi_id_table[][2] = {
|
||||
{ 0x0403, 0x6001 },
|
||||
{ 0x0403, 0x6010 },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
const struct usbh_class_driver ftdi_class_driver = {
|
||||
.driver_name = "ftdi",
|
||||
.connect = usbh_ftdi_connect,
|
||||
.disconnect = usbh_ftdi_disconnect
|
||||
};
|
||||
|
||||
CLASS_INFO_DEFINE const struct usbh_class_info ftdi_class_info = {
|
||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||
.bInterfaceClass = 0xff,
|
||||
.bInterfaceSubClass = 0x00,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.id_table = ftdi_id_table,
|
||||
.class_driver = &ftdi_class_driver
|
||||
};
|
||||
96
class/vendor/serial/usbh_ftdi.h
vendored
96
class/vendor/serial/usbh_ftdi.h
vendored
@@ -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 */
|
||||
449
class/vendor/serial/usbh_pl2303.c
vendored
449
class/vendor/serial/usbh_pl2303.c
vendored
@@ -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
|
||||
};
|
||||
62
class/vendor/serial/usbh_pl2303.h
vendored
62
class/vendor/serial/usbh_pl2303.h
vendored
@@ -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 */
|
||||
@@ -578,16 +578,6 @@ int usbh_rndis_eth_output(uint32_t buflen)
|
||||
return usbh_submit_urb(&g_rndis_class.bulkout_urb);
|
||||
}
|
||||
|
||||
__WEAK void usbh_rndis_run(struct usbh_rndis *rndis_class)
|
||||
{
|
||||
(void)rndis_class;
|
||||
}
|
||||
|
||||
__WEAK void usbh_rndis_stop(struct usbh_rndis *rndis_class)
|
||||
{
|
||||
(void)rndis_class;
|
||||
}
|
||||
|
||||
static const struct usbh_class_driver rndis_class_driver = {
|
||||
.driver_name = "rndis",
|
||||
.connect = usbh_rndis_connect,
|
||||
|
||||
@@ -318,24 +318,24 @@
|
||||
/* Setup packet definition used to read raw data from USB line */
|
||||
struct usb_setup_packet {
|
||||
/** Request type. Bits 0:4 determine recipient, see
|
||||
* \ref usb_request_recipient. Bits 5:6 determine type, see
|
||||
* \ref usb_request_type. Bit 7 determines data transfer direction, see
|
||||
* \ref usb_endpoint_direction.
|
||||
*/
|
||||
* \ref usb_request_recipient. Bits 5:6 determine type, see
|
||||
* \ref usb_request_type. Bit 7 determines data transfer direction, see
|
||||
* \ref usb_endpoint_direction.
|
||||
*/
|
||||
uint8_t bmRequestType;
|
||||
|
||||
/** Request. If the type bits of bmRequestType are equal to
|
||||
* \ref usb_request_type::LIBUSB_REQUEST_TYPE_STANDARD
|
||||
* "USB_REQUEST_TYPE_STANDARD" then this field refers to
|
||||
* \ref usb_standard_request. For other cases, use of this field is
|
||||
* application-specific. */
|
||||
* \ref usb_request_type::LIBUSB_REQUEST_TYPE_STANDARD
|
||||
* "USB_REQUEST_TYPE_STANDARD" then this field refers to
|
||||
* \ref usb_standard_request. For other cases, use of this field is
|
||||
* application-specific. */
|
||||
uint8_t bRequest;
|
||||
|
||||
/** Value. Varies according to request */
|
||||
uint16_t wValue;
|
||||
|
||||
/** Index. Varies according to request, typically used to pass an index
|
||||
* or offset */
|
||||
* or offset */
|
||||
uint16_t wIndex;
|
||||
|
||||
/** Number of bytes to transfer */
|
||||
|
||||
@@ -209,6 +209,23 @@
|
||||
19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
|
||||
9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
|
||||
/*
|
||||
* Divide positive or negative dividend by positive or negative divisor
|
||||
* and round to closest integer. Result is undefined for negative
|
||||
* divisors if the dividend variable type is unsigned and for negative
|
||||
* dividends if the divisor variable type is unsigned.
|
||||
*/
|
||||
#define DIV_ROUND_CLOSEST(x, divisor) ( \
|
||||
{ \
|
||||
typeof(x) __x = x; \
|
||||
typeof(divisor) __d = divisor; \
|
||||
(((typeof(x))-1) > 0 || \
|
||||
((typeof(divisor))-1) > 0 || \
|
||||
(((__x) > 0) == ((__d) > 0))) ? \
|
||||
(((__x) + ((__d) / 2)) / (__d)) : \
|
||||
(((__x) - ((__d) / 2)) / (__d)); \
|
||||
})
|
||||
|
||||
#define USB_MEM_ALIGNX __attribute__((aligned(CONFIG_USB_ALIGN_SIZE)))
|
||||
|
||||
#define USB_ALIGN_UP(size, align) (((size) + (align)-1) & ~((align)-1))
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#undef CHERRYUSB_VERSION_STR
|
||||
#endif
|
||||
|
||||
#define CHERRYUSB_VERSION 0x010503
|
||||
#define CHERRYUSB_VERSION_STR "v1.5.3"
|
||||
#define CHERRYUSB_VERSION 0x010600
|
||||
#define CHERRYUSB_VERSION_STR "v1.6.0"
|
||||
|
||||
#endif
|
||||
211
core/usbd_core.c
211
core/usbd_core.c
@@ -48,16 +48,10 @@ USB_NOCACHE_RAM_SECTION struct usbd_core_priv {
|
||||
uint32_t ep0_data_buf_len;
|
||||
/** Zero length packet flag of control transfer */
|
||||
bool zlp_flag;
|
||||
|
||||
/** Pointer to registered descriptors */
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
const struct usb_descriptor *descriptors;
|
||||
#else
|
||||
const uint8_t *descriptors;
|
||||
struct usb_msosv1_descriptor *msosv1_desc;
|
||||
struct usb_msosv2_descriptor *msosv2_desc;
|
||||
struct usb_bos_descriptor *bos_desc;
|
||||
struct usb_webusb_descriptor *webusb_url_desc;
|
||||
#endif
|
||||
|
||||
/* Buffer used for storing standard, class and vendor request data */
|
||||
USB_MEM_ALIGNX uint8_t req_data[USB_ALIGN_UP(CONFIG_USBDEV_REQUEST_BUFFER_LEN, CONFIG_USB_ALIGN_SIZE)];
|
||||
|
||||
@@ -69,9 +63,7 @@ USB_NOCACHE_RAM_SECTION struct usbd_core_priv {
|
||||
bool remote_wakeup_support;
|
||||
bool remote_wakeup_enabled;
|
||||
bool is_suspend;
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
uint8_t speed;
|
||||
#endif
|
||||
#ifdef CONFIG_USBDEV_TEST_MODE
|
||||
bool test_req;
|
||||
#endif
|
||||
@@ -180,7 +172,6 @@ static bool usbd_reset_endpoint(uint8_t busid, const struct usb_endpoint_descrip
|
||||
*
|
||||
* @return true if the descriptor was found, false otherwise
|
||||
*/
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static bool usbd_get_descriptor(uint8_t busid, uint16_t type_index, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
uint8_t type = 0U;
|
||||
@@ -326,93 +317,6 @@ static bool usbd_get_descriptor(uint8_t busid, uint16_t type_index, uint8_t **da
|
||||
}
|
||||
return found;
|
||||
}
|
||||
#else
|
||||
static bool usbd_get_descriptor(uint8_t busid, uint16_t type_index, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
uint8_t type = 0U;
|
||||
uint8_t index = 0U;
|
||||
uint8_t *p = NULL;
|
||||
uint32_t cur_index = 0U;
|
||||
bool found = false;
|
||||
|
||||
type = HI_BYTE(type_index);
|
||||
index = LO_BYTE(type_index);
|
||||
|
||||
if ((type == USB_DESCRIPTOR_TYPE_STRING) && (index == USB_OSDESC_STRING_DESC_INDEX)) {
|
||||
if (!g_usbd_core[busid].msosv1_desc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*data = (uint8_t *)g_usbd_core[busid].msosv1_desc->string;
|
||||
//memcpy(*data, (uint8_t *)g_usbd_core[busid].msosv1_desc->string, g_usbd_core[busid].msosv1_desc->string[0]);
|
||||
*len = g_usbd_core[busid].msosv1_desc->string[0];
|
||||
|
||||
return true;
|
||||
} else if (type == USB_DESCRIPTOR_TYPE_BINARY_OBJECT_STORE) {
|
||||
if (!g_usbd_core[busid].bos_desc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*data = (uint8_t *)g_usbd_core[busid].bos_desc->string;
|
||||
//memcpy(*data, (uint8_t *)g_usbd_core[busid].bos_desc->string, g_usbd_core[busid].bos_desc->string_len);
|
||||
*len = g_usbd_core[busid].bos_desc->string_len;
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* Invalid types of descriptors,
|
||||
* see USB Spec. Revision 2.0, 9.4.3 Get Descriptor
|
||||
*/
|
||||
else if ((type == USB_DESCRIPTOR_TYPE_INTERFACE) || (type == USB_DESCRIPTOR_TYPE_ENDPOINT) ||
|
||||
#ifndef CONFIG_USB_HS
|
||||
(type > USB_DESCRIPTOR_TYPE_ENDPOINT)) {
|
||||
#else
|
||||
(type > USB_DESCRIPTOR_TYPE_OTHER_SPEED)) {
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
p = (uint8_t *)g_usbd_core[busid].descriptors;
|
||||
|
||||
cur_index = 0U;
|
||||
|
||||
while (p[DESC_bLength] != 0U) {
|
||||
if (p[DESC_bDescriptorType] == type) {
|
||||
if (cur_index == index) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
cur_index++;
|
||||
}
|
||||
|
||||
/* skip to next descriptor */
|
||||
p += p[DESC_bLength];
|
||||
}
|
||||
|
||||
if (found) {
|
||||
if ((type == USB_DESCRIPTOR_TYPE_CONFIGURATION) || ((type == USB_DESCRIPTOR_TYPE_OTHER_SPEED))) {
|
||||
/* configuration or other speed descriptor is an
|
||||
* exception, length is at offset 2 and 3
|
||||
*/
|
||||
*len = (p[CONF_DESC_wTotalLength]) |
|
||||
(p[CONF_DESC_wTotalLength + 1] << 8);
|
||||
|
||||
g_usbd_core[busid].self_powered = (p[7] & USB_CONFIG_POWERED_MASK) ? true : false;
|
||||
g_usbd_core[busid].remote_wakeup_support = (p[7] & USB_CONFIG_REMOTE_WAKEUP) ? true : false;
|
||||
} else {
|
||||
/* normally length is at offset 0 */
|
||||
*len = p[DESC_bLength];
|
||||
}
|
||||
*data = p;
|
||||
//memcpy(*data, p, *len);
|
||||
} else {
|
||||
/* nothing found */
|
||||
USB_LOG_ERR("descriptor <type:0x%02x,index:0x%02x> not found!\r\n", type, index);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief set USB configuration
|
||||
@@ -436,11 +340,8 @@ static bool usbd_set_configuration(uint8_t busid, uint8_t config_index, uint8_t
|
||||
uint32_t desc_len = 0;
|
||||
uint32_t current_desc_len = 0;
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
p = g_usbd_core[busid].descriptors->config_descriptor_callback(g_usbd_core[busid].speed);
|
||||
#else
|
||||
p = (uint8_t *)g_usbd_core[busid].descriptors;
|
||||
#endif
|
||||
|
||||
/* configure endpoints for this configuration/altsetting */
|
||||
while (p[DESC_bLength] != 0U) {
|
||||
switch (p[DESC_bDescriptorType]) {
|
||||
@@ -508,11 +409,8 @@ static bool usbd_set_interface(uint8_t busid, uint8_t iface, uint8_t alt_setting
|
||||
uint32_t desc_len = 0;
|
||||
uint32_t current_desc_len = 0;
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
p = g_usbd_core[busid].descriptors->config_descriptor_callback(g_usbd_core[busid].speed);
|
||||
#else
|
||||
p = (uint8_t *)g_usbd_core[busid].descriptors;
|
||||
#endif
|
||||
|
||||
USB_LOG_DBG("iface %u alt_setting %u\r\n", iface, alt_setting);
|
||||
|
||||
while (p[DESC_bLength] != 0U) {
|
||||
@@ -683,11 +581,7 @@ static bool usbd_std_interface_req_handler(uint8_t busid, struct usb_setup_packe
|
||||
uint32_t current_desc_len = 0;
|
||||
uint8_t cur_iface = 0xFF;
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
p = g_usbd_core[busid].descriptors->config_descriptor_callback(g_usbd_core[busid].speed);
|
||||
#else
|
||||
p = (uint8_t *)g_usbd_core[busid].descriptors;
|
||||
#endif
|
||||
|
||||
/* Only when device is configured, then interface requests can be valid. */
|
||||
if (!is_device_configured(busid)) {
|
||||
@@ -925,7 +819,7 @@ static int usbd_class_request_handler(uint8_t busid, struct usb_setup_packet *se
|
||||
static int usbd_vendor_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
uint32_t desclen;
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
|
||||
if (g_usbd_core[busid].descriptors->msosv1_descriptor) {
|
||||
if (setup->bRequest == g_usbd_core[busid].descriptors->msosv1_descriptor->vendor_code) {
|
||||
switch (setup->wIndex) {
|
||||
@@ -982,61 +876,7 @@ static int usbd_vendor_request_handler(uint8_t busid, struct usb_setup_packet *s
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (g_usbd_core[busid].msosv1_desc) {
|
||||
if (setup->bRequest == g_usbd_core[busid].msosv1_desc->vendor_code) {
|
||||
switch (setup->wIndex) {
|
||||
case 0x04:
|
||||
*data = (uint8_t *)g_usbd_core[busid].msosv1_desc->compat_id;
|
||||
desclen = g_usbd_core[busid].msosv1_desc->compat_id[0] +
|
||||
(g_usbd_core[busid].msosv1_desc->compat_id[1] << 8) +
|
||||
(g_usbd_core[busid].msosv1_desc->compat_id[2] << 16) +
|
||||
(g_usbd_core[busid].msosv1_desc->compat_id[3] << 24);
|
||||
//memcpy(*data, g_usbd_core[busid].msosv1_desc->compat_id, desclen);
|
||||
*len = desclen;
|
||||
return 0;
|
||||
case 0x05:
|
||||
*data = (uint8_t *)g_usbd_core[busid].msosv1_desc->comp_id_property[setup->wValue];
|
||||
desclen = g_usbd_core[busid].msosv1_desc->comp_id_property[setup->wValue][0] +
|
||||
(g_usbd_core[busid].msosv1_desc->comp_id_property[setup->wValue][1] << 8) +
|
||||
(g_usbd_core[busid].msosv1_desc->comp_id_property[setup->wValue][2] << 16) +
|
||||
(g_usbd_core[busid].msosv1_desc->comp_id_property[setup->wValue][3] << 24);
|
||||
//memcpy(*data, g_usbd_core[busid].msosv1_desc->comp_id_property[setup->wValue], desclen);
|
||||
*len = desclen;
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (g_usbd_core[busid].msosv2_desc) {
|
||||
if (setup->bRequest == g_usbd_core[busid].msosv2_desc->vendor_code) {
|
||||
switch (setup->wIndex) {
|
||||
case WINUSB_REQUEST_GET_DESCRIPTOR_SET:
|
||||
*data = (uint8_t *)g_usbd_core[busid].msosv2_desc->compat_id;
|
||||
//memcpy(*data, g_usbd_core[busid].msosv2_desc->compat_id, g_usbd_core[busid].msosv2_desc->compat_id_len);
|
||||
*len = g_usbd_core[busid].msosv2_desc->compat_id_len;
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g_usbd_core[busid].webusb_url_desc) {
|
||||
if (setup->bRequest == g_usbd_core[busid].webusb_url_desc->vendor_code) {
|
||||
switch (setup->wIndex) {
|
||||
case WEBUSB_REQUEST_GET_URL:
|
||||
desclen = g_usbd_core[busid].webusb_url_desc->string_len;
|
||||
*data = (uint8_t *)g_usbd_core[busid].webusb_url_desc->string;
|
||||
//memcpy(*data, g_usbd_core[busid].webusb_url_desc->string, desclen);
|
||||
*len = desclen;
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
for (uint8_t i = 0; i < g_usbd_core[busid].intf_offset; i++) {
|
||||
struct usbd_interface *intf = g_usbd_core[busid].intf[i];
|
||||
|
||||
@@ -1151,7 +991,6 @@ void usbd_event_reset_handler(uint8_t busid)
|
||||
g_usbd_core[busid].device_address = 0;
|
||||
g_usbd_core[busid].configuration = 0;
|
||||
g_usbd_core[busid].ep0_next_state = USBD_EP0_STATE_SETUP;
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
g_usbd_core[busid].speed = USB_SPEED_UNKNOWN;
|
||||
|
||||
USB_ASSERT_MSG(g_usbd_core[busid].descriptors->device_descriptor_callback != NULL,
|
||||
@@ -1159,9 +998,6 @@ void usbd_event_reset_handler(uint8_t busid)
|
||||
|
||||
struct usb_device_descriptor *device_desc = (struct usb_device_descriptor *)g_usbd_core[busid].descriptors->device_descriptor_callback(g_usbd_core[busid].speed);
|
||||
ep0.wMaxPacketSize = device_desc->bMaxPacketSize0;
|
||||
#else
|
||||
ep0.wMaxPacketSize = USB_CTRL_EP_MPS;
|
||||
#endif
|
||||
|
||||
ep0.bLength = 7;
|
||||
ep0.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT;
|
||||
@@ -1377,7 +1213,6 @@ void usbd_event_ep_out_complete_handler(uint8_t busid, uint8_t ep, uint32_t nbyt
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
void usbd_desc_register(uint8_t busid, const struct usb_descriptor *desc)
|
||||
{
|
||||
memset(&g_usbd_core[busid], 0, sizeof(struct usbd_core_priv));
|
||||
@@ -1390,42 +1225,6 @@ void usbd_desc_register(uint8_t busid, const struct usb_descriptor *desc)
|
||||
g_usbd_core[busid].rx_msg[0].ep = 0x00;
|
||||
g_usbd_core[busid].rx_msg[0].cb = usbd_event_ep0_out_complete_handler;
|
||||
}
|
||||
#else
|
||||
void usbd_desc_register(uint8_t busid, const uint8_t *desc)
|
||||
{
|
||||
memset(&g_usbd_core[busid], 0, sizeof(struct usbd_core_priv));
|
||||
|
||||
g_usbd_core[busid].descriptors = desc;
|
||||
g_usbd_core[busid].intf_offset = 0;
|
||||
|
||||
g_usbd_core[busid].tx_msg[0].ep = 0x80;
|
||||
g_usbd_core[busid].tx_msg[0].cb = usbd_event_ep0_in_complete_handler;
|
||||
g_usbd_core[busid].rx_msg[0].ep = 0x00;
|
||||
g_usbd_core[busid].rx_msg[0].cb = usbd_event_ep0_out_complete_handler;
|
||||
}
|
||||
|
||||
/* Register MS OS Descriptors version 1 */
|
||||
void usbd_msosv1_desc_register(uint8_t busid, struct usb_msosv1_descriptor *desc)
|
||||
{
|
||||
g_usbd_core[busid].msosv1_desc = desc;
|
||||
}
|
||||
|
||||
/* Register MS OS Descriptors version 2 */
|
||||
void usbd_msosv2_desc_register(uint8_t busid, struct usb_msosv2_descriptor *desc)
|
||||
{
|
||||
g_usbd_core[busid].msosv2_desc = desc;
|
||||
}
|
||||
|
||||
void usbd_bos_desc_register(uint8_t busid, struct usb_bos_descriptor *desc)
|
||||
{
|
||||
g_usbd_core[busid].bos_desc = desc;
|
||||
}
|
||||
|
||||
void usbd_webusb_desc_register(uint8_t busid, struct usb_webusb_descriptor *desc)
|
||||
{
|
||||
g_usbd_core[busid].webusb_url_desc = desc;
|
||||
}
|
||||
#endif
|
||||
|
||||
void usbd_add_interface(uint8_t busid, struct usbd_interface *intf)
|
||||
{
|
||||
|
||||
@@ -96,15 +96,7 @@ extern struct usbd_bus g_usbdev_bus[];
|
||||
#error USBD_IRQHandler is obsolete, please call USBD_IRQHandler(xxx) in your irq
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
void usbd_desc_register(uint8_t busid, const struct usb_descriptor *desc);
|
||||
#else
|
||||
void usbd_desc_register(uint8_t busid, const uint8_t *desc);
|
||||
void usbd_msosv1_desc_register(uint8_t busid, struct usb_msosv1_descriptor *desc);
|
||||
void usbd_msosv2_desc_register(uint8_t busid, struct usb_msosv2_descriptor *desc);
|
||||
void usbd_bos_desc_register(uint8_t busid, struct usb_bos_descriptor *desc);
|
||||
void usbd_webusb_desc_register(uint8_t busid, struct usb_webusb_descriptor *desc);
|
||||
#endif
|
||||
|
||||
void usbd_add_interface(uint8_t busid, struct usbd_interface *intf);
|
||||
void usbd_add_endpoint(uint8_t busid, struct usbd_endpoint *ep);
|
||||
|
||||
107
core/usbh_core.c
107
core/usbh_core.c
@@ -31,6 +31,15 @@ struct usbh_bus g_usbhost_bus[CONFIG_USBHOST_MAX_BUS];
|
||||
#define USB_DEV_ADDR_MARK_OFFSET 5
|
||||
#define USB_DEV_ADDR_MARK_MASK 0x1f
|
||||
|
||||
static void dummy_event_handler(uint8_t busid, uint8_t hub_index, uint8_t hub_port, uint8_t intf, uint8_t event)
|
||||
{
|
||||
(void)busid;
|
||||
(void)hub_index;
|
||||
(void)hub_port;
|
||||
(void)intf;
|
||||
(void)event;
|
||||
}
|
||||
|
||||
static int usbh_allocate_devaddr(struct usbh_devaddr_map *devgen)
|
||||
{
|
||||
uint8_t lastaddr = devgen->last;
|
||||
@@ -542,6 +551,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
|
||||
}
|
||||
#endif
|
||||
USB_LOG_INFO("Enumeration success, start loading class driver\r\n");
|
||||
hport->bus->event_handler(hport->bus->busid, hport->parent->index, hport->port, USB_INTERFACE_ANY, USBH_EVENT_DEVICE_CONFIGURED);
|
||||
/*search supported class driver*/
|
||||
for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
|
||||
intf_desc = &hport->config.intf[i].altsetting[0].intf_desc;
|
||||
@@ -561,11 +571,15 @@ int usbh_enumerate(struct usbh_hubport *hport)
|
||||
intf_desc->bInterfaceSubClass,
|
||||
intf_desc->bInterfaceProtocol,
|
||||
i);
|
||||
hport->bus->event_handler(hport->bus->busid, hport->parent->index, hport->port, i, USBH_EVENT_INTERFACE_UNSUPPORTED);
|
||||
continue;
|
||||
}
|
||||
hport->config.intf[i].class_driver = class_driver;
|
||||
USB_LOG_INFO("Loading %s class driver on interface %u\r\n", class_driver->driver_name, i);
|
||||
ret = CLASS_CONNECT(hport, i);
|
||||
if (ret >= 0) {
|
||||
hport->bus->event_handler(hport->bus->busid, hport->parent->index, hport->port, i, USBH_EVENT_INTERFACE_START);
|
||||
}
|
||||
}
|
||||
|
||||
errout:
|
||||
@@ -586,11 +600,14 @@ void usbh_hubport_release(struct usbh_hubport *hport)
|
||||
if (hport->config.intf[i].class_driver && hport->config.intf[i].class_driver->disconnect) {
|
||||
CLASS_DISCONNECT(hport, i);
|
||||
}
|
||||
hport->bus->event_handler(hport->bus->busid, hport->parent->index, hport->port, i, USBH_EVENT_INTERFACE_STOP);
|
||||
}
|
||||
hport->config.config_desc.bNumInterfaces = 0;
|
||||
if (hport->mutex) {
|
||||
usb_osal_mutex_delete(hport->mutex);
|
||||
}
|
||||
USB_LOG_INFO("Device on Bus %u, Hub %u, Port %u disconnected\r\n", hport->bus->busid, hport->parent->index, hport->port);
|
||||
hport->bus->event_handler(hport->bus->busid, hport->parent->index, hport->port, USB_INTERFACE_ANY, USBH_EVENT_DEVICE_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,7 +624,7 @@ static void usbh_bus_init(struct usbh_bus *bus, uint8_t busid, uintptr_t reg_bas
|
||||
usb_slist_add_tail(&g_bus_head, &bus->list);
|
||||
}
|
||||
|
||||
int usbh_initialize(uint8_t busid, uintptr_t reg_base)
|
||||
int usbh_initialize(uint8_t busid, uintptr_t reg_base, usbh_event_handler_t event_handler)
|
||||
{
|
||||
struct usbh_bus *bus;
|
||||
|
||||
@@ -617,6 +634,12 @@ int usbh_initialize(uint8_t busid, uintptr_t reg_base)
|
||||
|
||||
usbh_bus_init(bus, busid, reg_base);
|
||||
|
||||
if (event_handler) {
|
||||
bus->event_handler = event_handler;
|
||||
} else {
|
||||
bus->event_handler = dummy_event_handler;
|
||||
}
|
||||
|
||||
#ifdef __ARMCC_VERSION /* ARM C Compiler */
|
||||
extern const int usbh_class_info$$Base;
|
||||
extern const int usbh_class_info$$Limit;
|
||||
@@ -643,6 +666,8 @@ int usbh_deinitialize(uint8_t busid)
|
||||
|
||||
bus = &g_usbhost_bus[busid];
|
||||
|
||||
bus->event_handler(bus->busid, USB_HUB_INDEX_ANY, USB_HUB_PORT_ANY, USB_INTERFACE_ANY, USBH_EVENT_DEINIT);
|
||||
|
||||
usbh_hub_deinitialize(bus);
|
||||
|
||||
usb_slist_remove(&g_bus_head, &bus->list);
|
||||
@@ -848,52 +873,52 @@ struct usbh_hubport *usbh_find_hubport(uint8_t busid, uint8_t hub_index, uint8_t
|
||||
static void usbh_print_hubport_info(struct usbh_hubport *hport)
|
||||
{
|
||||
USB_LOG_RAW("Device Descriptor:\r\n");
|
||||
USB_LOG_RAW("bLength: 0x%02x \r\n", hport->device_desc.bLength);
|
||||
USB_LOG_RAW("bDescriptorType: 0x%02x \r\n", hport->device_desc.bDescriptorType);
|
||||
USB_LOG_RAW("bcdUSB: 0x%04x \r\n", hport->device_desc.bcdUSB);
|
||||
USB_LOG_RAW("bDeviceClass: 0x%02x \r\n", hport->device_desc.bDeviceClass);
|
||||
USB_LOG_RAW("bDeviceSubClass: 0x%02x \r\n", hport->device_desc.bDeviceSubClass);
|
||||
USB_LOG_RAW("bDeviceProtocol: 0x%02x \r\n", hport->device_desc.bDeviceProtocol);
|
||||
USB_LOG_RAW("bMaxPacketSize0: 0x%02x \r\n", hport->device_desc.bMaxPacketSize0);
|
||||
USB_LOG_RAW("idVendor: 0x%04x \r\n", hport->device_desc.idVendor);
|
||||
USB_LOG_RAW("idProduct: 0x%04x \r\n", hport->device_desc.idProduct);
|
||||
USB_LOG_RAW("bcdDevice: 0x%04x \r\n", hport->device_desc.bcdDevice);
|
||||
USB_LOG_RAW("iManufacturer: 0x%02x \r\n", hport->device_desc.iManufacturer);
|
||||
USB_LOG_RAW("iProduct: 0x%02x \r\n", hport->device_desc.iProduct);
|
||||
USB_LOG_RAW("iSerialNumber: 0x%02x \r\n", hport->device_desc.iSerialNumber);
|
||||
USB_LOG_RAW("bNumConfigurations: 0x%02x\r\n", hport->device_desc.bNumConfigurations);
|
||||
USB_LOG_RAW(" bLength: 0x%02x \r\n", hport->device_desc.bLength);
|
||||
USB_LOG_RAW(" bDescriptorType: 0x%02x \r\n", hport->device_desc.bDescriptorType);
|
||||
USB_LOG_RAW(" bcdUSB: 0x%04x \r\n", hport->device_desc.bcdUSB);
|
||||
USB_LOG_RAW(" bDeviceClass: 0x%02x \r\n", hport->device_desc.bDeviceClass);
|
||||
USB_LOG_RAW(" bDeviceSubClass: 0x%02x \r\n", hport->device_desc.bDeviceSubClass);
|
||||
USB_LOG_RAW(" bDeviceProtocol: 0x%02x \r\n", hport->device_desc.bDeviceProtocol);
|
||||
USB_LOG_RAW(" bMaxPacketSize0: 0x%02x \r\n", hport->device_desc.bMaxPacketSize0);
|
||||
USB_LOG_RAW(" idVendor: 0x%04x \r\n", hport->device_desc.idVendor);
|
||||
USB_LOG_RAW(" idProduct: 0x%04x \r\n", hport->device_desc.idProduct);
|
||||
USB_LOG_RAW(" bcdDevice: 0x%04x \r\n", hport->device_desc.bcdDevice);
|
||||
USB_LOG_RAW(" iManufacturer: 0x%02x \r\n", hport->device_desc.iManufacturer);
|
||||
USB_LOG_RAW(" iProduct: 0x%02x \r\n", hport->device_desc.iProduct);
|
||||
USB_LOG_RAW(" iSerialNumber: 0x%02x \r\n", hport->device_desc.iSerialNumber);
|
||||
USB_LOG_RAW(" bNumConfigurations: 0x%02x\r\n", hport->device_desc.bNumConfigurations);
|
||||
|
||||
USB_LOG_RAW("Config Descriptor:\r\n");
|
||||
USB_LOG_RAW("bLength: 0x%02x \r\n", hport->config.config_desc.bLength);
|
||||
USB_LOG_RAW("bDescriptorType: 0x%02x \r\n", hport->config.config_desc.bDescriptorType);
|
||||
USB_LOG_RAW("wTotalLength: 0x%04x \r\n", hport->config.config_desc.wTotalLength);
|
||||
USB_LOG_RAW("bNumInterfaces: 0x%02x \r\n", hport->config.config_desc.bNumInterfaces);
|
||||
USB_LOG_RAW("bConfigurationValue: 0x%02x \r\n", hport->config.config_desc.bConfigurationValue);
|
||||
USB_LOG_RAW("iConfiguration: 0x%02x \r\n", hport->config.config_desc.iConfiguration);
|
||||
USB_LOG_RAW("bmAttributes: 0x%02x \r\n", hport->config.config_desc.bmAttributes);
|
||||
USB_LOG_RAW("bMaxPower: 0x%02x \r\n", hport->config.config_desc.bMaxPower);
|
||||
USB_LOG_RAW(" Config Descriptor:\r\n");
|
||||
USB_LOG_RAW(" bLength: 0x%02x \r\n", hport->config.config_desc.bLength);
|
||||
USB_LOG_RAW(" bDescriptorType: 0x%02x \r\n", hport->config.config_desc.bDescriptorType);
|
||||
USB_LOG_RAW(" wTotalLength: 0x%04x \r\n", hport->config.config_desc.wTotalLength);
|
||||
USB_LOG_RAW(" bNumInterfaces: 0x%02x \r\n", hport->config.config_desc.bNumInterfaces);
|
||||
USB_LOG_RAW(" bConfigurationValue: 0x%02x \r\n", hport->config.config_desc.bConfigurationValue);
|
||||
USB_LOG_RAW(" iConfiguration: 0x%02x \r\n", hport->config.config_desc.iConfiguration);
|
||||
USB_LOG_RAW(" bmAttributes: 0x%02x \r\n", hport->config.config_desc.bmAttributes);
|
||||
USB_LOG_RAW(" bMaxPower: 0x%02x \r\n", hport->config.config_desc.bMaxPower);
|
||||
|
||||
for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
|
||||
for (uint8_t j = 0; j < hport->config.intf[i].altsetting_num; j++) {
|
||||
USB_LOG_RAW("\tInterface Descriptor:\r\n");
|
||||
USB_LOG_RAW("\tbLength: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bLength);
|
||||
USB_LOG_RAW("\tbDescriptorType: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bDescriptorType);
|
||||
USB_LOG_RAW("\tbInterfaceNumber: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceNumber);
|
||||
USB_LOG_RAW("\tbAlternateSetting: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bAlternateSetting);
|
||||
USB_LOG_RAW("\tbNumEndpoints: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bNumEndpoints);
|
||||
USB_LOG_RAW("\tbInterfaceClass: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceClass);
|
||||
USB_LOG_RAW("\tbInterfaceSubClass: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceSubClass);
|
||||
USB_LOG_RAW("\tbInterfaceProtocol: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceProtocol);
|
||||
USB_LOG_RAW("\tiInterface: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.iInterface);
|
||||
USB_LOG_RAW(" Interface Descriptor:\r\n");
|
||||
USB_LOG_RAW(" bLength: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bLength);
|
||||
USB_LOG_RAW(" bDescriptorType: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bDescriptorType);
|
||||
USB_LOG_RAW(" bInterfaceNumber: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceNumber);
|
||||
USB_LOG_RAW(" bAlternateSetting: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bAlternateSetting);
|
||||
USB_LOG_RAW(" bNumEndpoints: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bNumEndpoints);
|
||||
USB_LOG_RAW(" bInterfaceClass: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceClass);
|
||||
USB_LOG_RAW(" bInterfaceSubClass: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceSubClass);
|
||||
USB_LOG_RAW(" bInterfaceProtocol: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.bInterfaceProtocol);
|
||||
USB_LOG_RAW(" iInterface: 0x%02x \r\n", hport->config.intf[i].altsetting[j].intf_desc.iInterface);
|
||||
|
||||
for (uint8_t k = 0; k < hport->config.intf[i].altsetting[j].intf_desc.bNumEndpoints; k++) {
|
||||
USB_LOG_RAW("\t\tEndpoint Descriptor:\r\n");
|
||||
USB_LOG_RAW("\t\tbLength: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bLength);
|
||||
USB_LOG_RAW("\t\tbDescriptorType: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bDescriptorType);
|
||||
USB_LOG_RAW("\t\tbEndpointAddress: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bEndpointAddress);
|
||||
USB_LOG_RAW("\t\tbmAttributes: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bmAttributes);
|
||||
USB_LOG_RAW("\t\twMaxPacketSize: 0x%04x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.wMaxPacketSize);
|
||||
USB_LOG_RAW("\t\tbInterval: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bInterval);
|
||||
USB_LOG_RAW(" Endpoint Descriptor:\r\n");
|
||||
USB_LOG_RAW(" bLength: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bLength);
|
||||
USB_LOG_RAW(" bDescriptorType: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bDescriptorType);
|
||||
USB_LOG_RAW(" bEndpointAddress: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bEndpointAddress);
|
||||
USB_LOG_RAW(" bmAttributes: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bmAttributes);
|
||||
USB_LOG_RAW(" wMaxPacketSize: 0x%04x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.wMaxPacketSize);
|
||||
USB_LOG_RAW(" bInterval: 0x%02x \r\n", hport->config.intf[i].altsetting[j].ep[k].ep_desc.bInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,35 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum usbh_event_type {
|
||||
/* USB HCD IRQ */
|
||||
USBH_EVENT_ERROR,
|
||||
USBH_EVENT_SOF,
|
||||
|
||||
/* USB DEVICE STATUS */
|
||||
USBH_EVENT_DEVICE_RESET,
|
||||
USBH_EVENT_DEVICE_CONNECTED,
|
||||
USBH_EVENT_DEVICE_DISCONNECTED,
|
||||
USBH_EVENT_DEVICE_CONFIGURED,
|
||||
USBH_EVENT_DEVICE_WAKEUP,
|
||||
USBH_EVENT_DEVICE_SUSPEND,
|
||||
USBH_EVENT_DEVICE_RESUME,
|
||||
|
||||
/* USB DEVICE INTERFACE STATUS */
|
||||
USBH_EVENT_INTERFACE_UNSUPPORTED,
|
||||
USBH_EVENT_INTERFACE_START,
|
||||
USBH_EVENT_INTERFACE_STOP,
|
||||
|
||||
/* USB FRAMEWORK STATUS */
|
||||
USBH_EVENT_INIT,
|
||||
USBH_EVENT_DEINIT,
|
||||
USBH_EVENT_UNKNOWN,
|
||||
};
|
||||
|
||||
#define USB_HUB_PORT_ANY 0
|
||||
#define USB_HUB_INDEX_ANY 0
|
||||
#define USB_INTERFACE_ANY 0xff
|
||||
|
||||
#define USB_CLASS_MATCH_VENDOR 0x0001
|
||||
#define USB_CLASS_MATCH_PRODUCT 0x0002
|
||||
#define USB_CLASS_MATCH_INTF_CLASS 0x0004
|
||||
@@ -135,7 +164,7 @@ struct usbh_hub {
|
||||
uint8_t powerdelay;
|
||||
uint8_t tt_think;
|
||||
bool ismtt;
|
||||
struct usb_hub_descriptor hub_desc; /* USB 2.0 only */
|
||||
struct usb_hub_descriptor hub_desc; /* USB 2.0 only */
|
||||
struct usb_hub_ss_descriptor hub_ss_desc; /* USB 3.0 only */
|
||||
struct usbh_hubport child[CONFIG_USBHOST_MAX_EHPORTS];
|
||||
struct usbh_hubport *parent;
|
||||
@@ -280,7 +309,7 @@ int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *out
|
||||
*/
|
||||
int usbh_set_interface(struct usbh_hubport *hport, uint8_t intf, uint8_t altsetting);
|
||||
|
||||
int usbh_initialize(uint8_t busid, uintptr_t reg_base);
|
||||
int usbh_initialize(uint8_t busid, uintptr_t reg_base, usbh_event_handler_t event_handler);
|
||||
int usbh_deinitialize(uint8_t busid);
|
||||
void *usbh_find_class_instance(const char *devname);
|
||||
struct usbh_hubport *usbh_find_hubport(uint8_t busid, uint8_t hub_index, uint8_t hub_port);
|
||||
|
||||
@@ -19,7 +19,7 @@ struct usbotg_core_priv {
|
||||
bool usbd_initialized;
|
||||
usbd_event_handler_t device_event_callback;
|
||||
usbh_event_handler_t host_event_callback;
|
||||
uint8_t current_mode;
|
||||
uint8_t request_mode;
|
||||
usb_osal_sem_t change_sem;
|
||||
usb_osal_thread_t change_thread;
|
||||
} g_usbotg_core[CONFIG_USB_OTG_MAX_BUS];
|
||||
@@ -66,9 +66,9 @@ static void usbotg_rolechange_thread(void *argument)
|
||||
|
||||
while (1) {
|
||||
if (usb_osal_sem_take(g_usbotg_core[busid].change_sem, USB_OSAL_WAITING_FOREVER) == 0) {
|
||||
if (g_usbotg_core[busid].current_mode == USBOTG_MODE_HOST) {
|
||||
if (g_usbotg_core[busid].request_mode == USBOTG_MODE_HOST) {
|
||||
usbotg_host_initialize(busid);
|
||||
} else if (g_usbotg_core[busid].current_mode == USBOTG_MODE_DEVICE) {
|
||||
} else if (g_usbotg_core[busid].request_mode == USBOTG_MODE_DEVICE) {
|
||||
usbotg_device_initialize(busid);
|
||||
}
|
||||
}
|
||||
@@ -110,13 +110,13 @@ int usbotg_deinitialize(uint8_t busid)
|
||||
USB_ASSERT_MSG(busid < CONFIG_USB_OTG_MAX_BUS, "bus overflow\r\n");
|
||||
|
||||
if (g_usbotg_core[busid].usbd_initialized) {
|
||||
g_usbotg_core[busid].usbd_initialized = false;
|
||||
usbd_deinitialize(busid);
|
||||
g_usbotg_core[busid].usbd_initialized = false;
|
||||
}
|
||||
|
||||
if (g_usbotg_core[busid].usbh_initialized) {
|
||||
g_usbotg_core[busid].usbh_initialized = false;
|
||||
usbh_deinitialize(busid);
|
||||
g_usbotg_core[busid].usbh_initialized = false;
|
||||
}
|
||||
|
||||
if (g_usbotg_core[busid].change_thread) {
|
||||
@@ -135,7 +135,7 @@ void usbotg_trigger_role_change(uint8_t busid, uint8_t mode)
|
||||
{
|
||||
USB_ASSERT_MSG(busid < CONFIG_USB_OTG_MAX_BUS, "bus overflow\r\n");
|
||||
|
||||
g_usbotg_core[busid].current_mode = mode;
|
||||
g_usbotg_core[busid].request_mode = mode;
|
||||
|
||||
if (g_usbotg_core[busid].change_sem) {
|
||||
usb_osal_sem_give(g_usbotg_core[busid].change_sem);
|
||||
@@ -146,9 +146,9 @@ void USBOTG_IRQHandler(uint8_t busid)
|
||||
{
|
||||
USB_ASSERT_MSG(busid < CONFIG_USB_OTG_MAX_BUS, "bus overflow\r\n");
|
||||
|
||||
if (g_usbotg_core[busid].current_mode == USBOTG_MODE_HOST && g_usbotg_core[busid].usbh_initialized) {
|
||||
if (g_usbotg_core[busid].usbh_initialized) {
|
||||
USBH_IRQHandler(busid);
|
||||
} else if (g_usbotg_core[busid].current_mode == USBOTG_MODE_DEVICE && g_usbotg_core[busid].usbd_initialized) {
|
||||
} else if (g_usbotg_core[busid].usbd_initialized) {
|
||||
USBD_IRQHandler(busid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,6 @@ struct usb_msosv1_descriptor msosv1_desc = {
|
||||
.comp_id_property = WINUSB_IFx_WCIDProperties,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0100, 0x01)
|
||||
};
|
||||
@@ -171,80 +170,6 @@ const struct usb_descriptor adb_descriptor = {
|
||||
.string_descriptor_callback = string_descriptor_callback,
|
||||
.msosv1_descriptor = &msosv1_desc
|
||||
};
|
||||
#else
|
||||
/*!< global descriptor */
|
||||
static const uint8_t adb_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0100, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
ADB_DESCRIPTOR_INIT(ADB_INTF_NUM, WINUSB_IN_EP, WINUSB_OUT_EP, WINUSB_MAX_MPS),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'A', 0x00, /* wcChar6 */
|
||||
'D', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x1C, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'A', 0x00, /* wcChar6 */
|
||||
'D', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
'2', 0x00, /* wcChar9 */
|
||||
'0', 0x00, /* wcChar10 */
|
||||
'2', 0x00, /* wcChar11 */
|
||||
'4', 0x00, /* wcChar12 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
static void usbd_event_handler(uint8_t busid, uint8_t event)
|
||||
{
|
||||
@@ -294,14 +219,9 @@ void cherryadb_init(uint8_t busid, uint32_t reg_base)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
|
||||
usbd_desc_register(busid, &adb_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, adb_descriptor);
|
||||
#endif
|
||||
#ifndef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_msosv1_desc_register(busid, &msosv1_desc);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_adb_init_intf(busid, &intf0, WINUSB_IN_EP, WINUSB_OUT_EP));
|
||||
usbd_initialize(busid, reg_base, usbd_event_handler);
|
||||
}
|
||||
@@ -21,8 +21,9 @@
|
||||
|
||||
#define AUDIO_IN_FU_ID 0x02
|
||||
|
||||
/* AUDIO Class Config */
|
||||
#define AUDIO_FREQ 16000U
|
||||
#define AUDIO_MIC_FREQ 16000U
|
||||
#define AUDIO_MIC_FRAME_SIZE_BYTE 2u
|
||||
#define AUDIO_MIC_RESOLUTION_BIT 16u
|
||||
|
||||
#define IN_CHANNEL_NUM 2
|
||||
|
||||
@@ -54,7 +55,7 @@
|
||||
|
||||
/* AudioFreq * DataSize (2 bytes) * NumChannels (Stereo: 1) */
|
||||
/* 16bit(2 Bytes) 单声道(Mono:1) */
|
||||
#define AUDIO_IN_PACKET ((uint32_t)((AUDIO_FREQ * 2 * IN_CHANNEL_NUM) / 1000))
|
||||
#define AUDIO_IN_PACKET ((uint32_t)((AUDIO_MIC_FREQ * 2 * IN_CHANNEL_NUM) / 1000))
|
||||
|
||||
#define USB_CONFIG_SIZE (unsigned long)(9 + \
|
||||
AUDIO_AC_DESCRIPTOR_LEN(1) + \
|
||||
@@ -68,7 +69,6 @@
|
||||
AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(IN_CHANNEL_NUM, 1) + \
|
||||
AUDIO_SIZEOF_AC_OUTPUT_TERMINAL_DESC)
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
|
||||
};
|
||||
@@ -79,7 +79,7 @@ static const uint8_t config_descriptor[] = {
|
||||
AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, IN_CHANNEL_NUM, INPUT_CH_ENABLE),
|
||||
AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x01, 0x01, INPUT_CTRL),
|
||||
AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID),
|
||||
AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, 2, 16, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET, EP_INTERVAL, AUDIO_SAMPLE_FREQ_3B(AUDIO_FREQ))
|
||||
AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET, EP_INTERVAL, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ))
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
@@ -134,89 +134,6 @@ const struct usb_descriptor audio_v1_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t audio_v1_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, 0x00, 0x01),
|
||||
AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, IN_CHANNEL_NUM, INPUT_CH_ENABLE),
|
||||
AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x01, 0x01, INPUT_CTRL),
|
||||
AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID),
|
||||
AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, 2, 16, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET, EP_INTERVAL, AUDIO_SAMPLE_FREQ_3B(AUDIO_FREQ)),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'U', 0x00, /* wcChar10 */
|
||||
'A', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'0' + IN_CHANNEL_NUM, 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
volatile bool tx_flag = 0;
|
||||
volatile bool ep_tx_busy_flag = false;
|
||||
@@ -305,11 +222,8 @@ struct audio_entity_info audio_entity_table[] = {
|
||||
|
||||
void audio_v1_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &audio_v1_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, audio_v1_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf0, 0x0100, audio_entity_table, 1));
|
||||
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf1, 0x0100, audio_entity_table, 1));
|
||||
usbd_add_endpoint(busid, &audio_in_ep);
|
||||
|
||||
@@ -123,15 +123,14 @@
|
||||
AUDIO_AS_FEEDBACK_DESCRIPTOR_LEN(1))
|
||||
#endif
|
||||
|
||||
#define AUDIO_AC_SIZ (AUDIO_SIZEOF_AC_HEADER_DESC(2) + \
|
||||
AUDIO_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(2, 1) + \
|
||||
AUDIO_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(2, 1) + \
|
||||
#define AUDIO_AC_SIZ (AUDIO_SIZEOF_AC_HEADER_DESC(2) + \
|
||||
AUDIO_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(IN_CHANNEL_NUM, 1) + \
|
||||
AUDIO_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(OUT_CHANNEL_NUM, 1) + \
|
||||
AUDIO_SIZEOF_AC_OUTPUT_TERMINAL_DESC)
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
|
||||
};
|
||||
@@ -208,104 +207,6 @@ const struct usb_descriptor audio_v1_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t audio_v1_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x03, AUDIO_AC_SIZ, 0x00, 0x01, 0x02),
|
||||
AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, IN_CHANNEL_NUM, INPUT_CH_ENABLE),
|
||||
AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x01, 0x01, INPUT_CTRL),
|
||||
AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID),
|
||||
AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE),
|
||||
AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x04, 0x01, OUTPUT_CTRL),
|
||||
AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID),
|
||||
AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET,
|
||||
EP_INTERVAL, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ)),
|
||||
#if USING_FEEDBACK == 0
|
||||
AUDIO_AS_DESCRIPTOR_INIT(0x02, 0x04, OUT_CHANNEL_NUM, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET,
|
||||
EP_INTERVAL, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
|
||||
#else
|
||||
AUDIO_AS_FEEDBACK_DESCRIPTOR_INIT(0x02, 0x04, OUT_CHANNEL_NUM, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, AUDIO_OUT_PACKET,
|
||||
EP_INTERVAL, AUDIO_OUT_FEEDBACK_EP, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
|
||||
#endif
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'U', 0x00, /* wcChar10 */
|
||||
'A', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
#if USING_FEEDBACK == 0
|
||||
'1', 0x00, /* wcChar9 */
|
||||
#else
|
||||
'2', 0x00, /* wcChar9 */
|
||||
#endif
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[AUDIO_OUT_PACKET];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[AUDIO_IN_PACKET];
|
||||
@@ -453,11 +354,8 @@ struct audio_entity_info audio_entity_table[] = {
|
||||
|
||||
void audio_v1_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &audio_v1_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, audio_v1_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf0, 0x0100, audio_entity_table, 2));
|
||||
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf1, 0x0100, audio_entity_table, 2));
|
||||
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf2, 0x0100, audio_entity_table, 2));
|
||||
|
||||
@@ -72,7 +72,6 @@
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(IN_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC)
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01)
|
||||
};
|
||||
@@ -139,90 +138,6 @@ const struct usb_descriptor audio_v2_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t audio_v2_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, AUDIO_CATEGORY_MICROPHONE, 0x00, 0x00),
|
||||
AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_IN_CLOCK_ID, 0x03, 0x03),
|
||||
AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_INTERM_MIC, AUDIO_IN_CLOCK_ID, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
|
||||
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x02, INPUT_CTRL),
|
||||
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID, AUDIO_IN_CLOCK_ID, 0x0000),
|
||||
AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x04, IN_CHANNEL_NUM, INPUT_CH_ENABLE, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'U', 0x00, /* wcChar10 */
|
||||
'A', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'1', 0x00, /* wcChar3 */
|
||||
'0', 0x00, /* wcChar4 */
|
||||
'3', 0x00, /* wcChar5 */
|
||||
'1', 0x00, /* wcChar6 */
|
||||
'0', 0x00, /* wcChar7 */
|
||||
'0', 0x00, /* wcChar8 */
|
||||
'4', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
static const uint8_t mic_default_sampling_freq_table[] = {
|
||||
AUDIO_SAMPLE_FREQ_NUM(5),
|
||||
@@ -339,11 +254,8 @@ struct audio_entity_info audio_entity_table[] = {
|
||||
|
||||
void audio_v2_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &audio_v2_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, audio_v2_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf0, 0x0200, audio_entity_table, 2));
|
||||
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf1, 0x0200, audio_entity_table, 2));
|
||||
usbd_add_endpoint(busid, &audio_in_ep);
|
||||
|
||||
@@ -138,7 +138,6 @@
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(IN_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC)
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01)
|
||||
};
|
||||
@@ -214,103 +213,6 @@ const struct usb_descriptor audio_v2_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
uint8_t audio_v2_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x03, AUDIO_AC_SIZ, AUDIO_CATEGORY_UNDEF, 0x00, 0x00),
|
||||
AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_OUT_CLOCK_ID, 0x03, 0x03),
|
||||
AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_TERMINAL_STREAMING, AUDIO_OUT_CLOCK_ID, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, 0x0000),
|
||||
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x02, OUTPUT_CTRL),
|
||||
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID, AUDIO_OUT_CLOCK_ID, 0x0000),
|
||||
AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_IN_CLOCK_ID, 0x03, 0x03),
|
||||
AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_INTERM_MIC, AUDIO_IN_CLOCK_ID, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
|
||||
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x06, INPUT_CTRL),
|
||||
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x08, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID, AUDIO_IN_CLOCK_ID, 0x0000),
|
||||
#if USING_FEEDBACK == 0
|
||||
AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL),
|
||||
#else
|
||||
AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL, AUDIO_OUT_FEEDBACK_EP),
|
||||
#endif
|
||||
AUDIO_V2_AS_DESCRIPTOR_INIT(0x02, 0x08, IN_CHANNEL_NUM, INPUT_CH_ENABLE, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'U', 0x00, /* wcChar10 */
|
||||
'A', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'1', 0x00, /* wcChar3 */
|
||||
'0', 0x00, /* wcChar4 */
|
||||
'3', 0x00, /* wcChar5 */
|
||||
'1', 0x00, /* wcChar6 */
|
||||
'0', 0x00, /* wcChar7 */
|
||||
'0', 0x00, /* wcChar8 */
|
||||
#if USING_FEEDBACK == 0
|
||||
'3', 0x00, /* wcChar9 */
|
||||
#else
|
||||
'4', 0x00, /* wcChar9 */
|
||||
#endif
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
static const uint8_t speaker_default_sampling_freq_table[] = {
|
||||
AUDIO_SAMPLE_FREQ_NUM(5),
|
||||
@@ -519,11 +421,8 @@ struct audio_entity_info audio_entity_table[] = {
|
||||
|
||||
void audio_v2_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &audio_v2_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, audio_v2_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf0, 0x0200, audio_entity_table, 4));
|
||||
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf1, 0x0200, audio_entity_table, 4));
|
||||
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf2, 0x0200, audio_entity_table, 4));
|
||||
|
||||
@@ -87,7 +87,6 @@
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(OUT_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC)
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01)
|
||||
};
|
||||
@@ -158,98 +157,6 @@ const struct usb_descriptor audio_v2_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t audio_v2_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, AUDIO_CATEGORY_SPEAKER, 0x00, 0x00),
|
||||
AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_OUT_CLOCK_ID, 0x03, 0x03),
|
||||
AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_TERMINAL_STREAMING, AUDIO_OUT_CLOCK_ID, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, 0x0000),
|
||||
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x02, OUTPUT_CTRL),
|
||||
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID, AUDIO_OUT_CLOCK_ID, 0x0000),
|
||||
#if USING_FEEDBACK == 0
|
||||
AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL),
|
||||
#else
|
||||
AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, AUDIO_OUT_PACKET, EP_INTERVAL, AUDIO_OUT_FEEDBACK_EP),
|
||||
#endif
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'U', 0x00, /* wcChar10 */
|
||||
'A', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'1', 0x00, /* wcChar3 */
|
||||
'0', 0x00, /* wcChar4 */
|
||||
'3', 0x00, /* wcChar5 */
|
||||
'1', 0x00, /* wcChar6 */
|
||||
'0', 0x00, /* wcChar7 */
|
||||
'0', 0x00, /* wcChar8 */
|
||||
#if USING_FEEDBACK == 0
|
||||
'3', 0x00, /* wcChar9 */
|
||||
#else
|
||||
'4', 0x00, /* wcChar9 */
|
||||
#endif
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
static const uint8_t default_sampling_freq_table[] = {
|
||||
AUDIO_SAMPLE_FREQ_NUM(5),
|
||||
@@ -401,11 +308,8 @@ struct audio_entity_info audio_entity_table[] = {
|
||||
|
||||
void audio_v2_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &audio_v2_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, audio_v2_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf0, 0x0200, audio_entity_table, 2));
|
||||
usbd_add_interface(busid, usbd_audio_init_intf(busid, &intf1, 0x0200, audio_entity_table, 2));
|
||||
usbd_add_endpoint(busid, &audio_out_ep);
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#define MSC_MAX_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01)
|
||||
};
|
||||
@@ -85,85 +84,6 @@ const struct usb_descriptor msc_bootuf2_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t msc_bootuf2_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x02),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'U', 0x00, /* wcChar10 */
|
||||
'F', 0x00, /* wcChar11 */
|
||||
'2', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
static void usbd_event_handler(uint8_t busid, uint8_t event)
|
||||
{
|
||||
@@ -215,11 +135,9 @@ static struct usbd_interface intf0;
|
||||
void msc_bootuf2_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
boot2uf2_flash_init();
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
|
||||
usbd_desc_register(busid, &msc_bootuf2_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, msc_bootuf2_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_msc_init_intf(busid, &intf0, MSC_OUT_EP, MSC_IN_EP));
|
||||
|
||||
usbd_initialize(busid, reg_base, usbd_event_handler);
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
#define MSC_MAX_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01)
|
||||
};
|
||||
@@ -107,87 +106,6 @@ const struct usb_descriptor cdc_acm_hid_msc_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t cdc_acm_hid_msc_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x04, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
|
||||
MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x02),
|
||||
HID_MOUSE_DESCRIPTOR_INIT(0x03, 0x01, HID_MOUSE_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'C', 0x00, /* wcChar10 */
|
||||
'M', 0x00, /* wcChar11 */
|
||||
'H', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
/*!< hid mouse report descriptor */
|
||||
static const uint8_t hid_mouse_report_desc[HID_MOUSE_REPORT_DESC_SIZE] = {
|
||||
@@ -339,11 +257,8 @@ struct usbd_interface intf3;
|
||||
|
||||
void cdc_acm_hid_msc_descriptor_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &cdc_acm_hid_msc_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, cdc_acm_hid_msc_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0));
|
||||
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
|
||||
usbd_add_endpoint(busid, &cdc_out_ep);
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#define CDC_MAX_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
|
||||
};
|
||||
@@ -89,86 +88,6 @@ const struct usb_descriptor cdc_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
/*!< global descriptor */
|
||||
static const uint8_t cdc_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'C', 0x00, /* wcChar10 */
|
||||
'D', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
chry_ringbuffer_t usb_rx_rb;
|
||||
uint8_t usb_rx_buffer[2048];
|
||||
@@ -243,11 +162,9 @@ static struct usbd_interface intf1;
|
||||
void cdc_acm_mavlink_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
chry_ringbuffer_init(&usb_rx_rb, usb_rx_buffer, sizeof(usb_rx_buffer));
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
|
||||
usbd_desc_register(busid, &cdc_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, cdc_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0));
|
||||
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
|
||||
usbd_add_endpoint(busid, &cdc_out_ep);
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#define MSC_MAX_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
|
||||
};
|
||||
@@ -98,87 +97,6 @@ const struct usb_descriptor cdc_msc_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
/*!< global descriptor */
|
||||
static const uint8_t cdc_msc_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
|
||||
MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x00),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'C', 0x00, /* wcChar10 */
|
||||
'-', 0x00, /* wcChar11 */
|
||||
'M', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048]; /* 2048 is only for test speed , please use CDC_MAX_MPS for common*/
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
|
||||
@@ -249,11 +167,8 @@ struct usbd_interface intf2;
|
||||
|
||||
void cdc_acm_msc_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &cdc_msc_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, cdc_msc_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0));
|
||||
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
|
||||
usbd_add_endpoint(busid, &cdc_out_ep);
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#define CDC_MAX_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
|
||||
};
|
||||
@@ -102,89 +101,6 @@ const struct usb_descriptor cdc_multi_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
/*!< global descriptor */
|
||||
static const uint8_t cdc_multi_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x08, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
|
||||
CDC_ACM_DESCRIPTOR_INIT(0x02, CDC_INT_EP2, CDC_OUT_EP2, CDC_IN_EP2, CDC_MAX_MPS, 0x02),
|
||||
CDC_ACM_DESCRIPTOR_INIT(0x04, CDC_INT_EP3, CDC_OUT_EP3, CDC_IN_EP3, CDC_MAX_MPS, 0x02),
|
||||
CDC_ACM_DESCRIPTOR_INIT(0x06, CDC_INT_EP4, CDC_OUT_EP4, CDC_IN_EP4, CDC_MAX_MPS, 0x02),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'C', 0x00, /* wcChar10 */
|
||||
'D', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[4][2048];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[4][2048];
|
||||
@@ -292,11 +208,8 @@ struct usbd_interface intf7;
|
||||
|
||||
void cdc_acm_multi_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &cdc_multi_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, cdc_multi_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0));
|
||||
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
|
||||
usbd_add_endpoint(busid, &cdc_out_ep1);
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#define CDC_MAX_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
|
||||
};
|
||||
@@ -87,86 +86,6 @@ const struct usb_descriptor cdc_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
/*!< global descriptor */
|
||||
static const uint8_t cdc_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'C', 0x00, /* wcChar10 */
|
||||
'D', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
static void usbd_event_handler(uint8_t busid, uint8_t event)
|
||||
{
|
||||
@@ -198,11 +117,8 @@ extern void usbd_cdc_acm_serial_init(uint8_t busid, uint8_t in_ep, uint8_t out_e
|
||||
|
||||
void cdc_acm_chardev_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &cdc_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, cdc_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_cdc_acm_serial_init(busid, CDC_IN_EP, CDC_OUT_EP);
|
||||
usbd_initialize(busid, reg_base, usbd_event_handler);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#define CDC_MAX_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
|
||||
};
|
||||
@@ -87,86 +86,6 @@ const struct usb_descriptor cdc_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
/*!< global descriptor */
|
||||
static const uint8_t cdc_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'C', 0x00, /* wcChar10 */
|
||||
'D', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048]; /* 2048 is only for test speed , please use CDC_MAX_MPS for common*/
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
|
||||
@@ -245,11 +164,8 @@ void cdc_acm_init(uint8_t busid, uintptr_t reg_base)
|
||||
memcpy(&write_buffer[0], data, 10);
|
||||
memset(&write_buffer[10], 'a', 2038);
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &cdc_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, cdc_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0));
|
||||
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
|
||||
usbd_add_endpoint(busid, &cdc_out_ep);
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
/* str idx = 4 is for mac address: aa:bb:cc:dd:ee:ff*/
|
||||
#define CDC_ECM_MAC_STRING_INDEX 4
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
|
||||
};
|
||||
@@ -83,7 +82,7 @@ static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
|
||||
|
||||
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
|
||||
{
|
||||
if (index > 3) {
|
||||
if (index > 4) {
|
||||
return NULL;
|
||||
}
|
||||
return string_descriptors[index];
|
||||
@@ -95,107 +94,6 @@ const struct usb_descriptor cdc_ecm_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
/*!< global descriptor */
|
||||
static const uint8_t cdc_ecm_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
CDC_ECM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, CDC_ECM_MAC_STRING_INDEX),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x2E, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'C', 0x00, /* wcChar10 */
|
||||
'D', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'E', 0x00, /* wcChar14 */
|
||||
'C', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
' ', 0x00, /* wcChar17 */
|
||||
'D', 0x00, /* wcChar18 */
|
||||
'E', 0x00, /* wcChar19 */
|
||||
'M', 0x00, /* wcChar20 */
|
||||
'O', 0x00, /* wcChar21 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
///////////////////////////////////////
|
||||
/// string4 descriptor
|
||||
///////////////////////////////////////
|
||||
0x1A, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'a', 0x00, /* wcChar0 */
|
||||
'a', 0x00, /* wcChar1 */
|
||||
'b', 0x00, /* wcChar2 */
|
||||
'b', 0x00, /* wcChar3 */
|
||||
'c', 0x00, /* wcChar4 */
|
||||
'c', 0x00, /* wcChar5 */
|
||||
'd', 0x00, /* wcChar6 */
|
||||
'd', 0x00, /* wcChar7 */
|
||||
'e', 0x00, /* wcChar8 */
|
||||
'e', 0x00, /* wcChar9 */
|
||||
'f', 0x00, /* wcChar10 */
|
||||
'f', 0x00, /* wcChar11 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
const uint8_t mac[6] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
|
||||
|
||||
@@ -459,11 +357,8 @@ void cdc_ecm_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
cdc_ecm_lwip_init();
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &cdc_ecm_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, cdc_ecm_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_cdc_ecm_init_intf(&intf0, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP));
|
||||
usbd_add_interface(busid, usbd_cdc_ecm_init_intf(&intf1, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP));
|
||||
usbd_initialize(busid, reg_base, usbd_event_handler);
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#define CDC_MAX_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
|
||||
};
|
||||
@@ -91,88 +90,6 @@ const struct usb_descriptor cdc_rndis_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
/*!< global descriptor */
|
||||
static const uint8_t cdc_rndis_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
CDC_RNDIS_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x2A, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'R', 0x00, /* wcChar10 */
|
||||
'N', 0x00, /* wcChar11 */
|
||||
'D', 0x00, /* wcChar12 */
|
||||
'I', 0x00, /* wcChar13 */
|
||||
'S', 0x00, /* wcChar14 */
|
||||
' ', 0x00, /* wcChar15 */
|
||||
'D', 0x00, /* wcChar16 */
|
||||
'E', 0x00, /* wcChar17 */
|
||||
'M', 0x00, /* wcChar18 */
|
||||
'O', 0x00, /* wcChar19 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
const uint8_t mac[6] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
|
||||
|
||||
@@ -438,11 +355,8 @@ void cdc_rndis_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
rndis_lwip_init();
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &cdc_rndis_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, cdc_rndis_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_rndis_init_intf(&intf0, CDC_OUT_EP, CDC_IN_EP, CDC_INT_EP, (uint8_t *)mac));
|
||||
usbd_add_interface(busid, usbd_rndis_init_intf(&intf1, CDC_OUT_EP, CDC_IN_EP, CDC_INT_EP, (uint8_t *)mac));
|
||||
usbd_initialize(busid, reg_base, usbd_event_handler);
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
#define USB_CONFIG_SIZE (9 + 9 + 9)
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01)
|
||||
};
|
||||
@@ -77,134 +76,6 @@ const struct usb_descriptor dfu_flash_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t dfu_flash_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
DFU_DESCRIPTOR_INIT(),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x1e, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'D', 0x00, /* wcChar0 */
|
||||
'F', 0x00, /* wcChar1 */
|
||||
'U', 0x00, /* wcChar2 */
|
||||
'W', 0x00, /* wcChar3 */
|
||||
'i', 0x00, /* wcChar4 */
|
||||
't', 0x00, /* wcChar5 */
|
||||
'h', 0x00, /* wcChar6 */
|
||||
's', 0x00, /* wcChar7 */
|
||||
't', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
't', 0x00, /* wcChar10 */
|
||||
'o', 0x00, /* wcChar11 */
|
||||
'o', 0x00, /* wcChar12 */
|
||||
'l', 0x00, /* wcChar13 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
///////////////////////////////////////
|
||||
/// string4 descriptor
|
||||
///////////////////////////////////////
|
||||
0x60, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'@', 0x00, /* wcChar0 */
|
||||
'I', 0x00, /* wcChar1 */
|
||||
'n', 0x00, /* wcChar2 */
|
||||
't', 0x00, /* wcChar3 */
|
||||
'e', 0x00, /* wcChar4 */
|
||||
'r', 0x00, /* wcChar5 */
|
||||
'n', 0x00, /* wcChar6 */
|
||||
'a', 0x00, /* wcChar7 */
|
||||
'l', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'F', 0x00, /* wcChar10 */
|
||||
'l', 0x00, /* wcChar11*/
|
||||
'a', 0x00, /* wcChar12 */
|
||||
's', 0x00, /* wcChar13 */
|
||||
'h', 0x00, /* wcChar14 */
|
||||
' ', 0x00, /* wcChar15 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
' ', 0x00, /* wcChar17 */
|
||||
'/', 0x00, /* wcChar18 */
|
||||
'0', 0x00, /* wcChar19 */
|
||||
'x', 0x00, /* wcChar20 */
|
||||
'0', 0x00, /* wcChar21*/
|
||||
'8', 0x00, /* wcChar22 */
|
||||
'0', 0x00, /* wcChar23 */
|
||||
'0', 0x00, /* wcChar24 */
|
||||
'0', 0x00, /* wcChar25 */
|
||||
'0', 0x00, /* wcChar26 */
|
||||
'0', 0x00, /* wcChar27 */
|
||||
'0', 0x00, /* wcChar28 */
|
||||
'/', 0x00, /* wcChar29 */
|
||||
'1', 0x00, /* wcChar30 */
|
||||
'6', 0x00, /* wcChar31*/
|
||||
'*', 0x00, /* wcChar32 */
|
||||
'0', 0x00, /* wcChar33 */
|
||||
'0', 0x00, /* wcChar34 */
|
||||
'1', 0x00, /* wcChar35 */
|
||||
'K', 0x00, /* wcChar36 */
|
||||
'a', 0x00, /* wcChar37 */
|
||||
',', 0x00, /* wcChar38 */
|
||||
'1', 0x00, /* wcChar39 */
|
||||
'1', 0x00, /* wcChar40 */
|
||||
'2', 0x00, /* wcChar41*/
|
||||
'*', 0x00, /* wcChar42 */
|
||||
'0', 0x00, /* wcChar43 */
|
||||
'1', 0x00, /* wcChar44 */
|
||||
'K', 0x00, /* wcChar45 */
|
||||
'g', 0x00, /* wcChar46 */
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
static void usbd_event_handler(uint8_t busid, uint8_t event)
|
||||
{
|
||||
@@ -235,11 +106,8 @@ struct usbd_interface intf0;
|
||||
|
||||
void dfu_flash_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &dfu_flash_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, dfu_flash_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_dfu_init_intf(&intf0));
|
||||
usbd_initialize(busid, reg_base, usbd_event_handler);
|
||||
}
|
||||
|
||||
250
demo/gamepad_template.c
Normal file
250
demo/gamepad_template.c
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (c) 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_gamepad.h"
|
||||
|
||||
#define GAMEPAD_IN_EP 0x81
|
||||
#define GAMEPAD_OUT_EP 0x02
|
||||
|
||||
#define USBD_MAX_POWER 500
|
||||
|
||||
static const uint8_t xinput_device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, XINPUT_VID, XINPUT_PID, XINPUT_BCD_DEVICE, 0x01)
|
||||
};
|
||||
|
||||
static const uint8_t switch_device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, SWITCH_VID, SWITCH_PID, SWITCH_BCD_DEVICE, 0x01)
|
||||
};
|
||||
|
||||
static const uint8_t xinput_config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT((9 + XINPUT_DESCRIPTOR_LEN), 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
XINPUT_DESCRIPTOR_INIT(0x00, GAMEPAD_OUT_EP, GAMEPAD_IN_EP)
|
||||
};
|
||||
|
||||
static const uint8_t switch_config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT((9 + SWITCH_DESCRIPTOR_LEN), 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
SWITCH_DESCRIPTOR_INIT(0x00, GAMEPAD_OUT_EP, GAMEPAD_IN_EP)
|
||||
};
|
||||
|
||||
static const char *xinput_string_descriptors[] = {
|
||||
(const char[]){ 0x09, 0x04 }, /* Langid */
|
||||
"Microsoft", /* Manufacturer */
|
||||
"XInput STANDARD GAMEPAD", /* Product */
|
||||
"1.0", /* Serial Number */
|
||||
};
|
||||
|
||||
static const char *switch_string_descriptors[] = {
|
||||
(const char[]){ 0x09, 0x04 }, /* Langid */
|
||||
"HORI", /* Manufacturer */
|
||||
"Switch Pro Controller", /* Product */
|
||||
"1.0", /* Serial Number */
|
||||
};
|
||||
|
||||
uint8_t gamepad_mode = USBD_GAMEPAD_MODE_XINPUT;
|
||||
bool gamepad_init_flag = false;
|
||||
|
||||
static const uint8_t *device_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
switch (gamepad_mode) {
|
||||
case USBD_GAMEPAD_MODE_XINPUT:
|
||||
return xinput_device_descriptor;
|
||||
case USBD_GAMEPAD_MODE_SWITCH:
|
||||
return switch_device_descriptor;
|
||||
case USBD_GAMEPAD_MODE_XBOXONE:
|
||||
break;
|
||||
case USBD_GAMEPAD_MODE_PS4:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const uint8_t *config_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
switch (gamepad_mode) {
|
||||
case USBD_GAMEPAD_MODE_XINPUT:
|
||||
return xinput_config_descriptor;
|
||||
case USBD_GAMEPAD_MODE_SWITCH:
|
||||
return switch_config_descriptor;
|
||||
case USBD_GAMEPAD_MODE_XBOXONE:
|
||||
break;
|
||||
case USBD_GAMEPAD_MODE_PS4:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
|
||||
{
|
||||
if (index > 3) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (gamepad_mode) {
|
||||
case USBD_GAMEPAD_MODE_XINPUT:
|
||||
return xinput_string_descriptors[index];
|
||||
case USBD_GAMEPAD_MODE_SWITCH:
|
||||
return switch_string_descriptors[index];
|
||||
case USBD_GAMEPAD_MODE_XBOXONE:
|
||||
break;
|
||||
case USBD_GAMEPAD_MODE_PS4:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct usb_descriptor gamepad_descriptor = {
|
||||
.device_descriptor_callback = device_descriptor_callback,
|
||||
.config_descriptor_callback = config_descriptor_callback,
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t gamepad_read_buffer[64];
|
||||
struct usb_gamepad_report gamepad_report;
|
||||
|
||||
#define GAMEPAD_STATE_IDLE 0
|
||||
#define GAMEPAD_STATE_BUSY 1
|
||||
|
||||
volatile uint8_t gamepad_state = GAMEPAD_STATE_IDLE;
|
||||
|
||||
static void usbd_event_handler(uint8_t busid, uint8_t event)
|
||||
{
|
||||
switch (event) {
|
||||
case USBD_EVENT_RESET:
|
||||
break;
|
||||
case USBD_EVENT_CONNECTED:
|
||||
break;
|
||||
case USBD_EVENT_DISCONNECTED:
|
||||
break;
|
||||
case USBD_EVENT_RESUME:
|
||||
break;
|
||||
case USBD_EVENT_SUSPEND:
|
||||
break;
|
||||
case USBD_EVENT_CONFIGURED:
|
||||
usbd_ep_start_read(busid, GAMEPAD_OUT_EP, gamepad_read_buffer, usbd_get_ep_mps(busid, GAMEPAD_OUT_EP));
|
||||
break;
|
||||
case USBD_EVENT_SET_REMOTE_WAKEUP:
|
||||
break;
|
||||
case USBD_EVENT_CLR_REMOTE_WAKEUP:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void usbd_gamepad_int_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
gamepad_state = GAMEPAD_STATE_IDLE;
|
||||
}
|
||||
|
||||
void usbd_gamepad_int_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
usbd_ep_start_read(busid, GAMEPAD_OUT_EP, gamepad_read_buffer, usbd_get_ep_mps(busid, GAMEPAD_OUT_EP));
|
||||
}
|
||||
|
||||
/*!< endpoint call back */
|
||||
static struct usbd_endpoint gamepad_in_ep = {
|
||||
.ep_cb = usbd_gamepad_int_in_callback,
|
||||
.ep_addr = GAMEPAD_IN_EP
|
||||
};
|
||||
|
||||
static struct usbd_endpoint gamepad_out_ep = {
|
||||
.ep_cb = usbd_gamepad_int_out_callback,
|
||||
.ep_addr = GAMEPAD_OUT_EP
|
||||
};
|
||||
|
||||
static struct usbd_interface intf0;
|
||||
|
||||
void gamepad_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
if (gamepad_init_flag) {
|
||||
return;
|
||||
}
|
||||
|
||||
gamepad_init_flag = true;
|
||||
|
||||
usbd_desc_register(busid, &gamepad_descriptor);
|
||||
|
||||
switch (gamepad_mode) {
|
||||
case USBD_GAMEPAD_MODE_XINPUT:
|
||||
usbd_add_interface(busid, usbd_gamepad_xinput_init_intf(&intf0));
|
||||
break;
|
||||
case USBD_GAMEPAD_MODE_SWITCH:
|
||||
usbd_add_interface(busid, usbd_gamepad_switch_init_intf(&intf0));
|
||||
break;
|
||||
case USBD_GAMEPAD_MODE_XBOXONE:
|
||||
break;
|
||||
case USBD_GAMEPAD_MODE_PS4:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
usbd_add_endpoint(busid, &gamepad_in_ep);
|
||||
usbd_add_endpoint(busid, &gamepad_out_ep);
|
||||
usbd_initialize(busid, reg_base, usbd_event_handler);
|
||||
}
|
||||
|
||||
void gamepad_change_mode(uint8_t mode, uintptr_t reg_base)
|
||||
{
|
||||
gamepad_mode = mode;
|
||||
|
||||
if (gamepad_init_flag) {
|
||||
usbd_deinitialize(0);
|
||||
}
|
||||
gamepad_init_flag = false;
|
||||
gamepad_init(0, reg_base);
|
||||
}
|
||||
|
||||
void gamepad_test(uint8_t busid)
|
||||
{
|
||||
static uint32_t test_counter = 0;
|
||||
|
||||
if (usb_device_is_configured(busid) == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
gamepad_state = GAMEPAD_STATE_BUSY;
|
||||
memset(&gamepad_report, 0, sizeof(gamepad_report));
|
||||
|
||||
gamepad_report.buttons = (1 << (test_counter % 18));
|
||||
|
||||
switch (gamepad_mode) {
|
||||
case USBD_GAMEPAD_MODE_XINPUT:
|
||||
usbd_gamepad_xinput_send_report(GAMEPAD_IN_EP, &gamepad_report);
|
||||
break;
|
||||
case USBD_GAMEPAD_MODE_SWITCH:
|
||||
usbd_gamepad_switch_send_report(GAMEPAD_IN_EP, &gamepad_report);
|
||||
break;
|
||||
case USBD_GAMEPAD_MODE_XBOXONE:
|
||||
break;
|
||||
case USBD_GAMEPAD_MODE_PS4:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
test_counter++;
|
||||
while (gamepad_state == GAMEPAD_STATE_BUSY) {
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@
|
||||
#define HIDRAW_IN_INTERVAL 1
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01)
|
||||
};
|
||||
@@ -92,86 +91,6 @@ const struct usb_descriptor hid_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
/*!< global descriptor */
|
||||
static const uint8_t hid_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
HID_CUSTOM_INOUT_DESCRIPTOR_INIT(0x00, 0x01, HID_CUSTOM_REPORT_DESC_SIZE, HIDRAW_OUT_EP, HIDRAW_IN_EP, HID_MAX_MPS, HIDRAW_IN_INTERVAL),
|
||||
/*
|
||||
* string0 descriptor
|
||||
*/
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
/*
|
||||
* string1 descriptor
|
||||
*/
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
/*
|
||||
* string2 descriptor
|
||||
*/
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'H', 0x00, /* wcChar10 */
|
||||
'I', 0x00, /* wcChar11 */
|
||||
'D', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
/*
|
||||
* string3 descriptor
|
||||
*/
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
/*
|
||||
* device qualifier descriptor
|
||||
*/
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
/*!< custom hid report descriptor */
|
||||
static const uint8_t hid_custom_report_desc[HID_CUSTOM_REPORT_DESC_SIZE] = {
|
||||
@@ -295,11 +214,8 @@ struct usbd_interface intf0;
|
||||
|
||||
void hid_custom_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &hid_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, hid_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf0, hid_custom_report_desc, HID_CUSTOM_REPORT_DESC_SIZE));
|
||||
usbd_add_endpoint(busid, &custom_in_ep);
|
||||
usbd_add_endpoint(busid, &custom_out_ep);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#define USB_CONFIG_SIZE 34
|
||||
#define HID_KEYBOARD_REPORT_DESC_SIZE 63
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01)
|
||||
};
|
||||
@@ -80,85 +79,6 @@ const struct usb_descriptor hid_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
static const uint8_t hid_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
HID_KEYBOARD_DESCRIPTOR_INIT(0x00, 0x01, HID_KEYBOARD_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'H', 0x00, /* wcChar10 */
|
||||
'I', 0x00, /* wcChar11 */
|
||||
'D', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
/* USB HID device Configuration Descriptor */
|
||||
static uint8_t hid_desc[9] __ALIGN_END = {
|
||||
@@ -255,11 +175,8 @@ struct usbd_interface intf0;
|
||||
|
||||
void hid_keyboard_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &hid_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, hid_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf0, hid_keyboard_report_desc, HID_KEYBOARD_REPORT_DESC_SIZE));
|
||||
usbd_add_endpoint(busid, &hid_in_ep);
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
/*!< report descriptor size */
|
||||
#define HID_MOUSE_REPORT_DESC_SIZE 74
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01)
|
||||
};
|
||||
@@ -83,86 +82,6 @@ const struct usb_descriptor hid_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
/*!< global descriptor */
|
||||
const uint8_t hid_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
HID_MOUSE_DESCRIPTOR_INIT(0x00, 0x01, HID_MOUSE_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'H', 0x00, /* wcChar10 */
|
||||
'I', 0x00, /* wcChar11 */
|
||||
'D', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
/*!< hid mouse report descriptor */
|
||||
static const uint8_t hid_mouse_report_desc[HID_MOUSE_REPORT_DESC_SIZE] = {
|
||||
@@ -273,11 +192,8 @@ struct usbd_interface intf0;
|
||||
|
||||
void hid_mouse_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &hid_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, hid_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf0, hid_mouse_report_desc, HID_MOUSE_REPORT_DESC_SIZE));
|
||||
usbd_add_endpoint(busid, &hid_in_ep);
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
/*!< report descriptor size */
|
||||
#define HID_MOUSE_REPORT_DESC_SIZE 74
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01)
|
||||
};
|
||||
@@ -83,86 +82,6 @@ const struct usb_descriptor hid_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
/*!< global descriptor */
|
||||
const uint8_t hid_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_REMOTE_WAKEUP | USB_CONFIG_SELF_POWERED, USBD_MAX_POWER),
|
||||
HID_MOUSE_DESCRIPTOR_INIT(0x00, 0x01, HID_MOUSE_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'H', 0x00, /* wcChar10 */
|
||||
'I', 0x00, /* wcChar11 */
|
||||
'D', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
/*!< hid mouse report descriptor */
|
||||
static const uint8_t hid_mouse_report_desc[HID_MOUSE_REPORT_DESC_SIZE] = {
|
||||
@@ -273,11 +192,8 @@ static struct usbd_interface intf0;
|
||||
|
||||
void hid_mouse_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &hid_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, hid_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf0, hid_mouse_report_desc, HID_MOUSE_REPORT_DESC_SIZE));
|
||||
usbd_add_endpoint(busid, &hid_in_ep);
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#define MIDI_EP_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0100, 0x01)
|
||||
};
|
||||
@@ -100,96 +99,6 @@ const struct usb_descriptor midi_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t midi_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0100, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, 0x00, 0x01),
|
||||
MIDI_STANDARD_DESCRIPTOR_INIT(0x01, 0x02),
|
||||
MIDI_CS_HEADER_DESCRIPTOR_INIT(AUDIO_MS_SIZ),
|
||||
MIDI_JACK_DESCRIPTOR_INIT(0x01),
|
||||
// OUT endpoint descriptor
|
||||
0x09, 0x05, MIDI_OUT_EP, 0x02, WBVAL(MIDI_EP_MPS), 0x00, 0x00, 0x00,
|
||||
0x05, 0x25, 0x01, 0x01, 0x01,
|
||||
|
||||
// IN endpoint descriptor
|
||||
0x09, 0x05, MIDI_IN_EP, 0x02, WBVAL(MIDI_EP_MPS), 0x00, 0x00, 0x00,
|
||||
0x05, 0x25, 0x01, 0x01, 0x03
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x28, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'M', 0x00, /* wcChar10 */
|
||||
'I', 0x00, /* wcChar11 */
|
||||
'D', 0x00, /* wcChar12 */
|
||||
'I', 0x00, /* wcChar13 */
|
||||
' ', 0x00, /* wcChar14 */
|
||||
'D', 0x00, /* wcChar15 */
|
||||
'E', 0x00, /* wcChar16 */
|
||||
'M', 0x00, /* wcChar17 */
|
||||
'O', 0x00, /* wcChar18 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'1', 0x00, /* wcChar3 */
|
||||
'0', 0x00, /* wcChar4 */
|
||||
'3', 0x00, /* wcChar5 */
|
||||
'1', 0x00, /* wcChar6 */
|
||||
'0', 0x00, /* wcChar7 */
|
||||
'0', 0x00, /* wcChar8 */
|
||||
'0', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[MIDI_EP_MPS];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[MIDI_EP_MPS];
|
||||
@@ -244,11 +153,8 @@ struct usbd_endpoint midi_in_ep = {
|
||||
|
||||
void midi_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &midi_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, midi_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, &intf0);
|
||||
usbd_add_interface(busid, &intf1);
|
||||
usbd_add_endpoint(busid, &midi_out_ep);
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#define MSC_MAX_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01)
|
||||
};
|
||||
@@ -84,85 +83,6 @@ const struct usb_descriptor msc_ram_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t msc_ram_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x02),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'M', 0x00, /* wcChar10 */
|
||||
'S', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
static void usbd_event_handler(uint8_t busid, uint8_t event)
|
||||
{
|
||||
@@ -267,11 +187,8 @@ void msc_ram_init(uint8_t busid, uintptr_t reg_base)
|
||||
res = rt_device_open(blk_dev, RT_DEVICE_OFLAG_RDWR);
|
||||
RT_ASSERT(res == RT_EOK);
|
||||
#endif
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &msc_ram_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, msc_ram_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_msc_init_intf(busid, &intf0, MSC_OUT_EP, MSC_IN_EP));
|
||||
|
||||
usbd_initialize(busid, reg_base, usbd_event_handler);
|
||||
|
||||
216
demo/usb_host.c
216
demo/usb_host.c
@@ -4,79 +4,73 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_cdc_acm.h"
|
||||
#include "usbh_serial.h"
|
||||
#include "usbh_hid.h"
|
||||
#include "usbh_msc.h"
|
||||
#include "usbh_video.h"
|
||||
#include "usbh_audio.h"
|
||||
|
||||
#ifndef CONFIG_TEST_USBH_CDC_ACM
|
||||
#define CONFIG_TEST_USBH_CDC_ACM 1
|
||||
#endif
|
||||
#ifndef TEST_USBH_CDC_SPEED
|
||||
#define TEST_USBH_CDC_SPEED 0
|
||||
#endif
|
||||
#ifndef CONFIG_TEST_USBH_HID
|
||||
#define CONFIG_TEST_USBH_HID 1
|
||||
#endif
|
||||
#ifndef CONFIG_TEST_USBH_MSC
|
||||
#define CONFIG_TEST_USBH_MSC 1
|
||||
#endif
|
||||
#ifndef TEST_USBH_MSC_FATFS
|
||||
#define TEST_USBH_MSC_FATFS 0
|
||||
#endif
|
||||
#ifndef TEST_USBH_MSC_FATFS_SPEED
|
||||
#define TEST_USBH_MSC_FATFS_SPEED 0
|
||||
#endif
|
||||
#ifndef CONFIG_TEST_USBH_AUDIO
|
||||
#define CONFIG_TEST_USBH_AUDIO 0
|
||||
#endif
|
||||
#ifndef CONFIG_TEST_USBH_VIDEO
|
||||
#define CONFIG_TEST_USBH_VIDEO 0
|
||||
// net class demos use socket api
|
||||
|
||||
#ifdef CONFIG_TEST_USBH_SERIAL
|
||||
#define SERIAL_TEST_LEN (1 * 1024)
|
||||
|
||||
#if SERIAL_TEST_LEN >= CONFIG_USBHOST_SERIAL_RX_SIZE
|
||||
#error SERIAL_TEST_LEN is larger than CONFIG_USBHOST_SERIAL_RX_SIZE, please reduce SERIAL_TEST_LEN or increase CONFIG_USBHOST_SERIAL_RX_SIZE
|
||||
#endif
|
||||
|
||||
#if defined(TEST_USBH_CDC_ECM) || defined(TEST_USBH_CDC_RNDIS) || defined(TEST_USBH_ASIX) || defined(TEST_USBH_RTL8152)
|
||||
#error we have move those class implements into platform/none/usbh_lwip.c, and you should call tcpip_init(NULL, NULL) in your app
|
||||
#endif
|
||||
volatile uint32_t serial_tx_bytes = 0;
|
||||
volatile uint32_t serial_rx_bytes = 0;
|
||||
volatile bool serial_is_opened = false;
|
||||
|
||||
#if CONFIG_TEST_USBH_CDC_ACM
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t cdc_buffer[4096];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t serial_tx_buffer[SERIAL_TEST_LEN];
|
||||
uint8_t serial_rx_data[SERIAL_TEST_LEN];
|
||||
|
||||
#if TEST_USBH_CDC_SPEED
|
||||
#ifdef CONFIG_TEST_USBH_CDC_SPEED
|
||||
#define TEST_LEN (16 * 1024)
|
||||
#define TEST_COUNT (10240)
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t cdc_speed_buffer[TEST_LEN];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t serial_speed_buffer[TEST_LEN];
|
||||
#endif
|
||||
|
||||
void usbh_cdc_acm_callback(void *arg, int nbytes)
|
||||
{
|
||||
//struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)arg;
|
||||
|
||||
if (nbytes > 0) {
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
USB_LOG_RAW("0x%02x ", cdc_buffer[i]);
|
||||
}
|
||||
USB_LOG_RAW("nbytes:%d\r\n", (unsigned int)nbytes);
|
||||
}
|
||||
}
|
||||
|
||||
static void usbh_cdc_acm_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
|
||||
static void usbh_serial_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_cdc_acm *cdc_acm_class = (struct usbh_cdc_acm *)CONFIG_USB_OSAL_THREAD_GET_ARGV;
|
||||
struct usbh_serial *serial;
|
||||
bool serial_test_success = false;
|
||||
|
||||
serial = usbh_serial_open("/dev/ttyACM0", USBH_SERIAL_O_RDWR | USBH_SERIAL_O_NONBLOCK);
|
||||
if (serial == NULL) {
|
||||
serial = usbh_serial_open("/dev/ttyUSB0", USBH_SERIAL_O_RDWR | USBH_SERIAL_O_NONBLOCK);
|
||||
if (serial == NULL) {
|
||||
USB_LOG_RAW("no serial device found\r\n");
|
||||
goto delete;
|
||||
}
|
||||
}
|
||||
|
||||
struct usbh_serial_termios termios;
|
||||
|
||||
memset(&termios, 0, sizeof(termios));
|
||||
termios.baudrate = 115200;
|
||||
termios.stopbits = 0;
|
||||
termios.parity = 0;
|
||||
termios.databits = 8;
|
||||
termios.rtscts = false;
|
||||
termios.rx_timeout = 0;
|
||||
ret = usbh_serial_control(serial, USBH_SERIAL_CMD_SET_ATTR, &termios);
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("set serial attr error, ret:%d\r\n", ret);
|
||||
goto delete_with_close;
|
||||
}
|
||||
|
||||
/* test with only one buffer, if you have more cdc acm class, modify by yourself */
|
||||
#if TEST_USBH_CDC_SPEED
|
||||
#ifdef CONFIG_TEST_USBH_CDC_SPEED
|
||||
const uint32_t test_len[] = { 512, 1 * 1024, 2 * 1024, 4 * 1024, 8 * 1024, 16 * 1024 };
|
||||
|
||||
memset(cdc_speed_buffer, 0xAA, TEST_LEN);
|
||||
memset(serial_speed_buffer, 0xAA, TEST_LEN);
|
||||
|
||||
for (uint8_t j = 0; j < 6; j++) {
|
||||
uint32_t start_time = (uint32_t)xTaskGetTickCount();
|
||||
for (uint32_t i = 0; i < TEST_COUNT; i++) {
|
||||
usbh_bulk_urb_fill(&cdc_acm_class->bulkout_urb, cdc_acm_class->hport, cdc_acm_class->bulkout, cdc_speed_buffer, test_len[j], 0XFFFFFFF, NULL, NULL);
|
||||
ret = usbh_submit_urb(&cdc_acm_class->bulkout_urb);
|
||||
usbh_serial_write(serial, serial_speed_buffer, test_len[j]);
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("bulk out error,ret:%d\r\n", ret);
|
||||
while (1) {
|
||||
@@ -87,35 +81,75 @@ static void usbh_cdc_acm_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
|
||||
uint32_t time_ms = xTaskGetTickCount() - start_time;
|
||||
USB_LOG_RAW("per packet len:%d, out speed:%f MB/S\r\n", (unsigned int)test_len[j], (test_len[j] * TEST_COUNT / 1024 / 1024) * 1000 / ((float)time_ms));
|
||||
}
|
||||
usbh_serial_close(serial);
|
||||
goto delete;
|
||||
#endif
|
||||
memset(cdc_buffer, 0x55, 4096);
|
||||
memset(serial_tx_buffer, 0xA5, sizeof(serial_tx_buffer));
|
||||
USB_LOG_RAW("start serial loopback test, len: %d\r\n", SERIAL_TEST_LEN);
|
||||
|
||||
/* for common, we use timeout with 0xffffffff, this is just a test */
|
||||
usbh_bulk_urb_fill(&cdc_acm_class->bulkout_urb, cdc_acm_class->hport, cdc_acm_class->bulkout, cdc_buffer, sizeof(cdc_buffer), 3000, NULL, NULL);
|
||||
ret = usbh_submit_urb(&cdc_acm_class->bulkout_urb);
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("bulk out error,ret:%d\r\n", ret);
|
||||
goto delete;
|
||||
} else {
|
||||
USB_LOG_RAW("send over:%d\r\n", (unsigned int)cdc_acm_class->bulkout_urb.actual_length);
|
||||
serial_tx_bytes = 0;
|
||||
while (1) {
|
||||
ret = usbh_serial_write(serial, serial_tx_buffer, sizeof(serial_tx_buffer));
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("serial write error, ret:%d\r\n", ret);
|
||||
goto delete_with_close;
|
||||
} else {
|
||||
serial_tx_bytes += ret;
|
||||
|
||||
if (serial_tx_bytes == SERIAL_TEST_LEN) {
|
||||
USB_LOG_RAW("send over\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we can change cdc_acm_class->bulkin->wMaxPacketSize with 4096 for testing zlp, default is ep mps */
|
||||
usbh_bulk_urb_fill(&cdc_acm_class->bulkin_urb, cdc_acm_class->hport, cdc_acm_class->bulkin, cdc_buffer, cdc_acm_class->bulkin->wMaxPacketSize, 0xffffffff, usbh_cdc_acm_callback, cdc_acm_class);
|
||||
ret = usbh_submit_urb(&cdc_acm_class->bulkin_urb);
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("bulk in error,ret:%d\r\n", ret);
|
||||
goto delete;
|
||||
} else {
|
||||
volatile uint32_t wait_timeout = 0;
|
||||
serial_rx_bytes = 0;
|
||||
while (1) {
|
||||
ret = usbh_serial_read(serial, &serial_rx_data[serial_rx_bytes], SERIAL_TEST_LEN - serial_rx_bytes);
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("serial read error, ret:%d\r\n", ret);
|
||||
goto delete_with_close;
|
||||
} else {
|
||||
serial_rx_bytes += ret;
|
||||
|
||||
if (serial_rx_bytes == SERIAL_TEST_LEN) {
|
||||
USB_LOG_RAW("receive over\r\n");
|
||||
for (uint32_t i = 0; i < SERIAL_TEST_LEN; i++) {
|
||||
if (serial_rx_data[i] != 0xa5) {
|
||||
USB_LOG_RAW("serial loopback data error at index %d, data: 0x%02x\r\n", (unsigned int)i, serial_rx_data[i]);
|
||||
goto delete_with_close;
|
||||
}
|
||||
}
|
||||
serial_test_success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
wait_timeout++;
|
||||
|
||||
if (wait_timeout > 500) { // 5s
|
||||
USB_LOG_RAW("serial read timeout\r\n");
|
||||
goto delete_with_close;
|
||||
}
|
||||
|
||||
usb_osal_msleep(10);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
delete_with_close:
|
||||
if (serial_test_success) {
|
||||
USB_LOG_RAW("serial loopback test success\r\n");
|
||||
} else {
|
||||
USB_LOG_RAW("serial loopback test failed\r\n");
|
||||
}
|
||||
usbh_serial_close(serial);
|
||||
delete:
|
||||
usb_osal_thread_delete(NULL);
|
||||
// clang-format on
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_TEST_USBH_HID
|
||||
#ifdef CONFIG_TEST_USBH_HID
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t hid_buffer[128];
|
||||
|
||||
void usbh_hid_callback(void *arg, int nbytes)
|
||||
@@ -140,7 +174,6 @@ static void usbh_hid_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_hid *hid_class = (struct usbh_hid *)CONFIG_USB_OSAL_THREAD_GET_ARGV;
|
||||
;
|
||||
|
||||
/* test with only one buffer, if you have more hid class, modify by yourself */
|
||||
|
||||
@@ -157,15 +190,15 @@ delete:
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_TEST_USBH_MSC
|
||||
#ifdef CONFIG_TEST_USBH_MSC
|
||||
|
||||
#if TEST_USBH_MSC_FATFS
|
||||
#ifdef CONFIG_TEST_USBH_MSC_FATFS
|
||||
#include "ff.h"
|
||||
|
||||
#if TEST_USBH_MSC_FATFS_SPEED
|
||||
#ifdef CONFIG_TEST_USBH_MSC_FATFS_SPEED
|
||||
#define WRITE_SIZE_MB (128UL)
|
||||
#define WRITE_SIZE (1024UL * 1024UL * WRITE_SIZE_MB)
|
||||
#define BUF_SIZE (1024UL * 128UL)
|
||||
#define WRITE_SIZE (1024UL * 1024UL * WRITE_SIZE_MB)
|
||||
#define BUF_SIZE (1024UL * 128UL)
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_write_buffer[BUF_SIZE];
|
||||
#else
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_write_buffer[25 * 100];
|
||||
@@ -223,7 +256,7 @@ int usb_msc_fatfs_test()
|
||||
goto unmount;
|
||||
}
|
||||
|
||||
#if TEST_USBH_MSC_FATFS_SPEED
|
||||
#ifdef CONFIG_TEST_USBH_MSC_FATFS_SPEED
|
||||
for (uint32_t i = 0; i < BUF_SIZE; i++) {
|
||||
read_write_buffer[i] = i % 256;
|
||||
}
|
||||
@@ -234,7 +267,7 @@ int usb_msc_fatfs_test()
|
||||
uint32_t write_size = WRITE_SIZE;
|
||||
uint32_t start_time = (uint32_t)xTaskGetTickCount();
|
||||
while (write_size > 0) {
|
||||
res_sd = f_write(&fnew, read_write_buffer, BUF_SIZE, (UINT*)&fnum);
|
||||
res_sd = f_write(&fnew, read_write_buffer, BUF_SIZE, (UINT *)&fnum);
|
||||
if (res_sd != FR_OK) {
|
||||
USB_LOG_RAW("Write file failed, cause: %s\n", res_sd);
|
||||
goto unmount;
|
||||
@@ -260,7 +293,7 @@ int usb_msc_fatfs_test()
|
||||
uint32_t write_size = WRITE_SIZE;
|
||||
uint32_t start_time = (uint32_t)xTaskGetTickCount();
|
||||
while (write_size > 0) {
|
||||
res_sd = f_read(&fnew, read_write_buffer, BUF_SIZE, (UINT*)&fnum);
|
||||
res_sd = f_read(&fnew, read_write_buffer, BUF_SIZE, (UINT *)&fnum);
|
||||
if (res_sd != FR_OK) {
|
||||
USB_LOG_RAW("Read file failed, cause: %s\n", res_sd);
|
||||
goto unmount;
|
||||
@@ -295,8 +328,10 @@ static void usbh_msc_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
|
||||
int ret;
|
||||
struct usbh_msc *msc_class = (struct usbh_msc *)CONFIG_USB_OSAL_THREAD_GET_ARGV;
|
||||
|
||||
(void)msc_class;
|
||||
|
||||
/* test with only one buffer, if you have more msc class, modify by yourself */
|
||||
#if TEST_USBH_MSC_FATFS == 0
|
||||
#ifndef TEST_USBH_MSC_FATFS
|
||||
ret = usbh_msc_scsi_init(msc_class);
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("scsi_init error,ret:%d\r\n", ret);
|
||||
@@ -326,18 +361,23 @@ delete:
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_TEST_USBH_CDC_ACM
|
||||
void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class)
|
||||
#ifdef CONFIG_TEST_USBH_SERIAL
|
||||
void usbh_serial_run(struct usbh_serial *serial)
|
||||
{
|
||||
usb_osal_thread_create("usbh_cdc", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_cdc_acm_thread, cdc_acm_class);
|
||||
if (serial_is_opened) {
|
||||
return;
|
||||
}
|
||||
serial_is_opened = true;
|
||||
usb_osal_thread_create("usbh_serial", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_serial_thread, serial);
|
||||
}
|
||||
|
||||
void usbh_cdc_acm_stop(struct usbh_cdc_acm *cdc_acm_class)
|
||||
void usbh_serial_stop(struct usbh_serial *serial)
|
||||
{
|
||||
serial_is_opened = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_TEST_USBH_HID
|
||||
#ifdef CONFIG_TEST_USBH_HID
|
||||
void usbh_hid_run(struct usbh_hid *hid_class)
|
||||
{
|
||||
usb_osal_thread_create("usbh_hid", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_hid_thread, hid_class);
|
||||
@@ -348,7 +388,7 @@ void usbh_hid_stop(struct usbh_hid *hid_class)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_TEST_USBH_MSC
|
||||
#ifdef CONFIG_TEST_USBH_MSC
|
||||
void usbh_msc_run(struct usbh_msc *msc_class)
|
||||
{
|
||||
usb_osal_thread_create("usbh_msc", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_msc_thread, msc_class);
|
||||
@@ -359,14 +399,6 @@ void usbh_msc_stop(struct usbh_msc *msc_class)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_TEST_USBH_AUDIO
|
||||
#error "commercial charge"
|
||||
#endif
|
||||
|
||||
#if CONFIG_TEST_USBH_VIDEO
|
||||
#error "commercial charge"
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#include "usbh_aoa.h"
|
||||
|
||||
|
||||
@@ -103,7 +103,6 @@
|
||||
|
||||
#define HID_KEYBOARD_REPORT_DESC_SIZE 63
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
|
||||
};
|
||||
@@ -185,136 +184,6 @@ const struct usb_descriptor video_audio_hid_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t video_audio_hid_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x06, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
//VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
|
||||
VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
|
||||
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
|
||||
VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
|
||||
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
|
||||
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
|
||||
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
|
||||
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01),
|
||||
AUDIO_AC_DESCRIPTOR_INIT(0x02, 0x03, AUDIO_AC_SIZ, 0x00, 0x03, 0x04),
|
||||
AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, 0x02, 0x0003),
|
||||
AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x02, 0x01, 0x01, 0x03, 0x00, 0x00),
|
||||
AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, 0x02),
|
||||
AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, 0x02, 0x0003),
|
||||
AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x05, 0x04, 0x01, 0x03, 0x00, 0x00),
|
||||
AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_OUTTERM_SPEAKER, 0x05),
|
||||
AUDIO_AS_DESCRIPTOR_INIT(0x03, 0x04, 0x02, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET,
|
||||
EP_INTERVAL, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
|
||||
AUDIO_AS_DESCRIPTOR_INIT(0x04, 0x03, 0x02, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET,
|
||||
EP_INTERVAL, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ)),
|
||||
/************** Descriptor of Joystick Mouse interface ****************/
|
||||
/* 09 */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
||||
0x05, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x01, /* bNumEndpoints */
|
||||
0x03, /* bInterfaceClass: HID */
|
||||
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
|
||||
0x01, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
|
||||
0, /* iInterface: Index of string descriptor */
|
||||
/******************** Descriptor of Joystick Mouse HID ********************/
|
||||
/* 18 */
|
||||
0x09, /* bLength: HID Descriptor size */
|
||||
HID_DESCRIPTOR_TYPE_HID, /* bDescriptorType: HID */
|
||||
0x11, /* bcdHID: HID Class Spec release number */
|
||||
0x01,
|
||||
0x00, /* bCountryCode: Hardware target country */
|
||||
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
|
||||
0x22, /* bDescriptorType */
|
||||
HID_KEYBOARD_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
|
||||
0x00,
|
||||
/******************** Descriptor of Mouse endpoint ********************/
|
||||
/* 27 */
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
|
||||
HID_INT_EP, /* bEndpointAddress: Endpoint Address (IN) */
|
||||
0x03, /* bmAttributes: Interrupt endpoint */
|
||||
HID_INT_EP_SIZE, /* wMaxPacketSize: 4 Byte max */
|
||||
0x00,
|
||||
HID_INT_EP_INTERVAL, /* bInterval: Polling Interval */
|
||||
/* 34 */
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'U', 0x00, /* wcChar10 */
|
||||
'A', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'4', 0x00, /* wcChar3 */
|
||||
'0', 0x00, /* wcChar4 */
|
||||
'3', 0x00, /* wcChar5 */
|
||||
'1', 0x00, /* wcChar6 */
|
||||
'0', 0x00, /* wcChar7 */
|
||||
'0', 0x00, /* wcChar8 */
|
||||
'0', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
static const uint8_t hid_keyboard_report_desc[HID_KEYBOARD_REPORT_DESC_SIZE] = {
|
||||
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
||||
@@ -510,11 +379,8 @@ struct audio_entity_info audio_entity_table[] = {
|
||||
|
||||
void composite_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &video_audio_hid_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, video_audio_hid_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf0, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
|
||||
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf1, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
|
||||
usbd_add_endpoint(busid, &video_in_ep);
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
#define USBD_MAX_POWER 100
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
|
||||
};
|
||||
@@ -118,94 +117,6 @@ const struct usb_descriptor video_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t video_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
//VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
|
||||
VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
|
||||
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
|
||||
VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
|
||||
VIDEO_VS_FORMAT_H264_DESCRIPTOR_INIT(0x01, 0x01),
|
||||
VIDEO_VS_FRAME_H264_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
|
||||
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
|
||||
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01),
|
||||
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'U', 0x00, /* wcChar10 */
|
||||
'V', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'1', 0x00, /* wcChar3 */
|
||||
'0', 0x00, /* wcChar4 */
|
||||
'3', 0x00, /* wcChar5 */
|
||||
'1', 0x00, /* wcChar6 */
|
||||
'0', 0x00, /* wcChar7 */
|
||||
'0', 0x00, /* wcChar8 */
|
||||
'0', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
volatile bool tx_flag = 0;
|
||||
volatile bool iso_tx_busy = false;
|
||||
@@ -272,11 +183,8 @@ struct usbd_interface intf1;
|
||||
|
||||
void video_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &video_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, video_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf0, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
|
||||
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf1, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
|
||||
usbd_add_endpoint(busid, &video_in_ep);
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
#define USBD_MAX_POWER 100
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
|
||||
};
|
||||
@@ -118,94 +117,6 @@ const struct usb_descriptor video_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t video_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
//VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
|
||||
VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
|
||||
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
|
||||
VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
|
||||
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
|
||||
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
|
||||
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
|
||||
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01),
|
||||
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'U', 0x00, /* wcChar10 */
|
||||
'V', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'1', 0x00, /* wcChar3 */
|
||||
'0', 0x00, /* wcChar4 */
|
||||
'3', 0x00, /* wcChar5 */
|
||||
'1', 0x00, /* wcChar6 */
|
||||
'0', 0x00, /* wcChar7 */
|
||||
'0', 0x00, /* wcChar8 */
|
||||
'0', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
volatile bool tx_flag = 0;
|
||||
volatile bool iso_tx_busy = false;
|
||||
@@ -272,11 +183,8 @@ struct usbd_interface intf1;
|
||||
|
||||
void video_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &video_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, video_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf0, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
|
||||
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf1, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
|
||||
usbd_add_endpoint(busid, &video_in_ep);
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
#define USBD_MAX_POWER 100
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
|
||||
};
|
||||
@@ -121,95 +120,6 @@ const struct usb_descriptor video_descriptor = {
|
||||
.device_quality_descriptor_callback = device_quality_descriptor_callback,
|
||||
.string_descriptor_callback = string_descriptor_callback
|
||||
};
|
||||
#else
|
||||
const uint8_t video_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
//VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
|
||||
VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
|
||||
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
|
||||
VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
|
||||
VIDEO_VS_FORMAT_UNCOMPRESSED_DESCRIPTOR_INIT(0x01, 0x01, VIDEO_GUID_YUY2),
|
||||
VIDEO_VS_FRAME_UNCOMPRESSED_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, DBVAL(INTERVAL), 0x01, DBVAL(INTERVAL)),
|
||||
VIDEO_VS_COLOR_MATCHING_DESCRIPTOR_INIT(),
|
||||
VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
|
||||
/* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01),
|
||||
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'U', 0x00, /* wcChar10 */
|
||||
'V', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'1', 0x00, /* wcChar3 */
|
||||
'0', 0x00, /* wcChar4 */
|
||||
'3', 0x00, /* wcChar5 */
|
||||
'1', 0x00, /* wcChar6 */
|
||||
'0', 0x00, /* wcChar7 */
|
||||
'0', 0x00, /* wcChar8 */
|
||||
'0', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
volatile bool tx_flag = 0;
|
||||
volatile bool iso_tx_busy = false;
|
||||
@@ -276,11 +186,8 @@ struct usbd_interface intf1;
|
||||
|
||||
void video_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &video_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, video_descriptor);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf0, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
|
||||
usbd_add_interface(busid, usbd_video_init_intf(busid, &intf1, INTERVAL, MAX_FRAME_SIZE, MAX_PAYLOAD_SIZE));
|
||||
usbd_add_endpoint(busid, &video_in_ep);
|
||||
|
||||
@@ -64,7 +64,6 @@ struct usb_bos_descriptor bos_desc = {
|
||||
#define USB_CONFIG_SIZE (34 + 9)
|
||||
#define HID_KEYBOARD_REPORT_DESC_SIZE 63
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01)
|
||||
};
|
||||
@@ -130,89 +129,6 @@ const struct usb_descriptor webusb_hid_descriptor = {
|
||||
.webusb_url_descriptor = &webusb_url_desc,
|
||||
.bos_descriptor = &bos_desc
|
||||
};
|
||||
#else
|
||||
static const uint8_t webusb_hid_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
HID_KEYBOARD_DESCRIPTOR_INIT(0x00, 0x01, HID_KEYBOARD_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(WEBUSB_INTF_NUM, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x2C, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'W', 0x00, /* wcChar10 */
|
||||
'E', 0x00, /* wcChar11 */
|
||||
'B', 0x00, /* wcChar12 */
|
||||
'U', 0x00, /* wcChar13 */
|
||||
'S', 0x00, /* wcChar14 */
|
||||
'B', 0x00, /* wcChar15 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
'D', 0x00, /* wcChar17 */
|
||||
'E', 0x00, /* wcChar18 */
|
||||
'M', 0x00, /* wcChar19 */
|
||||
'O', 0x00, /* wcChar20 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
/* USB HID device Configuration Descriptor */
|
||||
static uint8_t hid_desc[9] __ALIGN_END = {
|
||||
@@ -309,16 +225,8 @@ static struct usbd_interface intf0;
|
||||
|
||||
void webusb_hid_keyboard_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &webusb_hid_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, webusb_hid_descriptor);
|
||||
#endif
|
||||
#ifndef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_bos_desc_register(busid, &bos_desc);
|
||||
usbd_msosv2_desc_register(busid, &msosv2_desc);
|
||||
usbd_webusb_desc_register(busid, &webusb_url_desc);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf0, hid_keyboard_report_desc, HID_KEYBOARD_REPORT_DESC_SIZE));
|
||||
usbd_add_endpoint(busid, &hid_in_ep);
|
||||
|
||||
|
||||
@@ -133,7 +133,6 @@ struct usb_msosv1_descriptor msosv1_desc = {
|
||||
#define WINUSB_EP_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01)
|
||||
};
|
||||
@@ -205,151 +204,6 @@ const struct usb_descriptor winusbv1_descriptor = {
|
||||
.string_descriptor_callback = string_descriptor_callback,
|
||||
.msosv1_descriptor = &msosv1_desc
|
||||
};
|
||||
#else
|
||||
const uint8_t winusbv1_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, 0x02, WINUSB_EP_MPS, 0x00),
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, 0x02, WINUSB_EP_MPS, 0x00),
|
||||
#if WINUSB_NUM == 2
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(0x01, 0x00, 0x02, 0xff, 0xff, 0x00, 0x05),
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP2, 0x02, WINUSB_EP_MPS, 0x00),
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP2, 0x02, WINUSB_EP_MPS, 0x00),
|
||||
#endif
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x2C, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'W', 0x00, /* wcChar10 */
|
||||
'I', 0x00, /* wcChar11 */
|
||||
'N', 0x00, /* wcChar12 */
|
||||
'U', 0x00, /* wcChar13 */
|
||||
'S', 0x00, /* wcChar14 */
|
||||
'B', 0x00, /* wcChar15 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
'D', 0x00, /* wcChar17 */
|
||||
'E', 0x00, /* wcChar18 */
|
||||
'M', 0x00, /* wcChar19 */
|
||||
'O', 0x00, /* wcChar20 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'1', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
///////////////////////////////////////
|
||||
/// string4 descriptor
|
||||
///////////////////////////////////////
|
||||
0x30, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'W', 0x00, /* wcChar10 */
|
||||
'I', 0x00, /* wcChar11 */
|
||||
'N', 0x00, /* wcChar12 */
|
||||
'U', 0x00, /* wcChar13 */
|
||||
'S', 0x00, /* wcChar14 */
|
||||
'B', 0x00, /* wcChar15 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
'D', 0x00, /* wcChar17 */
|
||||
'E', 0x00, /* wcChar18 */
|
||||
'M', 0x00, /* wcChar19 */
|
||||
'O', 0x00, /* wcChar20 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
'1', 0x00, /* wcChar21 */
|
||||
///////////////////////////////////////
|
||||
/// string5 descriptor
|
||||
///////////////////////////////////////
|
||||
0x30, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'W', 0x00, /* wcChar10 */
|
||||
'I', 0x00, /* wcChar11 */
|
||||
'N', 0x00, /* wcChar12 */
|
||||
'U', 0x00, /* wcChar13 */
|
||||
'S', 0x00, /* wcChar14 */
|
||||
'B', 0x00, /* wcChar15 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
'D', 0x00, /* wcChar17 */
|
||||
'E', 0x00, /* wcChar18 */
|
||||
'M', 0x00, /* wcChar19 */
|
||||
'O', 0x00, /* wcChar20 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
'2', 0x00, /* wcChar21 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
|
||||
@@ -465,14 +319,8 @@ struct usbd_interface intf1;
|
||||
|
||||
void winusbv1_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &winusbv1_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, winusbv1_descriptor);
|
||||
#endif
|
||||
#ifndef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_msosv1_desc_register(busid, &msosv1_desc);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, &intf0);
|
||||
usbd_add_endpoint(busid, &winusb_out_ep1);
|
||||
usbd_add_endpoint(busid, &winusb_in_ep1);
|
||||
|
||||
@@ -50,7 +50,6 @@ const struct usb_bos_descriptor bos_desc = {
|
||||
#define WINUSB_EP_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
|
||||
};
|
||||
@@ -121,90 +120,6 @@ const struct usb_descriptor winusbv2_cdc_descriptor = {
|
||||
.msosv2_descriptor = &msosv2_desc,
|
||||
.bos_descriptor = &bos_desc
|
||||
};
|
||||
#else
|
||||
const uint8_t winusbv2_cdc_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
|
||||
/* Configuration 0 */
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
/* Interface 0 */
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
|
||||
/* Endpoint OUT 2 */
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
|
||||
/* Endpoint IN 1 */
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
|
||||
CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, WINUSB_EP_MPS, 0x00),
|
||||
/* String 0 (LANGID) */
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
/* String 1 (Manufacturer) */
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x2C, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'W', 0x00, /* wcChar10 */
|
||||
'I', 0x00, /* wcChar11 */
|
||||
'N', 0x00, /* wcChar12 */
|
||||
'U', 0x00, /* wcChar13 */
|
||||
'S', 0x00, /* wcChar14 */
|
||||
'B', 0x00, /* wcChar15 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
'D', 0x00, /* wcChar17 */
|
||||
'E', 0x00, /* wcChar18 */
|
||||
'M', 0x00, /* wcChar19 */
|
||||
'O', 0x00, /* wcChar20 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
/* Device Qualifier */
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x10,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
/* End */
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
|
||||
@@ -314,15 +229,8 @@ struct usbd_interface intf2;
|
||||
|
||||
void winusbv2_cdc_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &winusbv2_cdc_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, winusbv2_cdc_descriptor);
|
||||
#endif
|
||||
#ifndef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_bos_desc_register(busid, &bos_desc);
|
||||
usbd_msosv2_desc_register(busid, &msosv2_desc);
|
||||
#endif
|
||||
|
||||
/*!< winusb */
|
||||
usbd_add_interface(busid, &winusb_intf);
|
||||
usbd_add_endpoint(busid, &winusb_out_ep1);
|
||||
|
||||
@@ -62,7 +62,6 @@ const struct usb_bos_descriptor bos_desc = {
|
||||
#define WINUSB_EP_MPS 64
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01)
|
||||
};
|
||||
@@ -135,151 +134,6 @@ const struct usb_descriptor winusbv2_descriptor = {
|
||||
.msosv2_descriptor = &msosv2_desc,
|
||||
.bos_descriptor = &bos_desc,
|
||||
};
|
||||
#else
|
||||
const uint8_t winusbv2_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, 0x02, WINUSB_EP_MPS, 0x00),
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, 0x02, WINUSB_EP_MPS, 0x00),
|
||||
#if WINUSB_NUM == 2
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(0x01, 0x00, 0x02, 0xff, 0xff, 0x00, 0x05),
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP2, 0x02, WINUSB_EP_MPS, 0x00),
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP2, 0x02, WINUSB_EP_MPS, 0x00),
|
||||
#endif
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x2C, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'W', 0x00, /* wcChar10 */
|
||||
'I', 0x00, /* wcChar11 */
|
||||
'N', 0x00, /* wcChar12 */
|
||||
'U', 0x00, /* wcChar13 */
|
||||
'S', 0x00, /* wcChar14 */
|
||||
'B', 0x00, /* wcChar15 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
'D', 0x00, /* wcChar17 */
|
||||
'E', 0x00, /* wcChar18 */
|
||||
'M', 0x00, /* wcChar19 */
|
||||
'O', 0x00, /* wcChar20 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'1', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
///////////////////////////////////////
|
||||
/// string4 descriptor
|
||||
///////////////////////////////////////
|
||||
0x30, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'W', 0x00, /* wcChar10 */
|
||||
'I', 0x00, /* wcChar11 */
|
||||
'N', 0x00, /* wcChar12 */
|
||||
'U', 0x00, /* wcChar13 */
|
||||
'S', 0x00, /* wcChar14 */
|
||||
'B', 0x00, /* wcChar15 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
'D', 0x00, /* wcChar17 */
|
||||
'E', 0x00, /* wcChar18 */
|
||||
'M', 0x00, /* wcChar19 */
|
||||
'O', 0x00, /* wcChar20 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
'1', 0x00, /* wcChar21 */
|
||||
///////////////////////////////////////
|
||||
/// string5 descriptor
|
||||
///////////////////////////////////////
|
||||
0x30, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'W', 0x00, /* wcChar10 */
|
||||
'I', 0x00, /* wcChar11 */
|
||||
'N', 0x00, /* wcChar12 */
|
||||
'U', 0x00, /* wcChar13 */
|
||||
'S', 0x00, /* wcChar14 */
|
||||
'B', 0x00, /* wcChar15 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
'D', 0x00, /* wcChar17 */
|
||||
'E', 0x00, /* wcChar18 */
|
||||
'M', 0x00, /* wcChar19 */
|
||||
'O', 0x00, /* wcChar20 */
|
||||
' ', 0x00, /* wcChar16 */
|
||||
'2', 0x00, /* wcChar21 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
|
||||
@@ -395,15 +249,8 @@ struct usbd_interface intf1;
|
||||
|
||||
void winusbv2_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_desc_register(busid, &winusbv2_descriptor);
|
||||
#else
|
||||
usbd_desc_register(busid, winusbv2_descriptor);
|
||||
#endif
|
||||
#ifndef CONFIG_USBDEV_ADVANCE_DESC
|
||||
usbd_bos_desc_register(busid, &bos_desc);
|
||||
usbd_msosv2_desc_register(busid, &msosv2_desc);
|
||||
#endif
|
||||
|
||||
usbd_add_interface(busid, &intf0);
|
||||
usbd_add_endpoint(busid, &winusb_out_ep1);
|
||||
usbd_add_endpoint(busid, &winusb_in_ep1);
|
||||
|
||||
@@ -19,6 +19,11 @@ CONFIG_USB_PRINTF_COLOR_ENABLE
|
||||
|
||||
控制 log 颜色打印,默认开启
|
||||
|
||||
CONFIG_USB_DCACHE_ENABLE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
不使用 nocache ram 时,开启此宏以保证数据一致性。 **使用 EHCI 时,内部依旧需要使用 nocache ram**。
|
||||
|
||||
CONFIG_USB_ALIGN_SIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -126,7 +131,7 @@ rndis 与 lwip 接口的对接
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#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
|
||||
@@ -150,7 +155,7 @@ CONFIG_USBHOST_REQUEST_BUFFER_LEN
|
||||
CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
控制传输发送或者接收的超时时间,默认 1s
|
||||
控制传输发送或者接收的超时时间,默认 500 ms
|
||||
|
||||
CONFIG_USBHOST_MSC_TIMEOUT
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
CORE
|
||||
-----------------
|
||||
|
||||
.. note:: 请注意,v1.1 版本开始增加 busid 形参,其余保持不变,所以 API 说明不做更新
|
||||
|
||||
端点结构体
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
@@ -28,7 +26,6 @@ CORE
|
||||
usbd_endpoint_callback ep_cb;
|
||||
};
|
||||
|
||||
- **list** 端点的链表节点
|
||||
- **ep_addr** 端点地址(带方向)
|
||||
- **ep_cb** 端点完成中断回调函数。
|
||||
|
||||
@@ -58,64 +55,39 @@ CORE
|
||||
- **hid_report_descriptor** hid 报告描述符
|
||||
- **hid_report_descriptor_len** hid 报告描述符长度
|
||||
- **intf_num** 当前接口偏移
|
||||
- **ep_list** 端点的链表节点
|
||||
|
||||
usbd_desc_register
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_desc_register`` 用来注册 USB 描述符,描述符种类包括:设备描述符、配置描述符(包含配置描述符、接口描述符、class 类描述符、端点描述符)、字符串描述符、设备限定描述符。
|
||||
``usbd_desc_register`` 用来注册 USB 描述符,描述符种类包括:设备描述符、配置描述符(包含配置描述符、接口描述符、class 类描述符、端点描述符)、字符串描述符、设备限定描述符,其他速度描述符,
|
||||
bos描述符,winusb 描述符。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_desc_register(const uint8_t *desc);
|
||||
// 开启 CONFIG_USBDEV_ADVANCE_DESC
|
||||
void usbd_desc_register(uint8_t busid, const struct usb_descriptor *desc);
|
||||
|
||||
// 关闭 CONFIG_USBDEV_ADVANCE_DESC
|
||||
void usbd_desc_register(uint8_t busid, const uint8_t *desc);
|
||||
void usbd_msosv1_desc_register(uint8_t busid, struct usb_msosv1_descriptor *desc);
|
||||
void usbd_msosv2_desc_register(uint8_t busid, struct usb_msosv2_descriptor *desc);
|
||||
void usbd_bos_desc_register(uint8_t busid, struct usb_bos_descriptor *desc);
|
||||
void usbd_webusb_desc_register(uint8_t busid, struct usb_webusb_descriptor *desc);
|
||||
|
||||
- **desc** 描述符的句柄
|
||||
|
||||
.. note:: 当前 API 仅支持一种速度,如果需要更高级的速度切换功能,请开启 CONFIG_USBDEV_ADVANCE_DESC,并且包含了下面所有描述符注册功能
|
||||
|
||||
|
||||
usbd_msosv1_desc_register
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_msosv1_desc_register`` 用来注册一个 WINUSB 1.0 描述符。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_msosv1_desc_register(struct usb_msosv1_descriptor *desc);
|
||||
|
||||
- **desc** 描述符句柄
|
||||
|
||||
usbd_msosv2_desc_register
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_msosv2_desc_register`` 用来注册一个 WINUSB 2.0 描述符。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_msosv2_desc_register(struct usb_msosv2_descriptor *desc);
|
||||
|
||||
- **desc** 描述符句柄
|
||||
|
||||
usbd_bos_desc_register
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_bos_desc_register`` 用来注册一个 BOS 描述符, USB 2.1 版本以上必须注册。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_bos_desc_register(struct usb_bos_descriptor *desc);
|
||||
|
||||
- **desc** 描述符句柄
|
||||
.. note:: 当前默认开启 CONFIG_USBDEV_ADVANCE_DESC,如果需要使用旧版本 API 请关闭该宏,从 v1.6.0 开始只有开启了 CONFIG_USBDEV_ADVANCE_DESC 的 API
|
||||
|
||||
usbd_add_interface
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_add_interface`` 添加一个接口驱动。 **添加顺序必须按照描述符顺序**。
|
||||
``usbd_add_interface`` 添加一个接口驱动。 **添加顺序必须按照描述符中接口顺序**。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_add_interface(struct usbd_interface *intf);
|
||||
void usbd_add_interface(uint8_t busid, struct usbd_interface *intf);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **intf** 接口驱动句柄,通常从不同 class 的 `xxx_init_intf` 函数获取
|
||||
|
||||
usbd_add_endpoint
|
||||
@@ -125,27 +97,59 @@ usbd_add_endpoint
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_add_endpoint(struct usbd_endpoint *ep);;
|
||||
void usbd_add_endpoint(uint8_t busid, struct usbd_endpoint *ep);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **ep** 端点句柄
|
||||
|
||||
usbd_initialize
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_initialize`` 用来初始化 usb device 寄存器配置、usb 时钟、中断等,需要注意,此函数必须在所有列出的 API 最后。 **如果使用 os,必须放在线程中执行**。
|
||||
``usbd_initialize`` 用来初始化 usb device 寄存器配置、usb 时钟、中断等,需要注意,此函数必须在注册描述符 API 最后。 **如果使用 os,必须放在线程中执行**。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_initialize(void);
|
||||
int usbd_initialize(uint8_t busid, uintptr_t reg_base, usbd_event_handler_t event_handler);
|
||||
|
||||
usbd_event_handler
|
||||
- **busid** USB 总线 id
|
||||
- **reg_base** USB 设备寄存器基地址
|
||||
- **event_handler** 协议栈中断或者状态回调函数,event 事件
|
||||
- **return** 返回 0 表示成功,其他值表示失败
|
||||
|
||||
event 事件包括:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
USBD_EVENT_ERROR, /** USB error reported by the controller */
|
||||
USBD_EVENT_RESET, /** USB reset */
|
||||
USBD_EVENT_SOF, /** Start of Frame received */
|
||||
USBD_EVENT_CONNECTED, /** USB connected*/
|
||||
USBD_EVENT_DISCONNECTED, /** USB disconnected */
|
||||
USBD_EVENT_SUSPEND, /** USB connection suspended by the HOST */
|
||||
USBD_EVENT_RESUME, /** USB connection resumed by the HOST */
|
||||
|
||||
/* USB DEVICE STATUS */
|
||||
USBD_EVENT_CONFIGURED, /** USB configuration done */
|
||||
USBD_EVENT_SET_INTERFACE, /** USB interface selected */
|
||||
USBD_EVENT_SET_REMOTE_WAKEUP, /** USB set remote wakeup */
|
||||
USBD_EVENT_CLR_REMOTE_WAKEUP, /** USB clear remote wakeup */
|
||||
USBD_EVENT_INIT, /** USB init done when call usbd_initialize */
|
||||
USBD_EVENT_DEINIT, /** USB deinit done when call usbd_deinitialize */
|
||||
USBD_EVENT_UNKNOWN
|
||||
|
||||
.. note:: 大部分 IP USBD_EVENT_CONNECTED 和 USBD_EVENT_DISCONNECTED 事件都不支持,当前仅 HPM 芯片支持,其余芯片自行设计vbus检测电路替代
|
||||
|
||||
usbd_deinitialize
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_event_handler`` 是协议栈中中断或者协议栈一些状态的回调函数。大部分 IP 仅支持 USBD_EVENT_RESET 和 USBD_EVENT_CONFIGURED
|
||||
``usbd_deinitialize`` 用来反初始化 usb device,关闭 usb 设备时钟、中断等。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_event_handler(uint8_t event);
|
||||
int usbd_deinitialize(uint8_t busid);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **return** 返回 0 表示成功,其他值表示失败
|
||||
|
||||
CDC ACM
|
||||
-----------------
|
||||
@@ -160,8 +164,9 @@ usbd_cdc_acm_init_intf
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbd_interface *usbd_cdc_acm_init_intf(struct usbd_interface *intf);
|
||||
struct usbd_interface *usbd_cdc_acm_init_intf(uint8_t busid, struct usbd_interface *intf);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **return** 接口句柄
|
||||
|
||||
usbd_cdc_acm_set_line_coding
|
||||
@@ -171,8 +176,9 @@ usbd_cdc_acm_set_line_coding
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_cdc_acm_set_line_coding(uint8_t intf, struct cdc_line_coding *line_coding);
|
||||
void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **intf** 控制接口号
|
||||
- **line_coding** 串口配置
|
||||
|
||||
@@ -183,8 +189,9 @@ usbd_cdc_acm_get_line_coding
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_cdc_acm_get_line_coding(uint8_t intf, struct cdc_line_coding *line_coding);
|
||||
void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **intf** 控制接口号
|
||||
- **line_coding** 串口配置
|
||||
|
||||
@@ -195,8 +202,9 @@ usbd_cdc_acm_set_dtr
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_cdc_acm_set_dtr(uint8_t intf, bool dtr);
|
||||
void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **intf** 控制接口号
|
||||
- **dtr** dtr 为1表示拉低电平,为0表示拉高电平
|
||||
|
||||
@@ -207,8 +215,9 @@ usbd_cdc_acm_set_rts
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_cdc_acm_set_rts(uint8_t intf, bool rts);
|
||||
void usbd_cdc_acm_set_rts(uint8_t busid, uint8_t intf, bool rts);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **intf** 控制接口号
|
||||
- **rts** rts 为1表示拉低电平,为0表示拉高电平
|
||||
|
||||
@@ -240,8 +249,9 @@ usbd_hid_init_intf
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbd_interface *usbd_hid_init_intf(struct usbd_interface *intf, const uint8_t *desc, uint32_t desc_len);
|
||||
struct usbd_interface *usbd_hid_init_intf(uint8_t busid, struct usbd_interface *intf, const uint8_t *desc, uint32_t desc_len);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **desc** 报告描述符
|
||||
- **desc_len** 报告描述符长度
|
||||
|
||||
@@ -260,8 +270,9 @@ usbd_msc_init_intf
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbd_interface *usbd_msc_init_intf(struct usbd_interface *intf, const uint8_t out_ep, const uint8_t in_ep);
|
||||
struct usbd_interface *usbd_msc_init_intf(uint8_t busid, struct usbd_interface *intf, const uint8_t out_ep, const uint8_t in_ep);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **out_ep** out 端点地址
|
||||
- **in_ep** in 端点地址
|
||||
|
||||
@@ -272,8 +283,9 @@ usbd_msc_get_cap
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size);
|
||||
void usbd_msc_get_cap(uint8_t busid, uint8_t lun, uint32_t *block_num, uint16_t *block_size);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **lun** 存储逻辑单元,暂时无用,默认支持一个
|
||||
- **block_num** 存储扇区个数
|
||||
- **block_size** 存储扇区大小
|
||||
@@ -285,8 +297,10 @@ usbd_msc_sector_read
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length);
|
||||
int usbd_msc_sector_read(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **lun** 存储逻辑单元,暂时无用,默认支持一个
|
||||
- **sector** 扇区偏移
|
||||
- **buffer** 存储读取的数据的指针
|
||||
- **length** 读取长度
|
||||
@@ -299,8 +313,10 @@ usbd_msc_sector_write
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length);
|
||||
int usbd_msc_sector_write(uint8_t busid, uint8_t lun, uint32_t sector, uint8_t *buffer, uint32_t length);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **lun** 存储逻辑单元,暂时无用,默认支持一个
|
||||
- **sector** 扇区偏移
|
||||
- **buffer** 写入数据指针
|
||||
- **length** 写入长度
|
||||
@@ -318,15 +334,21 @@ usbd_audio_init_intf
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbd_interface *usbd_audio_init_intf(struct usbd_interface *intf);
|
||||
struct usbd_interface *usbd_audio_init_intf(uint8_t busid, struct usbd_interface *intf,
|
||||
uint16_t uac_version,
|
||||
struct audio_entity_info *table,
|
||||
uint8_t num);
|
||||
|
||||
- **class** 类的句柄
|
||||
- **busid** USB 总线 id
|
||||
- **intf** 接口句柄
|
||||
- **uac_version** 音频类版本,UAC1.0 或 UAC2.0
|
||||
- **table** 音频实体信息表
|
||||
- **num** 音频实体信息表长度
|
||||
|
||||
usbd_audio_open
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_audio_open`` 用来开启音频数据传输。
|
||||
``usbd_audio_open`` 用来开启音频数据传输。主机发送开启命令的回调函数。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
@@ -337,7 +359,7 @@ usbd_audio_open
|
||||
usbd_audio_close
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_audio_close`` 用来关闭音频数据传输。
|
||||
``usbd_audio_close`` 用来关闭音频数据传输。主机发送关闭命令的回调函数。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
@@ -345,18 +367,6 @@ usbd_audio_close
|
||||
|
||||
- **intf** 关闭的接口号
|
||||
|
||||
usbd_audio_add_entity
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_audio_add_entity`` 用来添加 unit 相关控制,例如 feature unit、clock source。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_audio_add_entity(uint8_t entity_id, uint16_t bDescriptorSubtype);
|
||||
|
||||
- **entity_id** 要添加的 unit id
|
||||
- **bDescriptorSubtype** entity_id 的描述符子类型
|
||||
|
||||
usbd_audio_set_mute
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
@@ -364,10 +374,12 @@ usbd_audio_set_mute
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_audio_set_mute(uint8_t ch, uint8_t enable);
|
||||
void usbd_audio_set_mute(uint8_t busid, uint8_t ep, uint8_t ch, bool mute);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **ep** 要设置静音的端点
|
||||
- **ch** 要设置静音的通道
|
||||
- **enable** 为1 表示静音,0相反
|
||||
- **mute** 为1 表示静音,0相反
|
||||
|
||||
usbd_audio_set_volume
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
@@ -376,10 +388,12 @@ usbd_audio_set_volume
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_audio_set_volume(uint8_t ch, float dB);
|
||||
void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume_db);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **ep** 要设置音量的端点
|
||||
- **ch** 要设置音量的通道
|
||||
- **dB** 要设置音量的分贝,其中 UAC1.0范围从 -127 ~ +127dB,UAC2.0 从 0 ~ 256dB
|
||||
- **volume_db** 要设置音量的分贝,单位 -100dB ~ 0dB
|
||||
|
||||
usbd_audio_set_sampling_freq
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
@@ -388,34 +402,23 @@ usbd_audio_set_sampling_freq
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_audio_set_sampling_freq(uint8_t ep_ch, uint32_t sampling_freq);
|
||||
void usbd_audio_set_sampling_freq(uint8_t busid, uint8_t ep, uint32_t sampling_freq);
|
||||
|
||||
- **ch** 要设置采样率的端点或者通道,UAC1.0为端点,UAC2.0 为通道
|
||||
- **dB** 要设置的采样率
|
||||
- **ep** 要设置采样率的端点
|
||||
- **sampling_freq** 要设置的采样率
|
||||
|
||||
usbd_audio_get_sampling_freq_table
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_audio_get_sampling_freq_table`` 用来获取支持的采样率列表,如果函数没有实现,则使用默认采样率列表。
|
||||
``usbd_audio_get_sampling_freq_table`` 用来获取支持的采样率列表,如果函数没有实现,则使用默认采样率列表。 UAC2 only。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_audio_get_sampling_freq_table(uint8_t **sampling_freq_table);
|
||||
void usbd_audio_get_sampling_freq_table(uint8_t busid, uint8_t ep, uint8_t **sampling_freq_table);
|
||||
|
||||
- **ep** 要获取采样率的端点
|
||||
- **sampling_freq_table** 采样率列表地址,格式参考默认采样率列表
|
||||
|
||||
usbd_audio_set_pitch
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_audio_set_pitch`` 用来设置音频音调,仅 UAC1.0 有这功能。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbd_audio_set_pitch(uint8_t ep, bool enable);
|
||||
|
||||
- **ep** 要设置音调的端点
|
||||
- **enable** 开启或关闭音调
|
||||
|
||||
UVC
|
||||
-----------------
|
||||
|
||||
@@ -428,13 +431,15 @@ usbd_video_init_intf
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbd_interface *usbd_video_init_intf(struct usbd_interface *intf,
|
||||
uint32_t dwFrameInterval,
|
||||
uint32_t dwMaxVideoFrameSize,
|
||||
uint32_t dwMaxPayloadTransferSize);
|
||||
|
||||
- **class** 类的句柄
|
||||
struct usbd_interface *usbd_video_init_intf(uint8_t busid, struct usbd_interface *intf,
|
||||
uint32_t dwFrameInterval,
|
||||
uint32_t dwMaxVideoFrameSize,
|
||||
uint32_t dwMaxPayloadTransferSize);
|
||||
- **busid** USB 总线 id
|
||||
- **intf** 接口句柄
|
||||
- **dwFrameInterval** 视频帧间隔,单位 100ns
|
||||
- **dwMaxVideoFrameSize** 最大视频帧大小
|
||||
- **dwMaxPayloadTransferSize** 最大负载传输大小
|
||||
|
||||
usbd_video_open
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
@@ -458,26 +463,40 @@ usbd_video_close
|
||||
|
||||
- **intf** 关闭的接口号
|
||||
|
||||
usbd_video_payload_fill
|
||||
usbd_video_stream_start_write
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_video_payload_fill`` 用来填充 mjpeg 到新的 buffer中,其中会对 mjpeg 数据按帧进行切分,切分大小由 ``dwMaxPayloadTransferSize`` 控制,并添加头部信息,当前头部字节数为 2。头部信息见 ``struct video_mjpeg_payload_header``
|
||||
``usbd_video_stream_start_write`` 用来启动一帧视频数据流发送。需要搭配 `usbd_video_stream_split_transfer` 使用。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
uint32_t usbd_video_payload_fill(uint8_t *input, uint32_t input_len, uint8_t *output, uint32_t *out_len);
|
||||
int usbd_video_stream_start_write(uint8_t busid, uint8_t ep, uint8_t *ep_buf, uint8_t *stream_buf, uint32_t stream_len, bool do_copy);
|
||||
|
||||
- **input** mjpeg 格式的数据包,从 FFD8~FFD9结束
|
||||
- **input_len** mjpeg数据包大小
|
||||
- **output** 输出缓冲区
|
||||
- **out_len** 输出实际要发送的长度大小
|
||||
- **return** 返回 usb 按照 ``dwMaxPayloadTransferSize`` 大小要发多少帧
|
||||
- **busid** USB 总线 id
|
||||
- **ep** 视频数据端点地址
|
||||
- **ep_buf** 视频数据端点传输缓冲区
|
||||
- **stream_buf** 一帧视频数据源缓冲区
|
||||
- **stream_len** 一帧视频数据源缓冲区大小
|
||||
- **do_copy** 是否需要将 stream_buf 数据复制到 ep_buf 中,当前仅当 stream_buf 在 nocache 区域并且未开启 DCACHE_ENABLE 时该参数才为 false
|
||||
|
||||
DFU
|
||||
usbd_video_stream_split_transfer
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbd_video_stream_split_transfer`` 用来分割视频数据流发送。需要搭配 `usbd_video_stream_start_write` 使用。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbd_video_stream_split_transfer(uint8_t busid, uint8_t ep);
|
||||
|
||||
- **busid** USB 总线 id
|
||||
- **ep** 视频数据端点地址
|
||||
- **return** 返回 true 表示一帧数据发送完成,false 表示数据未发送完成
|
||||
|
||||
RNDIS
|
||||
-----------------
|
||||
|
||||
PRINTER
|
||||
CDC ECM
|
||||
-----------------
|
||||
|
||||
MTP
|
||||
-----------------
|
||||
-----------------
|
||||
|
||||
@@ -126,10 +126,11 @@ usbh_initialize
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_initialize(uint8_t busid, uint32_t reg_base);
|
||||
int usbh_initialize(uint8_t busid, uint32_t reg_base, usbh_event_handler_t event_handler);
|
||||
|
||||
- **busid** bus id,从 0开始,不能超过 `CONFIG_USBHOST_MAX_BUS`
|
||||
- **reg_base** hcd 寄存器基地址
|
||||
- **event_handler** host 事件回调函数,可以为NULL
|
||||
- **return** 0 表示正常其他表示错误
|
||||
|
||||
usbh_find_class_instance
|
||||
@@ -153,14 +154,164 @@ lsusb
|
||||
|
||||
int lsusb(int argc, char **argv);
|
||||
|
||||
CDC ACM
|
||||
SERIAL
|
||||
-----------------
|
||||
|
||||
usbh_serial_open
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_open`` 根据路径打开一个串口设备。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_serial *usbh_serial_open(const char *devname, uint32_t open_flags);
|
||||
|
||||
- **devname** 串口路径
|
||||
- **open_flags** 打开标志,参考 `USBH_SERIAL_OFLAG_*` 定义
|
||||
- **return** serial 结构体句柄
|
||||
|
||||
usbh_serial_close
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_close`` 关闭串口设备。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbh_serial_close(struct usbh_serial *serial);
|
||||
|
||||
- **serial** serial 结构体句柄
|
||||
|
||||
usbh_serial_control
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_control`` 对串口进行配置。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_serial_control(struct usbh_serial *serial, int cmd, void *arg);
|
||||
|
||||
- **serial** serial 结构体句柄
|
||||
- **cmd** 控制命令,参考 `USBH_SERIAL_CMD_*` 定义
|
||||
- **arg** 控制参数指针
|
||||
- **return** 0 表示正常其他表示错误
|
||||
|
||||
usbh_serial_write
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_write`` 向串口写数据。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_serial_write(struct usbh_serial *serial, const void *buffer, uint32_t buflen);
|
||||
|
||||
- **serial** serial 结构体句柄
|
||||
- **buffer** 数据缓冲区指针
|
||||
- **buflen** 要写入的数据长度
|
||||
- **return** 实际写入的数据长度或者错误码
|
||||
|
||||
.. note:: 如果没有开启 CONFIG_USB_DCACHE_ENABLE,则 buffer 需要是 nocache区域,否则需要是对齐到 CONFIG_USB_ALIGN_SIZE 的区域。
|
||||
|
||||
usbh_serial_read
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_read`` 从串口读数据。 **如果没有设置波特率,不允许使用该 API,设置波特率后,内部会开启 rx 接收并将数据写入 ringbuf **。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_serial_read(struct usbh_serial *serial, void *buffer, uint32_t buflen);
|
||||
|
||||
- **serial** serial 结构体句柄
|
||||
- **buffer** 数据缓冲区指针
|
||||
- **buflen** 要读取的最大数据长度
|
||||
- **return** 实际读取的数据长度或者错误码
|
||||
|
||||
.. note:: 由于内部使用了 ringbuffer,对于用户的 buffer 属性没有限制。
|
||||
|
||||
usbh_serial_cdc_write_async
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_cdc_write_async`` 异步从串口读数据。 **如果设置了波特率,不允许使用该 API**。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_serial_cdc_write_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg);
|
||||
|
||||
- **serial** serial 结构体句柄
|
||||
- **buffer** 数据缓冲区指针
|
||||
- **buflen** 要发送的数据长度
|
||||
- **complete** 读数据完成回调函数
|
||||
- **arg** 回调函数参数
|
||||
- **return** 0 表示正常其他表示错误
|
||||
|
||||
.. note:: 如果没有开启 CONFIG_USB_DCACHE_ENABLE,则 buffer 需要是 nocache区域,否则需要是对齐到 CONFIG_USB_ALIGN_SIZE 的区域。
|
||||
|
||||
usbh_serial_cdc_read_async
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_serial_cdc_read_async`` 异步从串口读数据。 **如果设置了波特率,不允许使用该 API,设置波特率后,内部会开启 rx 接收并将数据写入 ringbuf **。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_serial_cdc_read_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg);
|
||||
|
||||
- **serial** serial 结构体句柄
|
||||
- **buffer** 数据缓冲区指针
|
||||
- **buflen** 要读取的最大数据长度,一次最高 16K。并且需要是 wMaxPacketSize 的整数倍
|
||||
- **complete** 读数据完成回调函数
|
||||
- **arg** 回调函数参数
|
||||
- **return** 0 表示正常其他表示错误
|
||||
|
||||
.. note:: 如果没有开启 CONFIG_USB_DCACHE_ENABLE,则 buffer 需要是 nocache区域,否则需要是对齐到 CONFIG_USB_ALIGN_SIZE 的区域。
|
||||
|
||||
HID
|
||||
-----------------
|
||||
|
||||
MSC
|
||||
-----------------
|
||||
|
||||
RNDIS
|
||||
-----------------
|
||||
usbh_msc_scsi_init
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_msc_scsi_init`` 初始化 msc scsi 设备。获取 MSC 状态和容量信息。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_msc_scsi_init(struct usbh_msc *msc_class);
|
||||
|
||||
- **msc_class** msc 结构体句柄
|
||||
- **return** 0 表示正常其他表示错误
|
||||
|
||||
usbh_msc_scsi_write10
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_msc_scsi_write10`` 向 msc 设备写数据。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors);
|
||||
|
||||
- **msc_class** msc 结构体句柄
|
||||
- **start_sector** 起始扇区
|
||||
- **buffer** 数据缓冲区指针
|
||||
- **nsectors** 要写入的扇区数
|
||||
- **return** 返回 0 表示正常其他表示错误
|
||||
|
||||
usbh_msc_scsi_read10
|
||||
""""""""""""""""""""""""""""""""""""
|
||||
|
||||
``usbh_msc_scsi_read10`` 从 msc 设备读数据。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, uint8_t *buffer, uint32_t nsectors);
|
||||
|
||||
- **msc_class** msc 结构体句柄
|
||||
- **start_sector** 起始扇区
|
||||
- **buffer** 数据缓冲区指针
|
||||
- **nsectors** 要读取的扇区数
|
||||
- **return** 返回 0 表示正常其他表示错误
|
||||
|
||||
NETWORK
|
||||
-----------------
|
||||
|
||||
已对接 lwIP 协议栈或者其他网络协议栈,使用 socket API 即可。
|
||||
@@ -6,8 +6,8 @@ project = 'CherryUSB'
|
||||
copyright = '2022 ~ 2025, sakumisu'
|
||||
author = 'sakumisu'
|
||||
|
||||
release = '1.5.3'
|
||||
version = '1.5.3'
|
||||
release = '1.6.0'
|
||||
version = '1.6.0'
|
||||
|
||||
# -- General configuration
|
||||
|
||||
|
||||
BIN
docs/source/demo/img/usbh_serial.png
Normal file
BIN
docs/source/demo/img/usbh_serial.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 MiB |
@@ -15,7 +15,7 @@ usbd_webusb
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(USBD_WEBUSB_INTF_NUM, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00)
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(USBD_WEBUSB_INTF_NUM, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00)
|
||||
|
||||
- 其余使用 hid 描述符,不再赘述
|
||||
- 枚举完成后,电脑右下角会弹出网页信息,点击即可打开网页
|
||||
@@ -1,11 +1,19 @@
|
||||
usbh_net
|
||||
===============
|
||||
|
||||
本节主要介绍 USB 网卡的使用,USB 网卡推荐采用 AIR780(RNDIS),EC20(ECM/RNDIS), 手机(RNDIS),RTL8152 USB 网卡,AX88772 USB 网卡。
|
||||
本节主要介绍 USB 网卡的使用,当前已经支持和测试以下 USB 网卡:
|
||||
|
||||
USB 网卡传输层面已经对接好了 LWIP 的收发接口,因此,用户只需要包含 **platform/XXX/usbh_lwip.c** 并根据需要开启对应的网卡类的宏即可。
|
||||
- 4G 网卡:EC20(ECM/RNDIS)、手机(RNDIS)、SIMCOM7600(RNDIS)、ML307R(RNDIS)、AIR780(RNDIS)
|
||||
|
||||
- 当前支持以下网卡类:
|
||||
.. caution:: 请注意,部分 4G 网卡默认不带自动拨号功能,请更换固件或者使用 AT 配置成自动拨号,否则无法获取 IP。
|
||||
|
||||
- USB 以太网卡:ASIX AX88772,REALTEK RTL8152
|
||||
- USB WIFI 网卡: 博流 BL616(RNDIS/ECM)
|
||||
|
||||
USB 网卡相关的宏和文件
|
||||
------------------------
|
||||
|
||||
网卡相关的宏如下,主要用于根据不同的网络组件注册网卡驱动:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
@@ -14,34 +22,24 @@ USB 网卡传输层面已经对接好了 LWIP 的收发接口,因此,用户
|
||||
// #define CONFIG_USBHOST_PLATFORM_CDC_NCM
|
||||
// #define CONFIG_USBHOST_PLATFORM_ASIX
|
||||
// #define CONFIG_USBHOST_PLATFORM_RTL8152
|
||||
// #define CONFIG_USBHOST_PLATFORM_BL616
|
||||
|
||||
- 包含了对接 LWIP 的输入输出接口,举例如下
|
||||
.. note:: 如果使用了 Kconfig 系统,上述宏自定生成,其他平台请手动定义。
|
||||
|
||||
.. code-block:: C
|
||||
USB 网卡传输层面已经对接好了相关网络组件,列举如下:
|
||||
|
||||
static err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
int ret;
|
||||
(void)netif;
|
||||
- 自定义 OS + LWIP 请使用 **platform/lwip/usbh_lwip.c**,需要自行包含该文件,并使能上述相关的宏。并在初始化 USB 之前调用 `tcpip_init(NULL, NULL)`
|
||||
- RT-THREAD + LWIP 请使用 **platform/rtthread/usbh_lwip.c**,在 Kconfig 中使能对应的网卡驱动后自动勾选该文件,勾选 rt-thread lwip以后自动调用 `tcpip_init(NULL, NULL)`
|
||||
- ESP-IDF + LWIP 请使用 **platform/freertos/usbh_net.c**,在 Kconfig 中使能对应的网卡驱动后自动勾选该文件,并且在初始化 USB 之前调用 `esp_netif_init()` + `esp_event_loop_create_default()`
|
||||
- NUTTX + NUTTX 网络组件 请使用 **platform/nuttx/usbh_net.c**,在 Kconfig 中使能对应的网卡驱动后自动勾选该文件,勾选网络组件以后自动调用
|
||||
|
||||
usbh_lwip_eth_output_common(p, usbh_cdc_ecm_get_eth_txbuf());
|
||||
ret = usbh_cdc_ecm_eth_output(p->tot_len);
|
||||
if (ret < 0) {
|
||||
return ERR_BUF;
|
||||
} else {
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
.. note:: 如果是自行添加代码,别忘了添加 USB 网卡驱动相关的源文件,例如 **class/usbh_cdc_ecm.c**。所以我们推荐搭配对应平台使用哦,省去自己添加文件的麻烦
|
||||
|
||||
void usbh_cdc_ecm_eth_input(uint8_t *buf, uint32_t buflen)
|
||||
{
|
||||
usbh_lwip_eth_input_common(&g_cdc_ecm_netif, buf, buflen);
|
||||
}
|
||||
USB 网卡对接过程
|
||||
-------------------
|
||||
|
||||
下面举例对接 LWIP 的对接过程。
|
||||
|
||||
- 网卡类枚举完成后,注册 netif,并且创建网卡接收线程(因此使用 RTTHREAD 时不需要使用 RTT 的接收线程模块)。
|
||||
- 必须开启 DHCP client 服务,用于从 USB 网卡获取 IP 地址。
|
||||
- 在 USB 网卡枚举完成以后,会 **自动** 调用 `usbh_xxx_run` 函数,此时注册 netif 驱动,并且开启 DHCP 客户端和获取 IP 的定时器。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
@@ -75,17 +73,61 @@ USB 网卡传输层面已经对接好了 LWIP 的收发接口,因此,用户
|
||||
#endif
|
||||
}
|
||||
|
||||
- 获取到 IP 以后,就与 USB 没有关系了,直接使用 LWIP 的接口即可。
|
||||
- `usbh_lwip_eth_output_common` 用于将发送 pbuf 组装成 USB 网卡数据包
|
||||
- `usbh_lwip_eth_input_common` 用于将 USB 网卡数据组装成 pbuf
|
||||
- 实际网卡发送和接收处理
|
||||
|
||||
- 需要注意以下参数
|
||||
.. code-block:: C
|
||||
|
||||
LWIP_TCPIP_CORE_LOCKING_INPUT 用于不使用 lwip 内置的 tcpip 线程,而使用 USB 自己的处理线程。
|
||||
static err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
int ret;
|
||||
(void)netif;
|
||||
|
||||
LWIP_TCPIP_CORE_LOCKING 在现在 lwip 版本中默认是打开的,也推荐必须打开。
|
||||
usbh_lwip_eth_output_common(p, usbh_cdc_ecm_get_eth_txbuf());
|
||||
ret = usbh_cdc_ecm_eth_output(p->tot_len);
|
||||
if (ret < 0) {
|
||||
return ERR_BUF;
|
||||
} else {
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
PBUF_POOL_BUFSIZE 推荐大于1600,搭配 LWIP_TCPIP_CORE_LOCKING_INPUT 使用,因为我们提供了使用 zero mempy 的方式,使用静态 pbuf,而不是把数据 copy 到 pbuf 中。
|
||||
void usbh_cdc_ecm_eth_input(uint8_t *buf, uint32_t buflen)
|
||||
{
|
||||
usbh_lwip_eth_input_common(&g_cdc_ecm_netif, buf, buflen);
|
||||
}
|
||||
|
||||
TCPIP_THREAD_STACKSIZE 推荐大于 1K,防止栈溢出。
|
||||
- USB 网卡 拔出以后会 **自动** 调用 `usbh_xxx_stop` 函数,此时需要停止 DHCP 客户端,删除定时器,并且移除 netif。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
|
||||
{
|
||||
struct netif *netif = &g_cdc_ecm_netif;
|
||||
(void)cdc_ecm_class;
|
||||
|
||||
#if LWIP_DHCP
|
||||
dhcp_stop(netif);
|
||||
dhcp_cleanup(netif);
|
||||
usb_osal_timer_delete(dhcp_handle);
|
||||
#endif
|
||||
netif_set_down(netif);
|
||||
netif_remove(netif);
|
||||
}
|
||||
|
||||
- 因为 USB 网卡内部已经对接了LWIP,因此用户可以直接使用 LWIP 的 API,无需关心 USB 的实现。
|
||||
|
||||
USB 网卡 LWIP 配置宏相关注意事项
|
||||
------------------------------------
|
||||
|
||||
**LWIP_TCPIP_CORE_LOCKING_INPUT** 用于不使用 lwip 内置的 tcpip 线程,而使用 USB 自己的接收处理线程。
|
||||
|
||||
**LWIP_TCPIP_CORE_LOCKING** 在现在 lwip 版本中默认是打开的,也推荐必须打开。
|
||||
|
||||
**PBUF_POOL_BUFSIZE** 推荐大于1600,搭配 LWIP_TCPIP_CORE_LOCKING_INPUT 使用,因为我们提供了使用 zero mempy 的方式,使用静态 pbuf,而不是把数据 copy 到 pbuf 中。
|
||||
|
||||
**TCPIP_THREAD_STACKSIZE** 推荐大于 1K,防止栈溢出。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
@@ -105,4 +147,10 @@ TCPIP_THREAD_STACKSIZE 推荐大于 1K,防止栈溢出。
|
||||
#error TCPIP_THREAD_STACKSIZE must be >= 1024
|
||||
#endif
|
||||
|
||||
- 具体移植文章可以参考 https://club.rt-thread.org/ask/article/5cf3e9e0b2d95800.html
|
||||
|
||||
总结
|
||||
--------------
|
||||
|
||||
.. note:: 通过以上内容,我们可以看到 CherryUSB 对 USB 网卡的支持是非常完善的,用户只需要使能对应的宏或者勾选,就可以实现 USB 网卡的自动识别和驱动注册,无需手动初始化网卡相关配置,用户只需关注应用层,极大地方便了用户的使用。
|
||||
|
||||
具体移植文章可以参考开发者的一些笔记 https://club.rt-thread.org/ask/article/5cf3e9e0b2d95800.html
|
||||
@@ -1,4 +1,196 @@
|
||||
usbh_serial
|
||||
===============
|
||||
|
||||
当前仅支持 rt-thread device 框架,包括 cdc acm, ftdi, cp210x, ch34x, pl2303, 具体使用方式参考 rt-thread device api 即可。
|
||||
Serial 框架当前支持 cdc acm, ftdi, cp210x, ch34x, pl2303,gsm 驱动。
|
||||
|
||||
.. figure:: img/usbh_serial.png
|
||||
|
||||
当前支持两种使用方式,一种是使用源生 CherryUSB usbhost serial API 进行操作,另一种是基于平台封装的 API 操作,比如 rt-thread device API,nuttx posix API。
|
||||
|
||||
下面演示的是使用 CherryUSB usbhost serial API 进行串口回环测试,并且使用阻塞发送,异步读取的方式:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
struct usbh_serial *serial;
|
||||
|
||||
serial = usbh_serial_open("/dev/ttyACM0", USBH_SERIAL_O_RDWR | USBH_SERIAL_O_NONBLOCK);
|
||||
if (serial == NULL) {
|
||||
serial = usbh_serial_open("/dev/ttyUSB0", USBH_SERIAL_O_RDWR | USBH_SERIAL_O_NONBLOCK);
|
||||
if (serial == NULL) {
|
||||
USB_LOG_RAW("no serial device found\r\n");
|
||||
goto delete;
|
||||
}
|
||||
}
|
||||
|
||||
struct usbh_serial_termios termios;
|
||||
|
||||
memset(&termios, 0, sizeof(termios));
|
||||
termios.baudrate = 115200;
|
||||
termios.stopbits = 0;
|
||||
termios.parity = 0;
|
||||
termios.databits = 8;
|
||||
termios.rtscts = false;
|
||||
termios.rx_timeout = 0;
|
||||
ret = usbh_serial_control(serial, USBH_SERIAL_CMD_SET_ATTR, &termios);
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("set serial attr error, ret:%d\r\n", ret);
|
||||
goto delete_with_close;
|
||||
}
|
||||
|
||||
serial_tx_bytes = 0;
|
||||
while (1) {
|
||||
ret = usbh_serial_write(serial, serial_tx_buffer, sizeof(serial_tx_buffer));
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("serial write error, ret:%d\r\n", ret);
|
||||
goto delete_with_close;
|
||||
} else {
|
||||
serial_tx_bytes += ret;
|
||||
|
||||
if (serial_tx_bytes == SERIAL_TEST_LEN) {
|
||||
USB_LOG_RAW("send over\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
volatile uint32_t wait_timeout = 0;
|
||||
serial_rx_bytes = 0;
|
||||
while (1) {
|
||||
ret = usbh_serial_read(serial, &serial_rx_data[serial_rx_bytes], SERIAL_TEST_LEN - serial_rx_bytes);
|
||||
if (ret < 0) {
|
||||
USB_LOG_RAW("serial read error, ret:%d\r\n", ret);
|
||||
goto delete_with_close;
|
||||
} else {
|
||||
serial_rx_bytes += ret;
|
||||
|
||||
if (serial_rx_bytes == SERIAL_TEST_LEN) {
|
||||
USB_LOG_RAW("receive over\r\n");
|
||||
for (uint32_t i = 0; i < SERIAL_TEST_LEN; i++) {
|
||||
if (serial_rx_data[i] != 0xa5) {
|
||||
USB_LOG_RAW("serial loopback data error at index %d, data: 0x%02x\r\n", (unsigned int)i, serial_rx_data[i]);
|
||||
goto delete_with_close;
|
||||
}
|
||||
}
|
||||
serial_test_success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
wait_timeout++;
|
||||
|
||||
if (wait_timeout > 500) { // 5s
|
||||
USB_LOG_RAW("serial read timeout\r\n");
|
||||
goto delete_with_close;
|
||||
}
|
||||
|
||||
usb_osal_msleep(10);
|
||||
}
|
||||
|
||||
usbh_serial_close(serial);
|
||||
|
||||
.. caution:: 需要注意,例程中使用的是比较简单的先发送后读取的方式,因此发送的总长度不可以超过 CONFIG_USBHOST_SERIAL_RX_SIZE,正常使用 TX/RX 请分开进行。
|
||||
|
||||
用户需要考虑以下三种场景:
|
||||
|
||||
- USB2TTL 设备 + 启用了波特率(USB2TTL设备必须启用波特率),这种情况下需要使用 `usbh_serial_write` 和 `usbh_serial_read` 进行收发数据, **并且 read 操作需要及时,防止 ringbuf 数据溢出而丢包**。不可以使用 `usbh_serial_cdc_write_async` 和 `usbh_serial_cdc_read_async`
|
||||
|
||||
- 纯 USB 设备 + 未启动波特率,这种情况下可以使用 `usbh_serial_cdc_write_async` 和 `usbh_serial_cdc_read_async` 进行异步收发数据。阻塞则可以用 `usbh_serial_write` ,不可以使用 `usbh_serial_read`。
|
||||
|
||||
- 纯 USB 设备 + 启动波特率,同 1,但是接收速率会打折扣(因为多了一层 ringbuf)。此时也不可以使用 `usbh_serial_cdc_write_async` 和 `usbh_serial_cdc_read_async`。 **如果是 GSM 设备请使用第一种场景**。
|
||||
|
||||
.. note:: 简单来说就是,如果接收数据需要用到ringbuf转一层的,请使用第一种场景。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
[I/usbh_hub] New full-speed device on Bus 0, Hub 1, Port 1 connected
|
||||
[I/usbh_core] New device found,idVendor:10c4,idProduct:ea60,bcdDevice:0100
|
||||
[I/usbh_core] The device has 1 bNumConfigurations
|
||||
[I/usbh_core] The device has 1 interfaces
|
||||
[I/usbh_core] Enumeration success, start loading class driver
|
||||
[I/usbh_core] Loading cp210x class driver on interface 0
|
||||
[I/usbh_cp210x] chip partnum: 0x02
|
||||
[I/usbh_cp210x] ulAmountInInQueue: 0, ulAmountInOutQueue: 0
|
||||
[I/usbh_serial] Ep=81 Attr=02 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=01 Attr=02 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Register Serial Class: /dev/ttyUSB0 (cp210x)
|
||||
start serial loopback test, len: 1024
|
||||
send over
|
||||
receive over
|
||||
serial loopback test success
|
||||
[I/usbh_serial] Unregister Serial Class: /dev/ttyUSB0 (cp210x)
|
||||
[I/usbh_core] Device on Bus 0, Hub 1, Port 1 disconnected
|
||||
[I/usbh_hub] New high-speed device on Bus 0, Hub 1, Port 1 connected
|
||||
[I/usbh_core] New device found,idVendor:0403,idProduct:6010,bcdDevice:0700
|
||||
[I/usbh_core] The device has 1 bNumConfigurations
|
||||
[I/usbh_core] The device has 2 interfaces
|
||||
[I/usbh_core] Enumeration success, start loading class driver
|
||||
[I/usbh_core] Loading ftdi class driver on interface 0
|
||||
[I/usbh_ftdi] chip name: FT2232H
|
||||
[I/usbh_serial] Ep=81 Attr=02 Mps=512 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=02 Attr=02 Mps=512 Interval=00 Mult=00
|
||||
[I/usbh_serial] Register Serial Class: /dev/ttyUSB0 (ftdi)
|
||||
[I/usbh_core] Loading ftdi class driver on interface 1
|
||||
[I/usbh_ftdi] chip name: FT2232H
|
||||
[I/usbh_serial] Ep=83 Attr=02 Mps=512 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=04 Attr=02 Mps=512 Interval=00 Mult=00
|
||||
[I/usbh_serial] Register Serial Class: /dev/ttyUSB1 (ftdi)
|
||||
start serial loopback test, len: 1024
|
||||
send over
|
||||
receive over
|
||||
serial loopback test success
|
||||
[I/usbh_serial] Unregister Serial Class: /dev/ttyUSB0 (ftdi)
|
||||
[I/usbh_serial] Unregister Serial Class: /dev/ttyUSB1 (ftdi)
|
||||
[I/usbh_core] Device on Bus 0, Hub 1, Port 1 disconnected
|
||||
[I/usbh_hub] New full-speed device on Bus 0, Hub 1, Port 1 connected
|
||||
[I/usbh_core] New device found,idVendor:067b,idProduct:2303,bcdDevice:0300
|
||||
[I/usbh_core] The device has 1 bNumConfigurations
|
||||
[I/usbh_core] The device has 1 interfaces
|
||||
[I/usbh_core] Enumeration success, start loading class driver
|
||||
[I/usbh_core] Loading pl2303 class driver on interface 0
|
||||
[I/usbh_pl2303] Ep=81 Attr=03 Mps=10 Interval=01 Mult=00
|
||||
[I/usbh_pl2303] chip type: PL2303HX
|
||||
[I/usbh_serial] Ep=02 Attr=02 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=83 Attr=02 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Register Serial Class: /dev/ttyUSB0 (pl2303)
|
||||
start serial loopback test, len: 1024
|
||||
send over
|
||||
receive over
|
||||
serial loopback test success
|
||||
[I/usbh_serial] Unregister Serial Class: /dev/ttyUSB0 (pl2303)
|
||||
[I/usbh_core] Device on Bus 0, Hub 1, Port 1 disconnected
|
||||
[W/usbh_hub] Failed to enable port 1
|
||||
[I/usbh_hub] New full-speed device on Bus 0, Hub 1, Port 1 connected
|
||||
[I/usbh_core] New device found,idVendor:1a86,idProduct:7523,bcdDevice:0264
|
||||
[I/usbh_core] The device has 1 bNumConfigurations
|
||||
[I/usbh_core] The device has 1 interfaces
|
||||
[I/usbh_core] Enumeration success, start loading class driver
|
||||
[I/usbh_core] Loading ch34x class driver on interface 0
|
||||
[I/usbh_ch43x] Ep=81 Attr=03 Mps=8 Interval=01 Mult=00
|
||||
[I/usbh_ch43x] chip version: 0x31
|
||||
[I/usbh_serial] Ep=82 Attr=02 Mps=32 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=02 Attr=02 Mps=32 Interval=00 Mult=00
|
||||
[I/usbh_serial] Register Serial Class: /dev/ttyUSB0 (ch34x)
|
||||
start serial loopback test, len: 1024
|
||||
send over
|
||||
receive over
|
||||
serial loopback test success
|
||||
[I/usbh_serial] Unregister Serial Class: /dev/ttyUSB0 (ch34x)
|
||||
[I/usbh_core] Device on Bus 0, Hub 1, Port 1 disconnected
|
||||
[I/usbh_hub] New full-speed device on Bus 0, Hub 1, Port 1 connected
|
||||
[I/usbh_core] New device found,idVendor:42bf,idProduct:b210,bcdDevice:0217
|
||||
[I/usbh_core] The device has 1 bNumConfigurations
|
||||
[I/usbh_core] The device has 3 interfaces
|
||||
[I/usbh_core] Enumeration success, start loading class driver
|
||||
[E/usbh_core] Do not support Class:0xff, Subclass:0x01, Protocl:0x00 on interface 0
|
||||
[I/usbh_core] Loading cdc_acm class driver on interface 1
|
||||
[I/usbh_cdc_acm] Ep=85 Attr=03 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=04 Attr=02 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Ep=83 Attr=02 Mps=64 Interval=00 Mult=00
|
||||
[I/usbh_serial] Register Serial Class: /dev/ttyACM0 (cdc_acm)
|
||||
[I/usbh_core] Loading cdc_data class driver on interface 2
|
||||
start serial loopback test, len: 1024
|
||||
send over
|
||||
receive over
|
||||
serial loopback test success
|
||||
[I/usbh_serial] Unregister Serial Class: /dev/ttyACM0 (cdc_acm)
|
||||
[I/usbh_core] Device on Bus 0, Hub 1, Port 1 disconnected
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统的
|
||||
quick_start/transplant
|
||||
quick_start/rtthread
|
||||
quick_start/q&a
|
||||
quick_start/migration
|
||||
quick_start/share
|
||||
quick_start/opensource
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ USB Host 移植要点
|
||||
|
||||
- 链接脚本修改参考 :ref:`usbh_link_script` 章节
|
||||
- 如果芯片带 cache,cache 修改参考 :ref:`usb_cache` 章节
|
||||
- 调用 `usbh_initialize` 并填入 `busid` 和 USB IP 的 `reg base`, `busid` 从 0 开始,不能超过 `CONFIG_USBHOST_MAX_BUS`
|
||||
- 调用 `usbh_initialize` 并填入 `busid` 和 USB IP 的 `reg base` 还有 `event_handler` 可缺省为NULL, `busid` 从 0 开始,不能超过 `CONFIG_USBHOST_MAX_BUS`
|
||||
- 启动线程
|
||||
|
||||
.. figure:: img/stm32_18.png
|
||||
|
||||
63
docs/source/quick_start/migration.rst
Normal file
63
docs/source/quick_start/migration.rst
Normal file
@@ -0,0 +1,63 @@
|
||||
部分改动迁移指南
|
||||
========================
|
||||
|
||||
|
||||
usbh_initialize
|
||||
------------------
|
||||
|
||||
usbh_initialize 从 v1.6.0 开始新增 event_handler 参数,通常不需要使用,可以传入 NULL。
|
||||
|
||||
dwc2 glue st
|
||||
----------------
|
||||
|
||||
dwc2 从 v1.5.0 开始 glue 文件内置底层初始化,比如 `usb_dc_low_level_init`,底层依赖 `HAL_PCD_MspInit` 和 `HAL_HCD_MspInit`,必须使用 stm32cubemx 生成。第三方平台不保证有这些函数实现,自行检查。
|
||||
|
||||
|
||||
dwc2 glue
|
||||
----------------
|
||||
|
||||
dwc2 从 v1.5.1 开始新增 `struct dwc2_user_params`,用于实现多 dwc2 port 不同配置。并替代 `usbd_get_dwc2_gccfg_conf` 和 `usbh_get_dwc2_hccfg_conf` 函数,
|
||||
并增加 `dwc2_get_user_params` 函数实现,举例如下:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#ifndef CONFIG_USB_DWC2_CUSTOM_PARAM
|
||||
void dwc2_get_user_params(uint32_t reg_base, struct dwc2_user_params *params)
|
||||
{
|
||||
memcpy(params, ¶m_common, sizeof(struct dwc2_user_params));
|
||||
#ifdef CONFIG_USB_DWC2_CUSTOM_FIFO
|
||||
struct usb_dwc2_user_fifo_config s_dwc2_fifo_config;
|
||||
|
||||
dwc2_get_user_fifo_config(reg_base, &s_dwc2_fifo_config);
|
||||
|
||||
params->device_rx_fifo_size = s_dwc2_fifo_config.device_rx_fifo_size;
|
||||
for (uint8_t i = 0; i < MAX_EPS_CHANNELS; i++) {
|
||||
params->device_tx_fifo_size[i] = s_dwc2_fifo_config.device_tx_fifo_size[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
host serial
|
||||
----------------
|
||||
|
||||
从 v1.6.0 开始,主机增加 host serial 框架,用于统一所有类串口设备。以下 API 需要使用新 serial API 替换:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
int usbh_xxx_set_line_coding(struct usbh_xxx *xxx_class, struct cdc_line_coding *line_coding);
|
||||
int usbh_xxx_get_line_coding(struct usbh_xxx *xxx_class, struct cdc_line_coding *line_coding);
|
||||
int usbh_xxx_set_line_state(struct usbh_xxx *xxx_class, bool dtr, bool rts);
|
||||
|
||||
int usbh_xxx_bulk_in_transfer(struct usbh_xxx *xxx_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
|
||||
int usbh_xxx_bulk_out_transfer(struct usbh_xxx *xxx_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout);
|
||||
|
||||
替换为:
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
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);
|
||||
@@ -115,10 +115,23 @@ Failed to enable port
|
||||
USB_ERR_NAK 说明
|
||||
----------------------------------------------------------------
|
||||
|
||||
USB_ERR_NAK 只存在于 DWC2 buffer dma 模式,DWC2 在 buffer dma模式下对于中断传输不支持硬件处理 NAK 中断,因此需要软件处理,导致 NAK 中断非常多,建议搭配定时器使用。
|
||||
DWC2 scatter/gather dma 模式下全部由硬件处理,但是不支持 split 传输。总结, **半斤 IP**。
|
||||
USB_ERR_NAK 只存在于 DWC2 buffer dma/slave 模式(我们不使用 slave 模式),DWC2 在 buffer dma模式下对于中断传输不支持硬件处理 NAK 中断,因此需要软件处理,导致 NAK 中断非常多,建议搭配定时器使用。
|
||||
DWC2 scatter/gather dma 模式下全部由硬件处理,但是不支持 split 传输。总结, **食之无味,弃之可惜**。
|
||||
|
||||
USB host 连接 USB 网卡问题
|
||||
----------------------------------------------------------------
|
||||
|
||||
表现为能识别网卡并且分配到 IP 地址,但是无法 ping 通,这是因为网卡自身需要开启自动拨号,通常需要使用 AT 口设置。具体为 EC20/ML307 等模块。
|
||||
|
||||
|
||||
什么时候需要开启 CONFIG_USB_DCACHE_ENABLE
|
||||
-------------------------------------------------
|
||||
|
||||
当芯片带有 cache 功能,并且没有使用 no cache ram 时需要开启此宏以保证数据一致性。 **使用 EHCI 时,内部依旧需要使用 nocache ram**。通常,对于第三方平台或者组件,没有使用 no cache ram 宏修饰,都是使用全局变量或者 malloc 等
|
||||
操作,这部分 RAM 通常是走 cache 的,因此需要开启此宏。建议第三方平台使用时,必须开启。
|
||||
|
||||
哪些 IP 对数据有对齐要求
|
||||
-------------------------------------------------
|
||||
|
||||
- 在未开启 CONFIG_USB_DCACHE_ENABLE 时,仅 DWC2/WCH/AIC IP 需要 4字节对齐,其余 1字节对齐即可。
|
||||
- 在开启 CONFIG_USB_DCACHE_ENABLE 时,所有 IP 都需要对齐到 CONFIG_USB_ALIGN_SIZE 字节
|
||||
@@ -56,7 +56,7 @@
|
||||
* USB IP 相关的 config 需要用户自己根据芯片实际情况修改
|
||||
* 在代码中实现 `usb_hc_low_level_init` 函数
|
||||
* 在 USB 中断函数中调用 `USBH_IRQHandler`,并传入 `busid`
|
||||
* 调用 `usbh_initialize` 并填入 `busid` 和 USB IP 的 `reg base`, `busid` 从 0 开始,不能超过 `CONFIG_USBHOST_MAX_BUS`
|
||||
* 调用 `usbh_initialize` 并填入 `busid` 和 USB IP 的 `reg base` 还有 `event_handler` 可缺省为NULL, `busid` 从 0 开始,不能超过 `CONFIG_USBHOST_MAX_BUS`
|
||||
* 使用 `scons --target=mdk5` 或者 `scons` 进行编译,如果是mdk,需要使用 AC6 编译器
|
||||
* 链接脚本修改参考 :ref:`usbh_link_script` 章节
|
||||
* 如果芯片带 cache,cache 修改参考 :ref:`usb_cache` 章节
|
||||
|
||||
@@ -19,11 +19,11 @@ USB Host 移植要点
|
||||
- 拷贝 CherryUSB 源码到工程目录下,并按需添加源文件和头文件路径,头文件路径建议全部添加。其中 `usbh_core.c` 、 `usb_hc_xxx.c` 以及 **osal** 目录下源文件(根据不同的 os 选择对应的源文件)为必须添加项。而 `usb_hc_xxx.c` 是芯片所对应的 USB IP hcd 部分驱动,如果不知道自己芯片属于那个 USB IP,参考 **port** 目录下的不同 USB IP 的 readme。如果使用的 USB IP 没有支持,只能自己实现了
|
||||
- 拷贝 `cherryusb_config_template.h` 文件到自己工程目录下,命名为 `usb_config.h`,并添加相应的目录头文件路径
|
||||
- 实现 `usb_hc_low_level_init` 函数(该函数主要负责 USB 时钟、引脚、中断的初始化)。该函数可以放在你想要放的任何参与编译的 c 文件中。如何进行 USB 的时钟、引脚、中断等初始化,请自行根据你使用的芯片原厂提供的源码中进行添加。
|
||||
- 调用 `usbh_initialize` 并填入 `busid` 和 USB IP 的 `reg base`, `busid` 从 0 开始,不能超过 `CONFIG_USBHOST_MAX_BUS`
|
||||
- 调用 `usbh_initialize` 并填入 `busid` 和 USB IP 的 `reg base` 还有 `event_handler` 可缺省为NULL, `busid` 从 0 开始,不能超过 `CONFIG_USBHOST_MAX_BUS`
|
||||
- 在中断函数中调用 `USBH_IRQHandler`,并传入 `busid`, 如果你的 SDK 中中断入口已经存在 `USBH_IRQHandler` ,请更改 USB 协议栈中的名称
|
||||
- 链接脚本修改参考 :ref:`usbh_link_script` 章节
|
||||
- 如果芯片带 cache,cache 修改参考 :ref:`usb_cache` 章节
|
||||
- 调用 `usbh_initialize` ,填入 `busid` 和 USB IP 的 `reg base`, `busid` 从 0 开始,不能超过 `CONFIG_USBHOST_MAX_BUS` 。基础的 cdc + hid + msc 参考 `usb_host.c` 文件,其余参考 **platform** 目录下适配
|
||||
- 调用 `usbh_initialize` ,填入 `busid` 和 USB IP 的 `reg base` 还有 `event_handler` 可缺省为NULL, `busid` 从 0 开始,不能超过 `CONFIG_USBHOST_MAX_BUS` 。基础的 cdc + hid + msc 参考 `usb_host.c` 文件,其余参考 **platform** 目录下适配
|
||||
|
||||
.. _usbh_link_script:
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user