27 Commits

Author SHA1 Message Date
sakumisu
c1435548e7 release v0.10.2 2023-11-15 22:02:16 +08:00
sakumisu
a8d40eb706 fix ecm mac buffer size 2023-11-15 22:02:07 +08:00
zhugengyu
aeffaea016 add pusb2 port, fix issue for rt-thread, add msc storage demo for rt-thread 2023-11-15 16:48:07 +08:00
sakumisu
9ce7b0ceb7 fix rndis query & set msg wLength, only support one rndis device 2023-11-13 20:03:35 +08:00
sakumisu
1c31156a37 add ms os request 2023-11-13 19:51:53 +08:00
sakumisu
e795ab73a0 check and execute modeswitch first 2023-11-13 19:50:37 +08:00
sakumisu
5e689dfe15 fix class api name 2023-11-13 19:50:04 +08:00
sakumisu
d10cbd5daf check if token is active without errors, if token has errors, go to wakeup sem 2023-11-13 19:49:49 +08:00
sakumisu
40a019e063 add ecm host demo 2023-11-13 19:49:27 +08:00
sakumisu
2080cf1206 add usbh_set_interface api 2023-11-11 14:00:29 +08:00
Yang Xijing
ae521bf95c add nuvoton port(not release) 2023-11-05 14:38:26 +08:00
sakumisu
a2f7b67dc4 update config rst 2023-11-04 17:16:43 +08:00
sakumisu
e79319cac9 add cdc ecm host 2023-11-04 17:16:24 +08:00
sakumisu
7acb667e20 support usb modeswitch 2023-11-04 16:45:20 +08:00
sakumisu
a04b1fa551 add cdc ecm device 2023-11-04 16:44:02 +08:00
sakumisu
c37c60c7c7 add usbh_get_string_desc api 2023-11-04 15:24:15 +08:00
sakumisu
0738c09a4d check qtd active status to fix nbytes = 0 in nak or ping status 2023-11-03 22:18:58 +08:00
sakumisu
cf4dfde49d update quick start, add readthedocs yaml 2023-10-13 20:39:11 +08:00
Zhihong Chen
d4ba2eef57 osal: add USB_OSAL_WAITING_FOREVER for Semaphore and Queue use
- add USB_OSAL_WAITING_FOREVER for Semaphore and Queue use

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2023-10-12 14:38:13 +08:00
Chen Leeren
3d96f64f94 Fix possible errors in endpoint 0 datapid 2023-10-07 23:46:28 +08:00
sakumisu
a746eb4bb1 update demo version 2023-10-05 17:12:32 +08:00
sakumisu
c84e769f78 remove ununsed input variable 2023-09-30 22:01:12 +08:00
helloeagleyang
d11260ef67 [common] Avoid IAR compiling error on USB HOST stack
- Avoided using a structure with zero-length array as a field in another
  structure when IAR toolchain is used.

Signed-off-by: helloeagleyang <helloeagleyang@163.com>
2023-09-18 00:10:39 +08:00
Wayne Lin
e6193bd131 Revert original parameter. 2023-09-07 15:07:04 +08:00
Wayne Lin
dd1f1d3ba8 Update hcd-ehci, dcd-dwc2 and examples.
1. Add some example Msh commands.
2. Fix device enumeration on EXT hub.
3. Re-file some templates.
4. Extend end-point number of dwc2 device driver.
5. Re-file rndis_host implementation includes
   a. rt_mutex_take in ISR
   b. 2rd pmsg is unaligned issue.
   c. destroy u0 ethernet resource after removing dongle.
2023-09-07 15:07:04 +08:00
sakumisu
bc1e7c4bd5 ignore dwc2 EPENA check 2023-09-04 15:43:32 +08:00
Runcheng Lu
7d76b4bae1 third_party: rtthread: add rndis to adapt lwip2.1.2 2023-09-01 16:13:34 +08:00
59 changed files with 4402 additions and 417 deletions

