Compare commits
117 Commits
v1.5.3-rc1
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
859db28964 | ||
|
|
6b0ec0e16f | ||
|
|
1a5bc9d150 | ||
|
|
08d1ce4ab5 | ||
|
|
0cac0ab34c | ||
|
|
5f47d1a6b6 | ||
|
|
64dced8ec7 | ||
|
|
eaefb8ed21 | ||
|
|
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 |
4
.github/workflows/deploy-docs.yml
vendored
4
.github/workflows/deploy-docs.yml
vendored
@@ -11,7 +11,7 @@ permissions:
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -23,6 +23,6 @@ jobs:
|
||||
- uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: docs/build/html
|
||||
folder: docs/output/zh/html
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -56,7 +58,6 @@ elseif(ESP_PLATFORM)
|
||||
OR CONFIG_CHERRYUSB_HOST_CDC_NCM
|
||||
OR CONFIG_CHERRYUSB_HOST_ASIX
|
||||
OR CONFIG_CHERRYUSB_HOST_RTL8152
|
||||
OR CONFIG_CHERRYUSB_HOST_BL616
|
||||
)
|
||||
idf_component_get_property(lwip lwip COMPONENT_LIB)
|
||||
target_compile_definitions(${lwip} PRIVATE "-DPBUF_POOL_BUFSIZE=1600")
|
||||
@@ -89,7 +90,7 @@ elseif(ESP_PLATFORM)
|
||||
|
||||
# 强制链接器不删除符号
|
||||
if(CONFIG_CHERRYUSB_HOST_CDC_ACM)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u cdc_acm_class_info")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u cdc_acm_none_class_info")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u cdc_data_class_info")
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_HID)
|
||||
@@ -140,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)
|
||||
@@ -179,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)
|
||||
@@ -195,7 +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_BL616 1)
|
||||
set(CONFIG_CHERRYUSB_HOST_GSM 1)
|
||||
|
||||
set(CONFIG_CHERRYUSB_DEVICE_HPM 1)
|
||||
set(CONFIG_CHERRYUSB_HOST_EHCI_HPM 1)
|
||||
|
||||
76
Kconfig
76
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
|
||||
@@ -136,6 +138,11 @@ if CHERRYUSB
|
||||
prompt "Enable usb dfu device"
|
||||
default n
|
||||
|
||||
config CHERRYUSB_DEVICE_DISPLAY
|
||||
bool
|
||||
prompt "Enable usb display device"
|
||||
default n
|
||||
|
||||
config USBDEV_REQUEST_BUFFER_LEN
|
||||
int
|
||||
prompt "Set device control transfer max buffer size"
|
||||
@@ -159,7 +166,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
|
||||
@@ -209,6 +216,10 @@ if CHERRYUSB
|
||||
bool
|
||||
prompt "cdc_ncm"
|
||||
depends on CHERRYUSB_DEVICE_CDC_NCM
|
||||
config CHERRYUSB_DEVICE_TEMPLATE_DFU
|
||||
bool
|
||||
prompt "dfu"
|
||||
depends on CHERRYUSB_DEVICE_DFU
|
||||
config CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
|
||||
bool
|
||||
prompt "cdc_acm_msc"
|
||||
@@ -220,14 +231,21 @@ if CHERRYUSB
|
||||
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1
|
||||
bool
|
||||
prompt "winusbv1"
|
||||
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2
|
||||
bool
|
||||
prompt "winusbv2"
|
||||
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC
|
||||
bool
|
||||
prompt "winusbv2_cdc"
|
||||
depends on CHERRYUSB_DEVICE_CDC_ACM
|
||||
config CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_HID
|
||||
config CHERRYUSB_DEVICE_TEMPLATE_WEBUSB_HID
|
||||
bool
|
||||
prompt "winusbv2_hid"
|
||||
prompt "webusb_hid"
|
||||
depends on CHERRYUSB_DEVICE_HID
|
||||
config CHERRYUSB_DEVICE_TEMPLATE_DISPLAY
|
||||
bool
|
||||
prompt "display"
|
||||
depends on CHERRYUSB_DEVICE_DISPLAY
|
||||
endchoice
|
||||
endif
|
||||
|
||||
@@ -236,7 +254,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
|
||||
@@ -261,6 +279,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
|
||||
@@ -296,6 +318,7 @@ if CHERRYUSB
|
||||
config CHERRYUSB_HOST_CDC_ACM
|
||||
bool
|
||||
prompt "Enable usb cdc acm driver"
|
||||
select USBHOST_SERIAL
|
||||
default n
|
||||
|
||||
config CHERRYUSB_HOST_HID
|
||||
@@ -357,21 +380,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
|
||||
@@ -379,6 +412,9 @@ if CHERRYUSB
|
||||
prompt "Enable usb aoa driver"
|
||||
default n
|
||||
|
||||
config USBHOST_SERIAL
|
||||
bool
|
||||
|
||||
config USBHOST_PLATFORM_CDC_ECM
|
||||
bool
|
||||
|
||||
@@ -414,22 +450,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
|
||||
|
||||
78
Kconfig.rtt
78
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
|
||||
@@ -137,6 +139,11 @@ if RT_USING_CHERRYUSB
|
||||
prompt "Enable usb dfu device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_DISPLAY
|
||||
bool
|
||||
prompt "Enable usb display device"
|
||||
default n
|
||||
|
||||
config RT_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
|
||||
bool
|
||||
prompt "Enable chardev for cdc acm device"
|
||||
@@ -165,7 +172,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
|
||||
@@ -219,6 +226,10 @@ if RT_USING_CHERRYUSB
|
||||
bool
|
||||
prompt "cdc_ncm"
|
||||
depends on RT_CHERRYUSB_DEVICE_CDC_NCM
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_DFU
|
||||
bool
|
||||
prompt "dfu"
|
||||
depends on RT_CHERRYUSB_DEVICE_DFU
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
|
||||
bool
|
||||
prompt "cdc_acm_msc"
|
||||
@@ -230,14 +241,21 @@ if RT_USING_CHERRYUSB
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1
|
||||
bool
|
||||
prompt "winusbv1"
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2
|
||||
bool
|
||||
prompt "winusbv2"
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC
|
||||
bool
|
||||
prompt "winusbv2_cdc"
|
||||
depends on RT_CHERRYUSB_DEVICE_CDC_ACM
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_HID
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_WEBUSB_HID
|
||||
bool
|
||||
prompt "winusbv2_hid"
|
||||
prompt "webusb_hid"
|
||||
depends on RT_CHERRYUSB_DEVICE_HID
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_DISPLAY
|
||||
bool
|
||||
prompt "display"
|
||||
depends on RT_CHERRYUSB_DEVICE_DISPLAY
|
||||
config RT_CHERRYUSB_DEVICE_TEMPLATE_ADB
|
||||
bool
|
||||
prompt "adb"
|
||||
@@ -260,7 +278,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
|
||||
@@ -285,6 +303,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
|
||||
@@ -312,6 +334,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
|
||||
@@ -379,23 +402,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
|
||||
|
||||
@@ -431,6 +467,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
|
||||
@@ -442,21 +483,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
|
||||
@@ -136,6 +138,11 @@ if PKG_USING_CHERRYUSB
|
||||
prompt "Enable usb dfu device"
|
||||
default n
|
||||
|
||||
config PKG_CHERRYUSB_DEVICE_DISPLAY
|
||||
bool
|
||||
prompt "Enable usb display device"
|
||||
default n
|
||||
|
||||
config PKG_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
|
||||
bool
|
||||
prompt "Enable chardev for cdc acm device"
|
||||
@@ -164,7 +171,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
|
||||
@@ -218,6 +225,10 @@ if PKG_USING_CHERRYUSB
|
||||
bool
|
||||
prompt "cdc_ncm"
|
||||
depends on PKG_CHERRYUSB_DEVICE_CDC_NCM
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_DFU
|
||||
bool
|
||||
prompt "dfu"
|
||||
depends on PKG_CHERRYUSB_DEVICE_DFU
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC
|
||||
bool
|
||||
prompt "cdc_acm_msc"
|
||||
@@ -229,14 +240,21 @@ if PKG_USING_CHERRYUSB
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1
|
||||
bool
|
||||
prompt "winusbv1"
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2
|
||||
bool
|
||||
prompt "winusbv2"
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC
|
||||
bool
|
||||
prompt "winusbv2_cdc"
|
||||
depends on PKG_CHERRYUSB_DEVICE_CDC_ACM
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_HID
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_WEBUSB_HID
|
||||
bool
|
||||
prompt "winusbv2_hid"
|
||||
prompt "webusb_hid"
|
||||
depends on PKG_CHERRYUSB_DEVICE_HID
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_DISPLAY
|
||||
bool
|
||||
prompt "display"
|
||||
depends on PKG_CHERRYUSB_DEVICE_DISPLAY
|
||||
config PKG_CHERRYUSB_DEVICE_TEMPLATE_ADB
|
||||
bool
|
||||
prompt "adb"
|
||||
@@ -259,7 +277,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
|
||||
@@ -284,6 +302,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
|
||||
@@ -311,6 +333,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
|
||||
@@ -378,23 +401,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
|
||||
|
||||
@@ -430,6 +466,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
|
||||
@@ -441,21 +482,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
|
||||
|
||||
@@ -471,12 +517,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
|
||||
@@ -492,9 +538,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
|
||||
|
||||
93
README.md
93
README.md
@@ -14,31 +14,31 @@ CherryUSB is a tiny and beautiful, high performance and portable USB host and de
|
||||
|
||||
## Why choose CherryUSB
|
||||
|
||||
### Easy to study USB
|
||||
### Easy to Learn USB
|
||||
|
||||
In order to make it easier for users to learn USB basics, enumeration, driver loading and IP drivers, the code has been written with the following advantages:
|
||||
To facilitate user learning of USB fundamentals, enumeration, driver loading, and IP drivers, the written code has the following advantages:
|
||||
|
||||
- Lean code, simple logic, no complex C syntax
|
||||
- Tree-based programming with cascading code
|
||||
- Class-drivers and porting-drivers are templating and simplification
|
||||
- Clear API classification (slave: initialisation, registration api, command callback api, data sending and receiving api; host: initialisation, lookup api, data sending and receiving api)
|
||||
- Streamlined code with simple logic and no complex C language syntax
|
||||
- Tree-structured programming with progressive code layers
|
||||
- Templated and simplified Class drivers and porting drivers
|
||||
- Clear API categorization (Device: initialization, class registration, command callbacks, data transmission; Host: initialization, class discovery, data transmission)
|
||||
|
||||
### Easy to use USB
|
||||
### Easy to Use USB
|
||||
|
||||
In order to facilitate the use of the USB interface and to take into account the fact that users have learned about uart and dma, the following advantages have been designed for the data sending and receiving class of interface:
|
||||
To facilitate user interaction with USB interfaces, considering users’ familiarity with UART and DMA, the designed data transmission interface has the following advantages:
|
||||
|
||||
- Equivalent to using uart tx dma/uart rx dma
|
||||
- There is no limit to the length of send and receive, the user does not need to care about the USB packetization process (the porting driver does it)
|
||||
- Equivalent to using UART TX DMA/UART RX DMA
|
||||
- No length restrictions on transmission/reception; users don’t need to worry about USB packetization (porting drivers handle packetization)
|
||||
|
||||
### Easy to bring out USB performance
|
||||
### Easy to Achieve USB Performance
|
||||
|
||||
Taking into account USB performance issues and trying to achieve the theoretical bandwidth of the USB hardware, the design of the data transceiver class interface has the following advantages:
|
||||
Considering USB performance requirements to reach theoretical USB hardware bandwidth, the designed data transmission interface has the following advantages:
|
||||
|
||||
- Porting drivers directly to registers, no abstraction layer encapsulation
|
||||
- Porting drivers directly interface with registers without abstraction layer encapsulation
|
||||
- Memory zero copy
|
||||
- If IP has DMA then uses DMA mode (DMA with hardware packetization)
|
||||
- Unlimited length make it easier to interface with hardware DMA and take advantage of DMA
|
||||
- Packetization is handled in interrupt
|
||||
- DMA mode used when IP supports DMA (DMA provides hardware packetization functionality)
|
||||
- No length restrictions, facilitating hardware DMA interfacing and maximizing DMA advantages
|
||||
- Packetization handled in interrupt context
|
||||
|
||||
Performance show:https://cherryusb.cherry-embedded.org/show/
|
||||
|
||||
@@ -75,6 +75,7 @@ CherryUSB Device Stack has the following functions:
|
||||
- Support Remote NDIS (RNDIS)
|
||||
- Support Media Transfer Protocol (MTP)
|
||||
- Support WINUSB1.0, WINUSB2.0, WEBUSB, BOS
|
||||
- Support Vendor display ([xfz1986_usb_graphic_driver](https://github.com/chuanjinpang/win10_idd_xfz1986_usb_graphic_driver_display))
|
||||
- Support Vendor class
|
||||
- Support UF2
|
||||
- Support Android Debug Bridge (Only support shell)
|
||||
@@ -93,6 +94,7 @@ CherryUSB Device Stack resource usage (GCC 10.2 with -O2, disable log):
|
||||
|usbd_rndis.c | ~2500 | 2 * 1580(default)+156+8 | 80 | 0 |
|
||||
|usbd_cdc_ecm.c | ~900 | 2 * 1514(default)+16 | 42 | 0 |
|
||||
|usbd_mtp.c | ~9000 | 2048(default)+128 | sizeof(struct mtp_object) * n| 0 |
|
||||
|usbd_dfu.c | ~2200 | 0 | 45 | 0 |
|
||||
|
||||
## Host Stack Overview
|
||||
|
||||
@@ -112,7 +114,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 +153,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
|
||||
@@ -175,55 +178,31 @@ Only standard and commercial USB IP are listed.
|
||||
| CDNS3(cadence) | CDNS3 | XHCI | × |
|
||||
| DWC3(synopsys) | DWC3 | XHCI | × |
|
||||
|
||||
## Documentation Tutorial
|
||||
## Resources
|
||||
|
||||
Quickly start, USB basic concepts, API manual, Class basic concepts and examples, see [CherryUSB Documentation Tutorial](https://cherryusb.readthedocs.io/).
|
||||
### Getting Started
|
||||
|
||||
## Video Tutorial
|
||||
- 📖 [CherryUSB Documentation](https://cherryusb.readthedocs.io/en/latest/)
|
||||
- 💻 [CherryUSB Demo Repo](https://cherryusb.readthedocs.io/en/latest/quick_start/demo.html)
|
||||
- 📺 [CherryUSB Cheese(>= V1.4.3)](https://www.bilibili.com/cheese/play/ss707687201)
|
||||
|
||||
CherryUSB Cheese (based V1.4.3): https://www.bilibili.com/cheese/play/ss707687201 .
|
||||
|
||||
## Descriptor Generator Tool
|
||||
|
||||
TODO
|
||||
|
||||
## Demo Repo
|
||||
|
||||
| Manufacturer | CHIP or Series | USB IP| Repo Url | Support version | Note |
|
||||
|:--------------------:|:------------------:|:-----:|:--------:|:------------------:|:-------------:|
|
||||
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/bouffalo_sdk)|<= latest | Official |
|
||||
|ST | STM32F1x/STM32F4/STM32H7 | fsdev/dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Community |
|
||||
|HPMicro | HPM6000/HPM5000 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/hpm_sdk)|<= latest | Official |
|
||||
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Official |
|
||||
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|>=1.4.0 | Official |
|
||||
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Official |
|
||||
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)/[espressif](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb)|<= latest | Official |
|
||||
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/k230_sdk)|v1.2.0 | Official |
|
||||
|Actionstech | ATS30xx | dwc2 |[action_zephyr_repo](https://github.com/CherryUSB/lv_port_actions_technology/tree/master/action_technology_sdk)|>=1.4.0 | Official |
|
||||
|SiFli | SF32LB5x | musb |[SiFli_sdk](https://github.com/OpenSiFli/SiFli-SDK)|>=1.5.0 | Official |
|
||||
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Community |
|
||||
|Nationstech | n32h4x | dwc2 |[nation_repo](https://github.com/CherryUSB/cherryusb_nation)|>=1.5.0 | Official ongoing |
|
||||
|Raspberry pi | rp2040/rp2350 | rp2040 |[pico-sdk](https://github.com/CherryUSB/pico-sdk)|<= latest | Official ongoing |
|
||||
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | no more update |
|
||||
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | Official |
|
||||
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | Official |
|
||||
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2/>=v1.5.0 | no more update |
|
||||
|
||||
## Package Support
|
||||
|
||||
CherryUSB package is available as follows:
|
||||
### Package Support
|
||||
|
||||
- [RT-Thread](https://packages.rt-thread.org/detail.html?package=CherryUSB)
|
||||
- [YOC](https://www.xrvm.cn/document?temp=usb-host-protocol-stack-device-driver-adaptation-instructions&slug=yocbook)
|
||||
- [ESP-Registry](https://components.espressif.com/components/cherry-embedded/cherryusb)
|
||||
|
||||
### Descriptor Generator Tool
|
||||
|
||||
Cherry Descriptor: https://desc.cherry-embedded.org/en
|
||||
|
||||
### Contact
|
||||
|
||||
CherryUSB discord: https://discord.com/invite/wFfvrSAey8
|
||||
|
||||
## Commercial Support
|
||||
|
||||
Refer to https://cherryusb.readthedocs.io/zh-cn/latest/support/index.html.
|
||||
|
||||
## Contact
|
||||
|
||||
CherryUSB discord: https://discord.com/invite/wFfvrSAey8.
|
||||
Refer to https://cherryusb.readthedocs.io/en/latest/support/index.html
|
||||
|
||||
## Company Support
|
||||
|
||||
|
||||
57
README_zh.md
57
README_zh.md
@@ -75,6 +75,7 @@ CherryUSB Device 协议栈当前实现以下功能:
|
||||
- 支持 Remote NDIS (RNDIS)
|
||||
- 支持 Media Transfer Protocol (MTP)
|
||||
- 支持 WINUSB1.0、WINUSB2.0、WEBUSB、BOS
|
||||
- 支持 Vendor display ([xfz1986_usb_graphic_driver](https://github.com/chuanjinpang/win10_idd_xfz1986_usb_graphic_driver_display))
|
||||
- 支持 Vendor 类 class
|
||||
- 支持 UF2
|
||||
- 支持 Android Debug Bridge (Only support shell)
|
||||
@@ -93,6 +94,7 @@ CherryUSB Device 协议栈资源占用说明(GCC 10.2 with -O2):
|
||||
|usbd_rndis.c | ~2500 | 2 * 1580(default)+156+8 | 80 | 0 |
|
||||
|usbd_cdc_ecm.c | ~900 | 2 * 1514(default)+16 | 42 | 0 |
|
||||
|usbd_mtp.c | ~9000 | 2048(default)+128 | sizeof(struct mtp_object) * n| 0 |
|
||||
|usbd_dfu.c | ~2200 | 0 | 45 | 0 |
|
||||
|
||||
## Host 协议栈简介
|
||||
|
||||
@@ -112,7 +114,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 +153,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
|
||||
@@ -175,58 +178,34 @@ x 受以下宏影响:
|
||||
| CDNS3(cadence) | CDNS3 | XHCI | × |
|
||||
| DWC3(synopsys) | DWC3 | XHCI | × |
|
||||
|
||||
## 文档教程
|
||||
## Resources
|
||||
|
||||
CherryUSB 快速入门、USB 基本概念、API 手册、Class 基本概念和例程,参考 [CherryUSB Documentation Tutorial](https://cherryusb.readthedocs.io/)。
|
||||
### 快速开始
|
||||
|
||||
## 视频教程
|
||||
- 📖 [CherryUSB Documentation](https://cherryusb.readthedocs.io/zh-cn/latest/)
|
||||
- 💻 [CherryUSB Demo Repo](https://cherryusb.readthedocs.io/zh-cn/latest/quick_start/demo.html)
|
||||
- 📺 [CherryUSB Cheese(>= V1.4.3)](https://www.bilibili.com/cheese/play/ss707687201)
|
||||
|
||||
CherryUSB 课程(基于 V1.4.3):https://www.bilibili.com/cheese/play/ss707687201 。
|
||||
|
||||
## 描述符生成工具
|
||||
|
||||
TODO
|
||||
|
||||
## 示例仓库
|
||||
|
||||
| Manufacturer | CHIP or Series | USB IP| Repo Url | Support version | Note |
|
||||
|:--------------------:|:------------------:|:-----:|:--------:|:------------------:|:-------------:|
|
||||
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/bouffalo_sdk)|<= latest | Official |
|
||||
|ST | STM32F1x/STM32F4/STM32H7 | fsdev/dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|<= latest | Community |
|
||||
|HPMicro | HPM6000/HPM5000 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/hpm_sdk)|<= latest | Official |
|
||||
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|<= latest | Official |
|
||||
|Phytium | e2000 | pusb2/xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|>=1.4.0 | Official |
|
||||
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Official |
|
||||
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)/[espressif](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/usb)|<= latest | Official |
|
||||
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/k230_sdk)|v1.2.0 | Official |
|
||||
|Actionstech | ATS30xx | dwc2 |[action_zephyr_repo](https://github.com/CherryUSB/lv_port_actions_technology/tree/master/action_technology_sdk)|>=1.4.0 | Official |
|
||||
|SiFli | SF32LB5x | musb |[SiFli_sdk](https://github.com/OpenSiFli/SiFli-SDK)|>=1.5.0 | Official |
|
||||
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Community |
|
||||
|Nationstech | n32h4x | dwc2 |[nation_repo](https://github.com/CherryUSB/cherryusb_nation)|>=1.5.0 | Official ongoing |
|
||||
|Raspberry pi | rp2040/rp2350 | rp2040 |[pico-sdk](https://github.com/CherryUSB/pico-sdk)|<= latest | Official ongoing |
|
||||
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | no more update |
|
||||
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | Official |
|
||||
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | Official |
|
||||
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|<= v0.10.2/>=v1.5.0 | no more update |
|
||||
|
||||
## 软件包支持
|
||||
|
||||
CherryUSB 软件包可以通过以下方式获取:
|
||||
### 软件包支持
|
||||
|
||||
- [RT-Thread](https://packages.rt-thread.org/detail.html?package=CherryUSB)
|
||||
- [YOC](https://www.xrvm.cn/document?temp=usb-host-protocol-stack-device-driver-adaptation-instructions&slug=yocbook)
|
||||
- [ESP-Registry](https://components.espressif.com/components/cherry-embedded/cherryusb)
|
||||
|
||||
## 商业支持
|
||||
### 描述符生成工具
|
||||
|
||||
参考 https://cherryusb.readthedocs.io/zh-cn/latest/support/index.html 。
|
||||
Cherry Descriptor: https://desc.cherry-embedded.org/zh
|
||||
|
||||
## 联系
|
||||
### Contact
|
||||
|
||||
CherryUSB QQ群:642693751
|
||||
|
||||
CherryUSB 微信群:与我联系后邀请加入
|
||||
|
||||
## 商业支持
|
||||
|
||||
参考 https://cherryusb.readthedocs.io/zh-cn/latest/support/index.html
|
||||
|
||||
## 支持企业
|
||||
|
||||
感谢以下企业支持(顺序不分先后):
|
||||
|
||||
54
SConscript
54
SConscript
@@ -14,10 +14,10 @@ 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']
|
||||
path += [cwd + '/class/vendor/display']
|
||||
src = []
|
||||
|
||||
LIBS = []
|
||||
@@ -47,6 +47,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 +115,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')
|
||||
@@ -131,6 +137,11 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
|
||||
src += Glob('class/cdc/usbd_cdc_ncm.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_DFU']):
|
||||
src += Glob('class/dfu/usbd_dfu.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_DISPLAY']):
|
||||
src += Glob('class/vendor/display/usbd_display.c')
|
||||
src += Glob('third_party/cherrymp/chry_mempool.c')
|
||||
src += Glob('third_party/cherrymp/chry_mempool_osal_rtthread.c')
|
||||
path += [cwd + '/third_party/cherrymp']
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_ADB']):
|
||||
src += Glob('class/adb/usbd_adb.c')
|
||||
src += Glob('platform/rtthread/usbd_adb_shell.c')
|
||||
@@ -160,16 +171,22 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
|
||||
src += Glob('demo/cdc_ecm_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_NCM']):
|
||||
src += Glob('demo/cdc_ncm_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_DFU']):
|
||||
src += Glob('demo/dfu_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC']):
|
||||
src += Glob('demo/cdc_acm_msc_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_MSC_HID']):
|
||||
src += Glob('demo/cdc_acm_hid_msc_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV1']):
|
||||
src += Glob('demo/winusb1.0_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2']):
|
||||
src += Glob('demo/winusb2.0_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_CDC']):
|
||||
src += Glob('demo/winusb2.0_cdc_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_WINUSBV2_HID']):
|
||||
src += Glob('demo/winusb2.0_hid_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_WEBUSB_HID']):
|
||||
src += Glob('demo/webusb_hid_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_DISPLAY']):
|
||||
src += Glob('demo/display/usbdisplay_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_ADB']):
|
||||
src += Glob('demo/adb/usbd_adb_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM_CHARDEV']):
|
||||
@@ -216,6 +233,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')
|
||||
@@ -266,8 +289,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']):
|
||||
@@ -289,23 +316,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,12 @@ 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/vendor/display
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/aoa
|
||||
${CMAKE_CURRENT_LIST_DIR}/class/gamepad
|
||||
)
|
||||
|
||||
if(CONFIG_CHERRYUSB_DEVICE)
|
||||
@@ -85,6 +87,12 @@ 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_DISPLAY)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/display/usbd_display.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_CHERRYUSB_DEVICE_FSDEV_ST)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/fsdev/usb_dc_fsdev.c)
|
||||
@@ -156,7 +164,7 @@ if(CONFIG_CHERRYUSB_HOST)
|
||||
)
|
||||
|
||||
if(CONFIG_CHERRYUSB_HOST_CDC_ACM)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbh_cdc_acm.c)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_cdc_acm.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_CDC_ECM)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/cdc/usbh_cdc_ecm.c)
|
||||
@@ -235,30 +243,39 @@ if(CONFIG_CHERRYUSB_HOST)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/net/usbh_rtl8152.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_CH34X)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_ch34x.c)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_ch34x.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_CP210X)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_cp210x.c)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_cp210x.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_FTDI)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_ftdi.c)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_ftdi.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_PL2303)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial/usbh_pl2303.c)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_pl2303.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_BL616)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi/usbh_bl616.c)
|
||||
if(CONFIG_CHERRYUSB_HOST_GSM)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_gsm.c)
|
||||
endif()
|
||||
if(CONFIG_CHERRYUSB_HOST_AOA)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/aoa/usbh_aoa.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_CHERRYUSB_HOST_CDC_ACM
|
||||
OR CONFIG_CHERRYUSB_HOST_CH34X
|
||||
OR CONFIG_CHERRYUSB_HOST_CP210X
|
||||
OR CONFIG_CHERRYUSB_HOST_FTDI
|
||||
OR CONFIG_CHERRYUSB_HOST_PL2303
|
||||
OR CONFIG_CHERRYUSB_HOST_GSM
|
||||
)
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/serial/usbh_serial.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_CHERRYUSB_HOST_CDC_ECM
|
||||
OR CONFIG_CHERRYUSB_HOST_CDC_RNDIS
|
||||
OR CONFIG_CHERRYUSB_HOST_CDC_NCM
|
||||
OR CONFIG_CHERRYUSB_HOST_ASIX
|
||||
OR CONFIG_CHERRYUSB_HOST_RTL8152
|
||||
OR CONFIG_CHERRYUSB_HOST_BL616
|
||||
)
|
||||
if("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "idf")
|
||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/platform/idf/usbh_net.c)
|
||||
@@ -335,7 +352,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
|
||||
|
||||
@@ -88,18 +88,6 @@
|
||||
#define AUDIO_ENDPOINT_UNDEFINED 0x00U
|
||||
#define AUDIO_ENDPOINT_GENERAL 0x01U
|
||||
|
||||
/* Feature Unit Control Bits */
|
||||
#define AUDIO_CONTROL_MUTE 0x0001
|
||||
#define AUDIO_CONTROL_VOLUME 0x0002
|
||||
#define AUDIO_CONTROL_BASS 0x0004
|
||||
#define AUDIO_CONTROL_MID 0x0008
|
||||
#define AUDIO_CONTROL_TREBLE 0x0010
|
||||
#define AUDIO_CONTROL_GRAPHIC_EQUALIZER 0x0020
|
||||
#define AUDIO_CONTROL_AUTOMATIC_GAIN 0x0040
|
||||
#define AUDIO_CONTROL_DEALY 0x0080
|
||||
#define AUDIO_CONTROL_BASS_BOOST 0x0100
|
||||
#define AUDIO_CONTROL_LOUDNESS 0x0200
|
||||
|
||||
/* Encoder Type Codes */
|
||||
#define AUDIO_ENCODER_UNDEF 0x00
|
||||
#define AUDIO_ENCODER_OTHER 0x01
|
||||
@@ -245,22 +233,34 @@
|
||||
#define AUDIO_FU_CONTROL_OVERFLOW 0x0f
|
||||
#define AUDIO_FU_CONTROL_LATENCY 0x10
|
||||
|
||||
#define AUDIO_V2_FU_CONTROL_UNDEF 0x00
|
||||
#define AUDIO_V2_FU_CONTROL_MUTE (0x03 << 0)
|
||||
#define AUDIO_V2_FU_CONTROL_VOLUME (0x03 << 2)
|
||||
#define AUDIO_V2_FU_CONTROL_BASS (0x03 << 4)
|
||||
#define AUDIO_V2_FU_CONTROL_MID (0x03 << 6)
|
||||
#define AUDIO_V2_FU_CONTROL_TREBLE (0x03 << 8)
|
||||
#define AUDIO_V2_FU_CONTROL_EQUALIZER (0x03 << 10)
|
||||
#define AUDIO_V2_FU_CONTROL_AGC (0x03 << 12)
|
||||
#define AUDIO_V2_FU_CONTROL_DELAY (0x03 << 14)
|
||||
#define AUDIO_V2_FU_CONTROL_BASS_BOOST (0x03 << 16)
|
||||
#define AUDIO_V2_FU_CONTROL_LOUDNESS (0x03 << 18)
|
||||
#define AUDIO_V2_FU_CONTROL_INP_GAIN (0x03 << 20)
|
||||
#define AUDIO_V2_FU_CONTROL_INP_GAIN_PAD (0x03 << 22)
|
||||
#define AUDIO_V2_FU_CONTROL_PHASE_INVERT (0x03 << 24)
|
||||
#define AUDIO_V2_FU_CONTROL_UNDERFLOW (0x03 << 26)
|
||||
#define AUDIO_V2_FU_CONTROL_OVERFLOW (0x03 << 28)
|
||||
/* Feature Unit Control Bits */
|
||||
#define AUDIO_CONTROL_MUTE 0x0001
|
||||
#define AUDIO_CONTROL_VOLUME 0x0002
|
||||
#define AUDIO_CONTROL_BASS 0x0004
|
||||
#define AUDIO_CONTROL_MID 0x0008
|
||||
#define AUDIO_CONTROL_TREBLE 0x0010
|
||||
#define AUDIO_CONTROL_GRAPHIC_EQUALIZER 0x0020
|
||||
#define AUDIO_CONTROL_AUTOMATIC_GAIN 0x0040
|
||||
#define AUDIO_CONTROL_DEALY 0x0080
|
||||
#define AUDIO_CONTROL_BASS_BOOST 0x0100
|
||||
#define AUDIO_CONTROL_LOUDNESS 0x0200
|
||||
|
||||
#define AUDIO_V2_CONTROL_UNDEF 0x00
|
||||
#define AUDIO_V2_CONTROL_MUTE (0x03 << 0)
|
||||
#define AUDIO_V2_CONTROL_VOLUME (0x03 << 2)
|
||||
#define AUDIO_V2_CONTROL_BASS (0x03 << 4)
|
||||
#define AUDIO_V2_CONTROL_MID (0x03 << 6)
|
||||
#define AUDIO_V2_CONTROL_TREBLE (0x03 << 8)
|
||||
#define AUDIO_V2_CONTROL_EQUALIZER (0x03 << 10)
|
||||
#define AUDIO_V2_CONTROL_AGC (0x03 << 12)
|
||||
#define AUDIO_V2_CONTROL_DELAY (0x03 << 14)
|
||||
#define AUDIO_V2_CONTROL_BASS_BOOST (0x03 << 16)
|
||||
#define AUDIO_V2_CONTROL_LOUDNESS (0x03 << 18)
|
||||
#define AUDIO_V2_CONTROL_INP_GAIN (0x03 << 20)
|
||||
#define AUDIO_V2_CONTROL_INP_GAIN_PAD (0x03 << 22)
|
||||
#define AUDIO_V2_CONTROL_PHASE_INVERT (0x03 << 24)
|
||||
#define AUDIO_V2_CONTROL_UNDERFLOW (0x03 << 26)
|
||||
#define AUDIO_V2_CONTROL_OVERFLOW (0x03 << 28)
|
||||
|
||||
/* Parametric Equalizer Section Effect Unit Control Selectors */
|
||||
#define AUDIO_PE_CONTROL_UNDEF 0x00
|
||||
@@ -605,7 +605,7 @@ struct audio_cs_if_ac_header_descriptor {
|
||||
uint8_t baInterfaceNr[];
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_SIZEOF_AC_HEADER_DESC(n) (8 + n)
|
||||
#define AUDIO_SIZEOF_AC_HEADER_DESC(bInCollection) (8 + (bInCollection))
|
||||
|
||||
struct audio_cs_if_ac_input_terminal_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -646,7 +646,7 @@ struct audio_cs_if_ac_feature_unit_descriptor {
|
||||
uint8_t iFeature;
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(ch, n) (7 + (ch + 1) * n)
|
||||
#define AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(bNrChannels, bControlSize) (7 + ((bNrChannels) + 1) * (bControlSize))
|
||||
|
||||
struct audio_cs_if_ac_selector_unit_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -658,7 +658,7 @@ struct audio_cs_if_ac_selector_unit_descriptor {
|
||||
uint8_t iSelector;
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_SIZEOF_AC_SELECTOR_UNIT_DESC(n) (6 + n)
|
||||
#define AUDIO_SIZEOF_AC_SELECTOR_UNIT_DESC(bNrInPins) (6 + (bNrInPins))
|
||||
|
||||
struct audio_cs_if_as_general_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -683,7 +683,7 @@ struct audio_cs_if_as_format_type_descriptor {
|
||||
uint8_t tSamFreq[3];
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_SIZEOF_FORMAT_TYPE_DESC(n) (8 + 3 * n)
|
||||
#define AUDIO_SIZEOF_FORMAT_TYPE_DESC(bSamFreqType) (8 + 3 * (bSamFreqType))
|
||||
|
||||
struct audio_ep_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -738,7 +738,7 @@ struct audio_cs_ep_ep_general_descriptor {
|
||||
PP_NARG(__VA_ARGS__), /* bInCollection */ \
|
||||
__VA_ARGS__ /* baInterfaceNr */
|
||||
|
||||
#define AUDIO_AC_DESCRIPTOR_INIT_LEN(n) (0x08 + 0x09 + 0x08 + n)
|
||||
#define AUDIO_AC_DESCRIPTOR_LEN(bInCollection) (0x08 + 0x09 + 0x08 + bInCollection)
|
||||
|
||||
#define AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(bTerminalID, wTerminalType, bNrChannels, wChannelConfig) \
|
||||
0x0C, /* bLength */ \
|
||||
@@ -880,8 +880,8 @@ struct audio_cs_ep_ep_general_descriptor {
|
||||
0x03, /* bRefresh, 8ms */ \
|
||||
0x00 /* bSynchAddress */
|
||||
|
||||
#define AUDIO_AS_DESCRIPTOR_INIT_LEN(n) (0x09 + 0x09 + 0x07 + 0x08 + 3 * n + 0x09 + 0x07)
|
||||
#define AUDIO_AS_FEEDBACK_DESCRIPTOR_INIT_LEN(n) (0x09 + 0x09 + 0x07 + 0x08 + 3 * n + 0x09 + 0x07 + 0x09)
|
||||
#define AUDIO_AS_DESCRIPTOR_LEN(bSamFreqType) (0x09 + 0x09 + 0x07 + 0x08 + 3 * (bSamFreqType) + 0x09 + 0x07)
|
||||
#define AUDIO_AS_FEEDBACK_DESCRIPTOR_LEN(bSamFreqType) (0x09 + 0x09 + 0x07 + 0x08 + 3 * (bSamFreqType) + 0x09 + 0x07 + 0x09)
|
||||
|
||||
#define AUDIO_AS_ALTSETTING_DESCRIPTOR_INIT(bInterfaceNumber, bAlternateSetting, bTerminalLink, bNrChannels, bSubFrameSize, bBitResolution, bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval, ...) \
|
||||
0x09, /* bLength */ \
|
||||
@@ -924,9 +924,9 @@ struct audio_cs_ep_ep_general_descriptor {
|
||||
0x00, /* wLockDelay */ \
|
||||
0x00
|
||||
|
||||
#define AUDIO_AS_ALTSETTING_DESCRIPTOR_INIT_LEN(n) (0x09 + 0x07 + 0x08 + 3 * n + 0x09 + 0x07)
|
||||
#define AUDIO_AS_ALTSETTING_DESCRIPTOR_LEN(bSamFreqType) (0x09 + 0x07 + 0x08 + 3 * (bSamFreqType) + 0x09 + 0x07)
|
||||
|
||||
#define AUDIO_AS_ALTSETTING0_DESCRIPTOR_INIT(bInterfaceNumber) \
|
||||
#define AUDIO_AS_ALTSETTING0_DESCRIPTOR_INIT(bInterfaceNumber) \
|
||||
0x09, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||
bInterfaceNumber, /* bInterfaceNumber */ \
|
||||
@@ -937,19 +937,6 @@ struct audio_cs_ep_ep_general_descriptor {
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ \
|
||||
0x00 /* iInterface */
|
||||
|
||||
#define AUDIO_MS_STANDARD_DESCRIPTOR_INIT(bInterfaceNumber, bNumEndpoints) \
|
||||
0x09, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||
bInterfaceNumber, /* bInterfaceNumber */ \
|
||||
0x00, /* bAlternateSetting */ \
|
||||
bNumEndpoints, /* bNumEndpoints */ \
|
||||
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ \
|
||||
AUDIO_SUBCLASS_MIDISTREAMING, /* bInterfaceSubClass */ \
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ \
|
||||
0x00 /* iInterface */
|
||||
|
||||
#define AUDIO_MS_STANDARD_DESCRIPTOR_INIT_LEN 0x09
|
||||
|
||||
struct audio_v2_channel_cluster_descriptor {
|
||||
uint8_t bNrChannels;
|
||||
uint32_t bmChannelConfig;
|
||||
@@ -993,7 +980,7 @@ struct audio_v2_cs_if_ac_clock_selector_descriptor {
|
||||
uint8_t iClockSelector;
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_SIZEOF_AC_CLOCK_SELECTOR_DESC(n) (7 + n)
|
||||
#define AUDIO_SIZEOF_AC_CLOCK_SELECTOR_DESC(bNrInPins) (7 + (bNrInPins))
|
||||
|
||||
struct audio_v2_cs_if_ac_clock_multiplier_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -1005,7 +992,7 @@ struct audio_v2_cs_if_ac_clock_multiplier_descriptor {
|
||||
uint8_t iClockMultiplier;
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_SIZEOF_AC_CLOCK_MULTIPLIER_DESC() (7)
|
||||
#define AUDIO_SIZEOF_AC_CLOCK_MULTIPLIER_DESC (7)
|
||||
|
||||
struct audio_v2_cs_if_ac_input_terminal_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -1049,7 +1036,7 @@ struct audio_v2_cs_if_ac_feature_unit_descriptor {
|
||||
uint8_t iFeature;
|
||||
} __PACKED;
|
||||
|
||||
#define AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(ch) (6 + (ch + 1) * 4)
|
||||
#define AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(bNrChannels) (6 + ((bNrChannels) + 1) * 4)
|
||||
|
||||
struct audio_v2_cs_if_as_general_descriptor {
|
||||
uint8_t bLength;
|
||||
@@ -1124,7 +1111,7 @@ struct audio_v2_control_range3_param_block {
|
||||
WBVAL(wTotalLength), /* wTotalLength */ \
|
||||
bmControls /* bmControls */ \
|
||||
|
||||
#define AUDIO_V2_AC_DESCRIPTOR_INIT_LEN (0x08 + 0x09 + 0x09)
|
||||
#define AUDIO_V2_AC_DESCRIPTOR_LEN (0x08 + 0x09 + 0x09)
|
||||
|
||||
#define AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(bClockID, bmAttributes, bmControls) \
|
||||
0x08, /* bLength */ \
|
||||
@@ -1262,7 +1249,7 @@ struct audio_v2_control_range3_param_block {
|
||||
0x00, /* wLockDelay */ \
|
||||
0x00
|
||||
|
||||
#define AUDIO_V2_AS_ALTSETTING0_DESCRIPTOR_INIT(bInterfaceNumber) \
|
||||
#define AUDIO_V2_AS_ALTSETTING0_DESCRIPTOR_INIT(bInterfaceNumber) \
|
||||
0x09, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||
bInterfaceNumber, /* bInterfaceNumber */ \
|
||||
@@ -1331,9 +1318,10 @@ struct audio_v2_control_range3_param_block {
|
||||
|
||||
// clang-format on
|
||||
|
||||
#define AUDIO_V2_AS_DESCRIPTOR_INIT_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08)
|
||||
#define AUDIO_V2_AS_ALTSETTING_DESCRIPTOR_INIT_LEN (0x09 + 0x10 + 0x06 + 0x07 + 0x08)
|
||||
#define AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08 + 0x07)
|
||||
#define AUDIO_V2_AS_DESCRIPTOR_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08)
|
||||
#define AUDIO_V2_AS_ALTSETTING0_DESCRIPTOR_LEN (0x09)
|
||||
#define AUDIO_V2_AS_ALTSETTING_DESCRIPTOR_LEN (0x09 + 0x10 + 0x06 + 0x07 + 0x08)
|
||||
#define AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_LEN (0x09 + 0x09 + 0x10 + 0x06 + 0x07 + 0x08 + 0x07)
|
||||
|
||||
#define AUDIO_SAMPLE_FREQ_NUM(num) (uint8_t)(num), (uint8_t)((num >> 8))
|
||||
#define AUDIO_SAMPLE_FREQ_3B(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), (uint8_t)((frq >> 16))
|
||||
|
||||
@@ -49,7 +49,6 @@ static int audio_class_endpoint_request_handler(uint8_t busid, struct usb_setup_
|
||||
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -109,7 +108,6 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
||||
*len = 1;
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@@ -124,7 +122,6 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -169,7 +166,6 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
||||
*len = 2;
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@@ -207,14 +203,12 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Audio Class cs 0x%02x \r\n", control_selector);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -247,7 +241,6 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x in cs 0x%02x\r\n", setup->bRequest, control_selector);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -261,7 +254,6 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
||||
break;
|
||||
|
||||
default:
|
||||
//USB_LOG_WRN("Unhandled Audio Class cs 0x%02x \r\n", control_selector);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -217,12 +217,12 @@
|
||||
#define CDC_SERIAL_STATE_BREAK (1 << 2) /* state of break detection */
|
||||
#define CDC_SERIAL_STATE_BREAK_Pos (2)
|
||||
#define CDC_SERIAL_STATE_BREAK_Msk (1 << CDC_SERIAL_STATE_BREAK_Pos)
|
||||
#define CDC_SERIAL_STATE_TX_CARRIER (1 << 1) /* state of transmission carrier */
|
||||
#define CDC_SERIAL_STATE_TX_CARRIER_Pos (1)
|
||||
#define CDC_SERIAL_STATE_TX_CARRIER_Msk (1 << CDC_SERIAL_STATE_TX_CARRIER_Pos)
|
||||
#define CDC_SERIAL_STATE_RX_CARRIER (1 << 0) /* state of receiver carrier */
|
||||
#define CDC_SERIAL_STATE_RX_CARRIER_Pos (0)
|
||||
#define CDC_SERIAL_STATE_RX_CARRIER_Msk (1 << CDC_SERIAL_STATE_RX_CARRIER_Pos)
|
||||
#define CDC_SERIAL_STATE_DSR (1 << 1) /* state of transmission carrier */
|
||||
#define CDC_SERIAL_STATE_DSR_Pos (1)
|
||||
#define CDC_SERIAL_STATE_DSR_Msk (1 << CDC_SERIAL_STATE_DSR_Pos)
|
||||
#define CDC_SERIAL_STATE_DCD (1 << 0) /* state of receiver carrier */
|
||||
#define CDC_SERIAL_STATE_DCD_Pos (0)
|
||||
#define CDC_SERIAL_STATE_DCD_Msk (1 << CDC_SERIAL_STATE_DCD_Pos)
|
||||
|
||||
#define CDC_ECM_XMIT_OK (1 << 0)
|
||||
#define CDC_ECM_RVC_OK (1 << 1)
|
||||
@@ -551,10 +551,9 @@ struct cdc_ncm_ndp16 {
|
||||
#define DBVAL_BE(x) ((x >> 24) & 0xFF), ((x >> 16) & 0xFF), ((x >> 8) & 0xFF), (x & 0xFF)
|
||||
|
||||
/*Length of template descriptor: 71 bytes*/
|
||||
#define CDC_ECM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 13 + 7 + 9 + 7 + 7)
|
||||
#define CDC_ECM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 13 + 7 + 9 + 7 + 7)
|
||||
// clang-format off
|
||||
#define CDC_ECM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, \
|
||||
eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx) \
|
||||
#define CDC_ECM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, str_idx) \
|
||||
/* Interface Associate */ \
|
||||
0x08, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
|
||||
@@ -587,10 +586,10 @@ eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx)
|
||||
CDC_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE */\
|
||||
CDC_FUNC_DESC_ETHERNET_NETWORKING, /* Ethernet Networking functional descriptor subtype */\
|
||||
str_idx, /* Device's MAC string index */\
|
||||
DBVAL_BE(eth_statistics), /* Ethernet statistics (bitmap) */\
|
||||
WBVAL(wMaxSegmentSize),/* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
|
||||
WBVAL(wNumberMCFilters), /* wNumberMCFilters: the number of multicast filters */\
|
||||
bNumberPowerFilters, /* bNumberPowerFilters: the number of wakeup power filters */\
|
||||
DBVAL_BE(0x00000000), /* Ethernet statistics (bitmap) */\
|
||||
WBVAL(1514), /* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
|
||||
WBVAL(0), /* wNumberMCFilters: the number of multicast filters */ \
|
||||
0, /* bNumberPowerFilters: the number of wakeup power filters */ \
|
||||
0x07, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
|
||||
int_ep, /* bEndpointAddress */ \
|
||||
@@ -621,10 +620,9 @@ eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx)
|
||||
// clang-format on
|
||||
|
||||
/*Length of template descriptor: 77 bytes*/
|
||||
#define CDC_NCM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 13 + 6 + 7 + 9 + 7 + 7)
|
||||
#define CDC_NCM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 13 + 6 + 7 + 9 + 7 + 7)
|
||||
// clang-format off
|
||||
#define CDC_NCM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, \
|
||||
eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx) \
|
||||
#define CDC_NCM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, str_idx) \
|
||||
/* Interface Associate */ \
|
||||
0x08, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
|
||||
@@ -657,10 +655,10 @@ eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx)
|
||||
CDC_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE */\
|
||||
CDC_FUNC_DESC_ETHERNET_NETWORKING, /* Ethernet Networking functional descriptor subtype */\
|
||||
str_idx, /* Device's MAC string index */\
|
||||
DBVAL_BE(eth_statistics), /* Ethernet statistics (bitmap) */\
|
||||
WBVAL(wMaxPacketSize),/* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
|
||||
WBVAL(wNumberMCFilters), /* wNumberMCFilters: the number of multicast filters */\
|
||||
bNumberPowerFilters, /* bNumberPowerFilters: the number of wakeup power filters */\
|
||||
DBVAL_BE(0x00000000), /* Ethernet statistics (bitmap) */\
|
||||
WBVAL(1514), /* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
|
||||
WBVAL(0), /* wNumberMCFilters: the number of multicast filters */ \
|
||||
0, /* bNumberPowerFilters: the number of wakeup power filters */ \
|
||||
0x06, \
|
||||
CDC_CS_INTERFACE, \
|
||||
CDC_FUNC_DESC_NCM, \
|
||||
|
||||
@@ -76,7 +76,6 @@ static int cdc_acm_class_interface_request_handler(uint8_t busid, struct usb_set
|
||||
usbd_cdc_acm_send_break(busid, intf_num);
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled CDC Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,6 @@ static int cdc_ecm_class_interface_request_handler(uint8_t busid, struct usb_set
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled CDC ECM Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -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,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#define DFU_PROTOCOL_RUNTIME 0x01
|
||||
|
||||
/** DFU Class DFU mode Protocol */
|
||||
#define DFU_PROTOCOL_MODE 0x02
|
||||
#define DFU_PROTOCOL_DFU 0x02
|
||||
|
||||
/**
|
||||
* @brief DFU Class Specific Requests
|
||||
@@ -76,21 +76,23 @@
|
||||
#define DFU_STATE_DFU_UPLOAD_IDLE 9U
|
||||
#define DFU_STATE_DFU_ERROR 10U
|
||||
|
||||
/** DFU Manifestation State */
|
||||
#define DFU_MANIFEST_COMPLETE 0U
|
||||
#define DFU_MANIFEST_IN_PROGRESS 1U
|
||||
/* Define DFU application notification signals. */
|
||||
#define DFU_NOTIFICATION_BEGIN_DOWNLOAD 0x1u
|
||||
#define DFU_NOTIFICATION_END_DOWNLOAD 0x2u
|
||||
#define DFU_NOTIFICATION_ABORT_DOWNLOAD 0x3u
|
||||
#define DFU_NOTIFICATION_BEGIN_UPLOAD 0x5u
|
||||
#define DFU_NOTIFICATION_END_UPLOAD 0x6u
|
||||
#define DFU_NOTIFICATION_ABORT_UPLOAD 0x7u
|
||||
|
||||
/** Special Commands with Download Request */
|
||||
#define DFU_CMD_GETCOMMANDS 0U
|
||||
#define DFU_CMD_SETADDRESSPOINTER 0x21U
|
||||
#define DFU_CMD_ERASE 0x41U
|
||||
#define DFU_MEDIA_ERASE 0x00U
|
||||
#define DFU_MEDIA_PROGRAM 0x01U
|
||||
/* Define DFU application notification signals. */
|
||||
#define DFU_MEDIA_STATUS_OK 0
|
||||
#define DFU_MEDIA_STATUS_BUSY 1
|
||||
#define DFU_MEDIA_STATUS_ERROR 2
|
||||
|
||||
/** Other defines */
|
||||
/* Bit Detach capable = bit 3 in bmAttributes field */
|
||||
#define DFU_DETACH_MASK (1U << 3)
|
||||
#define DFU_MANIFEST_MASK (1U << 2)
|
||||
/** Special Commands with Download Request for STM32, wValue = 0 */
|
||||
#define DFU_SPECIAL_CMD_SET_ADDRESS_POINTER 0x21U
|
||||
#define DFU_SPECIAL_CMD_ERASE 0x41U
|
||||
#define DFU_SPECIAL_READ_UNPROTECT 0x92U
|
||||
|
||||
/** Run-Time Functional Descriptor */
|
||||
struct dfu_runtime_descriptor {
|
||||
@@ -103,35 +105,36 @@ struct dfu_runtime_descriptor {
|
||||
} __PACKED;
|
||||
|
||||
/**\brief Payload packet to response in DFU_GETSTATUS request */
|
||||
struct dfu_info {
|
||||
uint8_t bStatus; /**<\brief An indication of the status resulting from the
|
||||
struct dfu_status {
|
||||
uint8_t bStatus; /**<\brief An indication of the status resulting from the
|
||||
* execution of the most recent request.*/
|
||||
uint8_t bPollTimeout; /**<\brief Minimum time (LSB) in ms, that the host should wait
|
||||
uint32_t bwPollTimeout; /**<\brief Minimum time in ms, that the host should wait
|
||||
* before sending a subsequent DFU_GETSTATUS request.*/
|
||||
uint16_t wPollTimeout; /**<\brief Minimum time (MSB) in ms, that the host should wait
|
||||
* before sending a subsequent DFU_GETSTATUS request.*/
|
||||
uint8_t bState; /**<\brief An indication of the state that the device is going
|
||||
uint8_t bState; /**<\brief An indication of the state that the device is going
|
||||
* to enter immediately following transmission of this response.*/
|
||||
uint8_t iString; /**<\brief Index of the status string descriptor.*/
|
||||
uint8_t iString; /**<\brief Index of the status string descriptor.*/
|
||||
};
|
||||
|
||||
#define DFU_DESCRIPTOR_LEN 18
|
||||
|
||||
// clang-format off
|
||||
#define DFU_DESCRIPTOR_INIT() \
|
||||
#define DFU_DESCRIPTOR_INIT(str_idx) \
|
||||
0x09, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||
0x00, /* bInterfaceNumber */ \
|
||||
0x00, /* bAlternateSetting */ \
|
||||
0x00, /* bNumEndpoints Default Control Pipe only */ \
|
||||
USB_DEVICE_CLASS_APP_SPECIFIC, /* bInterfaceClass */ \
|
||||
0x01, /* bInterfaceSubClass Device Firmware Upgrade */ \
|
||||
0x02, /* bInterfaceProtocol DFU mode */ \
|
||||
0x04, /* iInterface */ /*!< Device Firmware Update Functional Descriptor */ \
|
||||
DFU_SUBCLASS_DFU, /* bInterfaceSubClass Device Firmware Upgrade */ \
|
||||
DFU_PROTOCOL_DFU, /* bInterfaceProtocol DFU mode */ \
|
||||
str_idx, /* iInterface */ \
|
||||
/*!< Device Firmware Update Functional Descriptor */ \
|
||||
0x09, /* bLength */ \
|
||||
0x21, /* DFU Functional Descriptor */ \
|
||||
0x0B, /* bmAttributes */ \
|
||||
WBVAL(0x00ff), /* wDetachTimeOut */ \
|
||||
WBVAL(USBD_DFU_XFER_SIZE), /* wTransferSize */ \
|
||||
WBVAL(0x011a) /* bcdDFUVersion */
|
||||
WBVAL(CONFIG_USBDEV_REQUEST_BUFFER_LEN), /* wTransferSize */ \
|
||||
WBVAL(DFU_VERSION) /* bcdDFUVersion */
|
||||
// clang-format on
|
||||
|
||||
#endif /* USB_DFU_H */
|
||||
|
||||
@@ -1,431 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
* Copyright (c) 2022 ~ 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_dfu.h"
|
||||
|
||||
/** Modify the following three parameters according to different platforms */
|
||||
#ifndef USBD_DFU_XFER_SIZE
|
||||
#define USBD_DFU_XFER_SIZE 1024
|
||||
#endif
|
||||
|
||||
#ifndef USBD_DFU_APP_DEFAULT_ADD
|
||||
#define USBD_DFU_APP_DEFAULT_ADD 0x8004000
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_PROGRAM_TIME
|
||||
#define FLASH_PROGRAM_TIME 50
|
||||
#endif
|
||||
|
||||
#ifndef FLASH_ERASE_TIME
|
||||
#define FLASH_ERASE_TIME 50
|
||||
#endif
|
||||
|
||||
struct usbd_dfu_priv {
|
||||
struct dfu_info info;
|
||||
union {
|
||||
uint32_t d32[USBD_DFU_XFER_SIZE / 4U];
|
||||
uint8_t d8[USBD_DFU_XFER_SIZE];
|
||||
} buffer;
|
||||
|
||||
uint32_t wblock_num;
|
||||
uint32_t wlength;
|
||||
uint32_t data_ptr;
|
||||
uint32_t alt_setting;
|
||||
|
||||
uint8_t dev_status[6];
|
||||
uint8_t ReservedForAlign[2];
|
||||
uint8_t dev_state;
|
||||
uint8_t manif_state;
|
||||
uint8_t firmwar_flag;
|
||||
uint8_t dfu_state;
|
||||
} g_usbd_dfu;
|
||||
|
||||
static void dfu_reset(void)
|
||||
{
|
||||
memset(&g_usbd_dfu, 0, sizeof(g_usbd_dfu));
|
||||
|
||||
g_usbd_dfu.alt_setting = 0U;
|
||||
g_usbd_dfu.data_ptr = USBD_DFU_APP_DEFAULT_ADD;
|
||||
g_usbd_dfu.wblock_num = 0U;
|
||||
g_usbd_dfu.wlength = 0U;
|
||||
|
||||
g_usbd_dfu.manif_state = DFU_MANIFEST_COMPLETE;
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
|
||||
|
||||
g_usbd_dfu.dev_status[0] = DFU_STATUS_OK;
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = DFU_STATE_DFU_IDLE;
|
||||
g_usbd_dfu.dev_status[5] = 0U;
|
||||
}
|
||||
|
||||
static uint16_t dfu_getstatus(uint32_t add, uint8_t cmd, uint8_t *buffer)
|
||||
{
|
||||
switch (cmd) {
|
||||
case DFU_MEDIA_PROGRAM:
|
||||
buffer[1] = (uint8_t)FLASH_PROGRAM_TIME;
|
||||
buffer[2] = (uint8_t)(FLASH_PROGRAM_TIME << 8);
|
||||
buffer[3] = 0;
|
||||
break;
|
||||
|
||||
case DFU_MEDIA_ERASE:
|
||||
buffer[1] = (uint8_t)FLASH_ERASE_TIME;
|
||||
buffer[2] = (uint8_t)(FLASH_ERASE_TIME << 8);
|
||||
buffer[3] = 0;
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void dfu_request_detach(void)
|
||||
{
|
||||
if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_SYNC) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_MANIFEST_SYNC) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
|
||||
/* Update the state machine */
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
|
||||
g_usbd_dfu.dev_status[0] = DFU_STATUS_OK;
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U; /*bwPollTimeout=0ms*/
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
g_usbd_dfu.dev_status[5] = 0U; /*iString*/
|
||||
g_usbd_dfu.wblock_num = 0U;
|
||||
g_usbd_dfu.wlength = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
static void dfu_request_upload(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
struct usb_setup_packet *req = setup;
|
||||
uint32_t addr;
|
||||
/* Data setup request */
|
||||
if (req->wLength > 0U) {
|
||||
if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
|
||||
/* Update the global length and block number */
|
||||
g_usbd_dfu.wblock_num = req->wValue;
|
||||
g_usbd_dfu.wlength = MIN(req->wLength, USBD_DFU_XFER_SIZE);
|
||||
|
||||
/* DFU Get Command */
|
||||
if (g_usbd_dfu.wblock_num == 0U) {
|
||||
/* Update the state machine */
|
||||
g_usbd_dfu.dev_state = (g_usbd_dfu.wlength > 3U) ? DFU_STATE_DFU_IDLE : DFU_STATE_DFU_UPLOAD_IDLE;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
|
||||
/* Store the values of all supported commands */
|
||||
g_usbd_dfu.buffer.d8[0] = DFU_CMD_GETCOMMANDS;
|
||||
g_usbd_dfu.buffer.d8[1] = DFU_CMD_SETADDRESSPOINTER;
|
||||
g_usbd_dfu.buffer.d8[2] = DFU_CMD_ERASE;
|
||||
|
||||
/* Send the status data over EP0 */
|
||||
memcpy(*data, g_usbd_dfu.buffer.d8, 3);
|
||||
*len = 3;
|
||||
} else if (g_usbd_dfu.wblock_num > 1U) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_UPLOAD_IDLE;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
|
||||
addr = ((g_usbd_dfu.wblock_num - 2U) * USBD_DFU_XFER_SIZE) + g_usbd_dfu.data_ptr;
|
||||
|
||||
/* Return the physical address where data are stored */
|
||||
dfu_read_flash((uint8_t *)addr, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);
|
||||
|
||||
/* Send the status data over EP0 */
|
||||
memcpy(*data, g_usbd_dfu.buffer.d8, g_usbd_dfu.wlength);
|
||||
*len = g_usbd_dfu.wlength;
|
||||
} else /* unsupported g_usbd_dfu.wblock_num */
|
||||
{
|
||||
g_usbd_dfu.dev_state = DFU_STATUS_ERR_STALLEDPKT;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
|
||||
/* Call the error management function (command will be NAKed */
|
||||
USB_LOG_ERR("Dfu_request_upload unsupported g_usbd_dfu.wblock_num\r\n");
|
||||
}
|
||||
}
|
||||
/* Unsupported state */
|
||||
else {
|
||||
g_usbd_dfu.wlength = 0U;
|
||||
g_usbd_dfu.wblock_num = 0U;
|
||||
|
||||
/* Call the error management function (command will be NAKed */
|
||||
USB_LOG_ERR("Dfu_request_upload unsupported state\r\n");
|
||||
}
|
||||
}
|
||||
/* No Data setup request */
|
||||
else {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
}
|
||||
}
|
||||
|
||||
static void dfu_request_dnload(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
/* Data setup request */
|
||||
struct usb_setup_packet *req = setup;
|
||||
if (req->wLength > 0U) {
|
||||
if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE)) {
|
||||
/* Update the global length and block number */
|
||||
g_usbd_dfu.wblock_num = req->wValue;
|
||||
g_usbd_dfu.wlength = MIN(req->wLength, USBD_DFU_XFER_SIZE);
|
||||
|
||||
/* Update the state machine */
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_SYNC;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
|
||||
/*!< Data has received complete */
|
||||
memcpy((uint8_t *)g_usbd_dfu.buffer.d8, (uint8_t *)*data, g_usbd_dfu.wlength);
|
||||
/*!< Set flag = 1 Write the firmware to the flash in the next dfu_request_getstatus */
|
||||
g_usbd_dfu.firmwar_flag = 1;
|
||||
}
|
||||
/* Unsupported state */
|
||||
else {
|
||||
USB_LOG_ERR("Dfu_request_dnload unsupported state\r\n");
|
||||
}
|
||||
}
|
||||
/* 0 Data DNLOAD request */
|
||||
else {
|
||||
/* End of DNLOAD operation*/
|
||||
if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE) || (g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE)) {
|
||||
g_usbd_dfu.manif_state = DFU_MANIFEST_IN_PROGRESS;
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST_SYNC;
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
} else {
|
||||
/* Call the error management function (command will be NAKed */
|
||||
USB_LOG_ERR("Dfu_request_dnload End of DNLOAD operation but dev_state %02x \r\n", g_usbd_dfu.dev_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int8_t dfu_getstatus_special_handler(void)
|
||||
{
|
||||
uint32_t addr;
|
||||
if (g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_BUSY) {
|
||||
/* Decode the Special Command */
|
||||
if (g_usbd_dfu.wblock_num == 0U) {
|
||||
if (g_usbd_dfu.wlength == 1U) {
|
||||
if (g_usbd_dfu.buffer.d8[0] == DFU_CMD_GETCOMMANDS) {
|
||||
/* Nothing to do */
|
||||
}
|
||||
} else if (g_usbd_dfu.wlength == 5U) {
|
||||
if (g_usbd_dfu.buffer.d8[0] == DFU_CMD_SETADDRESSPOINTER) {
|
||||
g_usbd_dfu.data_ptr = g_usbd_dfu.buffer.d8[1];
|
||||
g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[2] << 8;
|
||||
g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[3] << 16;
|
||||
g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[4] << 24;
|
||||
} else if (g_usbd_dfu.buffer.d8[0] == DFU_CMD_ERASE) {
|
||||
g_usbd_dfu.data_ptr = g_usbd_dfu.buffer.d8[1];
|
||||
g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[2] << 8;
|
||||
g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[3] << 16;
|
||||
g_usbd_dfu.data_ptr += (uint32_t)g_usbd_dfu.buffer.d8[4] << 24;
|
||||
|
||||
USB_LOG_DBG("Erase start add %08x \r\n", g_usbd_dfu.data_ptr);
|
||||
/*!< Erase */
|
||||
dfu_erase_flash(g_usbd_dfu.data_ptr);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* Reset the global length and block number */
|
||||
g_usbd_dfu.wlength = 0U;
|
||||
g_usbd_dfu.wblock_num = 0U;
|
||||
/* Call the error management function (command will be NAKed) */
|
||||
USB_LOG_ERR("Reset the global length and block number\r\n");
|
||||
}
|
||||
}
|
||||
/* Regular Download Command */
|
||||
else {
|
||||
if (g_usbd_dfu.wblock_num > 1U) {
|
||||
/* Decode the required address */
|
||||
addr = ((g_usbd_dfu.wblock_num - 2U) * USBD_DFU_XFER_SIZE) + g_usbd_dfu.data_ptr;
|
||||
|
||||
/* Perform the write operation */
|
||||
/* Write flash */
|
||||
USB_LOG_DBG("Write start add %08x length %d\r\n", addr, g_usbd_dfu.wlength);
|
||||
dfu_write_flash(g_usbd_dfu.buffer.d8, (uint8_t *)addr, g_usbd_dfu.wlength);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the global length and block number */
|
||||
g_usbd_dfu.wlength = 0U;
|
||||
g_usbd_dfu.wblock_num = 0U;
|
||||
|
||||
/* Update the state machine */
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_SYNC;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dfu_request_getstatus(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
/*!< Determine whether to leave DFU mode */
|
||||
if (g_usbd_dfu.manif_state == DFU_MANIFEST_IN_PROGRESS &&
|
||||
g_usbd_dfu.dev_state == DFU_STATE_DFU_MANIFEST_SYNC &&
|
||||
g_usbd_dfu.dev_status[1] == 0U &&
|
||||
g_usbd_dfu.dev_status[2] == 0U &&
|
||||
g_usbd_dfu.dev_status[3] == 0U &&
|
||||
g_usbd_dfu.dev_status[4] == g_usbd_dfu.dev_state) {
|
||||
g_usbd_dfu.manif_state = DFU_MANIFEST_COMPLETE;
|
||||
|
||||
if ((0x0B & DFU_MANIFEST_MASK) != 0U) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST_SYNC;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
return;
|
||||
} else {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST_WAIT_RESET;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
/* Generate system reset to allow jumping to the user code */
|
||||
dfu_leave();
|
||||
}
|
||||
}
|
||||
|
||||
switch (g_usbd_dfu.dev_state) {
|
||||
case DFU_STATE_DFU_DNLOAD_SYNC:
|
||||
if (g_usbd_dfu.wlength != 0U) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_BUSY;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
|
||||
if ((g_usbd_dfu.wblock_num == 0U) && (g_usbd_dfu.buffer.d8[0] == DFU_CMD_ERASE)) {
|
||||
dfu_getstatus(g_usbd_dfu.data_ptr, DFU_MEDIA_ERASE, g_usbd_dfu.dev_status);
|
||||
} else {
|
||||
dfu_getstatus(g_usbd_dfu.data_ptr, DFU_MEDIA_PROGRAM, g_usbd_dfu.dev_status);
|
||||
}
|
||||
} else /* (g_usbd_dfu.wlength==0)*/
|
||||
{
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_DNLOAD_IDLE;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
}
|
||||
break;
|
||||
|
||||
case DFU_STATE_DFU_MANIFEST_SYNC:
|
||||
if (g_usbd_dfu.manif_state == DFU_MANIFEST_IN_PROGRESS) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_MANIFEST;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 1U; /*bwPollTimeout = 1ms*/
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
} else {
|
||||
if ((g_usbd_dfu.manif_state == DFU_MANIFEST_COMPLETE) &&
|
||||
((0x0B & DFU_MANIFEST_MASK) != 0U)) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
|
||||
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U;
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send the status data over EP0 */
|
||||
memcpy(*data, g_usbd_dfu.dev_status, 6);
|
||||
*len = 6;
|
||||
|
||||
if (g_usbd_dfu.firmwar_flag == 1) {
|
||||
if (dfu_getstatus_special_handler() != 0) {
|
||||
USB_LOG_ERR("dfu_getstatus_special_handler error \r\n");
|
||||
}
|
||||
g_usbd_dfu.firmwar_flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void dfu_request_clrstatus(void)
|
||||
{
|
||||
if (g_usbd_dfu.dev_state == DFU_STATE_DFU_ERROR) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
|
||||
g_usbd_dfu.dev_status[0] = DFU_STATUS_OK; /* bStatus */
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U; /* bwPollTimeout=0ms */
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state; /* bState */
|
||||
g_usbd_dfu.dev_status[5] = 0U; /* iString */
|
||||
} else {
|
||||
/* State Error */
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_ERROR;
|
||||
g_usbd_dfu.dev_status[0] = DFU_STATUS_ERR_UNKNOWN; /* bStatus */
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U; /* bwPollTimeout=0ms */
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state; /* bState */
|
||||
g_usbd_dfu.dev_status[5] = 0U; /* iString */
|
||||
}
|
||||
}
|
||||
|
||||
static void dfu_request_getstate(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
/* Return the current state of the DFU interface */
|
||||
(*data)[0] = g_usbd_dfu.dev_state;
|
||||
*len = 1;
|
||||
}
|
||||
|
||||
void dfu_request_abort(void)
|
||||
{
|
||||
if ((g_usbd_dfu.dev_state == DFU_STATE_DFU_IDLE) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_SYNC) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_DNLOAD_IDLE) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_MANIFEST_SYNC) ||
|
||||
(g_usbd_dfu.dev_state == DFU_STATE_DFU_UPLOAD_IDLE)) {
|
||||
g_usbd_dfu.dev_state = DFU_STATE_DFU_IDLE;
|
||||
g_usbd_dfu.dev_status[0] = DFU_STATUS_OK;
|
||||
g_usbd_dfu.dev_status[1] = 0U;
|
||||
g_usbd_dfu.dev_status[2] = 0U;
|
||||
g_usbd_dfu.dev_status[3] = 0U; /* bwPollTimeout=0ms */
|
||||
g_usbd_dfu.dev_status[4] = g_usbd_dfu.dev_state;
|
||||
g_usbd_dfu.dev_status[5] = 0U; /* iString */
|
||||
g_usbd_dfu.wblock_num = 0U;
|
||||
g_usbd_dfu.wlength = 0U;
|
||||
}
|
||||
}
|
||||
const char *usbd_dfu_state_string[] = {
|
||||
"APP_IDLE",
|
||||
"APP_DETACH",
|
||||
"DFU_IDLE",
|
||||
"DFU_DNLOAD_SYNC",
|
||||
"DFU_DNLOAD_BUSY",
|
||||
"DFU_DNLOAD_IDLE",
|
||||
"DFU_MANIFEST_SYNC",
|
||||
"DFU_MANIFEST",
|
||||
"DFU_MANIFEST_WAIT_RESET",
|
||||
"DFU_UPLOAD_IDLE",
|
||||
"DFU_ERROR"
|
||||
};
|
||||
|
||||
static int dfu_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
@@ -433,33 +30,260 @@ static int dfu_class_interface_request_handler(uint8_t busid, struct usb_setup_p
|
||||
"bRequest 0x%02x\r\n",
|
||||
setup->bRequest);
|
||||
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_DETACH:
|
||||
dfu_request_detach();
|
||||
USB_LOG_DBG("dfu state:%s\r\n", usbd_dfu_state_string[g_usbd_dfu.dfu_state]);
|
||||
|
||||
switch (g_usbd_dfu.dfu_state) {
|
||||
case DFU_STATE_APP_IDLE:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_DETACH:
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_REQUEST_DNLOAD:
|
||||
dfu_request_dnload(setup, data, len);
|
||||
case DFU_STATE_APP_DETACH:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_REQUEST_UPLOAD:
|
||||
dfu_request_upload(setup, data, len);
|
||||
case DFU_STATE_DFU_IDLE:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_DNLOAD:
|
||||
/* We received a DOWNLOAD command. Check the length field of the request. If it is 0,
|
||||
we are done with the transfer. */
|
||||
if (setup->wLength == 0) {
|
||||
usbd_dfu_end_load();
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_MANIFEST_SYNC;
|
||||
} else {
|
||||
usbd_dfu_begin_load();
|
||||
if (usbd_dfu_write(setup->wValue, *data, setup->wLength) < 0) {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_ERROR;
|
||||
return -1;
|
||||
} else {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_DNLOAD_SYNC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DFU_REQUEST_UPLOAD:
|
||||
usbd_dfu_begin_load();
|
||||
|
||||
uint16_t actual_length;
|
||||
if (usbd_dfu_read(setup->wValue, *data, setup->wLength, &actual_length) < 0) {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_ERROR;
|
||||
return -1;
|
||||
} else {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_UPLOAD_IDLE;
|
||||
}
|
||||
break;
|
||||
case DFU_REQUEST_ABORT:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_IDLE;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
dfu_request_getstatus(setup, data, len);
|
||||
case DFU_STATE_DFU_DNLOAD_SYNC:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_DNLOAD_BUSY;
|
||||
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_REQUEST_CLRSTATUS:
|
||||
dfu_request_clrstatus();
|
||||
case DFU_STATE_DFU_DNLOAD_BUSY:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_DNLOAD_IDLE;
|
||||
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
dfu_request_getstate(setup, data, len);
|
||||
case DFU_STATE_DFU_DNLOAD_IDLE:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_DNLOAD:
|
||||
/* We received a DOWNLOAD command. Check the length field of the request. If it is 0,
|
||||
we are done with the transfer. */
|
||||
if (setup->wLength == 0) {
|
||||
usbd_dfu_end_load();
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_MANIFEST_SYNC;
|
||||
} else {
|
||||
if (usbd_dfu_write(setup->wValue, *data, setup->wLength) < 0) {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_ERROR;
|
||||
return -1;
|
||||
} else {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_DNLOAD_SYNC;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case DFU_REQUEST_ABORT:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_IDLE;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_REQUEST_ABORT:
|
||||
dfu_request_abort();
|
||||
case DFU_STATE_DFU_UPLOAD_IDLE:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_UPLOAD: {
|
||||
uint16_t actual_length;
|
||||
if (usbd_dfu_read(setup->wValue, *data, setup->wLength, &actual_length) < 0) {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_ERROR;
|
||||
return -1;
|
||||
} else {
|
||||
if (actual_length < setup->wLength) {
|
||||
usbd_dfu_end_load();
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_IDLE;
|
||||
} else {
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_UPLOAD_IDLE;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case DFU_REQUEST_ABORT:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_IDLE;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_STATE_DFU_MANIFEST_SYNC:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_MANIFEST_WAIT_RESET;
|
||||
|
||||
(*data)[0] = DFU_STATUS_OK; /* bStatus */
|
||||
(*data)[1] = 0;
|
||||
(*data)[2] = 0;
|
||||
(*data)[3] = 0;
|
||||
(*data)[4] = g_usbd_dfu.dfu_state;
|
||||
(*data)[5] = 0; /* iString */
|
||||
*len = 6;
|
||||
|
||||
usbd_dfu_reset();
|
||||
break;
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
(*data)[0] = g_usbd_dfu.dfu_state;
|
||||
*len = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DFU_STATE_DFU_ERROR:
|
||||
switch (setup->bRequest) {
|
||||
case DFU_REQUEST_CLRSTATUS:
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled DFU Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
USB_LOG_WRN("Invalid dfu state %s\r\n", usbd_dfu_state_string[g_usbd_dfu.dfu_state]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -467,7 +291,7 @@ static void dfu_notify_handler(uint8_t busid, uint8_t event, void *arg)
|
||||
{
|
||||
switch (event) {
|
||||
case USBD_EVENT_RESET:
|
||||
dfu_reset();
|
||||
g_usbd_dfu.dfu_state = DFU_STATE_DFU_IDLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -484,21 +308,29 @@ struct usbd_interface *usbd_dfu_init_intf(struct usbd_interface *intf)
|
||||
return intf;
|
||||
}
|
||||
|
||||
__WEAK uint8_t *dfu_read_flash(uint8_t *src, uint8_t *dest, uint32_t len)
|
||||
uint8_t usbd_dfu_get_state(void)
|
||||
{
|
||||
return dest;
|
||||
return g_usbd_dfu.dfu_state;
|
||||
}
|
||||
|
||||
__WEAK uint16_t dfu_write_flash(uint8_t *src, uint8_t *dest, uint32_t len)
|
||||
__WEAK void usbd_dfu_begin_load(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void usbd_dfu_end_load(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void usbd_dfu_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK int usbd_dfu_write(uint16_t value, const uint8_t *data, uint16_t length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__WEAK uint16_t dfu_erase_flash(uint32_t add)
|
||||
__WEAK int usbd_dfu_read(uint16_t value, const uint8_t *data, uint16_t length, uint16_t *actual_length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
__WEAK void dfu_leave(void)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
* Copyright (c) 2022 ~ 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -14,12 +14,14 @@ extern "C" {
|
||||
|
||||
/* Init dfu interface driver */
|
||||
struct usbd_interface *usbd_dfu_init_intf(struct usbd_interface *intf);
|
||||
uint8_t usbd_dfu_get_state(void);
|
||||
|
||||
void usbd_dfu_begin_load(void);
|
||||
void usbd_dfu_end_load(void);
|
||||
void usbd_dfu_reset(void);
|
||||
int usbd_dfu_write(uint16_t value, const uint8_t *data, uint16_t length);
|
||||
int usbd_dfu_read(uint16_t value, const uint8_t *data, uint16_t length, uint16_t *actual_length);
|
||||
|
||||
/* Interface functions that need to be implemented by the user */
|
||||
uint8_t *dfu_read_flash(uint8_t *src, uint8_t *dest, uint32_t len);
|
||||
uint16_t dfu_write_flash(uint8_t *src, uint8_t *dest, uint32_t len);
|
||||
uint16_t dfu_erase_flash(uint32_t add);
|
||||
void dfu_leave(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
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 */
|
||||
@@ -634,7 +617,7 @@ struct usb_hid_js_report {
|
||||
|
||||
#define HID_CUSTOM_INOUT_DESCRIPTOR_LEN (9 + 9 + 7 + 7)
|
||||
|
||||
#define HID_CUSTOM_INOUT_DESCRIPTOR_INIT(bInterfaceNumber, bInterfaceSubClass, wItemLength, in_ep, out_ep,wMaxPacketSize, bInterval) \
|
||||
#define HID_CUSTOM_INOUT_DESCRIPTOR_INIT(bInterfaceNumber, bInterfaceSubClass, wItemLength, out_ep, in_ep, wMaxPacketSize, bInterval) \
|
||||
0x09, /* bLength: Interface Descriptor size */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */ \
|
||||
bInterfaceNumber, /* bInterfaceNumber: Number of Interface */ \
|
||||
@@ -654,13 +637,13 @@ struct usb_hid_js_report {
|
||||
WBVAL(wItemLength), /* wItemLength: Total length of Report descriptor */ \
|
||||
0x07, /* bLength: Endpoint Descriptor size */ \
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ \
|
||||
in_ep, /* bEndpointAddress: Endpoint Address (IN) */ \
|
||||
out_ep, /* bEndpointAddress: Endpoint Address (OUT) */ \
|
||||
0x03, /* bmAttributes: Interrupt endpoint */ \
|
||||
WBVAL(wMaxPacketSize), /* wMaxPacketSize: x Byte max */ \
|
||||
bInterval, /* bInterval: Polling Interval */ \
|
||||
0x07, /* bLength: Endpoint Descriptor size */ \
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */ \
|
||||
out_ep, /* bEndpointAddress: Endpoint Address (IN) */ \
|
||||
in_ep, /* bEndpointAddress: Endpoint Address (IN) */ \
|
||||
0x03, /* bmAttributes: Interrupt endpoint */ \
|
||||
WBVAL(wMaxPacketSize), /* wMaxPacketSize: x Byte max */ \
|
||||
bInterval /* bInterval: Polling Interval */
|
||||
|
||||
@@ -41,7 +41,6 @@ static int hid_class_interface_request_handler(uint8_t busid, struct usb_setup_p
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled HID Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,12 +682,15 @@ static void usbh_hub_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
|
||||
struct usbh_bus *bus = (struct usbh_bus *)CONFIG_USB_OSAL_THREAD_GET_ARGV;
|
||||
|
||||
usb_hc_init(bus);
|
||||
bus->event_handler(bus->busid, USB_HUB_INDEX_ANY, USB_HUB_PORT_ANY, USB_INTERFACE_ANY, USBH_EVENT_INIT);
|
||||
while (1) {
|
||||
ret = usb_osal_mq_recv(bus->hub_mq, (uintptr_t *)&hub, USB_OSAL_WAITING_FOREVER);
|
||||
if (ret < 0) {
|
||||
continue;
|
||||
}
|
||||
usb_osal_mutex_take(bus->mutex);
|
||||
usbh_hub_events(hub);
|
||||
usb_osal_mutex_give(bus->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,6 +720,12 @@ int usbh_hub_initialize(struct usbh_bus *bus)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bus->mutex = usb_osal_mutex_create();
|
||||
if (bus->mutex == NULL) {
|
||||
USB_LOG_ERR("Failed to create bus mutex\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(thread_name, 32, "usbh_hub%u", bus->busid);
|
||||
bus->hub_thread = usb_osal_thread_create(thread_name, CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO, usbh_hub_thread, bus);
|
||||
if (bus->hub_thread == NULL) {
|
||||
@@ -714,6 +740,7 @@ int usbh_hub_deinitialize(struct usbh_bus *bus)
|
||||
struct usbh_hubport *hport;
|
||||
struct usbh_hub *hub;
|
||||
|
||||
usb_osal_mutex_take(bus->mutex);
|
||||
hub = &bus->hcd.roothub;
|
||||
for (uint8_t port = 0; port < hub->nports; port++) {
|
||||
hport = &hub->child[port];
|
||||
@@ -726,6 +753,8 @@ int usbh_hub_deinitialize(struct usbh_bus *bus)
|
||||
usb_osal_thread_delete(bus->hub_thread);
|
||||
usb_osal_mq_delete(bus->hub_mq);
|
||||
|
||||
usb_osal_mutex_give(bus->mutex);
|
||||
usb_osal_mutex_delete(bus->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#ifndef USB_MIDI_H
|
||||
#define USB_MIDI_H
|
||||
|
||||
#include "usb_audio.h"
|
||||
|
||||
/* bDescriptorSubType */
|
||||
#define MIDI_VC_HEADER_DESCRIPTOR_SUBTYPE 0x01U
|
||||
#define MIDI_MS_HEADER_DESCRIPTOR_SUBTYPE 0x01U
|
||||
@@ -201,6 +203,19 @@ struct midi_cs_ep_ms_general_descriptor {
|
||||
#define MIDI_SIZEOF_MS_GENERAL_DESC(n) (4 + n)
|
||||
|
||||
// clang-format off
|
||||
#define MIDI_STANDARD_DESCRIPTOR_INIT(bInterfaceNumber, bNumEndpoints) \
|
||||
0x09, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||
bInterfaceNumber, /* bInterfaceNumber */ \
|
||||
0x00, /* bAlternateSetting */ \
|
||||
bNumEndpoints, /* bNumEndpoints */ \
|
||||
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ \
|
||||
AUDIO_SUBCLASS_MIDISTREAMING, /* bInterfaceSubClass */ \
|
||||
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ \
|
||||
0x00 /* iInterface */
|
||||
|
||||
#define MIDI_STANDARD_DESCRIPTOR_LEN 0x09
|
||||
|
||||
#define MIDI_CS_HEADER_DESCRIPTOR_INIT(wTotalLength) \
|
||||
0x07, /* bLength */ \
|
||||
USB_CS_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||
|
||||
@@ -89,7 +89,6 @@ static int msc_storage_class_interface_request_handler(uint8_t busid, struct usb
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled MSC Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
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_ch34x"
|
||||
#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 */
|
||||
184
class/vendor/display/usbd_display.c
vendored
Normal file
184
class/vendor/display/usbd_display.c
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_display.h"
|
||||
#include "chry_mempool.h"
|
||||
|
||||
struct usbd_disp_frame_header {
|
||||
uint16_t crc16; //payload crc16
|
||||
uint8_t type; //raw rgb,yuv,jpg,other
|
||||
uint8_t cmd;
|
||||
uint16_t x; //32bit
|
||||
uint16_t y;
|
||||
uint16_t width; //32bit
|
||||
uint16_t height;
|
||||
uint32_t frame_id : 10;
|
||||
uint32_t payload_total : 22; //payload max 4MB
|
||||
} __PACKED;
|
||||
|
||||
struct usbd_display_priv {
|
||||
struct chry_mempool pool;
|
||||
struct usbd_endpoint out_ep;
|
||||
struct usbd_endpoint in_ep;
|
||||
struct usbd_display_frame *current_frame;
|
||||
} g_usbd_display;
|
||||
|
||||
int usbd_display_frame_create(struct usbd_display_frame *frame, uint32_t count)
|
||||
{
|
||||
return chry_mempool_create(&g_usbd_display.pool, frame, sizeof(struct usbd_display_frame), count);
|
||||
}
|
||||
|
||||
struct usbd_display_frame *usbd_display_frame_alloc(void)
|
||||
{
|
||||
return (struct usbd_display_frame *)chry_mempool_alloc(&g_usbd_display.pool);
|
||||
}
|
||||
|
||||
int usbd_display_frame_free(struct usbd_display_frame *frame)
|
||||
{
|
||||
return chry_mempool_free(&g_usbd_display.pool, (uintptr_t *)frame);
|
||||
}
|
||||
|
||||
int usbd_display_frame_send(struct usbd_display_frame *frame)
|
||||
{
|
||||
return chry_mempool_send(&g_usbd_display.pool, (uintptr_t *)frame);
|
||||
}
|
||||
|
||||
int usbd_display_frame_recv(struct usbd_display_frame **frame, uint32_t timeout)
|
||||
{
|
||||
return chry_mempool_recv(&g_usbd_display.pool, (uintptr_t **)frame, timeout);
|
||||
}
|
||||
|
||||
uint8_t usb_dispay_dummy[512];
|
||||
volatile uint32_t usb_display_buf_offset;
|
||||
volatile bool usb_display_ignore_frame;
|
||||
|
||||
static void display_notify_handler(uint8_t busid, uint8_t event, void *arg)
|
||||
{
|
||||
switch (event) {
|
||||
case USBD_EVENT_RESET:
|
||||
break;
|
||||
case USBD_EVENT_CONFIGURED:
|
||||
usb_display_buf_offset = 0;
|
||||
usb_display_ignore_frame = true;
|
||||
g_usbd_display.current_frame = NULL;
|
||||
usbd_ep_start_read(busid, g_usbd_display.out_ep.ep_addr, usb_dispay_dummy, usbd_get_ep_mps(0, g_usbd_display.out_ep.ep_addr));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void usbd_display_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
if (usb_display_ignore_frame) {
|
||||
// alloc frame for next at the end of current frame
|
||||
if ((nbytes % usbd_get_ep_mps(0, g_usbd_display.out_ep.ep_addr)) || (nbytes == 0)) {
|
||||
if (g_usbd_display.current_frame == NULL) {
|
||||
g_usbd_display.current_frame = usbd_display_frame_alloc();
|
||||
if (g_usbd_display.current_frame) {
|
||||
usb_display_ignore_frame = false;
|
||||
usb_display_buf_offset = 0;
|
||||
|
||||
goto get_frame;
|
||||
} else {
|
||||
goto drop_frame;
|
||||
}
|
||||
} else {
|
||||
usb_display_ignore_frame = false;
|
||||
usb_display_buf_offset = 0;
|
||||
|
||||
goto get_frame;
|
||||
}
|
||||
} else {
|
||||
goto drop_frame;
|
||||
}
|
||||
} else {
|
||||
struct usbd_disp_frame_header *header = (struct usbd_disp_frame_header *)&g_usbd_display.current_frame->frame_buf[0];
|
||||
struct usbd_display_frame *frame;
|
||||
|
||||
if (header->payload_total > g_usbd_display.current_frame->frame_bufsize) {
|
||||
USB_LOG_ERR("frame overflow, drop it\r\n");
|
||||
usb_display_ignore_frame = true;
|
||||
|
||||
goto drop_frame;
|
||||
}
|
||||
|
||||
usb_display_buf_offset += nbytes;
|
||||
|
||||
if ((nbytes % usbd_get_ep_mps(0, g_usbd_display.out_ep.ep_addr)) || (nbytes == 0)) {
|
||||
frame = g_usbd_display.current_frame;
|
||||
g_usbd_display.current_frame = NULL;
|
||||
|
||||
frame->frame_format = header->type;
|
||||
frame->frame_size = header->payload_total;
|
||||
usbd_display_frame_send(frame);
|
||||
|
||||
g_usbd_display.current_frame = usbd_display_frame_alloc();
|
||||
if (g_usbd_display.current_frame) {
|
||||
usb_display_ignore_frame = false;
|
||||
usb_display_buf_offset = 0;
|
||||
|
||||
goto get_frame;
|
||||
} else {
|
||||
usb_display_ignore_frame = true;
|
||||
|
||||
goto drop_frame;
|
||||
}
|
||||
} else {
|
||||
goto get_frame;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
drop_frame:
|
||||
// drop current frame
|
||||
usbd_ep_start_read(busid, g_usbd_display.out_ep.ep_addr, usb_dispay_dummy, usbd_get_ep_mps(0, g_usbd_display.out_ep.ep_addr));
|
||||
return;
|
||||
get_frame:
|
||||
usbd_ep_start_read(busid, g_usbd_display.out_ep.ep_addr, &g_usbd_display.current_frame->frame_buf[usb_display_buf_offset], 16384);
|
||||
return;
|
||||
}
|
||||
|
||||
void usbd_display_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
}
|
||||
|
||||
struct usbd_interface *usbd_display_init_intf(struct usbd_interface *intf,
|
||||
const uint8_t out_ep,
|
||||
const uint8_t in_ep,
|
||||
struct usbd_display_frame *frame,
|
||||
uint32_t count)
|
||||
{
|
||||
intf->class_interface_handler = NULL;
|
||||
intf->class_endpoint_handler = NULL;
|
||||
intf->vendor_handler = NULL;
|
||||
intf->notify_handler = display_notify_handler;
|
||||
|
||||
g_usbd_display.out_ep.ep_addr = out_ep;
|
||||
g_usbd_display.out_ep.ep_cb = usbd_display_bulk_out;
|
||||
g_usbd_display.in_ep.ep_addr = in_ep;
|
||||
g_usbd_display.in_ep.ep_cb = usbd_display_bulk_in;
|
||||
usbd_add_endpoint(0, &g_usbd_display.out_ep);
|
||||
usbd_add_endpoint(0, &g_usbd_display.in_ep);
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
USB_ASSERT_MSG(frame[i].frame_bufsize % 16384, "frame_bufsize must be the multiple of 16384");
|
||||
}
|
||||
|
||||
usbd_display_frame_create(frame, count);
|
||||
return intf;
|
||||
}
|
||||
|
||||
int usbd_display_dequeue(struct usbd_display_frame **frame, uint32_t timeout)
|
||||
{
|
||||
return usbd_display_frame_recv(frame, timeout);
|
||||
}
|
||||
|
||||
int usbd_display_enqueue(struct usbd_display_frame *frame)
|
||||
{
|
||||
return usbd_display_frame_free(frame);
|
||||
}
|
||||
39
class/vendor/display/usbd_display.h
vendored
Normal file
39
class/vendor/display/usbd_display.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBD_DISPLAY_H
|
||||
#define USBD_DISPLAY_H
|
||||
|
||||
#define USBD_DISPLAY_TYPE_RGB565 0
|
||||
#define USBD_DISPLAY_TYPE_RGB888 1
|
||||
#define USBD_DISPLAY_TYPE_YUV420 2
|
||||
#define USBD_DISPLAY_TYPE_JPG 3
|
||||
|
||||
struct usbd_display_frame {
|
||||
uint8_t *frame_buf;
|
||||
uint32_t frame_bufsize;
|
||||
uint32_t frame_format;
|
||||
uint32_t frame_size;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Init display interface driver */
|
||||
struct usbd_interface *usbd_display_init_intf(struct usbd_interface *intf,
|
||||
const uint8_t out_ep,
|
||||
const uint8_t in_ep,
|
||||
struct usbd_display_frame *frame,
|
||||
uint32_t count);
|
||||
|
||||
int usbd_display_dequeue(struct usbd_display_frame **frame, uint32_t timeout);
|
||||
int usbd_display_enqueue(struct usbd_display_frame *frame);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBD_DISPLAY_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 */
|
||||
0
class/vendor/wifi/.gitkeep
vendored
Normal file
0
class/vendor/wifi/.gitkeep
vendored
Normal file
6
class/vendor/wifi/README.md
vendored
6
class/vendor/wifi/README.md
vendored
@@ -1,6 +0,0 @@
|
||||
# BL616 USB WIFI
|
||||
|
||||
Usbwifi firmware please contact bouffalolab. You can purchase a module in the following ways:
|
||||
|
||||
- https://iot.mi.com/moduleBrowser.html
|
||||
- https://docs.ai-thinker.com/ai_m61
|
||||
513
class/vendor/wifi/usbh_bl616.c
vendored
513
class/vendor/wifi/usbh_bl616.c
vendored
@@ -1,513 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_bl616.h"
|
||||
|
||||
#undef USB_DBG_TAG
|
||||
#define USB_DBG_TAG "usbh_bl616"
|
||||
#include "usb_log.h"
|
||||
|
||||
#define DEV_FORMAT "/dev/wifi/bl616"
|
||||
|
||||
#define MAC_FMT "%02X:%02X:%02X:%02X:%02X:%02X"
|
||||
#define ARR_ELE_6(e) (e)[0], (e)[1], (e)[2], (e)[3], (e)[4], (e)[5]
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bl616_tx_buffer[2048 + 512];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bl616_rx_buffer[2048 + 512];
|
||||
|
||||
static struct usbh_bl616 g_bl616_class;
|
||||
|
||||
static const char *auth_to_str(uint8_t auth)
|
||||
{
|
||||
const char *table[RNM_WIFI_AUTH_MAX] = {
|
||||
[RNM_WIFI_AUTH_UNKNOWN] = "UNKNOWN",
|
||||
[RNM_WIFI_AUTH_OPEN] = "OPEN",
|
||||
[RNM_WIFI_AUTH_WEP] = "WEP",
|
||||
[RNM_WIFI_AUTH_WPA_PSK] = "WPA-PSK",
|
||||
[RNM_WIFI_AUTH_WPA2_PSK] = "WPA2-PSK",
|
||||
[RNM_WIFI_AUTH_WPA_WPA2_PSK] = "WPA2-PSK/WPA-PSK",
|
||||
[RNM_WIFI_AUTH_WPA_ENTERPRISE] = "WPA-ENT",
|
||||
[RNM_WIFI_AUTH_WPA3_SAE] = "WPA3-SAE",
|
||||
[RNM_WIFI_AUTH_WPA2_PSK_WPA3_SAE] = "WPA2-PSK/WPA3-SAE",
|
||||
};
|
||||
if (auth < RNM_WIFI_AUTH_MAX)
|
||||
return table[auth];
|
||||
else
|
||||
return table[RNM_WIFI_AUTH_UNKNOWN];
|
||||
}
|
||||
|
||||
static const char *cipher_to_str(uint8_t cipher)
|
||||
{
|
||||
const char *table[RNM_WIFI_CIPHER_MAX] = {
|
||||
[RNM_WIFI_CIPHER_UNKNOWN] = "UNKNOWN",
|
||||
[RNM_WIFI_CIPHER_NONE] = "NONE",
|
||||
[RNM_WIFI_CIPHER_WEP] = "WEP",
|
||||
[RNM_WIFI_CIPHER_AES] = "AES",
|
||||
[RNM_WIFI_CIPHER_TKIP] = "TKIP",
|
||||
[RNM_WIFI_CIPHER_TKIP_AES] = "TKIP/AES",
|
||||
};
|
||||
if (cipher < RNM_WIFI_CIPHER_MAX)
|
||||
return table[cipher];
|
||||
else
|
||||
return table[RNM_WIFI_CIPHER_UNKNOWN];
|
||||
}
|
||||
|
||||
static int parse_get_mac_rsp_msg(struct usbh_bl616 *bl616_class, void *buf, int buf_len)
|
||||
{
|
||||
usb_data_t *usb_hdr = buf;
|
||||
rnm_mac_addr_ind_msg_t *rsp = buf + sizeof(usb_data_t);
|
||||
|
||||
if (buf_len != sizeof(usb_data_t) + sizeof(rnm_mac_addr_ind_msg_t)) {
|
||||
return -1;
|
||||
}
|
||||
if (usb_hdr->type != USBWIFI_DATA_TYPE_CMD || usb_hdr->length != sizeof(rnm_mac_addr_ind_msg_t)) {
|
||||
return -1;
|
||||
}
|
||||
if (rsp->hdr.cmd != BFLB_CMD_GET_MAC_ADDR || !(rsp->hdr.flags & RNM_MSG_FLAG_ACK)) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(bl616_class->sta_mac, rsp->sta_mac, 6);
|
||||
memcpy(bl616_class->ap_mac, rsp->ap_mac, 6);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbh_bl616_bulk_in_transfer(struct usbh_bl616 *bl616_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &bl616_class->bulkin_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, bl616_class->hport, bl616_class->bulkin, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_bl616_bulk_out_transfer(struct usbh_bl616 *bl616_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &bl616_class->bulkout_urb;
|
||||
|
||||
usbh_bulk_urb_fill(urb, bl616_class->hport, bl616_class->bulkout, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_bl616_get_wifi_mac(struct usbh_bl616 *bl616_class)
|
||||
{
|
||||
int ret;
|
||||
uint32_t msg_len;
|
||||
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
|
||||
rnm_base_msg_t *rnm_msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
|
||||
|
||||
memset(usb_hdr, 0, sizeof(usb_data_t));
|
||||
memset(rnm_msg, 0, sizeof(rnm_base_msg_t));
|
||||
|
||||
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
|
||||
usb_hdr->length = sizeof(rnm_base_msg_t);
|
||||
usb_hdr->payload_offset = sizeof(usb_data_t);
|
||||
|
||||
rnm_msg->cmd = BFLB_CMD_GET_MAC_ADDR;
|
||||
|
||||
msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t);
|
||||
|
||||
ret = usbh_bl616_bulk_out_transfer(bl616_class, g_bl616_tx_buffer, msg_len, 500);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = usbh_bl616_bulk_in_transfer(bl616_class, g_bl616_rx_buffer, sizeof(g_bl616_rx_buffer), 500);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = parse_get_mac_rsp_msg(bl616_class, g_bl616_rx_buffer, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_bl616_wifi_open(struct usbh_bl616 *bl616_class)
|
||||
{
|
||||
uint32_t msg_len;
|
||||
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
|
||||
rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
|
||||
|
||||
memset(usb_hdr, 0, sizeof(usb_data_t));
|
||||
memset(msg, 0, sizeof(rnm_base_msg_t));
|
||||
|
||||
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
|
||||
usb_hdr->length = sizeof(rnm_base_msg_t);
|
||||
usb_hdr->payload_offset = sizeof(usb_data_t);
|
||||
|
||||
msg->cmd = BFLB_CMD_HELLO;
|
||||
|
||||
msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t);
|
||||
|
||||
return usbh_bl616_bulk_out_transfer(bl616_class, g_bl616_tx_buffer, msg_len, 500);
|
||||
}
|
||||
|
||||
static int usbh_bl616_wifi_close(struct usbh_bl616 *bl616_class)
|
||||
{
|
||||
uint32_t msg_len;
|
||||
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
|
||||
rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
|
||||
|
||||
memset(usb_hdr, 0, sizeof(usb_data_t));
|
||||
memset(msg, 0, sizeof(rnm_base_msg_t));
|
||||
|
||||
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
|
||||
usb_hdr->length = sizeof(rnm_base_msg_t);
|
||||
usb_hdr->payload_offset = sizeof(usb_data_t);
|
||||
|
||||
msg->cmd = BFLB_CMD_UNLOAD_DRV;
|
||||
|
||||
msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t);
|
||||
|
||||
return usbh_bl616_bulk_out_transfer(bl616_class, g_bl616_tx_buffer, msg_len, 500);
|
||||
}
|
||||
|
||||
int usbh_bl616_wifi_sta_connect(const char *ssid,
|
||||
const int ssid_len,
|
||||
const char *password,
|
||||
const int pwd_len)
|
||||
{
|
||||
uint32_t msg_len;
|
||||
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
|
||||
rnm_sta_connect_msg_t *msg = (rnm_sta_connect_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
|
||||
|
||||
memset(usb_hdr, 0, sizeof(usb_data_t));
|
||||
memset(msg, 0, sizeof(rnm_sta_connect_msg_t));
|
||||
|
||||
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
|
||||
usb_hdr->length = sizeof(rnm_sta_connect_msg_t);
|
||||
usb_hdr->payload_offset = sizeof(usb_data_t);
|
||||
|
||||
msg->hdr.cmd = BFLB_CMD_STA_CONNECT;
|
||||
msg->hdr.msg_id = 0x0001;
|
||||
msg->hdr.session_id = 0x0002;
|
||||
msg->ssid_len = ssid_len;
|
||||
memcpy(msg->ssid, ssid, ssid_len);
|
||||
if (password) {
|
||||
memcpy(msg->password, password, pwd_len);
|
||||
}
|
||||
|
||||
msg_len = sizeof(usb_data_t) + sizeof(rnm_sta_connect_msg_t);
|
||||
|
||||
return usbh_bl616_bulk_out_transfer(&g_bl616_class, g_bl616_tx_buffer, msg_len, 500);
|
||||
}
|
||||
|
||||
int usbh_bl616_wifi_sta_disconnect(void)
|
||||
{
|
||||
uint32_t msg_len;
|
||||
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
|
||||
rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
|
||||
|
||||
memset(usb_hdr, 0, sizeof(usb_data_t));
|
||||
memset(msg, 0, sizeof(rnm_base_msg_t));
|
||||
|
||||
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
|
||||
usb_hdr->length = sizeof(rnm_base_msg_t);
|
||||
usb_hdr->payload_offset = sizeof(usb_data_t);
|
||||
|
||||
msg->cmd = BFLB_CMD_STA_DISCONNECT;
|
||||
|
||||
msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t);
|
||||
|
||||
return usbh_bl616_bulk_out_transfer(&g_bl616_class, g_bl616_tx_buffer, msg_len, 500);
|
||||
}
|
||||
|
||||
int usbh_bl616_get_wifi_scan_result(void)
|
||||
{
|
||||
uint32_t msg_len;
|
||||
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
|
||||
rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
|
||||
|
||||
memset(usb_hdr, 0, sizeof(usb_data_t));
|
||||
memset(msg, 0, sizeof(rnm_base_msg_t));
|
||||
|
||||
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
|
||||
usb_hdr->length = sizeof(rnm_base_msg_t);
|
||||
usb_hdr->payload_offset = sizeof(usb_data_t);
|
||||
|
||||
msg->cmd = BFLB_CMD_SCAN_RESULTS;
|
||||
|
||||
msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t);
|
||||
|
||||
return usbh_bl616_bulk_out_transfer(&g_bl616_class, g_bl616_tx_buffer, msg_len, 500);
|
||||
}
|
||||
|
||||
int usbh_bl616_wifi_scan(void)
|
||||
{
|
||||
int ret;
|
||||
uint32_t msg_len;
|
||||
usb_data_t *usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
|
||||
rnm_base_msg_t *msg = (rnm_base_msg_t *)(g_bl616_tx_buffer + sizeof(usb_data_t));
|
||||
|
||||
memset(usb_hdr, 0, sizeof(usb_data_t));
|
||||
memset(msg, 0, sizeof(rnm_base_msg_t));
|
||||
|
||||
usb_hdr->type = USBWIFI_DATA_TYPE_CMD;
|
||||
usb_hdr->length = sizeof(rnm_base_msg_t);
|
||||
usb_hdr->payload_offset = sizeof(usb_data_t);
|
||||
|
||||
msg->cmd = BFLB_CMD_SCAN;
|
||||
|
||||
msg_len = sizeof(usb_data_t) + sizeof(rnm_base_msg_t);
|
||||
|
||||
ret = usbh_bl616_bulk_out_transfer(&g_bl616_class, g_bl616_tx_buffer, msg_len, 500);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
usb_osal_msleep(500);
|
||||
return usbh_bl616_get_wifi_scan_result();
|
||||
}
|
||||
|
||||
static int usbh_bl616_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret = 0;
|
||||
|
||||
struct usbh_bl616 *bl616_class = &g_bl616_class;
|
||||
|
||||
memset(bl616_class, 0, sizeof(struct usbh_bl616));
|
||||
|
||||
bl616_class->hport = hport;
|
||||
bl616_class->intf = intf;
|
||||
|
||||
hport->config.intf[intf].priv = bl616_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(bl616_class->bulkin, ep_desc);
|
||||
} else {
|
||||
USBH_EP_INIT(bl616_class->bulkout, ep_desc);
|
||||
}
|
||||
}
|
||||
|
||||
usbh_bl616_get_wifi_mac(bl616_class);
|
||||
usbh_bl616_wifi_close(bl616_class);
|
||||
usbh_bl616_wifi_open(bl616_class);
|
||||
|
||||
USB_LOG_INFO("BL616 WIFI STA MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
|
||||
bl616_class->sta_mac[0],
|
||||
bl616_class->sta_mac[1],
|
||||
bl616_class->sta_mac[2],
|
||||
bl616_class->sta_mac[3],
|
||||
bl616_class->sta_mac[4],
|
||||
bl616_class->sta_mac[5]);
|
||||
|
||||
USB_LOG_INFO("BL616 WIFI AP MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
|
||||
bl616_class->ap_mac[0],
|
||||
bl616_class->ap_mac[1],
|
||||
bl616_class->ap_mac[2],
|
||||
bl616_class->ap_mac[3],
|
||||
bl616_class->ap_mac[4],
|
||||
bl616_class->ap_mac[5]);
|
||||
|
||||
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
|
||||
|
||||
USB_LOG_INFO("Register BL616 WIFI Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
|
||||
usbh_bl616_run(bl616_class);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_bl616_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct usbh_bl616 *bl616_class = (struct usbh_bl616 *)hport->config.intf[intf].priv;
|
||||
|
||||
if (bl616_class) {
|
||||
if (bl616_class->bulkin) {
|
||||
usbh_kill_urb(&bl616_class->bulkin_urb);
|
||||
}
|
||||
|
||||
if (bl616_class->bulkout) {
|
||||
usbh_kill_urb(&bl616_class->bulkout_urb);
|
||||
}
|
||||
|
||||
if (hport->config.intf[intf].devname[0] != '\0') {
|
||||
usb_osal_thread_schedule_other();
|
||||
USB_LOG_INFO("Unregister BL616 WIFI Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
usbh_bl616_stop(bl616_class);
|
||||
}
|
||||
|
||||
memset(bl616_class, 0, sizeof(struct usbh_bl616));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void usbh_bl616_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
|
||||
{
|
||||
int ret;
|
||||
usb_data_t *usb_hdr;
|
||||
rnm_base_msg_t *msg;
|
||||
rnm_sta_ip_update_ind_msg_t *ipmsg;
|
||||
rnm_scan_ind_msg_t *scanmsg;
|
||||
uint8_t *data;
|
||||
|
||||
(void)CONFIG_USB_OSAL_THREAD_GET_ARGV;
|
||||
USB_LOG_INFO("Create bl616 wifi rx thread\r\n");
|
||||
|
||||
while (1) {
|
||||
ret = usbh_bl616_bulk_in_transfer(&g_bl616_class, g_bl616_rx_buffer, sizeof(g_bl616_rx_buffer), USB_OSAL_WAITING_FOREVER);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
usb_hdr = (usb_data_t *)g_bl616_rx_buffer;
|
||||
|
||||
if (usb_hdr->type == USBWIFI_DATA_TYPE_CMD) {
|
||||
msg = (rnm_base_msg_t *)(g_bl616_rx_buffer + usb_hdr->payload_offset);
|
||||
|
||||
switch (msg->cmd) {
|
||||
case BFLB_CMD_STA_CONNECTED_IND:
|
||||
USB_LOG_INFO("AP connected\n");
|
||||
g_bl616_class.connect_status = true;
|
||||
usbh_bl616_sta_connect_callback();
|
||||
|
||||
break;
|
||||
case BFLB_CMD_STA_DISCONNECTED_IND:
|
||||
if (g_bl616_class.connect_status == true) {
|
||||
g_bl616_class.connect_status = false;
|
||||
USB_LOG_INFO("AP disconnected\n");
|
||||
usbh_bl616_sta_disconnect_callback();
|
||||
}
|
||||
break;
|
||||
case BFLB_CMD_STA_IP_UPDATE_IND:
|
||||
ipmsg = (rnm_sta_ip_update_ind_msg_t *)(g_bl616_rx_buffer + usb_hdr->payload_offset);
|
||||
|
||||
USB_LOG_INFO("WIFI IP update\r\n");
|
||||
USB_LOG_INFO("WIFI IPv4 Address : %d:%d:%d:%d\r\n",
|
||||
ipmsg->ip4_addr[0],
|
||||
ipmsg->ip4_addr[1],
|
||||
ipmsg->ip4_addr[2],
|
||||
ipmsg->ip4_addr[3]);
|
||||
USB_LOG_INFO("WIFI IPv4 Mask : %d:%d:%d:%d\r\n",
|
||||
ipmsg->ip4_mask[0],
|
||||
ipmsg->ip4_mask[1],
|
||||
ipmsg->ip4_mask[2],
|
||||
ipmsg->ip4_mask[3]);
|
||||
USB_LOG_INFO("WIFI IPv4 Gateway : %d:%d:%d:%d\r\n\r\n",
|
||||
ipmsg->ip4_gw[0],
|
||||
ipmsg->ip4_gw[1],
|
||||
ipmsg->ip4_gw[2],
|
||||
ipmsg->ip4_gw[3]);
|
||||
|
||||
g_bl616_class.mode = BL_MODE_STA;
|
||||
usbh_bl616_sta_update_ip(ipmsg->ip4_addr, ipmsg->ip4_mask, ipmsg->ip4_gw);
|
||||
break;
|
||||
case BFLB_CMD_SCAN_RESULTS:
|
||||
scanmsg = (rnm_scan_ind_msg_t *)(g_bl616_rx_buffer + usb_hdr->payload_offset);
|
||||
USB_LOG_INFO("WIFI scan result:\r\n");
|
||||
for (uint32_t i = 0; i < scanmsg->num; ++i) {
|
||||
struct bf1b_wifi_scan_record *r = &scanmsg->records[i];
|
||||
USB_LOG_INFO("BSSID " MAC_FMT ", channel %u, rssi %d, auth %s, cipher %s, SSID %s\r\n",
|
||||
ARR_ELE_6(r->bssid), r->channel, r->rssi,
|
||||
auth_to_str(r->auth_mode), cipher_to_str(r->cipher), r->ssid);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (usb_hdr->type == USBWIFI_DATA_TYPE_PKT) {
|
||||
data = (uint8_t *)(g_bl616_rx_buffer + usb_hdr->payload_offset);
|
||||
usbh_bl616_eth_input(data, usb_hdr->length);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
USB_LOG_INFO("Delete bl616 wifi rx thread\r\n");
|
||||
usb_osal_thread_delete(NULL);
|
||||
}
|
||||
|
||||
uint8_t *usbh_bl616_get_eth_txbuf(void)
|
||||
{
|
||||
return (g_bl616_tx_buffer + sizeof(usb_data_t));
|
||||
}
|
||||
|
||||
int usbh_bl616_eth_output(uint32_t buflen)
|
||||
{
|
||||
usb_data_t *usb_hdr;
|
||||
uint32_t txlen;
|
||||
|
||||
if (g_bl616_class.connect_status == false) {
|
||||
return -USB_ERR_NOTCONN;
|
||||
}
|
||||
|
||||
usb_hdr = (usb_data_t *)g_bl616_tx_buffer;
|
||||
memset(usb_hdr, 0, sizeof(usb_data_t));
|
||||
|
||||
usb_hdr->type = USBWIFI_DATA_TYPE_PKT;
|
||||
usb_hdr->length = buflen;
|
||||
usb_hdr->payload_offset = sizeof(usb_data_t);
|
||||
|
||||
txlen = buflen + sizeof(usb_data_t);
|
||||
if (!(txlen % USB_GET_MAXPACKETSIZE(g_bl616_class.bulkout->wMaxPacketSize))) {
|
||||
txlen += 1;
|
||||
}
|
||||
USB_LOG_DBG("txlen:%d\r\n", txlen);
|
||||
|
||||
usbh_bulk_urb_fill(&g_bl616_class.bulkout_urb, g_bl616_class.hport, g_bl616_class.bulkout, g_bl616_tx_buffer, txlen, USB_OSAL_WAITING_FOREVER, NULL, NULL);
|
||||
return usbh_submit_urb(&g_bl616_class.bulkout_urb);
|
||||
}
|
||||
|
||||
int wifi_sta_connect(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
USB_LOG_ERR("Usage: %s <ssid> <password>\r\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
usbh_bl616_wifi_sta_connect(argv[1], strlen(argv[1]), argv[2], strlen(argv[2]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wifi_scan(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
usbh_bl616_wifi_scan();
|
||||
return 0;
|
||||
}
|
||||
|
||||
__WEAK void usbh_bl616_run(struct usbh_bl616 *bl616_class)
|
||||
{
|
||||
(void)bl616_class;
|
||||
}
|
||||
|
||||
__WEAK void usbh_bl616_stop(struct usbh_bl616 *bl616_class)
|
||||
{
|
||||
(void)bl616_class;
|
||||
}
|
||||
|
||||
static const uint16_t bl616_id_table[][2] = {
|
||||
{ 0x349b, 0x616f },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
static const struct usbh_class_driver bl616_class_driver = {
|
||||
.driver_name = "bl616_wifi",
|
||||
.connect = usbh_bl616_connect,
|
||||
.disconnect = usbh_bl616_disconnect
|
||||
};
|
||||
|
||||
CLASS_INFO_DEFINE const struct usbh_class_info bl616_class_info = {
|
||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||
.bInterfaceClass = 0xff,
|
||||
.bInterfaceSubClass = 0x00,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.id_table = bl616_id_table,
|
||||
.class_driver = &bl616_class_driver
|
||||
};
|
||||
220
class/vendor/wifi/usbh_bl616.h
vendored
220
class/vendor/wifi/usbh_bl616.h
vendored
@@ -1,220 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBH_BL616_H
|
||||
#define USBH_BL616_H
|
||||
|
||||
#define USBWIFI_DATA_TYPE_CMD 0xA55A
|
||||
#define USBWIFI_DATA_TYPE_PKT 0x6996
|
||||
|
||||
#define USB_DATA_FLAG_AP_PKT (1u << 0)
|
||||
|
||||
typedef enum {
|
||||
BFLB_CMD_REBOOT = 0,
|
||||
BFLB_CMD_RESET,
|
||||
BFLB_CMD_HELLO,
|
||||
BFLB_CMD_PING,
|
||||
|
||||
BFLB_CMD_GET_MAC_ADDR,
|
||||
|
||||
// Scan
|
||||
BFLB_CMD_SCAN,
|
||||
BFLB_CMD_SCAN_RESULTS,
|
||||
|
||||
// STA
|
||||
BFLB_CMD_STA_CONNECT,
|
||||
BFLB_CMD_STA_DISCONNECT,
|
||||
BFLB_CMD_STA_CONNECTED_IND,
|
||||
BFLB_CMD_STA_DISCONNECTED_IND,
|
||||
BFLB_CMD_STA_IP_UPDATE_IND,
|
||||
BFLB_CMD_STA_SET_AUTO_RECONNECT,
|
||||
BFLB_CMD_STA_GET_LINK_STATUS,
|
||||
|
||||
// AP
|
||||
BFLB_CMD_AP_START,
|
||||
BFLB_CMD_AP_STOP,
|
||||
BFLB_CMD_AP_STARTED_IND,
|
||||
BFLB_CMD_AP_STOPPED_IND,
|
||||
BFLB_CMD_AP_GET_STA_LIST,
|
||||
|
||||
// Monitor
|
||||
BFLB_CMD_MONITOR_START,
|
||||
BFLB_CMD_MONITOR_STOP,
|
||||
BFLB_CMD_MONITOR_SET_CHANNEL,
|
||||
BFLB_CMD_MONITOR_GET_CHANNEL,
|
||||
|
||||
BFLB_CMD_SET_LPM_MODE,
|
||||
|
||||
// OTA
|
||||
BFLB_CMD_GET_DEV_VERSION,
|
||||
BFLB_CMD_OTA,
|
||||
|
||||
BFLB_CMD_EXT,
|
||||
|
||||
BFLB_CMD_USER_EXT,
|
||||
BFLB_CMD_UNLOAD_DRV,
|
||||
|
||||
BFLB_CMD_MAX,
|
||||
} bflb_cmd_t;
|
||||
|
||||
typedef enum {
|
||||
STATUS_OK,
|
||||
STATUS_NOMEM = 128,
|
||||
STATUS_INVALID_INPUT,
|
||||
STATUS_INVALID_MODE,
|
||||
STATUS_ERR_UNSPECIFIED,
|
||||
STATUS_NOT_IMPLEMENTED,
|
||||
} cmd_status_t;
|
||||
|
||||
typedef enum {
|
||||
RNM_WIFI_AUTH_UNKNOWN = 0,
|
||||
RNM_WIFI_AUTH_OPEN,
|
||||
RNM_WIFI_AUTH_WEP,
|
||||
RNM_WIFI_AUTH_WPA_PSK,
|
||||
RNM_WIFI_AUTH_WPA2_PSK,
|
||||
RNM_WIFI_AUTH_WPA_WPA2_PSK,
|
||||
RNM_WIFI_AUTH_WPA_ENTERPRISE,
|
||||
RNM_WIFI_AUTH_WPA3_SAE,
|
||||
RNM_WIFI_AUTH_WPA2_PSK_WPA3_SAE,
|
||||
RNM_WIFI_AUTH_MAX,
|
||||
} rnm_wifi_auth_mode_t;
|
||||
|
||||
typedef enum {
|
||||
RNM_WIFI_CIPHER_UNKNOWN = 0,
|
||||
RNM_WIFI_CIPHER_NONE,
|
||||
RNM_WIFI_CIPHER_WEP,
|
||||
RNM_WIFI_CIPHER_AES,
|
||||
RNM_WIFI_CIPHER_TKIP,
|
||||
RNM_WIFI_CIPHER_TKIP_AES,
|
||||
RNM_WIFI_CIPHER_MAX,
|
||||
} rnm_wifi_cipher_t;
|
||||
|
||||
/* common header */
|
||||
typedef struct {
|
||||
uint16_t cmd;
|
||||
// flag ACK is used by server to indicate a response to client
|
||||
#define RNM_MSG_FLAG_ACK (1 << 0)
|
||||
// flag TRANSPARENT is never transfered to peer but used locally
|
||||
#define RNM_MSG_FLAG_TRANSPARENT (1 << 1)
|
||||
// flag ASYNC is used by server to notify client events such as STA_CONNECTED
|
||||
#define RNM_MSG_FLAG_ASYNC (1 << 2)
|
||||
uint16_t flags;
|
||||
uint16_t status;
|
||||
uint16_t msg_id;
|
||||
uint16_t session_id;
|
||||
uint16_t msg_id_replying;
|
||||
} rnm_base_msg_t;
|
||||
|
||||
typedef struct {
|
||||
rnm_base_msg_t hdr;
|
||||
} rnm_ack_msg_t;
|
||||
|
||||
typedef struct {
|
||||
rnm_base_msg_t hdr;
|
||||
uint8_t sta_mac[6];
|
||||
uint8_t ap_mac[6];
|
||||
} rnm_mac_addr_ind_msg_t;
|
||||
|
||||
typedef struct {
|
||||
rnm_base_msg_t hdr;
|
||||
uint16_t ssid_len;
|
||||
uint8_t ssid[32];
|
||||
uint8_t password[64];
|
||||
} rnm_sta_connect_msg_t;
|
||||
|
||||
typedef struct {
|
||||
rnm_base_msg_t hdr;
|
||||
uint8_t ip4_addr[4];
|
||||
uint8_t ip4_mask[4];
|
||||
uint8_t ip4_gw[4];
|
||||
uint8_t ip4_dns1[4];
|
||||
uint8_t ip4_dns2[4];
|
||||
uint8_t gw_mac[6];
|
||||
} rnm_sta_ip_update_ind_msg_t;
|
||||
|
||||
struct bf1b_wifi_scan_record {
|
||||
uint8_t bssid[6];
|
||||
// TODO use compressed SSID encoding to save room
|
||||
uint8_t ssid[32 + 1];
|
||||
uint16_t channel;
|
||||
int8_t rssi;
|
||||
uint8_t auth_mode;
|
||||
uint8_t cipher;
|
||||
} __PACKED;
|
||||
|
||||
typedef struct {
|
||||
rnm_base_msg_t hdr;
|
||||
uint16_t num;
|
||||
struct bf1b_wifi_scan_record records[];
|
||||
} rnm_scan_ind_msg_t;
|
||||
|
||||
typedef enum {
|
||||
BL_MODE_NONE,
|
||||
BL_MODE_STA, // card is STA
|
||||
BL_MODE_AP, // card is AP
|
||||
BL_MODE_STA_AP, // card is STA&AP
|
||||
BL_MODE_SNIFFER, // card is sniffer
|
||||
BL_MODE_MAX,
|
||||
} bl_wifi_mode_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t type;
|
||||
uint16_t length;
|
||||
uint16_t flags;
|
||||
uint16_t payload_offset;
|
||||
uint32_t rsvd[8];
|
||||
uint8_t payload[];
|
||||
} __attribute__((aligned(4))) usb_data_t;
|
||||
|
||||
struct usbh_bl616 {
|
||||
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;
|
||||
|
||||
uint8_t intf;
|
||||
|
||||
uint8_t sta_mac[6];
|
||||
uint8_t ap_mac[6];
|
||||
uint8_t mode;
|
||||
bool connect_status;
|
||||
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int usbh_bl616_wifi_sta_connect(const char *ssid,
|
||||
const int ssid_len,
|
||||
const char *password,
|
||||
const int pwd_len);
|
||||
|
||||
int usbh_bl616_wifi_sta_disconnect(void);
|
||||
int usbh_bl616_wifi_scan(void);
|
||||
|
||||
void usbh_bl616_sta_connect_callback(void);
|
||||
void usbh_bl616_sta_disconnect_callback(void);
|
||||
void usbh_bl616_sta_update_ip(uint8_t ip4_addr[4], uint8_t ip4_mask[4], uint8_t ip4_gw[4]);
|
||||
|
||||
uint8_t *usbh_bl616_get_eth_txbuf(void);
|
||||
int usbh_bl616_eth_output(uint32_t buflen);
|
||||
void usbh_bl616_eth_input(uint8_t *buf, uint32_t buflen);
|
||||
void usbh_bl616_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV);
|
||||
|
||||
void usbh_bl616_run(struct usbh_bl616 *bl616_class);
|
||||
void usbh_bl616_stop(struct usbh_bl616 *bl616_class);
|
||||
|
||||
int wifi_sta_connect(int argc, char **argv);
|
||||
int wifi_scan(int argc, char **argv);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_BL616_H */
|
||||
@@ -44,7 +44,6 @@ static int usbd_video_control_request_handler(uint8_t busid, struct usb_setup_pa
|
||||
case VIDEO_REQUEST_GET_INFO:
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -58,7 +57,6 @@ static int usbd_video_control_request_handler(uint8_t busid, struct usb_setup_pa
|
||||
case VIDEO_REQUEST_GET_INFO:
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -91,7 +89,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 1;
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -127,7 +124,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 4;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -163,7 +159,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -199,7 +194,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -235,7 +229,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -247,16 +240,13 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class control selector 0x%02x\r\n", control_selector);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
USB_LOG_WRN("Unhandled Video Class wTerminalType 0x%02x\r\n", entity_info->wTerminalType);
|
||||
return -2;
|
||||
}
|
||||
break;
|
||||
@@ -298,7 +288,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -337,7 +326,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -373,7 +361,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -409,7 +396,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -440,7 +426,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -471,7 +456,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -502,7 +486,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -538,7 +521,6 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 2;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -550,13 +532,11 @@ static int usbd_video_control_unit_terminal_request_handler(uint8_t busid, struc
|
||||
*len = 1;
|
||||
} break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_usbd_video[busid].error_code = 0x06;
|
||||
USB_LOG_WRN("Unhandled Video Class control selector 0x%02x\r\n", control_selector);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -606,7 +586,6 @@ static int usbd_video_stream_request_handler(uint8_t busid, struct usb_setup_pac
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -638,7 +617,6 @@ static int usbd_video_stream_request_handler(uint8_t busid, struct usb_setup_pac
|
||||
break;
|
||||
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -653,7 +631,6 @@ static int usbd_video_stream_request_handler(uint8_t busid, struct usb_setup_pac
|
||||
*len = 1;
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -365,14 +365,9 @@ static int rndis_set_cmd_handler(uint8_t *data, uint32_t len)
|
||||
|
||||
switch (cmd->Oid) {
|
||||
case OID_GEN_RNDIS_CONFIG_PARAMETER:
|
||||
param = (rndis_config_parameter_t *)((uint8_t *)&(cmd->RequestId) + cmd->InformationBufferOffset);
|
||||
USB_LOG_WRN("RNDIS cfg param: NameOfs=%d, NameLen=%d, ValueOfs=%d, ValueLen=%d\r\n",
|
||||
param->ParameterNameOffset, param->ParameterNameLength,
|
||||
param->ParameterValueOffset, param->ParameterValueLength);
|
||||
break;
|
||||
case OID_GEN_CURRENT_PACKET_FILTER:
|
||||
if (cmd->InformationBufferLength < sizeof(g_usbd_rndis.net_filter)) {
|
||||
USB_LOG_WRN("PACKET_FILTER!\r\n");
|
||||
resp->Status = RNDIS_STATUS_INVALID_DATA;
|
||||
} else {
|
||||
uint32_t *filter;
|
||||
|
||||
@@ -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,
|
||||
|
||||
206
common/usb_def.h
206
common/usb_def.h
@@ -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 */
|
||||
@@ -556,7 +556,7 @@ struct usb_bos_header_descriptor {
|
||||
} __PACKED;
|
||||
|
||||
/* BOS Capability platform Descriptor */
|
||||
struct usb_bos_capability_platform_descriptor {
|
||||
struct usb_bos_capability_platform_common_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDevCapabilityType;
|
||||
@@ -564,16 +564,26 @@ struct usb_bos_capability_platform_descriptor {
|
||||
uint8_t PlatformCapabilityUUID[16];
|
||||
} __PACKED;
|
||||
|
||||
/* BOS Capability MS OS Descriptors version 2 */
|
||||
struct usb_bos_capability_msosv2_descriptor {
|
||||
/* Microsoft OS 2.0 Platform Capability Descriptor
|
||||
* See https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/
|
||||
* microsoft-defined-usb-descriptors
|
||||
* Adapted from the source:
|
||||
* https://github.com/sowbug/weblight/blob/master/firmware/webusb.c
|
||||
* (BSD-2) Thanks http://janaxelson.com/files/ms_os_20_descriptors.c
|
||||
*/
|
||||
struct usb_bos_capability_platform_winusb_descriptor {
|
||||
struct usb_bos_capability_platform_common_descriptor common;
|
||||
uint32_t dwWindowsVersion;
|
||||
uint16_t wMSOSDescriptorSetTotalLength;
|
||||
uint8_t bVendorCode;
|
||||
uint8_t bAltEnumCode;
|
||||
} __PACKED;
|
||||
|
||||
/* BOS Capability webusb */
|
||||
struct usb_bos_capability_webusb_descriptor {
|
||||
/* WebUSB Platform Capability Descriptor:
|
||||
* https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
|
||||
*/
|
||||
struct usb_bos_capability_platform_webusb_descriptor {
|
||||
struct usb_bos_capability_platform_common_descriptor common;
|
||||
uint16_t bcdVersion;
|
||||
uint8_t bVendorCode;
|
||||
uint8_t iLandingPage;
|
||||
@@ -587,26 +597,6 @@ struct usb_bos_capability_extension_descriptor {
|
||||
uint32_t bmAttributes;
|
||||
} __PACKED;
|
||||
|
||||
/* Microsoft OS 2.0 Platform Capability Descriptor
|
||||
* See https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/
|
||||
* microsoft-defined-usb-descriptors
|
||||
* Adapted from the source:
|
||||
* https://github.com/sowbug/weblight/blob/master/firmware/webusb.c
|
||||
* (BSD-2) Thanks http://janaxelson.com/files/ms_os_20_descriptors.c
|
||||
*/
|
||||
struct usb_bos_capability_platform_msosv2_descriptor {
|
||||
struct usb_bos_capability_platform_descriptor platform_msos;
|
||||
struct usb_bos_capability_msosv2_descriptor data_msosv2;
|
||||
} __PACKED;
|
||||
|
||||
/* WebUSB Platform Capability Descriptor:
|
||||
* https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
|
||||
*/
|
||||
struct usb_bos_capability_platform_webusb_descriptor {
|
||||
struct usb_bos_capability_platform_descriptor platform_webusb;
|
||||
struct usb_bos_capability_webusb_descriptor data_webusb;
|
||||
} __PACKED;
|
||||
|
||||
struct usb_webusb_url_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
@@ -625,18 +615,12 @@ struct usb_bos_descriptor {
|
||||
uint32_t string_len;
|
||||
};
|
||||
|
||||
/* USB Device Capability Descriptor */
|
||||
struct usb_device_capability_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDevCapabilityType;
|
||||
} __PACKED;
|
||||
|
||||
/** USB descriptor header */
|
||||
struct usb_desc_header {
|
||||
uint8_t bLength; /**< descriptor length */
|
||||
uint8_t bDescriptorType; /**< descriptor type */
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
#define USB_DEVICE_DESCRIPTOR_INIT(bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct, bcdDevice, bNumConfigurations) \
|
||||
0x12, /* bLength */ \
|
||||
@@ -705,7 +689,7 @@ struct usb_desc_header {
|
||||
WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
|
||||
bInterval /* bInterval */
|
||||
|
||||
#define USB_IAD_INIT(bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass, bFunctionProtocol) \
|
||||
#define USB_IAD_DESCRIPTOR_INIT(bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass, bFunctionProtocol) \
|
||||
0x08, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
|
||||
bFirstInterface, /* bFirstInterface */ \
|
||||
@@ -716,9 +700,145 @@ struct usb_desc_header {
|
||||
0x00 /* iFunction */
|
||||
|
||||
#define USB_LANGID_INIT(id) \
|
||||
0x04, /* bLength */ \
|
||||
0x04, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ \
|
||||
WBVAL(id) /* wLangID0 */
|
||||
|
||||
#define USB_BOS_HEADER_DESCRIPTOR_INIT(wTotalLength, bNumDeviceCaps) \
|
||||
0x05, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_BINARY_OBJECT_STORE, /* bDescriptorType */\
|
||||
WBVAL(wTotalLength), /* wTotalLength */ \
|
||||
bNumDeviceCaps /* bNumDeviceCaps */
|
||||
|
||||
#define USB_BOS_CAP_PLATFORM_WEBUSB_DESCRIPTOR_INIT(bVendorCode, iLandingPage) \
|
||||
0x18, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY, /* bDescriptorType */ \
|
||||
USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */ \
|
||||
0x00, /* bReserved */ \
|
||||
0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, /* PlatformCapabilityUUID */ \
|
||||
0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65, \
|
||||
WBVAL(0x0100), /* bcdVersion */ \
|
||||
bVendorCode, /* bVendorCode */ \
|
||||
iLandingPage /* iLandingPage */
|
||||
|
||||
#define USB_BOS_CAP_PLATFORM_WINUSB_DESCRIPTOR_INIT(bVendorCode, wMSOSDescriptorSetTotalLength) \
|
||||
0x1C, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY, /* bDescriptorType */ \
|
||||
USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */ \
|
||||
0x00, /* bReserved */ \
|
||||
0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, /* PlatformCapabilityUUID */ \
|
||||
0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F, \
|
||||
DBVAL(0x06030000), /* dwWindowsVersion */ \
|
||||
WBVAL(wMSOSDescriptorSetTotalLength), /* wMSOSDescriptorSetTotalLength */ \
|
||||
bVendorCode, /* bVendorCode */ \
|
||||
0x00 /* bAltEnumCode */
|
||||
|
||||
#define USB_BOS_CAP_PLATFORM_WEBUSB_DESCRIPTOR_LEN 24
|
||||
#define USB_BOS_CAP_PLATFORM_WINUSB_DESCRIPTOR_LEN 28
|
||||
|
||||
#define USB_MSOSV1_STRING_DESCRIPTOR_INIT(vendor_code) \
|
||||
0x12, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ \
|
||||
'M', 0, /* bString[0] */ \
|
||||
'S', 0, /* bString[1] */ \
|
||||
'F', 0, /* bString[2] */ \
|
||||
'T', 0, /* bString[3] */ \
|
||||
'1', 0, /* bString[4] */ \
|
||||
'0', 0, /* bString[5] */ \
|
||||
'0', 0, /* bString[6] */ \
|
||||
vendor_code, /* bMS_VendorCode */ \
|
||||
0x00 /* bPad */
|
||||
|
||||
#define USB_MSOSV1_COMP_ID_HEADER_DESCRIPTOR_INIT(bCount) \
|
||||
DBVAL((sizeof(struct usb_msosv1_compat_id_header_descriptor) + sizeof(struct usb_msosv1_comp_id_function_descriptor) * bCount)), /* dwLength */ \
|
||||
WBVAL(0x0100), /* bcdVersion */ \
|
||||
WBVAL(0x0004), /* wIndex */ \
|
||||
bCount, /* bCount */ \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* reserved[7] */
|
||||
|
||||
#define USB_MSOSV1_COMP_ID_FUNCTION_WINUSB_DESCRIPTOR_INIT(bFirstInterfaceNumber) \
|
||||
bFirstInterfaceNumber, /* bFirstInterfaceNumber */\
|
||||
0x01, /* reserved1 */ \
|
||||
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, /* compatibleID[8] */ \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* subCompatibleID[8] */ \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* reserved2[6] */
|
||||
|
||||
#define USB_MSOSV1_COMP_ID_FUNCTION_MTP_DESCRIPTOR_INIT(bFirstInterfaceNumber)\
|
||||
bFirstInterfaceNumber, /* bFirstInterfaceNumber */\
|
||||
0x01, /* reserved1 */ \
|
||||
'M', 'T', 'P', 'U', 'S', 'B', 0x00, 0x00, /* compatibleID[8] */ \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* subCompatibleID[8] */ \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* reserved2[6] */
|
||||
|
||||
#define USB_MSOSV1_COMP_ID_FUNCTION_ADB_DESCRIPTOR_INIT(bFirstInterfaceNumber)\
|
||||
bFirstInterfaceNumber, * bFirstInterfaceNumber */\
|
||||
0x01, /* reserved1 */ \
|
||||
'A', 'D', 'B', 0x00, 0x00, 0x00, 0x00, 0x00, /* compatibleID[8] */ \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* subCompatibleID[8] */ \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* reserved2[6] */
|
||||
|
||||
#define USB_MSOSV1_COMP_ID_DESCRIPTOR_LEN(bCount) \
|
||||
(sizeof(struct usb_msosv1_compat_id_header_descriptor) + sizeof(struct usb_msosv1_comp_id_function_descriptor) * (bCount))
|
||||
|
||||
#define USB_MSOSV2_COMP_ID_SET_HEADER_DESCRIPTOR_INIT(wDescriptorSetTotalLength) \
|
||||
WBVAL(WINUSB_DESCRIPTOR_SET_HEADER_SIZE), /* wLength */ \
|
||||
WBVAL(WINUSB_SET_HEADER_DESCRIPTOR_TYPE), /* wDescriptorType */ \
|
||||
DBVAL(0x06030000), /* dwWindowsVersion */ \
|
||||
WBVAL(wDescriptorSetTotalLength) /* wDescriptorSetTotalLength */
|
||||
|
||||
#define USB_MSOSV2_COMP_ID_FUNCTION_WINUSB_SINGLE_DESCRIPTOR_INIT() \
|
||||
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE), /* wLength */ \
|
||||
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE), /* wDescriptorType */ \
|
||||
'W', 'I', 'N', 'U', 'S', 'B', 0, 0, /* CompatibleId*/ \
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* SubCompatibleId*/ \
|
||||
WBVAL(132), /* wLength */ \
|
||||
WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE), /* wDescriptorType */ \
|
||||
WBVAL(WINUSB_PROP_DATA_TYPE_REG_SZ), /* wPropertyDataType */ \
|
||||
WBVAL(42), /* wPropertyNameLength bPropertyName: "DeviceInterfaceGUID" */ \
|
||||
'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, \
|
||||
'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, \
|
||||
'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0, \
|
||||
WBVAL(80), /* wPropertyDataLength */ \
|
||||
'{', 0, \
|
||||
'C', 0, 'D', 0, 'B', 0, '3', 0, 'B', 0, '5', 0, 'A', 0, 'D', 0, '-', 0, \
|
||||
'2', 0, '9', 0, '3', 0, 'B', 0, '-', 0, \
|
||||
'4', 0, '6', 0, '6', 0, '3', 0, '-', 0, \
|
||||
'A', 0, 'A', 0, '3', 0, '6', 0, '-', \
|
||||
0, '1', 0, 'A', 0, 'A', 0, 'E', 0, '4', 0, '6', 0, '4', 0, '6', 0, '3', 0, '7', 0, '7', 0, '6', 0, \
|
||||
'}', 0, 0, 0, 0, 0
|
||||
|
||||
#define USB_MSOSV2_COMP_ID_FUNCTION_WINUSB_SINGLE_DESCRIPTOR_LEN \
|
||||
(WINUSB_FEATURE_COMPATIBLE_ID_SIZE + 132)
|
||||
|
||||
#define USB_MSOSV2_COMP_ID_FUNCTION_WINUSB_MULTI_DESCRIPTOR_INIT(bFirstInterfaceNumber) \
|
||||
WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), /* wLength */ \
|
||||
WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), /* wDescriptorType */ \
|
||||
bFirstInterfaceNumber, /* bFirstInterface*/ \
|
||||
0, /* bReserved */ \
|
||||
WBVAL((WINUSB_FUNCTION_SUBSET_HEADER_SIZE + WINUSB_FEATURE_COMPATIBLE_ID_SIZE + 132)), /* wSubsetLength */\
|
||||
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE), /* wLength */ \
|
||||
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE), /* wDescriptorType */ \
|
||||
'W', 'I', 'N', 'U', 'S', 'B', 0, 0, /* CompatibleId*/ \
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* SubCompatibleId*/ \
|
||||
WBVAL(132), /* wLength */ \
|
||||
WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE), /* wDescriptorType */ \
|
||||
WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), /* wPropertyDataType */ \
|
||||
WBVAL(42), /* wPropertyNameLength bPropertyName: "DeviceInterfaceGUID" */ \
|
||||
'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, \
|
||||
'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, \
|
||||
'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0, \
|
||||
WBVAL(80), /* wPropertyDataLength */ \
|
||||
'{', 0, \
|
||||
'C', 0, 'D', 0, 'B', 0, '3', 0, 'B', 0, '5', 0, 'A', 0, 'D', 0, '-', 0, \
|
||||
'2', 0, '9', 0, '3', 0, 'B', 0, '-', 0, \
|
||||
'4', 0, '6', 0, '6', 0, '3', 0, '-', 0, \
|
||||
'A', 0, 'A', 0, '3', 0, '6', 0, '-', \
|
||||
0, '1', 0, 'A', 0, 'A', 0, 'E', 0, '4', 0, '6', 0, '4', 0, '6', 0, '3', 0, '7', 0, '7', 0, '6', 0, \
|
||||
'}', 0, 0, 0, 0, 0
|
||||
|
||||
#define USB_MSOSV2_COMP_ID_FUNCTION_WINUSB_MULTI_DESCRIPTOR_LEN \
|
||||
(WINUSB_FUNCTION_SUBSET_HEADER_SIZE + WINUSB_FEATURE_COMPATIBLE_ID_SIZE + 132)
|
||||
|
||||
// clang-format on
|
||||
|
||||
#endif /* USB_DEF_H */
|
||||
|
||||
@@ -185,8 +185,8 @@
|
||||
(field)[3] = (uint8_t)((value) >> 0); \
|
||||
} while (0)
|
||||
|
||||
#define WBVAL(x) (x & 0xFF), ((x >> 8) & 0xFF)
|
||||
#define DBVAL(x) (x & 0xFF), ((x >> 8) & 0xFF), ((x >> 16) & 0xFF), ((x >> 24) & 0xFF)
|
||||
#define WBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF)
|
||||
#define DBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF), (((x) >> 16) & 0xFF), (((x) >> 24) & 0xFF)
|
||||
|
||||
#define PP_NARG(...) \
|
||||
PP_NARG_(__VA_ARGS__, PP_RSEQ_N())
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -56,6 +56,7 @@ enum usbd_event_type {
|
||||
typedef int (*usbd_request_handler)(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len);
|
||||
typedef void (*usbd_endpoint_callback)(uint8_t busid, uint8_t ep, uint32_t nbytes);
|
||||
typedef void (*usbd_notify_handler)(uint8_t busid, uint8_t event, void *arg);
|
||||
typedef void (*usbd_event_handler_t)(uint8_t busid, uint8_t event);
|
||||
|
||||
struct usbd_endpoint {
|
||||
uint8_t ep_addr;
|
||||
@@ -95,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);
|
||||
@@ -115,7 +108,7 @@ bool usb_device_is_suspend(uint8_t busid);
|
||||
int usbd_send_remote_wakeup(uint8_t busid);
|
||||
uint8_t usbd_get_ep0_next_state(uint8_t busid);
|
||||
|
||||
int usbd_initialize(uint8_t busid, uintptr_t reg_base, void (*event_handler)(uint8_t busid, uint8_t event));
|
||||
int usbd_initialize(uint8_t busid, uintptr_t reg_base, usbd_event_handler_t event_handler);
|
||||
int usbd_deinitialize(uint8_t busid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
116
core/usbh_core.c
116
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;
|
||||
@@ -409,7 +418,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
|
||||
|
||||
USB_LOG_INFO("The device has %d bNumConfigurations\r\n", ((struct usb_device_descriptor *)ep0_request_buffer[hport->bus->busid])->bNumConfigurations);
|
||||
|
||||
config_index = 0;
|
||||
config_index = usbh_get_hport_active_config_index(hport);
|
||||
USB_LOG_DBG("The device selects config %d\r\n", config_index);
|
||||
|
||||
/* Read the first 9 bytes of the config descriptor */
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1183,3 +1208,10 @@ int lsusb(int argc, char **argv)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__WEAK uint8_t usbh_get_hport_active_config_index(struct usbh_hubport *hport)
|
||||
{
|
||||
ARG_UNUSED(hport);
|
||||
|
||||
return 0; // Default to configuration index 0
|
||||
}
|
||||
@@ -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
|
||||
@@ -61,6 +90,8 @@ extern "C" {
|
||||
USB_GET_MULT(ep_desc->wMaxPacketSize)); \
|
||||
} while (0)
|
||||
|
||||
typedef void (*usbh_event_handler_t)(uint8_t busid, uint8_t hub_index, uint8_t hub_port, uint8_t intf, uint8_t event);
|
||||
|
||||
struct usbh_class_info {
|
||||
uint8_t match_flags; /* Used for product specific matches; range is inclusive */
|
||||
uint8_t bInterfaceClass; /* Base device class code */
|
||||
@@ -133,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;
|
||||
@@ -170,6 +201,8 @@ struct usbh_bus {
|
||||
struct usbh_devaddr_map devgen;
|
||||
usb_osal_thread_t hub_thread;
|
||||
usb_osal_mq_t hub_mq;
|
||||
usb_osal_mutex_t mutex;
|
||||
usbh_event_handler_t event_handler;
|
||||
};
|
||||
|
||||
static inline void usbh_control_urb_fill(struct usbh_urb *urb,
|
||||
@@ -276,10 +309,11 @@ 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);
|
||||
uint8_t usbh_get_hport_active_config_index(struct usbh_hubport *hport);
|
||||
|
||||
int lsusb(int argc, char **argv);
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@ struct usbotg_core_priv {
|
||||
uint32_t reg_base;
|
||||
bool usbh_initialized;
|
||||
bool usbd_initialized;
|
||||
void *device_event_callback;
|
||||
void *host_event_callback;
|
||||
uint8_t current_mode;
|
||||
usbd_event_handler_t device_event_callback;
|
||||
usbh_event_handler_t host_event_callback;
|
||||
uint8_t request_mode;
|
||||
usb_osal_sem_t change_sem;
|
||||
usb_osal_thread_t change_thread;
|
||||
} g_usbotg_core[CONFIG_USB_OTG_MAX_BUS];
|
||||
@@ -31,14 +31,14 @@ static void usbotg_host_initialize(uint8_t busid)
|
||||
}
|
||||
|
||||
if (g_usbotg_core[busid].usbd_initialized) {
|
||||
g_usbotg_core[busid].usbd_initialized = false;
|
||||
usbd_deinitialize(busid);
|
||||
g_usbotg_core[busid].usbd_initialized = false;
|
||||
}
|
||||
|
||||
USB_LOG_INFO("Switch to HOST mode\r\n");
|
||||
|
||||
usbh_initialize(busid, g_usbotg_core[busid].reg_base);
|
||||
g_usbotg_core[busid].usbh_initialized = true;
|
||||
usbh_initialize(busid, g_usbotg_core[busid].reg_base);
|
||||
}
|
||||
|
||||
static void usbotg_device_initialize(uint8_t busid)
|
||||
@@ -48,14 +48,14 @@ static void usbotg_device_initialize(uint8_t busid)
|
||||
}
|
||||
|
||||
if (g_usbotg_core[busid].usbh_initialized) {
|
||||
g_usbotg_core[busid].usbh_initialized = false;
|
||||
usbh_deinitialize(busid);
|
||||
g_usbotg_core[busid].usbh_initialized = false;
|
||||
}
|
||||
|
||||
USB_LOG_INFO("Switch to DEVICE mode\r\n");
|
||||
|
||||
usbd_initialize(g_usbotg_core[busid].busid, g_usbotg_core[busid].reg_base, g_usbotg_core[busid].device_event_callback);
|
||||
g_usbotg_core[busid].usbd_initialized = true;
|
||||
usbd_initialize(g_usbotg_core[busid].busid, g_usbotg_core[busid].reg_base, g_usbotg_core[busid].device_event_callback);
|
||||
}
|
||||
|
||||
static void usbotg_rolechange_thread(void *argument)
|
||||
@@ -66,16 +66,16 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int usbotg_initialize(uint8_t busid, uint32_t reg_base, void *device_event_callback, void *host_event_callback, uint8_t default_role)
|
||||
int usbotg_initialize(uint8_t busid, uint32_t reg_base, usbd_event_handler_t device_event_callback, usbh_event_handler_t host_event_callback, uint8_t default_role)
|
||||
{
|
||||
char thread_name[32] = { 0 };
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ extern "C" {
|
||||
#include "usbh_core.h"
|
||||
#include "usb_otg.h"
|
||||
|
||||
int usbotg_initialize(uint8_t busid, uint32_t reg_base, void *device_event_callback, void *host_event_callback, uint8_t default_role);
|
||||
int usbotg_initialize(uint8_t busid, uint32_t reg_base, usbd_event_handler_t device_event_callback, usbh_event_handler_t host_event_callback, uint8_t default_role);
|
||||
int usbotg_deinitialize(uint8_t busid);
|
||||
|
||||
/* called by user */
|
||||
|
||||
@@ -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,14 +21,15 @@
|
||||
|
||||
#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 1
|
||||
#define IN_CHANNEL_NUM 2
|
||||
|
||||
#if IN_CHANNEL_NUM == 1
|
||||
#define INPUT_CTRL 0x03, 0x03
|
||||
#define INPUT_CH_ENABLE 0x0000
|
||||
#define INPUT_CH_ENABLE 0x0001
|
||||
#elif IN_CHANNEL_NUM == 2
|
||||
#define INPUT_CTRL 0x03, 0x03, 0x03
|
||||
#define INPUT_CH_ENABLE 0x0003
|
||||
@@ -54,32 +55,31 @@
|
||||
|
||||
/* 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_AUDIO_CONFIG_DESC_SIZ (unsigned long)(9 + \
|
||||
AUDIO_AC_DESCRIPTOR_INIT_LEN(1) + \
|
||||
AUDIO_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(IN_CHANNEL_NUM, 1) + \
|
||||
AUDIO_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_AS_DESCRIPTOR_INIT_LEN(1))
|
||||
#define USB_CONFIG_SIZE (unsigned long)(9 + \
|
||||
AUDIO_AC_DESCRIPTOR_LEN(1) + \
|
||||
AUDIO_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(IN_CHANNEL_NUM, 1) + \
|
||||
AUDIO_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_AS_DESCRIPTOR_LEN(1))
|
||||
|
||||
#define AUDIO_AC_SIZ (AUDIO_SIZEOF_AC_HEADER_DESC(1) + \
|
||||
AUDIO_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
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)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_AUDIO_CONFIG_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
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))
|
||||
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_AUDIO_CONFIG_DESC_SIZ, 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;
|
||||
@@ -301,13 +218,12 @@ struct audio_entity_info audio_entity_table[] = {
|
||||
.ep = AUDIO_IN_EP },
|
||||
};
|
||||
|
||||
// In windows, audio driver cannot remove auto, so when you modify any descriptor information, please modify string descriptors too.
|
||||
|
||||
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);
|
||||
|
||||
@@ -21,13 +21,69 @@
|
||||
#define FEEDBACK_ENDP_PACKET_SIZE 0x03
|
||||
#endif
|
||||
|
||||
#define AUDIO_IN_EP 0x81
|
||||
#define AUDIO_OUT_EP 0x02
|
||||
#define AUDIO_IN_EP 0x81
|
||||
#define AUDIO_OUT_EP 0x02
|
||||
#define AUDIO_OUT_FEEDBACK_EP 0x83
|
||||
|
||||
#define AUDIO_IN_FU_ID 0x02
|
||||
#define AUDIO_OUT_FU_ID 0x05
|
||||
|
||||
#define IN_CHANNEL_NUM 2
|
||||
|
||||
#if IN_CHANNEL_NUM == 1
|
||||
#define INPUT_CTRL 0x03, 0x03
|
||||
#define INPUT_CH_ENABLE 0x0001
|
||||
#elif IN_CHANNEL_NUM == 2
|
||||
#define INPUT_CTRL 0x03, 0x03, 0x03
|
||||
#define INPUT_CH_ENABLE 0x0003
|
||||
#elif IN_CHANNEL_NUM == 3
|
||||
#define INPUT_CTRL 0x03, 0x03, 0x03, 0x03
|
||||
#define INPUT_CH_ENABLE 0x0007
|
||||
#elif IN_CHANNEL_NUM == 4
|
||||
#define INPUT_CTRL 0x03, 0x03, 0x03, 0x03, 0x03
|
||||
#define INPUT_CH_ENABLE 0x000f
|
||||
#elif IN_CHANNEL_NUM == 5
|
||||
#define INPUT_CTRL 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
|
||||
#define INPUT_CH_ENABLE 0x001f
|
||||
#elif IN_CHANNEL_NUM == 6
|
||||
#define INPUT_CTRL 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
|
||||
#define INPUT_CH_ENABLE 0x003F
|
||||
#elif IN_CHANNEL_NUM == 7
|
||||
#define INPUT_CTRL 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
|
||||
#define INPUT_CH_ENABLE 0x007f
|
||||
#elif IN_CHANNEL_NUM == 8
|
||||
#define INPUT_CTRL 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
|
||||
#define INPUT_CH_ENABLE 0x00ff
|
||||
#endif
|
||||
|
||||
#define OUT_CHANNEL_NUM 2
|
||||
|
||||
#if OUT_CHANNEL_NUM == 1
|
||||
#define OUTPUT_CTRL 0x03, 0x03
|
||||
#define OUTPUT_CH_ENABLE 0x0001
|
||||
#elif OUT_CHANNEL_NUM == 2
|
||||
#define OUTPUT_CTRL 0x03, 0x03, 0x03
|
||||
#define OUTPUT_CH_ENABLE 0x0003
|
||||
#elif OUT_CHANNEL_NUM == 3
|
||||
#define OUTPUT_CTRL 0x03, 0x03, 0x03, 0x03
|
||||
#define OUTPUT_CH_ENABLE 0x0007
|
||||
#elif OUT_CHANNEL_NUM == 4
|
||||
#define OUTPUT_CTRL 0x03, 0x03, 0x03, 0x03, 0x03
|
||||
#define OUTPUT_CH_ENABLE 0x000f
|
||||
#elif OUT_CHANNEL_NUM == 5
|
||||
#define OUTPUT_CTRL 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
|
||||
#define OUTPUT_CH_ENABLE 0x001f
|
||||
#elif OUT_CHANNEL_NUM == 6
|
||||
#define OUTPUT_CTRL 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
|
||||
#define OUTPUT_CH_ENABLE 0x003F
|
||||
#elif OUT_CHANNEL_NUM == 7
|
||||
#define OUTPUT_CTRL 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
|
||||
#define OUTPUT_CH_ENABLE 0x007f
|
||||
#elif OUT_CHANNEL_NUM == 8
|
||||
#define OUTPUT_CTRL 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
|
||||
#define OUTPUT_CH_ENABLE 0x00ff
|
||||
#endif
|
||||
|
||||
/* AUDIO Class Config */
|
||||
#define AUDIO_SPEAKER_FREQ 16000U
|
||||
#define AUDIO_SPEAKER_FRAME_SIZE_BYTE 2u
|
||||
@@ -44,60 +100,59 @@
|
||||
#define AUDIO_IN_PACKET ((uint32_t)((AUDIO_MIC_FREQ * AUDIO_MIC_FRAME_SIZE_BYTE * 2) / 1000))
|
||||
|
||||
#if USING_FEEDBACK == 0
|
||||
#define USB_AUDIO_CONFIG_DESC_SIZ (unsigned long)(9 + \
|
||||
AUDIO_AC_DESCRIPTOR_INIT_LEN(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) + \
|
||||
AUDIO_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_AS_DESCRIPTOR_INIT_LEN(1) + \
|
||||
AUDIO_AS_DESCRIPTOR_INIT_LEN(1))
|
||||
#define USB_CONFIG_SIZE (unsigned long)(9 + \
|
||||
AUDIO_AC_DESCRIPTOR_LEN(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 + \
|
||||
AUDIO_AS_DESCRIPTOR_LEN(1) + \
|
||||
AUDIO_AS_DESCRIPTOR_LEN(1))
|
||||
#else
|
||||
#define USB_AUDIO_CONFIG_DESC_SIZ (unsigned long)(9 + \
|
||||
AUDIO_AC_DESCRIPTOR_INIT_LEN(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) + \
|
||||
AUDIO_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_AS_DESCRIPTOR_INIT_LEN(1) + \
|
||||
AUDIO_AS_FEEDBACK_DESCRIPTOR_INIT_LEN(1))
|
||||
#define USB_CONFIG_SIZE (unsigned long)(9 + \
|
||||
AUDIO_AC_DESCRIPTOR_LEN(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 + \
|
||||
AUDIO_AS_DESCRIPTOR_LEN(1) + \
|
||||
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)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_AUDIO_CONFIG_DESC_SIZ, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
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, 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_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(0x01, 0x04, 0x02, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET,
|
||||
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(0x01, 0x04, 0x02, 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)),
|
||||
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
|
||||
AUDIO_AS_DESCRIPTOR_INIT(0x02, 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))
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
@@ -152,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_AUDIO_CONFIG_DESC_SIZ, 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, 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),
|
||||
#if USING_FEEDBACK == 0
|
||||
AUDIO_AS_DESCRIPTOR_INIT(0x01, 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)),
|
||||
#else
|
||||
AUDIO_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x04, 0x02, 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
|
||||
AUDIO_AS_DESCRIPTOR_INIT(0x02, 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)),
|
||||
///////////////////////////////////////
|
||||
/// 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];
|
||||
@@ -393,13 +350,12 @@ struct audio_entity_info audio_entity_table[] = {
|
||||
.ep = AUDIO_OUT_EP },
|
||||
};
|
||||
|
||||
// In windows, audio driver cannot remove auto, so when you modify any descriptor information, please modify string descriptors too.
|
||||
|
||||
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));
|
||||
|
||||
@@ -22,17 +22,17 @@
|
||||
#define AUDIO_IN_CLOCK_ID 0x01
|
||||
#define AUDIO_IN_FU_ID 0x03
|
||||
|
||||
#define AUDIO_IN_MAX_FREQ 16000
|
||||
#define HALF_WORD_BYTES 2 //2 half word (one channel)
|
||||
#define SAMPLE_BITS 16 //16 bit per channel
|
||||
#define AUDIO_IN_MAX_FREQ 96000
|
||||
#define AUDIO_MIC_FRAME_SIZE_BYTE 2u
|
||||
#define AUDIO_MIC_RESOLUTION_BIT 16u
|
||||
|
||||
#define BMCONTROL (AUDIO_V2_FU_CONTROL_MUTE | AUDIO_V2_FU_CONTROL_VOLUME)
|
||||
#define BMCONTROL (AUDIO_V2_CONTROL_MUTE | AUDIO_V2_CONTROL_VOLUME)
|
||||
|
||||
#define IN_CHANNEL_NUM 2
|
||||
|
||||
#if IN_CHANNEL_NUM == 1
|
||||
#define INPUT_CTRL DBVAL(BMCONTROL), DBVAL(BMCONTROL)
|
||||
#define INPUT_CH_ENABLE 0x00000000
|
||||
#define INPUT_CH_ENABLE 0x00000001
|
||||
#elif IN_CHANNEL_NUM == 2
|
||||
#define INPUT_CTRL DBVAL(BMCONTROL), DBVAL(BMCONTROL), DBVAL(BMCONTROL)
|
||||
#define INPUT_CH_ENABLE 0x00000003
|
||||
@@ -56,15 +56,15 @@
|
||||
#define INPUT_CH_ENABLE 0x000000ff
|
||||
#endif
|
||||
|
||||
#define AUDIO_IN_PACKET ((uint32_t)((AUDIO_IN_MAX_FREQ * HALF_WORD_BYTES * IN_CHANNEL_NUM) / 1000))
|
||||
#define AUDIO_IN_PACKET ((uint32_t)((AUDIO_IN_MAX_FREQ * AUDIO_MIC_FRAME_SIZE_BYTE * IN_CHANNEL_NUM) / 1000))
|
||||
|
||||
#define USB_AUDIO_CONFIG_DESC_SIZ (9 + \
|
||||
AUDIO_V2_AC_DESCRIPTOR_INIT_LEN + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(IN_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_AS_DESCRIPTOR_INIT_LEN)
|
||||
#define USB_CONFIG_SIZE (9 + \
|
||||
AUDIO_V2_AC_DESCRIPTOR_LEN + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(IN_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_AS_DESCRIPTOR_LEN)
|
||||
|
||||
#define AUDIO_AC_SIZ (AUDIO_V2_SIZEOF_AC_HEADER_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
@@ -72,19 +72,18 @@
|
||||
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)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_AUDIO_CONFIG_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
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(0x01, 0x03, 0x03),
|
||||
AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_INTERM_MIC, 0x01, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
|
||||
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x03, 0x02, INPUT_CTRL),
|
||||
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, 0x03, 0x01, 0x0000),
|
||||
AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x04, IN_CHANNEL_NUM, INPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL)
|
||||
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)
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
@@ -139,96 +138,24 @@ 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_AUDIO_CONFIG_DESC_SIZ, 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(0x01, 0x03, 0x03),
|
||||
AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_INTERM_MIC, 0x01, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
|
||||
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x03, 0x02, INPUT_CTRL),
|
||||
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, 0x03, 0x01, 0x0000),
|
||||
AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x04, IN_CHANNEL_NUM, INPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, 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(1),
|
||||
AUDIO_SAMPLE_FREQ_NUM(5),
|
||||
AUDIO_SAMPLE_FREQ_4B(8000),
|
||||
AUDIO_SAMPLE_FREQ_4B(8000),
|
||||
AUDIO_SAMPLE_FREQ_4B(0x00),
|
||||
AUDIO_SAMPLE_FREQ_4B(16000),
|
||||
AUDIO_SAMPLE_FREQ_4B(16000),
|
||||
AUDIO_SAMPLE_FREQ_4B(0x00)
|
||||
AUDIO_SAMPLE_FREQ_4B(0x00),
|
||||
AUDIO_SAMPLE_FREQ_4B(32000),
|
||||
AUDIO_SAMPLE_FREQ_4B(32000),
|
||||
AUDIO_SAMPLE_FREQ_4B(0x00),
|
||||
AUDIO_SAMPLE_FREQ_4B(48000),
|
||||
AUDIO_SAMPLE_FREQ_4B(48000),
|
||||
AUDIO_SAMPLE_FREQ_4B(0x00),
|
||||
AUDIO_SAMPLE_FREQ_4B(96000),
|
||||
AUDIO_SAMPLE_FREQ_4B(96000),
|
||||
AUDIO_SAMPLE_FREQ_4B(0x00),
|
||||
};
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[AUDIO_IN_PACKET];
|
||||
@@ -323,13 +250,12 @@ struct audio_entity_info audio_entity_table[] = {
|
||||
.ep = AUDIO_IN_EP },
|
||||
};
|
||||
|
||||
// In windows, audio driver cannot remove auto, so when you modify any descriptor information, please modify string descriptors too.
|
||||
|
||||
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);
|
||||
|
||||
@@ -30,19 +30,21 @@
|
||||
#define AUDIO_IN_CLOCK_ID 0x05
|
||||
#define AUDIO_IN_FU_ID 0x07
|
||||
|
||||
#define AUDIO_OUT_MAX_FREQ 96000
|
||||
#define AUDIO_IN_MAX_FREQ 16000
|
||||
#define AUDIO_OUT_MAX_FREQ 96000
|
||||
#define AUDIO_SPEAKER_FRAME_SIZE_BYTE 2u
|
||||
#define AUDIO_SPEAKER_RESOLUTION_BIT 16u
|
||||
|
||||
#define HALF_WORD_BYTES 2 //2 half word (one channel)
|
||||
#define SAMPLE_BITS 16 //16 bit per channel
|
||||
#define AUDIO_IN_MAX_FREQ 96000
|
||||
#define AUDIO_MIC_FRAME_SIZE_BYTE 2u
|
||||
#define AUDIO_MIC_RESOLUTION_BIT 16u
|
||||
|
||||
#define BMCONTROL (AUDIO_V2_FU_CONTROL_MUTE | AUDIO_V2_FU_CONTROL_VOLUME)
|
||||
#define BMCONTROL (AUDIO_V2_CONTROL_MUTE | AUDIO_V2_CONTROL_VOLUME)
|
||||
|
||||
#define IN_CHANNEL_NUM 2
|
||||
|
||||
#if IN_CHANNEL_NUM == 1
|
||||
#define INPUT_CTRL DBVAL(BMCONTROL), DBVAL(BMCONTROL)
|
||||
#define INPUT_CH_ENABLE 0x00000000
|
||||
#define INPUT_CH_ENABLE 0x00000001
|
||||
#elif IN_CHANNEL_NUM == 2
|
||||
#define INPUT_CTRL DBVAL(BMCONTROL), DBVAL(BMCONTROL), DBVAL(BMCONTROL)
|
||||
#define INPUT_CH_ENABLE 0x00000003
|
||||
@@ -70,7 +72,7 @@
|
||||
|
||||
#if OUT_CHANNEL_NUM == 1
|
||||
#define OUTPUT_CTRL DBVAL(BMCONTROL), DBVAL(BMCONTROL)
|
||||
#define OUTPUT_CH_ENABLE 0x00000000
|
||||
#define OUTPUT_CH_ENABLE 0x00000001
|
||||
#elif OUT_CHANNEL_NUM == 2
|
||||
#define OUTPUT_CTRL DBVAL(BMCONTROL), DBVAL(BMCONTROL), DBVAL(BMCONTROL)
|
||||
#define OUTPUT_CH_ENABLE 0x00000003
|
||||
@@ -95,35 +97,35 @@
|
||||
#endif
|
||||
|
||||
/* AudioFreq * DataSize (2 bytes) * NumChannels */
|
||||
#define AUDIO_OUT_PACKET ((uint32_t)((AUDIO_OUT_MAX_FREQ * HALF_WORD_BYTES * OUT_CHANNEL_NUM) / 1000))
|
||||
#define AUDIO_IN_PACKET ((uint32_t)((AUDIO_IN_MAX_FREQ * HALF_WORD_BYTES * IN_CHANNEL_NUM) / 1000))
|
||||
#define AUDIO_OUT_PACKET ((uint32_t)((AUDIO_OUT_MAX_FREQ * AUDIO_SPEAKER_FRAME_SIZE_BYTE * OUT_CHANNEL_NUM) / 1000))
|
||||
#define AUDIO_IN_PACKET ((uint32_t)((AUDIO_IN_MAX_FREQ * AUDIO_MIC_FRAME_SIZE_BYTE * IN_CHANNEL_NUM) / 1000))
|
||||
|
||||
#if USING_FEEDBACK == 0
|
||||
#define USB_AUDIO_CONFIG_DESC_SIZ (9 + \
|
||||
AUDIO_V2_AC_DESCRIPTOR_INIT_LEN + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(OUT_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(IN_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_AS_DESCRIPTOR_INIT_LEN + \
|
||||
AUDIO_V2_AS_DESCRIPTOR_INIT_LEN)
|
||||
#define USB_CONFIG_SIZE (9 + \
|
||||
AUDIO_V2_AC_DESCRIPTOR_LEN + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(OUT_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(IN_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_AS_DESCRIPTOR_LEN + \
|
||||
AUDIO_V2_AS_DESCRIPTOR_LEN)
|
||||
#else
|
||||
#define USB_AUDIO_CONFIG_DESC_SIZ (9 + \
|
||||
AUDIO_V2_AC_DESCRIPTOR_INIT_LEN + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(OUT_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(IN_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT_LEN + \
|
||||
AUDIO_V2_AS_DESCRIPTOR_INIT_LEN)
|
||||
#define USB_CONFIG_SIZE (9 + \
|
||||
AUDIO_V2_AC_DESCRIPTOR_LEN + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(OUT_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(IN_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_LEN + \
|
||||
AUDIO_V2_AS_DESCRIPTOR_LEN)
|
||||
#endif
|
||||
|
||||
#define AUDIO_AC_SIZ (AUDIO_V2_SIZEOF_AC_HEADER_DESC + \
|
||||
@@ -136,28 +138,27 @@
|
||||
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)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_AUDIO_CONFIG_DESC_SIZ, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
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(0x01, 0x03, 0x03),
|
||||
AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_TERMINAL_STREAMING, 0x01, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, 0x0000),
|
||||
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x03, 0x02, OUTPUT_CTRL),
|
||||
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_OUTTERM_SPEAKER, 0x03, 0x01, 0x0000),
|
||||
AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(0x05, 0x03, 0x03),
|
||||
AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_INTERM_MIC, 0x05, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
|
||||
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x07, 0x06, INPUT_CTRL),
|
||||
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x08, AUDIO_TERMINAL_STREAMING, 0x07, 0x05, 0x0000),
|
||||
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, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL),
|
||||
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, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL, AUDIO_OUT_FEEDBACK_EP),
|
||||
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, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL)
|
||||
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)
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
@@ -212,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_AUDIO_CONFIG_DESC_SIZ, 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(0x01, 0x03, 0x03),
|
||||
AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_TERMINAL_STREAMING, 0x01, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, 0x0000),
|
||||
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x03, 0x02, OUTPUT_CTRL),
|
||||
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_OUTTERM_SPEAKER, 0x03, 0x01, 0x0000),
|
||||
AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(0x05, 0x03, 0x03),
|
||||
AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_INTERM_MIC, 0x05, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
|
||||
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x07, 0x06, INPUT_CTRL),
|
||||
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x08, AUDIO_TERMINAL_STREAMING, 0x07, 0x05, 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, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL, AUDIO_OUT_FEEDBACK_EP),
|
||||
#endif
|
||||
AUDIO_V2_AS_DESCRIPTOR_INIT(0x02, 0x08, IN_CHANNEL_NUM, INPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, 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),
|
||||
@@ -330,9 +234,21 @@ static const uint8_t speaker_default_sampling_freq_table[] = {
|
||||
};
|
||||
|
||||
static const uint8_t mic_default_sampling_freq_table[] = {
|
||||
AUDIO_SAMPLE_FREQ_NUM(1),
|
||||
AUDIO_SAMPLE_FREQ_NUM(5),
|
||||
AUDIO_SAMPLE_FREQ_4B(8000),
|
||||
AUDIO_SAMPLE_FREQ_4B(8000),
|
||||
AUDIO_SAMPLE_FREQ_4B(0x00),
|
||||
AUDIO_SAMPLE_FREQ_4B(16000),
|
||||
AUDIO_SAMPLE_FREQ_4B(16000),
|
||||
AUDIO_SAMPLE_FREQ_4B(0x00),
|
||||
AUDIO_SAMPLE_FREQ_4B(32000),
|
||||
AUDIO_SAMPLE_FREQ_4B(32000),
|
||||
AUDIO_SAMPLE_FREQ_4B(0x00),
|
||||
AUDIO_SAMPLE_FREQ_4B(48000),
|
||||
AUDIO_SAMPLE_FREQ_4B(48000),
|
||||
AUDIO_SAMPLE_FREQ_4B(0x00),
|
||||
AUDIO_SAMPLE_FREQ_4B(96000),
|
||||
AUDIO_SAMPLE_FREQ_4B(96000),
|
||||
AUDIO_SAMPLE_FREQ_4B(0x00)
|
||||
};
|
||||
|
||||
@@ -501,13 +417,12 @@ struct audio_entity_info audio_entity_table[] = {
|
||||
.ep = AUDIO_IN_EP },
|
||||
};
|
||||
|
||||
// In windows, audio driver cannot remove auto, so when you modify any descriptor information, please modify string descriptors too.
|
||||
|
||||
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));
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
#define HALF_WORD_BYTES 2 //2 half word (one channel)
|
||||
#define SAMPLE_BITS 16 //16 bit per channel
|
||||
|
||||
#define BMCONTROL (AUDIO_V2_FU_CONTROL_MUTE | AUDIO_V2_FU_CONTROL_VOLUME)
|
||||
#define BMCONTROL (AUDIO_V2_CONTROL_MUTE | AUDIO_V2_CONTROL_VOLUME)
|
||||
|
||||
#define OUT_CHANNEL_NUM 2
|
||||
|
||||
#if OUT_CHANNEL_NUM == 1
|
||||
#define OUTPUT_CTRL DBVAL(BMCONTROL), DBVAL(BMCONTROL)
|
||||
#define OUTPUT_CH_ENABLE 0x00000000
|
||||
#define OUTPUT_CH_ENABLE 0x00000001
|
||||
#elif OUT_CHANNEL_NUM == 2
|
||||
#define OUTPUT_CTRL DBVAL(BMCONTROL), DBVAL(BMCONTROL), DBVAL(BMCONTROL)
|
||||
#define OUTPUT_CH_ENABLE 0x00000003
|
||||
@@ -64,21 +64,21 @@
|
||||
#define AUDIO_OUT_PACKET ((uint32_t)((AUDIO_OUT_MAX_FREQ * HALF_WORD_BYTES * OUT_CHANNEL_NUM) / 1000))
|
||||
|
||||
#if USING_FEEDBACK == 0
|
||||
#define USB_AUDIO_CONFIG_DESC_SIZ (9 + \
|
||||
AUDIO_V2_AC_DESCRIPTOR_INIT_LEN + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(OUT_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_AS_DESCRIPTOR_INIT_LEN)
|
||||
#define USB_CONFIG_SIZE (9 + \
|
||||
AUDIO_V2_AC_DESCRIPTOR_LEN + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(OUT_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_AS_DESCRIPTOR_LEN)
|
||||
#else
|
||||
#define USB_AUDIO_CONFIG_DESC_SIZ (9 + \
|
||||
AUDIO_V2_AC_DESCRIPTOR_INIT_LEN + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(OUT_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT_LEN)
|
||||
#define USB_CONFIG_SIZE (9 + \
|
||||
AUDIO_V2_AC_DESCRIPTOR_LEN + \
|
||||
AUDIO_V2_SIZEOF_AC_CLOCK_SOURCE_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_INPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(OUT_CHANNEL_NUM) + \
|
||||
AUDIO_V2_SIZEOF_AC_OUTPUT_TERMINAL_DESC + \
|
||||
AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_LEN)
|
||||
#endif
|
||||
|
||||
#define AUDIO_AC_SIZ (AUDIO_V2_SIZEOF_AC_HEADER_DESC + \
|
||||
@@ -87,18 +87,17 @@
|
||||
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)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_AUDIO_CONFIG_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
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, 0x01, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, 0x0000),
|
||||
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, 0x03, 0x01, 0x0000),
|
||||
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
|
||||
@@ -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_AUDIO_CONFIG_DESC_SIZ, 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, 0x01, 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, 0x03, 0x01, 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),
|
||||
@@ -397,13 +304,12 @@ struct audio_entity_info audio_entity_table[] = {
|
||||
.ep = AUDIO_OUT_EP },
|
||||
};
|
||||
|
||||
// In windows, audio driver cannot remove auto, so when you modify any descriptor information, please modify string descriptors too.
|
||||
|
||||
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)
|
||||
};
|
||||
@@ -52,37 +51,7 @@ static const uint8_t config_descriptor[] = {
|
||||
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),
|
||||
/************** Descriptor of Joystick Mouse interface ****************/
|
||||
/* 09 */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
||||
0x03, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x01, /* bNumEndpoints */
|
||||
0x03, /* bInterfaceClass: HID */
|
||||
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
|
||||
0x02, /* 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_MOUSE_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 */
|
||||
HID_MOUSE_DESCRIPTOR_INIT(0x03, 0x01, HID_MOUSE_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
@@ -137,117 +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),
|
||||
/************** Descriptor of Joystick Mouse interface ****************/
|
||||
/* 09 */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
||||
0x03, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x01, /* bNumEndpoints */
|
||||
0x03, /* bInterfaceClass: HID */
|
||||
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
|
||||
0x02, /* 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_MOUSE_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 */
|
||||
///////////////////////////////////////
|
||||
/// 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] = {
|
||||
@@ -399,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);
|
||||
|
||||
@@ -29,22 +29,16 @@
|
||||
#define CDC_MAX_MPS 64
|
||||
#endif
|
||||
|
||||
#define CDC_ECM_ETH_STATISTICS_BITMAP 0x00000000
|
||||
|
||||
/* str idx = 4 is for mac address: aa:bb:cc:dd:ee:ff*/
|
||||
#define CDC_ECM_MAC_STRING_INDEX 4
|
||||
|
||||
/* Ethernet Maximum Segment size, typically 1514 bytes */
|
||||
#define CONFIG_CDC_ECM_ETH_MAX_SEGSZE 1514U
|
||||
|
||||
#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)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
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_ETH_STATISTICS_BITMAP, CONFIG_CDC_ECM_ETH_MAX_SEGSZE, 0, 0, CDC_ECM_MAC_STRING_INDEX)
|
||||
CDC_ECM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, CDC_ECM_MAC_STRING_INDEX)
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
@@ -88,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];
|
||||
@@ -100,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_ETH_STATISTICS_BITMAP, CONFIG_CDC_ECM_ETH_MAX_SEGSZE, 0, 0, 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 };
|
||||
|
||||
@@ -464,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);
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : main.c
|
||||
* @brief : Main program body
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "usbd_core.h"
|
||||
#include "usb_dfu.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PTD */
|
||||
|
||||
/* USER CODE END PTD */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PM */
|
||||
|
||||
/* USER CODE END PM */
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
UART_HandleTypeDef huart1;
|
||||
|
||||
PCD_HandleTypeDef hpcd_USB_FS;
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
void SystemClock_Config(void);
|
||||
static void MX_GPIO_Init(void);
|
||||
static void MX_USART1_UART_Init(void);
|
||||
static void MX_USB_PCD_Init(void);
|
||||
/* USER CODE BEGIN PFP */
|
||||
typedef void (*pFunction)(void);
|
||||
static void jump_app(void)
|
||||
{
|
||||
pFunction JumpToApplication;
|
||||
uint32_t JumpAddress;
|
||||
|
||||
if (((*(__IO uint32_t *)USBD_DFU_APP_DEFAULT_ADD) & 0x2FFFB000) == 0x20000000)
|
||||
{
|
||||
/* Jump to user application */
|
||||
/*!< Jump to app reset_handler */
|
||||
JumpAddress = *(__IO uint32_t *)(USBD_DFU_APP_DEFAULT_ADD + 4);
|
||||
JumpToApplication = (pFunction)JumpAddress;
|
||||
|
||||
/* Initialize user application's Stack Pointer */
|
||||
__set_MSP(*(__IO uint32_t *)USBD_DFU_APP_DEFAULT_ADD);
|
||||
JumpToApplication();
|
||||
}
|
||||
}
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* Private user code ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN 0 */
|
||||
int fputc(int ch, FILE *f)
|
||||
{
|
||||
while ((USART1->SR & USART_SR_TXE) == 0)
|
||||
;
|
||||
USART1->DR = ch;
|
||||
return ch;
|
||||
}
|
||||
|
||||
void usb_dc_low_level_init(void)
|
||||
{
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_USB_CLK_ENABLE();
|
||||
/* USB interrupt Init */
|
||||
HAL_NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||
|
||||
}
|
||||
|
||||
uint8_t *dfu_read_flash(uint8_t *src, uint8_t *dest, uint32_t len)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint8_t *psrc = src;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
dest[i] = *psrc++;
|
||||
}
|
||||
/* Return a valid address to avoid HardFault */
|
||||
return (uint8_t *)(dest);
|
||||
}
|
||||
|
||||
uint16_t dfu_write_flash(uint8_t *src, uint8_t *dest, uint32_t len)
|
||||
{
|
||||
HAL_FLASH_Unlock();
|
||||
uint32_t i = 0;
|
||||
|
||||
for (i = 0; i < len; i += 4)
|
||||
{
|
||||
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
|
||||
* be done by byte */
|
||||
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t)(dest + i),
|
||||
*(uint32_t *)(src + i)) == HAL_OK)
|
||||
{
|
||||
/* Check the written value */
|
||||
if (*(uint32_t *)(src + i) != *(uint32_t *)(dest + i))
|
||||
{
|
||||
/* Flash content doesn't match SRAM content */
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Error occurred while writing data in Flash memory */
|
||||
return (2);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t dfu_erase_flash(uint32_t add)
|
||||
{
|
||||
HAL_FLASH_Unlock();
|
||||
uint32_t PageError;
|
||||
/* Variable contains Flash operation status */
|
||||
HAL_StatusTypeDef status;
|
||||
FLASH_EraseInitTypeDef eraseinitstruct;
|
||||
|
||||
eraseinitstruct.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
eraseinitstruct.PageAddress = add;
|
||||
eraseinitstruct.NbPages = 1U;
|
||||
status = HAL_FLASHEx_Erase(&eraseinitstruct, &PageError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dfu_leave(void)
|
||||
{
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/**
|
||||
* @brief The application entry point.
|
||||
* @retval int
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
/* USER CODE BEGIN 1 */
|
||||
jump_app();
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/* MCU Configuration--------------------------------------------------------*/
|
||||
|
||||
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
|
||||
HAL_Init();
|
||||
|
||||
/* USER CODE BEGIN Init */
|
||||
|
||||
/* USER CODE END Init */
|
||||
|
||||
/* Configure the system clock */
|
||||
SystemClock_Config();
|
||||
|
||||
/* USER CODE BEGIN SysInit */
|
||||
|
||||
/* USER CODE END SysInit */
|
||||
|
||||
/* Initialize all configured peripherals */
|
||||
MX_GPIO_Init();
|
||||
MX_USART1_UART_Init();
|
||||
//MX_USB_PCD_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
|
||||
// extern void cdc_acm_msc_init(void);
|
||||
// cdc_acm_msc_init();
|
||||
extern void dfu_flash_init(void);
|
||||
dfu_flash_init();
|
||||
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* Infinite loop */
|
||||
/* USER CODE BEGIN WHILE */
|
||||
while (1) {
|
||||
/* USER CODE END WHILE */
|
||||
|
||||
/* USER CODE BEGIN 3 */
|
||||
// extern void cdc_acm_data_send_with_dtr_test(void);
|
||||
// cdc_acm_data_send_with_dtr_test();
|
||||
// HAL_Delay(100);
|
||||
}
|
||||
/* USER CODE END 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief System Clock Configuration
|
||||
* @retval None
|
||||
*/
|
||||
void SystemClock_Config(void)
|
||||
{
|
||||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
||||
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
|
||||
|
||||
/** Initializes the RCC Oscillators according to the specified parameters
|
||||
* in the RCC_OscInitTypeDef structure.
|
||||
*/
|
||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
|
||||
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
|
||||
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
|
||||
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
||||
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
|
||||
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/** Initializes the CPU, AHB and APB buses clocks
|
||||
*/
|
||||
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|
||||
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
||||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
||||
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
||||
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
|
||||
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
|
||||
|
||||
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
|
||||
PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
|
||||
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USART1 Initialization Function
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void MX_USART1_UART_Init(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN USART1_Init 0 */
|
||||
|
||||
/* USER CODE END USART1_Init 0 */
|
||||
|
||||
/* USER CODE BEGIN USART1_Init 1 */
|
||||
|
||||
/* USER CODE END USART1_Init 1 */
|
||||
huart1.Instance = USART1;
|
||||
huart1.Init.BaudRate = 115200;
|
||||
huart1.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
huart1.Init.StopBits = UART_STOPBITS_1;
|
||||
huart1.Init.Parity = UART_PARITY_NONE;
|
||||
huart1.Init.Mode = UART_MODE_TX_RX;
|
||||
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
if (HAL_UART_Init(&huart1) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN USART1_Init 2 */
|
||||
|
||||
/* USER CODE END USART1_Init 2 */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USB Initialization Function
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void MX_USB_PCD_Init(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN USB_Init 0 */
|
||||
|
||||
/* USER CODE END USB_Init 0 */
|
||||
|
||||
/* USER CODE BEGIN USB_Init 1 */
|
||||
|
||||
/* USER CODE END USB_Init 1 */
|
||||
hpcd_USB_FS.Instance = USB;
|
||||
hpcd_USB_FS.Init.dev_endpoints = 8;
|
||||
hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;
|
||||
hpcd_USB_FS.Init.low_power_enable = DISABLE;
|
||||
hpcd_USB_FS.Init.lpm_enable = DISABLE;
|
||||
hpcd_USB_FS.Init.battery_charging_enable = DISABLE;
|
||||
if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN USB_Init 2 */
|
||||
|
||||
/* USER CODE END USB_Init 2 */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GPIO Initialization Function
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void MX_GPIO_Init(void)
|
||||
{
|
||||
|
||||
/* GPIO Ports Clock Enable */
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 4 */
|
||||
|
||||
/* USER CODE END 4 */
|
||||
|
||||
/**
|
||||
* @brief This function is executed in case of error occurrence.
|
||||
* @retval None
|
||||
*/
|
||||
void Error_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN Error_Handler_Debug */
|
||||
/* User can add his own implementation to report the HAL error return state */
|
||||
__disable_irq();
|
||||
while (1) {
|
||||
}
|
||||
/* USER CODE END Error_Handler_Debug */
|
||||
}
|
||||
|
||||
#ifdef USE_FULL_ASSERT
|
||||
/**
|
||||
* @brief Reports the name of the source file and the source line number
|
||||
* where the assert_param error has occurred.
|
||||
* @param file: pointer to the source file name
|
||||
* @param line: assert_param error line source number
|
||||
* @retval None
|
||||
*/
|
||||
void assert_failed(uint8_t *file, uint32_t line)
|
||||
{
|
||||
/* USER CODE BEGIN 6 */
|
||||
/* User can add his own implementation to report the file name and line number,
|
||||
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
|
||||
/* USER CODE END 6 */
|
||||
}
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
157
demo/dfu_template.c
Normal file
157
demo/dfu_template.c
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2022 ~ 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_dfu.h"
|
||||
|
||||
#define USBD_VID 0x0483
|
||||
#define USBD_PID 0xdf11
|
||||
#define USBD_MAX_POWER 100
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
#define USB_CONFIG_SIZE (9 + DFU_DESCRIPTOR_LEN)
|
||||
|
||||
#define FLASH_DESC_STR "@Internal Flash /0x08000000/16*128Kg"
|
||||
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
DFU_DESCRIPTOR_INIT(4)
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
static const char *string_descriptors[] = {
|
||||
(const char[]){ 0x09, 0x04 }, /* Langid */
|
||||
"CherryUSB", /* Manufacturer */
|
||||
"CherryUSB DFU DEMO", /* Product */
|
||||
"2022123456", /* Serial Number */
|
||||
FLASH_DESC_STR
|
||||
};
|
||||
|
||||
static const uint8_t *device_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return device_descriptor;
|
||||
}
|
||||
|
||||
static const uint8_t *config_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return config_descriptor;
|
||||
}
|
||||
|
||||
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return device_quality_descriptor;
|
||||
}
|
||||
|
||||
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
|
||||
{
|
||||
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return string_descriptors[index];
|
||||
}
|
||||
|
||||
const struct usb_descriptor dfu_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
|
||||
};
|
||||
|
||||
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:
|
||||
break;
|
||||
case USBD_EVENT_SET_REMOTE_WAKEUP:
|
||||
break;
|
||||
case USBD_EVENT_CLR_REMOTE_WAKEUP:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct usbd_interface intf0;
|
||||
|
||||
void dfu_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
usbd_desc_register(busid, &dfu_descriptor);
|
||||
|
||||
usbd_add_interface(busid, usbd_dfu_init_intf(&intf0));
|
||||
usbd_initialize(busid, reg_base, usbd_event_handler);
|
||||
}
|
||||
|
||||
volatile uint32_t flash_start_address;
|
||||
|
||||
void usbd_dfu_begin_load(void)
|
||||
{
|
||||
flash_start_address = 0x08000000;
|
||||
}
|
||||
|
||||
void usbd_dfu_end_load(void)
|
||||
{
|
||||
}
|
||||
|
||||
void usbd_dfu_reset(void)
|
||||
{
|
||||
//NVIC_SystemReset();
|
||||
}
|
||||
|
||||
int usbd_dfu_write(uint16_t value, const uint8_t *data, uint16_t length)
|
||||
{
|
||||
//usb_hexdump(data, length);
|
||||
|
||||
// patch for stm32 special command
|
||||
#if 1
|
||||
if (value == 0) {
|
||||
if (data[0] == DFU_SPECIAL_CMD_SET_ADDRESS_POINTER) {
|
||||
memcpy((uint8_t *)&flash_start_address, data, 4);
|
||||
} else if (data[0] == DFU_SPECIAL_CMD_ERASE) {
|
||||
memcpy((uint8_t *)&flash_start_address, data, 4);
|
||||
}
|
||||
} else if (value > 1) {
|
||||
uint32_t addr = (value - 2) * CONFIG_USBDEV_REQUEST_BUFFER_LEN + flash_start_address;
|
||||
}
|
||||
#else
|
||||
flash_start_address += length;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_dfu_read(uint16_t value, const uint8_t *data, uint16_t length, uint16_t *actual_length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_dfu.h"
|
||||
|
||||
#define USBD_VID 0x0483
|
||||
#define USBD_PID 0xDF11
|
||||
#define USBD_MAX_POWER 100
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
#define FLASH_DESC_STR "@Internal Flash /0x08000000/16*001Ka,112*01Kg"
|
||||
|
||||
#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)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
DFU_DESCRIPTOR_INIT()
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
static const char *string_descriptors[] = {
|
||||
(const char[]){ 0x09, 0x04 }, /* Langid */
|
||||
"CherryUSB", /* Manufacturer */
|
||||
"CherryUSB DFU DEMO", /* Product */
|
||||
"2022123456", /* Serial Number */
|
||||
};
|
||||
|
||||
static const uint8_t *device_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return device_descriptor;
|
||||
}
|
||||
|
||||
static const uint8_t *config_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return config_descriptor;
|
||||
}
|
||||
|
||||
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return device_quality_descriptor;
|
||||
}
|
||||
|
||||
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
|
||||
{
|
||||
if (index > 3) {
|
||||
return NULL;
|
||||
}
|
||||
return string_descriptors[index];
|
||||
}
|
||||
|
||||
const struct usb_descriptor dfu_flash_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
|
||||
};
|
||||
#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)
|
||||
{
|
||||
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:
|
||||
break;
|
||||
case USBD_EVENT_SET_REMOTE_WAKEUP:
|
||||
break;
|
||||
case USBD_EVENT_CLR_REMOTE_WAKEUP:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
3
demo/display/README.md
Normal file
3
demo/display/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Thanks to https://github.com/chuanjinpang/win10_idd_xfz1986_usb_graphic_driver_display project.
|
||||
|
||||
Install tools/display/xfz1986_usb_graphic_250224_rc_sign.exe in windows before use.
|
||||
146
demo/display/usbdisplay_template.c
Normal file
146
demo/display/usbdisplay_template.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) 2026, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_display.h"
|
||||
|
||||
#define DISPLAY_IN_EP 0x81
|
||||
#define DISPLAY_OUT_EP 0x02
|
||||
|
||||
#define USBD_VID 0x303A
|
||||
#define USBD_PID 0x2987
|
||||
#define USBD_MAX_POWER 100
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
#define USB_CONFIG_SIZE (9 + 9 + 7 + 7)
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
#define DISPLAY_EP_MPS 512
|
||||
#else
|
||||
#define DISPLAY_EP_MPS 64
|
||||
#endif
|
||||
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0101, 0x01)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x00),
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_IN_EP, 0x02, DISPLAY_EP_MPS, 0x00),
|
||||
USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_OUT_EP, 0x02, DISPLAY_EP_MPS, 0x00),
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x00,
|
||||
0x00,
|
||||
};
|
||||
|
||||
static const char *string_descriptors[] = {
|
||||
(const char[]){ 0x09, 0x04 }, /* Langid */
|
||||
"CherryUSB", /* Manufacturer */
|
||||
"cherryusb_R640x480_Ergb16_Fps30_Bl128", /* Product */
|
||||
// "cherryusb_R640x480_Ejpg9_Fps30_Bl128", /* Product */
|
||||
"2022123456", /* Serial Number */
|
||||
};
|
||||
|
||||
static const uint8_t *device_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return device_descriptor;
|
||||
}
|
||||
|
||||
static const uint8_t *config_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return config_descriptor;
|
||||
}
|
||||
|
||||
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
|
||||
{
|
||||
return device_quality_descriptor;
|
||||
}
|
||||
|
||||
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
|
||||
{
|
||||
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return string_descriptors[index];
|
||||
}
|
||||
|
||||
const struct usb_descriptor usbdisplay_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
|
||||
};
|
||||
|
||||
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:
|
||||
break;
|
||||
case USBD_EVENT_SET_REMOTE_WAKEUP:
|
||||
break;
|
||||
case USBD_EVENT_CLR_REMOTE_WAKEUP:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct usbd_interface intf0;
|
||||
|
||||
struct usbd_display_frame frame_pool[2];
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usb_display_buffer[2][640 * 480 * 2];
|
||||
|
||||
void usbdisplay_init(uint8_t busid, uintptr_t reg_base)
|
||||
{
|
||||
frame_pool[0].frame_buf = usb_display_buffer[0];
|
||||
frame_pool[0].frame_bufsize = 640 * 480 * 2;
|
||||
frame_pool[1].frame_buf = usb_display_buffer[1];
|
||||
frame_pool[1].frame_bufsize = 640 * 480 * 2;
|
||||
|
||||
usbd_desc_register(busid, &usbdisplay_descriptor);
|
||||
|
||||
usbd_add_interface(busid, usbd_display_init_intf(&intf0, DISPLAY_OUT_EP, DISPLAY_IN_EP, frame_pool, 2));
|
||||
usbd_initialize(busid, reg_base, usbd_event_handler);
|
||||
}
|
||||
|
||||
void usbdisplay_poll(void)
|
||||
{
|
||||
struct usbd_display_frame *frame;
|
||||
int ret;
|
||||
|
||||
ret = usbd_display_dequeue(&frame, 0xffffffff); // timeout is not useful for baremental
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
USB_LOG_INFO("frame type: %u, frame size %u\r\n", frame->frame_format, frame->frame_size);
|
||||
usbd_display_enqueue(frame);
|
||||
}
|
||||
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) {
|
||||
}
|
||||
}
|
||||
@@ -8,25 +8,8 @@
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_hid.h"
|
||||
|
||||
|
||||
/*!< hidraw in endpoint */
|
||||
#define HIDRAW_IN_EP 0x81
|
||||
#ifdef CONFIG_USB_HS
|
||||
#define HIDRAW_IN_EP_SIZE 1024
|
||||
#define HIDRAW_IN_INTERVAL 4
|
||||
#else
|
||||
#define HIDRAW_IN_EP_SIZE 64
|
||||
#define HIDRAW_IN_INTERVAL 10
|
||||
#endif
|
||||
/*!< hidraw out endpoint */
|
||||
#define HIDRAW_OUT_EP 0x02
|
||||
#ifdef CONFIG_USB_HS
|
||||
#define HIDRAW_OUT_EP_SIZE 1024
|
||||
#define HIDRAW_OUT_EP_INTERVAL 4
|
||||
#else
|
||||
#define HIDRAW_OUT_EP_SIZE 64
|
||||
#define HIDRAW_OUT_EP_INTERVAL 10
|
||||
#endif
|
||||
#define HIDRAW_IN_EP 0x81
|
||||
#define HIDRAW_OUT_EP 0x02
|
||||
|
||||
#define USBD_VID 0xffff
|
||||
#define USBD_PID 0xffff
|
||||
@@ -34,53 +17,26 @@
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
/*!< config descriptor size */
|
||||
#define USB_HID_CONFIG_DESC_SIZ (9 + 9 + 9 + 7 + 7)
|
||||
#define USB_CONFIG_SIZE (9 + 9 + 9 + 7 + 7)
|
||||
|
||||
/*!< custom hid report descriptor size */
|
||||
#define HID_CUSTOM_REPORT_DESC_SIZE 38
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
#ifdef CONFIG_USB_HS
|
||||
#define HID_MAX_MPS 1024
|
||||
#define HIDRAW_IN_INTERVAL 1
|
||||
#else
|
||||
#define HID_MAX_MPS 64
|
||||
#define HIDRAW_IN_INTERVAL 1
|
||||
#endif
|
||||
|
||||
static const uint8_t device_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
/************** Descriptor of Custom interface *****************/
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
||||
0x00, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x02, /* bNumEndpoints */
|
||||
0x03, /* bInterfaceClass: HID */
|
||||
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
|
||||
0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
|
||||
0, /* iInterface: Index of string descriptor */
|
||||
/******************** Descriptor of Custom HID ********************/
|
||||
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_CUSTOM_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
|
||||
0x00,
|
||||
/******************** Descriptor of Custom in endpoint ********************/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
|
||||
HIDRAW_IN_EP, /* bEndpointAddress: Endpoint Address (IN) */
|
||||
0x03, /* bmAttributes: Interrupt endpoint */
|
||||
WBVAL(HIDRAW_IN_EP_SIZE), /* wMaxPacketSize: 4 Byte max */
|
||||
HIDRAW_IN_INTERVAL, /* bInterval: Polling Interval */
|
||||
/******************** Descriptor of Custom out endpoint ********************/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
|
||||
HIDRAW_OUT_EP, /* bEndpointAddress: Endpoint Address (IN) */
|
||||
0x03, /* bmAttributes: Interrupt endpoint */
|
||||
WBVAL(HIDRAW_OUT_EP_SIZE), /* wMaxPacketSize: 4 Byte max */
|
||||
HIDRAW_OUT_EP_INTERVAL, /* bInterval: Polling Interval */
|
||||
/* 73 */
|
||||
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),
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
@@ -135,120 +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_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
/************** Descriptor of Custom interface *****************/
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
||||
0x00, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x02, /* bNumEndpoints */
|
||||
0x03, /* bInterfaceClass: HID */
|
||||
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
|
||||
0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
|
||||
0, /* iInterface: Index of string descriptor */
|
||||
/******************** Descriptor of Custom HID ********************/
|
||||
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_CUSTOM_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
|
||||
0x00,
|
||||
/******************** Descriptor of Custom in endpoint ********************/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
|
||||
HIDRAW_IN_EP, /* bEndpointAddress: Endpoint Address (IN) */
|
||||
0x03, /* bmAttributes: Interrupt endpoint */
|
||||
WBVAL(HIDRAW_IN_EP_SIZE), /* wMaxPacketSize: 4 Byte max */
|
||||
HIDRAW_IN_INTERVAL, /* bInterval: Polling Interval */
|
||||
/******************** Descriptor of Custom out endpoint ********************/
|
||||
0x07, /* bLength: Endpoint Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType: */
|
||||
HIDRAW_OUT_EP, /* bEndpointAddress: Endpoint Address (IN) */
|
||||
0x03, /* bmAttributes: Interrupt endpoint */
|
||||
WBVAL(HIDRAW_OUT_EP_SIZE), /* wMaxPacketSize: 4 Byte max */
|
||||
HIDRAW_OUT_EP_INTERVAL, /* bInterval: Polling Interval */
|
||||
/* 73 */
|
||||
/*
|
||||
* 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] = {
|
||||
@@ -261,16 +103,16 @@ static const uint8_t hid_custom_report_desc[HID_CUSTOM_REPORT_DESC_SIZE] = {
|
||||
0x09, 0x02, /* USAGE (Vendor Usage 1) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0xff, /*LOGICAL_MAXIMUM (255) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x96, 0xff, 0x03, /* REPORT_COUNT (63) */
|
||||
0x81, 0x02, /* INPUT (Data,Var,Abs) */
|
||||
/* <___________________________________________________> */
|
||||
0x85, 0x01, /* REPORT ID (0x01) */
|
||||
0x09, 0x03, /* USAGE (Vendor Usage 1) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0xff, /* LOGICAL_MAXIMUM (255) */
|
||||
0x25, 0xff, /* LOGICAL_MAXIMUM (255) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x96, 0xff, 0x03, /* REPORT_COUNT (63) */
|
||||
0x96, 0xff, 0x03, /* REPORT_COUNT (63) */
|
||||
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
|
||||
/* USER CODE END 0 */
|
||||
0xC0 /* END_COLLECTION */
|
||||
@@ -299,8 +141,8 @@ static const uint8_t hid_custom_report_desc[HID_CUSTOM_REPORT_DESC_SIZE] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[HIDRAW_OUT_EP_SIZE];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t send_buffer[HIDRAW_IN_EP_SIZE];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[HID_MAX_MPS];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t send_buffer[HID_MAX_MPS];
|
||||
|
||||
#define HID_STATE_IDLE 0
|
||||
#define HID_STATE_BUSY 1
|
||||
@@ -311,27 +153,27 @@ static volatile uint8_t custom_state;
|
||||
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:
|
||||
/* setup first out ep read transfer */
|
||||
usbd_ep_start_read(busid, HIDRAW_OUT_EP, read_buffer, HIDRAW_OUT_EP_SIZE);
|
||||
break;
|
||||
case USBD_EVENT_SET_REMOTE_WAKEUP:
|
||||
break;
|
||||
case USBD_EVENT_CLR_REMOTE_WAKEUP:
|
||||
break;
|
||||
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:
|
||||
/* setup first out ep read transfer */
|
||||
usbd_ep_start_read(busid, HIDRAW_OUT_EP, read_buffer, HID_MAX_MPS);
|
||||
break;
|
||||
case USBD_EVENT_SET_REMOTE_WAKEUP:
|
||||
break;
|
||||
case USBD_EVENT_CLR_REMOTE_WAKEUP:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +188,7 @@ static void usbd_hid_custom_in_callback(uint8_t busid, uint8_t ep, uint32_t nbyt
|
||||
static void usbd_hid_custom_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
|
||||
usbd_ep_start_read(busid, ep, read_buffer, HIDRAW_IN_EP_SIZE);
|
||||
usbd_ep_start_read(busid, ep, read_buffer, HID_MAX_MPS);
|
||||
read_buffer[0] = 0x02; /* IN: report id */
|
||||
usbd_ep_start_write(busid, HIDRAW_IN_EP, read_buffer, nbytes);
|
||||
}
|
||||
@@ -372,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);
|
||||
|
||||
@@ -15,49 +15,16 @@
|
||||
#define HID_INT_EP_SIZE 8
|
||||
#define HID_INT_EP_INTERVAL 10
|
||||
|
||||
#define USB_HID_CONFIG_DESC_SIZ 34
|
||||
#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)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
|
||||
/************** Descriptor of Joystick Mouse interface ****************/
|
||||
/* 09 */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
||||
0x00, /* 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 */
|
||||
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),
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
@@ -112,117 +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_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
|
||||
/************** Descriptor of Joystick Mouse interface ****************/
|
||||
/* 09 */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
||||
0x00, /* 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 */
|
||||
'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 = {
|
||||
@@ -319,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);
|
||||
|
||||
|
||||
@@ -17,50 +17,17 @@
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
/*!< config descriptor size */
|
||||
#define USB_HID_CONFIG_DESC_SIZ 34
|
||||
#define USB_CONFIG_SIZE 34
|
||||
/*!< 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)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
|
||||
/************** Descriptor of Joystick Mouse interface ****************/
|
||||
/* 09 */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
||||
0x00, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x01, /* bNumEndpoints */
|
||||
0x03, /* bInterfaceClass: HID */
|
||||
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
|
||||
0x02, /* 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_MOUSE_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 */
|
||||
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),
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
@@ -115,118 +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_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
|
||||
/************** Descriptor of Joystick Mouse interface ****************/
|
||||
/* 09 */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
||||
0x00, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x01, /* bNumEndpoints */
|
||||
0x03, /* bInterfaceClass: HID */
|
||||
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
|
||||
0x02, /* 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_MOUSE_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 */
|
||||
'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] = {
|
||||
@@ -337,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);
|
||||
|
||||
|
||||
@@ -17,50 +17,17 @@
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
/*!< config descriptor size */
|
||||
#define USB_HID_CONFIG_DESC_SIZ 34
|
||||
#define USB_CONFIG_SIZE 34
|
||||
/*!< 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)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_REMOTE_WAKEUP | USB_CONFIG_SELF_POWERED, USBD_MAX_POWER),
|
||||
|
||||
/************** Descriptor of Joystick Mouse interface ****************/
|
||||
/* 09 */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
||||
0x00, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x01, /* bNumEndpoints */
|
||||
0x03, /* bInterfaceClass: HID */
|
||||
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
|
||||
0x02, /* 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_MOUSE_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 */
|
||||
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),
|
||||
};
|
||||
|
||||
static const uint8_t device_quality_descriptor[] = {
|
||||
@@ -115,118 +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_HID_CONFIG_DESC_SIZ, 0x01, 0x01, USB_CONFIG_REMOTE_WAKEUP | USB_CONFIG_SELF_POWERED, USBD_MAX_POWER),
|
||||
|
||||
/************** Descriptor of Joystick Mouse interface ****************/
|
||||
/* 09 */
|
||||
0x09, /* bLength: Interface Descriptor size */
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
||||
0x00, /* bInterfaceNumber: Number of Interface */
|
||||
0x00, /* bAlternateSetting: Alternate setting */
|
||||
0x01, /* bNumEndpoints */
|
||||
0x03, /* bInterfaceClass: HID */
|
||||
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
|
||||
0x02, /* 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_MOUSE_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 */
|
||||
'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] = {
|
||||
@@ -337,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);
|
||||
|
||||
|
||||
@@ -14,7 +14,13 @@
|
||||
#define USBD_MAX_POWER 100
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
#define USB_CONFIG_SIZE (9 + 9 + 9 + 9 + 7 + MIDI_SIZEOF_JACK_DESC + 9 + 5 + 9 + 5)
|
||||
#define AUDIO_AC_SIZ AUDIO_SIZEOF_AC_HEADER_DESC(1)
|
||||
#define AUDIO_MS_SIZ (7 + MIDI_SIZEOF_JACK_DESC + 9 + 5 + 9 + 5)
|
||||
|
||||
#define USB_CONFIG_SIZE (unsigned long)(9 + \
|
||||
AUDIO_AC_DESCRIPTOR_LEN(1) + \
|
||||
MIDI_STANDARD_DESCRIPTOR_LEN + \
|
||||
AUDIO_MS_SIZ)
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
#define MIDI_EP_MPS 512
|
||||
@@ -22,55 +28,15 @@
|
||||
#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)
|
||||
};
|
||||
|
||||
static const uint8_t config_descriptor[] = {
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
// Standard AC Interface Descriptor
|
||||
0x09,
|
||||
0x04,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
// Class-specific AC Interface Descriptor
|
||||
0x09,
|
||||
0x24,
|
||||
0x01,
|
||||
0x00,
|
||||
0x01,
|
||||
0x09,
|
||||
0x00,
|
||||
0x01,
|
||||
0x01,
|
||||
// MIDIStreaming Interface Descriptors
|
||||
0x09,
|
||||
0x04,
|
||||
0x01,
|
||||
0x00,
|
||||
0x02,
|
||||
0x01,
|
||||
0x03,
|
||||
0x00,
|
||||
0x00,
|
||||
// Class-Specific MS Interface Header Descriptor
|
||||
0x07,
|
||||
0x24,
|
||||
0x01,
|
||||
0x00,
|
||||
0x01,
|
||||
WBVAL(65),
|
||||
|
||||
// MIDI_IN_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EMBEDDED, 0x01),
|
||||
// MIDI_IN_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EXTERNAL, 0x02),
|
||||
// MIDI_OUT_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EMBEDDED, 0x03, 0x02),
|
||||
// MIDI_OUT_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EXTERNAL, 0x04, 0x01),
|
||||
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,
|
||||
@@ -133,136 +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),
|
||||
// Standard AC Interface Descriptor
|
||||
0x09,
|
||||
0x04,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x01,
|
||||
0x01,
|
||||
0x00,
|
||||
0x00,
|
||||
// Class-specific AC Interface Descriptor
|
||||
0x09,
|
||||
0x24,
|
||||
0x01,
|
||||
0x00,
|
||||
0x01,
|
||||
0x09,
|
||||
0x00,
|
||||
0x01,
|
||||
0x01,
|
||||
// MIDIStreaming Interface Descriptors
|
||||
0x09,
|
||||
0x04,
|
||||
0x01,
|
||||
0x00,
|
||||
0x02,
|
||||
0x01,
|
||||
0x03,
|
||||
0x00,
|
||||
0x00,
|
||||
// Class-Specific MS Interface Header Descriptor
|
||||
0x07,
|
||||
0x24,
|
||||
0x01,
|
||||
0x00,
|
||||
0x01,
|
||||
WBVAL(65),
|
||||
|
||||
// MIDI_IN_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EMBEDDED, 0x01),
|
||||
// MIDI_IN_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EXTERNAL, 0x02),
|
||||
// MIDI_OUT_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EMBEDDED, 0x03, 0x02),
|
||||
// MIDI_OUT_JACK_DESCRIPTOR_INIT(MIDI_JACK_TYPE_EXTERNAL, 0x04, 0x01),
|
||||
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];
|
||||
@@ -317,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);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user