Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1435548e7 | ||
|
|
a8d40eb706 | ||
|
|
aeffaea016 | ||
|
|
9ce7b0ceb7 | ||
|
|
1c31156a37 | ||
|
|
e795ab73a0 | ||
|
|
5e689dfe15 | ||
|
|
d10cbd5daf | ||
|
|
40a019e063 | ||
|
|
2080cf1206 | ||
|
|
ae521bf95c | ||
|
|
a2f7b67dc4 | ||
|
|
e79319cac9 | ||
|
|
7acb667e20 | ||
|
|
a04b1fa551 | ||
|
|
c37c60c7c7 | ||
|
|
0738c09a4d | ||
|
|
cf4dfde49d | ||
|
|
d4ba2eef57 | ||
|
|
3d96f64f94 | ||
|
|
a746eb4bb1 | ||
|
|
c84e769f78 | ||
|
|
d11260ef67 | ||
|
|
e6193bd131 | ||
|
|
dd1f1d3ba8 | ||
|
|
bc1e7c4bd5 | ||
|
|
7d76b4bae1 | ||
|
|
7c0ef50bb3 | ||
|
|
0f2cb9f900 | ||
|
|
7c1fae04b2 | ||
|
|
14f5dd2dd3 | ||
|
|
9029f8c5b1 | ||
|
|
b9915e0e1b | ||
|
|
1387790744 | ||
|
|
c5fc9f338e | ||
|
|
4d61e5e053 | ||
|
|
1a7259649b | ||
|
|
628e4ee928 | ||
|
|
749369b6fc | ||
|
|
89cd77374c | ||
|
|
3792ad4905 | ||
|
|
2789633b50 |
35
.readthedocs.yaml
Normal file
35
.readthedocs.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
# Read the Docs configuration file for Sphinx projects
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Set the OS, Python version and other tools you might need
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.11"
|
||||
# You can also specify other tool versions:
|
||||
# nodejs: "20"
|
||||
# rust: "1.70"
|
||||
# golang: "1.20"
|
||||
|
||||
# Build documentation in the "docs/" directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/source/conf.py
|
||||
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
|
||||
# builder: "dirhtml"
|
||||
# Fail on all warnings to avoid broken references
|
||||
# fail_on_warning: true
|
||||
|
||||
# Optionally build your docs in additional formats such as PDF and ePub
|
||||
# formats:
|
||||
# - pdf
|
||||
# - epub
|
||||
|
||||
# Optional but recommended, declare the Python requirements required
|
||||
# to build your documentation
|
||||
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
|
||||
python:
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
27
README.md
27
README.md
@@ -162,23 +162,22 @@ USB basic concepts and how the CherryUSB Device stack is implemented, see [Cherr
|
||||
|
||||
## Demo Repo
|
||||
|
||||
| Manufacturer | CHIP or Series | USB IP| Repo Url |Corresponds to master version|
|
||||
| Manufacturer | CHIP or Series | USB IP| Repo Url |Current version|
|
||||
|:--------------------:|:------------------:|:-----:|:--------:|:---------------------------:|
|
||||
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/cherryusb_bouffalolab)| v0.9.0 |
|
||||
|ST | STM32F1x | fsdev |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|latest |
|
||||
|ST | STM32F4/STM32H7 | dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|latest |
|
||||
|HPMicro | HPM6750 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/cherryusb_hpmicro)|v0.8.0 |
|
||||
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|latest |
|
||||
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|latest |
|
||||
|Phytium | e2000 | xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.9.0 |
|
||||
|Raspberry pi | rp2040 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|latest |
|
||||
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|latest |
|
||||
|Nordicsemi | Nrf52840 | nrf5x |[nrf5x_repo](https://github.com/CherryUSB/cherryusb_nrf5x)|latest |
|
||||
|Espressif | esp32s3 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|latest |
|
||||
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/cherryusb_bouffalolab)| v0.10.1 |
|
||||
|ST | STM32F1x | fsdev |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|≤ v0.10.1 |
|
||||
|ST | STM32F4/STM32H7 | dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|≤ v0.10.1 |
|
||||
|HPMicro | HPM6750 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/cherryusb_hpmicro)| v0.10.1 |
|
||||
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|≤ v0.10.1 |
|
||||
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|≤ v0.10.1 |
|
||||
|Phytium | e2000 | xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.1 |
|
||||
|Phytium | PhytiumPI | pusb2 |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.1 |
|
||||
|Raspberry pi | rp2040 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|≤ v0.10.1 |
|
||||
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|≤ v0.10.1 |
|
||||
|Nordicsemi | Nrf52840 | nrf5x |[nrf5x_repo](https://github.com/CherryUSB/cherryusb_nrf5x)|≤ v0.10.1 |
|
||||
|Espressif | esp32s3 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|≤ v0.10.1 |
|
||||
|Bekencorp | BK72xx | musb |[armino](https://github.com/CherryUSB/armino)|v0.7.0 |
|
||||
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)|v0.7.0 |
|
||||
|Nuvoton | Nuc442 | nuvoton |[nuc442_repo](https://github.com/CherryUSB/cherryusb_nuc442)|v0.4.1 |
|
||||
|Geehy | APM32E10x APM32F0xx| fsdev |[apm32_repo](https://github.com/CherryUSB/cherryusb_apm32)|v0.4.1 |
|
||||
|
||||
## Contact
|
||||
|
||||
|
||||
27
README_zh.md
27
README_zh.md
@@ -160,23 +160,22 @@ USB 基本知识点与 CherryUSB Device 协议栈是如何编写的,参考 [Ch
|
||||
|
||||
## 示例仓库
|
||||
|
||||
| 厂商 | 芯片或者系列 | USB IP| 仓库链接 | 对应 master 版本 |
|
||||
| 厂商 | 芯片或者系列 | USB IP| 仓库链接 | 当前版本 |
|
||||
|:--------------------:|:------------------:|:-----:|:--------:|:---------------------------:|
|
||||
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/cherryusb_bouffalolab)| v0.9.0 |
|
||||
|ST | STM32F1x | fsdev |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|latest |
|
||||
|ST | STM32F4/STM32H7 | dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|latest |
|
||||
|HPMicro | HPM6750 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/cherryusb_hpmicro)|v0.8.0 |
|
||||
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|latest |
|
||||
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|latest |
|
||||
|Phytium | e2000 | xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.9.0 |
|
||||
|Raspberry pi | rp2040 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|latest |
|
||||
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|latest |
|
||||
|Nordicsemi | Nrf52840 | nrf5x |[nrf5x_repo](https://github.com/CherryUSB/cherryusb_nrf5x)|latest |
|
||||
|Espressif | esp32s3 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|latest |
|
||||
|Bouffalolab | BL702/BL616/BL808 | bouffalolab/ehci|[bouffalo_sdk](https://github.com/CherryUSB/cherryusb_bouffalolab)| v0.10.1 |
|
||||
|ST | STM32F1x | fsdev |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|≤ v0.10.1 |
|
||||
|ST | STM32F4/STM32H7 | dwc2 |[stm32_repo](https://github.com/CherryUSB/cherryusb_stm32)|≤ v0.10.1 |
|
||||
|HPMicro | HPM6750 | hpm/ehci |[hpm_sdk](https://github.com/CherryUSB/cherryusb_hpmicro)| v0.10.1 |
|
||||
|Essemi | ES32F36xx | musb |[es32f369_repo](https://github.com/CherryUSB/cherryusb_es32)|≤ v0.10.1 |
|
||||
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|≤ v0.10.1 |
|
||||
|Phytium | e2000 | xhci |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.1 |
|
||||
|Phytium | e2000 | pusb2 |[phytium_repo](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk)|v0.10.1 |
|
||||
|Raspberry pi | rp2040 | rp2040 |[pico-examples](https://github.com/CherryUSB/pico-examples)|≤ v0.10.1 |
|
||||
|WCH | CH32V307/ch58x | ch32_usbfs/ch32_usbhs/ch58x |[wch_repo](https://github.com/CherryUSB/cherryusb_wch)|≤ v0.10.1 |
|
||||
|Nordicsemi | Nrf52840 | nrf5x |[nrf5x_repo](https://github.com/CherryUSB/cherryusb_nrf5x)|≤ v0.10.1 |
|
||||
|Espressif | esp32s3 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|≤ v0.10.1 |
|
||||
|Bekencorp | BK72xx | musb |[armino](https://github.com/CherryUSB/armino)|v0.7.0 |
|
||||
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)|v0.7.0 |
|
||||
|Nuvoton | Nuc442 | nuvoton |[nuc442_repo](https://github.com/CherryUSB/cherryusb_nuc442)|v0.4.1 |
|
||||
|Geehy | APM32E10x APM32F0xx| fsdev |[apm32_repo](https://github.com/CherryUSB/cherryusb_apm32)|v0.4.1 |
|
||||
|
||||
## Contact
|
||||
|
||||
|
||||
24
SConscript
24
SConscript
@@ -16,7 +16,9 @@ CPPDEFINES = []
|
||||
|
||||
# USB DEVICE
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE']):
|
||||
path += [cwd + '/osal']
|
||||
src += Glob('core/usbd_core.c')
|
||||
src += Glob('osal/usb_osal_rtthread.c')
|
||||
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_HS']):
|
||||
CPPDEFINES+=['CONFIG_USB_HS']
|
||||
@@ -44,6 +46,8 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
|
||||
src += Glob('demo/hid_keyboard_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_MSC_TEMPLATE']):
|
||||
src += Glob('demo/msc_ram_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_MSC_STORAGE_TEMPLATE']):
|
||||
src += Glob('demo/msc_storage_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_AUDIO_V1_TEMPLATE']):
|
||||
src += Glob('demo/audio_v1_mic_speaker_multichan_template.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_AUDIO_V2_TEMPLATE']):
|
||||
@@ -81,6 +85,12 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
|
||||
else:
|
||||
src += Glob('port/ch32/usb_dc_usbfs.c')
|
||||
|
||||
if GetDepend(['PKG_CHERRYUSB_DEVICE_PUSB2']):
|
||||
path += [cwd + '/port/pusb2/common']
|
||||
path += [cwd + '/port/pusb2/fpusb2']
|
||||
src += Glob('port/pusb2/fpusb2' + '/*.c')
|
||||
src += Glob('port/pusb2/usb_dc_pusb2.c')
|
||||
|
||||
# USB HOST
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST']):
|
||||
path += [cwd + '/osal']
|
||||
@@ -97,6 +107,7 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
|
||||
src += Glob('class/msc/usbh_msc.c')
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_RNDIS']):
|
||||
src += Glob('class/wireless/usbh_rndis.c')
|
||||
src += Glob('third_party/rt-thread-4.1.1/rndis_host/rndis_host.c')
|
||||
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2']):
|
||||
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
||||
@@ -111,6 +122,17 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_HPM']):
|
||||
src += Glob('port/ehci/usb_glue_hpm.c')
|
||||
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_XHCI']):
|
||||
src += Glob('port/xhci/usb_hc_xhci.c')
|
||||
src += Glob('port/xhci/xhci_dbg.c')
|
||||
src += Glob('port/xhci/xhci.c')
|
||||
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_PUSB2']):
|
||||
path += [cwd + '/port/pusb2/common']
|
||||
path += [cwd + '/port/pusb2/fpusb2']
|
||||
src += Glob('port/pusb2/fpusb2' + '/*.c')
|
||||
src += Glob('port/pusb2/usb_hc_pusb2.c')
|
||||
|
||||
if GetDepend(['PKG_CHERRYUSB_HOST_TEMPLATE']):
|
||||
src += Glob('demo/usb_host.c')
|
||||
|
||||
@@ -119,6 +141,8 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
|
||||
src += Glob('class/vendor/cp201x/usbh_cp210x.c')
|
||||
src += Glob('third_party/rt-thread-4.1.1/dfs/drv_usbh_cp210x_rtt.c')
|
||||
|
||||
src += Glob('third_party/rt-thread-4.1.1/msh_cmd.c')
|
||||
|
||||
group = DefineGroup('CherryUSB', src, depend = ['PKG_USING_CHERRYUSB'], CPPPATH = path, CPPDEFINES = CPPDEFINES)
|
||||
|
||||
Return('group')
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef CHERRYUSB_CONFIG_H
|
||||
#define CHERRYUSB_CONFIG_H
|
||||
|
||||
#define CHERRYUSB_VERSION 0x001000
|
||||
#define CHERRYUSB_VERSION 0x001002
|
||||
|
||||
/* ================ USB common Configuration ================ */
|
||||
|
||||
@@ -44,27 +44,6 @@
|
||||
/* Enable test mode */
|
||||
// #define CONFIG_USBDEV_TEST_MODE
|
||||
|
||||
//#define CONFIG_USBDEV_TX_THREAD
|
||||
//#define CONFIG_USBDEV_RX_THREAD
|
||||
|
||||
#ifdef CONFIG_USBDEV_TX_THREAD
|
||||
#ifndef CONFIG_USBDEV_TX_PRIO
|
||||
#define CONFIG_USBDEV_TX_PRIO 4
|
||||
#endif
|
||||
#ifndef CONFIG_USBDEV_TX_STACKSIZE
|
||||
#define CONFIG_USBDEV_TX_STACKSIZE 2048
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_RX_THREAD
|
||||
#ifndef CONFIG_USBDEV_RX_PRIO
|
||||
#define CONFIG_USBDEV_RX_PRIO 4
|
||||
#endif
|
||||
#ifndef CONFIG_USBDEV_RX_STACKSIZE
|
||||
#define CONFIG_USBDEV_RX_STACKSIZE 2048
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_BLOCK_SIZE
|
||||
#define CONFIG_USBDEV_MSC_BLOCK_SIZE 512
|
||||
#endif
|
||||
@@ -81,6 +60,16 @@
|
||||
#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
|
||||
#endif
|
||||
|
||||
// #define CONFIG_USBDEV_MSC_THREAD
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_PRIO
|
||||
#define CONFIG_USBDEV_MSC_PRIO 4
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_MSC_STACKSIZE
|
||||
#define CONFIG_USBDEV_MSC_STACKSIZE 2048
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
|
||||
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
|
||||
#endif
|
||||
@@ -113,7 +102,6 @@
|
||||
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
|
||||
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
|
||||
#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1
|
||||
#define CONFIG_USBHOST_MAX_RNDIS_CLASS 1
|
||||
|
||||
#define CONFIG_USBHOST_DEV_NAMELEN 16
|
||||
|
||||
@@ -126,6 +114,9 @@
|
||||
|
||||
//#define CONFIG_USBHOST_GET_STRING_DESC
|
||||
|
||||
// #define CONFIG_USBHOST_MSOS_ENABLE
|
||||
#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
|
||||
|
||||
/* Ep0 max transfer buffer */
|
||||
#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512
|
||||
|
||||
@@ -153,7 +144,7 @@
|
||||
#define CONFIG_USB_EHCI_HCOR_BASE (0x20072000 + 0x10)
|
||||
#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
|
||||
// #define CONFIG_USB_EHCI_INFO_ENABLE
|
||||
// #define CONFIG_USB_ECHI_HCOR_RESERVED_DISABLE
|
||||
// #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
|
||||
// #define CONFIG_USB_EHCI_CONFIGFLAG
|
||||
// #define CONFIG_USB_EHCI_PORT_POWER
|
||||
|
||||
|
||||
@@ -212,6 +212,57 @@
|
||||
#define CDC_SERIAL_STATE_RX_CARRIER_Pos (0)
|
||||
#define CDC_SERIAL_STATE_RX_CARRIER_Msk (1 << CDC_SERIAL_STATE_RX_CARRIER_Pos)
|
||||
|
||||
#define CDC_ECM_XMIT_OK (1 << 0)
|
||||
#define CDC_ECM_RVC_OK (1 << 1)
|
||||
#define CDC_ECM_XMIT_ERROR (1 << 2)
|
||||
#define CDC_ECM_RCV_ERROR (1 << 3)
|
||||
#define CDC_ECM_RCV_NO_BUFFER (1 << 4)
|
||||
#define CDC_ECM_DIRECTED_BYTES_XMIT (1 << 5)
|
||||
#define CDC_ECM_DIRECTED_FRAMES_XMIT (1 << 6)
|
||||
#define CDC_ECM_MULTICAST_BYTES_XMIT (1 << 7)
|
||||
#define CDC_ECM_MULTICAST_FRAMES_XMIT (1 << 8)
|
||||
#define CDC_ECM_BROADCAST_BYTES_XMIT (1 << 9)
|
||||
#define CDC_ECM_BROADCAST_FRAMES_XMIT (1 << 10)
|
||||
#define CDC_ECM_DIRECTED_BYTES_RCV (1 << 11)
|
||||
#define CDC_ECM_DIRECTED_FRAMES_RCV (1 << 12)
|
||||
#define CDC_ECM_MULTICAST_BYTES_RCV (1 << 13)
|
||||
#define CDC_ECM_MULTICAST_FRAMES_RCV (1 << 14)
|
||||
#define CDC_ECM_BROADCAST_BYTES_RCV (1 << 15)
|
||||
#define CDC_ECM_BROADCAST_FRAMES_RCV (1 << 16)
|
||||
#define CDC_ECM_RCV_CRC_ERROR (1 << 17)
|
||||
#define CDC_ECM_TRANSMIT_QUEUE_LENGTH (1 << 18)
|
||||
#define CDC_ECM_RCV_ERROR_ALIGNMENT (1 << 19)
|
||||
#define CDC_ECM_XMIT_ONE_COLLISION (1 << 20)
|
||||
#define CDC_ECM_XMIT_MORE_COLLISIONS (1 << 21)
|
||||
#define CDC_ECM_XMIT_DEFERRED (1 << 22)
|
||||
#define CDC_ECM_XMIT_MAX_COLLISIONS (1 << 23)
|
||||
#define CDC_ECM_RCV_OVERRUN (1 << 24)
|
||||
#define CDC_ECM_XMIT_UNDERRUN (1 << 25)
|
||||
#define CDC_ECM_XMIT_HEARTBEAT_FAILURE (1 << 26)
|
||||
#define CDC_ECM_XMIT_TIMES_CRS_LOST (1 << 27)
|
||||
#define CDC_ECM_XMIT_LATE_COLLISIONS (1 << 28)
|
||||
|
||||
#define CDC_ECM_MAC_STR_DESC (uint8_t *)"010202030000"
|
||||
#define CDC_ECM_MAC_ADDR0 0x00U /* 01 */
|
||||
#define CDC_ECM_MAC_ADDR1 0x02U /* 02 */
|
||||
#define CDC_ECM_MAC_ADDR2 0x02U /* 03 */
|
||||
#define CDC_ECM_MAC_ADDR3 0x03U /* 00 */
|
||||
#define CDC_ECM_MAC_ADDR4 0x00U /* 00 */
|
||||
#define CDC_ECM_MAC_ADDR5 0x00U /* 00 */
|
||||
|
||||
#define CDC_ECM_NET_DISCONNECTED 0x00U
|
||||
#define CDC_ECM_NET_CONNECTED 0x01U
|
||||
|
||||
#define CDC_ECM_ETH_STATS_RESERVED 0xE0U
|
||||
#define CDC_ECM_BMREQUEST_TYPE_ECM 0xA1U
|
||||
|
||||
#define CDC_ECM_CONNECT_SPEED_UPSTREAM 0x004C4B40U /* 5Mbps */
|
||||
#define CDC_ECM_CONNECT_SPEED_DOWNSTREAM 0x004C4B40U /* 5Mbps */
|
||||
|
||||
#define CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION 0x00
|
||||
#define CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE 0x01
|
||||
#define CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE 0x2A
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Structures based on usbcdc11.pdf (www.usb.org)
|
||||
*----------------------------------------------------------------------------*/
|
||||
@@ -299,6 +350,15 @@ struct cdc_ecm_descriptor {
|
||||
uint8_t bNumberPowerFilters;
|
||||
} __PACKED;
|
||||
|
||||
struct cdc_ecm_notification {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bNotificationType;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
uint8_t data[8];
|
||||
} __PACKED;
|
||||
|
||||
/*Length of template descriptor: 66 bytes*/
|
||||
#define CDC_ACM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 7)
|
||||
// clang-format off
|
||||
@@ -437,4 +497,76 @@ struct cdc_ecm_descriptor {
|
||||
0x00 /* bInterval */
|
||||
// clang-format on
|
||||
|
||||
#define DBVAL_BE(x) ((x >> 24) & 0xFF), ((x >> 16) & 0xFF), ((x >> 8) & 0xFF), (x & 0xFF)
|
||||
|
||||
/*Length of template descriptor: 66 bytes*/
|
||||
#define CDC_ECM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 13 + 7 + 9 + 7 + 7)
|
||||
// clang-format off
|
||||
#define CDC_ECM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, \
|
||||
eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx) \
|
||||
/* Interface Associate */ \
|
||||
0x08, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
|
||||
bFirstInterface, /* bFirstInterface */ \
|
||||
0x02, /* bInterfaceCount */ \
|
||||
USB_DEVICE_CLASS_CDC, /* bFunctionClass */ \
|
||||
CDC_ETHERNET_NETWORKING_CONTROL_MODEL, /* bFunctionSubClass */ \
|
||||
CDC_COMMON_PROTOCOL_NONE, /* bFunctionProtocol */ \
|
||||
0x00, /* iFunction */ \
|
||||
0x09, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||
bFirstInterface, /* bInterfaceNumber */ \
|
||||
0x00, /* bAlternateSetting */ \
|
||||
0x01, /* bNumEndpoints */ \
|
||||
USB_DEVICE_CLASS_CDC, /* bInterfaceClass */ \
|
||||
CDC_ETHERNET_NETWORKING_CONTROL_MODEL, /* bInterfaceSubClass */ \
|
||||
CDC_COMMON_PROTOCOL_NONE, /* bInterfaceProtocol */ \
|
||||
str_idx, /* iInterface */ \
|
||||
0x05, /* bLength */ \
|
||||
CDC_CS_INTERFACE, /* bDescriptorType */ \
|
||||
CDC_FUNC_DESC_HEADER, /* bDescriptorSubtype */ \
|
||||
WBVAL(CDC_V1_10), /* bcdCDC */ \
|
||||
0x05, /* bLength */ \
|
||||
CDC_CS_INTERFACE, /* bDescriptorType */ \
|
||||
CDC_FUNC_DESC_UNION, /* bDescriptorSubtype */ \
|
||||
bFirstInterface, /* bMasterInterface */ \
|
||||
(uint8_t)(bFirstInterface + 1), /* bSlaveInterface0 */ \
|
||||
/* CDC_ECM Functional Descriptor */ \
|
||||
0x0D, /* bFunctionLength */\
|
||||
CDC_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE */\
|
||||
CDC_FUNC_DESC_ETHERNET_NETWORKING, /* Ethernet Networking functional descriptor subtype */\
|
||||
str_idx, /* Device's MAC string index */\
|
||||
DBVAL_BE(eth_statistics), /* Ethernet statistics (bitmap) */\
|
||||
WBVAL(wMaxPacketSize),/* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\
|
||||
WBVAL(wNumberMCFilters), /* wNumberMCFilters: the number of multicast filters */\
|
||||
bNumberPowerFilters, /* bNumberPowerFilters: the number of wakeup power filters */\
|
||||
0x07, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
|
||||
int_ep, /* bEndpointAddress */ \
|
||||
0x03, /* bmAttributes */ \
|
||||
0x10, 0x00, /* wMaxPacketSize */ \
|
||||
0x10, /* bInterval */ \
|
||||
0x09, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||
(uint8_t)(bFirstInterface + 1), /* bInterfaceNumber */ \
|
||||
0x00, /* bAlternateSetting */ \
|
||||
0x02, /* bNumEndpoints */ \
|
||||
CDC_DATA_INTERFACE_CLASS, /* bInterfaceClass */ \
|
||||
0x00, /* bInterfaceSubClass */ \
|
||||
0x00, /* bInterfaceProtocol */ \
|
||||
0x00, /* iInterface */ \
|
||||
0x07, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
|
||||
out_ep, /* bEndpointAddress */ \
|
||||
0x02, /* bmAttributes */ \
|
||||
WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
|
||||
0x00, /* bInterval */ \
|
||||
0x07, /* bLength */ \
|
||||
USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
|
||||
in_ep, /* bEndpointAddress */ \
|
||||
0x02, /* bmAttributes */ \
|
||||
WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
|
||||
0x00 /* bInterval */
|
||||
// clang-format on
|
||||
|
||||
#endif /* USB_CDC_H */
|
||||
|
||||
237
class/cdc/usbd_cdc_ecm.c
Normal file
237
class/cdc/usbd_cdc_ecm.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (c) 2023, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_cdc_ecm.h"
|
||||
|
||||
#define CDC_ECM_OUT_EP_IDX 0
|
||||
#define CDC_ECM_IN_EP_IDX 1
|
||||
#define CDC_ECM_INT_EP_IDX 2
|
||||
|
||||
/* Describe EndPoints configuration */
|
||||
static struct usbd_endpoint cdc_ecm_ep_data[3];
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
#define CDC_ECM_MAX_PACKET_SIZE 512
|
||||
#else
|
||||
#define CDC_ECM_MAX_PACKET_SIZE 64
|
||||
#endif
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_notify_buf[16];
|
||||
|
||||
volatile uint8_t *g_cdc_ecm_rx_data_buffer = NULL;
|
||||
volatile uint32_t g_cdc_ecm_rx_data_length = 0;
|
||||
volatile uint32_t g_cdc_ecm_tx_data_length = 0;
|
||||
|
||||
static volatile uint8_t g_current_net_status = 0;
|
||||
static volatile uint8_t g_cmd_intf = 0;
|
||||
|
||||
static uint32_t g_connect_speed_table[2] = { CDC_ECM_CONNECT_SPEED_UPSTREAM,
|
||||
CDC_ECM_CONNECT_SPEED_DOWNSTREAM };
|
||||
|
||||
void usbd_cdc_ecm_send_notify(uint8_t notifycode, uint8_t value, uint32_t *speed)
|
||||
{
|
||||
struct cdc_ecm_notification *notify = (struct cdc_ecm_notification *)g_cdc_ecm_notify_buf;
|
||||
uint8_t bytes2send = 0;
|
||||
|
||||
notify->bmRequestType = CDC_ECM_BMREQUEST_TYPE_ECM;
|
||||
notify->bNotificationType = notifycode;
|
||||
|
||||
switch (notifycode) {
|
||||
case CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION:
|
||||
notify->wValue = value;
|
||||
notify->wIndex = g_cmd_intf;
|
||||
notify->wLength = 0U;
|
||||
|
||||
for (uint8_t i = 0U; i < 8U; i++) {
|
||||
notify->data[i] = 0U;
|
||||
}
|
||||
bytes2send = 8U;
|
||||
break;
|
||||
case CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE:
|
||||
notify->wValue = 0U;
|
||||
notify->wIndex = g_cmd_intf;
|
||||
notify->wLength = 0U;
|
||||
for (uint8_t i = 0U; i < 8U; i++) {
|
||||
notify->data[i] = 0U;
|
||||
}
|
||||
bytes2send = 8U;
|
||||
break;
|
||||
case CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE:
|
||||
notify->wValue = 0U;
|
||||
notify->wIndex = g_cmd_intf;
|
||||
notify->wLength = 0x0008U;
|
||||
bytes2send = 16U;
|
||||
|
||||
memcpy(notify->data, speed, 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytes2send) {
|
||||
usbd_ep_start_write(cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr, g_cdc_ecm_notify_buf, bytes2send);
|
||||
}
|
||||
}
|
||||
|
||||
static int cdc_ecm_class_interface_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
|
||||
{
|
||||
USB_LOG_DBG("CDC ECM Class request: "
|
||||
"bRequest 0x%02x\r\n",
|
||||
setup->bRequest);
|
||||
|
||||
g_cmd_intf = LO_BYTE(setup->wIndex);
|
||||
|
||||
switch (setup->bRequest) {
|
||||
case CDC_REQUEST_SET_ETHERNET_PACKET_FILTER:
|
||||
/* bit0 Promiscuous
|
||||
* bit1 ALL Multicast
|
||||
* bit2 Directed
|
||||
* bit3 Broadcast
|
||||
* bit4 Multicast
|
||||
*/
|
||||
if (g_current_net_status == 0) {
|
||||
g_current_net_status = 1;
|
||||
usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, NULL);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
USB_LOG_WRN("Unhandled CDC ECM Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cdc_ecm_notify_handler(uint8_t event, void *arg)
|
||||
{
|
||||
switch (event) {
|
||||
case USBD_EVENT_RESET:
|
||||
g_current_net_status = 0;
|
||||
g_cdc_ecm_rx_data_length = 0;
|
||||
g_cdc_ecm_tx_data_length = 0;
|
||||
g_cdc_ecm_rx_data_buffer = NULL;
|
||||
break;
|
||||
case USBD_EVENT_CONFIGURED:
|
||||
usbd_ep_start_read(cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_data_length], CDC_ECM_MAX_PACKET_SIZE);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cdc_ecm_bulk_out(uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
g_cdc_ecm_rx_data_length += nbytes;
|
||||
|
||||
if (nbytes < CDC_ECM_MAX_PACKET_SIZE) {
|
||||
g_cdc_ecm_rx_data_buffer = g_cdc_ecm_rx_buffer;
|
||||
usbd_cdc_ecm_data_recv_done();
|
||||
} else {
|
||||
usbd_ep_start_read(ep, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_data_length], CDC_ECM_MAX_PACKET_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void cdc_ecm_bulk_in(uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
if ((nbytes % CDC_ECM_MAX_PACKET_SIZE) == 0 && nbytes) {
|
||||
/* send zlp */
|
||||
usbd_ep_start_write(ep, NULL, 0);
|
||||
} else {
|
||||
g_cdc_ecm_tx_data_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void cdc_ecm_int_in(uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
if (g_current_net_status == 1) {
|
||||
g_current_net_status = 2;
|
||||
usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, g_connect_speed_table);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
|
||||
struct pbuf *usbd_cdc_ecm_eth_rx(void)
|
||||
{
|
||||
struct pbuf *p;
|
||||
|
||||
if (g_cdc_ecm_rx_data_buffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_data_length, PBUF_POOL);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_data_length);
|
||||
p->len = g_cdc_ecm_rx_data_length;
|
||||
|
||||
USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_data_length);
|
||||
g_cdc_ecm_rx_data_length = 0;
|
||||
g_cdc_ecm_rx_data_buffer = NULL;
|
||||
usbd_ep_start_read(cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, g_cdc_ecm_rx_buffer, CDC_ECM_MAX_PACKET_SIZE);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int usbd_cdc_ecm_eth_tx(struct pbuf *p)
|
||||
{
|
||||
struct pbuf *q;
|
||||
uint8_t *buffer;
|
||||
|
||||
if (g_cdc_ecm_tx_data_length > 0) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (p->tot_len > sizeof(g_cdc_ecm_tx_buffer)) {
|
||||
p->tot_len = sizeof(g_cdc_ecm_tx_buffer);
|
||||
}
|
||||
|
||||
buffer = g_cdc_ecm_tx_buffer;
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
memcpy(buffer, q->payload, q->len);
|
||||
buffer += q->len;
|
||||
}
|
||||
|
||||
g_cdc_ecm_tx_data_length = p->tot_len;
|
||||
|
||||
USB_LOG_DBG("txlen:%d\r\n", g_cdc_ecm_tx_data_length);
|
||||
return usbd_ep_start_write(cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr, g_cdc_ecm_tx_buffer, g_cdc_ecm_tx_data_length);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct usbd_interface *usbd_cdc_ecm_init_intf(struct usbd_interface *intf, const uint8_t int_ep, const uint8_t out_ep, const uint8_t in_ep)
|
||||
{
|
||||
intf->class_interface_handler = cdc_ecm_class_interface_request_handler;
|
||||
intf->class_endpoint_handler = NULL;
|
||||
intf->vendor_handler = NULL;
|
||||
intf->notify_handler = cdc_ecm_notify_handler;
|
||||
|
||||
cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr = out_ep;
|
||||
cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_cb = cdc_ecm_bulk_out;
|
||||
cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr = in_ep;
|
||||
cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_cb = cdc_ecm_bulk_in;
|
||||
cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr = int_ep;
|
||||
cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_cb = cdc_ecm_int_in;
|
||||
|
||||
usbd_add_endpoint(&cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX]);
|
||||
usbd_add_endpoint(&cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX]);
|
||||
usbd_add_endpoint(&cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX]);
|
||||
|
||||
return intf;
|
||||
}
|
||||
|
||||
void usbd_cdc_ecm_set_connect_speed(uint32_t speed[2])
|
||||
{
|
||||
memcpy(g_connect_speed_table, speed, 8);
|
||||
}
|
||||
|
||||
__WEAK void usbd_cdc_ecm_data_recv_done(void)
|
||||
{
|
||||
}
|
||||
36
class/cdc/usbd_cdc_ecm.h
Normal file
36
class/cdc/usbd_cdc_ecm.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBD_CDC_ECM_H
|
||||
#define USBD_CDC_ECM_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Ethernet Maximum Segment size, typically 1514 bytes */
|
||||
#define CONFIG_CDC_ECM_ETH_MAX_SEGSZE 1514U
|
||||
#define CONFIG_USBDEV_CDC_ECM_USING_LWIP
|
||||
|
||||
/* Init cdc ecm interface driver */
|
||||
struct usbd_interface *usbd_cdc_ecm_init_intf(struct usbd_interface *intf, const uint8_t int_ep, const uint8_t out_ep, const uint8_t in_ep);
|
||||
|
||||
/* Setup request command callback api */
|
||||
void usbd_cdc_ecm_set_connect_speed(uint32_t speed[2]);
|
||||
void usbd_cdc_ecm_data_recv_done(void);
|
||||
|
||||
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
|
||||
#include <lwip/pbuf.h>
|
||||
struct pbuf *usbd_cdc_ecm_eth_rx(void);
|
||||
int usbd_cdc_ecm_eth_tx(struct pbuf *p);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBD_CDC_ECM_H */
|
||||
330
class/cdc/usbh_cdc_ecm.c
Normal file
330
class/cdc/usbh_cdc_ecm.c
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_cdc_ecm.h"
|
||||
|
||||
#define DEV_FORMAT "/dev/cdc_ether"
|
||||
|
||||
/* general descriptor field offsets */
|
||||
#define DESC_bLength 0 /** Length offset */
|
||||
#define DESC_bDescriptorType 1 /** Descriptor type offset */
|
||||
#define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
|
||||
|
||||
/* interface descriptor field offsets */
|
||||
#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
|
||||
#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
|
||||
|
||||
#define CONFIG_USBHOST_CDC_ECM_PKT_FILTER 0x000C
|
||||
#define CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE 1514U
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE];
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_inttx_buffer[16];
|
||||
|
||||
static struct usbh_cdc_ecm g_cdc_ecm_class;
|
||||
|
||||
static int usbh_cdc_ecm_set_eth_packet_filter(struct usbh_cdc_ecm *cdc_ecm_class, uint16_t filter_value)
|
||||
{
|
||||
struct usb_setup_packet *setup = cdc_ecm_class->hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = CDC_REQUEST_SET_ETHERNET_PACKET_FILTER;
|
||||
setup->wValue = filter_value;
|
||||
setup->wIndex = cdc_ecm_class->ctrl_intf;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(cdc_ecm_class->hport->ep0, setup, NULL);
|
||||
}
|
||||
|
||||
int usbh_cdc_ecm_get_notification(struct usbh_cdc_ecm *cdc_ecm_class)
|
||||
{
|
||||
int ret;
|
||||
|
||||
usbh_int_urb_fill(&cdc_ecm_class->intin_urb, cdc_ecm_class->intin, g_cdc_ecm_inttx_buffer, 16, USB_OSAL_WAITING_FOREVER, NULL, NULL);
|
||||
ret = usbh_submit_urb(&cdc_ecm_class->intin_urb);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (g_cdc_ecm_inttx_buffer[1] == CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION) {
|
||||
cdc_ecm_class->connect_status = g_cdc_ecm_inttx_buffer[2];
|
||||
} else if (g_cdc_ecm_inttx_buffer[1] == CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE) {
|
||||
memcpy(cdc_ecm_class->speed, &g_cdc_ecm_inttx_buffer[8], 8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbh_cdc_ecm_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret;
|
||||
uint8_t altsetting = 0;
|
||||
char mac_buffer[12];
|
||||
uint8_t *p;
|
||||
uint8_t cur_iface = 0xff;
|
||||
uint8_t mac_str_idx = 0xff;
|
||||
|
||||
struct usbh_cdc_ecm *cdc_ecm_class = &g_cdc_ecm_class;
|
||||
|
||||
cdc_ecm_class->hport = hport;
|
||||
cdc_ecm_class->ctrl_intf = intf;
|
||||
cdc_ecm_class->data_intf = intf + 1;
|
||||
|
||||
hport->config.intf[intf].priv = cdc_ecm_class;
|
||||
hport->config.intf[intf + 1].priv = NULL;
|
||||
|
||||
p = hport->raw_config_desc;
|
||||
while (p[DESC_bLength]) {
|
||||
switch (p[DESC_bDescriptorType]) {
|
||||
case USB_DESCRIPTOR_TYPE_INTERFACE:
|
||||
cur_iface = p[INTF_DESC_bInterfaceNumber];
|
||||
//cur_alt_setting = p[INTF_DESC_bAlternateSetting];
|
||||
break;
|
||||
case CDC_CS_INTERFACE:
|
||||
if ((cur_iface == cdc_ecm_class->ctrl_intf) && p[DESC_bDescriptorSubType] == CDC_FUNC_DESC_ETHERNET_NETWORKING) {
|
||||
struct cdc_ecm_descriptor *desc = (struct cdc_ecm_descriptor *)p;
|
||||
mac_str_idx = desc->iMACAddress;
|
||||
cdc_ecm_class->max_segment_size = desc->wMaxSegmentSize;
|
||||
goto get_mac;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* skip to next descriptor */
|
||||
p += p[DESC_bLength];
|
||||
}
|
||||
|
||||
get_mac:
|
||||
if (mac_str_idx == 0xff) {
|
||||
USB_LOG_ERR("Do not find cdc ecm mac string\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(mac_buffer, 0, 8);
|
||||
ret = usbh_get_string_desc(cdc_ecm_class->hport, mac_str_idx, (uint8_t *)mac_buffer);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = 0, j = 0; i < 12; i += 2, j++) {
|
||||
char byte_str[3];
|
||||
byte_str[0] = mac_buffer[i];
|
||||
byte_str[1] = mac_buffer[i + 1];
|
||||
byte_str[2] = '\0';
|
||||
|
||||
uint32_t byte = strtoul(byte_str, NULL, 16);
|
||||
cdc_ecm_class->mac[j] = (unsigned char)byte;
|
||||
}
|
||||
|
||||
USB_LOG_INFO("CDC ECM MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
|
||||
cdc_ecm_class->mac[0],
|
||||
cdc_ecm_class->mac[1],
|
||||
cdc_ecm_class->mac[2],
|
||||
cdc_ecm_class->mac[3],
|
||||
cdc_ecm_class->mac[4],
|
||||
cdc_ecm_class->mac[5]);
|
||||
|
||||
if (cdc_ecm_class->max_segment_size > CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE) {
|
||||
USB_LOG_ERR("CDC ECM Max Segment Size is overflow, default is %u, but now %u\r\n", CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE, cdc_ecm_class->max_segment_size);
|
||||
} else {
|
||||
USB_LOG_INFO("CDC ECM Max Segment Size:%u\r\n", cdc_ecm_class->max_segment_size);
|
||||
}
|
||||
|
||||
/* enable int ep */
|
||||
ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
|
||||
usbh_hport_activate_epx(&cdc_ecm_class->intin, hport, ep_desc);
|
||||
|
||||
if (hport->config.intf[intf + 1].altsetting_num > 1) {
|
||||
altsetting = hport->config.intf[intf + 1].altsetting_num - 1;
|
||||
|
||||
for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[altsetting].intf_desc.bNumEndpoints; i++) {
|
||||
ep_desc = &hport->config.intf[intf + 1].altsetting[altsetting].ep[i].ep_desc;
|
||||
|
||||
if (ep_desc->bEndpointAddress & 0x80) {
|
||||
usbh_hport_activate_epx(&cdc_ecm_class->bulkin, hport, ep_desc);
|
||||
} else {
|
||||
usbh_hport_activate_epx(&cdc_ecm_class->bulkout, hport, ep_desc);
|
||||
}
|
||||
}
|
||||
|
||||
USB_LOG_INFO("Select cdc ecm altsetting: %d\r\n", altsetting);
|
||||
usbh_set_interface(cdc_ecm_class->hport, cdc_ecm_class->data_intf, altsetting);
|
||||
} else {
|
||||
for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
||||
ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
|
||||
|
||||
if (ep_desc->bEndpointAddress & 0x80) {
|
||||
usbh_hport_activate_epx(&cdc_ecm_class->bulkin, hport, ep_desc);
|
||||
} else {
|
||||
usbh_hport_activate_epx(&cdc_ecm_class->bulkout, hport, ep_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* bit0 Promiscuous
|
||||
* bit1 ALL Multicast
|
||||
* bit2 Directed
|
||||
* bit3 Broadcast
|
||||
* bit4 Multicast
|
||||
*/
|
||||
ret = usbh_cdc_ecm_set_eth_packet_filter(cdc_ecm_class, CONFIG_USBHOST_CDC_ECM_PKT_FILTER);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
USB_LOG_INFO("Set CDC ECM packet filter:%04x\r\n", CONFIG_USBHOST_CDC_ECM_PKT_FILTER);
|
||||
|
||||
memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
|
||||
|
||||
USB_LOG_INFO("Register CDC ECM Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
|
||||
usbh_cdc_ecm_run(cdc_ecm_class);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbh_cdc_ecm_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct usbh_cdc_ecm *cdc_ecm_class = (struct usbh_cdc_ecm *)hport->config.intf[intf].priv;
|
||||
|
||||
if (cdc_ecm_class) {
|
||||
if (cdc_ecm_class->bulkin) {
|
||||
usbh_pipe_free(cdc_ecm_class->bulkin);
|
||||
}
|
||||
|
||||
if (cdc_ecm_class->bulkout) {
|
||||
usbh_pipe_free(cdc_ecm_class->bulkout);
|
||||
}
|
||||
|
||||
if (cdc_ecm_class->intin) {
|
||||
usbh_pipe_free(cdc_ecm_class->intin);
|
||||
}
|
||||
|
||||
if (hport->config.intf[intf].devname[0] != '\0') {
|
||||
USB_LOG_INFO("Unregister CDC ECM Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
usbh_cdc_ecm_stop(cdc_ecm_class);
|
||||
}
|
||||
|
||||
memset(cdc_ecm_class, 0, sizeof(struct usbh_cdc_ecm));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usbh_cdc_ecm_rx_thread(void *argument)
|
||||
{
|
||||
uint32_t g_cdc_ecm_rx_length;
|
||||
int ret;
|
||||
err_t err;
|
||||
struct pbuf *p;
|
||||
struct netif *netif = (struct netif *)argument;
|
||||
uint16_t ep_mps;
|
||||
|
||||
// clang-format off
|
||||
find_class:
|
||||
// clang-format on
|
||||
while (usbh_find_class_instance("/dev/cdc_ether") == NULL) {
|
||||
usb_osal_msleep(1000);
|
||||
}
|
||||
|
||||
while (g_cdc_ecm_class.connect_status == CDC_ECM_NET_DISCONNECTED) {
|
||||
ret = usbh_cdc_ecm_get_notification(&g_cdc_ecm_class);
|
||||
if (ret < 0) {
|
||||
goto find_class;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_cdc_ecm_class.hport->speed == USB_SPEED_FULL) {
|
||||
ep_mps = 64;
|
||||
} else {
|
||||
ep_mps = 512;
|
||||
}
|
||||
g_cdc_ecm_rx_length = 0;
|
||||
while (1) {
|
||||
usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkin_urb, g_cdc_ecm_class.bulkin, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_length], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
|
||||
ret = usbh_submit_urb(&g_cdc_ecm_class.bulkin_urb);
|
||||
if (ret < 0) {
|
||||
goto find_class;
|
||||
}
|
||||
|
||||
g_cdc_ecm_rx_length += g_cdc_ecm_class.bulkin_urb.actual_length;
|
||||
|
||||
if (g_cdc_ecm_rx_length % ep_mps) {
|
||||
USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_length);
|
||||
|
||||
p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_length, PBUF_POOL);
|
||||
if (p != NULL) {
|
||||
memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_length);
|
||||
g_cdc_ecm_rx_length = 0;
|
||||
err = netif->input(p, netif);
|
||||
if (err != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
} else {
|
||||
g_cdc_ecm_rx_length = 0;
|
||||
USB_LOG_ERR("No memory to alloc pbuf for cdc ecm rx\r\n");
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
int ret;
|
||||
struct pbuf *q;
|
||||
uint8_t *buffer = g_cdc_ecm_tx_buffer;
|
||||
|
||||
if (g_cdc_ecm_class.connect_status == CDC_ECM_NET_DISCONNECTED) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
memcpy(buffer, q->payload, q->len);
|
||||
buffer += q->len;
|
||||
}
|
||||
|
||||
USB_LOG_DBG("txlen:%d\r\n", p->tot_len);
|
||||
|
||||
usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkout_urb, g_cdc_ecm_class.bulkout, g_cdc_ecm_tx_buffer, p->tot_len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
|
||||
ret = usbh_submit_urb(&g_cdc_ecm_class.bulkout_urb);
|
||||
if (ret < 0) {
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void usbh_cdc_ecm_lwip_thread_init(struct netif *netif)
|
||||
{
|
||||
usb_osal_thread_create("usbh_cdc_ecm_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_cdc_ecm_rx_thread, netif);
|
||||
}
|
||||
|
||||
__WEAK void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
|
||||
{
|
||||
}
|
||||
|
||||
const struct usbh_class_driver cdc_ecm_class_driver = {
|
||||
.driver_name = "cdc_ecm",
|
||||
.connect = usbh_cdc_ecm_connect,
|
||||
.disconnect = usbh_cdc_ecm_disconnect
|
||||
};
|
||||
|
||||
CLASS_INFO_DEFINE const struct usbh_class_info cdc_ecm_class_info = {
|
||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
||||
.class = USB_DEVICE_CLASS_CDC,
|
||||
.subclass = CDC_ETHERNET_NETWORKING_CONTROL_MODEL,
|
||||
.protocol = CDC_COMMON_PROTOCOL_NONE,
|
||||
.vid = 0x00,
|
||||
.pid = 0x00,
|
||||
.class_driver = &cdc_ecm_class_driver
|
||||
};
|
||||
50
class/cdc/usbh_cdc_ecm.h
Normal file
50
class/cdc/usbh_cdc_ecm.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef USBH_CDC_ECM_H
|
||||
#define USBH_CDC_ECM_H
|
||||
|
||||
#include "usb_cdc.h"
|
||||
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/pbuf.h"
|
||||
|
||||
struct usbh_cdc_ecm {
|
||||
struct usbh_hubport *hport;
|
||||
|
||||
uint8_t ctrl_intf; /* Control interface number */
|
||||
uint8_t data_intf; /* Data interface number */
|
||||
uint8_t minor;
|
||||
uint8_t mac[6];
|
||||
uint32_t max_segment_size;
|
||||
uint8_t connect_status;
|
||||
uint32_t speed[2];
|
||||
usbh_pipe_t bulkin; /* Bulk IN endpoint */
|
||||
usbh_pipe_t bulkout; /* Bulk OUT endpoint */
|
||||
usbh_pipe_t intin; /* Interrupt IN endpoint */
|
||||
struct usbh_urb bulkout_urb;
|
||||
struct usbh_urb bulkin_urb;
|
||||
struct usbh_urb intin_urb;
|
||||
|
||||
ip_addr_t ipaddr;
|
||||
ip_addr_t netmask;
|
||||
ip_addr_t gateway;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class);
|
||||
void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class);
|
||||
|
||||
err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p);
|
||||
void usbh_cdc_ecm_lwip_thread_init(struct netif *netif);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBH_CDC_ACM_H */
|
||||
@@ -108,7 +108,7 @@ static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
|
||||
memcpy(buffer, g_hub_buf, USB_SIZEOF_HUB_DESC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int _usbh_hub_get_status(struct usbh_hub *hub, uint8_t *buffer)
|
||||
{
|
||||
struct usb_setup_packet *setup;
|
||||
@@ -130,6 +130,7 @@ static int _usbh_hub_get_status(struct usbh_hub *hub, uint8_t *buffer)
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int _usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct hub_port_status *port_status)
|
||||
{
|
||||
@@ -298,7 +299,8 @@ static void hub_int_complete_callback(void *arg, int nbytes)
|
||||
{
|
||||
struct usbh_hub *hub = (struct usbh_hub *)arg;
|
||||
|
||||
if (nbytes > 0) {
|
||||
if (nbytes > 0)
|
||||
{
|
||||
usbh_hub_thread_wakeup(hub);
|
||||
}
|
||||
}
|
||||
@@ -311,7 +313,7 @@ static int usbh_hub_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
|
||||
struct usbh_hub *hub = usbh_hub_class_alloc();
|
||||
if (hub == NULL) {
|
||||
USB_LOG_ERR("Fail to alloc cdc_acm_class\r\n");
|
||||
USB_LOG_ERR("Fail to alloc hub_class\r\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -460,9 +462,10 @@ static void usbh_hub_events(struct usbh_hub *hub)
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
|
||||
portchange_index = hub->int_buffer[0];
|
||||
portchange_index = hub->int_buffer[0];
|
||||
hub->int_buffer[0] = 0;
|
||||
|
||||
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
|
||||
USB_LOG_DBG("Port change:0x%02x\r\n", portchange_index);
|
||||
|
||||
if (!(portchange_index & (1 << (port + 1)))) {
|
||||
@@ -625,7 +628,6 @@ static void usbh_hub_events(struct usbh_hub *hub)
|
||||
}
|
||||
}
|
||||
|
||||
hub->int_buffer[0] = 0;
|
||||
/* Start next hub int transfer */
|
||||
if (!hub->is_roothub && hub->connected) {
|
||||
usbh_submit_urb(&hub->intin_urb);
|
||||
@@ -639,7 +641,7 @@ static void usbh_hub_thread(void *argument)
|
||||
|
||||
usb_hc_init();
|
||||
while (1) {
|
||||
ret = usb_osal_mq_recv(hub_mq, (uintptr_t *)&hub, 0xffffffff);
|
||||
ret = usb_osal_mq_recv(hub_mq, (uintptr_t *)&hub, USB_OSAL_WAITING_FOREVER);
|
||||
if (ret < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_msc.h"
|
||||
#include "usb_scsi.h"
|
||||
#if defined(CONFIG_USBDEV_MSC_THREAD)
|
||||
#include "usb_osal.h"
|
||||
#endif
|
||||
|
||||
#define MSD_OUT_EP_IDX 0
|
||||
#define MSD_IN_EP_IDX 1
|
||||
@@ -41,6 +44,12 @@ USB_NOCACHE_RAM_SECTION struct usbd_msc_priv {
|
||||
uint32_t scsi_blk_nbr;
|
||||
|
||||
USB_MEM_ALIGNX uint8_t block_buffer[CONFIG_USBDEV_MSC_BLOCK_SIZE];
|
||||
|
||||
#if defined(CONFIG_USBDEV_MSC_THREAD)
|
||||
usb_osal_mq_t usbd_msc_mq;
|
||||
usb_osal_thread_t usbd_msc_thread;
|
||||
uint32_t nbytes;
|
||||
#endif
|
||||
} g_usbd_msc;
|
||||
|
||||
static void usbd_msc_reset(void)
|
||||
@@ -481,7 +490,12 @@ static bool SCSI_read10(uint8_t **data, uint32_t *len)
|
||||
return false;
|
||||
}
|
||||
g_usbd_msc.stage = MSC_DATA_IN;
|
||||
#ifdef CONFIG_USBDEV_MSC_THREAD
|
||||
usb_osal_mq_send(g_usbd_msc.usbd_msc_mq, MSC_DATA_IN);
|
||||
return true;
|
||||
#else
|
||||
return SCSI_processRead();
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool SCSI_read12(uint8_t **data, uint32_t *len)
|
||||
@@ -508,7 +522,12 @@ static bool SCSI_read12(uint8_t **data, uint32_t *len)
|
||||
return false;
|
||||
}
|
||||
g_usbd_msc.stage = MSC_DATA_IN;
|
||||
#ifdef CONFIG_USBDEV_MSC_THREAD
|
||||
usb_osal_mq_send(g_usbd_msc.usbd_msc_mq, MSC_DATA_IN);
|
||||
return true;
|
||||
#else
|
||||
return SCSI_processRead();
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool SCSI_write10(uint8_t **data, uint32_t *len)
|
||||
@@ -764,9 +783,14 @@ void mass_storage_bulk_out(uint8_t ep, uint32_t nbytes)
|
||||
switch (g_usbd_msc.cbw.CB[0]) {
|
||||
case SCSI_CMD_WRITE10:
|
||||
case SCSI_CMD_WRITE12:
|
||||
#ifdef CONFIG_USBDEV_MSC_THREAD
|
||||
g_usbd_msc.nbytes = nbytes;
|
||||
usb_osal_mq_send(g_usbd_msc.usbd_msc_mq, MSC_DATA_OUT);
|
||||
#else
|
||||
if (SCSI_processWrite(nbytes) == false) {
|
||||
usbd_msc_send_csw(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -784,10 +808,14 @@ void mass_storage_bulk_in(uint8_t ep, uint32_t nbytes)
|
||||
switch (g_usbd_msc.cbw.CB[0]) {
|
||||
case SCSI_CMD_READ10:
|
||||
case SCSI_CMD_READ12:
|
||||
#ifdef CONFIG_USBDEV_MSC_THREAD
|
||||
usb_osal_mq_send(g_usbd_msc.usbd_msc_mq, MSC_DATA_IN);
|
||||
#else
|
||||
if (SCSI_processRead() == false) {
|
||||
usbd_msc_send_csw(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -810,6 +838,32 @@ void mass_storage_bulk_in(uint8_t ep, uint32_t nbytes)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBDEV_MSC_THREAD
|
||||
static void usbdev_msc_thread(void *argument)
|
||||
{
|
||||
uintptr_t event;
|
||||
int ret;
|
||||
|
||||
while (1) {
|
||||
ret = usb_osal_mq_recv(g_usbd_msc.usbd_msc_mq, (uintptr_t *)&event, USB_OSAL_WAITING_FOREVER);
|
||||
if (ret < 0) {
|
||||
continue;
|
||||
}
|
||||
USB_LOG_DBG("%d\r\n", event);
|
||||
if (event == MSC_DATA_OUT) {
|
||||
if (SCSI_processWrite(g_usbd_msc.nbytes) == false) {
|
||||
usbd_msc_send_csw(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
|
||||
}
|
||||
} else if (event == MSC_DATA_IN) {
|
||||
if (SCSI_processRead() == false) {
|
||||
usbd_msc_send_csw(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct usbd_interface *usbd_msc_init_intf(struct usbd_interface *intf, const uint8_t out_ep, const uint8_t in_ep)
|
||||
{
|
||||
intf->class_interface_handler = msc_storage_class_interface_request_handler;
|
||||
@@ -834,6 +888,16 @@ struct usbd_interface *usbd_msc_init_intf(struct usbd_interface *intf, const uin
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBDEV_MSC_THREAD
|
||||
g_usbd_msc.usbd_msc_mq = usb_osal_mq_create(1);
|
||||
if (g_usbd_msc.usbd_msc_mq == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
g_usbd_msc.usbd_msc_thread = usb_osal_thread_create("usbd_msc", CONFIG_USBDEV_MSC_STACKSIZE, CONFIG_USBDEV_MSC_PRIO, usbdev_msc_thread, NULL);
|
||||
if (g_usbd_msc.usbd_msc_thread == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
return intf;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_msc_buf[32];
|
||||
|
||||
static struct usbh_msc g_msc_class[CONFIG_USBHOST_MAX_MSC_CLASS];
|
||||
static uint32_t g_devinuse = 0;
|
||||
static struct usbh_msc_modeswitch_config *g_msc_modeswitch_config = NULL;
|
||||
|
||||
static struct usbh_msc *usbh_msc_class_alloc(void)
|
||||
{
|
||||
@@ -274,10 +275,32 @@ int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, cons
|
||||
return usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, (uint8_t *)buffer);
|
||||
}
|
||||
|
||||
void usbh_msc_modeswitch_enable(struct usbh_msc_modeswitch_config *config)
|
||||
{
|
||||
if (config) {
|
||||
g_msc_modeswitch_config = config;
|
||||
} else {
|
||||
g_msc_modeswitch_config = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void usbh_msc_modeswitch(struct usbh_msc *msc_class, const uint8_t *message)
|
||||
{
|
||||
struct CBW *cbw;
|
||||
|
||||
/* Construct the CBW */
|
||||
cbw = (struct CBW *)g_msc_buf;
|
||||
|
||||
memcpy(g_msc_buf, message, 31);
|
||||
|
||||
usbh_bulk_cbw_csw_xfer(msc_class, cbw, (struct CSW *)g_msc_buf, NULL);
|
||||
}
|
||||
|
||||
static int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret;
|
||||
struct usbh_msc_modeswitch_config *config;
|
||||
|
||||
struct usbh_msc *msc_class = usbh_msc_class_alloc();
|
||||
if (msc_class == NULL) {
|
||||
@@ -306,6 +329,23 @@ static int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
}
|
||||
}
|
||||
|
||||
if (g_msc_modeswitch_config) {
|
||||
uint8_t num = 0;
|
||||
while (1) {
|
||||
config = &g_msc_modeswitch_config[num];
|
||||
if (config) {
|
||||
if ((hport->device_desc.idVendor == config->vid) &&
|
||||
(hport->device_desc.idProduct == config->pid)) {
|
||||
USB_LOG_INFO("%s usb_modeswitch enable\r\n", config->name);
|
||||
usbh_msc_modeswitch(msc_class, config->message_content);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = usbh_msc_scsi_testunitready(msc_class);
|
||||
if (ret < 0) {
|
||||
ret = usbh_msc_scsi_requestsense(msc_class);
|
||||
@@ -314,6 +354,7 @@ static int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = usbh_msc_scsi_inquiry(msc_class);
|
||||
if (ret < 0) {
|
||||
USB_LOG_ERR("Fail to scsi_inquiry\r\n");
|
||||
|
||||
@@ -22,6 +22,14 @@ struct usbh_msc {
|
||||
uint16_t blocksize; /* Block size of USB mass storage device */
|
||||
};
|
||||
|
||||
struct usbh_msc_modeswitch_config {
|
||||
const char *name;
|
||||
uint16_t vid; /* Vendor ID (for vendor/product specific devices) */
|
||||
uint16_t pid; /* Product ID (for vendor/product specific devices) */
|
||||
const uint8_t *message_content;
|
||||
};
|
||||
|
||||
void usbh_msc_modeswitch_enable(struct usbh_msc_modeswitch_config *config);
|
||||
int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors);
|
||||
int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors);
|
||||
|
||||
|
||||
28
class/vendor/air72x/usbh_air724.c
vendored
28
class/vendor/air72x/usbh_air724.c
vendored
@@ -16,6 +16,8 @@ struct usbh_cdc_custom_air724 {
|
||||
struct usbh_urb bulkout_urb; /* Bulk OUT urb */
|
||||
};
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_air724_buf[32];
|
||||
|
||||
static inline int usbh_air724_bulk_out_transfer(struct usbh_cdc_custom_air724 *cdc_custom_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
@@ -30,12 +32,26 @@ static inline int usbh_air724_bulk_out_transfer(struct usbh_cdc_custom_air724 *c
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int usbh_air724_bulk_in_transfer(struct usbh_cdc_custom_air724 *cdc_custom_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
|
||||
{
|
||||
int ret;
|
||||
struct usbh_urb *urb = &cdc_custom_class->bulkin_urb;
|
||||
memset(urb, 0, sizeof(struct usbh_urb));
|
||||
|
||||
usbh_bulk_urb_fill(urb, cdc_custom_class->bulkin, buffer, buflen, timeout, NULL, NULL);
|
||||
ret = usbh_submit_urb(urb);
|
||||
if (ret == 0) {
|
||||
ret = urb->actual_length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_air724_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usbh_endpoint_cfg ep_cfg = { 0 };
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret;
|
||||
|
||||
/* interface 3 is AT command */
|
||||
if (intf != 3) {
|
||||
USB_LOG_WRN("ignore intf:%d\r\n", intf);
|
||||
return 0;
|
||||
@@ -65,20 +81,22 @@ int usbh_air724_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
|
||||
USB_LOG_INFO("Register air724 Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
|
||||
uint8_t cdc_buffer[32] = { 0x41, 0x54, 0x0d, 0x0a };
|
||||
ret = usbh_air724_bulk_out_transfer(cdc_custom_class->bulkout, cdc_buffer, 4, 3000);
|
||||
const uint8_t AT[4] = { 0x41, 0x54, 0x0d, 0x0a };
|
||||
|
||||
memcpy(g_air724_buf, AT, 4);
|
||||
ret = usbh_air724_bulk_out_transfer(cdc_custom_class, g_air724_buf, 4, 3000);
|
||||
if (ret < 0) {
|
||||
USB_LOG_ERR("bulk out error,ret:%d\r\n", ret);
|
||||
} else {
|
||||
USB_LOG_RAW("send over:%d\r\n", ret);
|
||||
}
|
||||
ret = usbh_air724_bulk_out_transfer(cdc_custom_class->bulkin, cdc_buffer, 10, 3000);
|
||||
ret = usbh_air724_bulk_in_transfer(cdc_custom_class, g_air724_buf, 10, 3000);
|
||||
if (ret < 0) {
|
||||
USB_LOG_ERR("bulk in error,ret:%d\r\n", ret);
|
||||
} else {
|
||||
USB_LOG_RAW("recv over:%d\r\n", ret);
|
||||
for (size_t i = 0; i < ret; i++) {
|
||||
USB_LOG_RAW("0x%02x ", cdc_buffer[i]);
|
||||
USB_LOG_RAW("0x%02x ", g_air724_buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -769,14 +769,14 @@ uint32_t usbd_video_mjpeg_payload_fill(uint8_t *input, uint32_t input_len, uint8
|
||||
uint32_t picture_pos = 0;
|
||||
static uint8_t uvc_header[2] = { 0x02, 0x80 };
|
||||
|
||||
packets = input_len / g_usbd_video.probe.dwMaxPayloadTransferSize + 1;
|
||||
last_packet_size = input_len - ((packets - 1) * (g_usbd_video.probe.dwMaxPayloadTransferSize - 2)) + 2;
|
||||
packets = (input_len + (g_usbd_video.probe.dwMaxPayloadTransferSize - 2) ) / (g_usbd_video.probe.dwMaxPayloadTransferSize - 2);
|
||||
last_packet_size = input_len - ((packets - 1) * (g_usbd_video.probe.dwMaxPayloadTransferSize - 2));
|
||||
|
||||
for (size_t i = 0; i < packets; i++) {
|
||||
output[g_usbd_video.probe.dwMaxPayloadTransferSize * i] = uvc_header[0];
|
||||
output[g_usbd_video.probe.dwMaxPayloadTransferSize * i + 1] = uvc_header[1];
|
||||
if (i == (packets - 1)) {
|
||||
memcpy(&output[2 + g_usbd_video.probe.dwMaxPayloadTransferSize * i], &input[picture_pos], last_packet_size - 2);
|
||||
memcpy(&output[2 + g_usbd_video.probe.dwMaxPayloadTransferSize * i], &input[picture_pos], last_packet_size);
|
||||
output[g_usbd_video.probe.dwMaxPayloadTransferSize * i + 1] |= (1 << 1);
|
||||
} else {
|
||||
memcpy(&output[2 + g_usbd_video.probe.dwMaxPayloadTransferSize * i], &input[picture_pos], g_usbd_video.probe.dwMaxPayloadTransferSize - 2);
|
||||
|
||||
@@ -53,32 +53,45 @@ static void usbh_video_class_free(struct usbh_video *video_class)
|
||||
memset(video_class, 0, sizeof(struct usbh_video));
|
||||
}
|
||||
|
||||
int usbh_video_get_cur(struct usbh_video *video_class, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len)
|
||||
int usbh_video_get(struct usbh_video *video_class, uint8_t request, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
struct usb_setup_packet *setup = video_class->hport->setup;
|
||||
int ret;
|
||||
uint8_t retry;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = VIDEO_REQUEST_GET_CUR;
|
||||
setup->bRequest = request;
|
||||
setup->wValue = cs << 8;
|
||||
setup->wIndex = (entity_id << 8) | intf;
|
||||
setup->wLength = len;
|
||||
|
||||
ret = usbh_control_transfer(video_class->hport->ep0, setup, g_video_buf);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
retry = 0;
|
||||
while (1) {
|
||||
ret = usbh_control_transfer(video_class->hport->ep0, setup, g_video_buf);
|
||||
if (ret > 0) {
|
||||
break;
|
||||
}
|
||||
retry++;
|
||||
|
||||
if (retry == 3) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
memcpy(buf, g_video_buf, len);
|
||||
|
||||
if (buf) {
|
||||
memcpy(buf, g_video_buf, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_video_set_cur(struct usbh_video *video_class, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len)
|
||||
int usbh_video_set(struct usbh_video *video_class, uint8_t request, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
struct usb_setup_packet *setup = video_class->hport->setup;
|
||||
int ret;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = VIDEO_REQUEST_SET_CUR;
|
||||
setup->bRequest = request;
|
||||
setup->wValue = cs << 8;
|
||||
setup->wIndex = (entity_id << 8) | intf;
|
||||
setup->wLength = len;
|
||||
@@ -86,13 +99,13 @@ int usbh_video_set_cur(struct usbh_video *video_class, uint8_t intf, uint8_t ent
|
||||
memcpy(g_video_buf, buf, len);
|
||||
|
||||
ret = usbh_control_transfer(video_class->hport->ep0, setup, g_video_buf);
|
||||
usb_osal_msleep(5);
|
||||
usb_osal_msleep(50);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_videostreaming_get_cur_probe(struct usbh_video *video_class)
|
||||
{
|
||||
return usbh_video_get_cur(video_class, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, (uint8_t *)&video_class->probe, 26);
|
||||
return usbh_video_get(video_class, VIDEO_REQUEST_GET_CUR, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, (uint8_t *)&video_class->probe, 26);
|
||||
}
|
||||
|
||||
int usbh_videostreaming_set_cur_probe(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex)
|
||||
@@ -100,7 +113,8 @@ int usbh_videostreaming_set_cur_probe(struct usbh_video *video_class, uint8_t fo
|
||||
video_class->probe.bFormatIndex = formatindex;
|
||||
video_class->probe.bFrameIndex = frameindex;
|
||||
video_class->probe.dwMaxPayloadTransferSize = 0;
|
||||
return usbh_video_set_cur(video_class, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, (uint8_t *)&video_class->probe, 26);
|
||||
video_class->probe.dwFrameInterval = 333333;
|
||||
return usbh_video_set(video_class, VIDEO_REQUEST_SET_CUR, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, (uint8_t *)&video_class->probe, 26);
|
||||
}
|
||||
|
||||
int usbh_videostreaming_set_cur_commit(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex)
|
||||
@@ -108,7 +122,8 @@ int usbh_videostreaming_set_cur_commit(struct usbh_video *video_class, uint8_t f
|
||||
memcpy(&video_class->commit, &video_class->probe, sizeof(struct video_probe_and_commit_controls));
|
||||
video_class->commit.bFormatIndex = formatindex;
|
||||
video_class->commit.bFrameIndex = frameindex;
|
||||
return usbh_video_set_cur(video_class, video_class->data_intf, 0x00, VIDEO_VS_COMMIT_CONTROL, (uint8_t *)&video_class->commit, 26);
|
||||
video_class->commit.dwFrameInterval = 333333;
|
||||
return usbh_video_set(video_class, VIDEO_REQUEST_SET_CUR, video_class->data_intf, 0x00, VIDEO_VS_COMMIT_CONTROL, (uint8_t *)&video_class->commit, 26);
|
||||
}
|
||||
|
||||
int usbh_video_open(struct usbh_video *video_class,
|
||||
@@ -125,6 +140,7 @@ int usbh_video_open(struct usbh_video *video_class,
|
||||
bool found = false;
|
||||
uint8_t formatidx = 0;
|
||||
uint8_t frameidx = 0;
|
||||
uint8_t step;
|
||||
|
||||
if (video_class->is_opened) {
|
||||
return -EMFILE;
|
||||
@@ -152,31 +168,65 @@ int usbh_video_open(struct usbh_video *video_class,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Open video step:
|
||||
* Get CUR request (probe)
|
||||
* Set CUR request (probe)
|
||||
* Get CUR request (probe)
|
||||
* Get MAX request (probe)
|
||||
* Get MIN request (probe)
|
||||
* Get CUR request (probe)
|
||||
* Set CUR request (commit)
|
||||
*
|
||||
*/
|
||||
step = 0;
|
||||
ret = usbh_videostreaming_get_cur_probe(video_class);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = usbh_videostreaming_get_cur_probe(video_class);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = usbh_videostreaming_get_cur_probe(video_class);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = usbh_videostreaming_set_cur_commit(video_class, formatidx, frameidx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
step = 1;
|
||||
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx);
|
||||
if (ret < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
step = 2;
|
||||
ret = usbh_videostreaming_get_cur_probe(video_class);
|
||||
if (ret < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
step = 3;
|
||||
ret = usbh_video_get(video_class, VIDEO_REQUEST_GET_MAX, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, NULL, 26);
|
||||
if (ret < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
step = 4;
|
||||
ret = usbh_video_get(video_class, VIDEO_REQUEST_GET_MIN, video_class->data_intf, 0x00, VIDEO_VS_PROBE_CONTROL, NULL, 26);
|
||||
if (ret < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
step = 5;
|
||||
ret = usbh_videostreaming_set_cur_probe(video_class, formatidx, frameidx);
|
||||
if (ret < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
step = 6;
|
||||
ret = usbh_videostreaming_get_cur_probe(video_class);
|
||||
if (ret < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
step = 7;
|
||||
ret = usbh_videostreaming_set_cur_commit(video_class, formatidx, frameidx);
|
||||
if (ret < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
step = 8;
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = USB_REQUEST_SET_INTERFACE;
|
||||
setup->wValue = altsetting;
|
||||
@@ -185,7 +235,7 @@ int usbh_video_open(struct usbh_video *video_class,
|
||||
|
||||
ret = usbh_control_transfer(video_class->hport->ep0, setup, NULL);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ep_desc = &video_class->hport->config.intf[video_class->data_intf].altsetting[altsetting].ep[0].ep_desc;
|
||||
@@ -203,6 +253,10 @@ int usbh_video_open(struct usbh_video *video_class,
|
||||
video_class->is_opened = true;
|
||||
video_class->current_format = format_type;
|
||||
return ret;
|
||||
|
||||
errout:
|
||||
USB_LOG_ERR("Fail to open video in step %u\r\n", step);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_video_close(struct usbh_video *video_class)
|
||||
|
||||
@@ -25,6 +25,8 @@ struct usbh_video_format {
|
||||
struct usbh_videostreaming {
|
||||
uint32_t bufoffset;
|
||||
uint32_t buflen;
|
||||
uint16_t width;
|
||||
uint16_t heigth;
|
||||
void (*video_one_frame_callback)(struct usbh_videostreaming *stream);
|
||||
};
|
||||
|
||||
@@ -52,11 +54,8 @@ struct usbh_video {
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int usbh_video_get_cur(struct usbh_video *video_class, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len);
|
||||
int usbh_video_set_cur(struct usbh_video *video_class, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len);
|
||||
int usbh_videostreaming_get_cur_probe(struct usbh_video *video_class);
|
||||
int usbh_videostreaming_set_cur_probe(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex);
|
||||
int usbh_videostreaming_set_cur_commit(struct usbh_video *video_class, uint8_t formatindex, uint8_t frameindex);
|
||||
int usbh_video_get(struct usbh_video *video_class, uint8_t request, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len);
|
||||
int usbh_video_set(struct usbh_video *video_class, uint8_t request, uint8_t intf, uint8_t entity_id, uint8_t cs, uint8_t *buf, uint16_t len);
|
||||
|
||||
int usbh_video_open(struct usbh_video *video_class,
|
||||
uint8_t format_type,
|
||||
|
||||
@@ -394,7 +394,7 @@ static int rndis_set_cmd_handler(uint8_t *data, uint32_t len)
|
||||
|
||||
static int rndis_reset_cmd_handler(uint8_t *data, uint32_t len)
|
||||
{
|
||||
rndis_reset_msg_t *cmd = (rndis_reset_msg_t *)data;
|
||||
// rndis_reset_msg_t *cmd = (rndis_reset_msg_t *)data;
|
||||
rndis_reset_cmplt_t *resp;
|
||||
|
||||
resp = ((rndis_reset_cmplt_t *)rndis_encapsulated_resp_buffer);
|
||||
|
||||
@@ -7,37 +7,11 @@
|
||||
#include "usbh_rndis.h"
|
||||
#include "rndis_protocol.h"
|
||||
|
||||
#define DEV_FORMAT "/dev/rndis%d"
|
||||
#define DEV_FORMAT "/dev/rndis"
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_buf[4096];
|
||||
|
||||
static struct usbh_rndis g_rndis_class[CONFIG_USBHOST_MAX_RNDIS_CLASS];
|
||||
static uint32_t g_devinuse = 0;
|
||||
|
||||
static struct usbh_rndis *usbh_rndis_class_alloc(void)
|
||||
{
|
||||
int devno;
|
||||
|
||||
for (devno = 0; devno < CONFIG_USBHOST_MAX_RNDIS_CLASS; devno++) {
|
||||
if ((g_devinuse & (1 << devno)) == 0) {
|
||||
g_devinuse |= (1 << devno);
|
||||
memset(&g_rndis_class[devno], 0, sizeof(struct usbh_rndis));
|
||||
g_rndis_class[devno].minor = devno;
|
||||
return &g_rndis_class[devno];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void usbh_rndis_class_free(struct usbh_rndis *rndis_class)
|
||||
{
|
||||
int devno = rndis_class->minor;
|
||||
|
||||
if (devno >= 0 && devno < 32) {
|
||||
g_devinuse &= ~(1 << devno);
|
||||
}
|
||||
memset(rndis_class, 0, sizeof(struct usbh_rndis));
|
||||
}
|
||||
static struct usbh_rndis g_rndis_class;
|
||||
|
||||
static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
|
||||
{
|
||||
@@ -107,7 +81,7 @@ int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid,
|
||||
setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = 0;
|
||||
setup->wLength = sizeof(rndis_query_msg_t);
|
||||
setup->wLength = query_len + sizeof(rndis_query_msg_t);
|
||||
|
||||
ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)cmd);
|
||||
if (ret < 0) {
|
||||
@@ -159,7 +133,7 @@ static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t
|
||||
setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = 0;
|
||||
setup->wLength = sizeof(rndis_set_msg_t);
|
||||
setup->wLength = info_len + sizeof(rndis_set_msg_t);
|
||||
|
||||
ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)cmd);
|
||||
if (ret < 0) {
|
||||
@@ -260,7 +234,6 @@ int usbh_rndis_keepalive(struct usbh_rndis *rndis_class)
|
||||
|
||||
static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
{
|
||||
struct usbh_endpoint_cfg ep_cfg = { 0 };
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
int ret;
|
||||
uint32_t *oid_support_list;
|
||||
@@ -270,11 +243,9 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
uint8_t tmp_buffer[512];
|
||||
uint8_t data[32];
|
||||
|
||||
struct usbh_rndis *rndis_class = usbh_rndis_class_alloc();
|
||||
if (rndis_class == NULL) {
|
||||
USB_LOG_ERR("Fail to alloc rndis_class\r\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
struct usbh_rndis *rndis_class = &g_rndis_class;
|
||||
|
||||
memset(rndis_class, 0, sizeof(struct usbh_rndis));
|
||||
|
||||
rndis_class->hport = hport;
|
||||
rndis_class->ctrl_intf = intf;
|
||||
@@ -389,7 +360,7 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||
}
|
||||
USB_LOG_INFO("rndis set OID_802_3_MULTICAST_LIST success\r\n");
|
||||
|
||||
snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, rndis_class->minor);
|
||||
memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
|
||||
|
||||
USB_LOG_INFO("Register RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
|
||||
usbh_rndis_run(rndis_class);
|
||||
@@ -419,7 +390,7 @@ static int usbh_rndis_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||
usbh_rndis_stop(rndis_class);
|
||||
}
|
||||
|
||||
usbh_rndis_class_free(rndis_class);
|
||||
memset(rndis_class, 0, sizeof(struct usbh_rndis));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -59,7 +59,11 @@ struct usbh_urb {
|
||||
uint32_t start_frame;
|
||||
usbh_complete_callback_t complete;
|
||||
void *arg;
|
||||
#if defined(__ICCARM__) || defined(__ICCRISCV__) || defined(__ICCRX__)
|
||||
struct usbh_iso_frame_packet *iso_packet;
|
||||
#else
|
||||
struct usbh_iso_frame_packet iso_packet[0];
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, sakumisu
|
||||
* Copyright (c) 2022-2023, sakumisu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -44,9 +44,9 @@
|
||||
#ifndef __ALIGNED
|
||||
#define __ALIGNED(x) __attribute__((aligned(x)))
|
||||
#endif
|
||||
#elif defined(__ICCARM__) || defined(__ICCRX__)
|
||||
#elif defined(__ICCARM__) || defined(__ICCRX__) || defined(__ICCRISCV__)
|
||||
#ifndef __USED
|
||||
#if __ICCARM_V8
|
||||
#if defined(__ICCARM_V8) || defined (__ICCRISCV__)
|
||||
#define __USED __attribute__((used))
|
||||
#else
|
||||
#define __USED __root
|
||||
@@ -54,7 +54,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef __WEAK
|
||||
#if __ICCARM_V8
|
||||
#if defined(__ICCARM_V8) || defined (__ICCRISCV__)
|
||||
#define __WEAK __attribute__((weak))
|
||||
#else
|
||||
#define __WEAK _Pragma("__weak")
|
||||
@@ -62,7 +62,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef __PACKED
|
||||
#if __ICCARM_V8
|
||||
#if defined(__ICCARM_V8) || defined (__ICCRISCV__)
|
||||
#define __PACKED __attribute__((packed, aligned(1)))
|
||||
#else
|
||||
/* Needs IAR language extensions */
|
||||
@@ -71,7 +71,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef __PACKED_STRUCT
|
||||
#if __ICCARM_V8
|
||||
#if defined(__ICCARM_V8) || defined (__ICCRISCV__)
|
||||
#define __PACKED_STRUCT struct __attribute__((packed, aligned(1)))
|
||||
#else
|
||||
/* Needs IAR language extensions */
|
||||
@@ -80,7 +80,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef __PACKED_UNION
|
||||
#if __ICCARM_V8
|
||||
#if defined(__ICCARM_V8) || defined (__ICCRISCV__)
|
||||
#define __PACKED_UNION union __attribute__((packed, aligned(1)))
|
||||
#else
|
||||
/* Needs IAR language extensions */
|
||||
@@ -89,7 +89,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef __ALIGNED
|
||||
#if __ICCARM_V8
|
||||
#if defined(__ICCARM_V8) || defined (__ICCRISCV__)
|
||||
#define __ALIGNED(x) __attribute__((aligned(x)))
|
||||
#elif (__VER__ >= 7080000)
|
||||
/* Needs IAR language extensions */
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "usbd_core.h"
|
||||
#if defined(CONFIG_USBDEV_TX_THREAD) || defined(CONFIG_USBDEV_RX_THREAD)
|
||||
#include "usb_osal.h"
|
||||
#endif
|
||||
|
||||
/* general descriptor field offsets */
|
||||
#define DESC_bLength 0 /** Length offset */
|
||||
@@ -68,15 +65,6 @@ USB_NOCACHE_RAM_SECTION struct usbd_core_priv {
|
||||
struct usbd_tx_rx_msg rx_msg[USB_EP_OUT_NUM];
|
||||
} g_usbd_core;
|
||||
|
||||
#if defined(CONFIG_USBDEV_TX_THREAD)
|
||||
usb_osal_mq_t usbd_tx_mq;
|
||||
usb_osal_thread_t usbd_tx_thread;
|
||||
#endif
|
||||
#if defined(CONFIG_USBDEV_RX_THREAD)
|
||||
usb_osal_mq_t usbd_rx_mq;
|
||||
usb_osal_thread_t usbd_rx_thread;
|
||||
#endif
|
||||
|
||||
static void usbd_class_event_notify_handler(uint8_t event, void *arg);
|
||||
|
||||
static void usbd_print_setup(struct usb_setup_packet *setup)
|
||||
@@ -1140,66 +1128,18 @@ void usbd_event_ep0_out_complete_handler(uint8_t ep, uint32_t nbytes)
|
||||
|
||||
void usbd_event_ep_in_complete_handler(uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
#ifndef CONFIG_USBDEV_TX_THREAD
|
||||
if (g_usbd_core.tx_msg[ep & 0x7f].cb) {
|
||||
g_usbd_core.tx_msg[ep & 0x7f].cb(ep, nbytes);
|
||||
}
|
||||
#else
|
||||
g_usbd_core.tx_msg[ep & 0x7f].nbytes = nbytes;
|
||||
usb_osal_mq_send(usbd_tx_mq, (uintptr_t)&g_usbd_core.tx_msg[ep & 0x7f]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void usbd_event_ep_out_complete_handler(uint8_t ep, uint32_t nbytes)
|
||||
{
|
||||
#ifndef CONFIG_USBDEV_RX_THREAD
|
||||
if (g_usbd_core.rx_msg[ep & 0x7f].cb) {
|
||||
g_usbd_core.rx_msg[ep & 0x7f].cb(ep, nbytes);
|
||||
}
|
||||
#else
|
||||
g_usbd_core.rx_msg[ep & 0x7f].nbytes = nbytes;
|
||||
usb_osal_mq_send(usbd_rx_mq, (uintptr_t)&g_usbd_core.rx_msg[ep & 0x7f]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBDEV_TX_THREAD
|
||||
static void usbdev_tx_thread(void *argument)
|
||||
{
|
||||
struct usbd_tx_rx_msg *msg;
|
||||
int ret;
|
||||
|
||||
while (1) {
|
||||
ret = usb_osal_mq_recv(usbd_tx_mq, (uintptr_t *)&msg, 0xffffffff);
|
||||
if (ret < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg->cb) {
|
||||
msg->cb(msg->ep, msg->nbytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_RX_THREAD
|
||||
static void usbdev_rx_thread(void *argument)
|
||||
{
|
||||
struct usbd_tx_rx_msg *msg;
|
||||
int ret;
|
||||
|
||||
while (1) {
|
||||
ret = usb_osal_mq_recv(usbd_rx_mq, (uintptr_t *)&msg, 0xffffffff);
|
||||
if (ret < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg->cb) {
|
||||
msg->cb(msg->ep, msg->nbytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USBDEV_ADVANCE_DESC
|
||||
void usbd_desc_register(struct usb_descriptor *desc)
|
||||
{
|
||||
@@ -1270,26 +1210,6 @@ bool usb_device_is_configured(void)
|
||||
|
||||
int usbd_initialize(void)
|
||||
{
|
||||
#ifdef CONFIG_USBDEV_TX_THREAD
|
||||
usbd_tx_mq = usb_osal_mq_create(16);
|
||||
if (usbd_tx_mq == NULL) {
|
||||
return -1;
|
||||
}
|
||||
usbd_tx_thread = usb_osal_thread_create("usbd_tx", CONFIG_USBDEV_TX_STACKSIZE, CONFIG_USBDEV_TX_PRIO, usbdev_tx_thread, NULL);
|
||||
if (usbd_tx_thread == NULL) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_USBDEV_RX_THREAD
|
||||
usbd_rx_mq = usb_osal_mq_create(16);
|
||||
if (usbd_rx_mq == NULL) {
|
||||
return -1;
|
||||
}
|
||||
usbd_rx_thread = usb_osal_thread_create("usbd_rx", CONFIG_USBDEV_RX_STACKSIZE, CONFIG_USBDEV_RX_PRIO, usbdev_rx_thread, NULL);
|
||||
if (usbd_rx_thread == NULL) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return usb_dc_init();
|
||||
}
|
||||
|
||||
@@ -1297,8 +1217,6 @@ int usbd_deinitialize(void)
|
||||
{
|
||||
g_usbd_core.intf_offset = 0;
|
||||
usb_dc_deinit();
|
||||
#if defined(CONFIG_USBDEV_TX_THREAD) || defined(CONFIG_USBDEV_RX_THREAD)
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
136
core/usbh_core.c
136
core/usbh_core.c
@@ -13,8 +13,8 @@ USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t ep0_request_buffer[CONFIG_USBHOST
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX struct usb_setup_packet g_setup[CONFIG_USBHOST_MAX_EXTHUBS + 1][CONFIG_USBHOST_MAX_EHPORTS];
|
||||
|
||||
/* general descriptor field offsets */
|
||||
#define DESC_bLength 0 /** Length offset */
|
||||
#define DESC_bDescriptorType 1 /** Descriptor type offset */
|
||||
#define DESC_bLength 0 /** Length offset */
|
||||
#define DESC_bDescriptorType 1 /** Descriptor type offset */
|
||||
|
||||
#define USB_DEV_ADDR_MAX 0x7f
|
||||
#define USB_DEV_ADDR_MARK_OFFSET 5
|
||||
@@ -270,23 +270,6 @@ static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_config
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBHOST_GET_STRING_DESC
|
||||
void usbh_print_string(char *lead, uint8_t *str)
|
||||
{
|
||||
uint8_t string[64 + 1] = { 0 };
|
||||
|
||||
int len, i = 2, j = 0;
|
||||
|
||||
len = str[0];
|
||||
while (i < len) {
|
||||
string[j] = str[i];
|
||||
i += 2;
|
||||
j++;
|
||||
}
|
||||
USB_LOG_RAW("%s%s\r\n", lead, string);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void usbh_print_hubport_info(struct usbh_hubport *hport)
|
||||
{
|
||||
USB_LOG_RAW("Device Descriptor:\r\n");
|
||||
@@ -408,6 +391,54 @@ int usbh_hport_activate_epx(usbh_pipe_t *pipe, struct usbh_hubport *hport, struc
|
||||
return usbh_pipe_alloc(pipe, &ep_cfg);
|
||||
}
|
||||
|
||||
int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *output)
|
||||
{
|
||||
struct usb_setup_packet *setup = hport->setup;
|
||||
int ret;
|
||||
uint8_t *src;
|
||||
uint8_t *dst;
|
||||
uint16_t len;
|
||||
uint16_t i = 2;
|
||||
uint16_t j = 0;
|
||||
|
||||
/* Get Manufacturer string */
|
||||
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
|
||||
setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_STRING << 8) | index);
|
||||
setup->wIndex = 0x0409;
|
||||
setup->wLength = 255;
|
||||
|
||||
ret = usbh_control_transfer(hport->ep0, setup, ep0_request_buffer);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
src = ep0_request_buffer;
|
||||
dst = output;
|
||||
len = src[0];
|
||||
|
||||
while (i < len) {
|
||||
dst[j] = src[i];
|
||||
i += 2;
|
||||
j++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbh_set_interface(struct usbh_hubport *hport, uint8_t intf, uint8_t altsetting)
|
||||
{
|
||||
struct usb_setup_packet *setup = hport->setup;
|
||||
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||
setup->bRequest = USB_REQUEST_SET_INTERFACE;
|
||||
setup->wValue = intf;
|
||||
setup->wIndex = altsetting;
|
||||
setup->wLength = 0;
|
||||
|
||||
return usbh_control_transfer(hport->ep0, setup, NULL);
|
||||
}
|
||||
|
||||
int usbh_enumerate(struct usbh_hubport *hport)
|
||||
{
|
||||
struct usb_interface_descriptor *intf_desc;
|
||||
@@ -553,50 +584,37 @@ int usbh_enumerate(struct usbh_hubport *hport)
|
||||
}
|
||||
memcpy(hport->raw_config_desc, ep0_request_buffer, wTotalLength);
|
||||
#ifdef CONFIG_USBHOST_GET_STRING_DESC
|
||||
/* Get Manufacturer string */
|
||||
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
|
||||
setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_STRING << 8) | USB_STRING_MFC_INDEX);
|
||||
setup->wIndex = 0x0409;
|
||||
setup->wLength = 255;
|
||||
uint8_t string_buffer[128];
|
||||
|
||||
ret = usbh_control_transfer(hport->ep0, setup, ep0_request_buffer);
|
||||
/* Get Manufacturer string */
|
||||
memset(string_buffer, 0, 128);
|
||||
ret = usbh_get_string_desc(hport, USB_STRING_MFC_INDEX, string_buffer);
|
||||
if (ret < 0) {
|
||||
USB_LOG_ERR("Failed to get Manufacturer string,errorcode:%d\r\n", ret);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
usbh_print_string("Manufacturer: ", ep0_request_buffer);
|
||||
USB_LOG_INFO("Manufacturer: %s\r\n", string_buffer);
|
||||
|
||||
/* Get Product string */
|
||||
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
|
||||
setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_STRING << 8) | USB_STRING_PRODUCT_INDEX);
|
||||
setup->wIndex = 0x0409;
|
||||
setup->wLength = 255;
|
||||
|
||||
ret = usbh_control_transfer(hport->ep0, setup, ep0_request_buffer);
|
||||
memset(string_buffer, 0, 128);
|
||||
ret = usbh_get_string_desc(hport, USB_STRING_PRODUCT_INDEX, string_buffer);
|
||||
if (ret < 0) {
|
||||
USB_LOG_ERR("Failed to get get Product string,errorcode:%d\r\n", ret);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
usbh_print_string("Product: ", ep0_request_buffer);
|
||||
USB_LOG_INFO("Product: %s\r\n", string_buffer);
|
||||
|
||||
/* Get SerialNumber string */
|
||||
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
|
||||
setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_STRING << 8) | USB_STRING_SERIAL_INDEX);
|
||||
setup->wIndex = 0x0409;
|
||||
setup->wLength = 255;
|
||||
|
||||
ret = usbh_control_transfer(hport->ep0, setup, ep0_request_buffer);
|
||||
memset(string_buffer, 0, 128);
|
||||
ret = usbh_get_string_desc(hport, USB_STRING_SERIAL_INDEX, string_buffer);
|
||||
if (ret < 0) {
|
||||
USB_LOG_ERR("Failed to get get SerialNumber string,errorcode:%d\r\n", ret);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
usbh_print_string("SerialNumber: ", ep0_request_buffer);
|
||||
USB_LOG_INFO("SerialNumber: %s\r\n", string_buffer);
|
||||
#endif
|
||||
/* Select device configuration 1 */
|
||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
@@ -611,6 +629,19 @@ int usbh_enumerate(struct usbh_hubport *hport)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USBHOST_MSOS_ENABLE
|
||||
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||
setup->bRequest = CONFIG_USBHOST_MSOS_VENDOR_CODE;
|
||||
setup->wValue = 0;
|
||||
setup->wIndex = 0x0004;
|
||||
setup->wLength = 16;
|
||||
|
||||
ret = usbh_control_transfer(hport, setup, ep0_request_buffer);
|
||||
if (ret < 0 && (ret != -EPERM)) {
|
||||
USB_LOG_ERR("Failed to get msosv1 compat id,errorcode:%d\r\n", ret);
|
||||
goto errout;
|
||||
}
|
||||
#endif
|
||||
USB_LOG_INFO("Enumeration success, start loading class driver\r\n");
|
||||
/*search supported class driver*/
|
||||
for (uint8_t i = 0; i < hport->config.config_desc.bNumInterfaces; i++) {
|
||||
@@ -639,25 +670,6 @@ errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct usbh_hubport *usbh_find_hubport(uint8_t dev_addr)
|
||||
{
|
||||
struct usbh_hubport *hport;
|
||||
usb_slist_t *hub_list;
|
||||
usb_slist_for_each(hub_list, &hub_class_head)
|
||||
{
|
||||
struct usbh_hub *hub = usb_slist_entry(hub_list, struct usbh_hub, list);
|
||||
for (uint8_t port = 0; port < hub->hub_desc.bNbrPorts; port++) {
|
||||
hport = &hub->child[port];
|
||||
if (hport->connected) {
|
||||
if (hport->dev_addr == dev_addr) {
|
||||
return &hub->child[port];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *usbh_find_class_instance(const char *devname)
|
||||
{
|
||||
struct usbh_hubport *hport;
|
||||
|
||||
@@ -169,6 +169,16 @@ struct usbh_hub {
|
||||
struct usbh_hubport *parent;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Activates an endpoint for a USB host pipe on a specific hub port.
|
||||
*
|
||||
* This function is responsible for activating the specified endpoint
|
||||
* described by the given endpoint descriptor on the USB host pipe.
|
||||
* @param pipe Pointer to the USB host pipe structure.
|
||||
* @param hport Pointer to the USB hub port structure.
|
||||
* @param ep_desc Pointer to the USB endpoint descriptor.
|
||||
* @return On success will return 0, and others indicate fail.
|
||||
*/
|
||||
int usbh_hport_activate_epx(usbh_pipe_t *pipe, struct usbh_hubport *hport, struct usb_endpoint_descriptor *ep_desc);
|
||||
|
||||
/**
|
||||
@@ -183,8 +193,35 @@ int usbh_hport_activate_epx(usbh_pipe_t *pipe, struct usbh_hubport *hport, struc
|
||||
*/
|
||||
int usbh_control_transfer(usbh_pipe_t pipe, struct usb_setup_packet *setup, uint8_t *buffer);
|
||||
|
||||
/**
|
||||
* @brief Retrieves a USB string descriptor from a specific hub port.
|
||||
*
|
||||
* This function is responsible for retrieving the USB string descriptor
|
||||
* with the specified index from the USB device connected to the given hub port.
|
||||
* The retrieved descriptor is stored in the output buffer provided.
|
||||
*
|
||||
* @param hport Pointer to the USB hub port structure.
|
||||
* @param index Index of the string descriptor to retrieve.
|
||||
* @param output Pointer to the buffer where the retrieved descriptor will be stored.
|
||||
* @return On success will return 0, and others indicate fail.
|
||||
*/
|
||||
int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *output);
|
||||
|
||||
/**
|
||||
* @brief Sets the alternate setting for a USB interface on a specific hub port.
|
||||
*
|
||||
* This function is responsible for setting the alternate setting of the
|
||||
* specified USB interface on the USB device connected to the given hub port.
|
||||
* The interface and alternate setting are identified by the respective parameters.
|
||||
*
|
||||
* @param hport Pointer to the USB hub port structure.
|
||||
* @param intf Interface number to set the alternate setting for.
|
||||
* @param altsetting Alternate setting value to set for the interface.
|
||||
* @return On success will return 0, and others indicate fail.
|
||||
*/
|
||||
int usbh_set_interface(struct usbh_hubport *hport, uint8_t intf, uint8_t altsetting);
|
||||
|
||||
int usbh_initialize(void);
|
||||
struct usbh_hubport *usbh_find_hubport(uint8_t dev_addr);
|
||||
void *usbh_find_class_instance(const char *devname);
|
||||
|
||||
int lsusb(int argc, char **argv);
|
||||
|
||||
@@ -205,7 +205,7 @@ struct audio_entity_info audio_entity_table[] = {
|
||||
.ep = AUDIO_IN_EP },
|
||||
};
|
||||
|
||||
void audio_v1_init(uint8_t busid)
|
||||
void audio_v1_init(void)
|
||||
{
|
||||
usbd_desc_register(audio_v1_descriptor);
|
||||
usbd_add_interface(usbd_audio_init_intf(&intf0, 0x0100, audio_entity_table, 1));
|
||||
|
||||
@@ -171,8 +171,8 @@ struct usbd_endpoint cdc_in_ep = {
|
||||
.ep_cb = usbd_cdc_acm_bulk_in
|
||||
};
|
||||
|
||||
struct usbd_interface intf0;
|
||||
struct usbd_interface intf1;
|
||||
static struct usbd_interface intf0;
|
||||
static struct usbd_interface intf1;
|
||||
|
||||
void cdc_acm_init(void)
|
||||
{
|
||||
|
||||
274
demo/cdc_ecm_template.c
Normal file
274
demo/cdc_ecm_template.c
Normal file
@@ -0,0 +1,274 @@
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_cdc_ecm.h"
|
||||
|
||||
/*!< endpoint address */
|
||||
#define CDC_IN_EP 0x81
|
||||
#define CDC_OUT_EP 0x02
|
||||
#define CDC_INT_EP 0x83
|
||||
|
||||
#define USBD_VID 0xFFFF
|
||||
#define USBD_PID 0xFFFF
|
||||
#define USBD_MAX_POWER 100
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
/*!< config descriptor size */
|
||||
#define USB_CONFIG_SIZE (9 + CDC_ECM_DESCRIPTOR_LEN)
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
#define CDC_MAX_MPS 512
|
||||
#else
|
||||
#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
|
||||
|
||||
/*!< 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,
|
||||
0x02,
|
||||
0x02,
|
||||
0x01,
|
||||
0x40,
|
||||
0x01,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
|
||||
const uint8_t mac[6] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
|
||||
|
||||
/*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */
|
||||
#define IP_ADDR0 (uint8_t)192
|
||||
#define IP_ADDR1 (uint8_t)168
|
||||
#define IP_ADDR2 (uint8_t)123
|
||||
#define IP_ADDR3 (uint8_t)100
|
||||
|
||||
/*NETMASK*/
|
||||
#define NETMASK_ADDR0 (uint8_t)255
|
||||
#define NETMASK_ADDR1 (uint8_t)255
|
||||
#define NETMASK_ADDR2 (uint8_t)255
|
||||
#define NETMASK_ADDR3 (uint8_t)0
|
||||
|
||||
/*Gateway Address*/
|
||||
#define GW_ADDR0 (uint8_t)192
|
||||
#define GW_ADDR1 (uint8_t)168
|
||||
#define GW_ADDR2 (uint8_t)123
|
||||
#define GW_ADDR3 (uint8_t)1
|
||||
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/init.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/pbuf.h"
|
||||
|
||||
const ip_addr_t ipaddr = IPADDR4_INIT_BYTES(IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
|
||||
const ip_addr_t netmask = IPADDR4_INIT_BYTES(NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
|
||||
const ip_addr_t gateway = IPADDR4_INIT_BYTES(GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
|
||||
|
||||
static struct netif cdc_ecm_netif; //network interface
|
||||
|
||||
/* Network interface name */
|
||||
#define IFNAME0 'E'
|
||||
#define IFNAME1 'X'
|
||||
|
||||
static err_t linkoutput_fn(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
static int ret;
|
||||
|
||||
ret = usbd_cdc_ecm_eth_tx(p);
|
||||
if (ret == 0)
|
||||
return ERR_OK;
|
||||
else
|
||||
return ERR_BUF;
|
||||
}
|
||||
|
||||
err_t cdc_ecm_if_init(struct netif *netif)
|
||||
{
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
|
||||
netif->mtu = 1500;
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP;
|
||||
netif->state = NULL;
|
||||
netif->name[0] = IFNAME0;
|
||||
netif->name[1] = IFNAME1;
|
||||
netif->output = etharp_output;
|
||||
netif->linkoutput = linkoutput_fn;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t cdc_ecm_if_input(struct netif *netif)
|
||||
{
|
||||
static err_t err;
|
||||
static struct pbuf *p;
|
||||
|
||||
p = usbd_cdc_ecm_eth_rx();
|
||||
if (p != NULL) {
|
||||
err = netif->input(p, netif);
|
||||
if (err != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
} else {
|
||||
return ERR_BUF;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void cdc_ecm_lwip_init(void)
|
||||
{
|
||||
struct netif *netif = &cdc_ecm_netif;
|
||||
|
||||
lwip_init();
|
||||
|
||||
netif->hwaddr_len = 6;
|
||||
memcpy(netif->hwaddr, mac, 6);
|
||||
|
||||
netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, cdc_ecm_if_init, netif_input);
|
||||
netif_set_default(netif);
|
||||
while (!netif_is_up(netif)) {
|
||||
}
|
||||
|
||||
// while (dhserv_init(&dhcp_config)) {}
|
||||
|
||||
// while (dnserv_init(&ipaddr, PORT_DNS, dns_query_proc)) {}
|
||||
}
|
||||
|
||||
void usbd_cdc_ecm_data_recv_done(void)
|
||||
{
|
||||
}
|
||||
|
||||
void cdc_ecm_input_poll(void)
|
||||
{
|
||||
cdc_ecm_if_input(&cdc_ecm_netif);
|
||||
}
|
||||
|
||||
void usbd_event_handler(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_interface intf1;
|
||||
|
||||
/* ecm only supports in linux, and you should input the following command
|
||||
*
|
||||
* sudo ifconfig enxaabbccddeeff up
|
||||
* sudo dhcpclient enxaabbccddeeff
|
||||
*/
|
||||
void cdc_ecm_init(void)
|
||||
{
|
||||
cdc_ecm_lwip_init();
|
||||
|
||||
usbd_desc_register(cdc_ecm_descriptor);
|
||||
usbd_add_interface(usbd_cdc_ecm_init_intf(&intf0, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP));
|
||||
usbd_add_interface(usbd_cdc_ecm_init_intf(&intf1, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP));
|
||||
usbd_initialize();
|
||||
}
|
||||
@@ -102,12 +102,33 @@ static const uint8_t cdc_descriptor[] = {
|
||||
};
|
||||
|
||||
const uint8_t mac[6] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
|
||||
/*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */
|
||||
#define IP_ADDR0 (uint8_t)192
|
||||
#define IP_ADDR1 (uint8_t)168
|
||||
#define IP_ADDR2 (uint8_t)123
|
||||
#define IP_ADDR3 (uint8_t)100
|
||||
|
||||
/*NETMASK*/
|
||||
#define NETMASK_ADDR0 (uint8_t)255
|
||||
#define NETMASK_ADDR1 (uint8_t)255
|
||||
#define NETMASK_ADDR2 (uint8_t)255
|
||||
#define NETMASK_ADDR3 (uint8_t)0
|
||||
|
||||
/*Gateway Address*/
|
||||
#define GW_ADDR0 (uint8_t)192
|
||||
#define GW_ADDR1 (uint8_t)168
|
||||
#define GW_ADDR2 (uint8_t)123
|
||||
#define GW_ADDR3 (uint8_t)1
|
||||
|
||||
#ifdef RT_USING_LWIP
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <netif/ethernetif.h>
|
||||
|
||||
const ip_addr_t ipaddr = IPADDR4_INIT_BYTES(IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
|
||||
const ip_addr_t netmask = IPADDR4_INIT_BYTES(NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
|
||||
const ip_addr_t gateway = IPADDR4_INIT_BYTES(GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
|
||||
|
||||
struct eth_device rndis_dev;
|
||||
|
||||
static rt_err_t rt_usbd_rndis_control(rt_device_t dev, int cmd, void *args)
|
||||
@@ -161,33 +182,15 @@ void rt_usbd_rndis_init(void)
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/pbuf.h"
|
||||
|
||||
/*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */
|
||||
#define IP_ADDR0 (uint8_t)192
|
||||
#define IP_ADDR1 (uint8_t)168
|
||||
#define IP_ADDR2 (uint8_t)123
|
||||
#define IP_ADDR3 (uint8_t)100
|
||||
|
||||
/*NETMASK*/
|
||||
#define NETMASK_ADDR0 (uint8_t)255
|
||||
#define NETMASK_ADDR1 (uint8_t)255
|
||||
#define NETMASK_ADDR2 (uint8_t)255
|
||||
#define NETMASK_ADDR3 (uint8_t)0
|
||||
|
||||
/*Gateway Address*/
|
||||
#define GW_ADDR0 (uint8_t)192
|
||||
#define GW_ADDR1 (uint8_t)168
|
||||
#define GW_ADDR2 (uint8_t)123
|
||||
#define GW_ADDR3 (uint8_t)1
|
||||
|
||||
static struct netif rndis_netif; //network interface
|
||||
|
||||
const ip_addr_t ipaddr = IPADDR4_INIT_BYTES(IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
|
||||
const ip_addr_t netmask = IPADDR4_INIT_BYTES(NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
|
||||
const ip_addr_t gateway = IPADDR4_INIT_BYTES(GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
|
||||
|
||||
static struct netif rndis_netif; //network interface
|
||||
|
||||
/* Network interface name */
|
||||
#define IFNAME0 'E'
|
||||
#define IFNAME1 'X'
|
||||
#define IFNAME0 'E'
|
||||
#define IFNAME1 'X'
|
||||
|
||||
err_t linkoutput_fn(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
@@ -203,7 +206,7 @@ err_t linkoutput_fn(struct netif *netif, struct pbuf *p)
|
||||
err_t rndisif_init(struct netif *netif)
|
||||
{
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
|
||||
|
||||
netif->mtu = 1500;
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP;
|
||||
netif->state = NULL;
|
||||
|
||||
@@ -226,7 +226,7 @@ void hid_keyboard_init(void)
|
||||
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[64];
|
||||
|
||||
void hid_keyboard_test(uint8_t busid)
|
||||
void hid_keyboard_test(void)
|
||||
{
|
||||
const uint8_t sendbuffer[8] = { 0x00, 0x00, HID_KBD_USAGE_A, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
|
||||
@@ -256,15 +256,20 @@ void hid_mouse_init(void)
|
||||
*/
|
||||
void hid_mouse_test(void)
|
||||
{
|
||||
/*!< move mouse pointer */
|
||||
mouse_cfg.x += 10;
|
||||
mouse_cfg.y = 0;
|
||||
int counter = 0;
|
||||
while (counter < 1000) {
|
||||
/*!< move mouse pointer */
|
||||
mouse_cfg.x += 40;
|
||||
mouse_cfg.y += 0;
|
||||
|
||||
int ret = usbd_ep_start_write(HID_INT_EP, (uint8_t *)&mouse_cfg, 4);
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
hid_state = HID_STATE_BUSY;
|
||||
while (hid_state == HID_STATE_BUSY) {
|
||||
int ret = usbd_ep_start_write(HID_INT_EP, (uint8_t *)&mouse_cfg, 4);
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
hid_state = HID_STATE_BUSY;
|
||||
while (hid_state == HID_STATE_BUSY) {
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,14 +137,14 @@ void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
|
||||
}
|
||||
int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
if (sector < 10)
|
||||
if (sector < BLOCK_COUNT)
|
||||
memcpy(buffer, mass_block[sector].BlockSpace, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
if (sector < 10)
|
||||
if (sector < BLOCK_COUNT)
|
||||
memcpy(mass_block[sector].BlockSpace, buffer, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
167
demo/msc_storage_template.c
Normal file
167
demo/msc_storage_template.c
Normal file
@@ -0,0 +1,167 @@
|
||||
#include "usbd_core.h"
|
||||
#include "usbd_msc.h"
|
||||
|
||||
#ifdef __RT_THREAD_H__
|
||||
|
||||
#define MSC_IN_EP 0x81
|
||||
#define MSC_OUT_EP 0x02
|
||||
|
||||
#define USBD_VID 0xFFFF
|
||||
#define USBD_PID 0xFFFF
|
||||
#define USBD_MAX_POWER 100
|
||||
#define USBD_LANGID_STRING 1033
|
||||
|
||||
#define USB_CONFIG_SIZE (9 + MSC_DESCRIPTOR_LEN)
|
||||
|
||||
#ifdef CONFIG_USB_HS
|
||||
#define MSC_MAX_MPS 512
|
||||
#else
|
||||
#define MSC_MAX_MPS 64
|
||||
#endif
|
||||
|
||||
|
||||
const uint8_t msc_storage_descriptor[] = {
|
||||
USB_DEVICE_DESCRIPTOR_INIT(USB_1_1, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01),
|
||||
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
|
||||
MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x02),
|
||||
///////////////////////////////////////
|
||||
/// string0 descriptor
|
||||
///////////////////////////////////////
|
||||
USB_LANGID_INIT(USBD_LANGID_STRING),
|
||||
///////////////////////////////////////
|
||||
/// string1 descriptor
|
||||
///////////////////////////////////////
|
||||
0x14, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
///////////////////////////////////////
|
||||
/// string2 descriptor
|
||||
///////////////////////////////////////
|
||||
0x26, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'C', 0x00, /* wcChar0 */
|
||||
'h', 0x00, /* wcChar1 */
|
||||
'e', 0x00, /* wcChar2 */
|
||||
'r', 0x00, /* wcChar3 */
|
||||
'r', 0x00, /* wcChar4 */
|
||||
'y', 0x00, /* wcChar5 */
|
||||
'U', 0x00, /* wcChar6 */
|
||||
'S', 0x00, /* wcChar7 */
|
||||
'B', 0x00, /* wcChar8 */
|
||||
' ', 0x00, /* wcChar9 */
|
||||
'M', 0x00, /* wcChar10 */
|
||||
'S', 0x00, /* wcChar11 */
|
||||
'C', 0x00, /* wcChar12 */
|
||||
' ', 0x00, /* wcChar13 */
|
||||
'D', 0x00, /* wcChar14 */
|
||||
'E', 0x00, /* wcChar15 */
|
||||
'M', 0x00, /* wcChar16 */
|
||||
'O', 0x00, /* wcChar17 */
|
||||
///////////////////////////////////////
|
||||
/// string3 descriptor
|
||||
///////////////////////////////////////
|
||||
0x16, /* bLength */
|
||||
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
|
||||
'2', 0x00, /* wcChar0 */
|
||||
'0', 0x00, /* wcChar1 */
|
||||
'2', 0x00, /* wcChar2 */
|
||||
'2', 0x00, /* wcChar3 */
|
||||
'1', 0x00, /* wcChar4 */
|
||||
'2', 0x00, /* wcChar5 */
|
||||
'3', 0x00, /* wcChar6 */
|
||||
'4', 0x00, /* wcChar7 */
|
||||
'5', 0x00, /* wcChar8 */
|
||||
'6', 0x00, /* wcChar9 */
|
||||
#ifdef CONFIG_USB_HS
|
||||
///////////////////////////////////////
|
||||
/// device qualifier descriptor
|
||||
///////////////////////////////////////
|
||||
0x0a,
|
||||
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
|
||||
0x00,
|
||||
0x02,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40,
|
||||
0x01,
|
||||
0x00,
|
||||
#endif
|
||||
0x00
|
||||
};
|
||||
|
||||
struct usbd_interface intf0;
|
||||
|
||||
/* assume the block device is 512M */
|
||||
#define BLOCK_DEV_NAME "sd0"
|
||||
#define BLOCK_SIZE 512U
|
||||
#define BLOCK_COUNT 0x1024U * 0x1024U
|
||||
static rt_device_t blk_dev = RT_NULL;
|
||||
|
||||
void usbd_event_handler(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;
|
||||
}
|
||||
}
|
||||
|
||||
void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
|
||||
{
|
||||
*block_num = BLOCK_COUNT;
|
||||
*block_size = BLOCK_SIZE;
|
||||
}
|
||||
|
||||
int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
rt_device_read(blk_dev, sector, buffer, length / BLOCK_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
rt_device_write(blk_dev, sector, buffer, length / BLOCK_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void msc_storage_init(void)
|
||||
{
|
||||
rt_err_t res;
|
||||
|
||||
blk_dev = rt_device_find(BLOCK_DEV_NAME);
|
||||
RT_ASSERT(blk_dev);
|
||||
|
||||
res = rt_device_open(blk_dev, RT_DEVICE_OFLAG_RDWR);
|
||||
RT_ASSERT(res == RT_EOK);
|
||||
|
||||
usbd_desc_register(msc_storage_descriptor);
|
||||
usbd_add_interface(usbd_msc_init_intf(&intf0, MSC_OUT_EP, MSC_IN_EP));
|
||||
|
||||
usbd_initialize();
|
||||
}
|
||||
#endif
|
||||
@@ -11,6 +11,7 @@
|
||||
#define TEST_USBH_MSC_FATFS 0
|
||||
#define TEST_USBH_AUDIO 0
|
||||
#define TEST_USBH_VIDEO 0
|
||||
#define TEST_USBH_CDC_ECM 0
|
||||
|
||||
#if TEST_USBH_CDC_ACM
|
||||
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t cdc_buffer[512];
|
||||
@@ -380,6 +381,66 @@ void usbh_videostreaming_parse_yuyv2(struct usbh_urb *urb, struct usbh_videostre
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TEST_USBH_CDC_ECM
|
||||
#include "usbh_cdc_ecm.h"
|
||||
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#if LWIP_DHCP
|
||||
#include "lwip/dhcp.h"
|
||||
#endif
|
||||
|
||||
struct netif g_cdc_ecm_netif;
|
||||
|
||||
static err_t usbh_cdc_ecm_if_init(struct netif *netif)
|
||||
{
|
||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
||||
|
||||
netif->mtu = 1500;
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP;
|
||||
netif->state = NULL;
|
||||
netif->name[0] = 'E';
|
||||
netif->name[1] = 'X';
|
||||
netif->output = etharp_output;
|
||||
netif->linkoutput = usbh_cdc_ecm_linkoutput;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
|
||||
{
|
||||
struct netif *netif = &g_cdc_ecm_netif;
|
||||
|
||||
netif->hwaddr_len = 6;
|
||||
memcpy(netif->hwaddr, cdc_ecm_class->mac, 6);
|
||||
|
||||
IP4_ADDR(&cdc_ecm_class->ipaddr, 0, 0, 0, 0);
|
||||
IP4_ADDR(&cdc_ecm_class->netmask, 0, 0, 0, 0);
|
||||
IP4_ADDR(&cdc_ecm_class->gateway, 0, 0, 0, 0);
|
||||
|
||||
netif = netif_add(netif, &cdc_ecm_class->ipaddr, &cdc_ecm_class->netmask, &cdc_ecm_class->gateway, NULL, usbh_cdc_ecm_if_init, tcpip_input);
|
||||
netif_set_default(netif);
|
||||
while (!netif_is_up(netif)) {
|
||||
}
|
||||
|
||||
#if LWIP_DHCP
|
||||
dhcp_start(netif);
|
||||
#endif
|
||||
}
|
||||
|
||||
void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
|
||||
{
|
||||
struct netif *netif = &g_cdc_ecm_netif;
|
||||
#if LWIP_DHCP
|
||||
dhcp_stop(netif);
|
||||
dhcp_cleanup(netif);
|
||||
#endif
|
||||
netif_set_down(netif);
|
||||
netif_remove(netif);
|
||||
}
|
||||
#endif
|
||||
|
||||
void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class)
|
||||
{
|
||||
}
|
||||
@@ -439,4 +500,10 @@ void usbh_class_test(void)
|
||||
#error "if you want to use iso, please contact with me"
|
||||
usb_osal_thread_create("usbh_video", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_video_thread, NULL);
|
||||
#endif
|
||||
#if TEST_USBH_CDC_ECM
|
||||
/* Initialize the LwIP stack */
|
||||
tcpip_init(NULL, NULL);
|
||||
|
||||
usbh_cdc_ecm_lwip_thread_init(&g_cdc_ecm_netif);
|
||||
#endif
|
||||
}
|
||||
@@ -4,8 +4,152 @@ USB CONFIG 宏
|
||||
通用 CONFIG 宏
|
||||
---------------------
|
||||
|
||||
CONFIG_USB_PRINTF
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
USB log 功能,默认重定向到 printf,需要注意,USB log 会在中断中使用,因此重定向的 api 不允许阻塞。举例,如果使用的是 rt-thread,请更换成 rt-kprintf
|
||||
|
||||
CONFIG_USB_DBG_LEVEL
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
控制 log 的打印级别
|
||||
|
||||
CONFIG_USB_PRINTF_COLOR_ENABLE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
控制 log 颜色打印,默认开启
|
||||
|
||||
CONFIG_USB_ALIGN_SIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
USB buffer 的对齐大小,默认是 4。IP 在 dma 模式下可能对输入的 buffer有对齐要求,一般是4,如果是其他对齐方式,请修改此值。
|
||||
|
||||
USB_NOCACHE_RAM_SECTION
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
如果芯片没有 cache 功能,此宏无效。如果有,则 USB 的输入输出 buffer 必须放在 nocache ram 中,保证数据一致性。
|
||||
|
||||
设备相关 CONFIG 宏
|
||||
---------------------
|
||||
|
||||
CONFIG_USBDEV_REQUEST_BUFFER_LEN
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
控制传输接收和发送的 buffer 最大长度,默认是 256。
|
||||
|
||||
CONFIG_USBDEV_SETUP_LOG_PRINT
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
使能或者关闭 setup 包的 dump 信息,默认关闭。
|
||||
|
||||
CONFIG_USBDEV_DESC_CHECK
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
暂时没有实现
|
||||
|
||||
CONFIG_USBDEV_TEST_MODE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
使能或者关闭 usb test mode
|
||||
|
||||
CONFIG_USBDEV_MSC_BLOCK_SIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
msc 临时缓存的大小,缓存越大,msc 的速度越高,默认等于 1个内存介质的扇区大小(例如 sd卡 512,flash 4K),更改时需要是内存介质扇区的倍数。
|
||||
|
||||
虽然名字叫 block size,但是跟内存介质的 block size不是一个意思。
|
||||
|
||||
CONFIG_USBDEV_MSC_MANUFACTURER_STRING
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
CONFIG_USBDEV_MSC_PRODUCT_STRING
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
CONFIG_USBDEV_MSC_VERSION_STRING
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
CONFIG_USBDEV_MSC_THREAD
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
使能或者关闭 msc 线程,默认关闭。usbd_msc_sector_read 和 usbd_msc_sector_write 默认是在中断中执行,所以如果开启了 os 建议开启此宏,那么,
|
||||
usbd_msc_sector_read 和 usbd_msc_sector_write 就会在线程中执行。
|
||||
|
||||
CONFIG_USBDEV_MSC_PRIO
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
MSC 读写线程的优先级,默认是 4,数值越小,优先级越高
|
||||
|
||||
CONFIG_USBDEV_MSC_STACKSIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
MSC 读写线程的堆栈大小,默认 2K 字节
|
||||
|
||||
CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
rndis 控制传输最大接收和发送的长度,根据 RNDIS options list 决定最小长度,默认要大于等于 156
|
||||
|
||||
CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
rndis 以太网帧的最大长度,默认 1536
|
||||
|
||||
CONFIG_USBDEV_RNDIS_VENDOR_ID
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
CONFIG_USBDEV_RNDIS_VENDOR_DESC
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
CONFIG_USBDEV_RNDIS_USING_LWIP
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
rndis 与 lwip 接口的对接
|
||||
|
||||
主机相关 CONFIG 宏
|
||||
---------------------
|
||||
|
||||
以下参数决定了支持的最大外部hub数量,接口数,每个接口的端点数和 altsetting 数量,更改此值会影响 ram 的大小,建议根据实际情况更改。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#define CONFIG_USBHOST_MAX_RHPORTS 1
|
||||
#define CONFIG_USBHOST_MAX_EXTHUBS 1
|
||||
#define CONFIG_USBHOST_MAX_EHPORTS 4
|
||||
#define CONFIG_USBHOST_MAX_INTERFACES 6
|
||||
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 1
|
||||
#define CONFIG_USBHOST_MAX_ENDPOINTS 4
|
||||
|
||||
以下参数决定了支持的 class 数目,更改此值会影响 ram 的大小,建议根据实际情况更改。
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_HID_CLASS 4
|
||||
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
|
||||
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
|
||||
#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1
|
||||
#define CONFIG_USBHOST_MAX_RNDIS_CLASS 1
|
||||
|
||||
CONFIG_USBHOST_PSC_PRIO
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
主机插拔线程的优先级,默认是 4,数值越小,优先级越高
|
||||
|
||||
CONFIG_USBHOST_PSC_STACKSIZE
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
主机插拔线程的堆栈大小,默认 2K 字节
|
||||
|
||||
CONFIG_USBHOST_REQUEST_BUFFER_LEN
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
控制传输能够接收或者发送的最大长度
|
||||
|
||||
CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
控制传输发送或者接收的超时时间,默认 1s
|
||||
|
||||
CONFIG_USBHOST_MSC_TIMEOUT
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
MSC 读写传输的超时时间,默认 5s
|
||||
@@ -53,10 +53,7 @@ CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统的
|
||||
:maxdepth: 1
|
||||
:caption: 快速上手
|
||||
|
||||
quick_start/bl702
|
||||
quick_start/stm32
|
||||
quick_start/hpm
|
||||
quick_start/es32
|
||||
quick_start/index
|
||||
quick_start/rt-thread/rtthread
|
||||
quick_start/other_chip
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
基于 BL 系列开发指南
|
||||
=========================
|
||||
|
||||
BL 系列 USB 的开发主要使用 bl_mcu_sdk,参考 `bl_mcu_sdk <https://github.com/bouffalolab/bl_mcu_sdk>`_。
|
||||
|
||||
USB 的相关应用位于 `examples/usbdev` 和 `examples/usbhost` 目录下,环境搭建完成后,即可编译使用。
|
||||
@@ -1,84 +0,0 @@
|
||||
基于 ES32F369 开发指南
|
||||
=========================
|
||||
|
||||
ES32F3xx 系列单片机中 USB 外设使用标准的 musb ip,并且拥有 usb device 和 usb host 功能。本章主要介绍如何在东软载波的 ES32F369x 开发板中使用 CherryUSB。
|
||||
|
||||
在使用之前需要从 essemi 官网下载 `keil 芯片支持包 <http://www.essemi.com/index/product/detail?id=796>`_ 并安装,
|
||||
|
||||
|
||||
工程样例试用
|
||||
-----------------------
|
||||
|
||||
在 CherryUSB demo 目录下已经有主机跟从机的样例,在有板子的情况下,可以先跑工程样例,试用一下。
|
||||
|
||||
- 进入 MDK-ARM 目录下,双击 `example.uvprojx` 打开工程,选择好调试器后,编译烧录即可。
|
||||
- 如果是从机,默认提供的是 cdc acm 的示例,代码烧录以后,将 usb 线插到 板子的丝印为 USB-OTG 口,并接上电脑,按下复位键,电脑便会枚举出一个串口。打开串口,勾选 DTR 可以接收数据,在发送缓冲区填入数据并发送,调试器的串口便可以打印出接收的长度和数据。
|
||||
- 如果是主机,则需要一个 usb 母口转接线,并接入相关 usb 设备,就可以进行测试了。比如接上鼠标、U盘、4G 网卡等等。
|
||||
|
||||
USB Device 移植要点
|
||||
-----------------------
|
||||
|
||||
针对自定义的工程移植,需要按照以下步骤:
|
||||
|
||||
- 准备好可以进行调试打印的工程,并且实现 `printf`、 `malloc` 、 `free` 函数(也可以直接勾选 Use microlib 来使用)。
|
||||
- 拷贝 CherryUSB 源码到工程里
|
||||
- 添加 CherryUSB 源码和头文件路径,其中 `usbd_core.c` 和 `usb_dc_musb.c` 为必须添加项。
|
||||
- 拷贝 `cherryusb_config_template.h` 文件到自己工程目录下,命名为 `usb_config.h`,并添加相应的目录头文件路径。所以根目录下的文件仅作为参考,不要添加根目录下的头文件。
|
||||
|
||||
.. figure:: img/es322.png
|
||||
.. figure:: img/es323.png
|
||||
|
||||
- 实现 `usb_dc_low_level_init` 函数,该函数主要负责 USB 时钟、引脚、中断的初始化。例如
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usb_dc_low_level_init(void)
|
||||
{
|
||||
ald_pmu_perh_power_config(PMU_POWER_USB, ENABLE);
|
||||
ald_cmu_perh_clock_config(CMU_PERH_USB, ENABLE);
|
||||
ald_cmu_perh_clock_config(CMU_PERH_GPIO, ENABLE);
|
||||
ald_cmu_usb_clock_config(CMU_USB_CLOCK_SEL_HOSC, CMU_USB_DIV_1);
|
||||
ald_rmu_reset_periperal(RMU_PERH_USB);
|
||||
ald_mcu_irq_config(USB_INT_IRQn, 2, 2, ENABLE);
|
||||
ald_mcu_irq_config(USB_DMA_IRQn, 2, 2, ENABLE);
|
||||
usb_pin_init();
|
||||
}
|
||||
|
||||
- 描述符的注册、class的注册、接口的注册、端点中断的注册。不会的参考 demo 下的 template 。
|
||||
- 调用 `usbd_initialize` 初始化 usb 硬件。
|
||||
- 正常使用。
|
||||
|
||||
|
||||
USB Host 移植要点
|
||||
-----------------------
|
||||
|
||||
针对自定义的工程移植,需要以下步骤:
|
||||
|
||||
- 准备好可以进行调试打印的带 FreeRTOS 或者 RT-Thread 的工程,并且实现 `printf`、 `malloc` 、 `free` 函数(也可以直接勾选 Use microlib 来使用)。
|
||||
- 拷贝 CherryUSB 源码到工程里
|
||||
- 添加 CherryUSB 源码和头文件路径,其中 `usbh_core.c` 和 `usb_hc_musb.c` 、 osal 下的文件为必须添加项,根据不同的 os 添加对应的文件。
|
||||
- 拷贝 `cherryusb_config_template.h` 文件到自己工程目录下,命名为 `usb_config.h` ,并添加相应的目录头文件路径。所以根目录下的文件仅作为参考,不要添加根目录下的头文件。
|
||||
|
||||
.. figure:: img/es324.png
|
||||
.. figure:: img/es325.png
|
||||
|
||||
- 由于是作为主机,推荐添加所有的 class,功能全面。当然如果只用一个 class ,就添加一个。
|
||||
- 实现 `usb_hc_low_level_init` 函数,该函数主要负责 USB 时钟、引脚、中断的初始化。例如
|
||||
|
||||
.. code-block:: C
|
||||
|
||||
void usb_hc_low_level_init(void)
|
||||
{
|
||||
ald_pmu_perh_power_config(PMU_POWER_USB, ENABLE);
|
||||
ald_cmu_perh_clock_config(CMU_PERH_USB, ENABLE);
|
||||
ald_cmu_perh_clock_config(CMU_PERH_GPIO, ENABLE);
|
||||
ald_cmu_usb_clock_config(CMU_USB_CLOCK_SEL_HOSC, CMU_USB_DIV_1);
|
||||
ald_rmu_reset_periperal(RMU_PERH_USB);
|
||||
ald_mcu_irq_config(USB_INT_IRQn, 2, 2, ENABLE);
|
||||
ald_mcu_irq_config(USB_DMA_IRQn, 2, 2, ENABLE);
|
||||
usb_pin_init();
|
||||
}
|
||||
|
||||
- 调用 `usbh_initialize` 初始化 usb 硬件。
|
||||
- 此时编译会报错,因为协议栈中为每个 class 都添加了测试 demo,文件在 `usb_host.c` 中,如果不想要,可以直接删除。
|
||||
- 正常使用。
|
||||
@@ -1,6 +0,0 @@
|
||||
基于 HPM 系列开发指南
|
||||
=========================
|
||||
|
||||
HPM 系列 USB 的开发主要使用 hpm_sdk ,参考 `hpm sdk <https://github.com/hpmicro/hpm_sdk>`_。
|
||||
|
||||
USB 的相关应用位于 `samples/cherryusb` 目录下,环境搭建完成后,即可编译使用。
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.4 KiB |
@@ -1,13 +1,41 @@
|
||||
基于 STM32F1/F4/H7 开发指南
|
||||
=============================
|
||||
基于现有 demo 快速验证
|
||||
=========================
|
||||
|
||||
本节是基于 STM32 三个系列芯片的使用,涵盖 F1/F4/H7,其余芯片基本类似,不再赘述,具体区别有:
|
||||
在学习 USB 或者是学习 CherryUSB 代码之前,我们需要先基于现有的 demo 进行快速验证,为什么?是为了提升对 USB 的兴趣,能有信心进行下一步的动作,如果 demo 都跑不起来,或者自己摸索写代码,或者先看 USB 基本概念,结果看到最后,
|
||||
发现一点都看不懂,概念好多,根本记不住,从而丧失对 USB 的兴趣。因此,先跑 demo 非常重要。下面我将给大家罗列目前支持的 demo 仓库。
|
||||
|
||||
|
||||
基于 bouffalolab 系列芯片
|
||||
---------------------------
|
||||
|
||||
仓库参考:https://github.com/CherryUSB/cherryusb_bouffalolab
|
||||
|
||||
- BL702 是一个 USB2.0 全速芯片,共 8 个端点(包含端点0)。仅支持从机。
|
||||
- BL616/BL808 是一个 USB2.0 并且内置高速 PHY 芯片,共 5个端点(包含端点0)。支持主从机。
|
||||
- USB 的相关应用位于 `examples/usbdev` 和 `examples/usbhost` 目录下,根据官方环境搭建完成后,即可编译使用。
|
||||
|
||||
|
||||
基于 ST 系列芯片
|
||||
---------------------------
|
||||
|
||||
仓库参考:https://github.com/CherryUSB/cherryusb_stm32
|
||||
|
||||
默认提供以下 demo 工程:
|
||||
|
||||
- F103 使用 fsdev ip
|
||||
- F429 主从使用 hs port,并且均用 dma 模式
|
||||
- H7 设备使用 fs port,主机使用 hs port,并且主机带 cache 支持
|
||||
|
||||
默认删除 Drivers ,所以需要使用 stm32cubemx 生成一下 Drivers 目录下的文件,demo 底下提供了 **stm32xxx.ioc** 文件,双击打开,点击 **Generate Code** 即可。
|
||||
|
||||
.. caution:: 生成完以后,请使用 git reset 功能将被覆盖的 `main.c` 和 `stm32xxx_it.c` 文件撤回,禁止被 cubemx 覆盖。
|
||||
|
||||
涵盖 F1/F4/H7,其余芯片基本类似,不再赘述,具体区别有:
|
||||
|
||||
- usb ip 区别:F1使用 fsdev,F4/H7使用 dwc2
|
||||
- dwc2 ip 区别: fs port(引脚是 PA11/PA12) 和 hs port(引脚是 PB14/PB15), 其中 hs port 默认全速,可以接外部PHY 形成高速主机,并且带 dma 功能
|
||||
- F4 与 H7 cache 区别、USB BASE 区别
|
||||
|
||||
|
||||
如果是 STM32F7/STM32H7 这种带 cache 功能,需要将 usb 使用到的 ram 定位到 no cache ram 区域。举例如下
|
||||
|
||||
.. code-block:: C
|
||||
@@ -38,22 +66,8 @@
|
||||
|
||||
.. figure:: img/keil.png
|
||||
|
||||
工程样例试用
|
||||
-----------------------
|
||||
|
||||
默认提供以下 demo 工程:
|
||||
|
||||
- F103 使用 fsdev ip
|
||||
- F429 主从使用 hs port,并且均用 dma 模式
|
||||
- H7 设备使用 fs port,主机使用 hs port,并且主机带 cache 支持
|
||||
|
||||
|
||||
默认删除 Drivers ,所以需要使用 stm32cubemx 生成一下 Drivers 目录下的文件,demo 底下提供了 **stm32xxx.ioc** 文件,双击打开,点击 **Generate Code** 即可。
|
||||
|
||||
.. caution:: 生成完以后,请使用 git reset 功能将被覆盖的 `main.c` 和 `stm32xxx_it.c` 文件撤回,禁止被 cubemx 覆盖。
|
||||
|
||||
USB Device 移植要点
|
||||
-----------------------
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- 使用 **stm32cubemx** 创建工程,配置基本的 RCC、UART (作为log使用)
|
||||
|
||||
@@ -106,7 +120,7 @@ USB Device 移植要点
|
||||
.. figure:: img/stm32_15.png
|
||||
|
||||
USB Host 移植要点
|
||||
-----------------------
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
前面 7 步与 Device 一样。需要注意,host 驱动只支持带 dma 的 hs port (引脚是 PB14/PB15),所以 fs port (引脚是 PA11/PA12)不做支持(没有 dma 你玩什么主机)。
|
||||
|
||||
@@ -131,4 +145,12 @@ USB Host 移植要点
|
||||
|
||||
- 如果使用 **msc**,并且带文件系统,需要自行添加文件系统文件了,对应的 porting 编写参考 **fatfs_usbh.c** 文件。
|
||||
|
||||
.. figure:: img/stm32_21.png
|
||||
.. figure:: img/stm32_21.png
|
||||
|
||||
基于 HPMicro 系列芯片
|
||||
---------------------------
|
||||
|
||||
仓库参考:https://github.com/CherryUSB/cherryusb_hpmicro
|
||||
|
||||
- HPM 系列芯片均 USB 2.0 并且内置高速 PHY,支持主从机
|
||||
- USB 的相关应用位于 `samples/cherryusb` ,根据官方环境搭建完成后,即可编译使用。
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define USB_OSAL_WAITING_FOREVER (0xFFFFFFFFU)
|
||||
|
||||
typedef void *usb_osal_thread_t;
|
||||
typedef void *usb_osal_sem_t;
|
||||
typedef void *usb_osal_mutex_t;
|
||||
|
||||
@@ -35,7 +35,11 @@ void usb_osal_sem_delete(usb_osal_sem_t sem)
|
||||
|
||||
int usb_osal_sem_take(usb_osal_sem_t sem, uint32_t timeout)
|
||||
{
|
||||
return (xSemaphoreTake((SemaphoreHandle_t)sem, pdMS_TO_TICKS(timeout)) == pdPASS) ? 0 : -ETIMEDOUT;
|
||||
if (timeout == USB_OSAL_WAITING_FOREVER) {
|
||||
return (xSemaphoreTake((SemaphoreHandle_t)sem, portMAX_DELAY) == pdPASS) ? 0 : -ETIMEDOUT;
|
||||
} else {
|
||||
return (xSemaphoreTake((SemaphoreHandle_t)sem, pdMS_TO_TICKS(timeout)) == pdPASS) ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
int usb_osal_sem_give(usb_osal_sem_t sem)
|
||||
@@ -95,7 +99,11 @@ int usb_osal_mq_send(usb_osal_mq_t mq, uintptr_t addr)
|
||||
|
||||
int usb_osal_mq_recv(usb_osal_mq_t mq, uintptr_t *addr, uint32_t timeout)
|
||||
{
|
||||
return (xQueueReceive((usb_osal_mq_t)mq, addr, timeout) == pdPASS) ? 0 : -ETIMEDOUT;
|
||||
if (timeout == USB_OSAL_WAITING_FOREVER) {
|
||||
return (xQueueReceive((usb_osal_mq_t)mq, addr, portMAX_DELAY) == pdPASS) ? 0 : -ETIMEDOUT;
|
||||
} else {
|
||||
return (xQueueReceive((usb_osal_mq_t)mq, addr, pdMS_TO_TICKS(timeout)) == pdPASS) ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
size_t usb_osal_enter_critical_section(void)
|
||||
|
||||
@@ -40,7 +40,11 @@ int usb_osal_sem_take(usb_osal_sem_t sem, uint32_t timeout)
|
||||
int ret = 0;
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
result = rt_sem_take((rt_sem_t)sem, rt_tick_from_millisecond(timeout));
|
||||
if (timeout == USB_OSAL_WAITING_FOREVER) {
|
||||
result = rt_sem_take((rt_sem_t)sem, RT_WAITING_FOREVER);
|
||||
} else {
|
||||
result = rt_sem_take((rt_sem_t)sem, rt_tick_from_millisecond(timeout));
|
||||
}
|
||||
if (result == -RT_ETIMEOUT) {
|
||||
ret = -ETIMEDOUT;
|
||||
} else if (result == -RT_ERROR) {
|
||||
@@ -92,7 +96,11 @@ int usb_osal_mq_recv(usb_osal_mq_t mq, uintptr_t *addr, uint32_t timeout)
|
||||
int ret = 0;
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
result = rt_mq_recv((rt_mq_t)mq, addr, sizeof(uintptr_t), rt_tick_from_millisecond(timeout));
|
||||
if (timeout == USB_OSAL_WAITING_FOREVER) {
|
||||
result = rt_mq_recv((rt_mq_t)mq, addr, sizeof(uintptr_t), RT_WAITING_FOREVER);
|
||||
} else {
|
||||
result = rt_mq_recv((rt_mq_t)mq, addr, sizeof(uintptr_t), rt_tick_from_millisecond(timeout));
|
||||
}
|
||||
if (result == -RT_ETIMEOUT) {
|
||||
ret = -ETIMEDOUT;
|
||||
} else if (result == -RT_ERROR) {
|
||||
|
||||
@@ -38,7 +38,11 @@ void usb_osal_sem_delete(usb_osal_sem_t sem)
|
||||
|
||||
int usb_osal_sem_take(usb_osal_sem_t sem, uint32_t timeout)
|
||||
{
|
||||
return aos_sem_wait((aos_sem_t *)&sem, timeout);
|
||||
if (timeout == USB_OSAL_WAITING_FOREVER) {
|
||||
return aos_sem_wait((aos_sem_t *)&sem, AOS_WAIT_FOREVER);
|
||||
} else {
|
||||
return aos_sem_wait((aos_sem_t *)&sem, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
int usb_osal_sem_give(usb_osal_sem_t sem)
|
||||
@@ -88,7 +92,11 @@ int usb_osal_mq_send(usb_osal_mq_t mq, uintptr_t addr)
|
||||
int usb_osal_mq_recv(usb_osal_mq_t mq, uintptr_t *addr, uint32_t timeout)
|
||||
{
|
||||
size_t recv_size;
|
||||
return aos_queue_recv((aos_queue_t *)&mq, timeout, addr, &recv_size);
|
||||
if (timeout == USB_OSAL_WAITING_FOREVER) {
|
||||
return aos_queue_recv((aos_queue_t *)&mq, AOS_WAIT_FOREVER, addr, &recv_size);
|
||||
} else {
|
||||
return aos_queue_recv((aos_queue_t *)&mq, timeout, addr, &recv_size);
|
||||
}
|
||||
}
|
||||
|
||||
size_t usb_osal_enter_critical_section(void)
|
||||
|
||||
@@ -270,7 +270,7 @@ void USBD_IRQHandler(void)
|
||||
|
||||
case USBFS_UIS_TOKEN_IN:
|
||||
if (ep_idx == 0x00) {
|
||||
if (g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len > g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps) {
|
||||
if (g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len >= g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps) {
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len -= g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps;
|
||||
g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps;
|
||||
ep0_tx_data_toggle ^= 1;
|
||||
|
||||
@@ -258,7 +258,7 @@ void USBD_IRQHandler(void)
|
||||
|
||||
if (token == PID_IN) {
|
||||
if (ep_idx == 0x00) {
|
||||
if (g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len > g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps) {
|
||||
if (g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len >= g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps) {
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len -= g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps;
|
||||
g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps;
|
||||
ep0_tx_data_toggle ^= 1;
|
||||
|
||||
@@ -325,14 +325,17 @@ static void dwc2_set_turnaroundtime(uint32_t hclk, uint8_t speed)
|
||||
UsbTrd = USBD_DEFAULT_TRDT_VALUE;
|
||||
}
|
||||
|
||||
USB_OTG_GLB->GUSBCFG |= USB_OTG_GUSBCFG_TOCAL;
|
||||
|
||||
USB_OTG_GLB->GUSBCFG &= ~USB_OTG_GUSBCFG_TRDT;
|
||||
USB_OTG_GLB->GUSBCFG |= (uint32_t)((UsbTrd << 10) & USB_OTG_GUSBCFG_TRDT);
|
||||
USB_OTG_GLB->GUSBCFG |= (uint32_t)((UsbTrd << USB_OTG_GUSBCFG_TRDT_Pos) & USB_OTG_GUSBCFG_TRDT);
|
||||
}
|
||||
|
||||
static void dwc2_set_txfifo(uint8_t fifo, uint16_t size)
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t Tx_Offset;
|
||||
uint32_t Tx_Size;
|
||||
|
||||
/* TXn min size = 16 words. (n : Transmit FIFO index)
|
||||
When a TxFIFO is not used, the Configuration should be as follows:
|
||||
@@ -348,6 +351,7 @@ static void dwc2_set_txfifo(uint8_t fifo, uint16_t size)
|
||||
|
||||
if (fifo == 0U) {
|
||||
USB_OTG_GLB->DIEPTXF0_HNPTXFSIZ = ((uint32_t)size << 16) | Tx_Offset;
|
||||
Tx_Size = USB_OTG_GLB->DIEPTXF0_HNPTXFSIZ;
|
||||
} else {
|
||||
Tx_Offset += (USB_OTG_GLB->DIEPTXF0_HNPTXFSIZ) >> 16;
|
||||
for (i = 0U; i < (fifo - 1U); i++) {
|
||||
@@ -356,7 +360,11 @@ static void dwc2_set_txfifo(uint8_t fifo, uint16_t size)
|
||||
|
||||
/* Multiply Tx_Size by 2 to get higher performance */
|
||||
USB_OTG_GLB->DIEPTXF[fifo - 1U] = ((uint32_t)size << 16) | Tx_Offset;
|
||||
|
||||
Tx_Size = USB_OTG_GLB->DIEPTXF[fifo - 1U];
|
||||
}
|
||||
|
||||
USB_LOG_INFO("fifo-%02d size:%04d %08x\n", fifo, size, Tx_Size);
|
||||
}
|
||||
|
||||
static uint8_t dwc2_get_devspeed(void)
|
||||
@@ -665,8 +673,9 @@ int usb_dc_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
USB_OTG_GLB->GAHBCFG |= USB_OTG_GAHBCFG_HBSTLEN_2;
|
||||
USB_OTG_GLB->GAHBCFG |= USB_OTG_GAHBCFG_DMAEN;
|
||||
USB_OTG_DEV->DCFG &= ~USB_OTG_DCFG_DESCDMA;
|
||||
USB_OTG_GLB->GAHBCFG |= (USB_OTG_GAHBCFG_DMAEN | USB_OTG_GAHBCFG_HBSTLEN_2);
|
||||
|
||||
#else
|
||||
USB_OTG_GLB->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM;
|
||||
#endif
|
||||
@@ -688,6 +697,15 @@ int usb_dc_init(void)
|
||||
#endif
|
||||
#if USB_NUM_BIDIR_ENDPOINTS > 5
|
||||
dwc2_set_txfifo(5, CONFIG_USB_DWC2_TX5_FIFO_SIZE / 4);
|
||||
#endif
|
||||
#if USB_NUM_BIDIR_ENDPOINTS > 6
|
||||
dwc2_set_txfifo(6, CONFIG_USB_DWC2_TX6_FIFO_SIZE / 4);
|
||||
#endif
|
||||
#if USB_NUM_BIDIR_ENDPOINTS > 7
|
||||
dwc2_set_txfifo(7, CONFIG_USB_DWC2_TX7_FIFO_SIZE / 4);
|
||||
#endif
|
||||
#if USB_NUM_BIDIR_ENDPOINTS > 8
|
||||
dwc2_set_txfifo(8, CONFIG_USB_DWC2_TX8_FIFO_SIZE / 4);
|
||||
#endif
|
||||
USB_OTG_GLB->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
|
||||
USB_OTG_DEV->DCTL &= ~USB_OTG_DCTL_SDIS;
|
||||
@@ -821,7 +839,7 @@ int usbd_ep_close(const uint8_t ep)
|
||||
/* Clear and unmask endpoint disabled interrupt */
|
||||
USB_OTG_INEP(ep_idx)->DIEPINT |= USB_OTG_DIEPINT_EPDISD;
|
||||
}
|
||||
|
||||
|
||||
USB_OTG_DEV->DEACHMSK &= ~(USB_OTG_DAINTMSK_IEPM & (uint32_t)(1UL << (ep_idx & 0x07)));
|
||||
USB_OTG_DEV->DAINTMSK &= ~(USB_OTG_DAINTMSK_IEPM & (uint32_t)(1UL << (ep_idx & 0x07)));
|
||||
USB_OTG_INEP(ep_idx)->DIEPCTL = 0;
|
||||
@@ -888,9 +906,11 @@ int usbd_ep_start_write(const uint8_t ep, const uint8_t *data, uint32_t data_len
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
#if 0 /* some chips have confused with this, so disable as default */
|
||||
if (USB_OTG_INEP(ep_idx)->DIEPCTL & USB_OTG_DIEPCTL_EPENA) {
|
||||
return -2;
|
||||
}
|
||||
#endif
|
||||
if (ep_idx && !(USB_OTG_INEP(ep_idx)->DIEPCTL & USB_OTG_DIEPCTL_MPSIZ)) {
|
||||
return -3;
|
||||
}
|
||||
@@ -959,9 +979,11 @@ int usbd_ep_start_read(const uint8_t ep, uint8_t *data, uint32_t data_len)
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
#if 0 /* some chips have confused with this, so disable as default */
|
||||
if (USB_OTG_OUTEP(ep_idx)->DOEPCTL & USB_OTG_DOEPCTL_EPENA) {
|
||||
return -2;
|
||||
}
|
||||
#endif
|
||||
if (ep_idx && !(USB_OTG_OUTEP(ep_idx)->DOEPCTL & USB_OTG_DOEPCTL_MPSIZ)) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
@@ -241,6 +241,10 @@ typedef struct
|
||||
#define USB_OTG_DCFG_ERRATIM_Msk (0x1UL << USB_OTG_DCFG_ERRATIM_Pos) /*!< 0x00008000 */
|
||||
#define USB_OTG_DCFG_ERRATIM USB_OTG_DCFG_ERRATIM_Msk /*!< Erratic error interrupt mask */
|
||||
|
||||
#define USB_OTG_DCFG_DESCDMA_Pos (23U)
|
||||
#define USB_OTG_DCFG_DESCDMA_Msk (0x1UL << USB_OTG_DCFG_DESCDMA_Pos)
|
||||
#define USB_OTG_DCFG_DESCDMA USB_OTG_DCFG_DESCDMA_Msk
|
||||
|
||||
#define USB_OTG_DCFG_PERSCHIVL_Pos (24U)
|
||||
#define USB_OTG_DCFG_PERSCHIVL_Msk (0x3UL << USB_OTG_DCFG_PERSCHIVL_Pos) /*!< 0x03000000 */
|
||||
#define USB_OTG_DCFG_PERSCHIVL USB_OTG_DCFG_PERSCHIVL_Msk /*!< Periodic scheduling interval */
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
#define USBH_IRQHandler USBH_IRQHandler
|
||||
#endif
|
||||
|
||||
#define EHCI_HCCR ((struct ehci_hccr *)CONFIG_USB_EHCI_HCCR_BASE)
|
||||
#define EHCI_HCOR ((struct ehci_hcor *)CONFIG_USB_EHCI_HCOR_BASE)
|
||||
#define EHCI_HCCR ((struct ehci_hccr *)CONFIG_USB_EHCI_HCCR_BASE)
|
||||
#define EHCI_HCOR ((struct ehci_hcor *)CONFIG_USB_EHCI_HCOR_BASE)
|
||||
|
||||
#define EHCI_PTR2ADDR(x) ((uint32_t)x)
|
||||
#define EHCI_ADDRALIGN32(x) ((uint32_t)(x) & ~0x1F)
|
||||
#define EHCI_ADDR2QH(x) ((struct ehci_qh_hw *)((uint32_t)(x) & ~0x1F))
|
||||
#define EHCI_ADDR2ITD(x) ((struct ehci_itd_hw *)((uint32_t)(x) & ~0x1F))
|
||||
#define EHCI_PTR2ADDR(x) ((uint32_t)(x) & ~0x1F)
|
||||
#define EHCI_ADDR2QH(x) ((struct ehci_qh_hw *)((uint32_t)(x) & ~0x1F))
|
||||
#define EHCI_ADDR2QTD(x) ((struct ehci_qtd_hw *)((uint32_t)(x) & ~0x1F))
|
||||
#define EHCI_ADDR2ITD(x) ((struct ehci_itd_hw *)((uint32_t)(x) & ~0x1F))
|
||||
|
||||
#if CONFIG_USB_EHCI_FRAME_LIST_SIZE == 1024
|
||||
#define EHCI_PERIOIDIC_QH_NUM 11
|
||||
@@ -49,7 +49,6 @@ struct ehci_pipe {
|
||||
bool waiter;
|
||||
usb_osal_sem_t waitsem;
|
||||
struct usbh_hubport *hport;
|
||||
struct ehci_qh_hw *qh;
|
||||
struct usbh_urb *urb;
|
||||
uint8_t mf_unmask;
|
||||
uint8_t mf_valid;
|
||||
@@ -60,11 +59,14 @@ struct ehci_pipe {
|
||||
struct ehci_qh_hw {
|
||||
struct ehci_qh hw;
|
||||
uint32_t first_qtd;
|
||||
struct ehci_pipe *pipe;
|
||||
struct usbh_urb *urb;
|
||||
uint8_t remove_in_iaad;
|
||||
} __attribute__((aligned(32)));
|
||||
|
||||
struct ehci_qtd_hw {
|
||||
struct ehci_qtd hw;
|
||||
struct usbh_urb *urb;
|
||||
uint32_t total_len;
|
||||
} __attribute__((aligned(32)));
|
||||
|
||||
struct ehci_itd_hw {
|
||||
|
||||
134
port/ehci/usb_glue_bouffalo.c
Normal file
134
port/ehci/usb_glue_bouffalo.c
Normal file
@@ -0,0 +1,134 @@
|
||||
#include "bflb_core.h"
|
||||
#include "usbh_core.h"
|
||||
#include "hardware/usb_v2_reg.h"
|
||||
|
||||
#ifndef CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
|
||||
#error "usb host must enable CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE"
|
||||
#endif
|
||||
|
||||
#define BLFB_USB_BASE ((uint32_t)0x20072000)
|
||||
#define BFLB_PDS_BASE ((uint32_t)0x2000e000)
|
||||
|
||||
#define PDS_USB_CTL_OFFSET (0x500) /* usb_ctl */
|
||||
#define PDS_USB_PHY_CTRL_OFFSET (0x504) /* usb_phy_ctrl */
|
||||
|
||||
/* 0x500 : usb_ctl */
|
||||
#define PDS_REG_USB_SW_RST_N (1 << 0U)
|
||||
#define PDS_REG_USB_EXT_SUSP_N (1 << 1U)
|
||||
#define PDS_REG_USB_WAKEUP (1 << 2U)
|
||||
#define PDS_REG_USB_L1_WAKEUP (1 << 3U)
|
||||
#define PDS_REG_USB_DRVBUS_POL (1 << 4U)
|
||||
#define PDS_REG_USB_IDDIG (1 << 5U)
|
||||
|
||||
/* 0x504 : usb_phy_ctrl */
|
||||
#define PDS_REG_USB_PHY_PONRST (1 << 0U)
|
||||
#define PDS_REG_USB_PHY_OSCOUTEN (1 << 1U)
|
||||
#define PDS_REG_USB_PHY_XTLSEL_SHIFT (2U)
|
||||
#define PDS_REG_USB_PHY_XTLSEL_MASK (0x3 << PDS_REG_USB_PHY_XTLSEL_SHIFT)
|
||||
#define PDS_REG_USB_PHY_OUTCLKSEL (1 << 4U)
|
||||
#define PDS_REG_USB_PHY_PLLALIV (1 << 5U)
|
||||
#define PDS_REG_PU_USB20_PSW (1 << 6U)
|
||||
|
||||
#define USB_SOF_TIMER_MASK_AFTER_RESET_HS (0x44C)
|
||||
#define USB_SOF_TIMER_MASK_AFTER_RESET_FS (0x2710)
|
||||
|
||||
extern void USBH_IRQHandler();
|
||||
|
||||
static void bflb_usb_phy_init(void)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
/* USB_PHY_CTRL[3:2] reg_usb_phy_xtlsel=0 */
|
||||
/* 2000e504 = 0x40; #100; USB_PHY_CTRL[6] reg_pu_usb20_psw=1 (VCC33A) */
|
||||
/* 2000e504 = 0x41; #500; USB_PHY_CTRL[0] reg_usb_phy_ponrst=1 */
|
||||
/* 2000e500 = 0x20; #100; USB_CTL[0] reg_usb_sw_rst_n=0 */
|
||||
/* 2000e500 = 0x22; #500; USB_CTL[1] reg_usb_ext_susp_n=1 */
|
||||
/* 2000e500 = 0x23; #100; USB_CTL[0] reg_usb_sw_rst_n=1 */
|
||||
/* #1.2ms; wait UCLK */
|
||||
/* wait(soc616_b0.usb_uclk); */
|
||||
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
|
||||
regval &= ~PDS_REG_USB_PHY_XTLSEL_MASK;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
|
||||
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
|
||||
regval |= PDS_REG_PU_USB20_PSW;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
|
||||
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
|
||||
regval |= PDS_REG_USB_PHY_PONRST;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_PHY_CTRL_OFFSET);
|
||||
|
||||
/* greater than 5T */
|
||||
bflb_mtimer_delay_us(1);
|
||||
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
regval &= ~PDS_REG_USB_SW_RST_N;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
|
||||
/* greater than 5T */
|
||||
bflb_mtimer_delay_us(1);
|
||||
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
regval |= PDS_REG_USB_EXT_SUSP_N;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
|
||||
/* wait UCLK 1.2ms */
|
||||
bflb_mtimer_delay_ms(3);
|
||||
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
regval |= PDS_REG_USB_SW_RST_N;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
|
||||
bflb_mtimer_delay_ms(2);
|
||||
}
|
||||
|
||||
void usb_hc_low_level_init(void)
|
||||
{
|
||||
uint32_t regval;
|
||||
|
||||
bflb_usb_phy_init();
|
||||
|
||||
bflb_irq_attach(37, USBH_IRQHandler, NULL);
|
||||
bflb_irq_enable(37);
|
||||
|
||||
/* enable device-A for host */
|
||||
regval = getreg32(BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
regval &= ~PDS_REG_USB_IDDIG;
|
||||
putreg32(regval, BFLB_PDS_BASE + PDS_USB_CTL_OFFSET);
|
||||
|
||||
regval = getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
|
||||
regval |= USB_A_BUS_DROP_HOV;
|
||||
regval &= ~USB_A_BUS_REQ_HOV;
|
||||
putreg32(regval, BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
|
||||
|
||||
bflb_mtimer_delay_ms(10);
|
||||
|
||||
/* enable vbus and bus control */
|
||||
regval = getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
|
||||
regval &= ~USB_A_BUS_DROP_HOV;
|
||||
regval |= USB_A_BUS_REQ_HOV;
|
||||
putreg32(regval, BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
|
||||
|
||||
regval = getreg32(BLFB_USB_BASE + USB_GLB_INT_OFFSET);
|
||||
regval |= USB_MDEV_INT;
|
||||
regval |= USB_MOTG_INT;
|
||||
regval &= ~USB_MHC_INT;
|
||||
putreg32(regval, BLFB_USB_BASE + USB_GLB_INT_OFFSET);
|
||||
}
|
||||
|
||||
uint8_t usbh_get_port_speed(const uint8_t port)
|
||||
{
|
||||
uint8_t speed = 3;
|
||||
|
||||
speed = (getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET) & USB_SPD_TYP_HOV_POV_MASK) >> USB_SPD_TYP_HOV_POV_SHIFT;
|
||||
|
||||
if (speed == 0) {
|
||||
return USB_SPEED_FULL;
|
||||
} else if (speed == 1) {
|
||||
return USB_SPEED_LOW;
|
||||
} else if (speed == 2) {
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
return USB_SPEED_HIGH;
|
||||
}
|
||||
@@ -3,39 +3,13 @@
|
||||
#include "hpm_soc.h"
|
||||
#include "hpm_usb_drv.h"
|
||||
|
||||
#define USB_PHY_INIT_DELAY_COUNT (16U) /**< a delay count for USB phy initialization */
|
||||
#if !defined(CONFIG_USB_EHCI_HPMICRO) || !CONFIG_USB_EHCI_HPMICRO
|
||||
#error "hpm ehci must set CONFIG_USB_EHCI_HPMICRO=1"
|
||||
#endif
|
||||
|
||||
/* Initialize USB phy */
|
||||
static void usb_phy_init(USB_Type *ptr)
|
||||
{
|
||||
uint32_t status;
|
||||
|
||||
ptr->OTG_CTRL0 |= USB_OTG_CTRL0_OTG_UTMI_RESET_SW_MASK; /* set otg_utmi_reset_sw for naneng usbphy */
|
||||
ptr->OTG_CTRL0 &= ~USB_OTG_CTRL0_OTG_UTMI_SUSPENDM_SW_MASK; /* clr otg_utmi_suspend_m for naneng usbphy */
|
||||
ptr->PHY_CTRL1 &= ~USB_PHY_CTRL1_UTMI_CFG_RST_N_MASK; /* clr cfg_rst_n */
|
||||
|
||||
do {
|
||||
status = USB_OTG_CTRL0_OTG_UTMI_RESET_SW_GET(ptr->OTG_CTRL0); /* wait for reset status */
|
||||
} while (status == 0);
|
||||
|
||||
ptr->OTG_CTRL0 |= USB_OTG_CTRL0_OTG_UTMI_SUSPENDM_SW_MASK; /* set otg_utmi_suspend_m for naneng usbphy */
|
||||
|
||||
for (int i = 0; i < USB_PHY_INIT_DELAY_COUNT; i++) {
|
||||
ptr->PHY_CTRL0 = USB_PHY_CTRL0_GPIO_ID_SEL_N_SET(0); /* used for delay */
|
||||
}
|
||||
|
||||
ptr->OTG_CTRL0 &= ~USB_OTG_CTRL0_OTG_UTMI_RESET_SW_MASK; /* clear otg_utmi_reset_sw for naneng usbphy */
|
||||
|
||||
/* otg utmi clock detection */
|
||||
ptr->PHY_STATUS |= USB_PHY_STATUS_UTMI_CLK_VALID_MASK; /* write 1 to clear valid status */
|
||||
do {
|
||||
status = USB_PHY_STATUS_UTMI_CLK_VALID_GET(ptr->PHY_STATUS); /* get utmi clock status */
|
||||
} while (status == 0);
|
||||
|
||||
ptr->PHY_CTRL1 |= USB_PHY_CTRL1_UTMI_CFG_RST_N_MASK; /* set cfg_rst_n */
|
||||
|
||||
ptr->PHY_CTRL1 |= USB_PHY_CTRL1_UTMI_OTG_SUSPENDM_MASK; /* set otg_suspendm */
|
||||
}
|
||||
#if !defined(CONFIG_HPM_USBH_BASE) || !defined(CONFIG_HPM_USBH_IRQn)
|
||||
#error "hpm ehci must config CONFIG_HPM_USBH_BASE and CONFIG_HPM_USBH_IRQn"
|
||||
#endif
|
||||
|
||||
static void usb_host_mode_init(USB_Type *ptr)
|
||||
{
|
||||
@@ -58,20 +32,20 @@ static void usb_host_mode_init(USB_Type *ptr)
|
||||
|
||||
void usb_hc_low_level_init()
|
||||
{
|
||||
usb_phy_init((USB_Type *)HPM_USB0_BASE);
|
||||
intc_m_enable_irq(IRQn_USB0);
|
||||
usb_phy_init((USB_Type *)CONFIG_HPM_USBH_BASE);
|
||||
intc_m_enable_irq(CONFIG_HPM_USBH_IRQn);
|
||||
}
|
||||
|
||||
void usb_hc_low_level2_init()
|
||||
{
|
||||
usb_host_mode_init((USB_Type *)HPM_USB0_BASE);
|
||||
usb_host_mode_init((USB_Type *)CONFIG_HPM_USBH_BASE);
|
||||
}
|
||||
|
||||
uint8_t usbh_get_port_speed(const uint8_t port)
|
||||
{
|
||||
uint8_t speed;
|
||||
|
||||
speed = usb_get_port_speed((USB_Type *)HPM_USB0_BASE);
|
||||
speed = usb_get_port_speed((USB_Type *)CONFIG_HPM_USBH_BASE);
|
||||
|
||||
if (speed == 0x00) {
|
||||
return USB_SPEED_FULL;
|
||||
@@ -88,15 +62,8 @@ uint8_t usbh_get_port_speed(const uint8_t port)
|
||||
|
||||
extern void USBH_IRQHandler(void);
|
||||
|
||||
void isr_usb0(void)
|
||||
void isr_usb(void)
|
||||
{
|
||||
USBH_IRQHandler();
|
||||
}
|
||||
SDK_DECLARE_EXT_ISR_M(IRQn_USB0, isr_usb0)
|
||||
|
||||
#ifdef HPM_USB1_BASE
|
||||
void isr_usb1(void)
|
||||
{
|
||||
}
|
||||
SDK_DECLARE_EXT_ISR_M(IRQn_USB1, isr_usb1)
|
||||
#endif
|
||||
SDK_DECLARE_EXT_ISR_M(CONFIG_HPM_USBH_IRQn, isr_usb)
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
*/
|
||||
#include "usb_ehci_priv.h"
|
||||
|
||||
#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
|
||||
#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
|
||||
#define EHCI_TUNE_RL_TT 0
|
||||
#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
|
||||
#define EHCI_TUNE_MULT_TT 1
|
||||
|
||||
struct ehci_hcd g_ehci_hcd;
|
||||
|
||||
USB_NOCACHE_RAM_SECTION struct ehci_qh_hw ehci_qh_pool[CONFIG_USB_EHCI_QH_NUM];
|
||||
@@ -18,16 +24,17 @@ USB_NOCACHE_RAM_SECTION struct ehci_qh_hw g_periodic_qh_head[EHCI_PERIOIDIC_QH_N
|
||||
/* The frame list */
|
||||
USB_NOCACHE_RAM_SECTION uint32_t g_framelist[CONFIG_USB_EHCI_FRAME_LIST_SIZE] __attribute__((aligned(4096)));
|
||||
|
||||
static const uint8_t g_ehci_speed[4] = {
|
||||
0, EHCI_LOW_SPEED, EHCI_FULL_SPEED, EHCI_HIGH_SPEED
|
||||
};
|
||||
|
||||
static struct ehci_qh_hw *ehci_qh_alloc(void)
|
||||
{
|
||||
struct ehci_qh_hw *qh;
|
||||
size_t flags;
|
||||
|
||||
for (uint32_t i = 0; i < CONFIG_USB_EHCI_QH_NUM; i++) {
|
||||
if (!g_ehci_hcd.ehci_qh_used[i]) {
|
||||
flags = usb_osal_enter_critical_section();
|
||||
g_ehci_hcd.ehci_qh_used[i] = true;
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
qh = &ehci_qh_pool[i];
|
||||
memset(qh, 0, sizeof(struct ehci_qh_hw));
|
||||
qh->hw.hlp = QTD_LIST_END;
|
||||
@@ -41,9 +48,15 @@ static struct ehci_qh_hw *ehci_qh_alloc(void)
|
||||
|
||||
static void ehci_qh_free(struct ehci_qh_hw *qh)
|
||||
{
|
||||
size_t flags;
|
||||
|
||||
for (uint32_t i = 0; i < CONFIG_USB_EHCI_QH_NUM; i++) {
|
||||
if (&ehci_qh_pool[i] == qh) {
|
||||
flags = usb_osal_enter_critical_section();
|
||||
g_ehci_hcd.ehci_qh_used[i] = false;
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
qh->urb = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -52,9 +65,14 @@ static void ehci_qh_free(struct ehci_qh_hw *qh)
|
||||
static struct ehci_qtd_hw *ehci_qtd_alloc(void)
|
||||
{
|
||||
struct ehci_qtd_hw *qtd;
|
||||
size_t flags;
|
||||
|
||||
for (uint32_t i = 0; i < CONFIG_USB_EHCI_QTD_NUM; i++) {
|
||||
if (!g_ehci_hcd.ehci_qtd_used[i]) {
|
||||
flags = usb_osal_enter_critical_section();
|
||||
g_ehci_hcd.ehci_qtd_used[i] = true;
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
qtd = &ehci_qtd_pool[i];
|
||||
memset(qtd, 0, sizeof(struct ehci_qtd_hw));
|
||||
qtd->hw.next_qtd = QTD_LIST_END;
|
||||
@@ -68,9 +86,15 @@ static struct ehci_qtd_hw *ehci_qtd_alloc(void)
|
||||
|
||||
static void ehci_qtd_free(struct ehci_qtd_hw *qtd)
|
||||
{
|
||||
size_t flags;
|
||||
|
||||
for (uint32_t i = 0; i < CONFIG_USB_EHCI_QTD_NUM; i++) {
|
||||
if (&ehci_qtd_pool[i] == qtd) {
|
||||
flags = usb_osal_enter_critical_section();
|
||||
g_ehci_hcd.ehci_qtd_used[i] = false;
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
qtd->urb = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -149,10 +173,18 @@ static struct ehci_qh_hw *ehci_get_periodic_qhead(uint8_t interval)
|
||||
}
|
||||
|
||||
static void ehci_qh_fill(struct ehci_qh_hw *qh,
|
||||
struct ehci_pipe *pipe)
|
||||
uint8_t dev_addr,
|
||||
uint8_t ep_addr,
|
||||
uint8_t ep_type,
|
||||
uint16_t ep_mps,
|
||||
uint8_t ep_mult,
|
||||
uint8_t ep_interval,
|
||||
uint8_t speed,
|
||||
uint8_t hubaddr,
|
||||
uint8_t hubport)
|
||||
{
|
||||
struct usbh_hub *hub;
|
||||
uint32_t regval;
|
||||
uint32_t epchar = 0;
|
||||
uint32_t epcap = 0;
|
||||
|
||||
/* QH endpoint characteristics:
|
||||
*
|
||||
@@ -167,17 +199,6 @@ static void ehci_qh_fill(struct ehci_qh_hw *qh,
|
||||
* C Control endpoint
|
||||
* RL NAK count reloaded
|
||||
*/
|
||||
regval = ((uint32_t)pipe->dev_addr << QH_EPCHAR_DEVADDR_SHIFT) |
|
||||
((uint32_t)(pipe->ep_addr & 0xf) << QH_EPCHAR_ENDPT_SHIFT) |
|
||||
((uint32_t)g_ehci_speed[pipe->speed] << QH_EPCHAR_EPS_SHIFT) |
|
||||
((uint32_t)pipe->ep_mps << QH_EPCHAR_MAXPKT_SHIFT) |
|
||||
QH_EPCHAR_DTC |
|
||||
((uint32_t)0 << QH_EPCHAR_RL_SHIFT);
|
||||
|
||||
if (pipe->ep_type == USB_ENDPOINT_TYPE_CONTROL && (pipe->speed != USB_SPEED_HIGH)) {
|
||||
regval |= QH_EPCHAR_C;
|
||||
}
|
||||
qh->hw.epchar = regval;
|
||||
|
||||
/* QH endpoint capabilities
|
||||
*
|
||||
@@ -189,26 +210,59 @@ static void ehci_qh_fill(struct ehci_qh_hw *qh,
|
||||
* PORT Port number
|
||||
* MULT High band width multiplier
|
||||
*/
|
||||
regval = 0;
|
||||
|
||||
hub = pipe->hport->parent;
|
||||
epchar |= ((ep_addr & 0xf) << QH_EPCHAR_ENDPT_SHIFT);
|
||||
epchar |= (dev_addr << QH_EPCHAR_DEVADDR_SHIFT);
|
||||
epchar |= (ep_mps << QH_EPCHAR_MAXPKT_SHIFT);
|
||||
|
||||
regval |= QH_EPCAPS_HUBADDR(hub->hub_addr);
|
||||
regval |= QH_EPCAPS_PORT(pipe->hport->port);
|
||||
|
||||
if (pipe->ep_type == USB_ENDPOINT_TYPE_INTERRUPT) {
|
||||
if (pipe->speed == USB_SPEED_HIGH) {
|
||||
regval |= ehci_caculate_smask(pipe->ep_interval);
|
||||
} else {
|
||||
regval |= QH_EPCAPS_SSMASK(2);
|
||||
regval |= QH_EPCAPS_SCMASK(0x78);
|
||||
}
|
||||
regval |= QH_EPCAPS_MULT(1);
|
||||
if (ep_type == USB_ENDPOINT_TYPE_CONTROL) {
|
||||
epchar |= QH_EPCHAR_DTC; /* toggle from qtd */
|
||||
}
|
||||
|
||||
qh->hw.epcap = regval;
|
||||
switch (speed) {
|
||||
case USB_SPEED_LOW:
|
||||
epchar |= QH_EPCHAR_EPS_LOW;
|
||||
case USB_SPEED_FULL:
|
||||
if (ep_type == USB_ENDPOINT_TYPE_CONTROL) {
|
||||
epchar |= QH_EPCHAR_C; /* for TT */
|
||||
}
|
||||
|
||||
qh->pipe = pipe;
|
||||
if (ep_type != USB_ENDPOINT_TYPE_INTERRUPT) {
|
||||
epchar |= (EHCI_TUNE_RL_TT << QH_EPCHAR_RL_SHIFT);
|
||||
}
|
||||
|
||||
epcap |= QH_EPCAPS_MULT(EHCI_TUNE_MULT_TT);
|
||||
|
||||
epcap |= QH_EPCAPS_HUBADDR(hubaddr);
|
||||
epcap |= QH_EPCAPS_PORT(hubport);
|
||||
|
||||
if (ep_type == USB_ENDPOINT_TYPE_INTERRUPT) {
|
||||
epcap |= QH_EPCAPS_SSMASK(2);
|
||||
epcap |= QH_EPCAPS_SCMASK(0x78);
|
||||
}
|
||||
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
epchar |= QH_EPCHAR_EPS_HIGH;
|
||||
if (ep_type == USB_ENDPOINT_TYPE_CONTROL) {
|
||||
epchar |= (EHCI_TUNE_RL_HS << QH_EPCHAR_RL_SHIFT);
|
||||
|
||||
epcap |= QH_EPCAPS_MULT(EHCI_TUNE_MULT_HS);
|
||||
} else if (ep_type == USB_ENDPOINT_TYPE_BULK) {
|
||||
epcap |= QH_EPCAPS_MULT(EHCI_TUNE_MULT_HS);
|
||||
} else {
|
||||
/* only for interrupt ep */
|
||||
epcap |= QH_EPCAPS_MULT(ep_mult);
|
||||
epcap |= ehci_caculate_smask(ep_interval);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
qh->hw.epchar = epchar;
|
||||
qh->hw.epcap = epcap;
|
||||
}
|
||||
|
||||
static void ehci_qtd_bpl_fill(struct ehci_qtd_hw *qtd, uint32_t bufaddr, size_t buflen)
|
||||
@@ -237,7 +291,7 @@ static void ehci_qtd_bpl_fill(struct ehci_qtd_hw *qtd, uint32_t bufaddr, size_t
|
||||
}
|
||||
}
|
||||
|
||||
static void ehci_qtd_fill(struct ehci_pipe *pipe, struct ehci_qtd_hw *qtd, uint32_t bufaddr, size_t buflen, uint32_t token)
|
||||
static void ehci_qtd_fill(struct ehci_qtd_hw *qtd, uint32_t bufaddr, size_t buflen, uint32_t token)
|
||||
{
|
||||
/* qTD token
|
||||
*
|
||||
@@ -255,7 +309,7 @@ static void ehci_qtd_fill(struct ehci_pipe *pipe, struct ehci_qtd_hw *qtd, uint3
|
||||
qtd->hw.token = token;
|
||||
|
||||
ehci_qtd_bpl_fill(qtd, bufaddr, buflen);
|
||||
pipe->xfrd += buflen;
|
||||
qtd->total_len = buflen;
|
||||
}
|
||||
|
||||
static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct usb_setup_packet *setup, uint8_t *buffer, uint32_t buflen)
|
||||
@@ -289,15 +343,25 @@ static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ehci_qh_fill(qh, pipe);
|
||||
ehci_qh_fill(qh,
|
||||
pipe->dev_addr,
|
||||
pipe->ep_addr,
|
||||
pipe->ep_type,
|
||||
pipe->ep_mps,
|
||||
0,
|
||||
pipe->ep_interval,
|
||||
pipe->hport->speed,
|
||||
pipe->hport->parent->hub_addr,
|
||||
pipe->hport->port);
|
||||
|
||||
/* fill setup qtd */
|
||||
token = QTD_TOKEN_STATUS_ACTIVE |
|
||||
QTD_TOKEN_PID_SETUP |
|
||||
((uint32_t)3 << QTD_TOKEN_CERR_SHIFT) |
|
||||
((uint32_t)EHCI_TUNE_CERR << QTD_TOKEN_CERR_SHIFT) |
|
||||
((uint32_t)8 << QTD_TOKEN_NBYTES_SHIFT);
|
||||
|
||||
ehci_qtd_fill(pipe, qtd_setup, EHCI_PTR2ADDR(setup), 8, token);
|
||||
ehci_qtd_fill(qtd_setup, (uintptr_t)setup, 8, token);
|
||||
qtd_setup->urb = pipe->urb;
|
||||
|
||||
/* fill data qtd */
|
||||
if (setup->wLength > 0) {
|
||||
@@ -309,10 +373,11 @@ static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct
|
||||
token |= QTD_TOKEN_STATUS_ACTIVE |
|
||||
QTD_TOKEN_PID_OUT |
|
||||
QTD_TOKEN_TOGGLE |
|
||||
((uint32_t)3 << QTD_TOKEN_CERR_SHIFT) |
|
||||
((uint32_t)EHCI_TUNE_CERR << QTD_TOKEN_CERR_SHIFT) |
|
||||
((uint32_t)buflen << QTD_TOKEN_NBYTES_SHIFT);
|
||||
|
||||
ehci_qtd_fill(pipe, qtd_data, EHCI_PTR2ADDR(buffer), buflen, token);
|
||||
ehci_qtd_fill(qtd_data, (uintptr_t)buffer, buflen, token);
|
||||
qtd_data->urb = pipe->urb;
|
||||
qtd_setup->hw.next_qtd = EHCI_PTR2ADDR(qtd_data);
|
||||
qtd_data->hw.next_qtd = EHCI_PTR2ADDR(qtd_status);
|
||||
} else {
|
||||
@@ -328,13 +393,15 @@ static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct
|
||||
token |= QTD_TOKEN_STATUS_ACTIVE |
|
||||
QTD_TOKEN_TOGGLE |
|
||||
QTD_TOKEN_IOC |
|
||||
((uint32_t)3 << QTD_TOKEN_CERR_SHIFT) |
|
||||
((uint32_t)EHCI_TUNE_CERR << QTD_TOKEN_CERR_SHIFT) |
|
||||
((uint32_t)0 << QTD_TOKEN_NBYTES_SHIFT);
|
||||
|
||||
ehci_qtd_fill(pipe, qtd_status, 0, 0, token);
|
||||
ehci_qtd_fill(qtd_status, 0, 0, token);
|
||||
qtd_status->urb = pipe->urb;
|
||||
qtd_status->hw.next_qtd = QTD_LIST_END;
|
||||
|
||||
/* update qh first qtd */
|
||||
qh->hw.curr_qtd = EHCI_PTR2ADDR(qtd_setup);
|
||||
qh->hw.overlay.next_qtd = EHCI_PTR2ADDR(qtd_setup);
|
||||
|
||||
/* record qh first qtd */
|
||||
@@ -342,10 +409,12 @@ static struct ehci_qh_hw *ehci_control_pipe_init(struct ehci_pipe *pipe, struct
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
|
||||
pipe->qh = qh;
|
||||
qh->urb = pipe->urb;
|
||||
/* add qh into async list */
|
||||
ehci_qh_add_head(&g_async_qh_head, qh);
|
||||
|
||||
EHCI_HCOR->usbcmd |= EHCI_USBCMD_ASEN;
|
||||
|
||||
usb_osal_leave_critical_section(flags);
|
||||
return qh;
|
||||
}
|
||||
@@ -377,7 +446,16 @@ static struct ehci_qh_hw *ehci_bulk_pipe_init(struct ehci_pipe *pipe, uint8_t *b
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ehci_qh_fill(qh, pipe);
|
||||
ehci_qh_fill(qh,
|
||||
pipe->dev_addr,
|
||||
pipe->ep_addr,
|
||||
pipe->ep_type,
|
||||
pipe->ep_mps,
|
||||
0,
|
||||
pipe->ep_interval,
|
||||
pipe->hport->speed,
|
||||
pipe->hport->parent->hub_addr,
|
||||
pipe->hport->port);
|
||||
|
||||
while (buflen >= 0) {
|
||||
qtd = ehci_qtd_alloc();
|
||||
@@ -390,28 +468,22 @@ static struct ehci_qh_hw *ehci_bulk_pipe_init(struct ehci_pipe *pipe, uint8_t *b
|
||||
buflen = 0;
|
||||
}
|
||||
|
||||
/* fill qtd */
|
||||
if (pipe->toggle) {
|
||||
token = QTD_TOKEN_TOGGLE;
|
||||
} else {
|
||||
token = 0;
|
||||
}
|
||||
|
||||
if (pipe->ep_addr & 0x80) {
|
||||
token |= QTD_TOKEN_PID_IN;
|
||||
token = QTD_TOKEN_PID_IN;
|
||||
} else {
|
||||
token |= QTD_TOKEN_PID_OUT;
|
||||
token = QTD_TOKEN_PID_OUT;
|
||||
}
|
||||
|
||||
token |= QTD_TOKEN_STATUS_ACTIVE |
|
||||
((uint32_t)3 << QTD_TOKEN_CERR_SHIFT) |
|
||||
((uint32_t)EHCI_TUNE_CERR << QTD_TOKEN_CERR_SHIFT) |
|
||||
((uint32_t)xfer_len << QTD_TOKEN_NBYTES_SHIFT);
|
||||
|
||||
if (buflen == 0) {
|
||||
token |= QTD_TOKEN_IOC;
|
||||
}
|
||||
|
||||
ehci_qtd_fill(pipe, qtd, (uint32_t)buffer, xfer_len, token);
|
||||
ehci_qtd_fill(qtd, (uintptr_t)buffer, xfer_len, token);
|
||||
qtd->urb = pipe->urb;
|
||||
qtd->hw.next_qtd = QTD_LIST_END;
|
||||
buffer += xfer_len;
|
||||
|
||||
@@ -428,17 +500,27 @@ static struct ehci_qh_hw *ehci_bulk_pipe_init(struct ehci_pipe *pipe, uint8_t *b
|
||||
}
|
||||
|
||||
/* update qh first qtd */
|
||||
qh->hw.curr_qtd = EHCI_PTR2ADDR(first_qtd);
|
||||
qh->hw.overlay.next_qtd = EHCI_PTR2ADDR(first_qtd);
|
||||
|
||||
/* update data toggle */
|
||||
if (pipe->toggle) {
|
||||
qh->hw.overlay.token = QTD_TOKEN_TOGGLE;
|
||||
} else {
|
||||
qh->hw.overlay.token = 0;
|
||||
}
|
||||
|
||||
/* record qh first qtd */
|
||||
qh->first_qtd = EHCI_PTR2ADDR(first_qtd);
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
|
||||
pipe->qh = qh;
|
||||
qh->urb = pipe->urb;
|
||||
/* add qh into async list */
|
||||
ehci_qh_add_head(&g_async_qh_head, qh);
|
||||
|
||||
EHCI_HCOR->usbcmd |= EHCI_USBCMD_ASEN;
|
||||
|
||||
usb_osal_leave_critical_section(flags);
|
||||
return qh;
|
||||
}
|
||||
@@ -470,7 +552,16 @@ static struct ehci_qh_hw *ehci_intr_pipe_init(struct ehci_pipe *pipe, uint8_t *b
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ehci_qh_fill(qh, pipe);
|
||||
ehci_qh_fill(qh,
|
||||
pipe->dev_addr,
|
||||
pipe->ep_addr,
|
||||
pipe->ep_type,
|
||||
pipe->ep_mps,
|
||||
pipe->mult + 1,
|
||||
pipe->ep_interval,
|
||||
pipe->hport->speed,
|
||||
pipe->hport->parent->hub_addr,
|
||||
pipe->hport->port);
|
||||
|
||||
while (buflen >= 0) {
|
||||
qtd = ehci_qtd_alloc();
|
||||
@@ -483,28 +574,22 @@ static struct ehci_qh_hw *ehci_intr_pipe_init(struct ehci_pipe *pipe, uint8_t *b
|
||||
buflen = 0;
|
||||
}
|
||||
|
||||
/* fill qtd */
|
||||
if (pipe->toggle) {
|
||||
token = QTD_TOKEN_TOGGLE;
|
||||
} else {
|
||||
token = 0;
|
||||
}
|
||||
|
||||
if (pipe->ep_addr & 0x80) {
|
||||
token |= QTD_TOKEN_PID_IN;
|
||||
token = QTD_TOKEN_PID_IN;
|
||||
} else {
|
||||
token |= QTD_TOKEN_PID_OUT;
|
||||
token = QTD_TOKEN_PID_OUT;
|
||||
}
|
||||
|
||||
token |= QTD_TOKEN_STATUS_ACTIVE |
|
||||
((uint32_t)3 << QTD_TOKEN_CERR_SHIFT) |
|
||||
((uint32_t)EHCI_TUNE_CERR << QTD_TOKEN_CERR_SHIFT) |
|
||||
((uint32_t)xfer_len << QTD_TOKEN_NBYTES_SHIFT);
|
||||
|
||||
if (buflen == 0) {
|
||||
token |= QTD_TOKEN_IOC;
|
||||
}
|
||||
|
||||
ehci_qtd_fill(pipe, qtd, (uint32_t)buffer, xfer_len, token);
|
||||
ehci_qtd_fill(qtd, (uintptr_t)buffer, xfer_len, token);
|
||||
qtd->urb = pipe->urb;
|
||||
qtd->hw.next_qtd = QTD_LIST_END;
|
||||
buffer += xfer_len;
|
||||
|
||||
@@ -521,20 +606,31 @@ static struct ehci_qh_hw *ehci_intr_pipe_init(struct ehci_pipe *pipe, uint8_t *b
|
||||
}
|
||||
|
||||
/* update qh first qtd */
|
||||
qh->hw.curr_qtd = EHCI_PTR2ADDR(first_qtd);
|
||||
qh->hw.overlay.next_qtd = EHCI_PTR2ADDR(first_qtd);
|
||||
|
||||
/* update data toggle */
|
||||
if (pipe->toggle) {
|
||||
qh->hw.overlay.token = QTD_TOKEN_TOGGLE;
|
||||
} else {
|
||||
qh->hw.overlay.token = 0;
|
||||
}
|
||||
|
||||
/* record qh first qtd */
|
||||
qh->first_qtd = EHCI_PTR2ADDR(first_qtd);
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
|
||||
pipe->qh = qh;
|
||||
qh->urb = pipe->urb;
|
||||
/* add qh into periodic list */
|
||||
if (pipe->speed == USB_SPEED_HIGH) {
|
||||
ehci_qh_add_head(ehci_get_periodic_qhead(pipe->ep_interval), qh);
|
||||
} else {
|
||||
ehci_qh_add_head(ehci_get_periodic_qhead(pipe->ep_interval * 8), qh);
|
||||
}
|
||||
|
||||
EHCI_HCOR->usbcmd |= EHCI_USBCMD_PSEN;
|
||||
|
||||
usb_osal_leave_critical_section(flags);
|
||||
return qh;
|
||||
}
|
||||
@@ -560,92 +656,105 @@ void ehci_pipe_waitup(struct ehci_pipe *pipe)
|
||||
}
|
||||
}
|
||||
|
||||
static void ehci_qh_scan_qtds(struct ehci_qh_hw *qh, struct ehci_pipe *pipe)
|
||||
static void ehci_qh_scan_qtds(struct ehci_qh_hw *qhead, struct ehci_qh_hw *qh)
|
||||
{
|
||||
struct ehci_qtd_hw *qtd;
|
||||
struct ehci_qtd_hw *next;
|
||||
|
||||
if ((qh->first_qtd & QTD_LIST_END) == 0) {
|
||||
qtd = (struct ehci_qtd_hw *)qh->first_qtd;
|
||||
while (qtd) {
|
||||
if (qtd->hw.next_qtd & QTD_LIST_END) {
|
||||
next = NULL;
|
||||
} else {
|
||||
next = (struct ehci_qtd_hw *)qtd->hw.next_qtd;
|
||||
}
|
||||
ehci_qh_remove(qhead, qh);
|
||||
|
||||
qh->first_qtd = qtd->hw.next_qtd;
|
||||
qtd = EHCI_ADDR2QTD(qh->first_qtd);
|
||||
|
||||
if (pipe) {
|
||||
pipe->xfrd -= (qtd->hw.token & QTD_TOKEN_NBYTES_MASK) >>
|
||||
QTD_TOKEN_NBYTES_SHIFT;
|
||||
}
|
||||
while (qtd) {
|
||||
qtd->urb->actual_length += (qtd->total_len - ((qtd->hw.token & QTD_TOKEN_NBYTES_MASK) >> QTD_TOKEN_NBYTES_SHIFT));
|
||||
|
||||
ehci_qtd_free(qtd);
|
||||
|
||||
qtd = next;
|
||||
}
|
||||
ehci_qtd_free(qtd);
|
||||
qh->first_qtd = qtd->hw.next_qtd;
|
||||
qtd = EHCI_ADDR2QTD(qh->first_qtd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ehci_check_qh(struct ehci_qh_hw *qhead, struct ehci_qh_hw *qh, struct ehci_pipe *pipe)
|
||||
static void ehci_check_qh(struct ehci_qh_hw *qhead, struct ehci_qh_hw *qh)
|
||||
{
|
||||
struct usbh_urb *urb;
|
||||
struct ehci_pipe *pipe;
|
||||
struct ehci_qtd_hw *qtd;
|
||||
uint32_t token;
|
||||
|
||||
token = qh->hw.overlay.token;
|
||||
|
||||
if (token & QTD_TOKEN_STATUS_ACTIVE) {
|
||||
} else {
|
||||
urb = pipe->urb;
|
||||
/* Check if token is only in active status without errors */
|
||||
if ((token & (QTD_TOKEN_STATUS_ERRORS | QTD_TOKEN_STATUS_ACTIVE)) == QTD_TOKEN_STATUS_ACTIVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
ehci_qh_scan_qtds(qh, pipe);
|
||||
if (qh->first_qtd & QTD_LIST_END) {
|
||||
/* remove qh from list */
|
||||
ehci_qh_remove(qhead, qh);
|
||||
urb = qh->urb;
|
||||
pipe = urb->pipe;
|
||||
|
||||
if ((token & QTD_TOKEN_STATUS_ERRORS) == 0) {
|
||||
if (token & QTD_TOKEN_TOGGLE) {
|
||||
pipe->toggle = true;
|
||||
} else {
|
||||
pipe->toggle = false;
|
||||
}
|
||||
urb->errorcode = 0;
|
||||
} else {
|
||||
if (token & QTD_TOKEN_STATUS_BABBLE) {
|
||||
urb->errorcode = -EPERM;
|
||||
pipe->toggle = 0;
|
||||
} else if (token & QTD_TOKEN_STATUS_HALTED) {
|
||||
urb->errorcode = -EPERM;
|
||||
pipe->toggle = 0;
|
||||
} else if (token & (QTD_TOKEN_STATUS_DBERR | QTD_TOKEN_STATUS_XACTERR)) {
|
||||
urb->errorcode = -EIO;
|
||||
}
|
||||
}
|
||||
if ((token & QTD_TOKEN_STATUS_ERRORS) == 0) {
|
||||
qtd = EHCI_ADDR2QTD(qh->first_qtd);
|
||||
|
||||
urb->actual_length = pipe->xfrd;
|
||||
ehci_qh_free(qh);
|
||||
pipe->qh = NULL;
|
||||
while (qtd) {
|
||||
if (qtd->hw.token & QTD_TOKEN_STATUS_ACTIVE) {
|
||||
return;
|
||||
}
|
||||
qtd = EHCI_ADDR2QTD(qtd->hw.next_qtd);
|
||||
}
|
||||
|
||||
ehci_pipe_waitup(pipe);
|
||||
if (token & QTD_TOKEN_TOGGLE) {
|
||||
pipe->toggle = true;
|
||||
} else {
|
||||
pipe->toggle = false;
|
||||
}
|
||||
urb->errorcode = 0;
|
||||
} else {
|
||||
if (token & QTD_TOKEN_STATUS_BABBLE) {
|
||||
urb->errorcode = -EPERM;
|
||||
pipe->toggle = 0;
|
||||
} else if (token & QTD_TOKEN_STATUS_HALTED) {
|
||||
urb->errorcode = -EPERM;
|
||||
pipe->toggle = 0;
|
||||
} else if (token & (QTD_TOKEN_STATUS_DBERR | QTD_TOKEN_STATUS_XACTERR)) {
|
||||
urb->errorcode = -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
ehci_qh_scan_qtds(qhead, qh);
|
||||
|
||||
if (pipe->ep_type == USB_ENDPOINT_TYPE_INTERRUPT) {
|
||||
qh->remove_in_iaad = 0;
|
||||
ehci_qh_free(qh);
|
||||
ehci_pipe_waitup(pipe);
|
||||
} else {
|
||||
qh->remove_in_iaad = 1;
|
||||
|
||||
EHCI_HCOR->usbcmd |= EHCI_USBCMD_IAAD;
|
||||
}
|
||||
}
|
||||
|
||||
static void ehci_kill_qh(struct ehci_qh_hw *qhead, struct ehci_qh_hw *qh)
|
||||
{
|
||||
struct ehci_qtd_hw *qtd;
|
||||
|
||||
ehci_qh_remove(qhead, qh);
|
||||
ehci_qh_scan_qtds(qh, NULL);
|
||||
|
||||
qtd = EHCI_ADDR2QTD(qh->first_qtd);
|
||||
|
||||
while (qtd) {
|
||||
ehci_qtd_free(qtd);
|
||||
qh->first_qtd = qtd->hw.next_qtd;
|
||||
qtd = EHCI_ADDR2QTD(qh->first_qtd);
|
||||
}
|
||||
|
||||
ehci_qh_free(qh);
|
||||
}
|
||||
|
||||
static int usbh_reset_port(const uint8_t port)
|
||||
{
|
||||
uint32_t timeout = 0;
|
||||
volatile uint32_t timeout = 0;
|
||||
uint32_t regval;
|
||||
|
||||
#if defined(CONFIG_USB_EHCI_HPMICRO) && CONFIG_USB_EHCI_HPMICRO
|
||||
if ((*(volatile uint32_t *)(CONFIG_HPM_USB_BASE + 0x224) & 0xc0) == (2 << 6)) { /* Hardcode for hpm */
|
||||
if ((*(volatile uint32_t *)(CONFIG_HPM_USBH_BASE + 0x224) & 0xc0) == (2 << 6)) { /* Hardcode for hpm */
|
||||
EHCI_HCOR->portsc[port - 1] |= (1 << 29);
|
||||
} else {
|
||||
EHCI_HCOR->portsc[port - 1] &= ~(1 << 29);
|
||||
@@ -682,7 +791,7 @@ int usb_hc_init(void)
|
||||
uint32_t interval;
|
||||
struct ehci_qh_hw *qh;
|
||||
|
||||
uint32_t timeout = 0;
|
||||
volatile uint32_t timeout = 0;
|
||||
uint32_t regval;
|
||||
|
||||
memset(&g_ehci_hcd, 0, sizeof(struct ehci_hcd));
|
||||
@@ -1023,9 +1132,9 @@ int usbh_pipe_alloc(usbh_pipe_t *pipe, const struct usbh_endpoint_cfg *ep_cfg)
|
||||
int usbh_pipe_free(usbh_pipe_t pipe)
|
||||
{
|
||||
struct usbh_urb *urb;
|
||||
size_t flags;
|
||||
struct ehci_pipe *ppipe;
|
||||
|
||||
struct ehci_pipe *ppipe = (struct ehci_pipe *)pipe;
|
||||
ppipe = (struct ehci_pipe *)pipe;
|
||||
|
||||
if (!ppipe) {
|
||||
return -EINVAL;
|
||||
@@ -1037,9 +1146,7 @@ int usbh_pipe_free(usbh_pipe_t pipe)
|
||||
usbh_kill_urb(urb);
|
||||
}
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
ehci_pipe_free(ppipe);
|
||||
usb_osal_leave_critical_section(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1050,17 +1157,13 @@ int usbh_submit_urb(struct usbh_urb *urb)
|
||||
size_t flags;
|
||||
int ret = 0;
|
||||
|
||||
if (!urb) {
|
||||
if (!urb || !urb->pipe) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pipe = urb->pipe;
|
||||
|
||||
if (!pipe) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pipe->hport->connected) {
|
||||
if (!pipe->inuse /*|| !(EHCI_HCOR->portsc[pipe->hport->port-1] & EHCI_PORTSC_CCS)*/ || !pipe->hport->connected) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -1072,7 +1175,6 @@ int usbh_submit_urb(struct usbh_urb *urb)
|
||||
|
||||
pipe->waiter = false;
|
||||
pipe->xfrd = 0;
|
||||
pipe->qh = NULL;
|
||||
pipe->urb = urb;
|
||||
urb->errorcode = -EBUSY;
|
||||
urb->actual_length = 0;
|
||||
@@ -1081,6 +1183,7 @@ int usbh_submit_urb(struct usbh_urb *urb)
|
||||
pipe->waiter = true;
|
||||
}
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
switch (pipe->ep_type) {
|
||||
case USB_ENDPOINT_TYPE_CONTROL:
|
||||
qh = ehci_control_pipe_init(pipe, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
|
||||
@@ -1149,7 +1252,7 @@ int usbh_kill_urb(struct usbh_urb *urb)
|
||||
if ((pipe->ep_type == USB_ENDPOINT_TYPE_CONTROL) || (pipe->ep_type == USB_ENDPOINT_TYPE_BULK)) {
|
||||
qh = EHCI_ADDR2QH(g_async_qh_head.hw.hlp);
|
||||
while ((qh != &g_async_qh_head) && qh) {
|
||||
if (qh == pipe->qh) {
|
||||
if (qh->urb == urb) {
|
||||
ehci_kill_qh(&g_async_qh_head, qh);
|
||||
}
|
||||
qh = EHCI_ADDR2QH(qh->hw.hlp);
|
||||
@@ -1157,7 +1260,7 @@ int usbh_kill_urb(struct usbh_urb *urb)
|
||||
} else if (pipe->ep_type == USB_ENDPOINT_TYPE_INTERRUPT) {
|
||||
qh = EHCI_ADDR2QH(g_periodic_qh_head[EHCI_PERIOIDIC_QH_NUM - 1].hw.hlp);
|
||||
while (qh) {
|
||||
if (qh == pipe->qh) {
|
||||
if (qh->urb == urb) {
|
||||
if (pipe->speed == USB_SPEED_HIGH) {
|
||||
ehci_kill_qh(ehci_get_periodic_qhead(pipe->ep_interval), qh);
|
||||
} else {
|
||||
@@ -1174,7 +1277,6 @@ int usbh_kill_urb(struct usbh_urb *urb)
|
||||
|
||||
EHCI_HCOR->usbcmd |= (EHCI_USBCMD_PSEN | EHCI_USBCMD_ASEN);
|
||||
|
||||
pipe->qh = NULL;
|
||||
pipe->urb = NULL;
|
||||
|
||||
if (pipe->waiter) {
|
||||
@@ -1191,13 +1293,11 @@ int usbh_kill_urb(struct usbh_urb *urb)
|
||||
static void ehci_scan_async_list(void)
|
||||
{
|
||||
struct ehci_qh_hw *qh;
|
||||
struct ehci_pipe *pipe;
|
||||
|
||||
qh = EHCI_ADDR2QH(g_async_qh_head.hw.hlp);
|
||||
while ((qh != &g_async_qh_head) && qh) {
|
||||
pipe = qh->pipe;
|
||||
if (pipe) {
|
||||
ehci_check_qh(&g_async_qh_head, qh, pipe);
|
||||
if (qh->urb) {
|
||||
ehci_check_qh(&g_async_qh_head, qh);
|
||||
}
|
||||
qh = EHCI_ADDR2QH(qh->hw.hlp);
|
||||
}
|
||||
@@ -1210,12 +1310,12 @@ static void ehci_scan_periodic_list(void)
|
||||
|
||||
qh = EHCI_ADDR2QH(g_periodic_qh_head[EHCI_PERIOIDIC_QH_NUM - 1].hw.hlp);
|
||||
while (qh) {
|
||||
pipe = qh->pipe;
|
||||
if (pipe) {
|
||||
if (qh->urb && qh->urb->pipe) {
|
||||
pipe = (struct ehci_pipe *)qh->urb->pipe;
|
||||
if (pipe->speed == USB_SPEED_HIGH) {
|
||||
ehci_check_qh(ehci_get_periodic_qhead(pipe->ep_interval), qh, pipe);
|
||||
ehci_check_qh(ehci_get_periodic_qhead(pipe->ep_interval), qh);
|
||||
} else {
|
||||
ehci_check_qh(ehci_get_periodic_qhead(pipe->ep_interval * 8), qh, pipe);
|
||||
ehci_check_qh(ehci_get_periodic_qhead(pipe->ep_interval * 8), qh);
|
||||
}
|
||||
}
|
||||
qh = EHCI_ADDR2QH(qh->hw.hlp);
|
||||
@@ -1262,12 +1362,28 @@ void USBH_IRQHandler(void)
|
||||
g_ehci_hcd.ehci_itd_used[index] = false;
|
||||
}
|
||||
}
|
||||
|
||||
usbh_roothub_thread_wakeup(port + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (usbsts & EHCI_USBSTS_IAA) {
|
||||
for (uint8_t index = 0; index < CONFIG_USB_EHCI_QH_NUM; index++) {
|
||||
struct ehci_qh_hw *qh = &ehci_qh_pool[index];
|
||||
if (g_ehci_hcd.ehci_qh_used[index] && qh->remove_in_iaad) {
|
||||
struct usbh_urb *urb;
|
||||
struct ehci_pipe *pipe;
|
||||
|
||||
urb = qh->urb;
|
||||
pipe = urb->pipe;
|
||||
|
||||
qh->remove_in_iaad = 0;
|
||||
ehci_qh_free(qh);
|
||||
|
||||
ehci_pipe_waitup(pipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (usbsts & EHCI_USBSTS_FATAL) {
|
||||
|
||||
@@ -302,7 +302,7 @@ struct ehci_hcor {
|
||||
uint32_t ctrldssegment; /* 0x10: 4G Segment Selector */
|
||||
uint32_t periodiclistbase; /* 0x14: Frame List Base Address */
|
||||
uint32_t asynclistaddr; /* 0x18: Next Asynchronous List Address */
|
||||
#ifndef CONFIG_USB_ECHI_HCOR_RESERVED_DISABLE
|
||||
#ifndef CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
|
||||
uint32_t reserved[9];
|
||||
#endif
|
||||
uint32_t configflag; /* 0x40: Configured Flag Register */
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#define USB_NUM_BIDIR_ENDPOINTS USB_SOC_DCD_MAX_ENDPOINT_COUNT
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_HPM_USBD_BASE) || !defined(CONFIG_HPM_USBD_IRQn)
|
||||
#error "hpm dcd must config CONFIG_HPM_USBD_BASE and CONFIG_HPM_USBD_IRQn"
|
||||
#endif
|
||||
|
||||
/* USBSTS, USBINTR */
|
||||
enum {
|
||||
intr_usb = HPM_BITSMASK(1, 0),
|
||||
@@ -62,7 +66,7 @@ int usb_dc_init(void)
|
||||
|
||||
memset(&g_hpm_udc, 0, sizeof(struct hpm_udc));
|
||||
g_hpm_udc.handle = &usb_device_handle[0];
|
||||
g_hpm_udc.handle->regs = (USB_Type *)HPM_USB0_BASE;
|
||||
g_hpm_udc.handle->regs = (USB_Type *)CONFIG_HPM_USBD_BASE;
|
||||
g_hpm_udc.handle->dcd_data = &_dcd_data;
|
||||
|
||||
uint32_t int_mask;
|
||||
@@ -71,7 +75,7 @@ int usb_dc_init(void)
|
||||
|
||||
usb_device_init(g_hpm_udc.handle, int_mask);
|
||||
|
||||
intc_m_enable_irq(IRQn_USB0);
|
||||
intc_m_enable_irq(CONFIG_HPM_USBD_IRQn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -279,8 +283,8 @@ void USBD_IRQHandler(void)
|
||||
}
|
||||
}
|
||||
|
||||
void isr_usb0(void)
|
||||
void isr_usb(void)
|
||||
{
|
||||
USBD_IRQHandler();
|
||||
}
|
||||
SDK_DECLARE_EXT_ISR_M(IRQn_USB0, isr_usb0)
|
||||
SDK_DECLARE_EXT_ISR_M(CONFIG_HPM_USBD_IRQn, isr_usb)
|
||||
|
||||
14
port/nuvoton/README.md
Normal file
14
port/nuvoton/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Note
|
||||
|
||||
## Support Chip List
|
||||
|
||||
- M032 Series
|
||||
- M480 Series
|
||||
|
||||
## Before Use
|
||||
|
||||
Configure USBD_EPNUM.
|
||||
Your should implement `usb_dc_low_level_init` and `usb_dc_low_level_deinit`.
|
||||
- Enable or disable USB clock and set USB clock for 48M.
|
||||
- Enable or disable gpio and gpio clk for usb dp and dm.
|
||||
- Enable or disable usb irq
|
||||
454
port/nuvoton/usb_dc_usbfs.c
Normal file
454
port/nuvoton/usb_dc_usbfs.c
Normal file
@@ -0,0 +1,454 @@
|
||||
#include <stdint.h>
|
||||
#include "NuMicro.h"
|
||||
#include "usbd_core.h"
|
||||
|
||||
#ifndef USBD_IRQHandler
|
||||
#define USBD_IRQHandler USBD_IRQHandler
|
||||
#endif
|
||||
|
||||
#ifndef USBD_EPNUM
|
||||
#define USBD_EPNUM 8
|
||||
#endif
|
||||
#define USB_NUM_BIDIR_ENDPOINTS (USBD_EPNUM >> 1)
|
||||
|
||||
#define USBD_EP_GET_CONFIG(ep) (*((__IO uint32_t *)((uint32_t)&USBD->EP[0].CFG + (uint32_t)((ep) << 4))))
|
||||
|
||||
/* Define EP maximum packet size */
|
||||
#define DEFAULT_EP_MAX_PKT_SIZE 64
|
||||
|
||||
#define EP0_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
|
||||
#define EP1_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
|
||||
#define EP2_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
|
||||
#define EP3_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
|
||||
#define EP4_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
|
||||
#define EP5_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
|
||||
#define EP6_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
|
||||
#define EP7_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
|
||||
#define EP8_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
|
||||
#define EP9_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
|
||||
#define EP10_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
|
||||
#define EP11_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
|
||||
|
||||
#define SETUP_BUF_BASE 0
|
||||
#define SETUP_BUF_LEN 8
|
||||
#define EP0_BUF_BASE (SETUP_BUF_BASE + SETUP_BUF_LEN)
|
||||
#define EP0_BUF_LEN EP0_MAX_PKT_SIZE
|
||||
#define EP1_BUF_BASE (SETUP_BUF_BASE + SETUP_BUF_LEN)
|
||||
#define EP1_BUF_LEN EP1_MAX_PKT_SIZE
|
||||
#define EP2_BUF_BASE (EP1_BUF_BASE + EP1_BUF_LEN)
|
||||
#define EP2_BUF_LEN EP2_MAX_PKT_SIZE
|
||||
#define EP3_BUF_BASE (EP2_BUF_BASE + EP2_BUF_LEN)
|
||||
#define EP3_BUF_LEN EP3_MAX_PKT_SIZE
|
||||
#define EP4_BUF_BASE (EP3_BUF_BASE + EP3_BUF_LEN)
|
||||
#define EP4_BUF_LEN EP4_MAX_PKT_SIZE
|
||||
#define EP5_BUF_BASE (EP4_BUF_BASE + EP4_BUF_LEN)
|
||||
#define EP5_BUF_LEN EP5_MAX_PKT_SIZE
|
||||
#if USBD_EPNUM >= 8
|
||||
#define EP6_BUF_BASE (EP5_BUF_BASE + EP5_BUF_LEN)
|
||||
#define EP6_BUF_LEN EP6_MAX_PKT_SIZE
|
||||
#define EP7_BUF_BASE (EP6_BUF_BASE + EP6_BUF_LEN)
|
||||
#define EP7_BUF_LEN EP7_MAX_PKT_SIZE
|
||||
#if USBD_EPNUM >= 10
|
||||
#define EP8_BUF_BASE (EP7_BUF_BASE + EP7_BUF_LEN)
|
||||
#define EP8_BUF_LEN EP8_MAX_PKT_SIZE
|
||||
#define EP9_BUF_BASE (EP8_BUF_BASE + EP8_BUF_LEN)
|
||||
#define EP9_BUF_LEN EP9_MAX_PKT_SIZE
|
||||
#if USBD_EPNUM >= 12
|
||||
#define EP10_BUF_BASE (EP9_BUF_BASE + EP9_BUF_LEN)
|
||||
#define EP10_BUF_LEN EP10_MAX_PKT_SIZE
|
||||
#define EP11_BUF_BASE (EP10_BUF_BASE + EP10_BUF_LEN)
|
||||
#define EP11_BUF_LEN EP11_MAX_PKT_SIZE
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define USBD_EPNUM_FROM_IN_EPIDX(ep_idx) ((ep_idx) << 1)
|
||||
#define USBD_EPNUM_FROM_OUT_EPIDX(ep_idx) (((ep_idx) << 1) + 1)
|
||||
#define USBD_EPNUM_FROM_EPADDR(ep_addr) \
|
||||
(USB_EP_DIR_IS_IN(ep_addr) ? USBD_EPNUM_FROM_IN_EPIDX(USB_EP_GET_IDX(ep_addr)) : USBD_EPNUM_FROM_OUT_EPIDX(USB_EP_GET_IDX(ep_addr)))
|
||||
|
||||
/* Endpoint state */
|
||||
struct usb_dc_ep_state {
|
||||
uint16_t ep_mps; /* Endpoint max packet size */
|
||||
uint8_t ep_type; /* Endpoint type */
|
||||
uint8_t ep_stalled; /* Endpoint stall flag */
|
||||
uint8_t ep_enable; /* Endpoint enable */
|
||||
uint8_t *xfer_buf;
|
||||
uint32_t xfer_len;
|
||||
uint32_t actual_xfer_len;
|
||||
uint32_t mps_xfer_len;
|
||||
};
|
||||
|
||||
/* Driver state */
|
||||
struct usb_dc_config_priv {
|
||||
volatile uint8_t dev_addr;
|
||||
struct usb_dc_ep_state in_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< IN endpoint parameters*/
|
||||
struct usb_dc_ep_state out_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< OUT endpoint parameters */
|
||||
} g_nuvoton_udc;
|
||||
|
||||
static uint8_t usdb_set_address_flag = 0;
|
||||
static uint8_t usbd_out_toggle[USB_NUM_BIDIR_ENDPOINTS] = { 0 };
|
||||
|
||||
__WEAK void usb_dc_low_level_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void usb_dc_low_level_deinit(void)
|
||||
{
|
||||
}
|
||||
|
||||
int usb_dc_init(void)
|
||||
{
|
||||
memset(&g_nuvoton_udc, 0, sizeof(g_nuvoton_udc));
|
||||
|
||||
usb_dc_low_level_init();
|
||||
|
||||
/*****************************************************/
|
||||
/* Initial USB engine */
|
||||
USBD->ATTR = 0x6D0ul;
|
||||
/* Force SE0 */
|
||||
USBD_SET_SE0();
|
||||
|
||||
/*****************************************************/
|
||||
/* Init setup packet buffer */
|
||||
/* Buffer for setup packet -> [0 ~ 0x7] */
|
||||
USBD->STBUFSEG = SETUP_BUF_BASE;
|
||||
|
||||
USBD_SET_EP_BUF_ADDR(EP0, EP0_BUF_BASE);
|
||||
USBD_SET_EP_BUF_ADDR(EP1, EP1_BUF_BASE);
|
||||
USBD_SET_EP_BUF_ADDR(EP2, EP2_BUF_BASE);
|
||||
USBD_SET_EP_BUF_ADDR(EP3, EP3_BUF_BASE);
|
||||
USBD_SET_EP_BUF_ADDR(EP4, EP4_BUF_BASE);
|
||||
USBD_SET_EP_BUF_ADDR(EP5, EP5_BUF_BASE);
|
||||
#if USBD_EPNUM >= 8
|
||||
USBD_SET_EP_BUF_ADDR(EP6, EP6_BUF_BASE);
|
||||
USBD_SET_EP_BUF_ADDR(EP7, EP7_BUF_BASE);
|
||||
#if USBD_EPNUM >= 10
|
||||
USBD_SET_EP_BUF_ADDR(EP8, EP8_BUF_BASE);
|
||||
USBD_SET_EP_BUF_ADDR(EP9, EP9_BUF_BASE);
|
||||
USBD_SET_EP_BUF_ADDR(EP10, EP10_BUF_BASE);
|
||||
#if USBD_EPNUM >= 12
|
||||
USBD_SET_EP_BUF_ADDR(EP11, EP11_BUF_BASE);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*****************************************************/
|
||||
/* USB start */
|
||||
/* Disable software-disconnect function */
|
||||
USBD_CLR_SE0();
|
||||
USBD->ATTR = 0x7D0ul;
|
||||
|
||||
/* Clear USB-related interrupts before enable interrupt */
|
||||
USBD_CLR_INT_FLAG(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP);
|
||||
|
||||
/* Enable USB-related interrupts. */
|
||||
USBD_ENABLE_INT(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP);
|
||||
/*****************************************************/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(void)
|
||||
{
|
||||
USBD->ATTR = 0x00000040;
|
||||
/* Force SE0 */
|
||||
USBD_SET_SE0();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_address(const uint8_t addr)
|
||||
{
|
||||
uint8_t usbd_addr = USBD_GET_ADDR();
|
||||
if ((usbd_addr == 0) && (usbd_addr != addr)) {
|
||||
g_nuvoton_udc.dev_addr = addr;
|
||||
usdb_set_address_flag = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t usbd_get_port_speed(const uint8_t port)
|
||||
{
|
||||
return USB_SPEED_FULL;
|
||||
}
|
||||
|
||||
int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep_cfg->ep_addr);
|
||||
|
||||
if (USB_EP_DIR_IS_IN(ep_cfg->ep_addr)) {
|
||||
uint8_t epnum = USBD_EPNUM_FROM_IN_EPIDX(ep_idx);
|
||||
|
||||
g_nuvoton_udc.in_ep[ep_idx].ep_mps = ep_cfg->ep_mps;
|
||||
g_nuvoton_udc.in_ep[ep_idx].ep_type = ep_cfg->ep_type;
|
||||
g_nuvoton_udc.in_ep[ep_idx].ep_enable = true;
|
||||
if (ep_idx == 0) {
|
||||
/* EP0 ==> control IN endpoint, address 0 */
|
||||
USBD_CONFIG_EP(EP0, USBD_CFG_CSTALL | USBD_CFG_EPMODE_IN | 0);
|
||||
} else {
|
||||
USBD_CONFIG_EP(epnum, USBD_CFG_EPMODE_IN | ep_idx);
|
||||
USBD_STOP_TRANSACTION(epnum);
|
||||
}
|
||||
} else {
|
||||
uint8_t epnum = USBD_EPNUM_FROM_OUT_EPIDX(ep_idx);
|
||||
|
||||
g_nuvoton_udc.out_ep[ep_idx].ep_mps = ep_cfg->ep_mps;
|
||||
g_nuvoton_udc.out_ep[ep_idx].ep_type = ep_cfg->ep_type;
|
||||
g_nuvoton_udc.out_ep[ep_idx].ep_enable = true;
|
||||
if (ep_idx == 0) {
|
||||
/* EP1 ==> control OUT endpoint, address 0 */
|
||||
USBD_CONFIG_EP(EP1, USBD_CFG_CSTALL | USBD_CFG_EPMODE_OUT | 0);
|
||||
} else {
|
||||
USBD_CONFIG_EP(epnum, USBD_CFG_EPMODE_OUT | ep_idx);
|
||||
USBD_STOP_TRANSACTION(epnum);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_close(const uint8_t ep)
|
||||
{
|
||||
USBD->EP[USBD_EPNUM_FROM_EPADDR(ep)].CFG &= ~USBD_CFG_STATE_Msk; // disable endpoint
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_set_stall(const uint8_t ep)
|
||||
{
|
||||
USBD_SET_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_clear_stall(const uint8_t ep)
|
||||
{
|
||||
USBD_CLR_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled)
|
||||
{
|
||||
*stalled = USBD_GET_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep)) > 0 ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_write(const uint8_t ep, const uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_nuvoton_udc.in_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint8_t epnum = USBD_EPNUM_FROM_IN_EPIDX(ep);
|
||||
|
||||
g_nuvoton_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_nuvoton_udc.in_ep[ep_idx].xfer_len = data_len;
|
||||
g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
if (data_len > g_nuvoton_udc.in_ep[ep_idx].ep_mps) {
|
||||
data_len = g_nuvoton_udc.in_ep[ep_idx].ep_mps;
|
||||
}
|
||||
|
||||
if (epnum == 0) {
|
||||
USBD_SET_DATA1(epnum);
|
||||
}
|
||||
|
||||
USBD_MemCopy((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(epnum)), (uint8_t *)data, data_len);
|
||||
USBD_SET_PAYLOAD_LEN(epnum, data_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_read(const uint8_t ep, uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
|
||||
if (!data && data_len) {
|
||||
return -1;
|
||||
}
|
||||
if (!g_nuvoton_udc.out_ep[ep_idx].ep_enable) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint8_t epnum = USBD_EPNUM_FROM_OUT_EPIDX(ep);
|
||||
|
||||
g_nuvoton_udc.out_ep[ep_idx].xfer_buf = (uint8_t *)data;
|
||||
g_nuvoton_udc.out_ep[ep_idx].xfer_len = data_len;
|
||||
g_nuvoton_udc.out_ep[ep_idx].actual_xfer_len = 0;
|
||||
|
||||
if (g_nuvoton_udc.out_ep[ep_idx].xfer_len < g_nuvoton_udc.out_ep[ep_idx].ep_mps) {
|
||||
g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].xfer_len;
|
||||
} else {
|
||||
g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].ep_mps;
|
||||
}
|
||||
|
||||
USBD_SET_PAYLOAD_LEN(epnum, g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(void)
|
||||
{
|
||||
uint32_t int_flag = USBD_GET_INT_FLAG();
|
||||
uint32_t bus_state = USBD_GET_BUS_STATE();
|
||||
|
||||
if (int_flag & USBD_INTSTS_FLDET) {
|
||||
// Floating detect
|
||||
USBD_CLR_INT_FLAG(USBD_INTSTS_FLDET);
|
||||
|
||||
if (USBD_IS_ATTACHED()) {
|
||||
/* USB Plug In */
|
||||
USBD_ENABLE_USB();
|
||||
usbd_event_connect_handler();
|
||||
} else {
|
||||
/* USB Un-plug */
|
||||
USBD_DISABLE_USB();
|
||||
usbd_event_disconnect_handler();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
if (int_flag & USBD_INTSTS_BUS) {
|
||||
/* Clear event flag */
|
||||
USBD_CLR_INT_FLAG(USBD_INTSTS_BUS);
|
||||
|
||||
if (bus_state & USBD_STATE_USBRST) {
|
||||
/* Bus reset */
|
||||
USBD_ENABLE_USB();
|
||||
|
||||
memset((usbd_out_toggle + 1), 0, (USB_NUM_BIDIR_ENDPOINTS - 1));
|
||||
|
||||
for (uint8_t i = 0; i < USBD_MAX_EP; i++) {
|
||||
USBD->EP[i].CFG = 0; // default value
|
||||
}
|
||||
|
||||
USBD_SET_ADDR(0ul);
|
||||
g_nuvoton_udc.dev_addr = 0;
|
||||
|
||||
usbd_event_reset_handler();
|
||||
}
|
||||
|
||||
if (bus_state & USBD_STATE_SUSPEND) {
|
||||
/* Enable USB but disable PHY */
|
||||
USBD_DISABLE_PHY();
|
||||
usbd_event_suspend_handler();
|
||||
}
|
||||
if (bus_state & USBD_STATE_RESUME) {
|
||||
/* Enable USB and enable PHY */
|
||||
USBD_ENABLE_USB();
|
||||
usbd_event_resume_handler();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
if (int_flag & USBD_INTSTS_WAKEUP) {
|
||||
/* Clear event flag */
|
||||
USBD_CLR_INT_FLAG(USBD_INTSTS_WAKEUP);
|
||||
}
|
||||
|
||||
if (int_flag & USBD_INTSTS_USB) {
|
||||
// USB event
|
||||
if (int_flag & USBD_INTSTS_SETUP) {
|
||||
// Setup packet
|
||||
/* Clear event flag */
|
||||
USBD_CLR_INT_FLAG(USBD_INTSTS_SETUP);
|
||||
|
||||
/* Clear the data IN/OUT ready flag of control end-points */
|
||||
USBD_STOP_TRANSACTION(EP0);
|
||||
USBD_STOP_TRANSACTION(EP1);
|
||||
|
||||
usbd_out_toggle[0] = 0;
|
||||
usbd_event_ep0_setup_complete_handler((uint8_t *)(USBD_BUF_BASE));
|
||||
}
|
||||
|
||||
if (int_flag & USBD_INTSTS_EP0) {
|
||||
/* In ACK for Set address */
|
||||
if (usdb_set_address_flag == 1) {
|
||||
USBD_SET_ADDR(g_nuvoton_udc.dev_addr);
|
||||
usdb_set_address_flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// if (int_flag & USBD_INTSTS_EP1)
|
||||
// {
|
||||
// }
|
||||
|
||||
for (uint8_t epnum = 0; epnum < USBD_EPNUM; epnum++) {
|
||||
if (int_flag & (USBD_INTSTS_EP0 << epnum)) {
|
||||
USBD_CLR_INT_FLAG((USBD_INTSTS_EP0 << epnum));
|
||||
|
||||
uint8_t ep_cfg = USBD_EP_GET_CONFIG(epnum);
|
||||
|
||||
uint8_t ep_state = 0;
|
||||
#if USBD_EPNUM >= 10
|
||||
if (epnum > 7) {
|
||||
ep_state = (USBD->EPSTS1 >> ((epnum - 8) * 4)) & 0x0f;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ep_state = (USBD->EPSTS0 >> (epnum * 4)) & 0x0f;
|
||||
}
|
||||
|
||||
uint8_t ep_cfg_state = (ep_cfg & USBD_CFG_STATE_Msk) >> USBD_CFG_STATE_Pos;
|
||||
|
||||
if (ep_cfg_state == 0x01) {
|
||||
// OUT
|
||||
uint8_t ep_idx = ep_cfg & USBD_CFG_EPNUM_Msk;
|
||||
|
||||
if (ep_state == usbd_out_toggle[ep_idx]) {
|
||||
USBD_SET_PAYLOAD_LEN(epnum, g_nuvoton_udc.out_ep[ep_idx].ep_mps);
|
||||
} else {
|
||||
uint32_t recv_count = USBD_GET_PAYLOAD_LEN(epnum);
|
||||
|
||||
USBD_MemCopy((uint8_t *)g_nuvoton_udc.out_ep[ep_idx].xfer_buf,
|
||||
(uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(epnum)), recv_count);
|
||||
|
||||
g_nuvoton_udc.out_ep[ep_idx].xfer_buf += recv_count;
|
||||
g_nuvoton_udc.out_ep[ep_idx].xfer_len -= recv_count;
|
||||
g_nuvoton_udc.out_ep[ep_idx].actual_xfer_len += recv_count;
|
||||
|
||||
usbd_out_toggle[ep_idx] = ep_state;
|
||||
|
||||
if ((recv_count < g_nuvoton_udc.out_ep[ep_idx].ep_mps) ||
|
||||
(g_nuvoton_udc.out_ep[ep_idx].xfer_len == 0)) {
|
||||
usbd_event_ep_out_complete_handler(ep_idx, g_nuvoton_udc.out_ep[ep_idx].actual_xfer_len);
|
||||
} else {
|
||||
if (g_nuvoton_udc.out_ep[ep_idx].xfer_len < g_nuvoton_udc.out_ep[ep_idx].ep_mps) {
|
||||
g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].xfer_len;
|
||||
} else {
|
||||
g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].ep_mps;
|
||||
}
|
||||
|
||||
USBD_SET_PAYLOAD_LEN(epnum, g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len);
|
||||
}
|
||||
}
|
||||
} else if (ep_cfg_state == 0x02) {
|
||||
uint8_t ep_idx = ep_cfg & USBD_CFG_EPNUM_Msk;
|
||||
// In Ack
|
||||
|
||||
if (g_nuvoton_udc.in_ep[ep_idx].xfer_len > g_nuvoton_udc.in_ep[ep_idx].ep_mps) {
|
||||
g_nuvoton_udc.in_ep[ep_idx].xfer_buf += g_nuvoton_udc.in_ep[ep_idx].ep_mps;
|
||||
g_nuvoton_udc.in_ep[ep_idx].xfer_len -= g_nuvoton_udc.in_ep[ep_idx].ep_mps;
|
||||
g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len += g_nuvoton_udc.in_ep[ep_idx].ep_mps;
|
||||
|
||||
uint16_t min_len = MIN(g_nuvoton_udc.in_ep[ep_idx].xfer_len, g_nuvoton_udc.in_ep[ep_idx].ep_mps);
|
||||
|
||||
uint8_t *usbd_ep_buf_addr = (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(epnum));
|
||||
USBD_MemCopy(usbd_ep_buf_addr, g_nuvoton_udc.in_ep[ep_idx].xfer_buf, min_len);
|
||||
USBD_SET_PAYLOAD_LEN(epnum, min_len);
|
||||
} else {
|
||||
g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len += g_nuvoton_udc.in_ep[ep_idx].xfer_len;
|
||||
g_nuvoton_udc.in_ep[ep_idx].xfer_len = 0;
|
||||
|
||||
usbd_event_ep_in_complete_handler(ep_idx | 0x80, g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
port/pusb2/README.md
Normal file
7
port/pusb2/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# USB2.0 OTG 控制器 (PUSB2)
|
||||
|
||||
- Phytium PI 和 Phyium E2000 系列开发板提供了兼容 USB2.0 的 OTG 接口
|
||||
- 当前 Port 在 [RT-Thread](https://github.com/RT-Thread/rt-thread/tree/master/bsp/phytium) 上完成测试,具体使用方法参考 RT-Thread Phytium BSP 中的说明
|
||||
- usb_dc_pusb2.c 主要实现 Device 模式,测试过 msc_ram_template.c 和 cdc_acm_template.c 两个 Demo
|
||||
- usb_hc_pusb2.c 主要实现 Host 模式,测试过 usb_host.c,可以连接 USB Disk, HID 设备鼠标和键盘
|
||||
- PUSB2 的驱动代码欢迎联系 `opensource_embedded@phytium.com.cn` 获取
|
||||
474
port/pusb2/usb_dc_pusb2.c
Normal file
474
port/pusb2/usb_dc_pusb2.c
Normal file
@@ -0,0 +1,474 @@
|
||||
/*
|
||||
* Copyright : (C) 2023 Phytium Information Technology, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
|
||||
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
|
||||
* either version 1.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the Phytium Public License for more details.
|
||||
*
|
||||
*
|
||||
* FilePath: usb_dc_pusb2.c
|
||||
* Date: 2021-08-25 14:53:42
|
||||
* LastEditTime: 2021-08-26 09:01:26
|
||||
* Description: This file is for implementation of PUSB2 port to cherryusb for host mode
|
||||
*
|
||||
* Modify History:
|
||||
* Ver Who Date Changes
|
||||
* ----- ------ -------- --------------------------------------
|
||||
* 1.0 zhugengyu 2023/7/19 first commit
|
||||
*/
|
||||
|
||||
#include "usbd_core.h"
|
||||
#include "fpusb2.h"
|
||||
|
||||
/* Endpoint state */
|
||||
struct pusb2_dc_ep_state {
|
||||
uint16_t ep_mps; /* Endpoint max packet size */
|
||||
uint8_t ep_type; /* Endpoint type */
|
||||
uint8_t ep_stalled; /* Endpoint stall flag */
|
||||
const struct usb_endpoint_descriptor *desc;
|
||||
FPUsb2DcEp *priv_ep;
|
||||
};
|
||||
|
||||
/* Data IN/OUT request */
|
||||
struct pusb2_dc_request {
|
||||
struct pusb2_dc_ep_state *ep;
|
||||
FPUsb2DcReq *priv_req;
|
||||
int status;
|
||||
};
|
||||
|
||||
/* Driver state */
|
||||
struct pusb2_udc {
|
||||
FPUsb2 pusb2;
|
||||
int speed;
|
||||
FPUsb2Config config;
|
||||
volatile uint8_t dev_addr;
|
||||
int ep0_init_finish;
|
||||
struct pusb2_dc_ep_state in_ep[FPUSB2_DC_EP_NUM]; /*!< IN endpoint parameters*/
|
||||
struct pusb2_dc_ep_state out_ep[FPUSB2_DC_EP_NUM]; /*!< OUT endpoint parameters */
|
||||
} g_pusb2_udc;
|
||||
|
||||
__WEAK void usb_dc_low_level_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void usb_dc_low_level_deinit(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void pusb2_dc_init_ep_state(struct pusb2_dc_ep_state *ep_state,
|
||||
FPUsb2DcEp *priv_ep)
|
||||
{
|
||||
/* reset ep state and attach priv ep */
|
||||
ep_state->ep_mps = 0U;
|
||||
ep_state->ep_type = 0U;
|
||||
ep_state->ep_stalled = 0U;
|
||||
ep_state->desc = NULL;
|
||||
ep_state->priv_ep = priv_ep;
|
||||
}
|
||||
|
||||
static void pusb2_dc_connect_handler(FPUsb2DcController *instance)
|
||||
{
|
||||
FPUsb2DcDev *dc_dev = NULL;
|
||||
extern void FPUsb2DcNoReset(FPUsb2DcController *instance);
|
||||
|
||||
FPUsb2DcGetDevInstance(&g_pusb2_udc.pusb2.device_ctrl, &dc_dev);
|
||||
USB_ASSERT(dc_dev);
|
||||
|
||||
USB_LOG_DBG("%s \n", __func__);
|
||||
|
||||
usbd_event_reset_handler();
|
||||
|
||||
/* update speed and max packet size when connect */
|
||||
g_pusb2_udc.speed = dc_dev->speed;
|
||||
if (g_pusb2_udc.speed > USB_SPEED_HIGH) {
|
||||
g_pusb2_udc.in_ep[0].ep_mps = 9;
|
||||
g_pusb2_udc.out_ep[0].ep_mps = 9;
|
||||
} else {
|
||||
g_pusb2_udc.in_ep[0].ep_mps = dc_dev->ep0->max_packet;
|
||||
g_pusb2_udc.out_ep[0].ep_mps = dc_dev->ep0->max_packet;
|
||||
}
|
||||
|
||||
FPUsb2DcNoReset(instance);
|
||||
}
|
||||
|
||||
static void pusb2_dc_disconnect_handler(FPUsb2DcController *instance)
|
||||
{
|
||||
USB_LOG_DBG("%s \n", __func__);
|
||||
}
|
||||
|
||||
static void pusb2_dc_resume_handler(FPUsb2DcController *instance)
|
||||
{
|
||||
USB_LOG_DBG("%s \n", __func__);
|
||||
}
|
||||
|
||||
static uint32_t pusb2_dc_receive_steup_handler(FPUsb2DcController *instance, FUsbSetup *setup)
|
||||
{
|
||||
USB_LOG_DBG("%s 0x%x:0x%x:0x%x:0x%x:0x%x\n",
|
||||
__func__,
|
||||
setup->bmRequestType,
|
||||
setup->bRequest,
|
||||
setup->wIndex,
|
||||
setup->wLength,
|
||||
setup->wValue);
|
||||
|
||||
usbd_event_ep0_setup_complete_handler((u8 *)setup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pusb2_dc_suspend_handler(FPUsb2DcController *instance)
|
||||
{
|
||||
USB_LOG_DBG("%s \n", __func__);
|
||||
}
|
||||
|
||||
static void* pusb2_dc_allocate_request_handler(FPUsb2DcController *instance, uint32_t size)
|
||||
{
|
||||
FPUsb2DcReq * cusbd_req = usb_malloc(size);
|
||||
if (!cusbd_req) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(cusbd_req, 0, sizeof(*cusbd_req));
|
||||
|
||||
return cusbd_req;
|
||||
}
|
||||
|
||||
static void pusb2_dc_free_request_handler(FPUsb2DcController *instance, void *usb_request)
|
||||
{
|
||||
if (!usb_request)
|
||||
return;
|
||||
|
||||
usb_free(usb_request);
|
||||
}
|
||||
|
||||
static void pusb2_dc_pre_start_handler(FPUsb2DcController *instance)
|
||||
{
|
||||
FPUsb2DcEp *priv_epx = NULL;
|
||||
FPUsb2DcDev *dc_dev = NULL;
|
||||
FDListHead *list;
|
||||
int ep_num;
|
||||
|
||||
FPUsb2DcGetDevInstance(&g_pusb2_udc.pusb2.device_ctrl, &dc_dev);
|
||||
USB_ASSERT(dc_dev);
|
||||
|
||||
g_pusb2_udc.speed = dc_dev->max_speed;
|
||||
|
||||
pusb2_dc_init_ep_state(&g_pusb2_udc.in_ep[0], dc_dev->ep0);
|
||||
pusb2_dc_init_ep_state(&g_pusb2_udc.out_ep[0], dc_dev->ep0);
|
||||
|
||||
for(list = dc_dev->ep_list.next;
|
||||
list != &dc_dev->ep_list;
|
||||
list = list->next) {
|
||||
priv_epx = (FPUsb2DcEp*)list;
|
||||
ep_num = USB_EP_GET_IDX(priv_epx->address);
|
||||
|
||||
if (USB_EP_DIR_IS_IN(priv_epx->address)) {
|
||||
pusb2_dc_init_ep_state(&g_pusb2_udc.in_ep[ep_num], priv_epx);
|
||||
} else {
|
||||
pusb2_dc_init_ep_state(&g_pusb2_udc.out_ep[ep_num], priv_epx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pusb2_dc_prepare_ctrl_config(FPUsb2Config *config)
|
||||
{
|
||||
*config = *FPUsb2LookupConfig(CONFIG_USBDEV_PUSB2_CTRL_ID);
|
||||
|
||||
config->mode = FPUSB2_MODE_PERIPHERAL;
|
||||
|
||||
/* allocate DMA buffer for TRB transfer */
|
||||
config->trb_mem_addr = usb_align(64U, config->trb_mem_size);
|
||||
USB_ASSERT(config->trb_mem_addr);
|
||||
|
||||
/* hook up device callbacks */
|
||||
config->host_cb.givback_request = NULL;
|
||||
config->host_cb.otg_state_change = NULL;
|
||||
config->host_cb.port_status_change = NULL;
|
||||
config->host_cb.set_ep_toggle = NULL;
|
||||
config->host_cb.get_ep_toggle = NULL;
|
||||
config->host_cb.pre_start = NULL;
|
||||
|
||||
config->device_cb.connect = pusb2_dc_connect_handler;
|
||||
config->device_cb.disconnect= pusb2_dc_disconnect_handler;
|
||||
config->device_cb.resume = pusb2_dc_resume_handler;
|
||||
config->device_cb.setup = pusb2_dc_receive_steup_handler;
|
||||
config->device_cb.suspend = pusb2_dc_suspend_handler;
|
||||
config->device_cb.usb_request_mem_alloc = pusb2_dc_allocate_request_handler;
|
||||
config->device_cb.usb_request_mem_free = pusb2_dc_free_request_handler;
|
||||
config->device_cb.pre_start = pusb2_dc_pre_start_handler;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int usb_dc_init(void)
|
||||
{
|
||||
memset(&g_pusb2_udc, 0, sizeof(struct pusb2_udc));
|
||||
|
||||
usb_dc_low_level_init();
|
||||
|
||||
pusb2_dc_prepare_ctrl_config(&g_pusb2_udc.config);
|
||||
if (FPUSB2_SUCCESS != FPUsb2CfgInitialize(&g_pusb2_udc.pusb2,
|
||||
&g_pusb2_udc.config)) {
|
||||
USB_LOG_ERR("init pusb2 failed \n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
USB_LOG_INFO("init pusb2 successed \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_dc_deinit(void)
|
||||
{
|
||||
usb_dc_low_level_deinit();
|
||||
|
||||
FPUsb2DeInitialize(&g_pusb2_udc.pusb2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_set_address(const uint8_t addr)
|
||||
{
|
||||
g_pusb2_udc.dev_addr = addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_endpoint_descriptor *usbd_get_ep0_desc(const struct usbd_endpoint_cfg *ep_cfg)
|
||||
{
|
||||
static struct usb_endpoint_descriptor ep0_desc;
|
||||
|
||||
/* Config EP0 mps from speed */
|
||||
ep0_desc.bEndpointAddress = ep_cfg->ep_addr;
|
||||
ep0_desc.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT;
|
||||
ep0_desc.bmAttributes = ep_cfg->ep_type;
|
||||
ep0_desc.wMaxPacketSize = ep_cfg->ep_mps;
|
||||
ep0_desc.bInterval = 0;
|
||||
ep0_desc.bLength = 7;
|
||||
|
||||
return &ep0_desc;
|
||||
}
|
||||
|
||||
int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep_cfg->ep_addr);
|
||||
struct pusb2_dc_ep_state *ep_state;
|
||||
uint32_t error;
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep_cfg->ep_addr)) {
|
||||
ep_state = &g_pusb2_udc.out_ep[ep_idx];
|
||||
} else {
|
||||
ep_state = &g_pusb2_udc.in_ep[ep_idx];
|
||||
}
|
||||
|
||||
ep_state->ep_mps = ep_cfg->ep_mps;
|
||||
ep_state->ep_type = ep_cfg->ep_type;
|
||||
ep_state->desc = usbd_get_ep0_desc(ep_cfg);
|
||||
|
||||
USB_ASSERT(ep_state->priv_ep != NULL);
|
||||
USB_LOG_DBG("try to enable ep@0x%x 0x%x:0x%x\n", ep_cfg->ep_addr,
|
||||
ep_state->priv_ep, ep_state->desc );
|
||||
error = FPUsb2DcEpEnable(&g_pusb2_udc.pusb2.device_ctrl,
|
||||
ep_state->priv_ep,
|
||||
(const FUsbEndpointDescriptor *)ep_state->desc);
|
||||
if (FPUSB2_SUCCESS != error){
|
||||
USB_LOG_ERR("enable ep-%d failed, error = 0x%x\n", ep_cfg->ep_addr, error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_pusb2_udc.ep0_init_finish = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_close(const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
struct pusb2_dc_ep_state *ep_state;
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
ep_state = &g_pusb2_udc.out_ep[ep_idx];
|
||||
} else {
|
||||
ep_state = &g_pusb2_udc.in_ep[ep_idx];
|
||||
}
|
||||
|
||||
ep_state->desc = NULL;
|
||||
if (FPUSB2_SUCCESS != FPUsb2DcEpDisable(&g_pusb2_udc.pusb2.device_ctrl,
|
||||
ep_state->priv_ep)){
|
||||
USB_LOG_ERR("disable ep@0x%x failed\n", ep);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_set_stall(const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
struct pusb2_dc_ep_state *ep_state;
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
ep_state = &g_pusb2_udc.out_ep[ep_idx];
|
||||
} else {
|
||||
ep_state = &g_pusb2_udc.in_ep[ep_idx];
|
||||
}
|
||||
|
||||
if (FPUSB2_SUCCESS != FPUsb2DcEpSetHalt(&g_pusb2_udc.pusb2.device_ctrl,
|
||||
ep_state->priv_ep, 1)){
|
||||
USB_LOG_ERR("stall ep@0x%x failed\n", ep);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ep_state->ep_stalled = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_clear_stall(const uint8_t ep)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
struct pusb2_dc_ep_state *ep_state;
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
ep_state = &g_pusb2_udc.out_ep[ep_idx];
|
||||
} else {
|
||||
ep_state = &g_pusb2_udc.in_ep[ep_idx];
|
||||
}
|
||||
|
||||
if (FPUSB2_SUCCESS != FPUsb2DcEpSetHalt(&g_pusb2_udc.pusb2.device_ctrl,
|
||||
ep_state->priv_ep, 0)){
|
||||
USB_LOG_ERR("clear ep@0x%x stall status failed\n", ep);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ep_state->ep_stalled = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
struct pusb2_dc_ep_state *ep_state;
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
ep_state = &g_pusb2_udc.out_ep[ep_idx];
|
||||
} else {
|
||||
ep_state = &g_pusb2_udc.in_ep[ep_idx];
|
||||
}
|
||||
|
||||
if (stalled) {
|
||||
*stalled = ep_state->ep_stalled;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pusb2_dc_request *pusb2_dc_allocate_request(struct pusb2_dc_ep_state *ep_state)
|
||||
{
|
||||
struct pusb2_dc_request *request = usb_malloc(sizeof(*request));
|
||||
if (!request) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(request, 0, sizeof(*request));
|
||||
|
||||
request->ep = ep_state;
|
||||
request->priv_req = NULL;
|
||||
|
||||
if (FPUSB2_SUCCESS != FPUsb2DcReqAlloc(&g_pusb2_udc.pusb2.device_ctrl,
|
||||
ep_state->priv_ep,
|
||||
&request->priv_req )){
|
||||
USB_LOG_ERR("allocate request failed\n");
|
||||
usb_free(request);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
static void pusb2_dc_free_request(struct pusb2_dc_request *request)
|
||||
{
|
||||
USB_ASSERT(request);
|
||||
struct pusb2_dc_ep_state *ep_state = request->ep;
|
||||
FPUsb2DcReqFree(&g_pusb2_udc.pusb2.device_ctrl,
|
||||
ep_state->priv_ep,
|
||||
request->priv_req);
|
||||
|
||||
usb_free(request);
|
||||
}
|
||||
|
||||
void pusb2_dc_callback_complete(FPUsb2DcEp *priv_ep, FPUsb2DcReq *priv_request)
|
||||
{
|
||||
USB_ASSERT(priv_ep && priv_request);
|
||||
struct pusb2_dc_request *request;
|
||||
|
||||
request = priv_request->context;
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(priv_ep->address)) {
|
||||
usbd_event_ep_out_complete_handler(priv_ep->address, priv_request->actual);
|
||||
} else {
|
||||
usbd_event_ep_in_complete_handler(priv_ep->address, priv_request->actual);
|
||||
}
|
||||
|
||||
request->status = priv_request->status;
|
||||
if (request->status != 0) {
|
||||
USB_LOG_ERR("Request failed, status = %d\n", request->status);
|
||||
}
|
||||
|
||||
pusb2_dc_free_request(request);
|
||||
priv_request->context = NULL;
|
||||
}
|
||||
|
||||
int pusb2_dc_ep_read_write(const uint8_t ep, uintptr data, uint32_t data_len)
|
||||
{
|
||||
uint8_t ep_idx = USB_EP_GET_IDX(ep);
|
||||
struct pusb2_dc_ep_state *ep_state;
|
||||
struct pusb2_dc_request *request;
|
||||
uint32_t error;
|
||||
|
||||
if (USB_EP_DIR_IS_OUT(ep)) {
|
||||
ep_state = &g_pusb2_udc.out_ep[ep_idx];
|
||||
} else {
|
||||
ep_state = &g_pusb2_udc.in_ep[ep_idx];
|
||||
}
|
||||
|
||||
request = pusb2_dc_allocate_request(ep_state);
|
||||
if (!request) {
|
||||
USB_LOG_ERR("failed to allocate request !!!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
request->priv_req->dma = data;
|
||||
request->priv_req->buf = (void *)data;
|
||||
request->priv_req->length = data_len;
|
||||
|
||||
request->priv_req->complete = pusb2_dc_callback_complete;
|
||||
request->priv_req->context = request;
|
||||
request->priv_req->status = 0;
|
||||
|
||||
error = FPUsb2DcReqQueue(&g_pusb2_udc.pusb2.device_ctrl,
|
||||
ep_state->priv_ep,
|
||||
request->priv_req);
|
||||
if (FPUSB2_SUCCESS != error){
|
||||
USB_LOG_ERR("send req to ep@0x%x failed, error = 0x%x\n", ep, error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbd_ep_start_write(const uint8_t ep, const uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
return pusb2_dc_ep_read_write(ep, (uintptr)data, data_len);
|
||||
}
|
||||
|
||||
int usbd_ep_start_read(const uint8_t ep, uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
return pusb2_dc_ep_read_write(ep, (uintptr)data, data_len);
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(void)
|
||||
{
|
||||
FPUsb2InterruptHandler(&g_pusb2_udc.pusb2);
|
||||
}
|
||||
684
port/pusb2/usb_hc_pusb2.c
Normal file
684
port/pusb2/usb_hc_pusb2.c
Normal file
@@ -0,0 +1,684 @@
|
||||
/*
|
||||
* Copyright : (C) 2023 Phytium Information Technology, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
|
||||
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
|
||||
* either version 1.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the Phytium Public License for more details.
|
||||
*
|
||||
*
|
||||
* FilePath: usb_hc_pusb2.c
|
||||
* Date: 2021-08-25 14:53:42
|
||||
* LastEditTime: 2021-08-26 09:01:26
|
||||
* Description: This file is for implementation of PUSB2 port to cherryusb for host mode
|
||||
*
|
||||
* Modify History:
|
||||
* Ver Who Date Changes
|
||||
* ----- ------ -------- --------------------------------------
|
||||
* 1.0 zhugengyu 2023/7/19 first commit
|
||||
* 1.1 zhugengyu 2023/11/14 sync with 0.11.1 port interface
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_hub.h"
|
||||
#include "fpusb2.h"
|
||||
|
||||
struct pusb2_pipe;
|
||||
struct pusb2_dev;
|
||||
struct pusb2_hcd;
|
||||
|
||||
struct pusb2_hcd {
|
||||
FPUsb2 pusb2;
|
||||
FPUsb2Config config;
|
||||
};
|
||||
|
||||
struct pusb2_dev {
|
||||
FPUsb2HcEp ep0;
|
||||
FPUsb2HcEp *epx_in[FPUSB2_HC_EP_NUM];
|
||||
FPUsb2HcEp *epx_out[FPUSB2_HC_EP_NUM];
|
||||
FPUsb2HcDevice udev;
|
||||
|
||||
/*one bit for each endpoint, with ([0] = IN, [1] = OUT) endpoints*/
|
||||
unsigned int toggle[2];
|
||||
#define PUSB2_GET_TOGGLE(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
|
||||
#define PUSB2_DO_TOGGLE(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep)))
|
||||
#define PUSB2_SET_TOGGLE(dev, ep, out, bit) \
|
||||
((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | \
|
||||
((bit) << (ep)))
|
||||
};
|
||||
|
||||
struct pusb2_pipe {
|
||||
struct pusb2_hcd *hcd;
|
||||
struct pusb2_dev *dev;
|
||||
|
||||
uint8_t speed;
|
||||
uint8_t dev_addr;
|
||||
uint8_t ep_addr;
|
||||
uint8_t ep_type;
|
||||
uint8_t ep_num;
|
||||
uint8_t ep_is_in;
|
||||
uint8_t ep_interval;
|
||||
uint16_t ep_mps;
|
||||
|
||||
bool inuse;
|
||||
volatile bool waiter;
|
||||
usb_osal_sem_t waitsem;
|
||||
struct usbh_hubport *hport;
|
||||
struct usbh_urb *urb;
|
||||
const struct usb_endpoint_descriptor *desc;
|
||||
};
|
||||
|
||||
static int usb_id = CONFIG_USBDEV_PUSB2_CTRL_ID;
|
||||
static struct pusb2_hcd g_pusb2_hcd[CONFIG_USBDEV_PUSB2_CTRL_NUM];
|
||||
|
||||
__WEAK void usb_hc_low_level_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
__WEAK void *usb_hc_malloc(size_t size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__WEAK void *usb_hc_malloc_align(size_t align, size_t size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__WEAK void usb_hc_free()
|
||||
{
|
||||
}
|
||||
|
||||
/* one may get xhci register base address by PCIe bus emuration */
|
||||
__WEAK unsigned long usb_hc_get_register_base(uint32_t id)
|
||||
{
|
||||
return 0U;
|
||||
}
|
||||
|
||||
static inline struct pusb2_dev *pusb2_hc_pipe_to_dev(struct pusb2_pipe *ppipe)
|
||||
{
|
||||
USB_ASSERT(ppipe && ppipe->dev);
|
||||
return ppipe->dev;
|
||||
}
|
||||
|
||||
static inline struct pusb2_hcd *pusb2_hc_get_hcd(void)
|
||||
{
|
||||
return &g_pusb2_hcd[usb_id];
|
||||
}
|
||||
|
||||
static void pusb2_pipe_waitup(struct pusb2_pipe *pipe)
|
||||
{
|
||||
struct usbh_urb *urb;
|
||||
|
||||
urb = pipe->urb;
|
||||
pipe->urb = NULL;
|
||||
|
||||
if (pipe->waiter) {
|
||||
pipe->waiter = false;
|
||||
usb_osal_sem_give(pipe->waitsem);
|
||||
}
|
||||
|
||||
if (urb->complete) {
|
||||
if (urb->errorcode < 0) {
|
||||
urb->complete(urb->arg, urb->errorcode);
|
||||
} else {
|
||||
urb->complete(urb->arg, urb->actual_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pusb2_hc_request_giveback(FPUsb2HcController *instance, FPUsb2HcReq *req, u32 status)
|
||||
{
|
||||
struct usbh_urb *urb;
|
||||
struct pusb2_pipe *pipe;
|
||||
int error = 0;
|
||||
|
||||
urb = req->user_ext;
|
||||
pipe = urb->pipe;
|
||||
|
||||
switch(status) {
|
||||
case FPUSB2_HC_ESTALL:
|
||||
error = -EPIPE;
|
||||
break;
|
||||
case FPUSB2_HC_EUNHANDLED:
|
||||
error = -EPROTO;
|
||||
break;
|
||||
case FPUSB2_HC_ESHUTDOWN:
|
||||
error = -ESHUTDOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
urb->errorcode = error;
|
||||
urb->actual_length = req->actual_length;
|
||||
|
||||
pusb2_pipe_waitup(pipe);
|
||||
return;
|
||||
}
|
||||
|
||||
static void pusb2_hc_otg_state_change(FPUsb2HcController *instance, int otg_state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static int pusb2_hub_status_data(FPUsb2HcController *instance, char *buf)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
retval = FPUsb2VHubStatusChangeData(instance, (u8 *)buf);
|
||||
if(retval != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(*buf == 0x02) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void pusb2_hc_rh_port_status_change(FPUsb2HcController *instance)
|
||||
{
|
||||
u32 status_hub = 0U;
|
||||
u16 *status = (u16*)&status_hub;
|
||||
FUsbSetup setup;
|
||||
u32 retval = 0;
|
||||
|
||||
pusb2_hub_status_data(instance, (char*)status);
|
||||
|
||||
setup.bRequest = FUSB_REQ_GET_STATUS;
|
||||
setup.bmRequestType = FUSB_REQ_TYPE_CLASS | FUSB_REQ_RECIPIENT_OTHER | FUSB_DIR_DEVICE_TO_HOST;
|
||||
setup.wIndex = cpu_to_le16(1); /* port number */
|
||||
setup.wLength = cpu_to_le16(4);
|
||||
setup.wValue = 0;
|
||||
|
||||
retval = FPUsb2VHubControl(instance, &setup, (u8*)status);
|
||||
if(retval) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(status[1] & FUSB_PSC_CONNECTION) {
|
||||
if(status[0] & FUSB_PS_CONNECTION) {
|
||||
USB_LOG_DBG("resume roothub \n");
|
||||
/* Report port status change */
|
||||
usbh_roothub_thread_wakeup ( 1U );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u8 pusb2_hc_get_ep_toggle(void *instance, struct FPUsb2HcDevice *udev, u8 ep_num, u8 is_in)
|
||||
{
|
||||
struct pusb2_dev *dev;
|
||||
u8 toggle = 0;
|
||||
|
||||
dev = (struct pusb2_dev*) udev->user_ext;
|
||||
toggle = PUSB2_GET_TOGGLE(dev, ep_num, !is_in);
|
||||
return toggle;
|
||||
}
|
||||
|
||||
static void pusb2_hc_set_ep_toggle(void *instance, struct FPUsb2HcDevice *udev, u8 ep_num, u8 is_in, u8 toggle)
|
||||
{
|
||||
struct pusb2_dev *dev;
|
||||
|
||||
dev = (struct pusb2_dev*) udev->user_ext;
|
||||
PUSB2_SET_TOGGLE(dev, ep_num, !is_in, toggle);
|
||||
}
|
||||
|
||||
static void pusb2_hc_prepare_ctrl_config(uint32_t id, FPUsb2Config *config)
|
||||
{
|
||||
*config = *FPUsb2LookupConfig(id);
|
||||
|
||||
config->mode = FPUSB2_MODE_HOST;
|
||||
|
||||
/* allocate DMA buffer for TRB transfer */
|
||||
config->trb_mem_addr = usb_align(64U, config->trb_mem_size);
|
||||
USB_ASSERT(config->trb_mem_addr);
|
||||
|
||||
/* hook up host callbacks */
|
||||
config->host_cb.givback_request = pusb2_hc_request_giveback;
|
||||
config->host_cb.otg_state_change = pusb2_hc_otg_state_change;
|
||||
config->host_cb.port_status_change = pusb2_hc_rh_port_status_change;
|
||||
config->host_cb.set_ep_toggle = pusb2_hc_set_ep_toggle;
|
||||
config->host_cb.get_ep_toggle = pusb2_hc_get_ep_toggle;
|
||||
config->host_cb.pre_start = NULL;
|
||||
config->host_cb.usb_dev_callbacks = &config->device_cb;
|
||||
|
||||
config->device_cb.connect = NULL;
|
||||
config->device_cb.disconnect= NULL;
|
||||
config->device_cb.resume = NULL;
|
||||
config->device_cb.setup = NULL;
|
||||
config->device_cb.suspend = NULL;
|
||||
config->device_cb.usb_request_mem_alloc = NULL;
|
||||
config->device_cb.usb_request_mem_free = NULL;
|
||||
config->device_cb.pre_start = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int usb_hc_init(void)
|
||||
{
|
||||
int rc;
|
||||
struct pusb2_hcd *hcd = pusb2_hc_get_hcd();
|
||||
|
||||
size_t flag = usb_osal_enter_critical_section(); /* no interrupt when init hc */
|
||||
usb_hc_low_level_init(); /* set gic and memp */
|
||||
|
||||
memset(hcd, 0, sizeof(*hcd));
|
||||
|
||||
pusb2_hc_prepare_ctrl_config(usb_id, &hcd->config);
|
||||
|
||||
if (FPUSB2_SUCCESS != FPUsb2CfgInitialize(&hcd->pusb2,
|
||||
&hcd->config)) {
|
||||
USB_LOG_ERR("init pusb2 failed \n");
|
||||
rc = -1;
|
||||
} else {
|
||||
USB_LOG_INFO("init pusb2 successed \n");
|
||||
}
|
||||
|
||||
usb_osal_leave_critical_section(flag);
|
||||
return rc;
|
||||
}
|
||||
|
||||
uint16_t usbh_get_frame_number(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf)
|
||||
{
|
||||
struct pusb2_hcd *hcd = pusb2_hc_get_hcd();
|
||||
int retval = 0;
|
||||
|
||||
retval = FPUsb2VHubControl(&(hcd->pusb2.host_ctrl), (FUsbSetup *)setup, buf);
|
||||
if(retval != 0) {
|
||||
USB_LOG_ERR("%s failed, retval = %d \r\n", __func__, retval);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void pusb2_hc_update_device(struct pusb2_dev *dev, int dev_addr, int speed, int mps)
|
||||
{
|
||||
dev->udev.speed = (FUsbSpeed)speed;
|
||||
dev->udev.devnum = dev_addr;
|
||||
dev->ep0.ep_desc.max_packet_size = mps;
|
||||
}
|
||||
|
||||
int usbh_ep_pipe_reconfigure(usbh_pipe_t pipe, uint8_t dev_addr, uint8_t mtu, uint8_t speed)
|
||||
{
|
||||
struct pusb2_pipe *ppipe = pipe;
|
||||
struct usbh_hubport *hport = ppipe->hport;
|
||||
struct pusb2_dev *dev = pusb2_hc_pipe_to_dev(ppipe);
|
||||
|
||||
pusb2_hc_update_device(dev, dev_addr, hport->speed, mtu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pusb2_dev *pusb2_hc_allocate_dev(void)
|
||||
{
|
||||
struct pusb2_hcd *hcd = pusb2_hc_get_hcd();
|
||||
struct pusb2_dev *dev;
|
||||
|
||||
dev = usb_malloc((sizeof *dev)+ FPUsb2HcGetPrivateDataSize(&(hcd->pusb2.host_ctrl)));
|
||||
if (dev == NULL)
|
||||
return NULL;
|
||||
|
||||
dev->ep0.hc_priv = &((u8*)dev)[sizeof *dev]; /* ep private data */
|
||||
dev->udev.user_ext = (void*)dev;
|
||||
|
||||
dev->ep0.ep_desc.bLength = FUSB_DS_ENDPOINT;
|
||||
dev->ep0.ep_desc.bDescriptorType = FUSB_DT_ENDPOINT;
|
||||
FDLIST_INIT_HEAD(&dev->ep0.reqList);
|
||||
dev->epx_in[0] = &dev->ep0;
|
||||
dev->epx_out[0] = &dev->ep0;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void pusb2_hc_free_ep(struct pusb2_pipe *ppipe)
|
||||
{
|
||||
USB_ASSERT(ppipe && ppipe->hcd);
|
||||
struct usbh_hubport *hport = ppipe->hport;
|
||||
struct pusb2_hcd *hcd = ppipe->hcd;
|
||||
struct pusb2_dev *dev = pusb2_hc_pipe_to_dev(ppipe);
|
||||
int ep_num = USB_EP_GET_IDX(ppipe->ep_addr);
|
||||
|
||||
if (USB_EP_DIR_IS_IN(ppipe->ep_addr)) {
|
||||
dev->epx_in[ep_num]->user_ext = NULL;
|
||||
usb_free(dev->epx_in[ep_num]);
|
||||
dev->epx_in[ep_num] = NULL;
|
||||
} else {
|
||||
dev->epx_out[ep_num]->user_ext = NULL;
|
||||
usb_free(dev->epx_out[ep_num]);
|
||||
dev->epx_out[ep_num] = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void pusb2_hc_free_dev(struct pusb2_pipe *ppipe)
|
||||
{
|
||||
USB_ASSERT(ppipe && ppipe->hcd);
|
||||
struct usbh_hubport *hport = ppipe->hport;
|
||||
struct pusb2_hcd *hcd = ppipe->hcd;
|
||||
struct pusb2_dev *dev = pusb2_hc_pipe_to_dev(ppipe);
|
||||
|
||||
dev->epx_in[0] = NULL;
|
||||
dev->epx_out[0] = NULL;
|
||||
|
||||
for (int i = 1; i < FPUSB2_HC_EP_NUM; i++) {
|
||||
if (dev->epx_in[i]) {
|
||||
dev->epx_in[i]->user_ext = NULL;
|
||||
usb_free(dev->epx_in[i]);
|
||||
dev->epx_in[i] = NULL;
|
||||
}
|
||||
|
||||
if (dev->epx_out[i]) {
|
||||
dev->epx_out[i]->user_ext = NULL;
|
||||
usb_free(dev->epx_out[i]);
|
||||
dev->epx_out[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
usb_free(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
int usbh_pipe_alloc(usbh_pipe_t *pipe, const struct usbh_endpoint_cfg *ep_cfg)
|
||||
{
|
||||
struct usbh_hubport *hport = ep_cfg->hport;
|
||||
struct pusb2_hcd *hcd = pusb2_hc_get_hcd();
|
||||
struct pusb2_pipe *ppipe = usb_malloc(sizeof(struct pusb2_pipe));
|
||||
struct pusb2_dev *dev;
|
||||
|
||||
if (NULL == ppipe) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(ppipe, 0, sizeof(struct pusb2_pipe));
|
||||
|
||||
ppipe->waitsem = usb_osal_sem_create(0);
|
||||
ppipe->waiter = false;
|
||||
ppipe->urb = NULL;
|
||||
ppipe->hport = hport;
|
||||
|
||||
ppipe->ep_addr = ep_cfg->ep_addr;
|
||||
ppipe->ep_type = ep_cfg->ep_type;
|
||||
ppipe->ep_num = USB_EP_GET_IDX(ep_cfg->ep_addr);
|
||||
ppipe->ep_is_in = USB_EP_DIR_IS_IN(ep_cfg->ep_addr);
|
||||
ppipe->ep_mps = ep_cfg->ep_mps;
|
||||
ppipe->ep_interval = ep_cfg->ep_interval;
|
||||
ppipe->hcd = hcd;
|
||||
|
||||
USB_LOG_DBG("allocate ep-%d\n", ppipe->ep_num);
|
||||
if (ppipe->ep_addr == 0) { /* if try to allocate ctrl ep, open device first */
|
||||
dev = pusb2_hc_allocate_dev();
|
||||
if (NULL == dev) {
|
||||
usb_free(ppipe);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ppipe->desc = (const struct usb_endpoint_descriptor *)&(dev->ep0.ep_desc);
|
||||
ppipe->dev = dev;
|
||||
} else {
|
||||
dev = pusb2_hc_pipe_to_dev((struct pusb2_pipe *)hport->ep0);
|
||||
struct pusb2_pipe *ppipe_ctrl = hport->ep0;
|
||||
|
||||
ppipe->desc = ppipe_ctrl->desc;
|
||||
ppipe->dev = dev;
|
||||
}
|
||||
|
||||
*pipe = (usbh_pipe_t)ppipe;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usbh_pipe_free(usbh_pipe_t pipe)
|
||||
{
|
||||
USB_ASSERT(pipe);
|
||||
struct pusb2_pipe *ppipe = (struct pusb2_pipe *)pipe;
|
||||
struct usbh_urb *urb = ppipe->urb;
|
||||
size_t flags;
|
||||
|
||||
/* free any un-finished urb */
|
||||
if (ppipe->urb) {
|
||||
usbh_kill_urb(urb);
|
||||
}
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
if (USB_EP_GET_IDX(ppipe->ep_addr) == 0) {
|
||||
/* free control ep means free device */
|
||||
pusb2_hc_free_dev(ppipe);
|
||||
} else {
|
||||
/* free work ep */
|
||||
pusb2_hc_free_ep(ppipe);
|
||||
}
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pusb2_hc_update_endpoint(struct pusb2_hcd *hcd, struct pusb2_dev *dev, struct pusb2_pipe *pipe)
|
||||
{
|
||||
USB_ASSERT(hcd && dev && pipe);
|
||||
FPUsb2HcEp * priv_ep = NULL;
|
||||
int epnum = pipe->ep_num;
|
||||
int is_out = !pipe->ep_is_in;
|
||||
|
||||
if (is_out) {
|
||||
if (dev->epx_out[epnum] == NULL) {
|
||||
priv_ep = usb_malloc(sizeof(FPUsb2HcEp) + FPUsb2HcGetPrivateDataSize(&(hcd->pusb2.host_ctrl)));
|
||||
USB_ASSERT(priv_ep);
|
||||
dev->epx_out[epnum] = priv_ep;
|
||||
} else {
|
||||
priv_ep = dev->epx_out[epnum];
|
||||
}
|
||||
} else {
|
||||
if (dev->epx_in[epnum] == NULL) {
|
||||
priv_ep = usb_malloc(sizeof(FPUsb2HcEp) + FPUsb2HcGetPrivateDataSize(&(hcd->pusb2.host_ctrl)));
|
||||
USB_ASSERT(priv_ep);
|
||||
dev->epx_in[epnum] = priv_ep;
|
||||
} else {
|
||||
priv_ep = dev->epx_in[epnum];
|
||||
}
|
||||
}
|
||||
|
||||
priv_ep->ep_desc = *((FUsbEndpointDescriptor *)pipe->desc);
|
||||
priv_ep->user_ext = (void *)pipe;
|
||||
FDLIST_INIT_HEAD(&priv_ep->reqList);
|
||||
priv_ep->hc_priv = &((u8*)priv_ep)[sizeof *priv_ep];
|
||||
}
|
||||
|
||||
static int pusb2_hc_enqueue_urb(struct usbh_urb *urb)
|
||||
{
|
||||
struct pusb2_pipe *pipe = urb->pipe;
|
||||
struct usbh_hubport *hport = pipe->hport;
|
||||
struct pusb2_hcd *hcd = pusb2_hc_get_hcd();
|
||||
struct pusb2_dev *dev;
|
||||
|
||||
u32 iso_frame_size;
|
||||
FPUsb2HcReq *priv_req;
|
||||
int ret;
|
||||
|
||||
if(!FPUsb2HcIsHostMode(&(hcd->pusb2.host_ctrl))) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev = pusb2_hc_pipe_to_dev(pipe);
|
||||
if(!dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (pipe->ep_is_in) {
|
||||
if (!dev->epx_in[pipe->ep_num]) {
|
||||
pusb2_hc_update_endpoint(hcd, dev, pipe);
|
||||
}
|
||||
} else {
|
||||
if (!dev->epx_out[pipe->ep_num]) {
|
||||
pusb2_hc_update_endpoint(hcd, dev, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
iso_frame_size = urb->num_of_iso_packets * sizeof(FPUsb2HcIsoFrameDesc);
|
||||
priv_req = (FPUsb2HcReq*)usb_malloc((sizeof *priv_req) + iso_frame_size);
|
||||
if (!priv_req)
|
||||
return -ENOMEM;
|
||||
|
||||
priv_req->iso_frames_desc = NULL;
|
||||
priv_req->iso_frames_number = urb->num_of_iso_packets;
|
||||
|
||||
FDLIST_INIT_HEAD(&priv_req->list);
|
||||
priv_req->user_ext = (void*) urb;
|
||||
|
||||
priv_req->actual_length = urb->actual_length;
|
||||
priv_req->buf_address = urb->transfer_buffer;
|
||||
priv_req->buf_dma = (uintptr_t)urb->transfer_buffer;
|
||||
priv_req->buf_length = urb->transfer_buffer_length;
|
||||
priv_req->ep_is_in = pipe->ep_is_in;
|
||||
priv_req->ep_num = pipe->ep_num;
|
||||
priv_req->ep_type = pipe->ep_type;
|
||||
priv_req->faddress = dev->udev.devnum;
|
||||
priv_req->interval = pipe->ep_interval;
|
||||
priv_req->req_unlinked = 0;
|
||||
priv_req->setup = (FUsbSetup*)urb->setup;
|
||||
priv_req->setup_dma = (uintptr_t)urb->setup;
|
||||
priv_req->status = FPUSB2_ERR_INPROGRESS;
|
||||
priv_req->usb_dev = &dev->udev;
|
||||
priv_req->usb_ep = priv_req->ep_is_in ? dev->epx_in[priv_req->ep_num]:
|
||||
dev->epx_out[priv_req->ep_num];
|
||||
|
||||
if (priv_req->ep_num == 0) {
|
||||
dev->ep0.ep_desc.max_packet_size = pipe->ep_mps;
|
||||
}
|
||||
|
||||
urb->hcpriv = priv_req;
|
||||
|
||||
ret = FPUsb2HcReqQueue(&(hcd->pusb2.host_ctrl), priv_req);
|
||||
if(ret) {
|
||||
usb_free(priv_req);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usbh_submit_urb(struct usbh_urb *urb)
|
||||
{
|
||||
struct pusb2_pipe *pipe = (struct pusb2_pipe *)urb->pipe;
|
||||
size_t flags;
|
||||
int ret = 0;
|
||||
|
||||
if (!urb) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pipe->hport->connected) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (pipe->urb) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (urb->timeout > 0) {
|
||||
flags = usb_osal_enter_critical_section();
|
||||
}
|
||||
|
||||
pipe->waiter = false;
|
||||
pipe->urb = urb;
|
||||
urb->errorcode = -EBUSY;
|
||||
urb->actual_length = 0;
|
||||
|
||||
if (urb->timeout > 0) {
|
||||
pipe->waiter = true;
|
||||
}
|
||||
|
||||
if (urb->timeout > 0) {
|
||||
usb_osal_leave_critical_section(flags);
|
||||
}
|
||||
|
||||
switch (pipe->ep_type) {
|
||||
case USB_ENDPOINT_TYPE_CONTROL:
|
||||
case USB_ENDPOINT_TYPE_BULK:
|
||||
case USB_ENDPOINT_TYPE_INTERRUPT:
|
||||
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
|
||||
ret = pusb2_hc_enqueue_urb(urb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (urb->timeout > 0) {
|
||||
/* wait until timeout or sem give */
|
||||
ret = usb_osal_sem_take(pipe->waitsem, urb->timeout);
|
||||
if (ret < 0) {
|
||||
USB_LOG_ERR("wait request timeout, ret = %d \n", ret);
|
||||
goto errout_timeout;
|
||||
}
|
||||
|
||||
ret = urb->errorcode;
|
||||
}
|
||||
|
||||
return ret;
|
||||
errout_timeout:
|
||||
pipe->waiter = false;
|
||||
usbh_kill_urb(urb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pusb2_hc_dequeue_urb(struct usbh_urb *urb)
|
||||
{
|
||||
USB_ASSERT(urb);
|
||||
struct pusb2_pipe *pipe = urb->pipe;
|
||||
struct usbh_hubport *hport = pipe->hport;
|
||||
struct pusb2_hcd *hcd = pusb2_hc_get_hcd();
|
||||
struct pusb2_dev *dev;
|
||||
FPUsb2HcReq *priv_req = urb->hcpriv;
|
||||
|
||||
USB_ASSERT(priv_req);
|
||||
if (FPUSB2_SUCCESS != FPUsb2HcReqDequeue(&(hcd->pusb2.host_ctrl), priv_req, 0)) {
|
||||
USB_LOG_ERR("failed to dequeue urb \n");
|
||||
}
|
||||
|
||||
usb_free(priv_req);
|
||||
urb->hcpriv = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
int usbh_kill_urb(struct usbh_urb *urb)
|
||||
{
|
||||
size_t flags;
|
||||
if (!urb) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct pusb2_pipe *pipe = urb->pipe;
|
||||
|
||||
flags = usb_osal_enter_critical_section();
|
||||
|
||||
pusb2_hc_dequeue_urb(urb);
|
||||
pipe->urb = NULL;
|
||||
|
||||
if (pipe->waiter) {
|
||||
pipe->waiter = false;
|
||||
urb->errorcode = -ESHUTDOWN;
|
||||
usb_osal_sem_give(pipe->waitsem);
|
||||
}
|
||||
|
||||
usb_osal_sem_delete(pipe->waitsem);
|
||||
usb_osal_leave_critical_section(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USBH_IRQHandler(void *param)
|
||||
{
|
||||
struct pusb2_hcd *hcd = pusb2_hc_get_hcd();
|
||||
FPUsb2InterruptHandler(&hcd->pusb2);
|
||||
return;
|
||||
}
|
||||
@@ -299,9 +299,7 @@ int usbh_roothub_control(struct usb_setup_packet *setup, uint8_t *buf)
|
||||
uint8_t usbh_get_port_speed(struct usbh_hub *hub, const uint8_t port)
|
||||
{
|
||||
USB_ASSERT(hub);
|
||||
struct usbh_bus *usb = hub->usb;
|
||||
USB_ASSERT(usb && usb->priv);
|
||||
struct xhci_host *xhci = usb->priv;
|
||||
struct xhci_host *xhci = &(xhci_host);
|
||||
|
||||
if (hub->is_roothub) {
|
||||
return xhci_root_speed(xhci, port);
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
* 2.0 zhugengyu 2023/3/29 support usb3.0 device attached at roothub
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_hub.h"
|
||||
|
||||
@@ -31,6 +33,39 @@
|
||||
|
||||
extern struct usbh_hubport *usbh_get_roothub_port(unsigned int port);
|
||||
|
||||
#ifdef __aarch64__
|
||||
/* find last 64bit set, binary search */
|
||||
int xhci_fls(unsigned long v)
|
||||
{
|
||||
int n = 64;
|
||||
|
||||
if (!v) return -1;
|
||||
if (!(v & 0xFFFFFFFF00000000)) { v <<= 32; n -= 32; }
|
||||
if (!(v & 0xFFFF000000000000)) { v <<= 16; n -= 16; }
|
||||
if (!(v & 0xFF00000000000000)) { v <<= 8; n -= 8; }
|
||||
if (!(v & 0xF000000000000000)) { v <<= 4; n -= 4; }
|
||||
if (!(v & 0xC000000000000000)) { v <<= 2; n -= 2; }
|
||||
if (!(v & 0x8000000000000000)) { v <<= 1; n -= 1; }
|
||||
|
||||
return n - 1;
|
||||
}
|
||||
#else
|
||||
/* find first bit set, binary search */
|
||||
int xhci_fls(unsigned int v)
|
||||
{
|
||||
int n = 32;
|
||||
|
||||
if (!v) return -1;
|
||||
if (!(v & 0xFFFF0000)) { v <<= 16; n -= 16; }
|
||||
if (!(v & 0xFF000000)) { v <<= 8; n -= 8; }
|
||||
if (!(v & 0xF0000000)) { v <<= 4; n -= 4; }
|
||||
if (!(v & 0xC0000000)) { v <<= 2; n -= 2; }
|
||||
if (!(v & 0x80000000)) { v <<= 1; n -= 1; }
|
||||
|
||||
return n - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get USB transaction translator
|
||||
*
|
||||
@@ -143,7 +178,7 @@ static inline size_t xhci_align ( size_t len ) {
|
||||
size_t align;
|
||||
|
||||
/* Align to own length (rounded up to a power of two) */
|
||||
align = ( 1 << fls ( len - 1 ) );
|
||||
align = ( 1 << xhci_fls ( len - 1 ) );
|
||||
|
||||
/* Round up to XHCI_MIN_ALIGN if needed */
|
||||
if ( align < XHCI_MIN_ALIGN )
|
||||
@@ -2030,8 +2065,8 @@ static inline int xhci_configure_endpoint ( struct xhci_host *xhci,
|
||||
* @v input Input context
|
||||
*/
|
||||
static void
|
||||
xhci_deconfigure_endpoint_input ( struct xhci_host *xhci __unused,
|
||||
struct xhci_slot *slot __unused,
|
||||
xhci_deconfigure_endpoint_input ( struct xhci_host *xhci,
|
||||
struct xhci_slot *slot,
|
||||
struct xhci_endpoint *endpoint,
|
||||
void *input ) {
|
||||
struct xhci_control_context *control_ctx;
|
||||
@@ -2162,7 +2197,7 @@ int xhci_work_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, st
|
||||
|
||||
/* Calculate interval */
|
||||
if ( ctx_type & XHCI_EP_TYPE_PERIODIC ) {
|
||||
ep->interval = ( fls ( ep->interval ) - 1 );
|
||||
ep->interval = ( xhci_fls ( ep->interval ) - 1 );
|
||||
}
|
||||
|
||||
ep->ctx_type = ctx_type;
|
||||
@@ -2337,7 +2372,7 @@ err_enqueue:
|
||||
* @v input Input context
|
||||
*/
|
||||
static void xhci_evaluate_context_input ( struct xhci_host *xhci,
|
||||
struct xhci_slot *slot __unused,
|
||||
struct xhci_slot *slot,
|
||||
struct xhci_endpoint *endpoint,
|
||||
void *input ) {
|
||||
struct xhci_control_context *control_ctx;
|
||||
|
||||
@@ -159,7 +159,7 @@ static void lwip_rx_handle(void *pdata)
|
||||
while (1) {
|
||||
pmg_offset = 0;
|
||||
payload_offset = 0;
|
||||
ret = usbh_rndis_bulk_in_transfer(rndis_class, rx_buf_ptr, RNDIS_RXETH_BUFFER_LEN, portMAX_DELAY);
|
||||
ret = usbh_rndis_bulk_in_transfer(rndis_class, rx_buf_ptr, RNDIS_RXETH_BUFFER_LEN, USB_OSAL_WAITING_FOREVER);
|
||||
if (ret <= 0) {
|
||||
vTaskDelay(1);
|
||||
continue;
|
||||
|
||||
7
third_party/rt-thread-4.1.1/dfs/udisk.c
vendored
7
third_party/rt-thread-4.1.1/dfs/udisk.c
vendored
@@ -15,6 +15,7 @@
|
||||
#include "usbh_msc.h"
|
||||
|
||||
#define MAX_PARTITION_COUNT 5
|
||||
#define CONFIG_DFS_MOUNT_POINT "/"
|
||||
|
||||
struct ustor_data {
|
||||
struct dfs_partition part;
|
||||
@@ -251,7 +252,7 @@ rt_err_t rt_udisk_run(struct usbh_msc *msc_class)
|
||||
|
||||
stor_r->dev_cnt++;
|
||||
|
||||
if (dfs_mount(stor_r->dev[i].parent.name, "/", "elm", 0, 0) == 0) {
|
||||
if (dfs_mount(stor_r->dev[i].parent.name, CONFIG_DFS_MOUNT_POINT, "elm", 0, 0) == 0) {
|
||||
rt_kprintf("udisk part %d mount successfully\n", i);
|
||||
} else {
|
||||
rt_kprintf("udisk part %d mount failed\n", i);
|
||||
@@ -285,7 +286,7 @@ rt_err_t rt_udisk_run(struct usbh_msc *msc_class)
|
||||
rt_device_register(&stor_r->dev[0], dname, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
|
||||
|
||||
stor_r->dev_cnt++;
|
||||
if (dfs_mount(stor_r->dev[0].parent.name, "/", "elm", 0, 0) == 0) {
|
||||
if (dfs_mount(stor_r->dev[0].parent.name, CONFIG_DFS_MOUNT_POINT, "elm", 0, 0) == 0) {
|
||||
rt_kprintf("Mount FAT on Udisk successful.\n");
|
||||
} else {
|
||||
rt_kprintf("Mount FAT on Udisk failed.\n");
|
||||
@@ -325,7 +326,7 @@ rt_err_t rt_udisk_stop(struct usbh_msc *msc_class)
|
||||
data = (struct ustor_data *)dev->user_data;
|
||||
|
||||
/* unmount filesystem */
|
||||
dfs_unmount("/");
|
||||
dfs_unmount(CONFIG_DFS_MOUNT_POINT);
|
||||
|
||||
/* delete semaphore */
|
||||
rt_sem_delete(data->part.lock);
|
||||
|
||||
84
third_party/rt-thread-4.1.1/msh_cmd.c
vendored
Normal file
84
third_party/rt-thread-4.1.1/msh_cmd.c
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/**************************************************************************/ /**
|
||||
*
|
||||
* @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-8-9 Wayne First version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#if defined(PKG_USING_CHERRYUSB)
|
||||
|
||||
#if defined(PKG_CHERRYUSB_DEVICE_CDC_TEMPLATE)
|
||||
void cdc_acm_init(void);
|
||||
MSH_CMD_EXPORT(cdc_acm_init, start cdc_acm_init);
|
||||
#endif
|
||||
|
||||
#if defined(PKG_CHERRYUSB_DEVICE_HID_MOUSE_TEMPLATE)
|
||||
void hid_mouse_init(void);
|
||||
void hid_mouse_test(void);
|
||||
|
||||
MSH_CMD_EXPORT(hid_mouse_init, start hid_mouse_init);
|
||||
MSH_CMD_EXPORT(hid_mouse_test, start hid_mouse_test);
|
||||
#endif
|
||||
|
||||
#if defined(PKG_CHERRYUSB_DEVICE_HID_KEYBOARD_TEMPLATE)
|
||||
void hid_keyboard_init(void);
|
||||
void hid_keyboard_test(void);
|
||||
|
||||
MSH_CMD_EXPORT(hid_keyboard_init, start hid_keyboard_init);
|
||||
MSH_CMD_EXPORT(hid_keyboard_test, start hid_keyboard_test);
|
||||
#endif
|
||||
|
||||
#if defined(PKG_CHERRYUSB_DEVICE_MSC_TEMPLATE)
|
||||
void msc_ram_init(void);
|
||||
MSH_CMD_EXPORT(msc_ram_init, start msc_ram_init);
|
||||
#endif
|
||||
|
||||
#if defined(PKG_CHERRYUSB_DEVICE_RNDIS_TEMPLATE)
|
||||
void cdc_rndis_init(void);
|
||||
MSH_CMD_EXPORT(cdc_rndis_init, start cdc_rndis_init);
|
||||
#endif
|
||||
|
||||
#if defined(PKG_CHERRYUSB_DEVICE_VIDEO_TEMPLATE)
|
||||
void video_init(void);
|
||||
void video_test(void);
|
||||
|
||||
MSH_CMD_EXPORT(video_init, start video_init);
|
||||
MSH_CMD_EXPORT(video_test, start video_test);
|
||||
#endif
|
||||
|
||||
#if defined(PKG_CHERRYUSB_DEVICE_AUDIO_V1_TEMPLATE)
|
||||
void audio_v1_init(void);
|
||||
void audio_v1_test(void);
|
||||
|
||||
MSH_CMD_EXPORT(audio_v1_init, start audio_v1_init);
|
||||
MSH_CMD_EXPORT(audio_v1_test, start audio_v1_test);
|
||||
#endif
|
||||
|
||||
#if defined(PKG_CHERRYUSB_DEVICE_AUDIO_V2_TEMPLATE)
|
||||
void audio_v2_init(void);
|
||||
void audio_v2_test(void);
|
||||
|
||||
MSH_CMD_EXPORT(audio_v2_init, start audio_v2_init);
|
||||
MSH_CMD_EXPORT(audio_v2_test, start audio_v2_test);
|
||||
#endif
|
||||
|
||||
#if defined(PKG_CHERRYUSB_HOST)
|
||||
void usbh_class_test(void);
|
||||
MSH_CMD_EXPORT(usbh_class_test, start usbh_class_test);
|
||||
|
||||
int lsusb(int argc, char **argv);
|
||||
MSH_CMD_EXPORT(lsusb, start lsusb);
|
||||
|
||||
int usbh_initialize(void);
|
||||
//INIT_APP_EXPORT(usbh_initialize);
|
||||
MSH_CMD_EXPORT(usbh_initialize, start usbh_initialize);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
143
third_party/rt-thread-4.1.1/rndis_host/rndis_host.c
vendored
143
third_party/rt-thread-4.1.1/rndis_host/rndis_host.c
vendored
@@ -8,12 +8,13 @@
|
||||
#include <netdev.h>
|
||||
|
||||
/* define the rdnis device state*/
|
||||
#define RNDIS_BUS_UNINITIALIZED 0
|
||||
#define RNDIS_BUS_INITIALIZED 1
|
||||
#define RNDIS_INITIALIZED 2
|
||||
#define RNDIS_DATA_INITIALIZED 3
|
||||
#define RNDIS_BUS_UNINITIALIZED 0
|
||||
#define RNDIS_BUS_INITIALIZED 1
|
||||
#define RNDIS_INITIALIZED 2
|
||||
#define RNDIS_DATA_INITIALIZED 3
|
||||
|
||||
#define USB_ETH_MTU 1500 + 14
|
||||
#define USB_ETH_MTU (1500 + 14)
|
||||
#define RNDIS_THREAD_STACK_SIZE (4096)
|
||||
|
||||
#define RNDIS_NET_DEV_NAME "u0"
|
||||
#define MAX_ADDR_LEN 6
|
||||
@@ -27,8 +28,7 @@ struct usbh_user_rndis {
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct rndis_packet_msg
|
||||
{
|
||||
struct rndis_packet_msg {
|
||||
rt_uint32_t MessageType;
|
||||
rt_uint32_t MessageLength;
|
||||
rt_uint32_t DataOffset;
|
||||
@@ -65,12 +65,12 @@ struct rt_rndis_eth {
|
||||
|
||||
rt_uint32_t rndis_state;
|
||||
rt_thread_t rndis_recv;
|
||||
rt_timer_t keepalive_timer;
|
||||
rt_thread_t keepalive_timer;
|
||||
};
|
||||
typedef struct rt_rndis_eth *rt_rndis_eth_t;
|
||||
|
||||
struct usbh_user_rndis *g_user_rndis;
|
||||
USB_NOCACHE_RAM_SECTION struct rt_rndis_eth usbh_rndis_eth_device;
|
||||
struct usbh_user_rndis *g_user_rndis = RT_NULL;
|
||||
USB_NOCACHE_RAM_SECTION struct rt_rndis_eth usbh_rndis_eth_device = { 0 };
|
||||
|
||||
void hex_data_print(const char *name, const rt_uint8_t *buf, rt_size_t size)
|
||||
{
|
||||
@@ -139,7 +139,7 @@ static rt_err_t rt_rndis_msg_data_send(struct usbh_user_rndis *rndis_class, rt_u
|
||||
ret = usbh_rndis_bulk_out_transfer(rndis_class->rndis_class, buffer, nbytes, 5000);
|
||||
rt_mutex_release(usbh_rndis_eth_device.rndis_mutex);
|
||||
if (ret != nbytes) {
|
||||
rt_kprintf("rndis msg send fial\r\n");
|
||||
rt_kprintf("rndis msg send fail(%d %d)\r\n", ret, nbytes);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -158,7 +158,7 @@ static rt_err_t rndis_msg_data_recv(struct usbh_user_rndis *rndis_class, rt_uint
|
||||
if (rndis_class == RT_NULL) {
|
||||
return -RT_ERROR;
|
||||
}
|
||||
ret = usbh_rndis_bulk_in_transfer(rndis_class->rndis_class, buffer, nbytes, RT_WAITING_FOREVER);
|
||||
ret = usbh_rndis_bulk_in_transfer(rndis_class->rndis_class, buffer, nbytes, USB_OSAL_WAITING_FOREVER);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -187,55 +187,62 @@ static rt_err_t rt_rndis_keepalive_msg(struct usbh_user_rndis *rndis_class)
|
||||
*/
|
||||
void rt_usbh_rndis_data_recv_entry(void *pdata)
|
||||
{
|
||||
int ret = 0;
|
||||
struct usbh_user_rndis *rndis_class = (struct usbh_user_rndis *)pdata;
|
||||
rt_rndis_eth_t device = RT_NULL;
|
||||
device = (rt_rndis_eth_t)rndis_class->user_data;
|
||||
err_t err;
|
||||
struct pbuf *p;
|
||||
rndis_data_packet_t *pmsg;
|
||||
int pmg_offset;
|
||||
int payload_offset;
|
||||
rt_rndis_eth_t device = (rt_rndis_eth_t)rndis_class->user_data;
|
||||
rndis_data_packet_t sRndisDataPkt;
|
||||
|
||||
if ((pdata == RT_NULL) || (rndis_class == RT_NULL) ||
|
||||
(device == RT_NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
device->rx_buf_ptr = device->rx_buffer;
|
||||
//device->rx_buf_ptr = device->rx_buffer;
|
||||
|
||||
while (1) {
|
||||
pmg_offset = 0;
|
||||
payload_offset = 0;
|
||||
ret = usbh_rndis_bulk_in_transfer(rndis_class->rndis_class, device->rx_buf_ptr, RNDIS_ETH_BUFFER_LEN, RT_WAITING_FOREVER);
|
||||
int ret = 0;
|
||||
int pmg_offset = 0;
|
||||
int payload_offset = 0;
|
||||
ret = usbh_rndis_bulk_in_transfer(rndis_class->rndis_class, device->rx_buf_ptr, RNDIS_ETH_BUFFER_LEN, USB_OSAL_WAITING_FOREVER);
|
||||
if (ret <= 0) {
|
||||
rt_thread_mdelay(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
while (ret > 0) {
|
||||
pmsg = (rndis_data_packet_t *)(device->rx_buf_ptr + pmg_offset);
|
||||
rndis_data_packet_t *pmsg = (rndis_data_packet_t *)(device->rx_buf_ptr + pmg_offset);
|
||||
if (pmg_offset & 0x3) {
|
||||
/* Not word-aligned case */
|
||||
//rt_kprintf("pmsg@%08x Not word-aligned case\n", pmsg);
|
||||
|
||||
rt_memcpy(&sRndisDataPkt, pmsg, sizeof(rndis_data_packet_t));
|
||||
pmsg = &sRndisDataPkt;
|
||||
}
|
||||
|
||||
if (pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) {
|
||||
/* allocate buffer */
|
||||
p = pbuf_alloc(PBUF_RAW, pmsg->DataLength, PBUF_POOL);
|
||||
struct pbuf *p = pbuf_alloc(PBUF_RAW, pmsg->DataLength, PBUF_POOL);
|
||||
if (p != NULL) {
|
||||
struct pbuf *q;
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
/* Copy the received frame into buffer from memory pointed by the current ETHERNET DMA Rx descriptor */
|
||||
memcpy(q->payload, ((uint8_t *)(&pmsg->DataOffset) + pmsg->DataOffset + payload_offset), q->len);
|
||||
void *src = (void *)(device->rx_buf_ptr + pmg_offset + (2 * sizeof(uint32_t)) + pmsg->DataOffset + payload_offset);
|
||||
|
||||
rt_memcpy(q->payload,
|
||||
src,
|
||||
q->len);
|
||||
|
||||
payload_offset += q->len;
|
||||
}
|
||||
/* entry point to the LwIP stack */
|
||||
/* notify to upper layer */
|
||||
if(device->parent.netif->input(p, device->parent.netif)!= ERR_OK )
|
||||
{
|
||||
|
||||
if (device->parent.netif->input(p, device->parent.netif) != ERR_OK) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: Input error\n"));
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
}
|
||||
pmg_offset += pmsg->MessageLength;
|
||||
ret -= pmsg->MessageLength;
|
||||
}
|
||||
} else {
|
||||
rt_kprintf("pmsg->MessageType=%d\n", pmsg->MessageType);
|
||||
break;
|
||||
}
|
||||
|
||||
pmg_offset += pmsg->MessageLength;
|
||||
ret -= pmsg->MessageLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,15 +250,14 @@ void rt_usbh_rndis_data_recv_entry(void *pdata)
|
||||
void rt_rndis_dev_keepalive_timeout(void *pdata)
|
||||
{
|
||||
struct usbh_user_rndis *rndis_class = (struct usbh_user_rndis *)pdata;
|
||||
static rt_uint32_t keepalive_error = 0;
|
||||
|
||||
if (rndis_class == RT_NULL) {
|
||||
return;
|
||||
while (1) {
|
||||
rt_thread_mdelay(RT_TICK_PER_SECOND * RNDIS_DEV_KEEPALIVE_TIMEOUT / 1000);
|
||||
|
||||
rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER);
|
||||
rt_rndis_keepalive_msg(rndis_class);
|
||||
rt_mutex_release(usbh_rndis_eth_device.rndis_mutex);
|
||||
}
|
||||
|
||||
rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER);
|
||||
rt_rndis_keepalive_msg(rndis_class);
|
||||
rt_mutex_release(usbh_rndis_eth_device.rndis_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,22 +280,24 @@ rt_err_t rt_rndis_run(struct usbh_user_rndis *rndis_class)
|
||||
to reset the device, or to tear down the data and control channels*/
|
||||
usbh_rndis_eth_device.rndis_state = RNDIS_INITIALIZED;
|
||||
|
||||
usbh_rndis_eth_device.keepalive_timer = rt_timer_create("keeplive", rt_rndis_dev_keepalive_timeout,
|
||||
rndis_class,
|
||||
RT_TICK_PER_SECOND * RNDIS_DEV_KEEPALIVE_TIMEOUT / 1000,
|
||||
RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER);
|
||||
usbh_rndis_eth_device.keepalive_timer = rt_thread_create("keeplive",
|
||||
(void (*)(void *parameter))rt_rndis_dev_keepalive_timeout,
|
||||
rndis_class,
|
||||
RNDIS_THREAD_STACK_SIZE,
|
||||
5,
|
||||
20);
|
||||
|
||||
if (usbh_rndis_eth_device.keepalive_timer == RT_NULL) {
|
||||
ret = -RT_ENOMEM;
|
||||
goto __exit;
|
||||
}
|
||||
rt_timer_start(usbh_rndis_eth_device.keepalive_timer);
|
||||
|
||||
rndis_class->user_data = (struct rt_device *)&usbh_rndis_eth_device;
|
||||
|
||||
usbh_rndis_eth_device.rndis_recv = rt_thread_create("rndis",
|
||||
usbh_rndis_eth_device.rndis_recv = rt_thread_create("rndis_recv",
|
||||
(void (*)(void *parameter))rt_usbh_rndis_data_recv_entry,
|
||||
rndis_class,
|
||||
1024 + 512,
|
||||
RNDIS_THREAD_STACK_SIZE,
|
||||
5,
|
||||
20);
|
||||
|
||||
@@ -301,8 +309,6 @@ rt_err_t rt_rndis_run(struct usbh_user_rndis *rndis_class)
|
||||
/*the LINK SPEED is 100Mbps*/
|
||||
usbh_rndis_eth_device.rndis_speed = rndis_class->rndis_class->link_speed;
|
||||
|
||||
eth_device_linkchange(&usbh_rndis_eth_device.parent, rndis_class->rndis_class->link_status);
|
||||
|
||||
for (j = 0; j < MAX_ADDR_LEN; j++) {
|
||||
usbh_rndis_eth_device.dev_addr[j] = rndis_class->rndis_class->mac[j];
|
||||
}
|
||||
@@ -316,6 +322,8 @@ __exit:
|
||||
it can exchange REMOTE_NDIS_PACKET_MSG messages for network data transfer with the device on the data channel*/
|
||||
usbh_rndis_eth_device.rndis_state = RNDIS_DATA_INITIALIZED;
|
||||
rt_thread_startup(usbh_rndis_eth_device.rndis_recv);
|
||||
rt_thread_startup(usbh_rndis_eth_device.keepalive_timer);
|
||||
|
||||
RNDIS_DEV_PRINTF("rndis dev start!\n");
|
||||
usbh_rndis_eth_device.rndis_class = rndis_class;
|
||||
|
||||
@@ -332,8 +340,10 @@ void usbh_rndis_run(struct usbh_rndis *rndis_class)
|
||||
RT_ASSERT(g_user_rndis != RT_NULL);
|
||||
g_user_rndis->rndis_class = rndis_class;
|
||||
if (rt_rndis_run(g_user_rndis) == RT_EOK) {
|
||||
/* Allocate ethernet resource. */
|
||||
eth_device_init(&usbh_rndis_eth_device.parent, RNDIS_NET_DEV_NAME);
|
||||
eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_FALSE);
|
||||
//eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_FALSE);
|
||||
eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,16 +358,17 @@ rt_err_t rt_rndis_stop(struct usbh_user_rndis *rndis_class)
|
||||
info->rndis_recv = RT_NULL;
|
||||
}
|
||||
eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_FALSE);
|
||||
|
||||
/* Destroy ethernet resource. */
|
||||
eth_device_deinit(&usbh_rndis_eth_device.parent);
|
||||
|
||||
usbh_rndis_eth_device.rndis_class = RT_NULL;
|
||||
|
||||
/*disable the other thread etx call the rt_timer_start(rndis->keepalive_timer) cause the RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer)*/
|
||||
rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER);
|
||||
if (info->keepalive_timer) {
|
||||
rt_timer_stop(info->keepalive_timer);
|
||||
rt_timer_delete(info->keepalive_timer);
|
||||
rt_thread_delete(info->keepalive_timer);
|
||||
info->keepalive_timer = RT_NULL;
|
||||
}
|
||||
rt_mutex_release(usbh_rndis_eth_device.rndis_mutex);
|
||||
|
||||
info->rndis_state = RNDIS_BUS_UNINITIALIZED;
|
||||
|
||||
@@ -370,6 +381,7 @@ void usbh_rndis_stop(struct usbh_rndis *rndis_class)
|
||||
RT_ASSERT(g_user_rndis != RT_NULL);
|
||||
rt_rndis_stop(g_user_rndis);
|
||||
usb_free(g_user_rndis);
|
||||
g_user_rndis = RT_NULL;
|
||||
}
|
||||
/**
|
||||
* This function rndis eth device.
|
||||
@@ -428,7 +440,6 @@ static rt_err_t rt_rndis_eth_control(rt_device_t dev, int cmd, void *args)
|
||||
|
||||
/* ethernet device interface */
|
||||
|
||||
|
||||
/* transmit packet. */
|
||||
extern int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class,
|
||||
uint32_t oid, uint32_t query_len,
|
||||
@@ -455,7 +466,7 @@ rt_err_t rt_rndis_eth_tx(rt_device_t dev, struct pbuf *p)
|
||||
break;
|
||||
}
|
||||
RNDIS_DEV_PRINTF("linkdown, drop pkg\r\n");
|
||||
while(recount--) {
|
||||
while (recount--) {
|
||||
ret = usbh_rndis_query_msg_transfer(device->rndis_class->rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, sizeof(data), data, &info_len);
|
||||
if (ret < 0) {
|
||||
return -EBUSY;
|
||||
@@ -507,6 +518,7 @@ rt_err_t rt_rndis_eth_tx(rt_device_t dev, struct pbuf *p)
|
||||
}
|
||||
|
||||
if (device->frame_debug == RT_TRUE) {
|
||||
rt_kprintf("msg @ %08x\n", msg);
|
||||
hex_data_print("rndis eth tx", (rt_uint8_t *)msg, msg->MessageLength);
|
||||
}
|
||||
result = rt_rndis_msg_data_send(device->rndis_class, (rt_uint8_t *)msg, msg->MessageLength);
|
||||
@@ -527,13 +539,16 @@ const static struct rt_device_ops rndis_device_ops = {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
__WEAK void lowlevel_usb_init(void)
|
||||
__WEAK void
|
||||
lowlevel_usb_init(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int usbh_rndis_eth_device_init(void)
|
||||
{
|
||||
/* Initialize all data member in usbh_rndis_eth_device */
|
||||
rt_memset(&usbh_rndis_eth_device, 0, sizeof(struct rt_rndis_eth));
|
||||
|
||||
/* OUI 00-00-00, only for test. */
|
||||
usbh_rndis_eth_device.dev_addr[0] = 0xFF;
|
||||
usbh_rndis_eth_device.dev_addr[1] = 0xFF;
|
||||
@@ -573,9 +588,9 @@ int usbh_rndis_eth_device_init(void)
|
||||
|
||||
lowlevel_usb_init();
|
||||
|
||||
return RT_EOK;
|
||||
return 0;
|
||||
}
|
||||
INIT_APP_EXPORT(usbh_rndis_eth_device_init);
|
||||
INIT_DEVICE_EXPORT(usbh_rndis_eth_device_init);
|
||||
|
||||
/*********************************************************************************************************
|
||||
** Function name eth_rndis_frame_debug()
|
||||
|
||||
653
third_party/rt-thread-4.1.1/rndis_host/rndis_host_lwip2.1.2.c
vendored
Normal file
653
third_party/rt-thread-4.1.1/rndis_host/rndis_host_lwip2.1.2.c
vendored
Normal file
@@ -0,0 +1,653 @@
|
||||
#include <rtthread.h>
|
||||
#include "usbh_core.h"
|
||||
#include "usbh_rndis.h"
|
||||
#include "rndis_protocol.h"
|
||||
|
||||
/* RT-Thread LWIP ethernet interface */
|
||||
#include <netif/ethernetif.h>
|
||||
#include <netdev.h>
|
||||
|
||||
/* define the rdnis device state*/
|
||||
#define RNDIS_BUS_UNINITIALIZED 0
|
||||
#define RNDIS_BUS_INITIALIZED 1
|
||||
#define RNDIS_INITIALIZED 2
|
||||
#define RNDIS_DATA_INITIALIZED 3
|
||||
|
||||
#define USB_ETH_MTU 1500 + 14
|
||||
|
||||
#define RNDIS_NET_DEV_NAME "u0"
|
||||
#define MAX_ADDR_LEN 6
|
||||
/* rndis device keepalive time 5000ms*/
|
||||
#define RNDIS_DEV_KEEPALIVE_TIMEOUT 5000
|
||||
/*should be the usb Integer multiple of maximum packet length N*64*/
|
||||
#define RNDIS_ETH_BUFFER_LEN ((sizeof(struct rndis_packet_msg) + USB_ETH_MTU + 42) * 5)
|
||||
|
||||
static rt_err_t rt_rndis_eth_tx(rt_device_t dev, struct pbuf *p);
|
||||
|
||||
extern int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class,
|
||||
uint32_t oid, uint32_t query_len,
|
||||
uint8_t *info, uint32_t *info_len);
|
||||
|
||||
struct usbh_user_rndis {
|
||||
struct usbh_rndis *rndis_class;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct rndis_packet_msg
|
||||
{
|
||||
rt_uint32_t MessageType;
|
||||
rt_uint32_t MessageLength;
|
||||
rt_uint32_t DataOffset;
|
||||
rt_uint32_t DataLength;
|
||||
rt_uint32_t OOBDataOffset;
|
||||
rt_uint32_t OOBDataLength;
|
||||
rt_uint32_t NumOOBDataElements;
|
||||
rt_uint32_t PerPacketInfoOffset;
|
||||
rt_uint32_t PerPacketInfoLength;
|
||||
rt_uint32_t VcHandle;
|
||||
rt_uint32_t Reserved;
|
||||
rt_uint8_t data[0];
|
||||
};
|
||||
typedef struct rndis_packet_msg* rndis_packet_msg_t;
|
||||
|
||||
struct rt_rndis_eth {
|
||||
/* inherit from ethernet device */
|
||||
struct eth_device parent;
|
||||
|
||||
struct usbh_user_rndis *rndis_class;
|
||||
rt_mutex_t rndis_mutex;
|
||||
/* interface address info */
|
||||
rt_uint8_t dev_addr[MAX_ADDR_LEN];
|
||||
rt_uint16_t res;
|
||||
rt_uint32_t rndis_speed;
|
||||
rt_uint32_t res32;
|
||||
|
||||
rt_uint8_t tx_buffer[RNDIS_ETH_BUFFER_LEN];
|
||||
rt_uint8_t rx_buffer[RNDIS_ETH_BUFFER_LEN];
|
||||
rt_uint8_t *rx_buf_ptr;
|
||||
rt_uint32_t frame_debug;
|
||||
rt_uint32_t send_packet_counter;
|
||||
rt_uint32_t recv_packet_counter;
|
||||
|
||||
rt_uint32_t rndis_state;
|
||||
rt_thread_t rndis_recv;
|
||||
rt_timer_t keepalive_timer;
|
||||
};
|
||||
typedef struct rt_rndis_eth *rt_rndis_eth_t;
|
||||
|
||||
struct usbh_user_rndis *g_user_rndis;
|
||||
USB_NOCACHE_RAM_SECTION struct rt_rndis_eth usbh_rndis_eth_device;
|
||||
|
||||
void hex_data_print(const char *name, const rt_uint8_t *buf, rt_size_t size)
|
||||
{
|
||||
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
|
||||
#define WIDTH_SIZE 32
|
||||
|
||||
rt_size_t i, j;
|
||||
rt_tick_t tick = 0;
|
||||
rt_uint32_t time = 0;
|
||||
|
||||
tick = rt_tick_get();
|
||||
time = (tick * 1000) / RT_TICK_PER_SECOND;
|
||||
|
||||
rt_kprintf("%s time=%d.%ds,len = %d\n", name, time / 1000, time % 1000, size);
|
||||
|
||||
for (i = 0; i < size; i += WIDTH_SIZE) {
|
||||
rt_kprintf("[HEX] %s: %04X-%04X: ", name, i, i + WIDTH_SIZE);
|
||||
for (j = 0; j < WIDTH_SIZE; j++) {
|
||||
if (i + j < size) {
|
||||
rt_kprintf("%02X ", buf[i + j]);
|
||||
} else {
|
||||
rt_kprintf(" ");
|
||||
}
|
||||
if ((j + 1) % 8 == 0) {
|
||||
rt_kprintf(" ");
|
||||
}
|
||||
}
|
||||
rt_kprintf(" ");
|
||||
for (j = 0; j < WIDTH_SIZE; j++) {
|
||||
if (i + j < size) {
|
||||
rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
|
||||
}
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
#define RNDIS_DEV_DEBUG
|
||||
#ifdef RNDIS_DEV_DEBUG
|
||||
#define RNDIS_DEV_PRINTF \
|
||||
rt_kprintf("[RNDIS_DEV] "); \
|
||||
rt_kprintf
|
||||
#else
|
||||
#define RNDIS_DEV_PRINTF(...)
|
||||
#endif /* RNDIS_DEBUG */
|
||||
|
||||
/**
|
||||
* This function send the rndis data.
|
||||
*
|
||||
* @param rndis_class the usb interface instance.
|
||||
*
|
||||
* @return the error code, RT_EOK on successfully.
|
||||
*/
|
||||
static rt_err_t rt_rndis_msg_data_send(struct usbh_user_rndis *rndis_class, rt_uint8_t *buffer, int nbytes)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (rndis_class == RT_NULL) {
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_rndis_eth_t info = RT_NULL;
|
||||
|
||||
info = (rt_rndis_eth_t)rndis_class->user_data;
|
||||
rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER);
|
||||
ret = usbh_rndis_bulk_out_transfer(rndis_class->rndis_class, buffer, nbytes, 5000);
|
||||
rt_mutex_release(usbh_rndis_eth_device.rndis_mutex);
|
||||
if (ret != nbytes) {
|
||||
rt_kprintf("rndis msg send fial\r\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function recv the rndis data.
|
||||
*
|
||||
* @param rndis_class the usb interface instance.
|
||||
*
|
||||
* @return the error code, RT_EOK on successfully.
|
||||
*/
|
||||
static rt_err_t rndis_msg_data_recv(struct usbh_user_rndis *rndis_class, rt_uint8_t *buffer, int nbytes)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (rndis_class == RT_NULL) {
|
||||
return -RT_ERROR;
|
||||
}
|
||||
ret = usbh_rndis_bulk_in_transfer(rndis_class->rndis_class, buffer, nbytes, USB_OSAL_WAITING_FOREVER);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function send the rndis set msg.
|
||||
*
|
||||
* @param rndis_class the usb interface instance.
|
||||
*
|
||||
* @return the error code, RT_EOK on successfully.
|
||||
*/
|
||||
static rt_err_t rt_rndis_keepalive_msg(struct usbh_user_rndis *rndis_class)
|
||||
{
|
||||
return usbh_rndis_keepalive(rndis_class->rndis_class);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will send the bulk data to the usb device instance,
|
||||
*
|
||||
* @param device the usb device instance.
|
||||
* @param type the type of descriptor bRequest.
|
||||
* @param buffer the data buffer to save requested data
|
||||
* @param nbytes the size of buffer
|
||||
*
|
||||
* @return the error code, RT_EOK on successfully.
|
||||
*/
|
||||
void rt_usbh_rndis_data_recv_entry(void *pdata)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t data[4];
|
||||
uint32_t info_len = 0;
|
||||
rt_uint32_t recount = 1000;
|
||||
struct usbh_user_rndis *rndis_class = (struct usbh_user_rndis *)pdata;
|
||||
rt_rndis_eth_t device = RT_NULL;
|
||||
device = (rt_rndis_eth_t)rndis_class->user_data;
|
||||
err_t err;
|
||||
struct pbuf *p;
|
||||
rndis_data_packet_t *pmsg;
|
||||
int pmg_offset;
|
||||
int payload_offset;
|
||||
|
||||
if ((pdata == RT_NULL) || (rndis_class == RT_NULL) ||
|
||||
(device == RT_NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
device->rx_buf_ptr = device->rx_buffer;
|
||||
|
||||
if (!device->parent.link_status) {
|
||||
while (RT_TRUE) {
|
||||
if (device->rndis_class == RT_NULL) {
|
||||
rt_thread_delay(1000);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
RNDIS_DEV_PRINTF("linkdown, drop pkg\r\n");
|
||||
while(recount--) {
|
||||
ret = usbh_rndis_query_msg_transfer(rndis_class->rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, sizeof(data), data, &info_len);
|
||||
if (ret < 0) {
|
||||
continue;;
|
||||
}
|
||||
if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
|
||||
device->rndis_class->rndis_class->link_status = true;
|
||||
eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_TRUE);
|
||||
RNDIS_DEV_PRINTF("linkup, drop pkg\r\n");
|
||||
break;
|
||||
} else {
|
||||
device->rndis_class->rndis_class->link_status = false;
|
||||
eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_FALSE);
|
||||
}
|
||||
rt_thread_delay(100);
|
||||
}
|
||||
}
|
||||
while (1) {
|
||||
pmg_offset = 0;
|
||||
payload_offset = 0;
|
||||
ret = usbh_rndis_bulk_in_transfer(rndis_class->rndis_class, device->rx_buf_ptr, RNDIS_ETH_BUFFER_LEN, USB_OSAL_WAITING_FOREVER);
|
||||
if (ret <= 0) {
|
||||
rt_thread_mdelay(1);
|
||||
continue;
|
||||
}
|
||||
while (ret > 0) {
|
||||
pmsg = (rndis_data_packet_t *)(device->rx_buf_ptr + pmg_offset);
|
||||
if (pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) {
|
||||
/* allocate buffer */
|
||||
p = pbuf_alloc(PBUF_RAW, pmsg->DataLength, PBUF_POOL);
|
||||
if (p != NULL) {
|
||||
struct pbuf *q;
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
/* Copy the received frame into buffer from memory pointed by the current ETHERNET DMA Rx descriptor */
|
||||
memcpy(q->payload, ((uint8_t *)(&pmsg->DataOffset) + pmsg->DataOffset + payload_offset), q->len);
|
||||
payload_offset += q->len;
|
||||
}
|
||||
/* entry point to the LwIP stack */
|
||||
/* notify to upper layer */
|
||||
if(device->parent.netif->input(p, device->parent.netif)!= ERR_OK )
|
||||
{
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: Input error\n"));
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
}
|
||||
pmg_offset += pmsg->MessageLength;
|
||||
ret -= pmsg->MessageLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rt_rndis_dev_keepalive_timeout(void *pdata)
|
||||
{
|
||||
struct usbh_user_rndis *rndis_class = (struct usbh_user_rndis *)pdata;
|
||||
static rt_uint32_t keepalive_error = 0;
|
||||
|
||||
if (rndis_class == RT_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER);
|
||||
rt_rndis_keepalive_msg(rndis_class);
|
||||
rt_mutex_release(usbh_rndis_eth_device.rndis_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will run rndis driver when usb disk is detected.
|
||||
*
|
||||
* @param rndis_class the usb interface instance.
|
||||
*
|
||||
* @return the error code, RT_EOK on successfully.
|
||||
*/
|
||||
rt_err_t rt_rndis_run(struct usbh_user_rndis *rndis_class)
|
||||
{
|
||||
rt_err_t ret = 0;
|
||||
rt_uint32_t i = 0, j = 0;
|
||||
|
||||
/* check parameter */
|
||||
RT_ASSERT(rndis_class != RT_NULL);
|
||||
|
||||
/*The host is configured to send and receive any of the RNDIS control messages for suitably
|
||||
configuring or querying the device, to receive status indications from the device,
|
||||
to reset the device, or to tear down the data and control channels*/
|
||||
usbh_rndis_eth_device.rndis_state = RNDIS_INITIALIZED;
|
||||
|
||||
usbh_rndis_eth_device.keepalive_timer = rt_timer_create("keeplive", rt_rndis_dev_keepalive_timeout,
|
||||
rndis_class,
|
||||
RT_TICK_PER_SECOND * RNDIS_DEV_KEEPALIVE_TIMEOUT / 1000,
|
||||
RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER);
|
||||
|
||||
if (usbh_rndis_eth_device.keepalive_timer == RT_NULL) {
|
||||
ret = -RT_ENOMEM;
|
||||
goto __exit;
|
||||
}
|
||||
rt_timer_start(usbh_rndis_eth_device.keepalive_timer);
|
||||
rndis_class->user_data = (struct rt_device *)&usbh_rndis_eth_device;
|
||||
|
||||
usbh_rndis_eth_device.rndis_recv = rt_thread_create("rndis",
|
||||
(void (*)(void *parameter))rt_usbh_rndis_data_recv_entry,
|
||||
rndis_class,
|
||||
1024 + 512,
|
||||
5,
|
||||
20);
|
||||
|
||||
if (usbh_rndis_eth_device.rndis_recv == RT_NULL) {
|
||||
ret = -RT_ENOMEM;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
/*the LINK SPEED is 100Mbps*/
|
||||
usbh_rndis_eth_device.rndis_speed = rndis_class->rndis_class->link_speed;
|
||||
|
||||
eth_device_linkchange(&usbh_rndis_eth_device.parent, rndis_class->rndis_class->link_status);
|
||||
|
||||
for (j = 0; j < MAX_ADDR_LEN; j++) {
|
||||
usbh_rndis_eth_device.dev_addr[j] = rndis_class->rndis_class->mac[j];
|
||||
}
|
||||
|
||||
__exit:
|
||||
if (ret == RT_EOK) {
|
||||
/*This state is entered after the host has received REMOTE_NDIS_SET_CMPLT
|
||||
messages from the device in response to the REMOTE_NDIS_SET_MSG
|
||||
that it had sent earlier to the device with all the OIDs required to configure the device for data transfer.
|
||||
When the host is in this state, apart from the control messages,
|
||||
it can exchange REMOTE_NDIS_PACKET_MSG messages for network data transfer with the device on the data channel*/
|
||||
usbh_rndis_eth_device.rndis_state = RNDIS_DATA_INITIALIZED;
|
||||
RNDIS_DEV_PRINTF("rndis dev start!\n");
|
||||
usbh_rndis_eth_device.rndis_class = rndis_class;
|
||||
rt_thread_startup(usbh_rndis_eth_device.rndis_recv);
|
||||
|
||||
} else {
|
||||
RNDIS_DEV_PRINTF("rndis dev faile!\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static err_t linkoutput_fn(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
int ret;
|
||||
rt_device_t dev = (rt_device_t)&usbh_rndis_eth_device;
|
||||
ret = rt_rndis_eth_tx(dev, p);
|
||||
|
||||
if (-EBUSY == ret) {
|
||||
ret = ERR_BUF;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void usbh_rndis_run(struct usbh_rndis *rndis_class)
|
||||
{
|
||||
g_user_rndis = usb_malloc(sizeof(struct usbh_user_rndis));
|
||||
RT_ASSERT(g_user_rndis != RT_NULL);
|
||||
g_user_rndis->rndis_class = rndis_class;
|
||||
if (rt_rndis_run(g_user_rndis) == RT_EOK) {
|
||||
eth_device_init(&usbh_rndis_eth_device.parent, RNDIS_NET_DEV_NAME);
|
||||
usbh_rndis_eth_device.parent.netif->linkoutput = linkoutput_fn;
|
||||
eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
rt_err_t rt_rndis_stop(struct usbh_user_rndis *rndis_class)
|
||||
{
|
||||
rt_rndis_eth_t info = RT_NULL;
|
||||
|
||||
info = (rt_rndis_eth_t)rndis_class->user_data;
|
||||
|
||||
if (info->rndis_recv) {
|
||||
rt_thread_delete(info->rndis_recv);
|
||||
info->rndis_recv = RT_NULL;
|
||||
}
|
||||
eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_FALSE);
|
||||
usbh_rndis_eth_device.rndis_class = RT_NULL;
|
||||
|
||||
/*disable the other thread etx call the rt_timer_start(rndis->keepalive_timer) cause the RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer)*/
|
||||
rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER);
|
||||
if (info->keepalive_timer) {
|
||||
rt_timer_stop(info->keepalive_timer);
|
||||
rt_timer_delete(info->keepalive_timer);
|
||||
info->keepalive_timer = RT_NULL;
|
||||
}
|
||||
rt_mutex_release(usbh_rndis_eth_device.rndis_mutex);
|
||||
|
||||
info->rndis_state = RNDIS_BUS_UNINITIALIZED;
|
||||
|
||||
RNDIS_DEV_PRINTF("rndis dev stop!\n");
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
void usbh_rndis_stop(struct usbh_rndis *rndis_class)
|
||||
{
|
||||
RT_ASSERT(g_user_rndis != RT_NULL);
|
||||
rt_rndis_stop(g_user_rndis);
|
||||
usb_free(g_user_rndis);
|
||||
}
|
||||
/**
|
||||
* This function rndis eth device.
|
||||
*
|
||||
* @param intf the usb interface instance.
|
||||
*
|
||||
* @return the error code, RT_EOK on successfully.
|
||||
*/
|
||||
#ifdef RT_USING_LWIP
|
||||
/* initialize the interface */
|
||||
static rt_err_t rt_rndis_eth_init(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t rt_rndis_eth_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t rt_rndis_eth_close(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_rndis_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
|
||||
{
|
||||
rt_set_errno(-RT_ENOSYS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_rndis_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
|
||||
{
|
||||
rt_set_errno(-RT_ENOSYS);
|
||||
return 0;
|
||||
}
|
||||
static rt_err_t rt_rndis_eth_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
rt_rndis_eth_t rndis_eth_dev = (rt_rndis_eth_t)dev;
|
||||
switch (cmd) {
|
||||
case NIOCTL_GADDR:
|
||||
/* get mac address */
|
||||
if (args) {
|
||||
rt_memcpy(args, rndis_eth_dev->dev_addr, MAX_ADDR_LEN);
|
||||
} else {
|
||||
return -RT_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/* ethernet device interface */
|
||||
|
||||
|
||||
/* transmit packet. */
|
||||
|
||||
|
||||
static rt_err_t rt_rndis_eth_tx(rt_device_t dev, struct pbuf *p)
|
||||
{
|
||||
struct pbuf *q;
|
||||
rt_uint8_t *buffer = RT_NULL;
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_rndis_eth_t device = (rt_rndis_eth_t)dev;
|
||||
rndis_packet_msg_t msg = RT_NULL;
|
||||
int recount = 5;
|
||||
int ret;
|
||||
uint8_t data[4];
|
||||
uint32_t info_len = 0;
|
||||
|
||||
if (!device->parent.link_status) {
|
||||
while (RT_TRUE) {
|
||||
if (device->rndis_class == RT_NULL) {
|
||||
rt_thread_delay(1000);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
RNDIS_DEV_PRINTF("linkdown, drop pkg\r\n");
|
||||
while(recount--) {
|
||||
ret = usbh_rndis_query_msg_transfer(device->rndis_class->rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, sizeof(data), data, &info_len);
|
||||
if (ret < 0) {
|
||||
return -EBUSY;
|
||||
}
|
||||
if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
|
||||
device->rndis_class->rndis_class->link_status = true;
|
||||
eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_TRUE);
|
||||
RNDIS_DEV_PRINTF("linkup, drop pkg\r\n");
|
||||
break;
|
||||
} else {
|
||||
device->rndis_class->rndis_class->link_status = false;
|
||||
eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_FALSE);
|
||||
}
|
||||
rt_thread_delay(100);
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
RT_ASSERT((p->tot_len + sizeof(struct rndis_packet_msg)) < sizeof(device->tx_buffer));
|
||||
if (p->tot_len > sizeof(device->tx_buffer)) {
|
||||
RNDIS_DEV_PRINTF("RNDIS MTU is:%d, but the send packet size is %d\r\n",
|
||||
sizeof(device->tx_buffer), p->tot_len);
|
||||
p->tot_len = sizeof(device->tx_buffer);
|
||||
}
|
||||
|
||||
msg = (rndis_packet_msg_t)&device->tx_buffer;
|
||||
msg->MessageType = REMOTE_NDIS_PACKET_MSG;
|
||||
msg->DataOffset = sizeof(struct rndis_packet_msg) - 8;
|
||||
msg->DataLength = p->tot_len;
|
||||
msg->OOBDataLength = 0;
|
||||
msg->OOBDataOffset = 0;
|
||||
msg->NumOOBDataElements = 0;
|
||||
msg->PerPacketInfoOffset = 0;
|
||||
msg->PerPacketInfoLength = 0;
|
||||
msg->VcHandle = 0;
|
||||
msg->Reserved = 0;
|
||||
msg->MessageLength = sizeof(struct rndis_packet_msg) + p->tot_len;
|
||||
|
||||
buffer = msg->data;
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
rt_memcpy(buffer, q->payload, q->len);
|
||||
buffer += q->len;
|
||||
}
|
||||
|
||||
/* send */
|
||||
if ((msg->MessageLength & 0x3F) == 0) {
|
||||
/* pad a dummy. */
|
||||
msg->MessageLength += 1;
|
||||
}
|
||||
|
||||
if (device->frame_debug == RT_TRUE) {
|
||||
hex_data_print("rndis eth tx", (rt_uint8_t *)msg, msg->MessageLength);
|
||||
}
|
||||
result = rt_rndis_msg_data_send(device->rndis_class, (rt_uint8_t *)msg, msg->MessageLength);
|
||||
if (result == msg->MessageLength) {
|
||||
result = ERR_OK;
|
||||
}
|
||||
device->send_packet_counter++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops rndis_device_ops = {
|
||||
rt_rndis_eth_init,
|
||||
rt_rndis_eth_open,
|
||||
rt_rndis_eth_close,
|
||||
rt_rndis_eth_read,
|
||||
rt_rndis_eth_write,
|
||||
rt_rndis_eth_control
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
__WEAK void lowlevel_usb_init(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int usbh_rndis_eth_device_init(void)
|
||||
{
|
||||
/* OUI 00-00-00, only for test. */
|
||||
usbh_rndis_eth_device.dev_addr[0] = 0xFF;
|
||||
usbh_rndis_eth_device.dev_addr[1] = 0xFF;
|
||||
usbh_rndis_eth_device.dev_addr[2] = 0xFF;
|
||||
/* generate random MAC. */
|
||||
usbh_rndis_eth_device.dev_addr[3] = 0xFF;
|
||||
usbh_rndis_eth_device.dev_addr[4] = 0xFF;
|
||||
usbh_rndis_eth_device.dev_addr[5] = 0xFF;
|
||||
|
||||
usbh_rndis_eth_device.rndis_mutex = rt_mutex_create("rndis", RT_IPC_FLAG_PRIO);
|
||||
|
||||
if (usbh_rndis_eth_device.rndis_mutex == RT_NULL) {
|
||||
RNDIS_DEV_PRINTF("Rndis mutex creat faile!\r\n");
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
usbh_rndis_eth_device.parent.parent.ops = &rndis_device_ops;
|
||||
#else
|
||||
usbh_rndis_eth_device.parent.parent.init = rt_rndis_eth_init;
|
||||
usbh_rndis_eth_device.parent.parent.open = rt_rndis_eth_open;
|
||||
usbh_rndis_eth_device.parent.parent.close = rt_rndis_eth_close;
|
||||
usbh_rndis_eth_device.parent.parent.read = rt_rndis_eth_read;
|
||||
usbh_rndis_eth_device.parent.parent.write = rt_rndis_eth_write;
|
||||
usbh_rndis_eth_device.parent.parent.control = rt_rndis_eth_control;
|
||||
#endif
|
||||
usbh_rndis_eth_device.parent.parent.user_data = RT_NULL;
|
||||
|
||||
usbh_rndis_eth_device.parent.eth_rx = RT_NULL;
|
||||
usbh_rndis_eth_device.parent.eth_tx = RT_NULL;
|
||||
|
||||
/* register eth device */
|
||||
usbh_rndis_eth_device.rx_buf_ptr = usbh_rndis_eth_device.rx_buffer;
|
||||
usbh_rndis_eth_device.frame_debug = RT_FALSE;
|
||||
|
||||
usbh_rndis_eth_device.send_packet_counter = 0;
|
||||
usbh_rndis_eth_device.recv_packet_counter = 0;
|
||||
|
||||
lowlevel_usb_init();
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
INIT_APP_EXPORT(usbh_rndis_eth_device_init);
|
||||
|
||||
/*********************************************************************************************************
|
||||
** Function name eth_rndis_frame_debug()
|
||||
** Descriptions: rndis frame print
|
||||
** input parameters
|
||||
** output parameters None
|
||||
** Returned value: RT_EOK or RT_ERROR
|
||||
*********************************************************************************************************/
|
||||
static void eth_rndis_frame_debug(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
rt_kprintf("Please check the command you enter, it like this: rndis_debug on/off!\n");
|
||||
} else {
|
||||
if (rt_strcmp(argv[1], "on") == 0) {
|
||||
usbh_rndis_eth_device.frame_debug = RT_TRUE;
|
||||
} else {
|
||||
usbh_rndis_eth_device.frame_debug = RT_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FINSH_USING_MSH
|
||||
#include <finsh.h>
|
||||
MSH_CMD_EXPORT_ALIAS(eth_rndis_frame_debug, rndis_debug, set eth rndis frame print);
|
||||
#endif /* FINSH_USING_MSH */
|
||||
49
tools/test_srcipts/test_cdc_speed.py
Normal file
49
tools/test_srcipts/test_cdc_speed.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import serial
|
||||
import time
|
||||
try:
|
||||
from serial.tools.list_ports import comports
|
||||
except ImportError:
|
||||
raise serial.serialutil.SerialException
|
||||
|
||||
|
||||
test_comx = 'COM66'
|
||||
test_baudrate = 2000000
|
||||
test_maxsize = 10*1024*1024
|
||||
|
||||
test_data = '0xAA' * 4096
|
||||
|
||||
test_serial = serial.Serial(test_comx, test_baudrate, timeout = 1)
|
||||
|
||||
def test_cdc_out():
|
||||
send_count = 0
|
||||
begin = time.time()
|
||||
|
||||
while True:
|
||||
if send_count < test_maxsize:
|
||||
txdatalen = test_serial.write(test_data.encode("utf-8"))
|
||||
send_count += txdatalen
|
||||
else:
|
||||
print("cdc out speed %f MB/s" %(send_count//1024//1024/(time.time() - begin)))
|
||||
break
|
||||
|
||||
def test_cdc_in():
|
||||
read_count = 0
|
||||
begin = time.time()
|
||||
|
||||
while True:
|
||||
if read_count < test_maxsize:
|
||||
data = test_serial.read(test_maxsize).decode(encoding='utf-8',errors='ignore')
|
||||
read_count += len(data)
|
||||
else:
|
||||
print("cdc in speed %f MB/s" %(read_count//1024//1024/(time.time() - begin)))
|
||||
break
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('test cdc out speed')
|
||||
|
||||
test_serial.setDTR(0)
|
||||
test_cdc_out()
|
||||
|
||||
print('test cdc in speed')
|
||||
test_serial.setDTR(1)
|
||||
test_cdc_in()
|
||||
68
tools/test_srcipts/test_hid_inout.py
Normal file
68
tools/test_srcipts/test_hid_inout.py
Normal file
@@ -0,0 +1,68 @@
|
||||
# Copyright (c) 2021 HPMicro
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import pywinusb.hid as hid
|
||||
import os
|
||||
import time
|
||||
import sys
|
||||
import operator
|
||||
|
||||
# VID and PID customization changes here...
|
||||
|
||||
VID = 0xFFFF
|
||||
PID = 0xFFFF
|
||||
|
||||
# Send buffer
|
||||
buffer = [0xff]*64
|
||||
|
||||
# Const
|
||||
TIMEOUT = -1
|
||||
PASS = 0
|
||||
FAIL = 1
|
||||
|
||||
# Result
|
||||
result = TIMEOUT
|
||||
|
||||
def search_dev():
|
||||
filter = hid.HidDeviceFilter(vendor_id = VID, product_id = PID)
|
||||
hid_device = filter.get_devices()
|
||||
return hid_device
|
||||
|
||||
def recv_data(data):
|
||||
print("<=================== USB HID Read ========================>")
|
||||
for i in range(0, len(data)):
|
||||
print("0x{0:02x}" .format(data[i]), end=" ")
|
||||
print("\n")
|
||||
|
||||
global result
|
||||
result = (PASS if (operator.eq(data[1:-1], buffer[1:-1]) == True) else FAIL)
|
||||
|
||||
return None
|
||||
|
||||
def send_data(report):
|
||||
print("<=================== USB HID Write ========================>")
|
||||
buffer[0] = report[0].report_id
|
||||
print("0x{0:02x}" .format(buffer[0]), end=" ")
|
||||
|
||||
for i in range(1,64):
|
||||
buffer[i] = i % 256
|
||||
print("0x{0:02x}" .format(buffer[i]), end=" ")
|
||||
print("\n")
|
||||
|
||||
report[0].set_raw_data(buffer)
|
||||
report[0].send()
|
||||
return None
|
||||
|
||||
if __name__ == '__main__':
|
||||
device = search_dev()[0]
|
||||
device.open()
|
||||
device.set_raw_data_handler(recv_data)
|
||||
send_data(device.find_output_reports())
|
||||
time.sleep(1)
|
||||
|
||||
if result == PASS:
|
||||
print("USB hid echo passed!")
|
||||
elif result == FAIL:
|
||||
print("USB HID echo failed!")
|
||||
else:
|
||||
print("USB HID echo timed out!")
|
||||
Reference in New Issue
Block a user