35
.readthedocs.yaml Normal file
View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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')

View File

@@ -6,7 +6,7 @@
#ifndef CHERRYUSB_CONFIG_H
#define CHERRYUSB_CONFIG_H
#define CHERRYUSB_VERSION 0x001001
#define CHERRYUSB_VERSION 0x001002
/* ================ USB common Configuration ================ */
@@ -102,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
@@ -115,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

View File

@@ -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
View 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
View 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
View 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
View 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 */

View File

@@ -299,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);
}
}
@@ -312,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;
}
@@ -640,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;
}

View File

@@ -845,7 +845,7 @@ static void usbdev_msc_thread(void *argument)
int ret;
while (1) {
ret = usb_osal_mq_recv(g_usbd_msc.usbd_msc_mq, (uintptr_t *)&event, 0xffffffff);
ret = usb_osal_mq_recv(g_usbd_msc.usbd_msc_mq, (uintptr_t *)&event, USB_OSAL_WAITING_FOREVER);
if (ret < 0) {
continue;
}

View File

@@ -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");

View File

@@ -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);

View File

@@ -54,8 +54,8 @@ struct usbh_video {
extern "C" {
#endif
int usbh_video_get_cur(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_cur(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_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,

View File

@@ -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) {
@@ -269,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;
@@ -388,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);
@@ -418,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;

View File

@@ -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
};
/**

View File

@@ -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;

View File

@@ -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);

View File

@@ -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));

View File

@@ -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
View 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();
}

View File

@@ -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;

View File

@@ -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 };

View File

@@ -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++;
}
}

View File

@@ -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
View 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

View File

@@ -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
}

View File

@@ -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卡 512flash 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

View File

@@ -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

View File

@@ -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` 目录下,环境搭建完成后,即可编译使用。

View File

@@ -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` 中,如果不想要,可以直接删除。
- 正常使用。

View File

@@ -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

View File

@@ -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使用 fsdevF4/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` ,根据官方环境搭建完成后,即可编译使用。

View File

@@ -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;

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -656,17 +656,15 @@ void ehci_pipe_waitup(struct ehci_pipe *pipe)
}
}
static void ehci_qh_scan_qtds(struct ehci_qh_hw *qh)
static void ehci_qh_scan_qtds(struct ehci_qh_hw *qhead, struct ehci_qh_hw *qh)
{
struct ehci_qtd_hw *qtd;
ehci_qh_remove(qhead, qh);
qtd = EHCI_ADDR2QTD(qh->first_qtd);
while (qtd) {
// if (qtd->hw.token & QTD_TOKEN_STATUS_ACTIVE) {
// continue;
// }
qtd->urb->actual_length += (qtd->total_len - ((qtd->hw.token & QTD_TOKEN_NBYTES_MASK) >> QTD_TOKEN_NBYTES_SHIFT));
ehci_qtd_free(qtd);
@@ -679,43 +677,57 @@ 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 = qh->urb;
pipe = urb->pipe;
/* 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);
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);
qh->remove_in_iaad = 1;
while (qtd) {
if (qtd->hw.token & QTD_TOKEN_STATUS_ACTIVE) {
return;
}
qtd = EHCI_ADDR2QTD(qtd->hw.next_qtd);
}
EHCI_HCOR->usbcmd |= EHCI_USBCMD_IAAD;
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;
}
}
@@ -1151,7 +1163,7 @@ int usbh_submit_urb(struct usbh_urb *urb)
pipe = urb->pipe;
if (!pipe->inuse || !(EHCI_HCOR->portsc[0] & EHCI_PORTSC_CCS) || !pipe->hport->connected) {
if (!pipe->inuse /*|| !(EHCI_HCOR->portsc[pipe->hport->port-1] & EHCI_PORTSC_CCS)*/ || !pipe->hport->connected) {
return -ENODEV;
}

14
port/nuvoton/README.md Normal file
View 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
View 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
View 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
View 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
View 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;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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
View 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

View File

@@ -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()

View 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 */