summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build_tests.yml149
-rw-r--r--CMakeLists.txt8
-rw-r--r--Kconfig46
-rw-r--r--Kconfig.rtt38
-rw-r--r--Kconfig.rttpkg38
-rw-r--r--README.md13
-rw-r--r--README_zh.md13
-rw-r--r--SConscript39
-rw-r--r--cherryusb.cmake31
-rw-r--r--cherryusb_config_template.h7
-rw-r--r--class/adb/usbd_adb.c616
-rw-r--r--class/adb/usbd_adb.h68
-rw-r--r--class/adb/usbd_adb_cherrysh.c (renamed from demo/adb/cherrysh_port.c)113
-rw-r--r--class/adb/usbd_adb_sync.c932
-rw-r--r--class/aoa/usbh_aoa.c2
-rw-r--r--class/audio/usb_audio.h40
-rw-r--r--class/audio/usbd_audio.c146
-rw-r--r--class/audio/usbd_audio.h5
-rw-r--r--class/audio/usbh_audio.c33
-rw-r--r--class/cdc/usb_cdc.h86
-rw-r--r--class/cdc/usbd_cdc_ecm.c33
-rw-r--r--class/cdc/usbd_cdc_ncm.c545
-rw-r--r--class/cdc/usbd_cdc_ncm.h41
-rw-r--r--class/cdc/usbh_cdc_ecm.c22
-rw-r--r--class/cdc/usbh_cdc_ncm.c46
-rw-r--r--class/gs_usb/gs_usb.h319
-rw-r--r--class/gs_usb/usbd_gs_usb.c113
-rw-r--r--class/gs_usb/usbd_gs_usb.h18
-rw-r--r--class/hid/usbh_hid.c12
-rw-r--r--class/hub/usbh_hub.c24
-rw-r--r--class/msc/usbd_msc.c58
-rw-r--r--class/msc/usbh_msc.c15
-rw-r--r--class/mtp/usbd_mtp.h76
-rw-r--r--class/serial/usbh_cdc_acm.c2
-rw-r--r--class/serial/usbh_ch34x.c2
-rw-r--r--class/serial/usbh_cp210x.c2
-rw-r--r--class/serial/usbh_ftdi.c4
-rw-r--r--class/serial/usbh_pl2303.c8
-rw-r--r--class/serial/usbh_serial.c85
-rw-r--r--class/serial/usbh_serial.h13
-rw-r--r--class/tmc/usb_tmc.h149
-rw-r--r--class/tmc/usbd_tmc.c258
-rw-r--r--class/tmc/usbd_tmc.h27
-rw-r--r--class/vendor/net/usbh_asix.c46
-rw-r--r--class/vendor/net/usbh_rtl8152.c46
-rw-r--r--class/video/usbh_video.c2
-rw-r--r--class/wireless/usbd_rndis.c57
-rw-r--r--class/wireless/usbh_rndis.c283
-rw-r--r--common/usb_dc.h36
-rw-r--r--common/usb_def.h41
-rw-r--r--common/usb_hc.h17
-rw-r--r--common/usb_util.h20
-rw-r--r--common/usb_vfs.h150
-rw-r--r--core/usbd_core.c441
-rw-r--r--core/usbd_core.h21
-rw-r--r--core/usbh_core.c112
-rw-r--r--core/usbh_core.h7
-rw-r--r--core/usbotg_core.c9
-rw-r--r--demo/adb_template.c (renamed from demo/adb/usbd_adb_template.c)86
-rw-r--r--demo/audio_v1_mic_multichan_template.c94
-rw-r--r--demo/audio_v1_mic_speaker_multichan_template.c139
-rw-r--r--demo/audio_v2_mic_multichan_template.c97
-rw-r--r--demo/audio_v2_mic_speaker_multichan_template.c162
-rw-r--r--demo/audio_v2_speaker_multichan_template.c140
-rw-r--r--demo/bootuf2/msc_bootuf2_template.c65
-rw-r--r--demo/cdc_acm_hid_msc_template.c81
-rw-r--r--demo/cdc_acm_mavlink_template.c63
-rw-r--r--demo/cdc_acm_msc_template.c76
-rw-r--r--demo/cdc_acm_multi_template.c80
-rw-r--r--demo/cdc_acm_rttchardev_template.c63
-rw-r--r--demo/cdc_acm_template.c65
-rw-r--r--demo/cdc_ecm_template.c65
-rw-r--r--demo/cdc_ncm_template.c405
-rw-r--r--demo/cdc_rndis_template.c65
-rw-r--r--demo/display/usbdisplay_template.c73
-rw-r--r--demo/gs_usb_template.c244
-rw-r--r--demo/hid_custom_inout_template.c124
-rw-r--r--demo/hid_keyboard_template.c2
-rw-r--r--demo/midi_template.c106
-rw-r--r--demo/msc_ram_template.c65
-rw-r--r--demo/tmc/tmc_template.c275
-rw-r--r--[-rwxr-xr-x]demo/tmc/tmcdev1.png (renamed from docs/en/support/img/tmcdev1.png)bin578670 -> 578670 bytes
-rw-r--r--[-rwxr-xr-x]demo/tmc/tmcdev2.png (renamed from docs/en/support/img/tmcdev2.png)bin218648 -> 218648 bytes
-rw-r--r--demo/video_audiov1_hid_template.c142
-rw-r--r--demo/video_static_h264_template.c95
-rw-r--r--demo/video_static_mjpeg_template.c95
-rw-r--r--demo/video_static_yuyv_template.c101
-rw-r--r--demo/winusb1.0_template.c94
-rw-r--r--demo/winusb2.0_cdc_template.c90
-rw-r--r--demo/winusb2.0_template.c94
-rw-r--r--docs/assets/allwinnertech.jpgbin0 -> 67642 bytes
-rw-r--r--docs/assets/listenai.jpgbin0 -> 43493 bytes
-rw-r--r--docs/assets/wch.jpgbin0 -> 37268 bytes
-rwxr-xr-xdocs/en/api/api_device.rst18
-rwxr-xr-xdocs/en/support/index.rst5
-rw-r--r--docs/zh/api/api_device.rst19
-rw-r--r--docs/zh/api/api_host.rst14
-rw-r--r--docs/zh/demo/usbd_adb.rst18
-rw-r--r--docs/zh/quick_start/demo.rst56
-rw-r--r--docs/zh/quick_start/q&a.rst1
-rw-r--r--docs/zh/show/img/wch_speed.jpgbin0 -> 75341 bytes
-rw-r--r--docs/zh/show/index.rst3
-rw-r--r--docs/zh/support/img/tmcdev1.pngbin578670 -> 0 bytes
-rw-r--r--docs/zh/support/img/tmcdev2.pngbin218648 -> 0 bytes
-rw-r--r--docs/zh/support/index.rst5
-rw-r--r--docs/zh/version.rst287
-rw-r--r--osal/idf/usb_osal_idf.c2
-rw-r--r--osal/usb_osal_freertos.c29
-rw-r--r--osal/usb_osal_rtthread.c4
-rw-r--r--osal/usb_osal_zephyr.c16
-rw-r--r--platform/blackmagic/bmp_port_cdc_acm.c18
-rw-r--r--platform/daplink/dap_main.c41
-rw-r--r--platform/fatfs/usbd_fatfs_mtp.c351
-rw-r--r--platform/fatfs/usbh_fatfs.c11
-rw-r--r--platform/fatfs/vfs_fatfs_port.c504
-rw-r--r--platform/idf/usbh_fatfs.c5
-rw-r--r--platform/rtthread/rt_usbd_adb_msh.c (renamed from platform/rtthread/rt_usbd_adb.c)87
-rw-r--r--platform/rtthread/rt_usbd_serial.c1
-rw-r--r--platform/rtthread/rt_usbh_msc.c11
-rw-r--r--platform/rtthread/rt_vfs_dfs.c310
-rw-r--r--platform/zephyr/usbh_msc_disk.c126
-rw-r--r--port/aic/README.md5
-rw-r--r--port/aic/usb_glue_aic.c (renamed from port/ehci/usb_glue_aic.c)0
-rw-r--r--port/bouffalolab/README.md2
-rw-r--r--port/bouffalolab/usb_glue_bouffalo.c (renamed from port/ehci/usb_glue_bouffalo.c)18
-rw-r--r--port/ch32/README.md16
-rw-r--r--port/ch32/ch32fs/usb_ch32_usbfs_reg.h409
-rw-r--r--port/ch32/ch32fs/usb_dc_usbfs.c412
-rw-r--r--port/ch32/ch32hs/usb_ch32_usbhs_reg.h564
-rw-r--r--port/ch32/ch32hs/usb_dc_usbhs.c428
-rw-r--r--port/ch32/ch58x/usb_ch585_usbhs_dc.c526
-rw-r--r--port/ch32/ch58x/usb_ch585_usbhs_reg.h455
-rw-r--r--port/ch32/ch58x/usb_ch58x_dc_usbfs.c640
-rw-r--r--port/ch32/ch58x/usb_ch58x_usbfs_reg.h249
-rw-r--r--port/chipidea/usb_dc_chipidea.c9
-rw-r--r--port/dwc2/usb_dc_dwc2.c44
-rw-r--r--port/dwc2/usb_dwc2_param.h11
-rw-r--r--port/dwc2/usb_dwc2_reg.h5
-rw-r--r--port/dwc2/usb_glue_gd.c94
-rw-r--r--port/dwc2/usb_hc_dwc2.c32
-rw-r--r--port/ehci/README.md8
-rw-r--r--port/ehci/usb_glue_intel.c55
-rw-r--r--port/ehci/usb_glue_ma35d0.c117
-rw-r--r--port/ehci/usb_glue_nuc980.c62
-rw-r--r--port/ehci/usb_hc_ehci.c131
-rw-r--r--port/ehci/usb_hc_ehci.h1
-rw-r--r--port/fsdev/README.md8
-rw-r--r--port/fsdev/usb_dc_fsdev.c49
-rw-r--r--port/fsdev/usb_fsdev_reg.h381
-rw-r--r--port/fsdev/usb_glue_nation.c191
-rw-r--r--port/hpmicro/usb_dc_hpm.c5
-rw-r--r--port/kinetis/usb_dc_kinetis.c9
-rw-r--r--port/kinetis/usb_glue_mm32.c36
-rw-r--r--port/musb/README.md1
-rw-r--r--port/musb/usb_dc_musb.c13
-rw-r--r--port/musb/usb_glue_bk.c4
-rw-r--r--port/musb/usb_glue_ti.c4
-rw-r--r--port/musb/usb_hc_musb.c156
-rw-r--r--port/nuvoton/README.md8
-rw-r--r--port/nuvoton/usb_dc_usbfs.c455
-rw-r--r--port/ohci/README.md4
-rw-r--r--port/ohci/usb_hc_ohci.c12
-rw-r--r--port/pusb2/README.md20
-rw-r--r--port/pusb2/freertos/usb_config.h13
-rw-r--r--port/pusb2/freertos/usb_dc_glue_phytium.c118
-rw-r--r--port/pusb2/freertos/usb_glue_phytium.c369
-rw-r--r--port/pusb2/freertos/usb_hc_glue_phytium.c102
-rw-r--r--port/pusb2/libpusb2_dc_a32_hardfp.abin171332 -> 287036 bytes
-rw-r--r--port/pusb2/libpusb2_dc_a32_softfp_crypto-neon-fp-armv8.abin0 -> 287036 bytes
-rw-r--r--port/pusb2/libpusb2_dc_a32_softfp_crypto_neon.abin171328 -> 0 bytes
-rw-r--r--port/pusb2/libpusb2_dc_a32_softfp_neon.abin325436 -> 0 bytes
-rw-r--r--port/pusb2/libpusb2_dc_a64.abin141528 -> 321072 bytes
-rw-r--r--port/pusb2/libpusb2_hc_a32_hardfp.abin923220 -> 289950 bytes
-rw-r--r--port/pusb2/libpusb2_hc_a32_softfp_crypto-neon-fp-armv8.abin0 -> 289950 bytes
-rw-r--r--port/pusb2/libpusb2_hc_a32_softfp_crypto_neon.abin923192 -> 0 bytes
-rw-r--r--port/pusb2/libpusb2_hc_a32_softfp_neon.abin328504 -> 0 bytes
-rw-r--r--port/pusb2/libpusb2_hc_a64.abin1179500 -> 323334 bytes
-rw-r--r--port/pusb2/libpusb2_otg_a32_hardfp.abin0 -> 311864 bytes
-rw-r--r--port/pusb2/libpusb2_otg_a32_softfp_crypto-neon-fp-armv8.abin0 -> 311864 bytes
-rw-r--r--port/pusb2/libpusb2_otg_a64.abin0 -> 341524 bytes
-rw-r--r--port/pusb2/rt-thread/usb_config.h11
-rw-r--r--port/pusb2/rt-thread/usb_dc_glue_phytium.c5
-rw-r--r--port/pusb2/standalone/usb_config.h10
-rw-r--r--port/pusb2/standalone/usb_dc_glue_phytium.c29
-rw-r--r--port/pusb3/README.md57
-rw-r--r--port/pusb3/freertos/usb_config.h198
-rw-r--r--port/pusb3/freertos/usb_glue_dc_phytium.c38
-rw-r--r--port/pusb3/freertos/usb_glue_hc_phytium.c43
-rw-r--r--port/pusb3/freertos/usb_glue_phytium.c448
-rw-r--r--port/pusb3/libpusb3_dc_a64.abin0 -> 222348 bytes
-rw-r--r--port/pusb3/libpusb3_hc_a64.abin0 -> 245310 bytes
-rw-r--r--port/pusb3/libpusb3_otg_a64.abin0 -> 450332 bytes
-rw-r--r--port/pusb3/standalone/usb_config.h130
-rw-r--r--port/pusb3/standalone/usb_glue_phytium.c228
-rw-r--r--port/rp2040/usb_hc_rp2040.c14
-rw-r--r--port/sunxi/README.md1
-rw-r--r--port/wch/README.md24
-rw-r--r--port/wch/usbfs/usb_dc_usbfs.c452
-rw-r--r--port/wch/usbfs/usb_hc_usbfs.c641
-rw-r--r--port/wch/usbfs/usb_usbfs_reg.h356
-rw-r--r--port/wch/usbhs/usb_dc_usbhs.c443
-rw-r--r--port/wch/usbhs/usb_hc_usbhs.c827
-rw-r--r--port/wch/usbhs/usb_usbhs_reg.h559
-rw-r--r--port/xhci/phytium/README.md8
-rw-r--r--[-rwxr-xr-x]port/xhci/phytium/freertos/usb_config.h248
-rw-r--r--port/xhci/phytium/freertos/usb_glue_phytium.c78
-rw-r--r--port/xhci/phytium/freertos/usb_glue_phytium_common.c181
-rw-r--r--port/xhci/phytium/freertos/usb_glue_phytium_common.h64
-rw-r--r--port/xhci/phytium/freertos/usb_glue_phytium_pcie.c161
-rw-r--r--[-rwxr-xr-x]port/xhci/phytium/freertos/usb_glue_phytium_plat.c130
-rw-r--r--port/xhci/phytium/libxhci_a32_hardfp.abin52784 -> 252318 bytes
-rw-r--r--port/xhci/phytium/libxhci_a32_softfp_crypto-neon-fp-armv8.abin0 -> 252314 bytes
-rw-r--r--port/xhci/phytium/libxhci_a32_softfp_crypto_neon.abin73868 -> 0 bytes
-rw-r--r--port/xhci/phytium/libxhci_a32_softfp_neon.abin104852 -> 0 bytes
-rw-r--r--port/xhci/phytium/libxhci_a64.abin62300 -> 224730 bytes
-rw-r--r--port/xhci/phytium/rt-thread/usb_config.h2
-rw-r--r--port/xhci/phytium/rt-thread/usb_glue_phytium.c13
-rw-r--r--port/xhci/phytium/rt-thread/usb_glue_phytium_plat.c2
-rw-r--r--tests/hpmicro/CMakeLists.txt8
-rw-r--r--third_party/libscpi/inc/scpi/cc.h211
-rw-r--r--third_party/libscpi/inc/scpi/config.h291
-rw-r--r--third_party/libscpi/inc/scpi/constants.h62
-rw-r--r--third_party/libscpi/inc/scpi/error.h208
-rw-r--r--third_party/libscpi/inc/scpi/expression.h62
-rw-r--r--third_party/libscpi/inc/scpi/ieee488.h94
-rw-r--r--third_party/libscpi/inc/scpi/minimal.h69
-rw-r--r--third_party/libscpi/inc/scpi/parser.h151
-rw-r--r--third_party/libscpi/inc/scpi/scpi.h51
-rw-r--r--third_party/libscpi/inc/scpi/types.h459
-rw-r--r--third_party/libscpi/inc/scpi/units.h60
-rw-r--r--third_party/libscpi/inc/scpi/utils.h62
-rw-r--r--third_party/libscpi/src/error.c237
-rw-r--r--third_party/libscpi/src/expression.c316
-rw-r--r--third_party/libscpi/src/fifo.c146
-rw-r--r--third_party/libscpi/src/fifo_private.h61
-rw-r--r--third_party/libscpi/src/ieee488.c424
-rw-r--r--third_party/libscpi/src/lexer.c935
-rw-r--r--third_party/libscpi/src/lexer_private.h69
-rw-r--r--third_party/libscpi/src/minimal.c215
-rw-r--r--third_party/libscpi/src/parser.c1834
-rw-r--r--third_party/libscpi/src/parser_private.h56
-rw-r--r--third_party/libscpi/src/scpi.g141
-rw-r--r--third_party/libscpi/src/units.c512
-rw-r--r--third_party/libscpi/src/utils.c1142
-rw-r--r--third_party/libscpi/src/utils_private.h128
245 files changed, 23280 insertions, 7247 deletions
diff --git a/.github/workflows/build_tests.yml b/.github/workflows/build_tests.yml
index 929762ea..fd53d5f0 100644
--- a/.github/workflows/build_tests.yml
+++ b/.github/workflows/build_tests.yml
@@ -2,13 +2,7 @@ name: Build Tests
on:
push:
- branches:
- - master
- - release/v1.5
pull_request:
- branches:
- - master
- - release/v1.5
jobs:
build_hpmicro:
@@ -33,10 +27,10 @@ jobs:
- name: Build hpm demo
run: |
- cd tests/hpmicro
export HPM_SDK_BASE=~/hpm_sdk
export GNURISCV_TOOLCHAIN_PATH=~/rv32imac_zicsr_zifencei_multilib_b_ext-linux
export HPM_SDK_TOOLCHAIN_VARIANT=
+ cd tests/hpmicro
cmake -S . -B build -GNinja -DBOARD=hpm6800evk -DHPM_BUILD_TYPE=flash_sdram_xip -DCMAKE_BUILD_TYPE=debug -DEXTRA_C_FLAGS="-Werror";cmake --build build
build_bouffalolab:
@@ -56,13 +50,13 @@ jobs:
- name: Download RISC-V toolchain
run: |
cd ~
- git clone https://github.com/bouffalolab/toolchain_gcc_t-head_linux.git
+ git clone https://github.com/CherryUSB/toolchain_gcc_t-head_linux.git
- name: Build bouffalo demo
run: |
- cd tests/bouffalolab
export BL_SDK_BASE=~/bouffalo_sdk
export PATH=~/toolchain_gcc_t-head_linux/bin:$PATH
+ cd tests/bouffalolab
make CHIP=bl616 BOARD=bl616dk -j12
build_espressif:
@@ -72,9 +66,9 @@ jobs:
runs-on: ubuntu-latest
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- - uses: actions/checkout@v3
- with:
- submodules: 'recursive'
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
- name: Build espressif demo
shell: bash
run: |
@@ -85,6 +79,9 @@ jobs:
build_rtthread:
runs-on: ubuntu-latest
steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
- name: Set up Python
uses: actions/setup-python@main
with:
@@ -111,16 +108,136 @@ jobs:
- name: Build rtthread demo
run: |
+ rm -rf ~/sdk-bsp-stm32h7r-realthread-artpi2/projects/art_pi2_cherryusb_usbhost/packages/CherryUSB-latest
+ cp ../CherryUSB ~/sdk-bsp-stm32h7r-realthread-artpi2/projects/art_pi2_cherryusb_usbhost/packages/CherryUSB-latest -r
+ rm -rf ~/sdk-bsp-stm32h7r-realthread-artpi2/projects/art_pi2_cherryusb_usbdev_cdc_acm/packages/CherryUSB-latest
+ cp ../CherryUSB ~/sdk-bsp-stm32h7r-realthread-artpi2/projects/art_pi2_cherryusb_usbdev_cdc_acm/packages/CherryUSB-latest -r
cd ~/sdk-bsp-stm32h7r-realthread-artpi2
source ~/.env/env.sh
export RTT_ROOT=~/sdk-bsp-stm32h7r-realthread-artpi2/rt-thread
export RTT_CC=gcc
export RTT_EXEC_PATH=/opt/arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-eabi/bin
cd ~/sdk-bsp-stm32h7r-realthread-artpi2/projects/art_pi2_cherryusb_usbdev_cdc_acm
- rm -rf packages/CherryUSB-latest
- pkgs --update
scons -j8
cd ~/sdk-bsp-stm32h7r-realthread-artpi2/projects/art_pi2_cherryusb_usbhost
- rm -rf packages/CherryUSB-latest
- pkgs --update
scons -j8
+
+ build_wch:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Install dependencies
+ run: sudo apt-get update && sudo apt-get install -y make
+
+ - name: Download wch demo repo
+ run: |
+ cd ~
+ git clone https://github.com/CherryUSB/wch-support-cherryusb.git --recursive
+
+ - name: Download RISC-V toolchain
+ run: |
+ cd ~
+ wget https://github.com/CherryUSB/wch-support-cherryusb/releases/download/v1.0/MRS_Toolchain_Linux_X64_V240.tar.xz
+ tar -xJf MRS_Toolchain_Linux_X64_V240.tar.xz
+
+ - name: Build wch demo
+ run: |
+ rm -rf ~/wch-support-cherryusb/CherryUSB
+ cp ../CherryUSB ~/wch-support-cherryusb/CherryUSB -r
+ export PATH=~/Toolchain/riscv32-wch-elf-gcc/bin:$PATH
+ cd ~/wch-support-cherryusb
+ make all -j8 CHIP=ch32h417qeu6 IP=usbfs
+ make clear
+ make all -j8 CHIP=ch32h417qeu6 IP=usbhs
+
+ build_sifli:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Install dependencies
+ run: sudo apt-get install git wget flex bison gperf cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0
+
+ - name: Download sifli_sdk
+ run: |
+ cd ~
+ git clone https://github.com/OpenSiFli/SiFli-SDK --recursive -b release/v2.5
+
+ - name: Build sifli demo
+ run: |
+ rm -rf ~/SiFli-SDK/external/cherryusb
+ cp ../CherryUSB ~/SiFli-SDK/external/cherryusb -r
+ cd ~/SiFli-SDK
+ curl -LsSf https://astral.sh/uv/install.sh | sh
+ ./install.sh
+ . export.sh
+ cd ~/SiFli-SDK/example/cherryusb/device/cdc_hid_msc/project
+ scons --board=sf32lb52-lcd_n16r8 -j8
+ cd ~/SiFli-SDK/example/cherryusb/host/msc_host/project
+ scons --board=sf32lb52-lcd_n16r8 -j8
+
+ build_phytium:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Install dependencies
+ run: sudo apt-get update && sudo apt-get install -y make
+
+ - name: Download phytium-free-rtos-sdk
+ run: |
+ cd ~
+ git config --global http.version HTTP/1.1
+ git config --global http.postBuffer 524288000
+ git clone https://gitee.com/phytium_embedded/phytium-free-rtos-sdk.git
+ cd ~/phytium-free-rtos-sdk
+ git checkout 1e6f4ca501d9cd92a99204193939e45df6b8502d
+ ./install.py
+
+ - name: Download toolchain
+ run: |
+ cd ~
+ git clone https://github.com/CherryUSB/phytium_env_ubuntu_x64
+
+ - name: Build phytium demo
+ run: |
+ rm -rf ~/phytium-free-rtos-sdk/standalone/third-party/cherryusb/class
+ rm -rf ~/phytium-free-rtos-sdk/standalone/third-party/cherryusb/core
+ rm -rf ~/phytium-free-rtos-sdk/standalone/third-party/cherryusb/common
+ rm -rf ~/phytium-free-rtos-sdk/standalone/third-party/cherryusb/osal
+ rm -rf ~/phytium-free-rtos-sdk/standalone/third-party/cherryusb/port
+ rm -rf ~/phytium-free-rtos-sdk/standalone/third-party/cherryusb/demo
+ cp -r ../CherryUSB/class ~/phytium-free-rtos-sdk/standalone/third-party/cherryusb/class
+ cp -r ../CherryUSB/core ~/phytium-free-rtos-sdk/standalone/third-party/cherryusb/core
+ cp -r ../CherryUSB/common ~/phytium-free-rtos-sdk/standalone/third-party/cherryusb/common
+ cp -r ../CherryUSB/osal ~/phytium-free-rtos-sdk/standalone/third-party/cherryusb/osal
+ cp -r ../CherryUSB/port ~/phytium-free-rtos-sdk/standalone/third-party/cherryusb/port
+ cp -r ../CherryUSB/demo ~/phytium-free-rtos-sdk/standalone/third-party/cherryusb/demo
+ cd ~/phytium_env_ubuntu_x64
+ ./setup_dev.py
+ source /etc/profile.d/phytium_dev.sh
+ mkdir -p ~/output
+ cd ~/phytium-free-rtos-sdk/example/peripheral/usb/usb_device
+ make load_kconfig LOAD_CONFIG_NAME=pe2204_aarch64_demo_pusb2_lib
+ make clean image USR_BOOT_DIR=~/output
+ make load_kconfig LOAD_CONFIG_NAME=pe2204_aarch32_demo_pusb2_hardfp_lib
+ make clean image USR_BOOT_DIR=~/output
+ make load_kconfig LOAD_CONFIG_NAME=pe2204_aarch32_demo_pusb2_softfp_lib
+ make clean image USR_BOOT_DIR=~/output
+ cd ~/phytium-free-rtos-sdk/example/peripheral/usb/usb_host
+ make load_kconfig LOAD_CONFIG_NAME=pe2204_aarch64_demo_xhci
+ make clean image USR_BOOT_DIR=~/output
+ make load_kconfig LOAD_CONFIG_NAME=pe2204_aarch32_demo_xhci_hardfp
+ make clean image USR_BOOT_DIR=~/output
+ make load_kconfig LOAD_CONFIG_NAME=pe2204_aarch32_demo_xhci_softfp
+ make clean image USR_BOOT_DIR=~/output
+ make load_kconfig LOAD_CONFIG_NAME=pe2204_aarch64_demo_pusb2
+ make clean image USR_BOOT_DIR=~/output
+ make load_kconfig LOAD_CONFIG_NAME=pe2204_aarch32_demo_pusb2_hardfp
+ make clean image USR_BOOT_DIR=~/output
+ make load_kconfig LOAD_CONFIG_NAME=pe2204_aarch32_demo_pusb2_softfp
+ make clean image USR_BOOT_DIR=~/output \ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index be652aa8..d8971a68 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,7 +11,11 @@ if(BL_SDK_BASE)
set(CONFIG_CHERRYUSB_DEVICE_AUDIO 1)
set(CONFIG_CHERRYUSB_DEVICE_VIDEO 1)
set(CONFIG_CHERRYUSB_DEVICE_DFU 1)
+ set(CONFIG_CHERRYUSB_DEVICE_TMC 1)
+ set(CONFIG_CHERRYUSB_DEVICE_DISPLAY 1)
set(CONFIG_CHERRYUSB_DEVICE_GAMEPAD 1)
+ set(CONFIG_CHERRYUSB_DEVICE_ADB 1)
+ set(CONFIG_CHERRYUSB_DEVICE_GS_USB 1)
set(CONFIG_CHERRYUSB_HOST_CDC_ACM 1)
set(CONFIG_CHERRYUSB_HOST_CDC_ECM 1)
@@ -185,7 +189,11 @@ elseif(HPM_SDK_BASE)
set(CONFIG_CHERRYUSB_DEVICE_AUDIO 1)
set(CONFIG_CHERRYUSB_DEVICE_VIDEO 1)
set(CONFIG_CHERRYUSB_DEVICE_DFU 1)
+ set(CONFIG_CHERRYUSB_DEVICE_TMC 1)
+ set(CONFIG_CHERRYUSB_DEVICE_DISPLAY 1)
set(CONFIG_CHERRYUSB_DEVICE_GAMEPAD 1)
+ set(CONFIG_CHERRYUSB_DEVICE_ADB 1)
+ set(CONFIG_CHERRYUSB_DEVICE_GS_USB 1)
set(CONFIG_CHERRYUSB_HOST_CDC_ACM 1)
set(CONFIG_CHERRYUSB_HOST_CDC_ECM 1)
diff --git a/Kconfig b/Kconfig
index ad48c93e..5b2e46c1 100644
--- a/Kconfig
+++ b/Kconfig
@@ -78,8 +78,12 @@ if CHERRYUSB
bool "rp2040"
config CHERRYUSB_DEVICE_RENESAS
bool "renesas"
- config CHERRYUSB_DEVICE_CH32
- bool "ch32"
+ config CHERRYUSB_DEVICE_CH32_USBFS
+ bool "ch32_usbfs"
+ config CHERRYUSB_DEVICE_CH32_USBHS
+ bool "ch32_usbhs"
+ config CHERRYUSB_DEVICE_CH32_USBSS
+ bool "ch32_usbss"
config CHERRYUSB_DEVICE_PUSB2
bool "pusb2"
endchoice
@@ -122,7 +126,6 @@ if CHERRYUSB
config CHERRYUSB_DEVICE_CDC_NCM
bool
prompt "Enable usb cdc ncm device"
- depends on !IDF_CMAKE
default n
config CHERRYUSB_DEVICE_MTP
@@ -135,6 +138,21 @@ if CHERRYUSB
prompt "Enable usb adb device"
default n
+ config CHERRYUSB_DEVICE_ADB_CHERRYSH
+ bool
+ prompt "Enable usb adb shell service with cherrysh"
+ default n
+
+ config CHERRYUSB_DEVICE_ADB_SYNC
+ bool
+ prompt "Enable usb adb sync service"
+ default n
+
+ config CHERRYUSB_DEVICE_ADB_SYNC_FATFS
+ bool
+ prompt "Enable usb adb sync service with fatfs"
+ default n
+
config CHERRYUSB_DEVICE_DFU
bool
prompt "Enable usb dfu device"
@@ -145,6 +163,16 @@ if CHERRYUSB
prompt "Enable usb display device"
default n
+ config CHERRYUSB_DEVICE_TMC
+ bool
+ prompt "Enable usb tmc device"
+ default n
+
+ config CHERRYUSB_DEVICE_GS_USB
+ bool
+ prompt "Enable usb gs_usb device"
+ default n
+
config USBDEV_REQUEST_BUFFER_LEN
int
prompt "Set device control transfer max buffer size"
@@ -269,10 +297,6 @@ if CHERRYUSB
bool "ehci_aic"
config CHERRYUSB_HOST_EHCI_MCX
bool "ehci_mcx"
- config CHERRYUSB_HOST_EHCI_NUC980
- bool "ehci_nuc980"
- config CHERRYUSB_HOST_EHCI_MA35D0
- bool "ehci_ma35d0"
config CHERRYUSB_HOST_EHCI_CUSTOM
bool "ehci_custom"
config CHERRYUSB_HOST_DWC2_ST
@@ -309,12 +333,16 @@ if CHERRYUSB
bool "xhci"
config CHERRYUSB_HOST_KINETIS_MCX
bool "kinetis_mcx"
- config CHERRYUSB_HOST_KINETIS_MM32
- bool "kinetis_mm32"
config CHERRYUSB_HOST_KINETIS_CUSTOM
bool "kinetis_custom"
config CHERRYUSB_HOST_RP2040
bool "rp2040"
+ config CHERRYUSB_HOST_CH32_USBFS
+ bool "ch32_usbfs"
+ config CHERRYUSB_HOST_CH32_USBHS
+ bool "ch32_usbhs"
+ config CHERRYUSB_HOST_CH32_USBSS
+ bool "ch32_usbss"
endchoice
config CHERRYUSB_HOST_CDC_ACM
diff --git a/Kconfig.rtt b/Kconfig.rtt
index 62da4e34..a9ba6924 100644
--- a/Kconfig.rtt
+++ b/Kconfig.rtt
@@ -64,8 +64,6 @@ if RT_USING_CHERRYUSB
bool "chipidea_custom"
config RT_CHERRYUSB_DEVICE_KINETIS_MCX
bool "kinetis_mcx"
- config RT_CHERRYUSB_DEVICE_KINETIS_MM32
- bool "kinetis_mm32"
config RT_CHERRYUSB_DEVICE_KINETIS_CUSTOM
bool "kinetis_custom"
config RT_CHERRYUSB_DEVICE_BL
@@ -78,8 +76,12 @@ if RT_USING_CHERRYUSB
bool "rp2040"
config RT_CHERRYUSB_DEVICE_RENESAS
bool "renesas"
- config RT_CHERRYUSB_DEVICE_CH32
- bool "ch32"
+ config RT_CHERRYUSB_DEVICE_CH32_USBFS
+ bool "ch32_usbfs"
+ config RT_CHERRYUSB_DEVICE_CH32_USBHS
+ bool "ch32_usbhs"
+ config RT_CHERRYUSB_DEVICE_CH32_USBSS
+ bool "ch32_usbss"
config RT_CHERRYUSB_DEVICE_PUSB2
bool "pusb2"
config RT_CHERRYUSB_DEVICE_NRF5X
@@ -136,6 +138,14 @@ if RT_USING_CHERRYUSB
prompt "Enable usb adb device"
default n
+ config RT_CHERRYUSB_DEVICE_ADB_SYNC
+ bool
+ prompt "Enable usb adb sync service"
+ default n
+ select RT_USING_DFS
+ select RT_USING_DFS_ELMFAT
+ select DFS_USING_POSIX
+
config RT_CHERRYUSB_DEVICE_DFU
bool
prompt "Enable usb dfu device"
@@ -146,6 +156,16 @@ if RT_USING_CHERRYUSB
prompt "Enable usb display device"
default n
+ config RT_CHERRYUSB_DEVICE_TMC
+ bool
+ prompt "Enable usb tmc device"
+ default n
+
+ config RT_CHERRYUSB_DEVICE_GS_USB
+ bool
+ prompt "Enable usb gs_usb device"
+ default n
+
config RT_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
bool
prompt "Enable chardev for cdc acm device"
@@ -298,10 +318,6 @@ if RT_USING_CHERRYUSB
bool "ehci_aic"
config RT_CHERRYUSB_HOST_EHCI_MCX
bool "ehci_mcx"
- config RT_CHERRYUSB_HOST_EHCI_NUC980
- bool "ehci_nuc980"
- config RT_CHERRYUSB_HOST_EHCI_MA35D0
- bool "ehci_ma35d0"
config RT_CHERRYUSB_HOST_EHCI_CUSTOM
bool "ehci_custom"
config RT_CHERRYUSB_HOST_DWC2_ST
@@ -336,6 +352,12 @@ if RT_USING_CHERRYUSB
bool "xhci"
config RT_CHERRYUSB_HOST_RP2040
bool "rp2040"
+ config RT_CHERRYUSB_HOST_CH32_USBFS
+ bool "ch32_usbfs"
+ config RT_CHERRYUSB_HOST_CH32_USBHS
+ bool "ch32_usbhs"
+ config RT_CHERRYUSB_HOST_CH32_USBSS
+ bool "ch32_usbss"
endchoice
config RT_CHERRYUSB_HOST_CDC_ACM
diff --git a/Kconfig.rttpkg b/Kconfig.rttpkg
index 0f534a9f..1caf86ef 100644
--- a/Kconfig.rttpkg
+++ b/Kconfig.rttpkg
@@ -65,8 +65,6 @@ if PKG_USING_CHERRYUSB
bool "chipidea_custom"
config PKG_CHERRYUSB_DEVICE_KINETIS_MCX
bool "kinetis_mcx"
- config PKG_CHERRYUSB_DEVICE_KINETIS_MM32
- bool "kinetis_mm32"
config PKG_CHERRYUSB_DEVICE_KINETIS_CUSTOM
bool "kinetis_custom"
config PKG_CHERRYUSB_DEVICE_BL
@@ -79,8 +77,12 @@ if PKG_USING_CHERRYUSB
bool "rp2040"
config PKG_CHERRYUSB_DEVICE_RENESAS
bool "renesas"
- config PKG_CHERRYUSB_DEVICE_CH32
- bool "ch32"
+ config PKG_CHERRYUSB_DEVICE_CH32_USBFS
+ bool "ch32_usbfs"
+ config PKG_CHERRYUSB_DEVICE_CH32_USBHS
+ bool "ch32_usbhs"
+ config PKG_CHERRYUSB_DEVICE_CH32_USBSS
+ bool "ch32_usbss"
config PKG_CHERRYUSB_DEVICE_PUSB2
bool "pusb2"
endchoice
@@ -135,16 +137,34 @@ if PKG_USING_CHERRYUSB
prompt "Enable usb adb device"
default n
+ config PKG_CHERRYUSB_DEVICE_ADB_SYNC
+ bool
+ prompt "Enable usb adb sync service"
+ default n
+ select RT_USING_DFS
+ select RT_USING_DFS_ELMFAT
+ select DFS_USING_POSIX
+
config PKG_CHERRYUSB_DEVICE_DFU
bool
prompt "Enable usb dfu device"
default n
+ config PKG_CHERRYUSB_DEVICE_GS_USB
+ bool
+ prompt "Enable usb gs_usb device"
+ default n
+
config PKG_CHERRYUSB_DEVICE_DISPLAY
bool
prompt "Enable usb display device"
default n
+ config PKG_CHERRYUSB_DEVICE_TMC
+ bool
+ prompt "Enable usb tmc device"
+ default n
+
config PKG_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV
bool
prompt "Enable chardev for cdc acm device"
@@ -297,10 +317,6 @@ if PKG_USING_CHERRYUSB
bool "ehci_aic"
config PKG_CHERRYUSB_HOST_EHCI_MCX
bool "ehci_mcx"
- config PKG_CHERRYUSB_HOST_EHCI_NUC980
- bool "ehci_nuc980"
- config PKG_CHERRYUSB_HOST_EHCI_MA35D0
- bool "ehci_ma35d0"
config PKG_CHERRYUSB_HOST_EHCI_CUSTOM
bool "ehci_custom"
config PKG_CHERRYUSB_HOST_DWC2_ST
@@ -335,6 +351,12 @@ if PKG_USING_CHERRYUSB
bool "xhci"
config PKG_CHERRYUSB_HOST_RP2040
bool "rp2040"
+ config PKG_CHERRYUSB_HOST_CH32_USBFS
+ bool "ch32_usbfs"
+ config PKG_CHERRYUSB_HOST_CH32_USBHS
+ bool "ch32_usbhs"
+ config PKG_CHERRYUSB_HOST_CH32_USBSS
+ bool "ch32_usbss"
endchoice
config PKG_CHERRYUSB_HOST_CDC_ACM
diff --git a/README.md b/README.md
index 5f2563a7..fb8c66d9 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ Considering USB performance requirements to reach theoretical USB hardware bandw
- No length restrictions, facilitating hardware DMA interfacing and maximizing DMA advantages
- Packetization handled in interrupt context
-Performance show:https://cherryusb.cherry-embedded.org/show/
+Performance show:https://cherryusb.readthedocs.io/en/latest/show/index.html
## Directory Structure
@@ -77,10 +77,11 @@ CherryUSB Device Stack has the following functions:
- Support Test and Measurement Class (TMC)
- Support WINUSB1.0, WINUSB2.0, WEBUSB, BOS
- Support Vendor display ([xfz1986_usb_graphic_driver](https://github.com/chuanjinpang/win10_idd_xfz1986_usb_graphic_driver_display))
+- Support Linux GS USB class
- Support Vendor class
- Support UF2
-- Support Android Debug Bridge (Only support shell)
-- Support multi device with the same USB IP
+- Support Android Debug Bridge (support shell and sync)
+- Support multi device USB IP (IP can be different)
CherryUSB Device Stack resource usage (GCC 10.2 with -O2, disable log):
@@ -122,7 +123,7 @@ CherryUSB Host Stack has the following functions:
- Support Vendor network Class(RTL8152、AX88772)
- Support USB modeswitch
- Support Android Open Accessory
-- Support multi host with the same USB IP
+- Support multi host USB IP (IP can be different)
The CherryUSB Host stack also provides the lsusb function, which allows you to view information about all mounted devices, including those on external hubs, with the help of a shell plugin.
@@ -222,6 +223,6 @@ Only standard and commercial USB IP are listed.
## Company Support
-Thanks to the following companies for their support (in no particular order):
+Thanks to the following companies for their support and use.
-<img src="docs/assets/bouffalolab.jpg" width="100" height="80"/> <img src="docs/assets/hpmicro.jpg" width="100" height="80" /> <img src="docs/assets/eastsoft.jpg" width="100" height="80" /> <img src="docs/assets/rtthread.jpg" width="100" height="80" /> <img src="docs/assets/sophgo.jpg" width="100" height="80" /> <img src="docs/assets/phytium.jpg" width="100" height="80" /> <img src="docs/assets/thead.jpg" width="100" height="80" /> <img src="docs/assets/nuvoton.jpg" width="100" height="80" /> <img src="docs/assets/artinchip.jpg" width="100" height="80" /> <img src="docs/assets/bekencorp.jpg" width="100" height="80" /> <img src="docs/assets/nxp.png" width="100" height="80" /> <img src="docs/assets/espressif.png" width="100" height="80" /> <img src="docs/assets/canaan.jpg" width="100" height="80" /> <img src="docs/assets/actions.jpg" width="100" height="80" /> <img src="docs/assets/sifli.jpg" width="100" height="80" /> <img src="docs/assets/nationstech.jpg" width="100" height="80" />
+<img src="docs/assets/bouffalolab.jpg" width="100" height="80"/> <img src="docs/assets/hpmicro.jpg" width="100" height="80" /> <img src="docs/assets/eastsoft.jpg" width="100" height="80" /> <img src="docs/assets/rtthread.jpg" width="100" height="80" /> <img src="docs/assets/sophgo.jpg" width="100" height="80" /> <img src="docs/assets/phytium.jpg" width="100" height="80" /> <img src="docs/assets/thead.jpg" width="100" height="80" /> <img src="docs/assets/nuvoton.jpg" width="100" height="80" /> <img src="docs/assets/artinchip.jpg" width="100" height="80" /> <img src="docs/assets/bekencorp.jpg" width="100" height="80" /> <img src="docs/assets/nxp.png" width="100" height="80" /> <img src="docs/assets/espressif.png" width="100" height="80" /> <img src="docs/assets/canaan.jpg" width="100" height="80" /> <img src="docs/assets/actions.jpg" width="100" height="80" /> <img src="docs/assets/sifli.jpg" width="100" height="80" /> <img src="docs/assets/nationstech.jpg" width="100" height="80" /> <img src="docs/assets/wch.jpg" width="100" height="80" /> <img src="docs/assets/allwinnertech.jpg" width="100" height="80" /> <img src="docs/assets/listenai.jpg" width="100" height="80" />
diff --git a/README_zh.md b/README_zh.md
index 5151340a..c1234657 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -40,7 +40,7 @@ CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统(�
- 长度无限制,方便对接硬件 DMA 并且发挥 DMA 的优势
- 分包过程在中断中执行
-性能展示:https://cherryusb.cherry-embedded.org/show/
+性能展示:https://cherryusb.readthedocs.io/zh-cn/latest/show/index.html
## 目录结构
@@ -77,10 +77,11 @@ CherryUSB Device 协议栈当前实现以下功能:
- 支持 Test and Measurement Class (TMC)
- 支持 WINUSB1.0、WINUSB2.0、WEBUSB、BOS
- 支持 Vendor display ([xfz1986_usb_graphic_driver](https://github.com/chuanjinpang/win10_idd_xfz1986_usb_graphic_driver_display))
+- 支持 linux gs usb class
- 支持 Vendor 类 class
- 支持 UF2
-- 支持 Android Debug Bridge (Only support shell)
-- 支持相同 USB IP 的多从机
+- 支持 Android Debug Bridge (support shell and sync)
+- 支持多从机 USBIP(IP 可以不一样)
CherryUSB Device 协议栈资源占用说明(GCC 10.2 with -O2):
@@ -122,7 +123,7 @@ CherryUSB Host 协议栈当前实现以下功能:
- 支持 Vendor network 类(RTL8152、AX88772)
- 支持 USB modeswitch
- 支持 Android Open Accessory
-- 支持相同 USB IP 的多主机
+- 支持多主机 USBIP(IP 可以不一样)
同时,CherryUSB Host 协议栈还提供了 lsusb 的功能,借助 shell 插件可以查看所有挂载设备的信息,包括外部 hub 上的设备的信息。
@@ -222,6 +223,6 @@ x 受以下宏影响:
## 支持企业
-感谢以下企业支持(顺序不分先后):
+感谢以下企业的支持和使用。
-<img src="docs/assets/bouffalolab.jpg" width="100" height="80"/> <img src="docs/assets/hpmicro.jpg" width="100" height="80" /> <img src="docs/assets/eastsoft.jpg" width="100" height="80" /> <img src="docs/assets/rtthread.jpg" width="100" height="80" /> <img src="docs/assets/sophgo.jpg" width="100" height="80" /> <img src="docs/assets/phytium.jpg" width="100" height="80" /> <img src="docs/assets/thead.jpg" width="100" height="80" /> <img src="docs/assets/nuvoton.jpg" width="100" height="80" /> <img src="docs/assets/artinchip.jpg" width="100" height="80" /> <img src="docs/assets/bekencorp.jpg" width="100" height="80" /> <img src="docs/assets/nxp.png" width="100" height="80" /> <img src="docs/assets/espressif.png" width="100" height="80" /> <img src="docs/assets/canaan.jpg" width="100" height="80" /> <img src="docs/assets/actions.jpg" width="100" height="80" /> <img src="docs/assets/sifli.jpg" width="100" height="80" /> <img src="docs/assets/nationstech.jpg" width="100" height="80" />
+<img src="docs/assets/bouffalolab.jpg" width="100" height="80"/> <img src="docs/assets/hpmicro.jpg" width="100" height="80" /> <img src="docs/assets/eastsoft.jpg" width="100" height="80" /> <img src="docs/assets/rtthread.jpg" width="100" height="80" /> <img src="docs/assets/sophgo.jpg" width="100" height="80" /> <img src="docs/assets/phytium.jpg" width="100" height="80" /> <img src="docs/assets/thead.jpg" width="100" height="80" /> <img src="docs/assets/nuvoton.jpg" width="100" height="80" /> <img src="docs/assets/artinchip.jpg" width="100" height="80" /> <img src="docs/assets/bekencorp.jpg" width="100" height="80" /> <img src="docs/assets/nxp.png" width="100" height="80" /> <img src="docs/assets/espressif.png" width="100" height="80" /> <img src="docs/assets/canaan.jpg" width="100" height="80" /> <img src="docs/assets/actions.jpg" width="100" height="80" /> <img src="docs/assets/sifli.jpg" width="100" height="80" /> <img src="docs/assets/nationstech.jpg" width="100" height="80" /> <img src="docs/assets/wch.jpg" width="100" height="80" /> <img src="docs/assets/allwinnertech.jpg" width="100" height="80" /> <img src="docs/assets/listenai.jpg" width="100" height="80" />
diff --git a/SConscript b/SConscript
index b1ea4906..b39b08b2 100644
--- a/SConscript
+++ b/SConscript
@@ -15,6 +15,7 @@ path += [cwd + '/class/midi']
path += [cwd + '/class/mtp']
path += [cwd + '/class/adb']
path += [cwd + '/class/dfu']
+path += [cwd + '/class/gs_usb']
path += [cwd + '/class/serial']
path += [cwd + '/class/vendor/net']
path += [cwd + '/class/vendor/wifi']
@@ -105,7 +106,7 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
src += Glob('port/renesas/device/r_usb_device.c')
src += Glob('port/renesas/device/usb_dc_rensas.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_CH32']):
- if GetDepend(['PKG_CHERRYUSB_DEVICE_HS']):
+ if GetDepend(['PKG_CHERRYUSB_DEVICE_SPEED_HS']):
src += Glob('port/ch32/usb_dc_usbhs.c')
else:
src += Glob('port/ch32/usb_dc_usbfs.c')
@@ -117,7 +118,7 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
LIBS = ['libpusb2_dc_a64.a']
if GetDepend(['ARCH_ARM_CORTEX_A']):
LIBPATH = [cwd + '/port/pusb2']
- LIBS = ['libpusb2_dc_a32_softfp_neon.a']
+ LIBS = ['libpusb2_dc_a32_softfp_crypto-neon-fp-armv8.a']
if GetDepend(['PKG_CHERRYUSB_DEVICE_NRF5X']):
src += Glob('port/nrf5x/usb_dc_nrf5x.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_RP2040']):
@@ -146,7 +147,25 @@ if GetDepend(['PKG_CHERRYUSB_DEVICE']):
src += Glob('class/vendor/display/usbd_display.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_ADB']):
src += Glob('class/adb/usbd_adb.c')
- src += Glob('platform/rtthread/rt_usbd_adb.c')
+ src += Glob('platform/rtthread/rt_usbd_adb_msh.c')
+ if GetDepend(['PKG_CHERRYUSB_DEVICE_ADB_SYNC']):
+ src += Glob('class/adb/usbd_adb_sync.c')
+ src += Glob('platform/rtthread/rt_vfs_dfs.c')
+ if GetDepend(['PKG_CHERRYUSB_DEVICE_TMC']):
+ src += Glob('class/tmc/usbd_tmc.c')
+ src += Glob('third_party/libscpi/src/error.c')
+ src += Glob('third_party/libscpi/src/expression.c')
+ src += Glob('third_party/libscpi/src/fifo.c')
+ src += Glob('third_party/libscpi/src/ieee488.c')
+ src += Glob('third_party/libscpi/src/lexer.c')
+ src += Glob('third_party/libscpi/src/minimal.c')
+ src += Glob('third_party/libscpi/src/parser.c')
+ src += Glob('third_party/libscpi/src/units.c')
+ src += Glob('third_party/libscpi/src/utils.c')
+ path += [cwd + '/third_party/libscpi/inc']
+
+ if GetDepend(['PKG_CHERRYUSB_DEVICE_GS_USB']):
+ src += Glob('class/gs_usb/usbd_gs_usb.c')
if GetDepend(['PKG_CHERRYUSB_DEVICE_CDC_ACM_CHARDEV']):
src += Glob('platform/rtthread/rt_usbd_serial.c')
@@ -205,7 +224,7 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_BL']):
src += Glob('port/ehci/usb_hc_ehci.c')
- src += Glob('port/ehci/usb_glue_bouffalo.c')
+ src += Glob('port/bouffalolab/usb_glue_bouffalo.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_HPM']):
path += [cwd + '/port/hpmicro']
src += Glob('port/ehci/usb_hc_ehci.c')
@@ -215,18 +234,12 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
path += [cwd + '/port/ehci']
path += [cwd + '/port/ohci']
src += Glob('port/ehci/usb_hc_ehci.c')
- src += Glob('port/ehci/usb_glue_aic.c')
+ src += Glob('port/aic/usb_glue_aic.c')
src += Glob('port/ohci/usb_hc_ohci.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_MCX']):
path += [cwd + '/port/chipidea']
src += Glob('port/ehci/usb_hc_ehci.c')
src += Glob('port/nxp/usb_glue_mcx.c')
- if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_NUC980']):
- src += Glob('port/ehci/usb_hc_ehci.c')
- src += Glob('port/ehci/usb_glue_nuc980.c')
- if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_MA35D0']):
- src += Glob('port/ehci/usb_hc_ehci.c')
- src += Glob('port/ehci/usb_glue_ma35d0.c')
if GetDepend(['PKG_CHERRYUSB_HOST_EHCI_CUSTOM']):
src += Glob('port/ehci/usb_hc_ehci.c')
if GetDepend(['PKG_CHERRYUSB_HOST_DWC2_ST']):
@@ -281,7 +294,7 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
LIBS = ['libpusb2_hc_a64.a']
if GetDepend(['ARCH_ARM_CORTEX_A']):
LIBPATH = [cwd + '/port/pusb2']
- LIBS = ['libpusb2_hc_a32_softfp_neon.a']
+ LIBS = ['libpusb2_hc_a32_softfp_crypto-neon-fp-armv8.a']
if GetDepend(['PKG_CHERRYUSB_HOST_XHCI']):
path += [cwd + '/port/xhci/phytium/rt-thread']
@@ -292,7 +305,7 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
LIBS = ['libxhci_a64.a']
if GetDepend(['ARCH_ARM_CORTEX_A']):
LIBPATH = [cwd + '/port/xhci/phytium']
- LIBS = ['libxhci_a32_softfp_neon.a']
+ LIBS = ['libxhci_a32_softfp_crypto-neon-fp-armv8.a']
if GetDepend(['PKG_CHERRYUSB_HOST_RP2040']):
path += [cwd + '/port/rp2040']
diff --git a/cherryusb.cmake b/cherryusb.cmake
index fac45b36..1007cf8f 100644
--- a/cherryusb.cmake
+++ b/cherryusb.cmake
@@ -49,6 +49,7 @@ list(
${CMAKE_CURRENT_LIST_DIR}/class/mtp
${CMAKE_CURRENT_LIST_DIR}/class/adb
${CMAKE_CURRENT_LIST_DIR}/class/dfu
+ ${CMAKE_CURRENT_LIST_DIR}/class/gs_usb
${CMAKE_CURRENT_LIST_DIR}/class/serial
${CMAKE_CURRENT_LIST_DIR}/class/vendor/net
${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi
@@ -56,6 +57,7 @@ list(
${CMAKE_CURRENT_LIST_DIR}/class/vendor/xbox
${CMAKE_CURRENT_LIST_DIR}/class/aoa
${CMAKE_CURRENT_LIST_DIR}/class/gamepad
+ ${CMAKE_CURRENT_LIST_DIR}/class/tmc
)
if(CONFIG_CHERRYUSB_DEVICE)
@@ -89,6 +91,15 @@ if(CONFIG_CHERRYUSB_DEVICE)
endif()
if(CONFIG_CHERRYUSB_DEVICE_ADB)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/adb/usbd_adb.c)
+ if(CONFIG_CHERRYUSB_DEVICE_ADB_CHERRYSH)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/adb/usbd_adb_cherrysh.c)
+ endif()
+ if(CONFIG_CHERRYUSB_DEVICE_ADB_SYNC)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/adb/usbd_adb_sync.c)
+ if(CONFIG_CHERRYUSB_DEVICE_ADB_SYNC_FATFS)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/platform/fatfs/vfs_fatfs_port.c)
+ endif()
+ endif()
endif()
if(CONFIG_CHERRYUSB_DEVICE_GAMEPAD)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/gamepad/usbd_gamepad.c)
@@ -96,6 +107,22 @@ if(CONFIG_CHERRYUSB_DEVICE)
if(CONFIG_CHERRYUSB_DEVICE_DISPLAY)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/display/usbd_display.c)
endif()
+ if(CONFIG_CHERRYUSB_DEVICE_TMC)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/tmc/usbd_tmc.c)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/libscpi/src/error.c)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/libscpi/src/expression.c)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/libscpi/src/fifo.c)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/libscpi/src/ieee488.c)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/libscpi/src/lexer.c)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/libscpi/src/minimal.c)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/libscpi/src/parser.c)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/libscpi/src/units.c)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/libscpi/src/utils.c)
+ list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/third_party/libscpi/inc)
+ endif()
+ if(CONFIG_CHERRYUSB_DEVICE_GS_USB)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/gs_usb/usbd_gs_usb.c)
+ endif()
if(CONFIG_CHERRYUSB_DEVICE_FSDEV_ST)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/fsdev/usb_dc_fsdev.c)
@@ -293,7 +320,7 @@ if(CONFIG_CHERRYUSB_HOST)
if(CONFIG_CHERRYUSB_HOST_EHCI_BL)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
# list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
- list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_glue_bouffalo.c)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/bouffalolab/usb_glue_bouffalo.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
elseif(CONFIG_CHERRYUSB_HOST_EHCI_HPM)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
@@ -306,7 +333,7 @@ if(CONFIG_CHERRYUSB_HOST)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci.c)
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ohci/usb_hc_ohci.c)
# list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_hc_ehci_iso.c)
- list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/ehci/usb_glue_aic.c)
+ list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/port/aic/usb_glue_aic.c)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ehci)
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/port/ohci)
elseif(CONFIG_CHERRYUSB_HOST_EHCI_MCX)
diff --git a/cherryusb_config_template.h b/cherryusb_config_template.h
index 7d3b8287..7cb36431 100644
--- a/cherryusb_config_template.h
+++ b/cherryusb_config_template.h
@@ -306,6 +306,7 @@
/* ---------------- MUSB Configuration ---------------- */
#define CONFIG_USB_MUSB_PIPE_NUM 8
// #define CONFIG_USB_MUSB_SUNXI
+// #define CONFIG_USB_MUSB_SIFLI
// #define CONFIG_USB_MUSB_WITHOUT_MULTIPOINT
/* When your chip hardware supports high-speed and wants to initialize it in high-speed mode,
@@ -326,4 +327,10 @@
/* Enable OTG support, only support hpmicro now */
// #define CONFIG_USB_OTG_ENABLE
+/* Support multiple device controller with different IP */
+// #define CONFIG_USBDEV_MULT_DC
+
+/* Support multiple host controller with different IP */
+// #define CONFIG_USBHOST_MULT_HC
+
#endif
diff --git a/class/adb/usbd_adb.c b/class/adb/usbd_adb.c
index dc664309..b82ab998 100644
--- a/class/adb/usbd_adb.c
+++ b/class/adb/usbd_adb.c
@@ -1,203 +1,367 @@
/*
- * Copyright (c) 2024, sakumisu
+ * Copyright (c) 2024 ~ 2026, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usbd_adb.h"
-#define ADB_OUT_EP_IDX 0
-#define ADB_IN_EP_IDX 1
+#undef USB_DBG_TAG
+#define USB_DBG_TAG "usbd_adb"
+#include "usb_log.h"
-#define ADB_STATE_READ_MSG 0
-#define ADB_STATE_READ_DATA 1
-#define ADB_STATE_WRITE_MSG 2
-#define ADB_STATE_WRITE_DATA 3
-#define ADB_STATE_AWRITE_MSG 4
-#define ADB_STATE_AWRITE_DATA 5
+#define ADB_OUT_EP_IDX 0u
+#define ADB_IN_EP_IDX 1u
-#define MAX_PAYLOAD_V1 (4 * 1024)
-#define MAX_PAYLOAD_V2 (256 * 1024)
-#define MAX_PAYLOAD MAX_PAYLOAD_V1
-#define A_VERSION 0x01000000
+#define ADB_RX_STATE_READ_MSG 0u /* armed, waiting for the 24-byte header */
+#define ADB_RX_STATE_READ_DATA 1u /* armed, waiting for the payload */
+#define ADB_RX_STATE_COMPLETE 2u /* full packet ready, ISR already notified */
-#define A_SYNC 0x434e5953
-#define A_CNXN 0x4e584e43
-#define A_OPEN 0x4e45504f
-#define A_OKAY 0x59414b4f
-#define A_CLSE 0x45534c43
-#define A_WRTE 0x45545257
-#define A_AUTH 0x48545541
+#define ADB_TX_STATE_MSG 0u /* 24-byte header in flight */
+#define ADB_TX_STATE_DATA 1u /* payload in flight */
+#define ADB_TX_STATE_COMPLETE 2u /* transfer finished, the next send may start */
-struct adb_msg {
- uint32_t command; /* command identifier constant (A_CNXN, ...) */
- uint32_t arg0; /* first argument */
- uint32_t arg1; /* second argument */
- uint32_t data_length; /* length of payload (0 is allowed) */
- uint32_t data_crc32; /* crc32 of data payload */
- uint32_t magic; /* command ^ 0xffffffff */
-};
+#define ADB_DAEMON_THREAD_STACK 4096u
+#define ADB_DAEMON_THREAD_PRIO 10u
-struct adb_packet {
- USB_MEM_ALIGNX struct adb_msg msg;
- USB_MEM_ALIGNX uint8_t payload[USB_ALIGN_UP(MAX_PAYLOAD, CONFIG_USB_ALIGN_SIZE)];
-};
+struct usbd_adb_priv {
+ struct usbd_endpoint ep_data[2];
+ uint8_t busid;
-struct usbd_adb {
- uint8_t state;
- uint8_t common_state;
- uint8_t write_state;
- bool writable;
- uint32_t localid;
- uint32_t shell_remoteid;
- uint32_t file_remoteid;
-} adb_client;
+ const struct adb_service *svc_tab[ADB_MAX_SERVICE];
+ uint32_t remote_id[ADB_MAX_SERVICE];
+ bool svc_opened[ADB_MAX_SERVICE];
-static struct usbd_endpoint adb_ep_data[2];
+ volatile uint8_t rx_state;
+ volatile uint8_t tx_state;
-USB_NOCACHE_RAM_SECTION struct adb_packet tx_packet;
-USB_NOCACHE_RAM_SECTION struct adb_packet rx_packet;
+ usb_osal_sem_t rx_sem;
+ usb_osal_sem_t tx_sem;
+ usb_osal_mutex_t tx_lock;
+ usb_osal_thread_t rx_thread;
+} g_usbd_adb;
-static inline uint32_t adb_packet_checksum(struct adb_packet *packet)
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX struct adb_packet adb_tx_packet;
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX struct adb_packet adb_rx_packet;
+
+static uint32_t adb_packet_checksum(const struct adb_packet *packet)
{
uint32_t sum = 0;
uint32_t i;
- for (i = 0; i < packet->msg.data_length; ++i) {
- sum += (uint32_t)(packet->payload[i]);
+ for (i = 0; i < packet->msg.data_length; i++) {
+ sum += (uint32_t)packet->payload[i];
}
return sum;
}
-static uint32_t usbd_adb_get_remoteid(uint32_t localid)
+static int adb_svc_slot(uint32_t localid)
{
- if (localid == ADB_SHELL_LOALID) {
- return adb_client.shell_remoteid;
- } else {
- return adb_client.file_remoteid;
+ uint32_t i;
+
+ for (i = 0; i < ADB_MAX_SERVICE; i++) {
+ if (g_usbd_adb.svc_tab[i] && (g_usbd_adb.svc_tab[i]->localid == localid)) {
+ return (int)i;
+ }
}
+
+ return -1;
}
-static void adb_send_msg(struct adb_packet *packet)
+int usbd_adb_service_register(const struct adb_service *svc)
{
- adb_client.common_state = ADB_STATE_WRITE_MSG;
+ uint32_t i;
+
+ if (!svc || !svc->name || (svc->localid == 0u)) {
+ return -1;
+ }
- packet->msg.data_crc32 = adb_packet_checksum(packet);
- packet->msg.magic = packet->msg.command ^ 0xffffffff;
+ if (adb_svc_slot(svc->localid) >= 0) {
+ return -1; /* local id already taken */
+ }
- usbd_ep_start_write(0, adb_ep_data[ADB_IN_EP_IDX].ep_addr, (uint8_t *)&packet->msg, sizeof(struct adb_msg));
+ for (i = 0; i < ADB_MAX_SERVICE; i++) {
+ if (g_usbd_adb.svc_tab[i] == NULL) {
+ g_usbd_adb.svc_tab[i] = svc;
+ g_usbd_adb.remote_id[i] = 0;
+ g_usbd_adb.svc_opened[i] = false;
+ return 0;
+ }
+ }
+
+ return -1; /* table full */
}
-static void adb_send_okay(struct adb_packet *packet, uint32_t localid)
+static uint32_t usbd_adb_service_get_remoteid(uint32_t localid)
{
- packet->msg.command = A_OKAY;
- packet->msg.arg0 = localid;
- packet->msg.arg1 = usbd_adb_get_remoteid(localid);
- packet->msg.data_length = 0;
+ int slot = adb_svc_slot(localid);
- adb_send_msg(&tx_packet);
+ return (slot >= 0) ? g_usbd_adb.remote_id[slot] : 0u;
}
-static void adb_send_close(struct adb_packet *packet, uint32_t localid, uint32_t remoteid)
+static bool usbd_adb_service_is_opened(uint32_t localid)
{
- packet->msg.command = A_CLSE;
- packet->msg.arg0 = localid;
- packet->msg.arg1 = remoteid;
- packet->msg.data_length = 0;
+ int slot = adb_svc_slot(localid);
- adb_send_msg(&tx_packet);
+ return (slot >= 0) ? g_usbd_adb.svc_opened[slot] : false;
}
-void usbd_adb_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
+static int usbd_adb_send_internal(uint32_t command,
+ uint32_t arg0,
+ uint32_t arg1,
+ const uint8_t *data,
+ uint32_t len)
{
- (void)ep;
+ int ret;
- if (adb_client.common_state == ADB_STATE_READ_MSG) {
- USB_ASSERT(nbytes == sizeof(struct adb_msg));
- USB_ASSERT(rx_packet.msg.data_length <= sizeof(rx_packet.payload));
+ if (len && !data) {
+ return -1;
+ }
- USB_LOG_DBG("command:%x arg0:%x arg1:%x len:%d\r\n",
- rx_packet.msg.command,
- rx_packet.msg.arg0,
- rx_packet.msg.arg1,
- rx_packet.msg.data_length);
+ /* one transmitter at a time */
+ usb_osal_mutex_take(g_usbd_adb.tx_lock);
- if (rx_packet.msg.data_length) {
- /* setup next out ep read transfer */
- adb_client.common_state = ADB_STATE_READ_DATA;
- usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, rx_packet.payload, rx_packet.msg.data_length);
- } else {
- if (rx_packet.msg.command == A_CLSE) {
- adb_client.writable = false;
- usbd_adb_notify_write_done();
- USB_LOG_INFO("Close remoteid:%x\r\n", rx_packet.msg.arg0);
- }
- adb_client.common_state = ADB_STATE_READ_MSG;
- /* setup first out ep read transfer */
- usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
+ adb_tx_packet.msg.command = command;
+ adb_tx_packet.msg.arg0 = arg0;
+ adb_tx_packet.msg.arg1 = arg1;
+ adb_tx_packet.msg.data_length = len;
+ if (len) {
+ memcpy(adb_tx_packet.payload, data, len);
+ }
+ adb_tx_packet.msg.data_crc32 = adb_packet_checksum(&adb_tx_packet);
+ adb_tx_packet.msg.magic = command ^ 0xffffffffu;
+
+ /* drop a stale completion left behind by a previous timeout */
+ usb_osal_sem_reset(g_usbd_adb.tx_sem);
+
+ g_usbd_adb.tx_state = ADB_TX_STATE_MSG;
+ usbd_ep_start_write(g_usbd_adb.busid, g_usbd_adb.ep_data[ADB_IN_EP_IDX].ep_addr,
+ (uint8_t *)&adb_tx_packet.msg, sizeof(struct adb_msg));
+
+ ret = usb_osal_sem_take(g_usbd_adb.tx_sem, ADB_TX_TIMEOUT_MS);
+ if (ret != 0) {
+ USB_LOG_ERR("tx timeout, cmd %08x len %u\r\n", (unsigned)command, (unsigned)len);
+ g_usbd_adb.tx_state = ADB_TX_STATE_COMPLETE;
+ ret = -2;
+ } else {
+ ret = 0;
+ }
+
+ usb_osal_mutex_give(g_usbd_adb.tx_lock);
+
+ return ret;
+}
+
+static void adb_reply_okay(uint32_t localid, uint32_t remoteid)
+{
+ usbd_adb_send_internal(A_OKAY, localid, remoteid, NULL, 0);
+}
+
+static void adb_reply_close(uint32_t localid, uint32_t remoteid)
+{
+ usbd_adb_send_internal(A_CLSE, localid, remoteid, NULL, 0);
+}
+
+static void adb_handle_cnxn(struct adb_packet *pkt)
+{
+ static const char support_feature[] =
+ "device::"
+ "ro.product.name=cherryadb;"
+ "ro.product.model=cherrysh;"
+ "ro.product.device=cherryadb;"
+ "features=cmd,shell_v1";
+
+ (void)pkt;
+
+ usbd_adb_send_internal(A_CNXN, ADB_VERSION, ADB_MAX_PAYLOAD,
+ (const uint8_t *)support_feature, strlen(support_feature));
+}
+
+static void adb_handle_open(struct adb_packet *pkt)
+{
+ uint32_t remoteid = pkt->msg.arg0;
+ char *dest = (char *)pkt->payload;
+ uint32_t i;
+
+ if ((pkt->msg.data_length == 0) || (pkt->msg.data_length >= ADB_MAX_PAYLOAD)) {
+ adb_reply_close(0, remoteid);
+ return;
+ }
+
+ /* the destination string is not guaranteed to be NUL terminated */
+ dest[pkt->msg.data_length] = '\0';
+
+ for (i = 0; i < ADB_MAX_SERVICE; i++) {
+ const struct adb_service *svc = g_usbd_adb.svc_tab[i];
+ size_t name_len;
+
+ if (!svc) {
+ continue;
+ }
+
+ name_len = strlen(svc->name);
+ if (strncmp(dest, svc->name, name_len) != 0) {
+ continue;
}
- } else if (adb_client.common_state == ADB_STATE_READ_DATA) {
- switch (rx_packet.msg.command) {
- case A_SYNC:
- break;
- case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
- {
- char *support_feature = "device::"
- "ro.product.name=cherryadb;"
- "ro.product.model=cherrysh;"
- "ro.product.device=cherryadb;"
- "features=cmd,shell_v1";
+ g_usbd_adb.remote_id[i] = remoteid;
+ g_usbd_adb.svc_opened[i] = true;
+
+ if (svc->on_open) {
+ svc->on_open(remoteid);
+ }
+
+ adb_reply_okay(svc->localid, remoteid);
+ return;
+ }
+
+ USB_LOG_WRN("unsupported destination '%s'\r\n", dest);
+ adb_reply_close(0, remoteid);
+}
+
+static void adb_handle_write(struct adb_packet *pkt)
+{
+ uint32_t remoteid = pkt->msg.arg0;
+ uint32_t localid = pkt->msg.arg1;
+ int slot = adb_svc_slot(localid);
+
+ if ((slot < 0) || !g_usbd_adb.svc_opened[slot] || (g_usbd_adb.remote_id[slot] != remoteid)) {
+ adb_reply_close(0, remoteid);
+ return;
+ }
+
+ if (g_usbd_adb.svc_tab[slot]->on_write) {
+ g_usbd_adb.svc_tab[slot]->on_write(remoteid, pkt->payload, pkt->msg.data_length);
+ }
+
+ adb_reply_okay(localid, remoteid);
+}
+
+static void adb_handle_close(struct adb_packet *pkt)
+{
+ uint32_t remoteid = pkt->msg.arg0;
+ uint32_t localid = pkt->msg.arg1;
+ int slot = adb_svc_slot(localid);
+
+ if (slot < 0) {
+ return;
+ }
+
+ g_usbd_adb.svc_opened[slot] = false;
+
+ if (g_usbd_adb.svc_tab[slot]->on_close) {
+ g_usbd_adb.svc_tab[slot]->on_close(remoteid);
+ }
+
+ g_usbd_adb.remote_id[slot] = 0;
+}
+
+static void adb_dispatch(struct adb_packet *pkt)
+{
+ switch (pkt->msg.command) {
+ case A_CNXN:
+ adb_handle_cnxn(pkt);
+ break;
+ case A_OPEN:
+ adb_handle_open(pkt);
+ break;
+ case A_WRTE:
+ adb_handle_write(pkt);
+ break;
+ case A_CLSE:
+ adb_handle_close(pkt);
+ break;
+ case A_OKAY:
+ /* the host acknowledged one of our writes, nothing to answer */
+ break;
+ case A_SYNC:
+ case A_AUTH:
+ break;
+ default:
+ USB_LOG_WRN("unknown command 0x%08x\r\n", (unsigned)pkt->msg.command);
+ break;
+ }
+}
+
+static void adb_handle_packet(struct adb_packet *pkt)
+{
+ if (pkt->msg.magic != (pkt->msg.command ^ 0xffffffffu)) {
+ USB_LOG_ERR("bad magic 0x%08x for command 0x%08x\r\n",
+ (unsigned)pkt->msg.magic, (unsigned)pkt->msg.command);
+ return;
+ }
+
+ adb_dispatch(pkt);
+}
+
+static void adb_rx_thread_entry(CONFIG_USB_OSAL_THREAD_SET_ARGV)
+{
+ (void)argument;
- tx_packet.msg.command = A_CNXN;
- tx_packet.msg.arg0 = A_VERSION;
- tx_packet.msg.arg1 = MAX_PAYLOAD;
- tx_packet.msg.data_length = strlen(support_feature);
- memcpy(tx_packet.payload, support_feature, strlen(support_feature));
+ while (1) {
+ if (usb_osal_sem_take(g_usbd_adb.rx_sem, USB_OSAL_WAITING_FOREVER) != 0) {
+ continue;
+ }
- adb_send_msg(&tx_packet);
+ adb_handle_packet(&adb_rx_packet);
- adb_client.writable = false;
- } break;
- case A_OPEN: /* OPEN(local-id, 0, "destination") */
- rx_packet.payload[rx_packet.msg.data_length] = '\0';
+ /* the packet has been consumed, arm the OUT endpoint again */
+ g_usbd_adb.rx_state = ADB_RX_STATE_READ_MSG;
+ usbd_ep_start_read(g_usbd_adb.busid, g_usbd_adb.ep_data[ADB_OUT_EP_IDX].ep_addr,
+ (uint8_t *)&adb_rx_packet.msg, sizeof(struct adb_msg));
+ }
+}
- if (strncmp((const char *)rx_packet.payload, "shell:", 6) == 0) {
- adb_client.localid = ADB_SHELL_LOALID;
- adb_client.shell_remoteid = rx_packet.msg.arg0;
- adb_send_okay(&tx_packet, ADB_SHELL_LOALID);
+void usbd_adb_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+ (void)ep;
- USB_LOG_INFO("Open shell service, remoteid:%x\r\n", rx_packet.msg.arg0);
- } else if (strncmp((const char *)rx_packet.payload, "sync:", 5) == 0) {
- adb_client.localid = ADB_FILE_LOALID;
- adb_client.file_remoteid = rx_packet.msg.arg0;
- adb_send_okay(&tx_packet, ADB_FILE_LOALID);
- USB_LOG_INFO("Open file service, remoteid:%x\r\n", rx_packet.msg.arg0);
- }
- break;
- case A_OKAY:
+ if (nbytes == 0) {
+ g_usbd_adb.rx_state = ADB_RX_STATE_READ_MSG;
+ usbd_ep_start_read(busid, g_usbd_adb.ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&adb_rx_packet.msg,
+ sizeof(struct adb_msg));
+ return;
+ }
- break;
- case A_CLSE:
+ if (g_usbd_adb.rx_state == ADB_RX_STATE_READ_MSG) {
+ if (nbytes != sizeof(struct adb_msg)) {
+ USB_LOG_ERR("short header %u bytes\r\n", (unsigned)nbytes);
+ g_usbd_adb.rx_state = ADB_RX_STATE_READ_MSG;
+ usbd_ep_start_read(busid, g_usbd_adb.ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&adb_rx_packet.msg,
+ sizeof(struct adb_msg));
+ return;
+ }
- break;
- case A_WRTE: /* WRITE(local-id, remote-id, "data") */
- if ((rx_packet.msg.arg0 == adb_client.shell_remoteid) && (rx_packet.msg.arg1 == ADB_SHELL_LOALID)) {
- adb_send_okay(&tx_packet, rx_packet.msg.arg1);
- } else if ((rx_packet.msg.arg0 == adb_client.file_remoteid) && (rx_packet.msg.arg1 == ADB_FILE_LOALID)) {
- adb_send_okay(&tx_packet, rx_packet.msg.arg1);
- } else {
- adb_send_close(&tx_packet, 0, rx_packet.msg.arg0);
- }
- break;
- case A_AUTH:
+ if (adb_rx_packet.msg.data_length > ADB_MAX_PAYLOAD) {
+ USB_LOG_ERR("header length %u too large\r\n",
+ (unsigned)adb_rx_packet.msg.data_length);
+ g_usbd_adb.rx_state = ADB_RX_STATE_READ_MSG;
+ usbd_ep_start_read(busid, g_usbd_adb.ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&adb_rx_packet.msg,
+ sizeof(struct adb_msg));
+ return;
+ }
- break;
+ if (adb_rx_packet.msg.data_length) {
+ USB_LOG_DBG("rx cmd 0x%08x arg0 0x%x arg1 0x%x len %u\r\n",
+ (unsigned)adb_rx_packet.msg.command,
+ (unsigned)adb_rx_packet.msg.arg0,
+ (unsigned)adb_rx_packet.msg.arg1,
+ (unsigned)adb_rx_packet.msg.data_length);
- default:
- break;
+ g_usbd_adb.rx_state = ADB_RX_STATE_READ_DATA;
+ usbd_ep_start_read(busid, g_usbd_adb.ep_data[ADB_OUT_EP_IDX].ep_addr, adb_rx_packet.payload,
+ adb_rx_packet.msg.data_length);
+ } else {
+ /* no payload -> the packet is already complete */
+ g_usbd_adb.rx_state = ADB_RX_STATE_COMPLETE;
+ usb_osal_sem_give(g_usbd_adb.rx_sem);
}
+ } else if (g_usbd_adb.rx_state == ADB_RX_STATE_READ_DATA) {
+ /* payload complete -> the packet is complete */
+ g_usbd_adb.rx_state = ADB_RX_STATE_COMPLETE;
+ usb_osal_sem_give(g_usbd_adb.rx_sem);
+ } else {
}
}
@@ -206,104 +370,152 @@ void usbd_adb_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
(void)ep;
(void)nbytes;
- if (adb_client.common_state == ADB_STATE_WRITE_MSG) {
- if (tx_packet.msg.data_length) {
- adb_client.common_state = ADB_STATE_WRITE_DATA;
- usbd_ep_start_write(busid, adb_ep_data[ADB_IN_EP_IDX].ep_addr, tx_packet.payload, tx_packet.msg.data_length);
- } else {
- if (rx_packet.msg.command == A_WRTE) {
- adb_client.writable = true;
- if (adb_client.localid == ADB_SHELL_LOALID) {
- usbd_adb_notify_shell_read(rx_packet.payload, rx_packet.msg.data_length);
- } else {
- }
- }
- adb_client.common_state = ADB_STATE_READ_MSG;
- /* setup first out ep read transfer */
- usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
- }
- } else if (adb_client.common_state == ADB_STATE_WRITE_DATA) {
- adb_client.common_state = ADB_STATE_READ_MSG;
- /* setup first out ep read transfer */
- usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
- } else if (adb_client.write_state == ADB_STATE_AWRITE_MSG) {
- if (tx_packet.msg.data_length) {
- adb_client.write_state = ADB_STATE_AWRITE_DATA;
- usbd_ep_start_write(busid, adb_ep_data[ADB_IN_EP_IDX].ep_addr, tx_packet.payload, tx_packet.msg.data_length);
+ if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
+ /* send zlp */
+ usbd_ep_start_write(busid, g_usbd_adb.ep_data[ADB_IN_EP_IDX].ep_addr, NULL, 0);
+ return;
+ }
+
+ if (g_usbd_adb.tx_state == ADB_TX_STATE_MSG) {
+ if (adb_tx_packet.msg.data_length) {
+ g_usbd_adb.tx_state = ADB_TX_STATE_DATA;
+ usbd_ep_start_write(busid, g_usbd_adb.ep_data[ADB_IN_EP_IDX].ep_addr,
+ adb_tx_packet.payload, adb_tx_packet.msg.data_length);
} else {
+ g_usbd_adb.tx_state = ADB_TX_STATE_COMPLETE;
+ usb_osal_sem_give(g_usbd_adb.tx_sem);
}
- } else if (adb_client.write_state == ADB_STATE_AWRITE_DATA) {
- usbd_adb_notify_write_done();
+ } else if (g_usbd_adb.tx_state == ADB_TX_STATE_DATA) {
+ g_usbd_adb.tx_state = ADB_TX_STATE_COMPLETE;
+ usb_osal_sem_give(g_usbd_adb.tx_sem);
}
}
-void adb_notify_handler(uint8_t busid, uint8_t event, void *arg)
+static void adb_notify_handler(uint8_t busid, uint8_t event, void *arg)
{
(void)arg;
switch (event) {
- case USBD_EVENT_INIT:
- break;
- case USBD_EVENT_DEINIT:
+ case USBD_EVENT_CONFIGURED:
+ g_usbd_adb.rx_state = ADB_RX_STATE_READ_MSG;
+ g_usbd_adb.tx_state = ADB_TX_STATE_COMPLETE;
+ usbd_ep_start_read(busid, g_usbd_adb.ep_data[ADB_OUT_EP_IDX].ep_addr,
+ (uint8_t *)&adb_rx_packet.msg, sizeof(struct adb_msg));
break;
+
case USBD_EVENT_RESET:
- break;
- case USBD_EVENT_CONFIGURED:
- adb_client.common_state = ADB_STATE_READ_MSG;
- /* setup first out ep read transfer */
- usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
+ for (uint32_t i = 0; i < ADB_MAX_SERVICE; i++) {
+ g_usbd_adb.svc_opened[i] = false;
+ g_usbd_adb.remote_id[i] = 0;
+ }
break;
+ case USBD_EVENT_INIT:
+ break;
+ case USBD_EVENT_DEINIT:
+ break;
default:
break;
}
}
-struct usbd_interface *usbd_adb_init_intf(uint8_t busid, struct usbd_interface *intf, uint8_t in_ep, uint8_t out_ep)
+/* -------------------------------------------------------------------------
+ * initialisation
+ * ---------------------------------------------------------------------- */
+struct usbd_interface *usbd_adb_init_intf(uint8_t busid, struct usbd_interface *intf,
+ uint8_t in_ep, uint8_t out_ep)
{
- (void)busid;
+ g_usbd_adb.busid = busid;
+
+ g_usbd_adb.ep_data[ADB_OUT_EP_IDX].ep_addr = out_ep;
+ g_usbd_adb.ep_data[ADB_OUT_EP_IDX].ep_cb = usbd_adb_bulk_out;
+ g_usbd_adb.ep_data[ADB_IN_EP_IDX].ep_addr = in_ep;
+ g_usbd_adb.ep_data[ADB_IN_EP_IDX].ep_cb = usbd_adb_bulk_in;
+
+ usbd_add_endpoint(busid, &g_usbd_adb.ep_data[ADB_OUT_EP_IDX]);
+ usbd_add_endpoint(busid, &g_usbd_adb.ep_data[ADB_IN_EP_IDX]);
intf->class_interface_handler = NULL;
intf->class_endpoint_handler = NULL;
intf->vendor_handler = NULL;
intf->notify_handler = adb_notify_handler;
- adb_ep_data[ADB_OUT_EP_IDX].ep_addr = out_ep;
- adb_ep_data[ADB_OUT_EP_IDX].ep_cb = usbd_adb_bulk_out;
- adb_ep_data[ADB_IN_EP_IDX].ep_addr = in_ep;
- adb_ep_data[ADB_IN_EP_IDX].ep_cb = usbd_adb_bulk_in;
+ g_usbd_adb.rx_sem = usb_osal_sem_create(0);
+ USB_ASSERT_MSG(g_usbd_adb.rx_sem, "adb rx_sem fail");
+ g_usbd_adb.tx_sem = usb_osal_sem_create(0);
+ USB_ASSERT_MSG(g_usbd_adb.tx_sem, "adb tx_sem fail");
+ g_usbd_adb.tx_lock = usb_osal_mutex_create();
+ USB_ASSERT_MSG(g_usbd_adb.tx_lock, "adb tx_lock fail");
- usbd_add_endpoint(busid, &adb_ep_data[ADB_OUT_EP_IDX]);
- usbd_add_endpoint(busid, &adb_ep_data[ADB_IN_EP_IDX]);
+ g_usbd_adb.rx_thread = usb_osal_thread_create("usbd_adb", ADB_DAEMON_THREAD_STACK,
+ ADB_DAEMON_THREAD_PRIO, adb_rx_thread_entry, NULL);
+ USB_ASSERT_MSG(g_usbd_adb.rx_thread, "adb rx_thread fail");
+ usbd_adb_shell_init();
+ usbd_adb_sync_init();
return intf;
}
-bool usbd_adb_can_write(void)
+int usbd_adb_write(uint32_t localid,
+ const uint8_t *data,
+ uint32_t len)
{
- return adb_client.writable;
-}
+ uint32_t sent = 0;
-int usbd_abd_write(uint32_t localid, const uint8_t *data, uint32_t len)
-{
- struct adb_packet *packet;
+ if (usbd_adb_service_is_opened(localid) == false) {
+ return -1;
+ }
- packet = &tx_packet;
- packet->msg.command = A_WRTE;
- packet->msg.arg0 = localid;
- packet->msg.arg1 = usbd_adb_get_remoteid(localid);
- packet->msg.data_length = len;
- memcpy(packet->payload, data, len);
+ uint32_t remoteid = usbd_adb_service_get_remoteid(localid);
+ if (!remoteid) {
+ return -1;
+ }
- packet->msg.data_crc32 = adb_packet_checksum(packet);
- packet->msg.magic = packet->msg.command ^ 0xffffffff;
+ if (!len) {
+ return 0;
+ }
+
+ while (sent < len) {
+ uint32_t chunk = len - sent;
+ int ret;
+
+ if (chunk > ADB_MAX_PAYLOAD) {
+ chunk = ADB_MAX_PAYLOAD;
+ }
+
+ ret = usbd_adb_send_internal(A_WRTE,
+ localid,
+ remoteid,
+ data + sent,
+ chunk);
+ if (ret != 0) {
+ return ret;
+ }
+
+ sent += chunk;
+ }
- adb_client.write_state = ADB_STATE_AWRITE_MSG;
- usbd_ep_start_write(0, adb_ep_data[ADB_IN_EP_IDX].ep_addr, (uint8_t *)&packet->msg, sizeof(struct adb_msg));
return 0;
}
void usbd_adb_close(uint32_t localid)
{
- adb_send_close(&tx_packet, 0, usbd_adb_get_remoteid(localid));
+ if (usbd_adb_service_is_opened(localid) == false) {
+ return;
+ }
+
+ uint32_t remoteid = usbd_adb_service_get_remoteid(localid);
+ if (!remoteid) {
+ return;
+ }
+
+ usbd_adb_send_internal(A_CLSE, localid, remoteid, NULL, 0);
+}
+
+__WEAK void usbd_adb_shell_init(void)
+{
+}
+
+__WEAK void usbd_adb_sync_init(void)
+{
} \ No newline at end of file
diff --git a/class/adb/usbd_adb.h b/class/adb/usbd_adb.h
index 98ec19ba..dae33236 100644
--- a/class/adb/usbd_adb.h
+++ b/class/adb/usbd_adb.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, sakumisu
+ * Copyright (c) 2024 ~ 2026, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -7,14 +7,59 @@
#define USBD_ADB_H
#include <stdint.h>
+#include "usb_vfs.h"
-#define ADB_SHELL_LOALID 0x01
-#define ADB_FILE_LOALID 0x02
+#define ADB_VERSION 0x01000000u
+#define ADB_MAX_PAYLOAD (4u * 1024u)
+#define ADB_TX_TIMEOUT_MS 5000u
+#define ADB_MAX_SERVICE 4u
+
+#define ADB_LOCALID_SHELL 0x01u
+#define ADB_LOCALID_SYNC 0x02u
+
+/* -------------------------------------------------------------------------
+ * adb packet commands
+ *
+ * The 4cc is stored as a little endian integer, exactly like the official
+ * adb implementation does (A_CNXN == 0x4e584e43 == "CNXN" on the wire).
+ * ---------------------------------------------------------------------- */
+#define ADB_FOURCC(c0, c1, c2, c3) ((uint32_t)(c0) | ((uint32_t)(c1) << 8) | \
+ ((uint32_t)(c2) << 16) | ((uint32_t)(c3) << 24))
+
+#define A_SYNC ADB_FOURCC('S', 'Y', 'N', 'C')
+#define A_CNXN ADB_FOURCC('C', 'N', 'X', 'N')
+#define A_OPEN ADB_FOURCC('O', 'P', 'E', 'N')
+#define A_OKAY ADB_FOURCC('O', 'K', 'A', 'Y')
+#define A_CLSE ADB_FOURCC('C', 'L', 'S', 'E')
+#define A_WRTE ADB_FOURCC('W', 'R', 'T', 'E')
+#define A_AUTH ADB_FOURCC('A', 'U', 'T', 'H')
+
+struct adb_msg {
+ uint32_t command; /* A_CNXN / A_OPEN / A_OKAY / A_CLSE / A_WRTE */
+ uint32_t arg0; /* first argument */
+ uint32_t arg1; /* second argument */
+ uint32_t data_length; /* length of the payload that follows */
+ uint32_t data_crc32; /* checksum of the payload (plain 32-bit sum) */
+ uint32_t magic; /* command ^ 0xffffffff */
+};
+
+struct adb_packet {
+ USB_MEM_ALIGNX struct adb_msg msg;
+ USB_MEM_ALIGNX uint8_t payload[ADB_MAX_PAYLOAD];
+};
+
+struct adb_service {
+ const char *name; /* destination prefix, e.g. "shell:" / "sync:" */
+ uint32_t localid; /* ADB_LOCALID_SHELL / ADB_LOCALID_FILE / ... */
+ void (*on_open)(uint32_t remoteid);
+ void (*on_close)(uint32_t remoteid);
+ void (*on_write)(uint32_t remoteid, const uint8_t *data, uint32_t len);
+};
// clang-format off
-#define ADB_DESCRIPTOR_INIT(bFirstInterface, in_ep, out_ep, wMaxPacketSize) \
+#define ADB_DESCRIPTOR_INIT(bFirstInterface, in_ep, out_ep, wMaxPacketSize) \
USB_INTERFACE_DESCRIPTOR_INIT(bFirstInterface, 0x00, 0x02, 0xff, 0x42, 0x01, 0x02), \
- USB_ENDPOINT_DESCRIPTOR_INIT(in_ep, 0x02, wMaxPacketSize, 0x00), \
+ USB_ENDPOINT_DESCRIPTOR_INIT(in_ep, 0x02, wMaxPacketSize, 0x00), \
USB_ENDPOINT_DESCRIPTOR_INIT(out_ep, 0x02, wMaxPacketSize, 0x00)
// clang-format on
@@ -23,14 +68,15 @@ extern "C" {
#endif
struct usbd_interface *usbd_adb_init_intf(uint8_t busid, struct usbd_interface *intf, uint8_t in_ep, uint8_t out_ep);
-
-void usbd_adb_notify_shell_read(uint8_t *data, uint32_t len);
-void usbd_adb_notify_file_read(uint8_t *data, uint32_t len);
-void usbd_adb_notify_write_done(void);
-bool usbd_adb_can_write(void);
-int usbd_abd_write(uint32_t localid, const uint8_t *data, uint32_t len);
+int usbd_adb_write(uint32_t localid,
+ const uint8_t *data,
+ uint32_t len);
void usbd_adb_close(uint32_t localid);
+int usbd_adb_service_register(const struct adb_service *svc);
+void usbd_adb_shell_init(void);
+void usbd_adb_sync_init(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/demo/adb/cherrysh_port.c b/class/adb/usbd_adb_cherrysh.c
index 85971724..61ed3b73 100644
--- a/demo/adb/cherrysh_port.c
+++ b/class/adb/usbd_adb_cherrysh.c
@@ -1,35 +1,36 @@
/*
- * Copyright (c) 2024, sakumisu
+ * Copyright (c) 2024 ~ 2026, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
+#include "usbd_core.h"
+#include "usbd_adb.h"
+#include "csh.h"
+
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"
-#include "csh.h"
-#include "usbd_core.h"
-#include "usbd_adb.h"
-#include "chry_ringbuffer.h"
-static chry_ringbuffer_t shell_rb;
-static uint8_t mempool[1024];
+#ifndef CHERRYSH_TASK_REPL_PRIORITY
+#define CHERRYSH_TASK_REPL_PRIORITY (2)
+#endif
-#ifndef task_repl_PRIORITY
-#define task_repl_PRIORITY (configMAX_PRIORITIES - 4U)
+#ifndef CHERRYSH_TASK_EXEC_PRIORITY
+#define CHERRYSH_TASK_EXEC_PRIORITY (1)
#endif
-#ifndef task_exec_PRIORITY
-#define task_exec_PRIORITY (configMAX_PRIORITIES - 5U)
+#ifndef CHERRYSH_TASK_REPL_STACK_SIZE
+#define CHERRYSH_TASK_REPL_STACK_SIZE 1024U
+#endif
+
+#ifndef CHERRYSH_TASK_EXEC_STACK_SIZE
+#define CHERRYSH_TASK_EXEC_STACK_SIZE 1024U
#endif
static chry_shell_t csh;
static volatile bool login = false;
-
-static StaticTask_t task_buffer_repl;
-static StaticTask_t task_buffer_exec;
-
-static StackType_t task_stack_repl[1024];
-static StackType_t task_stack_exec[1024];
+static usb_ringbuffer_t shell_rb;
+static uint8_t mempool[1024];
static TaskHandle_t task_hdl_repl = NULL;
static TaskHandle_t task_hdl_exec = NULL;
@@ -37,34 +38,45 @@ static TaskHandle_t task_hdl_exec = NULL;
static EventGroupHandle_t event_hdl;
static StaticEventGroup_t event_grp;
-void usbd_adb_notify_shell_read(uint8_t *data, uint32_t len)
+static int shell_init(bool need_login);
+
+static void adb_shell_on_open(uint32_t remoteid)
{
- chry_ringbuffer_write(&shell_rb, data, len);
+ USB_LOG_INFO("adb shell open, remoteid:%u\r\n", (unsigned)remoteid);
+}
- BaseType_t xHigherPriorityTaskWoken = pdFALSE;
- xEventGroupSetBitsFromISR(event_hdl, 0x10, &xHigherPriorityTaskWoken);
- portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+static void adb_shell_on_close(uint32_t remoteid)
+{
+ USB_LOG_INFO("adb shell close, remoteid:%u\r\n", (unsigned)remoteid);
}
-void usbd_adb_notify_write_done(void)
+static void adb_shell_on_write(uint32_t remoteid, const uint8_t *data, uint32_t len)
{
- BaseType_t xHigherPriorityTaskWoken = pdFALSE;
- xEventGroupSetBitsFromISR(event_hdl, 0x20, &xHigherPriorityTaskWoken);
- portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+ usb_ringbuffer_write(&shell_rb, (uint8_t *)data, len);
+ xEventGroupSetBits(event_hdl, 0x10);
+}
+
+static const struct adb_service adb_shell_service = {
+ .name = "shell:",
+ .localid = ADB_LOCALID_SHELL,
+ .on_open = adb_shell_on_open,
+ .on_close = adb_shell_on_close,
+ .on_write = adb_shell_on_write,
+};
+
+void usbd_adb_shell_init(void)
+{
+ if (usbd_adb_service_register(&adb_shell_service) != 0) {
+ USB_LOG_ERR("adb shell: register failed\r\n");
+ }
+ shell_init(false);
}
static uint16_t csh_sput_cb(chry_readline_t *rl, const void *data, uint16_t size)
{
(void)rl;
- if (!usb_device_is_configured(0)) {
- return size;
- }
-
- if (usbd_adb_can_write() && size) {
- usbd_abd_write(ADB_SHELL_LOALID, data, size);
- xEventGroupWaitBits(event_hdl, 0x20, pdTRUE, pdFALSE, portMAX_DELAY);
- }
+ usbd_adb_write(ADB_LOCALID_SHELL, data, size);
return size;
}
@@ -72,8 +84,7 @@ static uint16_t csh_sput_cb(chry_readline_t *rl, const void *data, uint16_t size
static uint16_t csh_sget_cb(chry_readline_t *rl, void *data, uint16_t size)
{
(void)rl;
-
- return chry_ringbuffer_read(&shell_rb, data, size);
+ return usb_ringbuffer_read(&shell_rb, data, size);
}
static void wait_char(void)
@@ -173,7 +184,10 @@ int chry_shell_port_create_context(chry_shell_t *csh, int argc, const char **arg
vTaskDelete(*p_task_hdl_exec);
}
- *p_task_hdl_exec = xTaskCreateStatic(task_exec, "task_exec", 1024U, NULL, task_exec_PRIORITY, task_stack_exec, &task_buffer_exec);
+ *p_task_hdl_exec = NULL;
+ if (xTaskCreate(task_exec, "task_exec", CHERRYSH_TASK_EXEC_STACK_SIZE, NULL, CHERRYSH_TASK_EXEC_PRIORITY, (TaskHandle_t *)p_task_hdl_exec) != pdPASS) {
+ return -1;
+ }
return 0;
}
@@ -221,11 +235,11 @@ void chry_shell_port_default_handler(chry_shell_t *csh, int sig)
chry_readline_edit_refresh(&csh->rl);
}
-int shell_init(bool need_login)
+static int shell_init(bool need_login)
{
- chry_shell_init_t csh_init;
+ chry_shell_init_t csh_init = {0};
- if (chry_ringbuffer_init(&shell_rb, mempool, sizeof(mempool))) {
+ if (usb_ringbuffer_init(&shell_rb, mempool, sizeof(mempool))) {
return -1;
}
@@ -240,6 +254,7 @@ int shell_init(bool need_login)
csh_init.sget = csh_sget_cb;
#if defined(CONFIG_CSH_SYMTAB) && CONFIG_CSH_SYMTAB
+#if defined(__GNUC__)
extern const int __fsymtab_start;
extern const int __fsymtab_end;
extern const int __vsymtab_start;
@@ -250,6 +265,14 @@ int shell_init(bool need_login)
csh_init.command_table_end = &__fsymtab_end;
csh_init.variable_table_beg = &__vsymtab_start;
csh_init.variable_table_end = &__vsymtab_end;
+#elif defined(__ICCARM__) || defined(__ICCRX__) || defined(__ICCRISCV__)
+#pragma section="FSymTab"
+#pragma section="VSymTab"
+ csh_init.command_table_beg = __section_begin("FSymTab");
+ csh_init.command_table_end = __section_end("FSymTab");
+ csh_init.variable_table_beg = __section_begin("VSymTab");
+ csh_init.variable_table_end = __section_end("VSymTab");
+#endif
#endif
#if defined(CONFIG_CSH_PROMPTEDIT) && CONFIG_CSH_PROMPTEDIT
@@ -283,7 +306,7 @@ int shell_init(bool need_login)
and the strcmp attribute is used weakly by default,
int chry_shell_port_hash_strcmp(const char *hash, const char *str); */
csh_init.hash[0] = "12345678"; /*!< If there is no password, set to NULL */
- csh_init.host = "cherryadb";
+ csh_init.host = BOARD_NAME;
csh_init.user_data = NULL;
int ret = chry_shell_init(&csh, &csh_init);
@@ -293,7 +316,10 @@ int shell_init(bool need_login)
task_hdl_exec = NULL;
event_hdl = xEventGroupCreateStatic(&event_grp);
- task_hdl_repl = xTaskCreateStatic(task_repl, "task_repl", 1024U, NULL, task_repl_PRIORITY, task_stack_repl, &task_buffer_repl);
+ task_hdl_repl = NULL;
+ if (xTaskCreate(task_repl, "task_repl", CHERRYSH_TASK_REPL_STACK_SIZE, NULL, CHERRYSH_TASK_REPL_PRIORITY, (TaskHandle_t *)&task_hdl_repl) != pdPASS) {
+ return -1;
+ }
return 0;
}
@@ -315,8 +341,7 @@ static int csh_exit(int argc, char **argv)
(void)argc;
(void)argv;
- usbd_adb_close(ADB_SHELL_LOALID);
-
+ usbd_adb_close(ADB_LOCALID_SHELL);
return 0;
}
CSH_SCMD_EXPORT_ALIAS(csh_exit, exit, );
diff --git a/class/adb/usbd_adb_sync.c b/class/adb/usbd_adb_sync.c
new file mode 100644
index 00000000..b18e2b09
--- /dev/null
+++ b/class/adb/usbd_adb_sync.c
@@ -0,0 +1,932 @@
+/*
+ * Copyright (c) 2024 ~ 2026, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_adb.h"
+
+#include "stdarg.h"
+
+#define ID_STAT ADB_FOURCC('S', 'T', 'A', 'T') /* "lstat_v1": the v1 stat */
+#define ID_LIST ADB_FOURCC('L', 'I', 'S', 'T')
+#define ID_DENT ADB_FOURCC('D', 'E', 'N', 'T')
+#define ID_SEND ADB_FOURCC('S', 'E', 'N', 'D')
+#define ID_RECV ADB_FOURCC('R', 'E', 'C', 'V')
+#define ID_DONE ADB_FOURCC('D', 'O', 'N', 'E')
+#define ID_DATA ADB_FOURCC('D', 'A', 'T', 'A')
+#define ID_OKAY ADB_FOURCC('O', 'K', 'A', 'Y')
+#define ID_FAIL ADB_FOURCC('F', 'A', 'I', 'L')
+#define ID_QUIT ADB_FOURCC('Q', 'U', 'I', 'T')
+
+struct adb_sync_wire_hdr {
+ uint32_t id;
+ uint32_t len;
+};
+
+struct adb_sync_wire_stat {
+ uint32_t id;
+ uint32_t mode;
+ uint32_t size;
+ uint32_t mtime;
+};
+
+struct adb_sync_wire_dent {
+ uint32_t id;
+ uint32_t mode;
+ uint32_t size;
+ uint32_t mtime;
+ uint32_t namelen;
+};
+
+/* The one size a request has: the client refuses to send anything whose path is
+ * longer than this (SendRequest(), and the same check on the "path,mode" of a
+ * SEND), so a body arriving here cannot be longer, and a body is all a request
+ * carries. Every path this file keeps is held with one byte over, for its
+ * terminator. */
+#define ADB_SYNC_PATH_MAX 1024u
+/* How much is read from the card and sent in one DATA record. The client sends
+ * up to 64KiB at a time and this side reassembles whatever arrives in whatever
+ * pieces it arrives in, so this only decides how big the records are - and it is
+ * what sizes the payload of the one record buffer, see struct adb_sync_packet. */
+#define ADB_SYNC_DATA_MAX 2048u
+#define ADB_SYNC_NAME_MAX VFS_MAX_PATHNAME
+/* Room for the longest reason this file builds, which is a path and an errno. */
+#define ADB_SYNC_MSG_MAX 160u
+
+#define SYNC_RX_STATE_HEADER 0u
+#define SYNC_RX_STATE_BODY 1u
+#define SYNC_RX_STATE_DATA 2u
+#define SYNC_RX_STATE_SKIP 3u
+
+struct adb_sync_packet {
+ struct adb_sync_wire_hdr hdr;
+ uint8_t payload[ADB_SYNC_DATA_MAX];
+};
+
+struct adb_sync_priv {
+ uint32_t req;
+
+ uint8_t rx_state;
+ uint32_t hdr_len;
+ uint32_t body_len;
+ uint32_t rx_remain;
+
+ bool push_failed;
+ bool push_isdir;
+ int fd;
+
+ bool have_target;
+ bool target_isdir;
+ char target[ADB_SYNC_PATH_MAX + 1u];
+
+ char path[ADB_SYNC_PATH_MAX + 1u];
+
+ struct adb_sync_packet packet;
+} g_adb_sync;
+
+static void adb_sync_send(const void *data, uint32_t len)
+{
+ if (len) {
+ usbd_adb_write(ADB_LOCALID_SYNC, (const uint8_t *)data, (uint32_t)len);
+ }
+}
+
+static void adb_sync_send_record(uint32_t id, const void *payload, uint32_t len)
+{
+ g_adb_sync.packet.hdr.id = id;
+ g_adb_sync.packet.hdr.len = len;
+
+ if (len) {
+ memcpy(g_adb_sync.packet.payload, payload, len);
+ }
+
+ adb_sync_send(&g_adb_sync.packet, sizeof(g_adb_sync.packet.hdr) + len);
+}
+
+static void adb_sync_send_data_record(uint32_t len)
+{
+ g_adb_sync.packet.hdr.id = ID_DATA;
+ g_adb_sync.packet.hdr.len = len;
+
+ adb_sync_send(&g_adb_sync.packet, sizeof(g_adb_sync.packet.hdr) + len);
+}
+
+static void adb_sync_send_stat(uint32_t mode, uint32_t size, uint32_t mtime)
+{
+ struct adb_sync_wire_stat *st = (struct adb_sync_wire_stat *)&g_adb_sync.packet;
+
+ st->id = ID_STAT;
+ st->mode = mode;
+ st->size = size;
+ st->mtime = mtime;
+
+ adb_sync_send(st, (uint32_t)sizeof(*st));
+}
+
+static void adb_sync_send_dent(uint32_t mode, uint32_t size, uint32_t mtime,
+ const char *name, uint32_t namelen)
+{
+ struct adb_sync_wire_dent *dent = (struct adb_sync_wire_dent *)&g_adb_sync.packet;
+
+ dent->id = ID_DENT;
+ dent->mode = mode;
+ dent->size = size;
+ dent->mtime = mtime;
+ dent->namelen = namelen;
+
+ memcpy((uint8_t *)dent + sizeof(*dent), name, namelen);
+
+ adb_sync_send(dent, (uint32_t)sizeof(*dent) + namelen);
+}
+
+static void adb_sync_send_list_end(void)
+{
+ struct adb_sync_wire_dent *dent = (struct adb_sync_wire_dent *)&g_adb_sync.packet;
+
+ memset(dent, 0, sizeof(*dent));
+ dent->id = ID_DONE;
+
+ adb_sync_send(dent, (uint32_t)sizeof(*dent));
+}
+
+static void adb_sync_send_recv_end(void)
+{
+ adb_sync_send_record(ID_DONE, NULL, 0u);
+}
+
+static void adb_sync_fail(const char *fmt, ...)
+{
+ char msg[ADB_SYNC_MSG_MAX];
+ va_list ap;
+ int n;
+
+ va_start(ap, fmt);
+ n = vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+
+ if ((n < 0) || ((size_t)n >= sizeof(msg))) {
+ n = (int)sizeof(msg) - 1; /* the reason was long: it got cut off */
+ }
+ msg[n] = '\0';
+
+ USB_LOG_ERR("adb sync: %s\r\n", msg);
+
+ switch (g_adb_sync.req) {
+ /* A SEND has its payload and the DONE behind it still on their way, and
+ * a pushed file is answered exactly once: the rest of it is read and
+ * dropped, and only this FAIL goes back. adbd does the same, for the
+ * same reason. Only a SEND and a pull can read a FAIL at all. */
+ case ID_SEND:
+ case ID_RECV:
+ if (g_adb_sync.req == ID_SEND) {
+ g_adb_sync.push_failed = true;
+ g_adb_sync.push_isdir = false;
+ }
+
+ adb_sync_send_record(ID_FAIL, msg, (uint32_t)n);
+ break;
+
+ case ID_STAT:
+ /* A stat is a query and is answered with the record it asked for,
+ * with nothing in it: it is a valid answer, and the client reads a
+ * FAIL in its place as a protocol fault. */
+ adb_sync_send_stat(0u, 0u, 0u);
+ break;
+
+ case ID_LIST:
+ adb_sync_send_list_end();
+ break;
+
+ default:
+ break; /* no request behind it, so there is nothing to answer */
+ }
+}
+
+static bool adb_sync_path_is_root(const char *path)
+{
+ return strcmp(path, vfs_get_fs_root_path()) == 0;
+}
+
+static bool adb_sync_name_is_dir(const char *path)
+{
+ size_t i = strlen(path);
+
+ while ((i > 0u) && (path[i - 1u] != '/')) {
+ if (path[i - 1u] == '.') {
+ return false; /* it has an extension, so it names a file */
+ }
+ i--;
+ }
+
+ return true;
+}
+
+/* Where a pushed directory lands is decided by the client, and it says so in
+ * the path it sends: "src" at an existing "dst" arrives as "dst/Basename(src)/",
+ * while "src/." arrives as "dst/./" - whose "." is a component like any other
+ * here, so folding it away is exactly "the contents of src land in dst".
+ * Both spellings therefore already arrive as the path they mean, and this side
+ * never has to guess which of the two was asked for.
+ *
+ * A Windows host spells its local source with backslashes and the client takes
+ * that basename verbatim, so "adb push .\output /sdc" arrives as
+ * "/sdc/.\output/...". FatFs takes both separators alike, so the backslashes
+ * are folded into forward ones before any component is looked at - otherwise
+ * ".\output" stays a single, unmakable name and the push dies on the first
+ * file. The checks above run first, so this never turns a relative path into
+ * something that looks absolute. */
+static bool adb_sync_build_full_path(const char *root, char *path, bool *wants_dir)
+{
+ char *dst0;
+ char *dst;
+ char *src;
+ size_t len;
+ size_t root_len;
+ size_t i;
+
+ *wants_dir = false;
+
+ root_len = strlen(root);
+ len = strlen(path);
+
+ if ((root_len == 0u) || (len < root_len) || (strncmp(path, root, root_len) != 0)) {
+ return false;
+ }
+
+ if ((len > root_len) && (root[root_len - 1u] != '/') && (path[root_len] != '/')) {
+ return false;
+ }
+
+ for (i = 0u; i < len; i++) {
+ if (path[i] == '\\') {
+ path[i] = '/';
+ }
+ }
+
+ *wants_dir = (len > 1u) && (path[len - 1u] == '/');
+
+ dst0 = path;
+ dst = path;
+ src = path;
+
+ for (;;) {
+ char c = *src;
+
+ if (c == '.') {
+ if (src[1] == '\0') {
+ src++; /* "." and the path ends there */
+ } else if (src[1] == '/') {
+ src += 2; /* "./" */
+ while (*src == '/') {
+ src++;
+ }
+ continue;
+ } else if ((src[1] == '.') && ((src[2] == '\0') || (src[2] == '/'))) {
+ src += (src[2] == '/') ? 3 : 2;
+ while (*src == '/') {
+ src++;
+ }
+ goto up_one; /* ".." */
+ }
+ }
+
+ while (((c = *src++) != '\0') && (c != '/')) {
+ *dst++ = c;
+ }
+
+ if (c != '/') {
+ break; /* the path ends here */
+ }
+
+ *dst++ = '/';
+ while ((c = *src++) == '/') {
+ /* an empty component, "//" - nothing to copy */
+ }
+ src--;
+
+ continue;
+
+ up_one:
+ /* keep the topmost root directory: there is nothing above it */
+ if (((dst - dst0) != 1) || (dst[-1] != '/')) {
+ if (dst > dst0) {
+ dst--;
+ }
+ }
+ while ((dst0 < dst) && (dst[-1] != '/')) {
+ dst--;
+ }
+ }
+
+ *dst = '\0';
+
+ /* the separator that said "directory" is not part of the path */
+ if (((dst - dst0) > 1) && (dst[-1] == '/')) {
+ dst[-1] = '\0';
+ }
+
+ return true;
+}
+
+static bool adb_sync_path_join(const char *dir, const char *name, char *out, size_t out_size)
+{
+ size_t dir_len = strlen(dir);
+ int n;
+
+ if ((dir_len == 0u) || (dir[dir_len - 1u] == '/')) {
+ n = snprintf(out, out_size, "%s%s", dir, name);
+ } else {
+ n = snprintf(out, out_size, "%s/%s", dir, name);
+ }
+
+ return (n > 0) && ((size_t)n < out_size);
+}
+
+static int adb_sync_path_type(const char *path, struct vfs_stat *info)
+{
+ if (adb_sync_path_is_root(path)) {
+ memset(info, 0, sizeof(*info));
+ info->st_mode = VFS_S_IFDIR | VFS_S_IRWXU | VFS_S_IRWXG | VFS_S_IRWXO;
+ return 0;
+ }
+
+ return vfs_stat(path, info);
+}
+
+static int adb_sync_mkdir_one(const char *path)
+{
+ struct vfs_stat info;
+ bool there = (adb_sync_path_type(path, &info) == 0);
+ int ret;
+
+ if (there && ((info.st_mode & VFS_S_IFMT) == VFS_S_IFDIR)) {
+ return 0; /* already a directory: nothing to make, nothing to do */
+ }
+
+ if (there && (adb_sync_name_is_dir(path) == false)) {
+ return VFS_ERR_NOTDIR; /* it is a file, and it is meant to be one */
+ }
+
+ if (there) {
+ if (vfs_unlink(path) != 0) {
+ return VFS_ERR_NOTDIR; /* still in the way, and it could not be taken away */
+ }
+ }
+
+ ret = vfs_mkdir(path);
+ if (ret != 0) {
+ return ret; /* the port layer's own reason is the one worth passing on */
+ }
+
+ /* It says it worked, so say so too: which directories a push had to make is
+ * the first thing worth knowing when a tree lands one level off. */
+ USB_LOG_INFO("adb sync: mkdir '%s'\r\n", path);
+
+ if ((adb_sync_path_type(path, &info) != 0) ||
+ ((info.st_mode & VFS_S_IFMT) != VFS_S_IFDIR)) {
+ /* It says it worked and the directory cannot be found: believe neither,
+ * and let the caller report a failure rather than write into nothing. */
+ return VFS_ERR_NOENT;
+ }
+
+ return 0;
+}
+
+static int adb_sync_mkdirs(char *path, bool last_is_dir)
+{
+ size_t end = strlen(path);
+ size_t cut;
+ size_t i;
+ char saved;
+ int ret;
+
+ if (adb_sync_path_is_root(path)) {
+ return 0; /* the root of the volume is always there */
+ }
+
+ if (last_is_dir == false) {
+ for (cut = end; cut > 0u; cut--) {
+ if (path[cut - 1u] == '/') {
+ break;
+ }
+ }
+ if (cut <= 1u) {
+ return 0; /* the parent is the root, which always exists */
+ }
+ end = cut - 1u;
+ }
+
+ for (i = 1u; i < end; i++) {
+ if (path[i] != '/') {
+ continue;
+ }
+
+ path[i] = '\0';
+ ret = adb_sync_mkdir_one(path);
+ path[i] = '/';
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ saved = path[end];
+ path[end] = '\0'; /* in front of the file name, or of the trailing slash */
+ ret = adb_sync_mkdir_one(path);
+ path[end] = saved;
+
+ return ret;
+}
+
+static int adb_sync_write_err(const char *path, int err)
+{
+ struct vfs_stat info;
+
+ if ((err == VFS_ERR_ROFS) && (adb_sync_path_type(path, &info) == 0) &&
+ ((info.st_mode & VFS_S_IFMT) == VFS_S_IFDIR)) {
+ return VFS_ERR_ISDIR;
+ }
+
+ return err;
+}
+
+static void adb_sync_fail_write(char *path, int err)
+{
+ struct vfs_stat info;
+ char saved;
+ size_t cut;
+ size_t len = strlen(path);
+
+ if (err == VFS_ERR_NOENT) {
+ for (cut = 1u; cut < len; cut++) {
+ if (path[cut] != '/') {
+ continue;
+ }
+
+ saved = path[cut];
+ path[cut] = '\0';
+
+ if (adb_sync_path_type(path, &info) != 0) {
+ adb_sync_fail("cannot write into '%s': that directory is not there", path);
+ path[cut] = saved;
+ return;
+ }
+
+ if ((info.st_mode & VFS_S_IFMT) != VFS_S_IFDIR) {
+ adb_sync_fail("cannot write into '%s': a file is where a directory has to be", path);
+ path[cut] = saved;
+ return;
+ }
+
+ path[cut] = saved; /* an ancestor, and a directory as it should be */
+ }
+ }
+
+ adb_sync_fail("cannot write '%s': %s", path, vfs_strerror(adb_sync_write_err(path, err)));
+}
+
+static void adb_sync_remember_target(const char *path, bool is_dir)
+{
+ size_t len = strlen(path);
+
+ if (g_adb_sync.have_target) {
+ return;
+ }
+
+ if (len >= sizeof(g_adb_sync.target)) {
+ return;
+ }
+
+ memcpy(g_adb_sync.target, path, len);
+ g_adb_sync.target[len] = '\0';
+ g_adb_sync.target_isdir = is_dir;
+ g_adb_sync.have_target = true;
+}
+
+static void adb_sync_do_stat(const char *path, bool wants_dir)
+{
+ struct vfs_stat info;
+ bool as_dir = (wants_dir || adb_sync_name_is_dir(path));
+ bool is_dir;
+ int ret;
+
+ USB_LOG_INFO("adb sync: stat '%s'\r\n", path);
+
+ ret = adb_sync_path_type(path, &info);
+ is_dir = (ret == 0) && ((info.st_mode & VFS_S_IFMT) == VFS_S_IFDIR);
+
+ if (is_dir) {
+ adb_sync_remember_target(path, true);
+ adb_sync_send_stat(info.st_mode, (uint32_t)info.st_size, info.st_mtime);
+ } else if (as_dir) {
+ adb_sync_remember_target(path, true);
+ adb_sync_send_stat(VFS_S_IFDIR | VFS_S_IRWXU | VFS_S_IRWXG | VFS_S_IRWXO, 0u, 0u);
+ } else if (ret == 0) {
+ adb_sync_remember_target(path, false);
+ adb_sync_send_stat(info.st_mode, (uint32_t)info.st_size, info.st_mtime);
+ } else {
+ adb_sync_remember_target(path, false);
+ adb_sync_fail("'%s' does not exist", path);
+ }
+}
+
+static void adb_sync_do_list(char *path)
+{
+ struct vfs_dirent *de;
+ struct vfs_stat info;
+ VFS_DIR *dir;
+ uint32_t namelen;
+ char *entry = (char *)g_adb_sync.packet.payload;
+
+ USB_LOG_INFO("adb sync: listing '%s'\r\n", path);
+
+ dir = vfs_opendir(path);
+ if (!dir) {
+ adb_sync_fail("cannot read '%s' as a directory", path);
+ return;
+ }
+
+ while ((de = vfs_readdir(dir)) != NULL) {
+ namelen = de->d_namlen;
+
+ /* "." and ".." are never part of a listing */
+ if ((namelen == 0u) || (namelen > ADB_SYNC_NAME_MAX)) {
+ continue;
+ }
+ if ((strcmp(de->d_name, ".") == 0) || (strcmp(de->d_name, "..") == 0)) {
+ continue;
+ }
+
+ if (adb_sync_path_join(path, de->d_name, entry,
+ sizeof(g_adb_sync.packet.payload)) == false) {
+ continue;
+ }
+
+ if (vfs_stat(entry, &info) == 0) {
+ adb_sync_send_dent(info.st_mode, (uint32_t)info.st_size, info.st_mtime,
+ de->d_name, namelen);
+ }
+ }
+
+ vfs_closedir(dir);
+
+ adb_sync_send_list_end();
+}
+
+static void adb_sync_do_recv(const char *path)
+{
+ int fd;
+ int n;
+
+ USB_LOG_INFO("adb sync: reading '%s'\r\n", path);
+
+ fd = vfs_open(path, VFS_O_RDONLY);
+ if (fd < 0) {
+ adb_sync_fail("cannot open '%s' for reading: %s", path, vfs_strerror(fd));
+ return;
+ }
+
+ for (;;) {
+ n = vfs_read(fd, g_adb_sync.packet.payload, ADB_SYNC_DATA_MAX);
+ if (n < 0) {
+ vfs_close(fd);
+ adb_sync_fail("cannot read '%s': %s", path, vfs_strerror(n));
+ return; /* the FAIL is the answer; the client reads it as failure */
+ }
+
+ if (n == 0) {
+ break;
+ }
+
+ adb_sync_send_data_record((uint32_t)n);
+ }
+
+ vfs_close(fd);
+
+ adb_sync_send_recv_end();
+}
+
+static void adb_sync_do_send(char *path, bool wants_dir, uint32_t mode)
+{
+ int ret;
+
+ if ((mode & VFS_S_IFMT) == VFS_S_IFDIR) {
+ ret = adb_sync_mkdirs(path, true);
+ if (ret != 0) {
+ adb_sync_fail("cannot make '%s' a directory: %s", path, vfs_strerror(ret));
+ return;
+ }
+
+ g_adb_sync.push_isdir = true;
+ g_adb_sync.fd = -1;
+ return;
+ }
+
+ if (g_adb_sync.have_target && g_adb_sync.target_isdir &&
+ (strcmp(path, g_adb_sync.target) == 0)) {
+ ret = adb_sync_mkdirs(path, true);
+ if (ret != 0) {
+ adb_sync_fail("cannot make '%s' a directory: %s", path, vfs_strerror(ret));
+ } else {
+ adb_sync_fail("'%s' is a directory, so no file can be written at it", path);
+ }
+ return;
+ }
+
+ if (wants_dir) {
+ ret = adb_sync_mkdirs(path, true);
+ if (ret != 0) {
+ adb_sync_fail("cannot make '%s' a directory: %s", path, vfs_strerror(ret));
+ } else {
+ adb_sync_fail("'%s' is a directory, so no file can be written at it", path);
+ }
+ return;
+ }
+
+ USB_LOG_INFO("adb sync: writing '%s'\r\n", path);
+
+ g_adb_sync.fd = vfs_open(path, VFS_O_WRONLY);
+ if (g_adb_sync.fd == VFS_ERR_NOENT) {
+ ret = adb_sync_mkdirs(path, false);
+ if (ret != 0) {
+ adb_sync_fail_write(path, ret);
+ return;
+ }
+ g_adb_sync.fd = vfs_open(path, VFS_O_WRONLY);
+ }
+
+ if (g_adb_sync.fd < 0) {
+ ret = g_adb_sync.fd;
+ g_adb_sync.fd = -1;
+ adb_sync_fail_write(path, ret);
+ return;
+ }
+}
+
+static void adb_sync_do_send_done(void)
+{
+ if (g_adb_sync.fd >= 0) {
+ vfs_close(g_adb_sync.fd);
+ g_adb_sync.fd = -1;
+ }
+
+ if (g_adb_sync.push_isdir) {
+ g_adb_sync.push_isdir = false;
+ adb_sync_send_record(ID_OKAY, NULL, 0u);
+ return;
+ }
+
+ if (g_adb_sync.push_failed) {
+ g_adb_sync.push_failed = false;
+ return;
+ }
+
+ adb_sync_send_record(ID_OKAY, NULL, 0u);
+}
+
+static void adb_sync_data_write(const uint8_t *data, uint32_t len)
+{
+ int n;
+
+ if (g_adb_sync.fd < 0) {
+ return; /* refused, or a directory: the bytes are dropped */
+ }
+
+ n = vfs_write(g_adb_sync.fd, data, len);
+ if (n != (int)len) {
+ int err = (n < 0) ? n : VFS_ERR_IO; /* a short write counts as I/O */
+
+ vfs_close(g_adb_sync.fd);
+ g_adb_sync.fd = -1;
+
+ adb_sync_fail("cannot write '%s': %s", g_adb_sync.path, vfs_strerror(err));
+ }
+}
+
+static void adb_sync_reset(void)
+{
+ if (g_adb_sync.fd >= 0) {
+ vfs_close(g_adb_sync.fd);
+ g_adb_sync.fd = -1;
+ }
+
+ g_adb_sync.rx_state = SYNC_RX_STATE_HEADER;
+ g_adb_sync.hdr_len = 0;
+ g_adb_sync.body_len = 0;
+ g_adb_sync.rx_remain = 0;
+ g_adb_sync.req = 0;
+ g_adb_sync.push_failed = false;
+ g_adb_sync.push_isdir = false;
+ g_adb_sync.have_target = false;
+ g_adb_sync.target_isdir = false;
+}
+
+static void adb_sync_dispatch(uint32_t id, char *body)
+{
+ bool wants_dir = false;
+ uint32_t mode = 0u;
+ size_t len;
+
+ g_adb_sync.req = id;
+
+ if (id == ID_QUIT) {
+ adb_sync_reset();
+ return;
+ }
+
+ if ((id != ID_STAT) && (id != ID_LIST) && (id != ID_RECV) && (id != ID_SEND)) {
+ adb_sync_fail("unsupported request 0x%08x", (unsigned)id);
+ return;
+ }
+
+ if (id == ID_SEND) {
+ char *comma = strrchr(body, ',');
+
+ if (comma == NULL) {
+ adb_sync_fail("the SEND request came without a mode behind its path");
+ return;
+ }
+
+ mode = (uint32_t)strtoul(comma + 1, NULL, 0);
+ *comma = '\0';
+ }
+
+ len = strlen(body);
+ memcpy(g_adb_sync.path, body, len + 1u);
+
+ if (adb_sync_build_full_path(vfs_get_fs_root_path(), g_adb_sync.path, &wants_dir) == false) {
+ adb_sync_fail("the path has to be absolute, starting with '%s', not '%s'",
+ vfs_get_fs_root_path(), g_adb_sync.path);
+ return;
+ }
+
+ switch (id) {
+ case ID_STAT:
+ adb_sync_do_stat(g_adb_sync.path, wants_dir);
+ break;
+ case ID_LIST:
+ adb_sync_do_list(g_adb_sync.path);
+ break;
+ case ID_RECV:
+ adb_sync_do_recv(g_adb_sync.path);
+ break;
+ case ID_SEND:
+ adb_sync_do_send(g_adb_sync.path, wants_dir, mode);
+ break;
+ default:
+ break; /* not reachable: the four above are the only ones left */
+ }
+}
+
+static void adb_sync_header_ready(void)
+{
+ uint32_t id = g_adb_sync.packet.hdr.id;
+ uint32_t len = g_adb_sync.packet.hdr.len;
+
+ if (id == ID_DONE) {
+ adb_sync_do_send_done();
+ g_adb_sync.rx_state = SYNC_RX_STATE_HEADER;
+ return;
+ }
+
+ if (id == ID_DATA) {
+ g_adb_sync.rx_remain = len;
+ g_adb_sync.rx_state = len ? SYNC_RX_STATE_DATA : SYNC_RX_STATE_HEADER;
+ return;
+ }
+
+ if ((id == ID_STAT) || (id == ID_LIST) || (id == ID_RECV) || (id == ID_SEND)) {
+ if (len > ADB_SYNC_PATH_MAX) {
+ g_adb_sync.req = id;
+ g_adb_sync.rx_remain = len;
+ g_adb_sync.rx_state = SYNC_RX_STATE_SKIP; /* read it and drop it */
+ adb_sync_fail("a request of %u bytes is longer than the %u bytes a path may be",
+ (unsigned)len, (unsigned)ADB_SYNC_PATH_MAX);
+ return;
+ }
+
+ g_adb_sync.body_len = 0;
+ g_adb_sync.rx_remain = len;
+
+ if (len == 0) {
+ g_adb_sync.packet.payload[0] = '\0';
+ adb_sync_dispatch(id, (char *)g_adb_sync.packet.payload);
+ g_adb_sync.rx_state = SYNC_RX_STATE_HEADER;
+ } else {
+ g_adb_sync.rx_state = SYNC_RX_STATE_BODY;
+ }
+ return;
+ }
+
+ g_adb_sync.rx_remain = len;
+ g_adb_sync.rx_state = len ? SYNC_RX_STATE_SKIP : SYNC_RX_STATE_HEADER;
+ adb_sync_dispatch(id, (char *)g_adb_sync.packet.payload);
+}
+
+static void adb_sync_consume(const uint8_t *data, uint32_t len)
+{
+ uint8_t *body = g_adb_sync.packet.payload;
+ uint32_t take;
+
+ while (len) {
+ switch (g_adb_sync.rx_state) {
+ case SYNC_RX_STATE_HEADER:
+ take = sizeof(struct adb_sync_wire_hdr) - g_adb_sync.hdr_len;
+ if (take > len) {
+ take = len;
+ }
+ memcpy((uint8_t *)&g_adb_sync.packet.hdr + g_adb_sync.hdr_len, data, take);
+ g_adb_sync.hdr_len += take;
+ data += take;
+ len -= take;
+
+ if (g_adb_sync.hdr_len == sizeof(struct adb_sync_wire_hdr)) {
+ g_adb_sync.hdr_len = 0;
+ adb_sync_header_ready();
+ }
+ break;
+
+ case SYNC_RX_STATE_BODY:
+ take = (g_adb_sync.rx_remain < len) ? g_adb_sync.rx_remain : len;
+ memcpy(body + g_adb_sync.body_len, data, take);
+ g_adb_sync.body_len += take;
+ g_adb_sync.rx_remain -= take;
+ data += take;
+ len -= take;
+
+ if (g_adb_sync.rx_remain == 0) {
+ body[g_adb_sync.body_len] = '\0';
+ adb_sync_dispatch(g_adb_sync.packet.hdr.id, (char *)body);
+ g_adb_sync.rx_state = SYNC_RX_STATE_HEADER;
+ }
+ break;
+
+ case SYNC_RX_STATE_DATA:
+ take = (g_adb_sync.rx_remain < len) ? g_adb_sync.rx_remain : len;
+ adb_sync_data_write(data, take);
+ g_adb_sync.rx_remain -= take;
+ data += take;
+ len -= take;
+
+ if (g_adb_sync.rx_remain == 0) {
+ g_adb_sync.rx_state = SYNC_RX_STATE_HEADER;
+ }
+ break;
+
+ case SYNC_RX_STATE_SKIP:
+ default:
+ take = (g_adb_sync.rx_remain < len) ? g_adb_sync.rx_remain : len;
+ g_adb_sync.rx_remain -= take;
+ data += take;
+ len -= take;
+
+ if (g_adb_sync.rx_remain == 0) {
+ g_adb_sync.rx_state = SYNC_RX_STATE_HEADER;
+ }
+ break;
+ }
+ }
+}
+
+static void usbd_adb_sync_on_open(uint32_t remoteid)
+{
+ adb_sync_reset();
+ USB_LOG_INFO("adb sync open, remoteid:%u\r\n", (unsigned)remoteid);
+}
+
+static void usbd_adb_sync_on_close(uint32_t remoteid)
+{
+ (void)remoteid;
+
+ adb_sync_reset();
+ USB_LOG_INFO("adb sync close, remoteid:%u\r\n", (unsigned)remoteid);
+}
+
+static void usbd_adb_sync_on_write(uint32_t remoteid, const uint8_t *data, uint32_t len)
+{
+ (void)remoteid;
+
+ if (!data || !len) {
+ return;
+ }
+
+ adb_sync_consume(data, len);
+}
+
+static const struct adb_service adb_sync_service = {
+ .name = "sync:",
+ .localid = ADB_LOCALID_SYNC,
+ .on_open = usbd_adb_sync_on_open,
+ .on_close = usbd_adb_sync_on_close,
+ .on_write = usbd_adb_sync_on_write,
+};
+
+void usbd_adb_sync_init(void)
+{
+ g_adb_sync.fd = -1;
+ adb_sync_reset();
+
+ if (usbd_adb_service_register(&adb_sync_service) != 0) {
+ USB_LOG_ERR("adb sync: registering the service failed\r\n");
+ }
+}
diff --git a/class/aoa/usbh_aoa.c b/class/aoa/usbh_aoa.c
index 02d9fab5..22426dad 100644
--- a/class/aoa/usbh_aoa.c
+++ b/class/aoa/usbh_aoa.c
@@ -36,7 +36,7 @@ int usbh_aoa_switch(struct usbh_hubport *hport, struct aoa_string_info *info)
setup->wLength = 2;
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
- if (ret < 0) {
+ if (ret < 2) {
return ret;
}
diff --git a/class/audio/usb_audio.h b/class/audio/usb_audio.h
index 95609765..efb758ae 100644
--- a/class/audio/usb_audio.h
+++ b/class/audio/usb_audio.h
@@ -687,6 +687,10 @@ struct audio_cs_if_as_general_descriptor {
#define AUDIO_SIZEOF_AS_GENERAL_DESC (7)
+#ifndef CONFIG_USBHOST_AUDIO_MAX_SAMPLE_FREQ_NUM
+#define CONFIG_USBHOST_AUDIO_MAX_SAMPLE_FREQ_NUM 8
+#endif
+
struct audio_cs_if_as_format_type_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
@@ -696,7 +700,7 @@ struct audio_cs_if_as_format_type_descriptor {
uint8_t bSubframeSize;
uint8_t bBitResolution;
uint8_t bSamFreqType;
- uint8_t tSamFreq[3];
+ uint8_t tSamFreq[3 * CONFIG_USBHOST_AUDIO_MAX_SAMPLE_FREQ_NUM];
} __PACKED;
#define AUDIO_SIZEOF_FORMAT_TYPE_DESC(bSamFreqType) (8 + 3 * (bSamFreqType))
@@ -1344,19 +1348,27 @@ struct audio_v2_control_range3_param_block {
#define AUDIO_SAMPLE_FREQ_4B(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), \
(uint8_t)((frq >> 16)), (uint8_t)((frq >> 24))
-/* format 10.14 */
-#define AUDIO_FREQ_TO_FEEDBACK_FS(freq) ((freq << 10) / 1000)
-#define AUDIO_FEEDBACK_TO_BUF_FS(buf, feedback) \
- buf[0] = ((feedback << 4) & 0xFFU); \
- buf[1] = (((feedback << 4) >> 8U) & 0xFFU); \
- buf[2] = (((feedback << 4) >> 16U) & 0xFFU)
+/* FS feedback uses 10.14 samples per audio data service interval. */
+#define AUDIO_FREQ_TO_FEEDBACK_FS(freq) ((uint32_t)(((uint64_t)(freq) << 10U) / 1000U))
+#define AUDIO_FEEDBACK_TO_FREQ_FS(feedback) ((uint32_t)(((uint64_t)(feedback) * 1000U) >> 10U))
+#define AUDIO_FEEDBACK_TO_BUF_FS_INTERVAL(buf, feedback, interval) do { \
+ uint32_t audio_feedback_value = (uint32_t)((uint64_t)(feedback) << ((interval) + 3U)); \
+ (buf)[0] = (uint8_t)(audio_feedback_value); \
+ (buf)[1] = (uint8_t)(audio_feedback_value >> 8U); \
+ (buf)[2] = (uint8_t)(audio_feedback_value >> 16U); \
+} while (0)
+#define AUDIO_FEEDBACK_TO_BUF_FS(buf, feedback) AUDIO_FEEDBACK_TO_BUF_FS_INTERVAL(buf, feedback, 1U)
-/* format 16.16 */
-#define AUDIO_FREQ_TO_FEEDBACK_HS(freq) ((freq << 13) / 1000)
-#define AUDIO_FEEDBACK_TO_BUF_HS(buf, feedback) \
- buf[0] = (((feedback & 0x00001FFFu) << 3) & 0xFFu); \
- buf[1] = ((((feedback & 0x00001FFFu) << 3) >> 8) & 0xFFu); \
- buf[2] = (((feedback & 0x01FFE000u) >> 13) & 0xFFu); \
- buf[3] = (((feedback & 0x01FFE000u) >> 21) & 0xFFu)
+/* Keep HS feedback in 16.16 samples per microframe, then scale it by the audio data endpoint interval when serialized. */
+#define AUDIO_FREQ_TO_FEEDBACK_HS(freq) ((uint32_t)(((uint64_t)(freq) << 16U) / 8000U))
+#define AUDIO_FEEDBACK_TO_FREQ_HS(feedback) ((uint32_t)(((uint64_t)(feedback) * 8000U) >> 16U))
+#define AUDIO_FEEDBACK_TO_BUF_HS_INTERVAL(buf, feedback, interval) do { \
+ uint32_t audio_feedback_value = (uint32_t)((uint64_t)(feedback) << ((interval) - 1U)); \
+ (buf)[0] = (uint8_t)(audio_feedback_value); \
+ (buf)[1] = (uint8_t)(audio_feedback_value >> 8U); \
+ (buf)[2] = (uint8_t)(audio_feedback_value >> 16U); \
+ (buf)[3] = (uint8_t)(audio_feedback_value >> 24U); \
+} while (0)
+#define AUDIO_FEEDBACK_TO_BUF_HS(buf, feedback) AUDIO_FEEDBACK_TO_BUF_HS_INTERVAL(buf, feedback, 4U)
#endif /* USB_AUDIO_H */
diff --git a/class/audio/usbd_audio.c b/class/audio/usbd_audio.c
index 9e4e2ac0..446ecdf0 100644
--- a/class/audio/usbd_audio.c
+++ b/class/audio/usbd_audio.c
@@ -6,19 +6,53 @@
#include "usbd_core.h"
#include "usbd_audio.h"
-struct audio_entity_param {
- uint32_t wCur;
- uint32_t wMin;
- uint32_t wMax;
- uint32_t wRes;
-};
-
struct usbd_audio_priv {
struct audio_entity_info *table;
uint8_t num;
uint16_t uac_version;
} g_usbd_audio[CONFIG_USBDEV_MAX_BUS];
+static float volume_hex2float(int16_t volume_hex)
+{
+ return (float)volume_hex / 256.0f;
+}
+
+static int16_t volume_float2hex(float volume_db)
+{
+ return (int16_t)(volume_db * 256);
+}
+
+static float volume_roundf(float x) {
+ if (x >= 0.0f) {
+ int intpart = (int)x;
+ float frac = x - (float)intpart;
+
+ if (frac >= 0.5f) {
+ intpart++;
+ }
+ return (float)intpart;
+ } else {
+ int intpart = (int)x;
+ float frac = x - (float)intpart;
+ if (frac <= -0.5f) {
+ intpart--;
+ }
+ return (float)intpart;
+ }
+}
+
+static float volume_align_to_res(int16_t volume_hex, int16_t res_hex)
+{
+ float val = volume_hex2float(volume_hex);
+ float res = volume_hex2float(res_hex);
+
+ if (res == 0.0f) {
+ return val;
+ }
+
+ return volume_roundf(val / res) * res;
+}
+
static int audio_class_endpoint_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
uint8_t control_selector;
@@ -66,8 +100,14 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
uint8_t control_selector;
uint8_t ch;
uint8_t mute;
- uint16_t volume;
- int volume_db = 0;
+ int16_t volume_hex_curr;
+ int16_t volume_hex_min;
+ int16_t volume_hex_max;
+ int16_t volume_hex_res;
+ float volume_db_curr = 0.0f;
+ float volume_db_min = 0.0f;
+ float volume_db_max = 0.0f;
+ float volume_db_res = 0.0f;
uint32_t sampling_freq = 0;
const char *mute_string[2] = { "off", "on" };
@@ -93,6 +133,11 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
USB_LOG_DBG("Audio entity_id:%02x, subtype:%02x, cs:%02x\r\n", entity_id, subtype, control_selector);
+ usbd_audio_get_volume_range(busid, ep, ch, &volume_db_min, &volume_db_max, &volume_db_res);
+ volume_hex_res = volume_float2hex(volume_db_res);
+ volume_hex_min = volume_float2hex(volume_db_min);
+ volume_hex_max = volume_float2hex(volume_db_max);
+
switch (subtype) {
case AUDIO_CONTROL_FEATURE_UNIT:
switch (control_selector) {
@@ -130,39 +175,29 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
if (g_usbd_audio[busid].uac_version < 0x0200) {
switch (setup->bRequest) {
case AUDIO_REQUEST_SET_CUR:
- memcpy(&volume, *data, 2);
- if (volume < 0x8000) {
- volume_db = volume / 256;
- } else {
- volume_db = (volume - 0x10000) / 256;
- }
- USB_LOG_DBG("Set ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
- usbd_audio_set_volume(busid, ep, ch, volume_db);
+ memcpy(&volume_hex_curr, *data, 2);
+ volume_db_curr = volume_align_to_res(volume_hex_curr, volume_hex_res);
+ volume_db_curr = MIN(MAX(volume_db_curr, volume_db_min), volume_db_max);
+ USB_LOG_DBG("Set ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%.2f dB\r\n", ep, ch, volume_hex_curr, volume_db_curr);
+ usbd_audio_set_volume(busid, ep, ch, volume_db_curr);
break;
case AUDIO_REQUEST_GET_CUR:
- volume_db = usbd_audio_get_volume(busid, ep, ch);
- if (volume_db >= 0) {
- volume = volume_db * 256;
- } else {
- volume = volume_db * 256 + 0x10000;
- }
- USB_LOG_DBG("Get ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
- memcpy(*data, &volume, 2);
+ volume_db_curr = usbd_audio_get_volume(busid, ep, ch);
+ volume_hex_curr = volume_float2hex(volume_db_curr);
+ USB_LOG_DBG("Get ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%.2f dB\r\n", ep, ch, volume_hex_curr, volume_db_curr);
+ memcpy(*data, &volume_hex_curr, 2);
*len = 2;
break;
case AUDIO_REQUEST_GET_MIN:
- (*data)[0] = 0x00; /* -100 dB */
- (*data)[1] = 0x9c;
+ memcpy(*data, &volume_hex_min, 2);
*len = 2;
break;
case AUDIO_REQUEST_GET_MAX:
- (*data)[0] = 0x00; /* 0 dB */
- (*data)[1] = 0x00;
+ memcpy(*data, &volume_hex_max, 2);
*len = 2;
break;
case AUDIO_REQUEST_GET_RES:
- (*data)[0] = 0x00; /* 1 dB */
- (*data)[1] = 0x01;
+ memcpy(*data, &volume_hex_res, 2);
*len = 2;
break;
default:
@@ -172,32 +207,26 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
switch (setup->bRequest) {
case AUDIO_REQUEST_CUR:
if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
- volume_db = usbd_audio_get_volume(busid, ep, ch);
- if (volume_db >= 0) {
- volume = volume_db * 256;
- } else {
- volume = volume_db * 256 + 0x10000;
- }
- USB_LOG_DBG("Get ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
- memcpy(*data, &volume, 2);
+ volume_db_curr = usbd_audio_get_volume(busid, ep, ch);
+ volume_hex_curr = volume_float2hex(volume_db_curr);
+ USB_LOG_DBG("Get ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume_hex_curr, volume_db_curr);
+ memcpy(*data, &volume_hex_curr, 2);
*len = 2;
} else {
- memcpy(&volume, *data, 2);
- if (volume < 0x8000) {
- volume_db = volume / 256;
- } else {
- volume_db = (volume - 0x10000) / 256;
- }
- USB_LOG_DBG("Set ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
- usbd_audio_set_volume(busid, ep, ch, volume_db);
+ memcpy(&volume_hex_curr, *data, 2);
+ volume_db_curr = volume_align_to_res(volume_hex_curr, volume_hex_res);
+ volume_db_curr = MIN(MAX(volume_db_curr, volume_db_min), volume_db_max);
+ USB_LOG_DBG("Set ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume_hex_curr, volume_db_curr);
+ usbd_audio_set_volume(busid, ep, ch, volume_db_curr);
}
break;
case AUDIO_REQUEST_RANGE:
if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
*((uint16_t *)(*data + 0)) = 1;
- *((uint16_t *)(*data + 2)) = 0x9c00; /* MIN -100 dB */
- *((uint16_t *)(*data + 4)) = 0x0000; /* MAX 0 dB */
- *((uint16_t *)(*data + 6)) = 0x100; /* RES 1 dB */
+
+ *((uint16_t *)(*data + 2)) = volume_hex_min;
+ *((uint16_t *)(*data + 4)) = volume_hex_max;
+ *((uint16_t *)(*data + 6)) = volume_hex_res;
*len = 8;
} else {
}
@@ -312,7 +341,7 @@ struct usbd_interface *usbd_audio_init_intf(uint8_t busid,
return intf;
}
-__WEAK void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume_db)
+__WEAK void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, float volume_db)
{
(void)busid;
(void)ep;
@@ -320,13 +349,24 @@ __WEAK void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int vol
(void)volume_db;
}
-__WEAK int usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch)
+__WEAK float usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch)
{
(void)busid;
(void)ep;
(void)ch;
- return 0;
+ return 0.0f;
+}
+
+__WEAK void usbd_audio_get_volume_range(uint8_t busid, uint8_t ep, uint8_t ch, float *min, float *max, float *res)
+{
+ (void)busid;
+ (void)ep;
+ (void)ch;
+
+ *min = -100.0f;
+ *max = 0.0f;
+ *res = 1.0f;
}
__WEAK void usbd_audio_set_mute(uint8_t busid, uint8_t ep, uint8_t ch, bool mute)
diff --git a/class/audio/usbd_audio.h b/class/audio/usbd_audio.h
index 75a0b17d..c74f54a4 100644
--- a/class/audio/usbd_audio.h
+++ b/class/audio/usbd_audio.h
@@ -27,8 +27,9 @@ struct usbd_interface *usbd_audio_init_intf(uint8_t busid, struct usbd_interface
void usbd_audio_open(uint8_t busid, uint8_t intf);
void usbd_audio_close(uint8_t busid, uint8_t intf);
-void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume_db);
-int usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch);
+void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, float volume_db);
+float usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch);
+void usbd_audio_get_volume_range(uint8_t busid, uint8_t ep, uint8_t ch, float *min, float *max, float *res);
void usbd_audio_set_mute(uint8_t busid, uint8_t ep, uint8_t ch, bool mute);
bool usbd_audio_get_mute(uint8_t busid, uint8_t ep, uint8_t ch);
void usbd_audio_set_sampling_freq(uint8_t busid, uint8_t ep, uint32_t sampling_freq);
diff --git a/class/audio/usbh_audio.c b/class/audio/usbh_audio.c
index ee0a3349..5ef08c90 100644
--- a/class/audio/usbh_audio.c
+++ b/class/audio/usbh_audio.c
@@ -37,6 +37,25 @@ static int16_t volume_float2hex(float volume_db)
return (int16_t)(volume_db * 256);
}
+static float volume_roundf(float x) {
+ if (x >= 0.0f) {
+ int intpart = (int)x;
+ float frac = x - (float)intpart;
+
+ if (frac >= 0.5f) {
+ intpart++;
+ }
+ return (float)intpart;
+ } else {
+ int intpart = (int)x;
+ float frac = x - (float)intpart;
+ if (frac <= -0.5f) {
+ intpart--;
+ }
+ return (float)intpart;
+ }
+}
+
static struct usbh_audio *usbh_audio_class_alloc(void)
{
uint8_t devno;
@@ -385,7 +404,7 @@ feature_found:
setup->wLength = 2;
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
- if (ret < 0) {
+ if (ret < 2) {
return ret;
}
@@ -400,7 +419,7 @@ feature_found:
setup->wLength = 2;
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
- if (ret < 0) {
+ if (ret < 2) {
return ret;
}
@@ -415,7 +434,7 @@ feature_found:
setup->wLength = 2;
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
- if (ret < 0) {
+ if (ret < 2) {
return ret;
}
memcpy(volume_max, g_audio_buf, 2);
@@ -429,7 +448,7 @@ feature_found:
setup->wLength = 2;
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
- if (ret < 0) {
+ if (ret < 2) {
return ret;
}
memcpy(volume_res, g_audio_buf, 2);
@@ -486,7 +505,7 @@ feature_found:
/* Calculate target volume in float to avoid int16_t calculation overflow. */
volume_db = volume_hex2float(volume_min) + (volume_hex2float(volume_max) - volume_hex2float(volume_min)) * (float)volume / 100.0f;
/* Round to the nearest float value based on volume_res. */
- volume_db = roundf(volume_db / volume_hex2float(volume_res)) * volume_hex2float(volume_res);
+ volume_db = volume_roundf(volume_db / volume_hex2float(volume_res)) * volume_hex2float(volume_res);
volume_hex = volume_float2hex(volume_db);
USB_LOG_INFO("ch %d volume info: (%.2f dB ~ %.2f dB, step: %.2f dB)\r\n",
@@ -694,12 +713,12 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
case AUDIO_STREAMING_FORMAT_TYPE: {
struct audio_cs_if_as_format_type_descriptor *desc = (struct audio_cs_if_as_format_type_descriptor *)p;
- USB_ASSERT(desc->bSamFreqType == 1);
+ USB_ASSERT(desc->bSamFreqType <= CONFIG_USBHOST_AUDIO_MAX_SAMPLE_FREQ_NUM && desc->bSamFreqType > 0);
USB_ASSERT(desc->bNrChannels <= CONFIG_USBHOST_AUDIO_MAX_CHANNELS);
USB_ASSERT(cur_alt_setting < CONFIG_USBHOST_MAX_INTF_ALTSETTINGS);
audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].bNrChannels = desc->bNrChannels;
- memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_format[cur_alt_setting], desc, AUDIO_SIZEOF_FORMAT_TYPE_DESC(1));
+ memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_format[cur_alt_setting], desc, AUDIO_SIZEOF_FORMAT_TYPE_DESC(desc->bSamFreqType));
} break;
default:
break;
diff --git a/class/cdc/usb_cdc.h b/class/cdc/usb_cdc.h
index a21bc3b2..be718301 100644
--- a/class/cdc/usb_cdc.h
+++ b/class/cdc/usb_cdc.h
@@ -275,6 +275,9 @@
#define CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE 0x01
#define CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE 0x2A
+#define CDC_NCM_CONNECT_SPEED_UPSTREAM 0x004C4B40U /* 5Mbps */
+#define CDC_NCM_CONNECT_SPEED_DOWNSTREAM 0x004C4B40U /* 5Mbps */
+
#define CDC_NCM_NTH16_SIGNATURE 0x484D434E
#define CDC_NCM_NDP16_SIGNATURE_NCM0 0x304D434E
#define CDC_NCM_NDP16_SIGNATURE_NCM1 0x314D434E
@@ -477,6 +480,89 @@ struct cdc_ncm_ndp16 {
0x02, /* bmAttributes */ \
WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
0x00 /* bInterval */
+
+/*Length of template descriptor: 84 bytes*/
+#define USB3_CDC_ACM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 4 + 5 + 7 + 6 + 9 + 7 + 6 + 7 + 6)
+
+#define USB3_CDC_ACM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, bMaxBurst, maxstream, str_idx) \
+ /* Interface Associate */ \
+ 0x08, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
+ bFirstInterface, /* bFirstInterface */ \
+ 0x02, /* bInterfaceCount */ \
+ USB_DEVICE_CLASS_CDC, /* bFunctionClass */ \
+ CDC_ABSTRACT_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_ABSTRACT_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_CALL_MANAGEMENT, /* bDescriptorSubtype */ \
+ 0x00, /* bmCapabilities */ \
+ (uint8_t)(bFirstInterface + 1), /* bDataInterface */ \
+ 0x04, /* bLength */ \
+ CDC_CS_INTERFACE, /* bDescriptorType */ \
+ CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, /* bDescriptorSubtype */ \
+ 0x02, /* bmCapabilities */ \
+ 0x05, /* bLength */ \
+ CDC_CS_INTERFACE, /* bDescriptorType */ \
+ CDC_FUNC_DESC_UNION, /* bDescriptorSubtype */ \
+ bFirstInterface, /* bMasterInterface */ \
+ (uint8_t)(bFirstInterface + 1), /* bSlaveInterface0 */ \
+ 0x07, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
+ int_ep, /* bEndpointAddress */ \
+ 0x03, /* bmAttributes */ \
+ 0x08, 0x00, /* wMaxPacketSize */ \
+ 0x0a, /* bInterval */ \
+ 0x06, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_ENDPOINT_COMPANION, /* bDescriptorType */ \
+ 0x00, /* bMaxBurst */ \
+ 0x00, /* bmAttributes */ \
+ WBVAL(0x08), /* wBytesPerInterval */ \
+ 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 */ \
+ 0x06, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_ENDPOINT_COMPANION, /* bDescriptorType */ \
+ bMaxBurst, /* bMaxBurst */ \
+ maxstream, /* bmAttributes */ \
+ WBVAL(0), /* wBytesPerInterval */ \
+ 0x07, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \
+ in_ep, /* bEndpointAddress */ \
+ 0x02, /* bmAttributes */ \
+ WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
+ 0x00, /* bInterval */ \
+ 0x06, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_ENDPOINT_COMPANION, /* bDescriptorType */ \
+ bMaxBurst, /* bMaxBurst */ \
+ maxstream, /* bmAttributes */ \
+ WBVAL(0) /* wBytesPerInterval */ \
// clang-format on
/*Length of template descriptor: 66 bytes*/
diff --git a/class/cdc/usbd_cdc_ecm.c b/class/cdc/usbd_cdc_ecm.c
index dde40907..bb3071ee 100644
--- a/class/cdc/usbd_cdc_ecm.c
+++ b/class/cdc/usbd_cdc_ecm.c
@@ -27,6 +27,7 @@ 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 volatile bool g_cdc_ecm_opened = false;
static uint32_t g_connect_speed_table[2] = { CDC_ECM_CONNECT_SPEED_UPSTREAM,
CDC_ECM_CONNECT_SPEED_DOWNSTREAM };
@@ -122,12 +123,23 @@ void cdc_ecm_notify_handler(uint8_t busid, uint8_t event, void *arg)
g_current_net_status = 0;
g_cdc_ecm_rx_data_length = 0;
g_cdc_ecm_tx_data_length = 0;
+ g_cdc_ecm_opened = false;
break;
case USBD_EVENT_CONFIGURED:
+ break;
+ case USBD_EVENT_SET_INTERFACE: {
+ struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)arg;
+ if (intf->bAlternateSetting) {
+ g_cdc_ecm_opened = true;
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
- usbd_cdc_ecm_start_read(g_cdc_ecm_rx_buffer, CONFIG_CDC_ECM_ETH_MAX_SEGSZE);
+ usbd_cdc_ecm_start_read(g_cdc_ecm_rx_buffer, CONFIG_CDC_ECM_ETH_MAX_SEGSZE);
#endif
- break;
+ } else {
+ g_cdc_ecm_rx_data_length = 0;
+ g_cdc_ecm_tx_data_length = 0;
+ g_cdc_ecm_opened = false;
+ }
+ } break;
default:
break;
@@ -171,6 +183,8 @@ void cdc_ecm_int_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len)
{
+ int ret;
+
if (!usb_device_is_configured(0)) {
return -USB_ERR_NOTCONN;
}
@@ -179,10 +193,19 @@ int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len)
return -USB_ERR_BUSY;
}
+ if (!g_cdc_ecm_opened) {
+ return -USB_ERR_NOTCONN;
+ }
+
g_cdc_ecm_tx_data_length = len;
USB_LOG_DBG("txlen:%d\r\n", g_cdc_ecm_tx_data_length);
- return usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr, buf, len);
+ ret = usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr, buf, len);
+ if (ret < 0) {
+ g_cdc_ecm_tx_data_length = 0;
+ return ret;
+ }
+ return 0;
}
int usbd_cdc_ecm_start_read(uint8_t *buf, uint32_t len)
@@ -191,6 +214,10 @@ int usbd_cdc_ecm_start_read(uint8_t *buf, uint32_t len)
return -USB_ERR_NOTCONN;
}
+ if (!g_cdc_ecm_opened) {
+ return -USB_ERR_NOTCONN;
+ }
+
g_cdc_ecm_rx_data_length = 0;
return usbd_ep_start_read(0, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, buf, len);
}
diff --git a/class/cdc/usbd_cdc_ncm.c b/class/cdc/usbd_cdc_ncm.c
new file mode 100644
index 00000000..68a272ee
--- /dev/null
+++ b/class/cdc/usbd_cdc_ncm.c
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2026, 54fire
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <string.h>
+#include "usbd_core.h"
+#include "usbd_cdc_ncm.h"
+
+#define CDC_NCM_OUT_EP_IDX 0
+#define CDC_NCM_IN_EP_IDX 1
+#define CDC_NCM_INT_EP_IDX 2
+
+#define CONFIG_CDC_NCM_ETH_MAX_SEGSZE 1514U
+#define CONFIG_CDC_NCM_NTB_MAX_SIZE 2048U
+#define CDC_NCM_NTH16_LEN 12U
+#define CDC_NCM_NDP16_LEN 16U
+#define CDC_NCM_DATAGRAM_OFFSET 16U
+
+static struct usbd_endpoint cdc_ncm_ep_data[3];
+
+#ifdef CONFIG_USBDEV_CDC_NCM_USING_LWIP
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_rx_buffer[USB_ALIGN_UP(CONFIG_CDC_NCM_NTB_MAX_SIZE, CONFIG_USB_ALIGN_SIZE)];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_tx_buffer[USB_ALIGN_UP(CONFIG_CDC_NCM_NTB_MAX_SIZE, CONFIG_USB_ALIGN_SIZE)];
+#endif
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_ctrl_buf[USB_ALIGN_UP(32, CONFIG_USB_ALIGN_SIZE)];
+static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_notify_buf[USB_ALIGN_UP(16, CONFIG_USB_ALIGN_SIZE)];
+
+static volatile uint32_t g_cdc_ncm_rx_ntb_length = 0;
+static volatile uint32_t g_cdc_ncm_tx_ntb_length = 0;
+static volatile bool g_cdc_ncm_data_alt_active = false;
+static uint8_t *g_cdc_ncm_rx_data_buffer = NULL;
+static uint32_t g_cdc_ncm_rx_total_length = 0;
+static uint16_t g_cdc_ncm_rx_datagram_pos = 0;
+static uint16_t g_cdc_ncm_rx_ndp_index = 0;
+static uint16_t g_cdc_ncm_rx_sequence = 0;
+static uint16_t g_cdc_ncm_tx_sequence = 0;
+static uint16_t g_cdc_ncm_max_datagram_size = CONFIG_CDC_NCM_ETH_MAX_SEGSZE;
+static uint32_t g_cdc_ncm_ntb_in_max_size = CONFIG_CDC_NCM_NTB_MAX_SIZE;
+static uint32_t g_cdc_ncm_ntb_out_max_size = CONFIG_CDC_NCM_NTB_MAX_SIZE;
+static uint16_t g_cdc_ncm_ntb_format = 0;
+static uint16_t g_cdc_ncm_packet_filter = 0;
+static volatile uint8_t g_current_net_status = 0;
+static volatile uint8_t g_cmd_intf = 0;
+static uint8_t g_cdc_ncm_mac[6] = { 0 };
+static bool g_cdc_ncm_ep_registered = false;
+
+static uint32_t g_connect_speed_table[2] = { CDC_NCM_CONNECT_SPEED_UPSTREAM, CDC_NCM_CONNECT_SPEED_DOWNSTREAM };
+
+static void usbd_cdc_ncm_send_notify(uint8_t notifycode, uint8_t value, uint32_t *speed)
+{
+ struct cdc_eth_notification *notify = (struct cdc_eth_notification *)g_cdc_ncm_notify_buf;
+ uint8_t bytes2send = 0;
+
+ memset(g_cdc_ncm_notify_buf, 0, 16);
+ notify->bmRequestType = CDC_ECM_BMREQUEST_TYPE_ECM;
+ notify->bNotificationType = notifycode;
+ notify->wIndex = g_cmd_intf;
+
+ switch (notifycode) {
+ case CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION:
+ notify->wValue = value;
+ bytes2send = 8;
+ break;
+ case CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE:
+ bytes2send = 8;
+ break;
+ case CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE:
+ notify->wLength = 8;
+ if (speed) {
+ memcpy(notify->data, speed, 8);
+ }
+ bytes2send = 16;
+ break;
+ default:
+ break;
+ }
+
+ if (usb_device_is_configured(0) && bytes2send) {
+ usbd_ep_start_write(0, cdc_ncm_ep_data[CDC_NCM_INT_EP_IDX].ep_addr, g_cdc_ncm_notify_buf, bytes2send);
+ }
+}
+
+static void usbd_cdc_ncm_fill_ntb_parameters(void)
+{
+ memset(g_cdc_ncm_ctrl_buf, 0, 32);
+ SET_LE16(&g_cdc_ncm_ctrl_buf[0], 28); /* wLength */
+ SET_LE16(&g_cdc_ncm_ctrl_buf[2], 0x0001); /* NTB16 only */
+ SET_LE32(&g_cdc_ncm_ctrl_buf[4], g_cdc_ncm_ntb_in_max_size); /* device-to-host NTB */
+ SET_LE16(&g_cdc_ncm_ctrl_buf[8], 4); /* wNdbInDivisor */
+ SET_LE16(&g_cdc_ncm_ctrl_buf[10], 0); /* wNdbInPayloadRemainder */
+ SET_LE16(&g_cdc_ncm_ctrl_buf[12], 4); /* wNdbInAlignment */
+ SET_LE16(&g_cdc_ncm_ctrl_buf[14], 0); /* wReserved */
+ SET_LE32(&g_cdc_ncm_ctrl_buf[16], g_cdc_ncm_ntb_out_max_size);/* host-to-device NTB */
+ SET_LE16(&g_cdc_ncm_ctrl_buf[20], 4); /* wNdbOutDivisor */
+ SET_LE16(&g_cdc_ncm_ctrl_buf[22], 0); /* wNdbOutPayloadRemainder */
+ SET_LE16(&g_cdc_ncm_ctrl_buf[24], 4); /* wNdbOutAlignment */
+ SET_LE16(&g_cdc_ncm_ctrl_buf[26], 1); /* one datagram preferred */
+}
+
+static int cdc_ncm_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ (void)busid;
+
+ g_cmd_intf = LO_BYTE(setup->wIndex);
+
+ switch (setup->bRequest) {
+ case CDC_REQUEST_GET_NTB_PARAMETERS:
+ usbd_cdc_ncm_fill_ntb_parameters();
+ *data = g_cdc_ncm_ctrl_buf;
+ *len = 28;
+ break;
+ case CDC_REQUEST_GET_NTB_FORMAT:
+ SET_LE16(g_cdc_ncm_ctrl_buf, g_cdc_ncm_ntb_format);
+ *data = g_cdc_ncm_ctrl_buf;
+ *len = 2;
+ break;
+ case CDC_REQUEST_SET_NTB_FORMAT:
+ if (setup->wValue != 0) {
+ return -1;
+ }
+ g_cdc_ncm_ntb_format = 0;
+ break;
+ case CDC_REQUEST_GET_NTB_INPUT_SIZE:
+ SET_LE32(g_cdc_ncm_ctrl_buf, g_cdc_ncm_ntb_in_max_size);
+ *data = g_cdc_ncm_ctrl_buf;
+ *len = 4;
+ break;
+ case CDC_REQUEST_SET_NTB_INPUT_SIZE:
+ if (setup->wLength >= 4 && data && *data) {
+ uint32_t ntb_size = GET_LE32(*data);
+ if (ntb_size >= (CDC_NCM_DATAGRAM_OFFSET + CDC_NCM_NDP16_LEN) && ntb_size <= CONFIG_CDC_NCM_NTB_MAX_SIZE) {
+ g_cdc_ncm_ntb_in_max_size = ntb_size;
+ }
+ }
+ break;
+ case CDC_REQUEST_GET_MAX_DATAGRAM_SIZE:
+ SET_LE16(g_cdc_ncm_ctrl_buf, g_cdc_ncm_max_datagram_size);
+ *data = g_cdc_ncm_ctrl_buf;
+ *len = 2;
+ break;
+ case CDC_REQUEST_SET_MAX_DATAGRAM_SIZE:
+ if (setup->wLength >= 2 && data && *data) {
+ uint16_t max_datagram_size = GET_LE16(*data);
+ if (max_datagram_size >= 64 && max_datagram_size <= CONFIG_CDC_NCM_ETH_MAX_SEGSZE) {
+ g_cdc_ncm_max_datagram_size = max_datagram_size;
+ }
+ } else if (setup->wValue >= 64 && setup->wValue <= CONFIG_CDC_NCM_ETH_MAX_SEGSZE) {
+ g_cdc_ncm_max_datagram_size = setup->wValue;
+ }
+ break;
+ case CDC_REQUEST_GET_CRC_MODE:
+ SET_LE16(g_cdc_ncm_ctrl_buf, 0);
+ *data = g_cdc_ncm_ctrl_buf;
+ *len = 2;
+ break;
+ case CDC_REQUEST_SET_CRC_MODE:
+ if (setup->wValue != 0) {
+ return -1;
+ }
+ break;
+ case CDC_REQUEST_GET_NET_ADDRESS:
+ memcpy(g_cdc_ncm_ctrl_buf, g_cdc_ncm_mac, 6);
+ *data = g_cdc_ncm_ctrl_buf;
+ *len = 6;
+ break;
+ case CDC_REQUEST_SET_NET_ADDRESS:
+ if (setup->wLength >= 6 && data && *data) {
+ memcpy(g_cdc_ncm_mac, *data, 6);
+ }
+ break;
+ case CDC_REQUEST_SET_ETHERNET_PACKET_FILTER:
+ g_cdc_ncm_packet_filter = setup->wValue;
+ g_connect_speed_table[0] = 100000000;
+ g_connect_speed_table[1] = 100000000;
+ usbd_cdc_ncm_set_connect(g_cdc_ncm_packet_filter != 0, g_connect_speed_table);
+ break;
+ case CDC_REQUEST_SET_ETHERNET_MULTICAST_FILTERS:
+ case CDC_REQUEST_SET_ETHERNET_PMP_FILTER:
+ break;
+ default:
+ USB_LOG_WRN("Unhandled CDC NCM Class bRequest 0x%02x\r\n", setup->bRequest);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void cdc_ncm_notify_handler(uint8_t busid, uint8_t event, void *arg)
+{
+ (void)busid;
+
+ switch (event) {
+ case USBD_EVENT_RESET:
+ case USBD_EVENT_DISCONNECTED:
+ g_current_net_status = 0;
+ g_cdc_ncm_rx_ntb_length = 0;
+ g_cdc_ncm_tx_ntb_length = 0;
+ g_cdc_ncm_data_alt_active = false;
+ g_cdc_ncm_rx_datagram_pos = 0;
+ g_cdc_ncm_rx_ndp_index = 0;
+ break;
+ case USBD_EVENT_SET_INTERFACE: {
+#ifdef CONFIG_USBDEV_CDC_NCM_USING_LWIP
+ struct usb_interface_descriptor *desc = (struct usb_interface_descriptor *)arg;
+
+ if (desc && desc->bAlternateSetting == 1) {
+ g_cdc_ncm_data_alt_active = true;
+ usbd_cdc_ncm_start_read(g_cdc_ncm_rx_buffer, g_cdc_ncm_ntb_out_max_size);
+ } else {
+ g_cdc_ncm_data_alt_active = false;
+ g_cdc_ncm_tx_ntb_length = 0;
+ }
+#else
+ (void)arg;
+#endif
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void cdc_ncm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+ (void)busid;
+ (void)ep;
+
+ g_cdc_ncm_rx_ntb_length = nbytes;
+ g_cdc_ncm_rx_datagram_pos = 0;
+ g_cdc_ncm_rx_ndp_index = 0;
+ usbd_cdc_ncm_data_recv_done(g_cdc_ncm_rx_ntb_length);
+}
+
+static void cdc_ncm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+ (void)busid;
+
+ if ((nbytes % usbd_get_ep_mps(0, ep)) == 0 && nbytes) {
+ usbd_ep_start_write(0, ep, NULL, 0);
+ } else {
+ usbd_cdc_ncm_data_send_done(g_cdc_ncm_tx_ntb_length);
+ g_cdc_ncm_tx_ntb_length = 0;
+ }
+}
+
+static void cdc_ncm_int_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+ (void)busid;
+ (void)ep;
+ (void)nbytes;
+
+ if (g_current_net_status == 2) {
+ g_current_net_status = 3;
+ usbd_cdc_ncm_send_notify(CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE, 0, g_connect_speed_table);
+ } else {
+ g_current_net_status = 0;
+ }
+}
+
+int usbd_cdc_ncm_start_write(uint8_t *buf, uint32_t len)
+{
+ int ret;
+
+ if (!usb_device_is_configured(0) || !g_cdc_ncm_data_alt_active) {
+ return -USB_ERR_NOTCONN;
+ }
+
+ if (g_cdc_ncm_tx_ntb_length > 0) {
+ return -USB_ERR_BUSY;
+ }
+
+ /* mark busy before submitting: the transfer may complete in interrupt
+ context before usbd_ep_start_write() returns */
+ g_cdc_ncm_tx_ntb_length = len;
+ ret = usbd_ep_start_write(0, cdc_ncm_ep_data[CDC_NCM_IN_EP_IDX].ep_addr, buf, len);
+ if (ret != 0) {
+ g_cdc_ncm_tx_ntb_length = 0;
+ return ret;
+ }
+
+ USB_LOG_DBG("txlen:%d\r\n", g_cdc_ncm_tx_ntb_length);
+ return 0;
+}
+
+int usbd_cdc_ncm_start_read(uint8_t *buf, uint32_t len)
+{
+ if (!usb_device_is_configured(0)) {
+ return -USB_ERR_NOTCONN;
+ }
+
+ g_cdc_ncm_rx_data_buffer = buf;
+ g_cdc_ncm_rx_total_length = len;
+ g_cdc_ncm_rx_ntb_length = 0;
+ g_cdc_ncm_rx_datagram_pos = 0;
+ g_cdc_ncm_rx_ndp_index = 0;
+ return usbd_ep_start_read(0, cdc_ncm_ep_data[CDC_NCM_OUT_EP_IDX].ep_addr, buf, len);
+}
+
+#ifdef CONFIG_USBDEV_CDC_NCM_USING_LWIP
+static bool cdc_ncm_check_ndp16(uint16_t ndp_index)
+{
+ struct cdc_ncm_ndp16 *ndp16;
+ uint32_t signature;
+ uint16_t ndp_len;
+
+ if (ndp_index == 0 || (uint32_t)ndp_index + sizeof(struct cdc_ncm_ndp16) > g_cdc_ncm_rx_ntb_length) {
+ return false;
+ }
+
+ ndp16 = (struct cdc_ncm_ndp16 *)&g_cdc_ncm_rx_data_buffer[ndp_index];
+ signature = GET_LE32((uint8_t *)&ndp16->dwSignature);
+ ndp_len = GET_LE16((uint8_t *)&ndp16->wLength);
+
+ if ((signature != CDC_NCM_NDP16_SIGNATURE_NCM0) &&
+ (signature != CDC_NCM_NDP16_SIGNATURE_NCM1)) {
+ USB_LOG_WRN("invalid ncm ndp16 signature\r\n");
+ return false;
+ }
+
+ if (ndp_len < 12 || (uint32_t)ndp_index + ndp_len > g_cdc_ncm_rx_ntb_length) {
+ USB_LOG_WRN("invalid ncm ndp16 len\r\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool cdc_ncm_prepare_rx_ndp(void)
+{
+ struct cdc_ncm_nth16 *nth16;
+ uint16_t ndp_index;
+
+ if (g_cdc_ncm_rx_ntb_length < (CDC_NCM_NTH16_LEN + CDC_NCM_NDP16_LEN)) {
+ return false;
+ }
+
+ nth16 = (struct cdc_ncm_nth16 *)g_cdc_ncm_rx_data_buffer;
+ ndp_index = GET_LE16((uint8_t *)&nth16->wNdpIndex);
+ if (GET_LE32((uint8_t *)&nth16->dwSignature) != CDC_NCM_NTH16_SIGNATURE ||
+ GET_LE16((uint8_t *)&nth16->wHeaderLength) != CDC_NCM_NTH16_LEN ||
+ (uint32_t)GET_LE16((uint8_t *)&nth16->wBlockLength) > g_cdc_ncm_rx_ntb_length ||
+ !cdc_ncm_check_ndp16(ndp_index)) {
+ USB_LOG_WRN("invalid ncm nth16\r\n");
+ return false;
+ }
+
+ g_cdc_ncm_rx_ndp_index = ndp_index;
+ g_cdc_ncm_rx_sequence = GET_LE16((uint8_t *)&nth16->wSequence);
+ (void)g_cdc_ncm_rx_sequence;
+ return true;
+}
+
+struct pbuf *usbd_cdc_ncm_eth_rx(void)
+{
+ struct cdc_ncm_ndp16 *ndp16;
+ uint16_t ndp_len;
+ uint16_t next_ndp_index;
+
+ if (g_cdc_ncm_rx_ntb_length == 0 || g_cdc_ncm_rx_data_buffer == NULL) {
+ return NULL;
+ }
+
+ if (g_cdc_ncm_rx_ndp_index == 0 && !cdc_ncm_prepare_rx_ndp()) {
+ usbd_cdc_ncm_start_read(g_cdc_ncm_rx_buffer, g_cdc_ncm_ntb_out_max_size);
+ return NULL;
+ }
+
+ for (;;) {
+ ndp16 = (struct cdc_ncm_ndp16 *)&g_cdc_ncm_rx_data_buffer[g_cdc_ncm_rx_ndp_index];
+ ndp_len = GET_LE16((uint8_t *)&ndp16->wLength);
+
+ while ((8 + 4 * (g_cdc_ncm_rx_datagram_pos + 1)) <= ndp_len) {
+ struct cdc_ncm_ndp16_datagram *datagram;
+ uint16_t index;
+ uint16_t length;
+ struct pbuf *p;
+
+ datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_rx_data_buffer[g_cdc_ncm_rx_ndp_index + 8 + 4 * g_cdc_ncm_rx_datagram_pos];
+ g_cdc_ncm_rx_datagram_pos++;
+ index = GET_LE16((uint8_t *)&datagram->wDatagramIndex);
+ length = GET_LE16((uint8_t *)&datagram->wDatagramLength);
+
+ if (index == 0 || length == 0) {
+ break;
+ }
+ if ((uint32_t)index + length > g_cdc_ncm_rx_ntb_length || length > g_cdc_ncm_max_datagram_size) {
+ USB_LOG_WRN("invalid ncm datagram index:%u len:%u\r\n", index, length);
+ continue;
+ }
+
+ p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL);
+ if (p == NULL) {
+ USB_LOG_WRN("ncm pbuf alloc failed\r\n");
+ usbd_cdc_ncm_start_read(g_cdc_ncm_rx_buffer, g_cdc_ncm_ntb_out_max_size);
+ return NULL;
+ }
+ if (pbuf_take(p, &g_cdc_ncm_rx_data_buffer[index], length) != ERR_OK) {
+ pbuf_free(p);
+ continue;
+ }
+
+ USB_LOG_DBG("rxlen:%d\r\n", length);
+ return p;
+ }
+
+ /* current ndp is exhausted, follow the ndp chain if present */
+ next_ndp_index = GET_LE16((uint8_t *)&ndp16->wNextNdpIndex);
+ if (next_ndp_index == 0 || !cdc_ncm_check_ndp16(next_ndp_index)) {
+ break;
+ }
+ g_cdc_ncm_rx_ndp_index = next_ndp_index;
+ g_cdc_ncm_rx_datagram_pos = 0;
+ }
+
+ usbd_cdc_ncm_start_read(g_cdc_ncm_rx_buffer, g_cdc_ncm_ntb_out_max_size);
+ return NULL;
+}
+
+int usbd_cdc_ncm_eth_tx(struct pbuf *p)
+{
+ struct cdc_ncm_nth16 *nth16;
+ struct cdc_ncm_ndp16 *ndp16;
+ struct cdc_ncm_ndp16_datagram *datagram;
+ struct pbuf *q;
+ uint8_t *buffer;
+ uint16_t payload_len;
+ uint16_t aligned_payload_len;
+ uint16_t ndp_index;
+ uint16_t block_len;
+
+ if (!usb_device_is_configured(0)) {
+ return -USB_ERR_NOTCONN;
+ }
+
+ if (g_cdc_ncm_tx_ntb_length > 0) {
+ return -USB_ERR_BUSY;
+ }
+
+ if (p->tot_len > g_cdc_ncm_max_datagram_size) {
+ USB_LOG_WRN("ncm tx frame too large:%u\r\n", p->tot_len);
+ return -USB_ERR_INVAL;
+ }
+
+ payload_len = p->tot_len;
+ aligned_payload_len = USB_ALIGN_UP(payload_len, 4);
+ ndp_index = CDC_NCM_DATAGRAM_OFFSET + aligned_payload_len;
+ block_len = ndp_index + CDC_NCM_NDP16_LEN;
+ if (block_len > sizeof(g_cdc_ncm_tx_buffer) || block_len > g_cdc_ncm_ntb_in_max_size) {
+ return -USB_ERR_INVAL;
+ }
+
+ memset(g_cdc_ncm_tx_buffer, 0, block_len);
+ buffer = &g_cdc_ncm_tx_buffer[CDC_NCM_DATAGRAM_OFFSET];
+ for (q = p; q != NULL && payload_len > 0; q = q->next) {
+ uint16_t copy_len = MIN(q->len, payload_len);
+ usb_memcpy(buffer, q->payload, copy_len);
+ buffer += copy_len;
+ payload_len -= copy_len;
+ }
+ payload_len = p->tot_len;
+
+ nth16 = (struct cdc_ncm_nth16 *)&g_cdc_ncm_tx_buffer[0];
+ SET_LE32((uint8_t *)&nth16->dwSignature, CDC_NCM_NTH16_SIGNATURE);
+ SET_LE16((uint8_t *)&nth16->wHeaderLength, CDC_NCM_NTH16_LEN);
+ SET_LE16((uint8_t *)&nth16->wSequence, g_cdc_ncm_tx_sequence++);
+ SET_LE16((uint8_t *)&nth16->wBlockLength, block_len);
+ SET_LE16((uint8_t *)&nth16->wNdpIndex, ndp_index);
+
+ ndp16 = (struct cdc_ncm_ndp16 *)&g_cdc_ncm_tx_buffer[ndp_index];
+ SET_LE32((uint8_t *)&ndp16->dwSignature, CDC_NCM_NDP16_SIGNATURE_NCM0);
+ SET_LE16((uint8_t *)&ndp16->wLength, CDC_NCM_NDP16_LEN);
+ SET_LE16((uint8_t *)&ndp16->wNextNdpIndex, 0);
+
+ datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_tx_buffer[ndp_index + 8];
+ SET_LE16((uint8_t *)&datagram[0].wDatagramIndex, CDC_NCM_DATAGRAM_OFFSET);
+ SET_LE16((uint8_t *)&datagram[0].wDatagramLength, payload_len);
+ datagram[1].wDatagramIndex = 0;
+ datagram[1].wDatagramLength = 0;
+
+ return usbd_cdc_ncm_start_write(g_cdc_ncm_tx_buffer, block_len);
+}
+#endif
+
+struct usbd_interface *usbd_cdc_ncm_init_intf(struct usbd_interface *intf,
+ const uint8_t int_ep,
+ const uint8_t out_ep,
+ const uint8_t in_ep,
+ uint8_t mac[6])
+{
+ memcpy(g_cdc_ncm_mac, mac, 6);
+
+ intf->class_interface_handler = cdc_ncm_class_interface_request_handler;
+ intf->class_endpoint_handler = NULL;
+ intf->vendor_handler = NULL;
+ intf->notify_handler = cdc_ncm_notify_handler;
+
+ /* control and data interfaces share the same endpoints, register them only once */
+ if (!g_cdc_ncm_ep_registered) {
+ g_cdc_ncm_ep_registered = true;
+
+ cdc_ncm_ep_data[CDC_NCM_OUT_EP_IDX].ep_addr = out_ep;
+ cdc_ncm_ep_data[CDC_NCM_OUT_EP_IDX].ep_cb = cdc_ncm_bulk_out;
+ cdc_ncm_ep_data[CDC_NCM_IN_EP_IDX].ep_addr = in_ep;
+ cdc_ncm_ep_data[CDC_NCM_IN_EP_IDX].ep_cb = cdc_ncm_bulk_in;
+ cdc_ncm_ep_data[CDC_NCM_INT_EP_IDX].ep_addr = int_ep;
+ cdc_ncm_ep_data[CDC_NCM_INT_EP_IDX].ep_cb = cdc_ncm_int_in;
+
+ usbd_add_endpoint(0, &cdc_ncm_ep_data[CDC_NCM_OUT_EP_IDX]);
+ usbd_add_endpoint(0, &cdc_ncm_ep_data[CDC_NCM_IN_EP_IDX]);
+ usbd_add_endpoint(0, &cdc_ncm_ep_data[CDC_NCM_INT_EP_IDX]);
+ }
+
+ return intf;
+}
+
+int usbd_cdc_ncm_set_connect(bool connect, uint32_t speed[2])
+{
+ if (!usb_device_is_configured(0)) {
+ return -USB_ERR_NOTCONN;
+ }
+
+ if (connect) {
+ g_current_net_status = 2;
+ if (speed) {
+ memcpy(g_connect_speed_table, speed, 8);
+ }
+ usbd_cdc_ncm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, NULL);
+ } else {
+ g_current_net_status = 1;
+ usbd_cdc_ncm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_DISCONNECTED, NULL);
+ }
+
+ return 0;
+}
+
+__WEAK void usbd_cdc_ncm_data_recv_done(uint32_t len)
+{
+ (void)len;
+}
+
+__WEAK void usbd_cdc_ncm_data_send_done(uint32_t len)
+{
+ (void)len;
+}
diff --git a/class/cdc/usbd_cdc_ncm.h b/class/cdc/usbd_cdc_ncm.h
new file mode 100644
index 00000000..7a232c32
--- /dev/null
+++ b/class/cdc/usbd_cdc_ncm.h
@@ -0,0 +1,41 @@
+/*
+ * CherryUSB CDC NCM device class glue
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_CDC_NCM_H
+#define USBD_CDC_NCM_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "usb_cdc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct usbd_interface *usbd_cdc_ncm_init_intf(struct usbd_interface *intf,
+ const uint8_t int_ep,
+ const uint8_t out_ep,
+ const uint8_t in_ep,
+ uint8_t mac[6]);
+
+int usbd_cdc_ncm_set_connect(bool connect, uint32_t speed[2]);
+
+void usbd_cdc_ncm_data_recv_done(uint32_t len);
+void usbd_cdc_ncm_data_send_done(uint32_t len);
+int usbd_cdc_ncm_start_write(uint8_t *buf, uint32_t len);
+int usbd_cdc_ncm_start_read(uint8_t *buf, uint32_t len);
+
+#ifdef CONFIG_USBDEV_CDC_NCM_USING_LWIP
+#include "lwip/netif.h"
+#include "lwip/pbuf.h"
+struct pbuf *usbd_cdc_ncm_eth_rx(void);
+int usbd_cdc_ncm_eth_tx(struct pbuf *p);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBD_CDC_NCM_H */
diff --git a/class/cdc/usbh_cdc_ecm.c b/class/cdc/usbh_cdc_ecm.c
index 6fef9b20..35b92e2a 100644
--- a/class/cdc/usbh_cdc_ecm.c
+++ b/class/cdc/usbh_cdc_ecm.c
@@ -245,9 +245,7 @@ void usbh_cdc_ecm_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
(void)CONFIG_USB_OSAL_THREAD_GET_ARGV;
USB_LOG_INFO("Create cdc ecm rx thread\r\n");
- // clang-format off
-find_class:
- // clang-format on
+
g_cdc_ecm_class.connect_status = false;
if (usbh_find_class_instance("/dev/cdc_ether") == NULL) {
goto delete;
@@ -256,8 +254,7 @@ find_class:
while (g_cdc_ecm_class.connect_status == false) {
ret = usbh_cdc_ecm_get_connect_status(&g_cdc_ecm_class);
if (ret < 0) {
- usb_osal_msleep(100);
- goto find_class;
+ goto delete;
}
usb_osal_msleep(128);
}
@@ -267,25 +264,22 @@ find_class:
usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkin_urb, g_cdc_ecm_class.hport, g_cdc_ecm_class.bulkin, g_cdc_ecm_rx_buffer, CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_cdc_ecm_class.bulkin_urb);
if (ret < 0) {
- goto find_class;
+ goto delete;
}
g_cdc_ecm_rx_length = g_cdc_ecm_class.bulkin_urb.actual_length;
+ if (g_cdc_ecm_rx_length == 0) {
+ continue;
+ }
- /* A transfer is complete because last packet is a short packet.
- * Short packet is not zero, match g_cdc_ecm_rx_length % USB_GET_MAXPACKETSIZE(g_cdc_ecm_class.bulkin->wMaxPacketSize).
- * Short packet is zero, check if g_cdc_ecm_class.bulkin_urb.actual_length < transfer_size, for example transfer is complete with size is 512 < 1514.
- * This case is always true
- */
- if (g_cdc_ecm_rx_length % USB_GET_MAXPACKETSIZE(g_cdc_ecm_class.bulkin->wMaxPacketSize) ||
- (g_cdc_ecm_class.bulkin_urb.actual_length < CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE)) {
+ if (g_cdc_ecm_rx_length < CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE) {
USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_length);
usbh_cdc_ecm_eth_input(g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_length);
g_cdc_ecm_rx_length = 0;
} else {
- /* There's no way to run here. */
+ USB_LOG_ERR("cdc ecm rx packet overflow\r\n");
}
}
// clang-format off
diff --git a/class/cdc/usbh_cdc_ncm.c b/class/cdc/usbh_cdc_ncm.c
index 225a7fcd..83310e09 100644
--- a/class/cdc/usbh_cdc_ncm.c
+++ b/class/cdc/usbh_cdc_ncm.c
@@ -23,6 +23,10 @@
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_SEGSZE 1514U
+#if CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE > (16 * 1024)
+#error "CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE must be less than 16K"
+#endif
+
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_rx_buffer[CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_tx_buffer[CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ncm_inttx_buffer[USB_ALIGN_UP(16, CONFIG_USB_ALIGN_SIZE)];
@@ -48,11 +52,11 @@ static int usbh_cdc_ncm_get_ntb_parameters(struct usbh_cdc_ncm *cdc_ncm_class, s
setup->wLength = 28;
ret = usbh_control_transfer(cdc_ncm_class->hport, setup, g_cdc_ncm_buf);
- if (ret < 8) {
+ if (ret < sizeof(struct cdc_ncm_ntb_parameters)) {
return ret;
}
- memcpy((uint8_t *)param, g_cdc_ncm_buf, MIN(ret - 8, sizeof(struct cdc_ncm_ntb_parameters)));
+ memcpy((uint8_t *)param, g_cdc_ncm_buf, sizeof(struct cdc_ncm_ntb_parameters));
return 0;
}
@@ -260,17 +264,10 @@ void usbh_cdc_ncm_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
{
uint32_t g_cdc_ncm_rx_length;
int ret;
-#if CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE <= (16 * 1024)
- uint32_t transfer_size = CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE;
-#else
- uint32_t transfer_size = (16 * 1024);
-#endif
(void)CONFIG_USB_OSAL_THREAD_GET_ARGV;
USB_LOG_INFO("Create cdc ncm rx thread\r\n");
- // clang-format off
-find_class:
- // clang-format on
+
g_cdc_ncm_class.connect_status = false;
if (usbh_find_class_instance("/dev/cdc_ncm") == NULL) {
goto delete;
@@ -279,27 +276,24 @@ find_class:
while (g_cdc_ncm_class.connect_status == false) {
ret = usbh_cdc_ncm_get_connect_status(&g_cdc_ncm_class);
if (ret < 0) {
- usb_osal_msleep(100);
- goto find_class;
+ goto delete;
}
}
g_cdc_ncm_rx_length = 0;
while (1) {
- usbh_bulk_urb_fill(&g_cdc_ncm_class.bulkin_urb, g_cdc_ncm_class.hport, g_cdc_ncm_class.bulkin, &g_cdc_ncm_rx_buffer[g_cdc_ncm_rx_length], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+ usbh_bulk_urb_fill(&g_cdc_ncm_class.bulkin_urb, g_cdc_ncm_class.hport, g_cdc_ncm_class.bulkin, g_cdc_ncm_rx_buffer, CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_cdc_ncm_class.bulkin_urb);
if (ret < 0) {
- goto find_class;
+ goto delete;
}
- g_cdc_ncm_rx_length += g_cdc_ncm_class.bulkin_urb.actual_length;
+ g_cdc_ncm_rx_length = g_cdc_ncm_class.bulkin_urb.actual_length;
+ if(g_cdc_ncm_rx_length == 0) {
+ continue;
+ }
- /* A transfer is complete because last packet is a short packet.
- * Short packet is not zero, match g_cdc_ncm_rx_length % USB_GET_MAXPACKETSIZE(g_cdc_ncm_class.bulkin->wMaxPacketSize).
- * Short packet is zero, check if g_cdc_ncm_class.bulkin_urb.actual_length < transfer_size, for example transfer is complete with size is 1024 < 2048.
- */
- if ((g_cdc_ncm_rx_length % USB_GET_MAXPACKETSIZE(g_cdc_ncm_class.bulkin->wMaxPacketSize)) ||
- (g_cdc_ncm_class.bulkin_urb.actual_length < transfer_size)) {
+ if (g_cdc_ncm_rx_length < CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE) {
USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ncm_rx_length);
struct cdc_ncm_nth16 *nth16 = (struct cdc_ncm_nth16 *)&g_cdc_ncm_rx_buffer[0];
@@ -333,15 +327,7 @@ find_class:
g_cdc_ncm_rx_length = 0;
} else {
-#if CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE <= (16 * 1024)
- if (g_cdc_ncm_rx_length == CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE) {
-#else
- if ((g_cdc_ncm_rx_length + (16 * 1024)) > CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE) {
-#endif
- USB_LOG_ERR("Rx packet is overflow, please reduce tcp window size or increase CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE\r\n");
- while (1) {
- }
- }
+ USB_LOG_ERR("cdc ncm rx packet overflow\r\n");
}
}
// clang-format off
diff --git a/class/gs_usb/gs_usb.h b/class/gs_usb/gs_usb.h
new file mode 100644
index 00000000..7869831e
--- /dev/null
+++ b/class/gs_usb/gs_usb.h
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2016 Hubert Denkmair
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef GS_USB_H
+#define GS_USB_H
+
+/*
+ * gs_usb wire protocol definitions.
+ *
+ * Names and layout follow Linux drivers/net/can/usb/gs_usb.c
+ */
+
+enum gs_usb_breq {
+ GS_USB_BREQ_HOST_FORMAT = 0,
+ GS_USB_BREQ_BITTIMING,
+ GS_USB_BREQ_MODE,
+ GS_USB_BREQ_BERR,
+ GS_USB_BREQ_BT_CONST,
+ GS_USB_BREQ_DEVICE_CONFIG,
+ GS_USB_BREQ_TIMESTAMP,
+ GS_USB_BREQ_IDENTIFY,
+ GS_USB_BREQ_GET_USER_ID,
+ GS_USB_BREQ_QUIRK_CANTACT_PRO_DATA_BITTIMING = GS_USB_BREQ_GET_USER_ID,
+ GS_USB_BREQ_SET_USER_ID,
+ GS_USB_BREQ_DATA_BITTIMING,
+ GS_USB_BREQ_BT_CONST_EXT,
+ GS_USB_BREQ_SET_TERMINATION,
+ GS_USB_BREQ_GET_TERMINATION,
+ GS_USB_BREQ_GET_STATE,
+};
+
+enum gs_can_mode {
+ /* reset a channel. turns it off */
+ GS_CAN_MODE_RESET = 0,
+ /* starts a channel */
+ GS_CAN_MODE_START
+};
+
+enum gs_can_state {
+ GS_CAN_STATE_ERROR_ACTIVE = 0,
+ GS_CAN_STATE_ERROR_WARNING,
+ GS_CAN_STATE_ERROR_PASSIVE,
+ GS_CAN_STATE_BUS_OFF,
+ GS_CAN_STATE_STOPPED,
+ GS_CAN_STATE_SLEEPING
+};
+
+enum gs_can_identify_mode {
+ GS_CAN_IDENTIFY_OFF = 0,
+ GS_CAN_IDENTIFY_ON
+};
+
+enum gs_can_termination_state {
+ GS_CAN_TERMINATION_STATE_OFF = 0,
+ GS_CAN_TERMINATION_STATE_ON
+};
+
+#define GS_CAN_MODE_NORMAL 0
+#define GS_CAN_MODE_LISTEN_ONLY (1U << 0)
+#define GS_CAN_MODE_LOOP_BACK (1U << 1)
+#define GS_CAN_MODE_TRIPLE_SAMPLE (1U << 2)
+#define GS_CAN_MODE_ONE_SHOT (1U << 3)
+#define GS_CAN_MODE_HW_TIMESTAMP (1U << 4)
+/* GS_CAN_FEATURE_IDENTIFY BIT(5) */
+/* GS_CAN_FEATURE_USER_ID BIT(6) */
+#define GS_CAN_MODE_PAD_PKTS_TO_MAX_PKT_SIZE (1U << 7)
+#define GS_CAN_MODE_FD (1U << 8)
+/* GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9) */
+/* GS_CAN_FEATURE_BT_CONST_EXT BIT(10) */
+/* GS_CAN_FEATURE_TERMINATION BIT(11) */
+#define GS_CAN_MODE_BERR_REPORTING (1U << 12)
+/* GS_CAN_FEATURE_GET_STATE BIT(13) */
+
+#define GS_CAN_FEATURE_LISTEN_ONLY (1U << 0)
+#define GS_CAN_FEATURE_LOOP_BACK (1U << 1)
+#define GS_CAN_FEATURE_TRIPLE_SAMPLE (1U << 2)
+#define GS_CAN_FEATURE_ONE_SHOT (1U << 3)
+#define GS_CAN_FEATURE_HW_TIMESTAMP (1U << 4)
+#define GS_CAN_FEATURE_IDENTIFY (1U << 5)
+#define GS_CAN_FEATURE_USER_ID (1U << 6)
+#define GS_CAN_FEATURE_PAD_PKTS_TO_MAX_PKT_SIZE (1U << 7)
+#define GS_CAN_FEATURE_FD (1U << 8)
+#define GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX (1U << 9)
+#define GS_CAN_FEATURE_BT_CONST_EXT (1U << 10)
+#define GS_CAN_FEATURE_TERMINATION (1U << 11)
+#define GS_CAN_FEATURE_BERR_REPORTING (1U << 12)
+#define GS_CAN_FEATURE_GET_STATE (1U << 13)
+#define GS_CAN_FEATURE_MASK ((1U << 14) - 1)
+
+/* internal quirks - keep in GS_CAN_FEATURE space for now */
+
+/* CANtact Pro original firmware:
+ * BREQ DATA_BITTIMING overlaps with GET_USER_ID
+ */
+#define GS_CAN_FEATURE_QUIRK_BREQ_CANTACT_PRO (1U << 31)
+
+#define GS_CAN_FLAG_OVERFLOW (1U << 0)
+#define GS_CAN_FLAG_FD (1U << 1)
+#define GS_CAN_FLAG_BRS (1U << 2)
+#define GS_CAN_FLAG_ESI (1U << 3)
+
+#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
+#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
+#define CAN_ERR_FLAG 0x20000000U /* error message frame */
+
+#define CAN_ERR_DLC 8 /* dlc for error message frames */
+
+/* error class (mask) in can_id */
+#define CAN_ERR_TX_TIMEOUT 0x00000001U /* TX timeout (by netdevice driver) */
+#define CAN_ERR_LOSTARB 0x00000002U /* lost arbitration / data[0] */
+#define CAN_ERR_CRTL 0x00000004U /* controller problems / data[1] */
+#define CAN_ERR_PROT 0x00000008U /* protocol violations / data[2..3] */
+#define CAN_ERR_TRX 0x00000010U /* transceiver status / data[4] */
+#define CAN_ERR_ACK 0x00000020U /* received no ACK on transmission */
+#define CAN_ERR_BUSOFF 0x00000040U /* bus off */
+#define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */
+#define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */
+#define CAN_ERR_CNT 0x00000200U /* TX error counter / data[6] */
+ /* RX error counter / data[7] */
+
+/* arbitration lost in bit ... / data[0] */
+#define CAN_ERR_LOSTARB_UNSPEC 0x00 /* unspecified */
+/* else bit number in bitstream */
+
+/* error status of CAN-controller / data[1] */
+#define CAN_ERR_CRTL_UNSPEC 0x00 /* unspecified */
+#define CAN_ERR_CRTL_RX_OVERFLOW 0x01 /* RX buffer overflow */
+#define CAN_ERR_CRTL_TX_OVERFLOW 0x02 /* TX buffer overflow */
+#define CAN_ERR_CRTL_RX_WARNING 0x04 /* reached warning level for RX errors */
+#define CAN_ERR_CRTL_TX_WARNING 0x08 /* reached warning level for TX errors */
+#define CAN_ERR_CRTL_RX_PASSIVE 0x10 /* reached error passive status RX */
+#define CAN_ERR_CRTL_TX_PASSIVE 0x20 /* reached error passive status TX */
+/* (at least one error counter exceeds */
+/* the protocol-defined level of 127) */
+#define CAN_ERR_CRTL_ACTIVE 0x40 /* recovered to error active state */
+
+/* error in CAN protocol (type) / data[2] */
+#define CAN_ERR_PROT_UNSPEC 0x00 /* unspecified */
+#define CAN_ERR_PROT_BIT 0x01 /* single bit error */
+#define CAN_ERR_PROT_FORM 0x02 /* frame format error */
+#define CAN_ERR_PROT_STUFF 0x04 /* bit stuffing error */
+#define CAN_ERR_PROT_BIT0 0x08 /* unable to send dominant bit */
+#define CAN_ERR_PROT_BIT1 0x10 /* unable to send recessive bit */
+#define CAN_ERR_PROT_OVERLOAD 0x20 /* bus overload */
+#define CAN_ERR_PROT_ACTIVE 0x40 /* active error announcement */
+#define CAN_ERR_PROT_TX 0x80 /* error occurred on transmission */
+
+/* error in CAN protocol (location) / data[3] */
+#define CAN_ERR_PROT_LOC_UNSPEC 0x00 /* unspecified */
+#define CAN_ERR_PROT_LOC_SOF 0x03 /* start of frame */
+#define CAN_ERR_PROT_LOC_ID28_21 0x02 /* ID bits 28 - 21 (SFF: 10 - 3) */
+#define CAN_ERR_PROT_LOC_ID20_18 0x06 /* ID bits 20 - 18 (SFF: 2 - 0 )*/
+#define CAN_ERR_PROT_LOC_SRTR 0x04 /* substitute RTR (SFF: RTR) */
+#define CAN_ERR_PROT_LOC_IDE 0x05 /* identifier extension */
+#define CAN_ERR_PROT_LOC_ID17_13 0x07 /* ID bits 17-13 */
+#define CAN_ERR_PROT_LOC_ID12_05 0x0F /* ID bits 12-5 */
+#define CAN_ERR_PROT_LOC_ID04_00 0x0E /* ID bits 4-0 */
+#define CAN_ERR_PROT_LOC_RTR 0x0C /* RTR */
+#define CAN_ERR_PROT_LOC_RES1 0x0D /* reserved bit 1 */
+#define CAN_ERR_PROT_LOC_RES0 0x09 /* reserved bit 0 */
+#define CAN_ERR_PROT_LOC_DLC 0x0B /* data length code */
+#define CAN_ERR_PROT_LOC_DATA 0x0A /* data section */
+#define CAN_ERR_PROT_LOC_CRC_SEQ 0x08 /* CRC sequence */
+#define CAN_ERR_PROT_LOC_CRC_DEL 0x18 /* CRC delimiter */
+#define CAN_ERR_PROT_LOC_ACK 0x19 /* ACK slot */
+#define CAN_ERR_PROT_LOC_ACK_DEL 0x1B /* ACK delimiter */
+#define CAN_ERR_PROT_LOC_EOF 0x1A /* end of frame */
+#define CAN_ERR_PROT_LOC_INTERM 0x12 /* intermission */
+
+/* error status of CAN-transceiver / data[4] */
+/* CANH CANL */
+#define CAN_ERR_TRX_UNSPEC 0x00 /* 0000 0000 */
+#define CAN_ERR_TRX_CANH_NO_WIRE 0x04 /* 0000 0100 */
+#define CAN_ERR_TRX_CANH_SHORT_TO_BAT 0x05 /* 0000 0101 */
+#define CAN_ERR_TRX_CANH_SHORT_TO_VCC 0x06 /* 0000 0110 */
+#define CAN_ERR_TRX_CANH_SHORT_TO_GND 0x07 /* 0000 0111 */
+#define CAN_ERR_TRX_CANL_NO_WIRE 0x40 /* 0100 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_BAT 0x50 /* 0101 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_VCC 0x60 /* 0110 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_GND 0x70 /* 0111 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_CANH 0x80 /* 1000 0000 */
+
+struct gs_host_config {
+ uint32_t byte_order;
+} __PACKED;
+
+struct gs_device_config {
+ uint8_t reserved1;
+ uint8_t reserved2;
+ uint8_t reserved3;
+ uint8_t icount;
+ uint32_t sw_version;
+ uint32_t hw_version;
+} __PACKED;
+
+struct gs_device_mode {
+ uint32_t mode;
+ uint32_t flags;
+} __PACKED;
+
+struct gs_device_state {
+ uint32_t state;
+ uint32_t rxerr;
+ uint32_t txerr;
+} __PACKED;
+
+struct gs_device_bittiming {
+ uint32_t prop_seg;
+ uint32_t phase_seg1;
+ uint32_t phase_seg2;
+ uint32_t sjw;
+ uint32_t brp;
+} __PACKED;
+
+struct gs_identify_mode {
+ uint32_t mode;
+} __PACKED;
+
+struct gs_device_termination_state {
+ uint32_t state;
+} __PACKED;
+
+/* Hardware bit-timing ranges. Linux stores these fields inline in gs_device_bt_const. */
+struct can_bt_const {
+ uint32_t tseg1_min; /* Minimum of (prop_seg + phase_seg1) */
+ uint32_t tseg1_max;
+ uint32_t tseg2_min;
+ uint32_t tseg2_max;
+ uint32_t sjw_max;
+ uint32_t brp_min;
+ uint32_t brp_max;
+ uint32_t brp_inc; /* Prescaler step (1 or 2 depending on hardware) */
+} __PACKED;
+
+struct gs_device_bt_const {
+ uint32_t feature; /* GS_CAN_FEATURE_* bit mask */
+ uint32_t fclk_can; /* CAN clock in Hz, used with brp to form bit time */
+ struct can_bt_const bt_const; /* Classic / arbitration timing limits */
+} __PACKED;
+
+/* Layout must begin with the same three members as gs_device_bt_const (feature,
+ * fclk_can, bt_const), in the same order/size, so GET_BT_CONST can reuse the
+ * leading bytes of this extended struct.
+ */
+struct gs_device_bt_const_extended {
+ uint32_t feature;
+ uint32_t fclk_can;
+ struct can_bt_const bt_const; /* Classic / arbitration timing limits */
+ struct can_bt_const dbt_const; /* CAN FD data-phase timing limits */
+} __PACKED;
+
+struct classic_can {
+ uint8_t data[8];
+} __PACKED;
+
+struct classic_can_ts {
+ uint8_t data[8];
+ uint32_t timestamp_us;
+} __PACKED;
+
+struct classic_can_quirk {
+ uint8_t data[8];
+ uint8_t quirk;
+} __PACKED;
+
+struct canfd {
+ uint8_t data[64];
+} __PACKED;
+
+struct canfd_ts {
+ uint8_t data[64];
+ uint32_t timestamp_us;
+} __PACKED;
+
+struct canfd_quirk {
+ uint8_t data[64];
+ uint8_t quirk;
+} __PACKED;
+
+/* struct gs_host_frame::echo_id == GS_HOST_FRAME_ECHO_ID_RX indicates
+ * a regular RX'ed CAN frame
+ */
+#define GS_HOST_FRAME_ECHO_ID_RX 0xffffffff
+
+#define DECLARE_FLEX_ARRAY(_t, _n) \
+ struct { \
+ struct { \
+ } __dummy_##_n; \
+ _t _n[0]; \
+ }
+
+struct gs_host_frame {
+ uint32_t echo_id;
+ uint32_t can_id;
+
+ uint8_t can_dlc;
+ uint8_t channel;
+ uint8_t flags;
+ uint8_t reserved;
+
+ union {
+ DECLARE_FLEX_ARRAY(struct classic_can, classic_can);
+ DECLARE_FLEX_ARRAY(struct classic_can_ts, classic_can_ts);
+ DECLARE_FLEX_ARRAY(struct classic_can_quirk, classic_can_quirk);
+ DECLARE_FLEX_ARRAY(struct canfd, canfd);
+ DECLARE_FLEX_ARRAY(struct canfd_ts, canfd_ts);
+ DECLARE_FLEX_ARRAY(struct canfd_quirk, canfd_quirk);
+ };
+} __PACKED;
+
+#define struct_size(ptr, field, num) \
+ (offsetof(__typeof(*(ptr)), field) + sizeof((ptr)->field[0]) * (num))
+
+#define GS_HOST_CANFD_FRAME_SIZE struct_size((struct gs_host_frame *)NULL, canfd_ts, 1)
+#define GS_HOST_CAN_FRAME_SIZE struct_size((struct gs_host_frame *)NULL, classic_can, 1)
+
+#endif // GS_USB_H \ No newline at end of file
diff --git a/class/gs_usb/usbd_gs_usb.c b/class/gs_usb/usbd_gs_usb.c
new file mode 100644
index 00000000..77d970d2
--- /dev/null
+++ b/class/gs_usb/usbd_gs_usb.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2026, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_gs_usb.h"
+
+static int gs_usb_vendor_class_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ USB_LOG_DBG("GS USB Class request: "
+ "bRequest 0x%02x\r\n",
+ setup->bRequest);
+
+ uint16_t can_channel = setup->wValue;
+
+ switch (setup->bRequest) {
+ case GS_USB_BREQ_BT_CONST:
+ *len = sizeof(struct gs_device_bt_const);
+ return usbd_gs_usb_can_get(can_channel, setup->bRequest, *data, *len);
+ case GS_USB_BREQ_DEVICE_CONFIG:
+ *len = sizeof(struct gs_device_config);
+ return usbd_gs_usb_can_get(can_channel, setup->bRequest, *data, *len);
+ case GS_USB_BREQ_TIMESTAMP:
+ *len = sizeof(uint32_t);
+ return usbd_gs_usb_can_get(can_channel, setup->bRequest, *data, *len);
+ case GS_USB_BREQ_BT_CONST_EXT:
+ *len = sizeof(struct gs_device_bt_const_extended);
+ return usbd_gs_usb_can_get(can_channel, setup->bRequest, *data, *len);
+ case GS_USB_BREQ_GET_TERMINATION:
+ *len = sizeof(struct gs_device_termination_state);
+ return usbd_gs_usb_can_get(can_channel, setup->bRequest, *data, *len);
+ case GS_USB_BREQ_GET_STATE:
+ *len = sizeof(struct gs_device_state);
+ return usbd_gs_usb_can_get(can_channel, setup->bRequest, *data, *len);
+ case GS_USB_BREQ_HOST_FORMAT:
+ case GS_USB_BREQ_BITTIMING:
+ case GS_USB_BREQ_MODE:
+ case GS_USB_BREQ_IDENTIFY:
+ case GS_USB_BREQ_DATA_BITTIMING:
+ case GS_USB_BREQ_SET_TERMINATION:
+ return usbd_gs_usb_can_set(can_channel, setup->bRequest, *data, *len);
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+struct usbd_interface *usbd_gs_usb_init_intf(struct usbd_interface *intf)
+{
+ intf->class_interface_handler = NULL;
+ intf->class_endpoint_handler = NULL;
+ intf->vendor_handler = gs_usb_vendor_class_request_handler;
+ intf->notify_handler = NULL;
+
+ return intf;
+}
+
+__WEAK int usbd_gs_usb_can_get(uint16_t can_channel, uint8_t bRequest, uint8_t *data, uint32_t len)
+{
+ (void)can_channel;
+ (void)bRequest;
+ (void)data;
+ (void)len;
+
+ switch (bRequest) {
+ case GS_USB_BREQ_BT_CONST:
+ break;
+ case GS_USB_BREQ_DEVICE_CONFIG:
+ break;
+ case GS_USB_BREQ_TIMESTAMP:
+ break;
+ case GS_USB_BREQ_BT_CONST_EXT:
+ break;
+ case GS_USB_BREQ_GET_TERMINATION:
+ break;
+ case GS_USB_BREQ_GET_STATE:
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+__WEAK int usbd_gs_usb_can_set(uint16_t can_channel, uint8_t bRequest, uint8_t *data, uint32_t len)
+{
+ (void)can_channel;
+ (void)bRequest;
+ (void)data;
+ (void)len;
+
+ switch (bRequest) {
+ case GS_USB_BREQ_HOST_FORMAT:
+ break;
+ case GS_USB_BREQ_BITTIMING:
+ break;
+ case GS_USB_BREQ_MODE:
+ break;
+ case GS_USB_BREQ_IDENTIFY:
+ break;
+ case GS_USB_BREQ_DATA_BITTIMING:
+ break;
+ case GS_USB_BREQ_SET_TERMINATION:
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/class/gs_usb/usbd_gs_usb.h b/class/gs_usb/usbd_gs_usb.h
new file mode 100644
index 00000000..7e03d3f4
--- /dev/null
+++ b/class/gs_usb/usbd_gs_usb.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2026, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_GS_USB_H
+#define USBD_GS_USB_H
+
+#include "gs_usb.h"
+
+/* Init gs usb interface driver */
+struct usbd_interface *usbd_gs_usb_init_intf(struct usbd_interface *intf);
+
+/* Setup request command callback api */
+int usbd_gs_usb_can_get(uint16_t can_channel, uint8_t bRequest, uint8_t *data, uint32_t len);
+int usbd_gs_usb_can_set(uint16_t can_channel, uint8_t bRequest, uint8_t *data, uint32_t len);
+
+#endif // USBD_GS_USB_H \ No newline at end of file
diff --git a/class/hid/usbh_hid.c b/class/hid/usbh_hid.c
index 3039f5aa..f8b89786 100644
--- a/class/hid/usbh_hid.c
+++ b/class/hid/usbh_hid.c
@@ -103,10 +103,10 @@ int usbh_hid_get_idle(struct usbh_hid *hid_class, uint8_t *buffer)
setup->wLength = 1;
ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf[hid_class->minor]);
- if (ret < 8) {
+ if (ret < 1) {
return ret;
}
- memcpy(buffer, g_hid_buf[hid_class->minor], MIN((uint32_t)ret - 8, 1));
+ *buffer = g_hid_buf[hid_class->minor][0];
return ret;
}
@@ -145,10 +145,10 @@ int usbh_hid_get_protocol(struct usbh_hid *hid_class, uint8_t *protocol)
setup->wLength = 1;
ret = usbh_control_transfer(hid_class->hport, setup, g_hid_buf[hid_class->minor]);
- if (ret < 8) {
+ if (ret < 1) {
return ret;
}
- memcpy(protocol, g_hid_buf[hid_class->minor], MIN((uint32_t)ret - 8, 1));
+ *protocol = g_hid_buf[hid_class->minor][0];
return ret;
}
@@ -324,7 +324,7 @@ int usbh_hid_parse_report_descriptor(const uint8_t *report_data, uint32_t report
if (itemsize == 3) /* HID spec: 6.2.2.2 - Short Items */
itemsize = 4;
- if((itemsize + i + 1) > report_size) {
+ if ((itemsize + i + 1) > report_size) {
goto err;
}
@@ -450,7 +450,7 @@ int usbh_hid_report_convert(struct usbh_hid_report_item *item, const uint8_t *re
const uint8_t *src;
uint32_t bits_len = item->attribute.report_size * item->attribute.report_count;
- if(bits_len == 0) {
+ if (bits_len == 0) {
return -1;
}
diff --git a/class/hub/usbh_hub.c b/class/hub/usbh_hub.c
index 5538de86..98e9f0e2 100644
--- a/class/hub/usbh_hub.c
+++ b/class/hub/usbh_hub.c
@@ -71,7 +71,7 @@ static int _usbh_hub_get_hub_descriptor(struct usbh_hub *hub, uint8_t *buffer)
setup->wLength = USB_SIZEOF_HUB_DESC;
ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
- if (ret < 0) {
+ if (ret < USB_SIZEOF_HUB_DESC) {
return ret;
}
memcpy(buffer, g_hub_buf[hub->bus->busid], USB_SIZEOF_HUB_DESC);
@@ -93,7 +93,7 @@ static int _usbh_hub_get_hub_ss_descriptor(struct usbh_hub *hub, uint8_t *buffer
setup->wLength = USB_SIZEOF_HUB_SS_DESC;
ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
- if (ret < 0) {
+ if (ret < USB_SIZEOF_HUB_SS_DESC) {
return ret;
}
memcpy(buffer, g_hub_buf[hub->bus->busid], USB_SIZEOF_HUB_SS_DESC);
@@ -115,7 +115,7 @@ static int _usbh_hub_get_portstatus(struct usbh_hub *hub, uint8_t port, struct h
setup->wLength = 4;
ret = usbh_control_transfer(hub->parent, setup, g_hub_buf[hub->bus->busid]);
- if (ret < 0) {
+ if (ret < 4) {
return ret;
}
memcpy(port_status, g_hub_buf[hub->bus->busid], 4);
@@ -647,15 +647,9 @@ static void usbh_hub_events(struct usbh_hub *hub)
USB_LOG_INFO("New %s device on Bus %u, Hub %u, Port %u connected\r\n", speed_table[speed], hub->bus->busid, hub->index, port + 1);
if (usbh_enumerate(child) < 0) {
- /** release child sources */
- usbh_hubport_release(child);
USB_LOG_ERR("Port %u enumerate fail\r\n", child->port);
}
} else {
- child = &hub->child[port];
- /** release child sources */
- usbh_hubport_release(child);
-
/** some USB 3.0 ip may failed to enable USB 2.0 port for USB 3.0 device */
USB_LOG_WRN("Failed to enable port %u\r\n", port + 1);
@@ -731,21 +725,21 @@ int usbh_hub_initialize(struct usbh_bus *bus)
bus->hub_mq = usb_osal_mq_create(7);
if (bus->hub_mq == NULL) {
- USB_LOG_ERR("Failed to create hub mq\r\n");
- return -1;
+ return -USB_ERR_NOMEM;
}
bus->hub_sem = usb_osal_sem_create(0);
if (bus->hub_sem == NULL) {
- USB_LOG_ERR("Failed to create hub sem\r\n");
- return -1;
+ usb_osal_mq_delete(bus->hub_mq);
+ return -USB_ERR_NOMEM;
}
snprintf(thread_name, 32, "usbh_hub%u", bus->busid);
bus->hub_thread = usb_osal_thread_create(thread_name, CONFIG_USBHOST_PSC_STACKSIZE, CONFIG_USBHOST_PSC_PRIO, usbh_hub_thread, bus);
if (bus->hub_thread == NULL) {
- USB_LOG_ERR("Failed to create hub thread\r\n");
- return -1;
+ usb_osal_mq_delete(bus->hub_mq);
+ usb_osal_sem_delete(bus->hub_sem);
+ return -USB_ERR_NOMEM;
}
return 0;
}
diff --git a/class/msc/usbd_msc.c b/class/msc/usbd_msc.c
index 6523ffb9..d21051f0 100644
--- a/class/msc/usbd_msc.c
+++ b/class/msc/usbd_msc.c
@@ -103,11 +103,12 @@ void msc_storage_notify_handler(uint8_t busid, uint8_t event, void *arg)
#if defined(CONFIG_USBDEV_MSC_THREAD)
g_usbd_msc[busid].usbd_msc_mq = usb_osal_mq_create(1);
if (g_usbd_msc[busid].usbd_msc_mq == NULL) {
- USB_LOG_ERR("No memory to alloc for g_usbd_msc[busid].usbd_msc_mq\r\n");
+ return;
}
g_usbd_msc[busid].usbd_msc_thread = usb_osal_thread_create("usbd_msc", CONFIG_USBDEV_MSC_STACKSIZE, CONFIG_USBDEV_MSC_PRIO, usbdev_msc_thread, (void *)(uint32_t)busid);
if (g_usbd_msc[busid].usbd_msc_thread == NULL) {
- USB_LOG_ERR("No memory to alloc for g_usbd_msc[busid].usbd_msc_thread\r\n");
+ usb_osal_mq_delete(g_usbd_msc[busid].usbd_msc_mq);
+ return;
}
#elif defined(CONFIG_USBDEV_MSC_POLLING)
g_usbd_msc[busid].event = 0;
@@ -151,8 +152,8 @@ static void usbd_msc_send_csw(uint8_t busid, uint8_t CSW_Status)
g_usbd_msc[busid].csw.bStatus = CSW_Status;
/* updating the State Machine , so that we wait CSW when this
- * transfer is complete, ie when we get a bulk in callback
- */
+ * transfer is complete, ie when we get a bulk in callback
+ */
g_usbd_msc[busid].stage = MSC_WAIT_CSW;
USB_LOG_DBG("Send csw\r\n");
@@ -164,8 +165,8 @@ static void usbd_msc_send_info(uint8_t busid, uint8_t *buffer, uint8_t size)
size = MIN(size, g_usbd_msc[busid].cbw.dDataLength);
/* updating the State Machine , so that we send CSW when this
- * transfer is complete, ie when we get a bulk in callback
- */
+ * transfer is complete, ie when we get a bulk in callback
+ */
g_usbd_msc[busid].stage = MSC_SEND_CSW;
usbd_ep_start_write(busid, mass_ep_data[busid][MSD_IN_EP_IDX].ep_addr, buffer, size);
@@ -504,6 +505,39 @@ static bool SCSI_readCapacity10(uint8_t busid, uint8_t **data, uint32_t *len)
return true;
}
+static bool SCSI_readCapacity16(uint8_t busid, uint8_t **data, uint32_t *len)
+{
+ uint8_t capacity16[32];
+ uint32_t last_lba;
+ uint32_t blk_size;
+
+ /* service action 0x10 = READ CAPACITY(16); other service actions unsupported */
+ if ((g_usbd_msc[busid].cbw.dDataLength == 0U) ||
+ ((g_usbd_msc[busid].cbw.CB[1] & 0x1fU) != 0x10U)) {
+ SCSI_SetSenseData(busid, SCSI_KCQIR_INVALIDCOMMAND);
+ return false;
+ }
+
+ last_lba = g_usbd_msc[busid].scsi_blk_nbr[g_usbd_msc[busid].cbw.bLUN] - 1U;
+ blk_size = g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN];
+
+ memset(capacity16, 0, sizeof(capacity16));
+ /* 8-byte LBA (project volume < 4G, upper 4 bytes stay 0) */
+ capacity16[4] = (uint8_t)((last_lba >> 24) & 0xff);
+ capacity16[5] = (uint8_t)((last_lba >> 16) & 0xff);
+ capacity16[6] = (uint8_t)((last_lba >> 8) & 0xff);
+ capacity16[7] = (uint8_t)(last_lba & 0xff);
+ /* 4-byte block length */
+ capacity16[8] = (uint8_t)((blk_size >> 24) & 0xff);
+ capacity16[9] = (uint8_t)((blk_size >> 16) & 0xff);
+ capacity16[10] = (uint8_t)((blk_size >> 8) & 0xff);
+ capacity16[11] = (uint8_t)(blk_size & 0xff);
+
+ memcpy(*data, (uint8_t *)capacity16, sizeof(capacity16));
+ *len = sizeof(capacity16);
+ return true;
+}
+
static bool SCSI_read10(uint8_t busid, uint8_t **data, uint32_t *len)
{
(void)data;
@@ -657,10 +691,15 @@ static bool SCSI_processRead(uint8_t busid)
static bool SCSI_processWrite(uint8_t busid, uint32_t nbytes)
{
uint32_t data_len = 0;
+ uint8_t csw_status = CSW_STATUS_CMD_PASSED;
USB_LOG_DBG("write lba:%d\r\n", g_usbd_msc[busid].start_sector);
- if (usbd_msc_sector_write(busid, g_usbd_msc[busid].cbw.bLUN, g_usbd_msc[busid].start_sector, g_usbd_msc[busid].block_buffer, nbytes) != 0) {
+ if (g_usbd_msc[busid].readonly) {
+ /* Discard data when read-only */
+ SCSI_SetSenseData(busid, SCSI_KCQWP_COMMANDNOTALLOWED);
+ csw_status = CSW_STATUS_CMD_FAILED;
+ } else if (usbd_msc_sector_write(busid, g_usbd_msc[busid].cbw.bLUN, g_usbd_msc[busid].start_sector, g_usbd_msc[busid].block_buffer, nbytes) != 0) {
SCSI_SetSenseData(busid, SCSI_KCQHE_WRITEFAULT);
return false;
}
@@ -670,7 +709,7 @@ static bool SCSI_processWrite(uint8_t busid, uint32_t nbytes)
g_usbd_msc[busid].csw.dDataResidue -= nbytes;
if (g_usbd_msc[busid].nsectors == 0) {
- usbd_msc_send_csw(busid, CSW_STATUS_CMD_PASSED);
+ usbd_msc_send_csw(busid, csw_status);
} else {
data_len = MIN(g_usbd_msc[busid].nsectors * g_usbd_msc[busid].scsi_blk_size[g_usbd_msc[busid].cbw.bLUN], CONFIG_USBDEV_MSC_MAX_BUFSIZE);
usbd_ep_start_read(busid, mass_ep_data[busid][MSD_OUT_EP_IDX].ep_addr, g_usbd_msc[busid].block_buffer, data_len);
@@ -727,6 +766,9 @@ static bool SCSI_CBWDecode(uint8_t busid, uint32_t nbytes)
case SCSI_CMD_READCAPACITY10:
ret = SCSI_readCapacity10(busid, &buf2send, &len2send);
break;
+ case SCSI_CMD_READCAPACITY16:
+ ret = SCSI_readCapacity16(busid, &buf2send, &len2send);
+ break;
case SCSI_CMD_READ10:
ret = SCSI_read10(busid, NULL, 0);
break;
diff --git a/class/msc/usbh_msc.c b/class/msc/usbh_msc.c
index cec9eb0c..1a93af6a 100644
--- a/class/msc/usbh_msc.c
+++ b/class/msc/usbh_msc.c
@@ -52,6 +52,7 @@ static void usbh_msc_class_free(struct usbh_msc *msc_class)
static int usbh_msc_get_maxlun(struct usbh_msc *msc_class, uint8_t *buffer)
{
struct usb_setup_packet *setup;
+ int ret;
if (!msc_class || !msc_class->hport) {
return -USB_ERR_INVAL;
@@ -64,7 +65,12 @@ static int usbh_msc_get_maxlun(struct usbh_msc *msc_class, uint8_t *buffer)
setup->wIndex = msc_class->intf;
setup->wLength = 1;
- return usbh_control_transfer(msc_class->hport, setup, buffer);
+ ret = usbh_control_transfer(msc_class->hport, setup, buffer);
+ if (ret < 1) {
+ return ret;
+ }
+
+ return ret;
}
static void usbh_msc_cbw_dump(struct CBW *cbw)
@@ -383,11 +389,14 @@ int usbh_msc_scsi_init(struct usbh_msc *msc_class)
return ret;
}
- if (msc_class->blocksize > 0) {
+ if (msc_class->blocksize == 512 ||
+ msc_class->blocksize == 1024 ||
+ msc_class->blocksize == 2048 ||
+ msc_class->blocksize == 4096) {
USB_LOG_INFO("Capacity info:\r\n");
USB_LOG_INFO("Block num:%d,block size:%d\r\n", (unsigned int)msc_class->blocknum, (unsigned int)msc_class->blocksize);
} else {
- USB_LOG_ERR("Invalid block size\r\n");
+ USB_LOG_ERR("Invalid block size %u\r\n", (unsigned int)msc_class->blocksize);
return -USB_ERR_RANGE;
}
diff --git a/class/mtp/usbd_mtp.h b/class/mtp/usbd_mtp.h
index 5db8cf97..6f9209cf 100644
--- a/class/mtp/usbd_mtp.h
+++ b/class/mtp/usbd_mtp.h
@@ -8,63 +8,6 @@
#include "usb_mtp.h"
-#define MTP_O_RDONLY 0 /* +1 == FREAD */
-#define MTP_O_WRONLY 1 /* +1 == FWRITE */
-#define MTP_O_RDWR 2 /* +1 == FREAD|FWRITE */
-
-#define MTP_S_IFMT 0170000 /* type of file */
-#define MTP_S_IFDIR 0040000 /* directory */
-#define MTP_S_IFCHR 0020000 /* character special */
-#define MTP_S_IFBLK 0060000 /* block special */
-#define MTP_S_IFREG 0100000 /* regular */
-#define MTP_S_IFLNK 0120000 /* symbolic link */
-#define MTP_S_IFSOCK 0140000 /* socket */
-#define MTP_S_IFIFO 0010000 /* fifo */
-#define MTP_S_IREAD 0000400 /* read permission, owner */
-#define MTP_S_IWRITE 0000200 /* write permission, owner */
-#define MTP_S_IEXEC 0000100 /* execute/search permission, owner */
-#define MTP_S_ENFMT 0002000 /* enforcement-mode locking */
-
-#define MTP_S_IRWXU (MTP_S_IRUSR | MTP_S_IWUSR | MTP_S_IXUSR)
-#define MTP_S_IRUSR 0000400 /* read permission, owner */
-#define MTP_S_IWUSR 0000200 /* write permission, owner */
-#define MTP_S_IXUSR 0000100 /* execute/search permission, owner */
-#define MTP_S_IRWXG (MTP_S_IRGRP | MTP_S_IWGRP | MTP_S_IXGRP)
-#define MTP_S_IRGRP 0000040 /* read permission, group */
-#define MTP_S_IWGRP 0000020 /* write permission, grougroup */
-#define MTP_S_IXGRP 0000010 /* execute/search permission, group */
-#define MTP_S_IRWXO (MTP_S_IROTH | MTP_S_IWOTH | MTP_S_IXOTH)
-#define MTP_S_IROTH 0000004 /* read permission, other */
-#define MTP_S_IWOTH 0000002 /* write permission, other */
-#define MTP_S_IXOTH 0000001 /* execute/search permission, other */
-
-typedef void MTP_DIR;
-
-struct mtp_statfs {
- size_t f_bsize; /* block size */
- size_t f_blocks; /* total data blocks in file system */
- size_t f_bfree; /* free blocks in file system */
-};
-
-struct mtp_stat {
- uint32_t st_dev;
- uint32_t st_ino;
- uint32_t st_mode;
- uint32_t st_nlink;
- uint32_t st_uid;
- uint32_t st_gid;
- size_t st_size;
- size_t st_blksize;
- size_t st_blocks;
-};
-
-struct mtp_dirent {
- uint8_t d_type; /* The type of the file */
- uint8_t d_namlen; /* The length of the not including the terminating null file name */
- uint16_t d_reclen; /* length of this record */
- char d_name[CONFIG_USBDEV_MTP_MAX_PATHNAME]; /* The null-terminated file name */
-};
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -77,25 +20,6 @@ struct usbd_interface *usbd_mtp_init_intf(struct usbd_interface *intf,
int usbd_mtp_notify_object_add(const char *path);
int usbd_mtp_notify_object_remove(const char *path);
-const char *usbd_mtp_fs_root_path(void);
-const char *usbd_mtp_fs_description(void);
-
-int usbd_mtp_mkdir(const char *path);
-int usbd_mtp_rmdir(const char *path);
-MTP_DIR *usbd_mtp_opendir(const char *name);
-int usbd_mtp_closedir(MTP_DIR *d);
-struct mtp_dirent *usbd_mtp_readdir(MTP_DIR *d);
-
-int usbd_mtp_statfs(const char *path, struct mtp_statfs *buf);
-int usbd_mtp_stat(const char *file, struct mtp_stat *buf);
-
-int usbd_mtp_open(const char *path, uint8_t mode);
-int usbd_mtp_close(int fd);
-int usbd_mtp_read(int fd, void *buf, size_t len);
-int usbd_mtp_write(int fd, const void *buf, size_t len);
-
-int usbd_mtp_unlink(const char *path);
-
#ifdef __cplusplus
}
#endif
diff --git a/class/serial/usbh_cdc_acm.c b/class/serial/usbh_cdc_acm.c
index cf5363ef..48643cb3 100644
--- a/class/serial/usbh_cdc_acm.c
+++ b/class/serial/usbh_cdc_acm.c
@@ -108,7 +108,7 @@ static int usbh_cdc_acm_get_line_coding(struct usbh_serial *serial, struct cdc_l
setup->wLength = 7;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
- if (ret < 0) {
+ if (ret < sizeof(struct cdc_line_coding)) {
return ret;
}
memcpy(line_coding, serial->iobuffer, sizeof(struct cdc_line_coding));
diff --git a/class/serial/usbh_ch34x.c b/class/serial/usbh_ch34x.c
index 4595bcae..a5fcd334 100644
--- a/class/serial/usbh_ch34x.c
+++ b/class/serial/usbh_ch34x.c
@@ -103,7 +103,7 @@ static int usbh_ch34x_control_in(struct usbh_serial *serial, uint8_t bRequest, u
setup->wLength = size;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
- if (ret < 0) {
+ if (ret < size) {
return ret;
}
memcpy(data, serial->iobuffer, size);
diff --git a/class/serial/usbh_cp210x.c b/class/serial/usbh_cp210x.c
index 7b240e2c..0f645a17 100644
--- a/class/serial/usbh_cp210x.c
+++ b/class/serial/usbh_cp210x.c
@@ -181,7 +181,7 @@ static int usbh_cp210x_control_in(struct usbh_serial *serial, uint8_t bRequest,
setup->wLength = size;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
- if (ret < 0) {
+ if (ret < size) {
return ret;
}
memcpy(data, serial->iobuffer, size);
diff --git a/class/serial/usbh_ftdi.c b/class/serial/usbh_ftdi.c
index c2d3a77b..19f00110 100644
--- a/class/serial/usbh_ftdi.c
+++ b/class/serial/usbh_ftdi.c
@@ -340,8 +340,8 @@ static int usbh_ftdi_get_modem_status(struct usbh_serial *serial)
setup->wLength = 2;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
- if (ret < 0) {
- return 0;
+ if (ret < 2) {
+ return ret;
}
status = (serial->iobuffer[0] & FTDI_SIO_DSR_MASK ? USBH_SERIAL_TIOCM_DSR : 0) |
diff --git a/class/serial/usbh_pl2303.c b/class/serial/usbh_pl2303.c
index 062f8128..e3b6a307 100644
--- a/class/serial/usbh_pl2303.c
+++ b/class/serial/usbh_pl2303.c
@@ -242,10 +242,10 @@ static int pl2303_vendor_read(struct usbh_serial *serial, uint16_t wValue, uint8
setup->wLength = 1;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
- if (ret < 0) {
+ if (ret < 1) {
return ret;
}
- memcpy(data, serial->iobuffer, 1);
+ *data = serial->iobuffer[0];
return ret;
}
@@ -280,7 +280,7 @@ static bool pl2303_is_hxd_clone(struct usbh_serial *serial)
setup->wLength = 7;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
- if (ret < 0) {
+ if (ret < 7) {
return false;
}
return true;
@@ -566,7 +566,7 @@ static int usbh_pl2303_get_line_coding(struct usbh_serial *serial, struct cdc_li
setup->wLength = 7;
ret = usbh_control_transfer(serial->hport, setup, serial->iobuffer);
- if (ret < 0) {
+ if (ret < sizeof(struct cdc_line_coding)) {
return ret;
}
memcpy(line_coding, serial->iobuffer, sizeof(struct cdc_line_coding));
diff --git a/class/serial/usbh_serial.c b/class/serial/usbh_serial.c
index 66aa51fc..65bf63f6 100644
--- a/class/serial/usbh_serial.c
+++ b/class/serial/usbh_serial.c
@@ -19,7 +19,9 @@ static struct usbh_serial g_serial_class[CONFIG_USBHOST_MAX_SERIAL_CLASS];
static uint32_t g_devinuse = 0;
static uint32_t g_cdcacm_devinuse = 0;
-USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_serial_iobuffer[CONFIG_USBHOST_MAX_SERIAL_CLASS][USB_ALIGN_UP((USBH_SERIAL_RX2_NOCACHE_OFFSET + USBH_SERIAL_RX2_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_serial_iobuffer[CONFIG_USBHOST_MAX_SERIAL_CLASS][USB_ALIGN_UP((USBH_SERIAL_RX2_NOCACHE_OFFSET + CONFIG_USBHOST_SERIAL_BULKIN_SIZE), CONFIG_USB_ALIGN_SIZE)];
+
+static void usbh_serial_callback(void *arg, int nbytes);
static struct usbh_serial *usbh_serial_alloc(bool is_cdcacm)
{
@@ -35,6 +37,11 @@ static struct usbh_serial *usbh_serial_alloc(bool is_cdcacm)
g_serial_class[devno].iobuffer = g_serial_iobuffer[devno];
g_serial_class[devno].rx_complete_sem = usb_osal_sem_create(0);
+ if (g_serial_class[devno].rx_complete_sem == NULL) {
+ g_devinuse &= ~(1U << devno);
+ return NULL;
+ }
+
if (is_cdcacm) {
for (devno2 = 0; devno2 < CONFIG_USBHOST_MAX_SERIAL_CLASS; devno2++) {
if ((g_cdcacm_devinuse & (1U << devno2)) == 0) {
@@ -67,19 +74,30 @@ static void usbh_serial_free(struct usbh_serial *serial)
if (g_serial_class[devno].rx_complete_sem) {
usb_osal_sem_delete(g_serial_class[devno].rx_complete_sem);
+ g_serial_class[devno].rx_complete_sem = NULL;
}
}
+static int usbh_serial_rx_restart(struct usbh_serial *serial)
+{
+ /* resubmit the read urb */
+ serial->rx_errorcode = 0;
+ usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET], CONFIG_USBHOST_SERIAL_BULKIN_SIZE,
+ 0, usbh_serial_callback, serial);
+ return usbh_submit_urb(&serial->bulkin_urb);
+}
+
static void usbh_serial_callback(void *arg, int nbytes)
{
struct usbh_serial *serial = (struct usbh_serial *)arg;
- uint32_t free_space;
+ uint8_t prev_buf_index;
int ret;
+ if (!serial)
+ return;
+
if (nbytes < 0) {
- if (nbytes != -USB_ERR_SHUTDOWN) {
- USB_LOG_ERR("serial transfer error: %d\n", nbytes);
- }
+ USB_LOG_ERR("serial transfer error: %d\n", nbytes);
serial->rx_errorcode = nbytes;
usb_osal_sem_give(serial->rx_complete_sem);
return;
@@ -93,30 +111,29 @@ static void usbh_serial_callback(void *arg, int nbytes)
}
if (nbytes >= serial->driver->ignore_rx_header) {
- /* resubmit the read urb */
- usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX_NOCACHE_OFFSET : USBH_SERIAL_RX2_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
- 0, usbh_serial_callback, serial);
- ret = usbh_submit_urb(&serial->bulkin_urb);
- if (ret < 0) {
- USB_LOG_ERR("serial submit failed: %d\n", ret);
- serial->rx_errorcode = ret;
- usb_osal_sem_give(serial->rx_complete_sem);
- return;
- }
-
- free_space = usb_ringbuffer_get_free(&serial->rx_rb);
- if (free_space < (nbytes - serial->driver->ignore_rx_header)) {
- USB_LOG_ERR("serial rx ringbuffer overflow, free space: %u, rx size: %u\n", free_space, (nbytes - serial->driver->ignore_rx_header));
+ prev_buf_index = serial->rx_buf_index;
+ serial->rx_buf_index ^= 1;
+ // next ringbuffer write will cause overflow, so don't resubmit the read urb
+ if (((nbytes - serial->driver->ignore_rx_header) + CONFIG_USBHOST_SERIAL_BULKIN_SIZE) > usb_ringbuffer_get_free(&serial->rx_rb)) {
+ serial->rx_pending = true;
+ } else {
+ serial->rx_pending = false;
+ ret = usbh_serial_rx_restart(serial);
+ if (ret < 0) {
+ USB_LOG_ERR("serial submit failed: %d\n", ret);
+ serial->rx_errorcode = ret;
+ usb_osal_sem_give(serial->rx_complete_sem);
+ return;
+ }
}
usb_ringbuffer_write(&serial->rx_rb,
- &serial->iobuffer[(serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET) + serial->driver->ignore_rx_header],
+ &serial->iobuffer[(prev_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET) + serial->driver->ignore_rx_header],
(nbytes - serial->driver->ignore_rx_header));
if (serial->rx_complete_callback) {
serial->rx_complete_callback(serial, nbytes - serial->driver->ignore_rx_header);
}
- serial->rx_buf_index ^= 1;
serial->rx_errorcode = 0;
usb_osal_sem_give(serial->rx_complete_sem);
}
@@ -375,10 +392,7 @@ int usbh_serial_control(struct usbh_serial *serial, int cmd, void *arg)
usb_ringbuffer_reset(&serial->rx_rb);
usb_osal_sem_reset(serial->rx_complete_sem);
serial->rx_buf_index = 0;
- usbh_bulk_urb_fill(&serial->bulkin_urb, serial->hport, serial->bulkin, &serial->iobuffer[serial->rx_buf_index ? USBH_SERIAL_RX2_NOCACHE_OFFSET : USBH_SERIAL_RX_NOCACHE_OFFSET], serial->bulkin->wMaxPacketSize,
- 0, usbh_serial_callback, serial);
- ret = usbh_submit_urb(&serial->bulkin_urb);
-
+ ret = usbh_serial_rx_restart(serial);
return ret;
} break;
case USBH_SERIAL_CMD_GET_ATTR: {
@@ -480,20 +494,27 @@ int usbh_serial_read(struct usbh_serial *serial, void *buffer, uint32_t buflen)
return -USB_ERR_NODEV;
}
- if (serial->open_flags & USBH_SERIAL_O_NONBLOCK) {
- return usb_ringbuffer_read(&serial->rx_rb, buffer, buflen);
- } else {
+ if (usb_ringbuffer_get_free(&serial->rx_rb) >= CONFIG_USBHOST_SERIAL_BULKIN_SIZE && serial->rx_pending) {
+ serial->rx_pending = false;
+ ret = usbh_serial_rx_restart(serial);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ if (!(serial->open_flags & USBH_SERIAL_O_NONBLOCK)) {
if (usb_ringbuffer_get_used(&serial->rx_rb) == 0) {
ret = usb_osal_sem_take(serial->rx_complete_sem, serial->rx_timeout_ms == 0 ? USB_OSAL_WAITING_FOREVER : serial->rx_timeout_ms);
if (ret < 0) {
return ret;
}
- if (serial->rx_errorcode < 0) {
- return serial->rx_errorcode;
- }
}
- return usb_ringbuffer_read(&serial->rx_rb, buffer, buflen);
}
+
+ if (serial->rx_errorcode < 0) {
+ return serial->rx_errorcode;
+ }
+ return usb_ringbuffer_read(&serial->rx_rb, buffer, buflen);
}
int usbh_serial_cdc_write_async(struct usbh_serial *serial, uint8_t *buffer, uint32_t buflen, usbh_complete_callback_t complete, void *arg)
diff --git a/class/serial/usbh_serial.h b/class/serial/usbh_serial.h
index 06a31709..17d0bd43 100644
--- a/class/serial/usbh_serial.h
+++ b/class/serial/usbh_serial.h
@@ -9,14 +9,20 @@
#include "usb_cdc.h"
+#ifndef CONFIG_USBHOST_SERIAL_BULKIN_SIZE
+#define CONFIG_USBHOST_SERIAL_BULKIN_SIZE 512
+#endif
+
#define USBH_SERIAL_CTRL_NOCACHE_OFFSET 0
#define USBH_SERIAL_CTRL_NOCACHE_SIZE 32
#define USBH_SERIAL_INT_NOCACHE_OFFSET USB_ALIGN_UP(USBH_SERIAL_CTRL_NOCACHE_SIZE, CONFIG_USB_ALIGN_SIZE)
#define USBH_SERIAL_INT_NOCACHE_SIZE 32
#define USBH_SERIAL_RX_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_INT_NOCACHE_OFFSET + USBH_SERIAL_INT_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)
-#define USBH_SERIAL_RX_NOCACHE_SIZE 512
-#define USBH_SERIAL_RX2_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_RX_NOCACHE_OFFSET + USBH_SERIAL_RX_NOCACHE_SIZE), CONFIG_USB_ALIGN_SIZE)
-#define USBH_SERIAL_RX2_NOCACHE_SIZE 512
+#define USBH_SERIAL_RX2_NOCACHE_OFFSET USB_ALIGN_UP((USBH_SERIAL_RX_NOCACHE_OFFSET + CONFIG_USBHOST_SERIAL_BULKIN_SIZE), CONFIG_USB_ALIGN_SIZE)
+
+#if CONFIG_USBHOST_SERIAL_RX_SIZE < CONFIG_USBHOST_SERIAL_BULKIN_SIZE
+#error "CONFIG_USBHOST_SERIAL_RX_SIZE must be greater than or equal to CONFIG_USBHOST_SERIAL_BULKIN_SIZE"
+#endif
#define USBH_SERIAL_DATABITS_5 5
#define USBH_SERIAL_DATABITS_6 6
@@ -142,6 +148,7 @@ struct usbh_serial {
uint8_t rx_buf_index;
int rx_errorcode;
usbh_serial_rx_complete_callback_t rx_complete_callback;
+ bool rx_pending;
void *priv; /* Private Data */
void *user_data; /* User Data */
diff --git a/class/tmc/usb_tmc.h b/class/tmc/usb_tmc.h
new file mode 100644
index 00000000..de03d297
--- /dev/null
+++ b/class/tmc/usb_tmc.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USB_TMC_H
+#define USB_TMC_H
+
+#define TMC_VERSION 0x0100
+
+/* Table 43: TMC Class Code */
+#define TMC_CLASS_APPLICATION 0xfe
+#define TMC_APPLICATION_SUBCLASS_TMC 0x03
+
+/* Table 44 */
+#define TMC_PROTOCOL_NONE 0
+#define TMC_PROTOCOL_USB488 1
+
+/* USB TMC Class Specific Requests, Table 15 sec 4.2.1 */
+#define TMC_REQUEST_INITIATE_ABORT_BULK_OUT 1
+#define TMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS 2
+#define TMC_REQUEST_INITIATE_ABORT_BULK_IN 3
+#define TMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS 4
+#define TMC_REQUEST_INITIATE_CLEAR 5
+#define TMC_REQUEST_CHECK_CLEAR_STATUS 6
+#define TMC_REQUEST_GET_CAPABILITIES 7
+#define TMC_REQUEST_INDICATOR_PULSE 64 //optional
+
+/* USB TMC status values Table 16 */
+#define TMC_STATUS_SUCCESS 1
+#define TMC_STATUS_PENDING 2
+#define TMC_STATUS_FAILED 0x80
+#define TMC_STATUS_TRANSFER_NOT_IN_PROGRESS 0x81
+#define TMC_STATUS_SPLIT_NOT_IN_PROGRESS 0x82
+#define TMC_STATUS_SPLIT_IN_PROGRESS 0x83
+
+struct tmc_bulk_header {
+ uint8_t MsgID;
+ uint8_t bTag;
+ uint8_t bTagInverse;
+ uint8_t reserved;
+
+ union {
+ struct _dev_dep_msg_out {
+ uint32_t transferSize;
+ uint8_t bmTransferAttributes;
+ uint8_t reserved[3];
+ } dev_dep_msg_out;
+
+ struct _req_dev_dep_msg_in {
+ uint32_t transferSize;
+ uint8_t bmTransferAttributes;
+ uint8_t TermChar;
+ uint8_t reserved[2];
+ } req_dev_dep_msg_in;
+
+ struct _dev_dep_msg_in {
+ uint32_t transferSize;
+ uint8_t bmTransferAttributes;
+ uint8_t reserved[3];
+ } dev_dep_msg_in;
+
+ struct _vendor_specific_out {
+ uint32_t transferSize;
+ uint8_t reserved[4];
+ } vendor_specific_out;
+
+ struct _req_vendor_specific_in {
+ uint32_t transferSize;
+ uint8_t reserved[4];
+ } req_vendor_specific_in;
+
+ struct _vendor_specific_in {
+ uint32_t transferSize;
+ uint8_t reserved[4];
+ } vendor_specific_in;
+
+ uint8_t data[8];
+ } msg_specific;
+} __attribute__((packed));
+
+/* Table 2, MsgId values */
+#define TMC_MSGID_OUT_DEV_DEP_MSG_OUT 1
+#define TMC_MSGID_OUT_REQUEST_DEV_DEP_MSG_IN 2
+#define TMC_MSGID_IN_DEV_DEP_MSG_IN 2
+/* 3-125 Reserved for USBTMC */
+#define TMC_MSGID_OUT_VENDOR_SPECIFIC_OUT 126
+#define TMC_MSGID_OUT_REQUEST_VENDOR_SPECIFIC_IN 127
+#define TMC_MSGID_IN_VENDOR_SPECIFIC_IN 127
+/* 128-255 Reserved for USBTMC subclass and VISA */
+
+/** The last USBTMC message data byte in the transfer is the last byte of the
+ * USBTMC message. */
+#define TMC_BULK_HEADER_TRANSFER_ATTR_EOM (1 << 0)
+/** The Bulk-IN transfer must terminate on the specified TermChar. The Host may
+ * only set this bit if the USBTMC interface indicates it supports TermChar in
+ * the GET_CAPABILITIES response packet */
+#define TMC_BULK_HEADER_TRANSFER_ATTR_TERMCHAR (1 << 1)
+
+#define TMC_INTERFACE_CAPABILITY_INDICATOR_PULSE (1 << 2)
+#define TMC_INTERFACE_CAPABILITY_TALK_ONLY (1 << 1)
+#define TMC_INTERFACE_CAPABILITY_LISTEN_ONLY (1 << 0)
+#define TMC_DEVICE_CAPABILITY_TERMCHAR (1 << 0)
+
+struct tmc_capabilities_response {
+ uint8_t USBTMC_status;
+ uint8_t reserved0;
+ uint16_t bcdUSBTMC;
+ uint8_t InterfaceCapabilities;
+ uint8_t DeviceCapabilities;
+ uint8_t reserved1[6];
+ uint16_t bcdUSB488;
+ uint8_t InterfaceCapabilities488;
+ uint8_t DeviceCapabilities488;
+ uint8_t reserved_subclass[8];
+} __attribute__((packed));
+
+struct tmc_initiate_abort_response {
+ uint8_t USBTMC_status;
+ uint8_t bTag;
+} __attribute__((packed));
+
+struct tmc_check_abort_bulk_response {
+ uint8_t USBTMC_status;
+ uint8_t bmAbortBulkIn; // D0: BulkInFifoBytes/BulkOutFifoBytes
+ uint8_t reserved[2];
+ uint32_t NBYTES_RXD_TXD;
+} __attribute__((packed));
+
+struct tmc_check_clear_status_response {
+ uint8_t USBTMC_status;
+ uint8_t bmClear; // D0: BulkInFifoBytes/BulkOutFifoBytes
+} __attribute__((packed));
+
+// clang-format off
+#define TMC_DESCRIPTOR_INIT(bInterfaceNumber, out_ep, in_ep, wMaxPacketSize, str_idx) \
+ USB_INTERFACE_DESCRIPTOR_INIT(bInterfaceNumber, 0x00, 0x02, 0xFE, 0x03, 0x00, str_idx), \
+ USB_ENDPOINT_DESCRIPTOR_INIT(out_ep, USB_ENDPOINT_TYPE_BULK, wMaxPacketSize, 0x00), \
+ USB_ENDPOINT_DESCRIPTOR_INIT(in_ep, USB_ENDPOINT_TYPE_BULK, wMaxPacketSize, 0x00)
+// clang-format on
+
+// clang-format off
+#define TMC488_DESCRIPTOR_INIT(bInterfaceNumber, out_ep, in_ep, wMaxPacketSize, str_idx) \
+ USB_INTERFACE_DESCRIPTOR_INIT(bInterfaceNumber, 0x00, 0x02, 0xFE, 0x03, 0x01, str_idx), \
+ USB_ENDPOINT_DESCRIPTOR_INIT(out_ep, USB_ENDPOINT_TYPE_BULK, wMaxPacketSize, 0x00), \
+ USB_ENDPOINT_DESCRIPTOR_INIT(in_ep, USB_ENDPOINT_TYPE_BULK, wMaxPacketSize, 0x00)
+// clang-format on
+
+#endif /* USB_TMC_H */ \ No newline at end of file
diff --git a/class/tmc/usbd_tmc.c b/class/tmc/usbd_tmc.c
new file mode 100644
index 00000000..7f351e99
--- /dev/null
+++ b/class/tmc/usbd_tmc.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_tmc.h"
+
+#define TMC_OUT_EP_IDX 0
+#define TMC_IN_EP_IDX 1
+
+/* Describe EndPoints configuration */
+static struct usbd_endpoint tmc_ep_data[2];
+
+#ifndef CONFIG_USBDEV_TMC_MAX_BUFSIZE
+#define CONFIG_USBDEV_TMC_MAX_BUFSIZE 1024
+#endif
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t tmc_read_buffer[CONFIG_USBDEV_TMC_MAX_BUFSIZE];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t tmc_write_buffer[CONFIG_USBDEV_TMC_MAX_BUFSIZE];
+
+static volatile uint32_t g_tmc_read_offset = 0;
+static volatile uint32_t g_tmc_read_total = 0;
+
+static scpi_t scpi_context;
+
+static char scpi_input_buffer[CONFIG_USBDEV_TMC_MAX_BUFSIZE];
+
+#define SCPI_ERROR_QUEUE_SIZE 4
+static scpi_error_t scpi_error_queue_data[SCPI_ERROR_QUEUE_SIZE];
+
+static size_t SCPI_Write(scpi_t *context, const char *data, size_t len)
+{
+ (void)context;
+
+ struct tmc_bulk_header *header = (struct tmc_bulk_header *)tmc_write_buffer;
+
+ USB_ASSERT_MSG((header->msg_specific.dev_dep_msg_in.transferSize + len) <= (CONFIG_USBDEV_TMC_MAX_BUFSIZE - sizeof(struct tmc_bulk_header)), "SCPI_Write: buffer overflow\r\n");
+
+ memcpy(tmc_write_buffer + sizeof(struct tmc_bulk_header) + header->msg_specific.dev_dep_msg_in.transferSize, data, len);
+ header->msg_specific.dev_dep_msg_in.transferSize += len;
+
+ return len;
+}
+
+static scpi_result_t SCPI_Flush(scpi_t *context)
+{
+ (void)context;
+
+ return SCPI_RES_OK;
+}
+
+static int SCPI_Error(scpi_t *context, int_fast16_t err)
+{
+ (void)context;
+
+ return SCPI_RES_OK;
+}
+
+static scpi_result_t SCPI_Control(scpi_t *context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val)
+{
+ (void)context;
+
+ return SCPI_RES_OK;
+}
+
+static scpi_result_t SCPI_Reset(scpi_t *context)
+{
+ (void)context;
+
+ return SCPI_RES_OK;
+}
+
+static scpi_interface_t scpi_interface = {
+ .error = SCPI_Error,
+ .write = SCPI_Write,
+ .control = SCPI_Control,
+ .flush = SCPI_Flush,
+ .reset = SCPI_Reset,
+};
+
+static int tmc_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ USB_LOG_DBG("TMC Class request: "
+ "bRequest 0x%02x\r\n",
+ setup->bRequest);
+
+ struct tmc_capabilities_response s_tmc_capabilities = {
+ .USBTMC_status = TMC_STATUS_SUCCESS,
+ .bcdUSBTMC = 0x0100,
+ .reserved0 = 0,
+ .reserved1 = { 0 },
+ .reserved_subclass = { 0 },
+ .InterfaceCapabilities = 0,
+ .DeviceCapabilities = 0
+ };
+
+ switch (setup->bRequest) {
+ case TMC_REQUEST_INITIATE_ABORT_BULK_OUT:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ *len = 2;
+ break;
+ case TMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ (*data)[1] = 0; // bmAbortBulkIn
+ (*data)[2] = 0; // reserved
+ (*data)[3] = 0; // reserved
+ *len = 4;
+ break;
+ case TMC_REQUEST_INITIATE_ABORT_BULK_IN:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ *len = 2;
+ break;
+ case TMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ (*data)[1] = 0; // bmAbortBulkIn
+ (*data)[2] = 0; // reserved
+ (*data)[3] = 0; // reserved
+ *len = 4;
+ break;
+ case TMC_REQUEST_INITIATE_CLEAR:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ *len = 1;
+ break;
+ case TMC_REQUEST_CHECK_CLEAR_STATUS:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ (*data)[1] = 0;
+ *len = 2;
+ break;
+ case TMC_REQUEST_GET_CAPABILITIES:
+ memcpy(*data, &s_tmc_capabilities, sizeof(s_tmc_capabilities));
+ *len = sizeof(s_tmc_capabilities);
+ break;
+ case TMC_REQUEST_INDICATOR_PULSE:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ *len = 1;
+ break;
+ default:
+ USB_LOG_WRN("Unhandled TMC Class bRequest 0x%02x\r\n", setup->bRequest);
+ return -1;
+ }
+
+ return 0;
+}
+
+void tmc_notify_handler(uint8_t busid, uint8_t event, void *arg)
+{
+ (void)arg;
+
+ switch (event) {
+ case USBD_EVENT_RESET:
+ break;
+ case USBD_EVENT_CONFIGURED:
+ g_tmc_read_offset = 0;
+ g_tmc_read_total = 0;
+ usbd_ep_start_read(busid, tmc_ep_data[TMC_OUT_EP_IDX].ep_addr, tmc_read_buffer + g_tmc_read_offset, usbd_get_ep_mps(busid, tmc_ep_data[TMC_OUT_EP_IDX].ep_addr));
+ break;
+
+ default:
+ break;
+ }
+}
+
+void tmc_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+ struct tmc_bulk_header *out_header = (struct tmc_bulk_header *)tmc_read_buffer;
+ struct tmc_bulk_header *in_header = (struct tmc_bulk_header *)tmc_write_buffer;
+
+ g_tmc_read_offset += nbytes;
+
+ if (g_tmc_read_total == 0) {
+ USB_ASSERT_MSG(nbytes >= sizeof(struct tmc_bulk_header), "tmc header size error\r\n");
+
+ switch (out_header->MsgID) {
+ case TMC_MSGID_OUT_DEV_DEP_MSG_OUT:
+ g_tmc_read_total = ((out_header->msg_specific.dev_dep_msg_out.transferSize + 3u) & ~3u) + sizeof(struct tmc_bulk_header);
+ break;
+ case TMC_MSGID_OUT_REQUEST_DEV_DEP_MSG_IN:
+ g_tmc_read_total = sizeof(struct tmc_bulk_header);
+ break;
+ default:
+ USB_LOG_WRN("Unhandled TMC MsgID 0x%02x\r\n", out_header->MsgID);
+ break;
+ }
+ USB_ASSERT_MSG(g_tmc_read_total <= CONFIG_USBDEV_TMC_MAX_BUFSIZE, "tmc read buffer overflow\r\n");
+ }
+
+ if (g_tmc_read_offset < g_tmc_read_total) {
+ usbd_ep_start_read(busid, tmc_ep_data[TMC_OUT_EP_IDX].ep_addr, tmc_read_buffer + g_tmc_read_offset, usbd_get_ep_mps(busid, tmc_ep_data[TMC_OUT_EP_IDX].ep_addr));
+ return;
+ }
+
+ switch (out_header->MsgID) {
+ case TMC_MSGID_OUT_DEV_DEP_MSG_OUT:
+ SCPI_Input(&scpi_context,
+ (const char *)(tmc_read_buffer + sizeof(struct tmc_bulk_header)),
+ g_tmc_read_total);
+ break;
+ case TMC_MSGID_OUT_REQUEST_DEV_DEP_MSG_IN:
+
+ in_header->MsgID = TMC_MSGID_IN_DEV_DEP_MSG_IN;
+ in_header->bTag = out_header->bTag;
+ in_header->bTagInverse = out_header->bTagInverse;
+ in_header->reserved = 0;
+ in_header->msg_specific.dev_dep_msg_in.bmTransferAttributes = TMC_BULK_HEADER_TRANSFER_ATTR_TERMCHAR;
+
+ usbd_ep_start_write(busid, tmc_ep_data[TMC_IN_EP_IDX].ep_addr, tmc_write_buffer, sizeof(struct tmc_bulk_header) + in_header->msg_specific.dev_dep_msg_in.transferSize);
+ break;
+ default:
+ USB_LOG_WRN("Unhandled TMC MsgID 0x%02x\r\n", out_header->MsgID);
+ break;
+ }
+
+ g_tmc_read_offset = 0;
+ g_tmc_read_total = 0;
+ usbd_ep_start_read(busid, tmc_ep_data[TMC_OUT_EP_IDX].ep_addr, tmc_read_buffer + g_tmc_read_offset, usbd_get_ep_mps(busid, tmc_ep_data[TMC_OUT_EP_IDX].ep_addr));
+}
+
+void tmc_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+ if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
+ /* send zlp */
+ usbd_ep_start_write(busid, ep, NULL, 0);
+ } else {
+ }
+}
+
+struct usbd_interface *usbd_tmc_init_intf(uint8_t busid,
+ struct usbd_interface *intf,
+ const uint8_t out_ep, const uint8_t in_ep,
+ const scpi_command_t *scpi_commands,
+ const char **idn)
+{
+ (void)busid;
+
+ intf->class_interface_handler = tmc_class_interface_request_handler;
+ intf->class_endpoint_handler = NULL;
+ intf->vendor_handler = NULL;
+ intf->notify_handler = tmc_notify_handler;
+
+ tmc_ep_data[TMC_OUT_EP_IDX].ep_addr = out_ep;
+ tmc_ep_data[TMC_OUT_EP_IDX].ep_cb = tmc_bulk_out;
+ tmc_ep_data[TMC_IN_EP_IDX].ep_addr = in_ep;
+ tmc_ep_data[TMC_IN_EP_IDX].ep_cb = tmc_bulk_in;
+
+ usbd_add_endpoint(busid, &tmc_ep_data[TMC_OUT_EP_IDX]);
+ usbd_add_endpoint(busid, &tmc_ep_data[TMC_IN_EP_IDX]);
+
+ SCPI_Init(&scpi_context,
+ scpi_commands,
+ &scpi_interface,
+ scpi_units_def,
+ idn[0], idn[1], idn[2], idn[3],
+ scpi_input_buffer, CONFIG_USBDEV_TMC_MAX_BUFSIZE,
+ scpi_error_queue_data, SCPI_ERROR_QUEUE_SIZE);
+
+ return intf;
+} \ No newline at end of file
diff --git a/class/tmc/usbd_tmc.h b/class/tmc/usbd_tmc.h
new file mode 100644
index 00000000..ca17d0d6
--- /dev/null
+++ b/class/tmc/usbd_tmc.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBD_TMC_H
+#define USBD_TMC_H
+
+#include "usb_tmc.h"
+#include "scpi/scpi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Init tmc interface driver */
+struct usbd_interface *usbd_tmc_init_intf(uint8_t busid,
+ struct usbd_interface *intf,
+ const uint8_t out_ep, const uint8_t in_ep,
+ const scpi_command_t *scpi_commands,
+ const char **idn);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBD_TMC_H */
diff --git a/class/vendor/net/usbh_asix.c b/class/vendor/net/usbh_asix.c
index 06a0d0ba..e63b274b 100644
--- a/class/vendor/net/usbh_asix.c
+++ b/class/vendor/net/usbh_asix.c
@@ -15,6 +15,10 @@
static struct usbh_asix g_asix_class;
+#if CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE > (16 * 1024)
+#error "CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE must be less than 16K"
+#endif
+
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_rx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_tx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_asix_inttx_buffer[USB_ALIGN_UP(16, CONFIG_USB_ALIGN_SIZE)];
@@ -71,10 +75,10 @@ static int usbh_asix_read_cmd(struct usbh_asix *asix_class,
setup->wLength = size;
ret = usbh_control_transfer(asix_class->hport, setup, g_asix_buf);
- if (ret < 8) {
+ if (ret < size) {
return ret;
}
- memcpy(data, g_asix_buf, MIN(ret - 8, size));
+ memcpy(data, g_asix_buf, size);
return ret;
}
@@ -679,17 +683,10 @@ void usbh_asix_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
uint16_t len;
uint16_t len_crc;
uint32_t data_offset;
-#if CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE <= (16 * 1024)
- uint32_t transfer_size = CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE;
-#else
- uint32_t transfer_size = (16 * 1024);
-#endif
(void)CONFIG_USB_OSAL_THREAD_GET_ARGV;
USB_LOG_INFO("Create asix rx thread\r\n");
- // clang-format off
-find_class:
- // clang-format on
+
g_asix_class.connect_status = false;
if (usbh_find_class_instance("/dev/asix") == NULL) {
goto delete;
@@ -698,28 +695,25 @@ find_class:
while (g_asix_class.connect_status == false) {
ret = usbh_asix_get_connect_status(&g_asix_class);
if (ret < 0) {
- usb_osal_msleep(100);
- goto find_class;
+ goto delete;
}
usb_osal_msleep(128);
}
g_asix_rx_length = 0;
while (1) {
- usbh_bulk_urb_fill(&g_asix_class.bulkin_urb, g_asix_class.hport, g_asix_class.bulkin, &g_asix_rx_buffer[g_asix_rx_length], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+ usbh_bulk_urb_fill(&g_asix_class.bulkin_urb, g_asix_class.hport, g_asix_class.bulkin, g_asix_rx_buffer, CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_asix_class.bulkin_urb);
if (ret < 0) {
- goto find_class;
+ goto delete;
}
- g_asix_rx_length += g_asix_class.bulkin_urb.actual_length;
+ g_asix_rx_length = g_asix_class.bulkin_urb.actual_length;
+ if (g_asix_rx_length == 0) {
+ continue;
+ }
- /* A transfer is complete because last packet is a short packet.
- * Short packet is not zero, match g_asix_rx_length % USB_GET_MAXPACKETSIZE(g_asix_class.bulkin->wMaxPacketSize).
- * Short packet is zero, check if g_asix_class.bulkin_urb.actual_length < transfer_size, for example transfer is complete with size is 1024 < 2048.
- */
- if (g_asix_rx_length % USB_GET_MAXPACKETSIZE(g_asix_class.bulkin->wMaxPacketSize) ||
- (g_asix_class.bulkin_urb.actual_length < transfer_size)) {
+ if (g_asix_rx_length < CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE) {
USB_LOG_DBG("rxlen:%d\r\n", g_asix_rx_length);
data_offset = 0;
@@ -743,15 +737,7 @@ find_class:
}
}
} else {
-#if CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE <= (16 * 1024)
- if (g_asix_rx_length == CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE) {
-#else
- if ((g_asix_rx_length + (16 * 1024)) > CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE) {
-#endif
- USB_LOG_ERR("Rx packet is overflow, please reduce tcp window size or increase CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE\r\n");
- while (1) {
- }
- }
+ USB_LOG_ERR("asix packet overflow\r\n");
}
}
// clang-format off
diff --git a/class/vendor/net/usbh_rtl8152.c b/class/vendor/net/usbh_rtl8152.c
index 50269f26..16393ab1 100644
--- a/class/vendor/net/usbh_rtl8152.c
+++ b/class/vendor/net/usbh_rtl8152.c
@@ -12,6 +12,10 @@
#define DEV_FORMAT "/dev/rtl8152"
+#if CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE > (16 * 1024)
+#error "CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE must be less than 16K"
+#endif
+
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_rx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_tx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rtl8152_inttx_buffer[USB_ALIGN_UP(2, CONFIG_USB_ALIGN_SIZE)];
@@ -962,10 +966,10 @@ static int usbh_rtl8152_read_regs(struct usbh_rtl8152 *rtl8152_class,
setup->wLength = size;
ret = usbh_control_transfer(rtl8152_class->hport, setup, g_rtl8152_buf);
- if (ret < 8) {
+ if (ret < size) {
return ret;
}
- memcpy(data, g_rtl8152_buf, MIN(ret - 8, size));
+ memcpy(data, g_rtl8152_buf, size);
return ret;
}
@@ -2138,17 +2142,10 @@ void usbh_rtl8152_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
int ret;
uint16_t len;
uint16_t data_offset;
-#if CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE <= (16 * 1024)
- uint32_t transfer_size = CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE;
-#else
- uint32_t transfer_size = (16 * 1024);
-#endif
(void)CONFIG_USB_OSAL_THREAD_GET_ARGV;
USB_LOG_INFO("Create rtl8152 rx thread\r\n");
- // clang-format off
-find_class:
- // clang-format on
+
g_rtl8152_class.connect_status = false;
if (usbh_find_class_instance("/dev/rtl8152") == NULL) {
goto delete;
@@ -2157,8 +2154,7 @@ find_class:
while (g_rtl8152_class.connect_status == false) {
ret = usbh_rtl8152_get_connect_status(&g_rtl8152_class);
if (ret < 0) {
- usb_osal_msleep(100);
- goto find_class;
+ goto delete;
}
usb_osal_msleep(128);
}
@@ -2174,20 +2170,18 @@ find_class:
g_rtl8152_rx_length = 0;
while (1) {
- usbh_bulk_urb_fill(&g_rtl8152_class.bulkin_urb, g_rtl8152_class.hport, g_rtl8152_class.bulkin, &g_rtl8152_rx_buffer[g_rtl8152_rx_length], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+ usbh_bulk_urb_fill(&g_rtl8152_class.bulkin_urb, g_rtl8152_class.hport, g_rtl8152_class.bulkin, g_rtl8152_rx_buffer, CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_rtl8152_class.bulkin_urb);
if (ret < 0) {
- goto find_class;
+ goto delete;
}
- g_rtl8152_rx_length += g_rtl8152_class.bulkin_urb.actual_length;
+ g_rtl8152_rx_length = g_rtl8152_class.bulkin_urb.actual_length;
+ if (g_rtl8152_rx_length == 0) {
+ continue;
+ }
- /* A transfer is complete because last packet is a short packet.
- * Short packet is not zero, match g_rtl8152_rx_length % USB_GET_MAXPACKETSIZE(g_rtl8152_class.bulkin->wMaxPacketSize).
- * Short packet is zero, check if g_rtl8152_class.bulkin_urb.actual_length < transfer_size, for example transfer is complete with size is 1024 < 2048.
- */
- if (g_rtl8152_rx_length % USB_GET_MAXPACKETSIZE(g_rtl8152_class.bulkin->wMaxPacketSize) ||
- (g_rtl8152_class.bulkin_urb.actual_length < transfer_size)) {
+ if (g_rtl8152_rx_length < CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE) {
data_offset = 0;
USB_LOG_DBG("rxlen:%d\r\n", g_rtl8152_rx_length);
@@ -2210,15 +2204,7 @@ find_class:
}
}
} else {
-#if CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE <= (16 * 1024)
- if (g_rtl8152_rx_length == CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE) {
-#else
- if ((g_rtl8152_rx_length + (16 * 1024)) > CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE) {
-#endif
- USB_LOG_ERR("Rx packet is overflow, please reduce tcp window size or increase CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE\r\n");
- while (1) {
- }
- }
+ USB_LOG_ERR("rtl8152 packet overflow\r\n");
}
}
// clang-format off
diff --git a/class/video/usbh_video.c b/class/video/usbh_video.c
index 8ecd252d..8e782e20 100644
--- a/class/video/usbh_video.c
+++ b/class/video/usbh_video.c
@@ -77,7 +77,7 @@ int usbh_video_get(struct usbh_video *video_class, uint8_t request, uint8_t intf
retry = 0;
while (1) {
ret = usbh_control_transfer(video_class->hport, setup, g_video_buf);
- if (ret > 0) {
+ if (ret >= len) {
break;
}
retry++;
diff --git a/class/wireless/usbd_rndis.c b/class/wireless/usbd_rndis.c
index 5fceb98f..ea62c50e 100644
--- a/class/wireless/usbd_rndis.c
+++ b/class/wireless/usbd_rndis.c
@@ -28,7 +28,7 @@ struct usbd_rndis_priv {
uint8_t mac[6];
} g_usbd_rndis;
-#if CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE < 140
+#if CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE < 156
#undef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
#endif
@@ -112,8 +112,7 @@ static int rndis_class_interface_request_handler(uint8_t busid, struct usb_setup
case CDC_REQUEST_SEND_ENCAPSULATED_COMMAND:
g_usbd_rndis.set_rsp_get = true;
- rndis_encapsulated_cmd_handler(*data, setup->wLength);
- break;
+ return rndis_encapsulated_cmd_handler(*data, setup->wLength);
case CDC_REQUEST_GET_ENCAPSULATED_RESPONSE:
g_usbd_rndis.set_rsp_get = false;
@@ -162,7 +161,9 @@ static int rndis_init_cmd_handler(uint8_t *data, uint32_t len)
rndis_initialize_msg_t *cmd = (rndis_initialize_msg_t *)data;
rndis_initialize_cmplt_t *resp;
- (void)len;
+ if (len < sizeof(rndis_initialize_msg_t)) {
+ return -1;
+ }
resp = ((rndis_initialize_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->RequestId = cmd->RequestId;
@@ -190,7 +191,10 @@ static int rndis_halt_cmd_handler(uint8_t *data, uint32_t len)
rndis_halt_msg_t *resp;
(void)data;
- (void)len;
+
+ if (len < sizeof(rndis_halt_msg_t)) {
+ return -1;
+ }
resp = ((rndis_halt_msg_t *)rndis_encapsulated_resp_buffer);
resp->MessageLength = 0;
@@ -207,7 +211,9 @@ static int rndis_query_cmd_handler(uint8_t *data, uint32_t len)
uint8_t *infomation_buffer;
uint32_t infomation_len = 0;
- (void)len;
+ if (len < sizeof(rndis_query_msg_t)) {
+ return -1;
+ }
resp = ((rndis_query_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->MessageType = REMOTE_NDIS_QUERY_CMPLT;
@@ -354,8 +360,11 @@ static int rndis_set_cmd_handler(uint8_t *data, uint32_t len)
rndis_set_msg_t *cmd = (rndis_set_msg_t *)data;
rndis_set_cmplt_t *resp;
rndis_config_parameter_t *param;
+ uint32_t *filter;
- (void)len;
+ if (len < sizeof(rndis_set_msg_t)) {
+ return -1;
+ }
resp = ((rndis_set_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->RequestId = cmd->RequestId;
@@ -367,21 +376,12 @@ static int rndis_set_cmd_handler(uint8_t *data, uint32_t len)
case OID_GEN_RNDIS_CONFIG_PARAMETER:
break;
case OID_GEN_CURRENT_PACKET_FILTER:
- if (cmd->InformationBufferLength < sizeof(g_usbd_rndis.net_filter)) {
- resp->Status = RNDIS_STATUS_INVALID_DATA;
- } else {
- uint32_t *filter;
- /* Parameter starts at offset buf_offset of the req_id field */
- filter = (uint32_t *)((uint8_t *)&(cmd->RequestId) + cmd->InformationBufferOffset);
-
- //g_usbd_rndis.net_filter = param->ParameterNameOffset;
- g_usbd_rndis.net_filter = *(uint32_t *)filter;
- if (g_usbd_rndis.net_filter) {
- g_usbd_rndis.init_state = rndis_data_initialized;
- } else {
- g_usbd_rndis.init_state = rndis_initialized;
- }
+ if (len < (sizeof(rndis_set_msg_t) + cmd->InformationBufferLength)) {
+ return -1;
}
+
+ filter = (uint32_t *)(data + sizeof(rndis_set_msg_t));
+ g_usbd_rndis.net_filter = *filter;
break;
case OID_GEN_CURRENT_LOOKAHEAD:
break;
@@ -409,7 +409,10 @@ static int rndis_reset_cmd_handler(uint8_t *data, uint32_t len)
rndis_reset_cmplt_t *resp;
(void)data;
- (void)len;
+
+ if (len < sizeof(rndis_reset_cmplt_t)) {
+ return -1;
+ }
resp = ((rndis_reset_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->MessageType = REMOTE_NDIS_RESET_CMPLT;
@@ -429,7 +432,9 @@ static int rndis_keepalive_cmd_handler(uint8_t *data, uint32_t len)
rndis_keepalive_msg_t *cmd = (rndis_keepalive_msg_t *)data;
rndis_keepalive_cmplt_t *resp;
- (void)len;
+ if (len < sizeof(rndis_keepalive_msg_t)) {
+ return -1;
+ }
resp = ((rndis_keepalive_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->RequestId = cmd->RequestId;
@@ -512,7 +517,7 @@ int usbd_rndis_start_write(uint8_t *buf, uint32_t len)
return -USB_ERR_BUSY;
}
- if((len % usbd_get_ep_mps(0, rndis_ep_data[RNDIS_IN_EP_IDX].ep_addr)) == 0) {
+ if ((len % usbd_get_ep_mps(0, rndis_ep_data[RNDIS_IN_EP_IDX].ep_addr)) == 0) {
/* If the data length is a multiple of the endpoint max packet size, add one byte to indicate the end of the transfer. */
len += 1;
}
@@ -628,7 +633,7 @@ int usbd_rndis_set_connect(bool connect)
return -USB_ERR_NOTCONN;
}
- if(g_usbd_rndis.set_rsp_get)
+ if (g_usbd_rndis.set_rsp_get)
return -USB_ERR_BUSY;
rndis_indicate_status_t *resp;
@@ -636,7 +641,7 @@ int usbd_rndis_set_connect(bool connect)
resp = ((rndis_indicate_status_t *)rndis_encapsulated_resp_buffer);
resp->MessageType = REMOTE_NDIS_INDICATE_STATUS_MSG;
resp->MessageLength = sizeof(rndis_indicate_status_t);
- if(connect) {
+ if (connect) {
resp->Status = RNDIS_STATUS_MEDIA_CONNECT;
g_usbd_rndis.link_status = NDIS_MEDIA_STATE_CONNECTED;
} else {
diff --git a/class/wireless/usbh_rndis.c b/class/wireless/usbh_rndis.c
index 709630cb..22f0e369 100644
--- a/class/wireless/usbh_rndis.c
+++ b/class/wireless/usbh_rndis.c
@@ -13,10 +13,11 @@
#define DEV_FORMAT "/dev/rndis"
-USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_buf[512];
+#if CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE > (16 * 1024)
+#error "CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE must be less than 16K"
+#endif
-#define CONFIG_USBHOST_RNDIS_ETH_MAX_FRAME_SIZE 1514
-#define CONFIG_USBHOST_RNDIS_ETH_MSG_SIZE (CONFIG_USBHOST_RNDIS_ETH_MAX_FRAME_SIZE + 44)
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_buf[512];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE, CONFIG_USB_ALIGN_SIZE)];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE, CONFIG_USB_ALIGN_SIZE)];
@@ -39,12 +40,96 @@ static int usbh_rndis_get_notification(struct usbh_rndis *rndis_class)
return 0;
}
+static int usbh_rndis_parse_resp(struct usbh_rndis *rndis_class)
+{
+ struct usb_setup_packet *setup;
+ rndis_generic_msg_t *resp_generic;
+ int ret;
+
+ if (!rndis_class || !rndis_class->hport) {
+ return -USB_ERR_INVAL;
+ }
+ setup = rndis_class->hport->setup;
+
+ usbh_rndis_get_notification(rndis_class);
+
+ setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
+ setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
+ setup->wValue = 0;
+ setup->wIndex = 0;
+ setup->wLength = sizeof(g_rndis_buf);
+
+ ret = usbh_control_transfer(rndis_class->hport, setup, g_rndis_buf);
+ if (ret < sizeof(rndis_generic_msg_t)) {
+ USB_LOG_ERR("resp recv error, ret: %d\r\n", ret);
+ return ret;
+ }
+
+ resp_generic = (rndis_generic_msg_t *)g_rndis_buf;
+ if (resp_generic->MessageLength != ret) {
+ USB_LOG_ERR("resp length error, expect: %d, actual: %d\r\n", resp_generic->MessageLength, ret);
+ return -USB_ERR_RANGE;
+ }
+
+ switch (resp_generic->MessageType) {
+ case REMOTE_NDIS_INITIALIZE_CMPLT:
+ if (ret != sizeof(rndis_initialize_cmplt_t)) {
+ return -USB_ERR_RANGE;
+ }
+ rndis_initialize_cmplt_t *resp_init;
+
+ resp_init = (rndis_initialize_cmplt_t *)g_rndis_buf;
+
+ rndis_class->max_transfer_pkts = resp_init->MaxPacketsPerTransfer;
+ rndis_class->max_transfer_size = resp_init->MaxTransferSize;
+ USB_LOG_INFO("MaxPacketsPerTransfer: %u\r\n", (unsigned int)resp_init->MaxPacketsPerTransfer);
+ USB_LOG_INFO("MaxTransferSize: %u\r\n", (unsigned int)resp_init->MaxTransferSize);
+ break;
+ case REMOTE_NDIS_QUERY_CMPLT:
+ if (ret < sizeof(rndis_query_cmplt_t)) {
+ return -USB_ERR_RANGE;
+ }
+
+ rndis_query_cmplt_t *resp_query;
+ resp_query = (rndis_query_cmplt_t *)g_rndis_buf;
+
+ if (ret != (sizeof(rndis_query_cmplt_t) + resp_query->InformationBufferLength)) {
+ return -USB_ERR_RANGE;
+ }
+ if (resp_query->InformationBufferOffset != (sizeof(rndis_query_cmplt_t) - sizeof(rndis_generic_msg_t))) {
+ return -USB_ERR_RANGE;
+ }
+
+ break;
+ case REMOTE_NDIS_SET_CMPLT:
+ break;
+ case REMOTE_NDIS_RESET_CMPLT:
+ break;
+ case REMOTE_NDIS_KEEPALIVE_CMPLT:
+ break;
+ case REMOTE_NDIS_INDICATE_STATUS_MSG:
+ if (ret != sizeof(rndis_indicate_status_t)) {
+ return -USB_ERR_RANGE;
+ }
+
+ rndis_indicate_status_t *resp_indicate;
+ resp_indicate = (rndis_indicate_status_t *)g_rndis_buf;
+
+ rndis_class->connect_status = (resp_indicate->Status == RNDIS_STATUS_MEDIA_CONNECT) ? true : false;
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
{
struct usb_setup_packet *setup;
- int ret = 0;
+ int ret;
rndis_initialize_msg_t *cmd;
- rndis_initialize_cmplt_t *resp;
if (!rndis_class || !rndis_class->hport) {
return -USB_ERR_INVAL;
@@ -68,46 +153,36 @@ static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
if (ret < 0) {
- USB_LOG_ERR("init send error, ret: %d\r\n", ret);
+ USB_LOG_ERR("init msg send error, ret: %d\r\n", ret);
return ret;
}
- usbh_rndis_get_notification(rndis_class);
-
- resp = (rndis_initialize_cmplt_t *)g_rndis_buf;
-
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
- setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
- setup->wValue = 0;
- setup->wIndex = 0;
- setup->wLength = sizeof(g_rndis_buf);
-
- ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
- if (ret < 0) {
- USB_LOG_ERR("init recv error, ret: %d\r\n", ret);
- return ret;
- }
-
- rndis_class->max_transfer_pkts = resp->MaxPacketsPerTransfer;
- rndis_class->max_transfer_size = resp->MaxTransferSize;
- USB_LOG_INFO("MaxPacketsPerTransfer: %u\r\n", (unsigned int)resp->MaxPacketsPerTransfer);
- USB_LOG_INFO("MaxTransferSize: %u\r\n", (unsigned int)resp->MaxTransferSize);
-
- return ret;
+ return usbh_rndis_parse_resp(rndis_class);
}
-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)
+static int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class,
+ uint32_t oid,
+ uint32_t query_len,
+ uint8_t *info,
+ uint32_t info_max_len,
+ uint32_t *info_len)
{
struct usb_setup_packet *setup;
- int ret = 0;
+ int ret;
rndis_query_msg_t *cmd;
rndis_query_cmplt_t *resp;
if (!rndis_class || !rndis_class->hport) {
return -USB_ERR_INVAL;
}
+
+ if(query_len > (sizeof(g_rndis_buf) - sizeof(rndis_query_msg_t))) {
+ return -USB_ERR_NOMEM;
+ }
+
setup = rndis_class->hport->setup;
+
cmd = (rndis_query_msg_t *)g_rndis_buf;
cmd->MessageType = REMOTE_NDIS_QUERY_MSG;
@@ -126,26 +201,29 @@ int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid,
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
if (ret < 0) {
- USB_LOG_ERR("oid:%08x send error, ret: %d\r\n", (unsigned int)oid, ret);
+ USB_LOG_ERR("query oid:%08x msg send error, ret: %d\r\n", (unsigned int)oid, ret);
return ret;
}
- usbh_rndis_get_notification(rndis_class);
+ ret = usbh_rndis_parse_resp(rndis_class);
+ if (ret < 0) {
+ return ret;
+ }
resp = (rndis_query_cmplt_t *)g_rndis_buf;
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
- setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
- setup->wValue = 0;
- setup->wIndex = 0;
- setup->wLength = sizeof(g_rndis_buf);
-
- ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
- if (ret < 0) {
- USB_LOG_ERR("oid:%08x recv error, ret: %d\r\n", (unsigned int)oid, ret);
+ if(resp->MessageType != REMOTE_NDIS_QUERY_CMPLT) {
return ret;
}
+ if (query_len != 0 && resp->InformationBufferLength != query_len) {
+ return -USB_ERR_RANGE;
+ }
+
+ if (resp->InformationBufferLength > info_max_len) {
+ return -USB_ERR_NOMEM;
+ }
+
memcpy(info, ((uint8_t *)resp + sizeof(rndis_query_cmplt_t)), resp->InformationBufferLength);
*info_len = resp->InformationBufferLength;
@@ -155,13 +233,17 @@ int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid,
static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid, uint8_t *info, uint32_t info_len)
{
struct usb_setup_packet *setup;
- int ret = 0;
+ int ret;
rndis_set_msg_t *cmd;
- rndis_set_cmplt_t *resp;
if (!rndis_class || !rndis_class->hport) {
return -USB_ERR_INVAL;
}
+
+ if(info_len > (sizeof(g_rndis_buf) - sizeof(rndis_set_msg_t))) {
+ return -USB_ERR_NOMEM;
+ }
+
setup = rndis_class->hport->setup;
cmd = (rndis_set_msg_t *)g_rndis_buf;
@@ -187,35 +269,24 @@ static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t
return ret;
}
- usbh_rndis_get_notification(rndis_class);
-
- resp = (rndis_set_cmplt_t *)g_rndis_buf;
-
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
- setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
- setup->wValue = 0;
- setup->wIndex = 0;
- setup->wLength = sizeof(g_rndis_buf);
-
- ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
- if (ret < 0) {
- USB_LOG_ERR("oid:%08x recv error, ret: %d\r\n", (unsigned int)oid, ret);
- return ret;
- }
-
- return ret;
+ return usbh_rndis_parse_resp(rndis_class);
}
int usbh_rndis_get_connect_status(struct usbh_rndis *rndis_class)
{
int ret;
- uint8_t data[32];
+ uint8_t data[4];
uint32_t data_len;
- ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, 4, data, &data_len);
+ ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, 4, data, sizeof(data), &data_len);
if (ret < 0) {
return ret;
}
+
+ if (ret == sizeof(rndis_indicate_status_t)) {
+ return 0;
+ }
+
if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
rndis_class->connect_status = true;
} else {
@@ -229,7 +300,6 @@ int usbh_rndis_keepalive(struct usbh_rndis *rndis_class)
struct usb_setup_packet *setup;
int ret = 0;
rndis_keepalive_msg_t *cmd;
- rndis_keepalive_cmplt_t *resp;
if (!rndis_class || !rndis_class->hport) {
return -USB_ERR_INVAL;
@@ -254,23 +324,7 @@ int usbh_rndis_keepalive(struct usbh_rndis *rndis_class)
return ret;
}
- usbh_rndis_get_notification(rndis_class);
-
- resp = (rndis_keepalive_cmplt_t *)g_rndis_buf;
-
- setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
- setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
- setup->wValue = 0;
- setup->wIndex = 0;
- setup->wLength = sizeof(g_rndis_buf);
-
- ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
- if (ret < 0) {
- USB_LOG_ERR("keepalive recv error, ret: %d\r\n", ret);
- return ret;
- }
-
- return ret;
+ return usbh_rndis_parse_resp(rndis_class);
}
static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
@@ -282,7 +336,7 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
uint32_t oid_num = 0;
uint32_t data_len;
uint8_t tmp_buffer[512];
- uint8_t data[32];
+ uint8_t data[6];
struct usbh_rndis *rndis_class = &g_rndis_class;
@@ -313,7 +367,7 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
return ret;
}
- ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_SUPPORTED_LIST, 0, tmp_buffer, &data_len);
+ ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_SUPPORTED_LIST, 0, tmp_buffer, sizeof(tmp_buffer), &data_len);
if (ret < 0) {
return ret;
}
@@ -326,19 +380,19 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
oid = oid_support_list[i];
switch (oid) {
case OID_GEN_PHYSICAL_MEDIUM:
- ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_PHYSICAL_MEDIUM, 4, data, &data_len);
+ ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_PHYSICAL_MEDIUM, 4, data, sizeof(data), &data_len);
if (ret < 0) {
goto query_errorout;
}
break;
case OID_GEN_MAXIMUM_FRAME_SIZE:
- ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MAXIMUM_FRAME_SIZE, 4, data, &data_len);
+ ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MAXIMUM_FRAME_SIZE, 4, data, sizeof(data), &data_len);
if (ret < 0) {
goto query_errorout;
}
break;
case OID_GEN_LINK_SPEED:
- ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_LINK_SPEED, 4, data, &data_len);
+ ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_LINK_SPEED, 4, data, sizeof(data), &data_len);
if (ret < 0) {
goto query_errorout;
}
@@ -346,7 +400,7 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
memcpy(&rndis_class->link_speed, data, 4);
break;
case OID_GEN_MEDIA_CONNECT_STATUS:
- ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, 4, data, &data_len);
+ ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, 4, data, sizeof(data), &data_len);
if (ret < 0) {
goto query_errorout;
}
@@ -357,13 +411,13 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
}
break;
case OID_802_3_MAXIMUM_LIST_SIZE:
- ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_MAXIMUM_LIST_SIZE, 4, data, &data_len);
+ ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_MAXIMUM_LIST_SIZE, 4, data, sizeof(data), &data_len);
if (ret < 0) {
goto query_errorout;
}
break;
case OID_802_3_CURRENT_ADDRESS:
- ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_CURRENT_ADDRESS, 6, data, &data_len);
+ ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_CURRENT_ADDRESS, 6, data, sizeof(data), &data_len);
if (ret < 0) {
goto query_errorout;
}
@@ -373,7 +427,7 @@ static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
}
break;
case OID_802_3_PERMANENT_ADDRESS:
- ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_PERMANENT_ADDRESS, 6, data, &data_len);
+ ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_PERMANENT_ADDRESS, 6, data, sizeof(data), &data_len);
if (ret < 0) {
goto query_errorout;
}
@@ -451,18 +505,11 @@ void usbh_rndis_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
uint32_t pmg_offset;
rndis_data_packet_t *pmsg;
rndis_data_packet_t temp;
-#if CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE <= (16 * 1024)
- uint32_t transfer_size = CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE;
-#else
- uint32_t transfer_size = (16 * 1024);
-#endif
(void)CONFIG_USB_OSAL_THREAD_GET_ARGV;
USB_LOG_INFO("Create rndis rx thread\r\n");
- // clang-format off
-find_class:
- // clang-format on
+
g_rndis_class.connect_status = false;
if (usbh_find_class_instance("/dev/rndis") == NULL) {
goto delete;
@@ -471,30 +518,28 @@ find_class:
while (g_rndis_class.connect_status == false) {
ret = usbh_rndis_get_connect_status(&g_rndis_class);
if (ret < 0) {
- usb_osal_msleep(100);
- goto find_class;
+ goto delete;
}
usb_osal_msleep(128);
}
g_rndis_rx_length = 0;
while (1) {
- usbh_bulk_urb_fill(&g_rndis_class.bulkin_urb, g_rndis_class.hport, g_rndis_class.bulkin, &g_rndis_rx_buffer[g_rndis_rx_length], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+ usbh_bulk_urb_fill(&g_rndis_class.bulkin_urb, g_rndis_class.hport, g_rndis_class.bulkin, g_rndis_rx_buffer, CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_rndis_class.bulkin_urb);
if (ret < 0) {
- break;
+ goto delete;
}
- g_rndis_rx_length += g_rndis_class.bulkin_urb.actual_length;
+ g_rndis_rx_length = g_rndis_class.bulkin_urb.actual_length;
+ if (g_rndis_rx_length == 0) {
+ USB_LOG_WRN("rndis rx length is 0 but no zero required in spec\r\n");
+ continue;
+ }
- /* A transfer is complete because last packet is a short packet.
- * Short packet is not zero, match g_rndis_rx_length % USB_GET_MAXPACKETSIZE(g_rndis_class.bulkin->wMaxPacketSize).
- * Short packet cannot be zero.
- */
if (g_rndis_rx_length % USB_GET_MAXPACKETSIZE(g_rndis_class.bulkin->wMaxPacketSize)) {
pmg_offset = 0;
-
- uint32_t total_len = g_rndis_rx_length;
+ USB_LOG_DBG("rxlen:%d\r\n", g_rndis_rx_length);
while (g_rndis_rx_length > 0) {
USB_LOG_DBG("rxlen:%u\r\n", (unsigned int)g_rndis_rx_length);
@@ -519,21 +564,12 @@ find_class:
g_rndis_rx_length = 0;
}
} else {
- USB_LOG_ERR("offset:%u,remain:%u,total:%u\r\n", (unsigned int)pmg_offset, (unsigned int)g_rndis_rx_length, (unsigned int)total_len);
+ USB_LOG_ERR("Error rndis packet message, offset:%u, remain:%u\r\n", (unsigned int)pmg_offset, (unsigned int)g_rndis_rx_length);
g_rndis_rx_length = 0;
- USB_LOG_ERR("Error rndis packet message\r\n");
}
}
} else {
-#if CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE <= (16 * 1024)
- if (g_rndis_rx_length == CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE) {
-#else
- if ((g_rndis_rx_length + (16 * 1024)) > CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE) {
-#endif
- USB_LOG_ERR("Rx packet is overflow, please reduce tcp window size or increase CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE\r\n");
- while (1) {
- }
- }
+ USB_LOG_ERR("rndis packet overflow\r\n");
}
}
@@ -601,3 +637,12 @@ CLASS_INFO_DEFINE const struct usbh_class_info rndis_cdcacm_class_info = {
.id_table = NULL,
.class_driver = &rndis_class_driver
};
+
+CLASS_INFO_DEFINE const struct usbh_class_info rndis_android_class_info = {
+ .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
+ .bInterfaceClass = USB_DEVICE_CLASS_MISC,
+ .bInterfaceSubClass = 0x04,
+ .bInterfaceProtocol = 0x01,
+ .id_table = NULL,
+ .class_driver = &rndis_class_driver
+};
diff --git a/common/usb_dc.h b/common/usb_dc.h
index 42a332e7..cdb9f415 100644
--- a/common/usb_dc.h
+++ b/common/usb_dc.h
@@ -13,6 +13,33 @@ extern "C" {
#endif
/**
+ * @brief USB device controller driver ops.
+ *
+ * Structure containing the USB device controller driver ops.
+ */
+struct usbd_dc_driver {
+ const char *driver_name;
+ const char *driver_desc;
+ int (*init)(uint8_t busid);
+ int (*deinit)(uint8_t busid);
+ int (*set_address)(uint8_t busid, const uint8_t addr);
+ int (*set_remote_wakeup)(uint8_t busid);
+ uint8_t (*get_port_speed)(uint8_t busid);
+ int (*ep_open)(uint8_t busid, const struct usb_endpoint_descriptor *ep);
+ int (*ep_open_extra)(uint8_t busid, const struct usb_endpoint_descriptor *ep, const struct usb_endpoint_companion_descriptor *ep_comp);
+ int (*ep_close)(uint8_t busid, const uint8_t ep);
+ int (*ep_set_stall)(uint8_t busid, const uint8_t ep);
+ int (*ep_clear_stall)(uint8_t busid, const uint8_t ep);
+ int (*ep_is_stalled)(uint8_t busid, const uint8_t ep, uint8_t *stalled);
+ int (*ep_start_write)(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len);
+ int (*ep_start_read)(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len);
+ void (*irq_handler)(uint8_t busid);
+#ifdef CONFIG_USBDEV_TEST_MODE
+ void (*execute_test_mode)(uint8_t busid, uint8_t test_mode);
+#endif
+};
+
+/**
* @brief init device controller registers.
* @return On success will return 0, and others indicate fail.
*/
@@ -59,6 +86,15 @@ uint8_t usbd_get_port_speed(uint8_t busid);
int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep);
/**
+ * @brief configure endpoint extra for usb3.0.
+ *
+ * @param [in] ep_cfg Endpoint config.
+ *
+ * @return On success will return 0, and others indicate fail.
+ */
+int usbd_ep_open_extra(uint8_t busid, const struct usb_endpoint_descriptor *ep, const struct usb_endpoint_companion_descriptor *ep_comp);
+
+/**
* @brief Disable the selected endpoint
*
* @param[in] ep Endpoint address
diff --git a/common/usb_def.h b/common/usb_def.h
index e3fdd240..73d2b800 100644
--- a/common/usb_def.h
+++ b/common/usb_def.h
@@ -104,6 +104,8 @@
#define USB_REQUEST_LOOPBACK_DATA_WRITE 0x15
#define USB_REQUEST_LOOPBACK_DATA_READ 0x16
#define USB_REQUEST_SET_INTERFACE_DS 0x17
+#define USB_REQUEST_SET_SEL 0x30
+#define USB_REQUEST_SET_ISOCH_DLY 0x31
/* USB Standard Feature selectors */
#define USB_FEATURE_ENDPOINT_HALT 0
@@ -116,11 +118,15 @@
#define USB_FEATURE_AHNPSUPPORT 4
#define USB_FEATURE_AALTHNPSUPPORT 5
#define USB_FEATURE_DEBUGMODE 6
+#define USB_FEATURE_U1_ENABLE 0x30
+#define USB_FEATURE_U2_ENABLE 0x31
/* USB GET_STATUS Bit Values */
#define USB_GETSTATUS_ENDPOINT_HALT 0x01
#define USB_GETSTATUS_SELF_POWERED 0x01
#define USB_GETSTATUS_REMOTE_WAKEUP 0x02
+#define USB_GETSTATUS_U1_ENABLE 0x04
+#define USB_GETSTATUS_U2_ENABLE 0x08
/* USB Descriptor Types */
#define USB_DESCRIPTOR_TYPE_DEVICE 0x01U
@@ -137,6 +143,7 @@
#define USB_DESCRIPTOR_TYPE_BINARY_OBJECT_STORE 0x0FU
#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY 0x10U
#define USB_DESCRIPTOR_TYPE_WIRELESS_ENDPOINTCOMP 0x11U
+#define USB_DESCRIPTOR_TYPE_ENDPOINT_COMPANION 0x30U
/* Class Specific Descriptor */
#define USB_CS_DESCRIPTOR_TYPE_DEVICE 0x21U
@@ -405,6 +412,17 @@ struct usb_endpoint_descriptor {
#define USB_SIZEOF_ENDPOINT_DESC 7
+/** Standard Endpoint Companion Descriptor */
+struct usb_endpoint_companion_descriptor {
+ uint8_t bLength; /* Descriptor size in bytes = 6 */
+ uint8_t bDescriptorType; /* ENDPOINT COMPANION descriptor type = 0x30 */
+ uint8_t bMaxBurst; /* Maximum number of bursts */
+ uint8_t bmAttributes; /* Companion attributes */
+ uint16_t wBytesPerInterval; /* Bytes per interval */
+} __PACKED;
+
+#define USB_SIZEOF_ENDPOINT_COMPANION_DESC 6
+
/** Unicode (UTF16LE) String Descriptor */
struct usb_string_descriptor {
uint8_t bLength;
@@ -638,6 +656,22 @@ struct usb_desc_header {
USB_STRING_SERIAL_INDEX, /* iSerial */ \
bNumConfigurations /* bNumConfigurations */
+#define USB3_DEVICE_DESCRIPTOR_INIT(bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct, bcdDevice, bNumConfigurations) \
+ 0x12, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_DEVICE, /* bDescriptorType */ \
+ WBVAL(USB_3_0), /* bcdUSB */ \
+ bDeviceClass, /* bDeviceClass */ \
+ bDeviceSubClass, /* bDeviceSubClass */ \
+ bDeviceProtocol, /* bDeviceProtocol */ \
+ 0x09, /* bMaxPacketSize */ \
+ WBVAL(idVendor), /* idVendor */ \
+ WBVAL(idProduct), /* idProduct */ \
+ WBVAL(bcdDevice), /* bcdDevice */ \
+ USB_STRING_MFC_INDEX, /* iManufacturer */ \
+ USB_STRING_PRODUCT_INDEX, /* iProduct */ \
+ USB_STRING_SERIAL_INDEX, /* iSerial */ \
+ bNumConfigurations /* bNumConfigurations */
+
#define USB_CONFIG_DESCRIPTOR_INIT(wTotalLength, bNumInterfaces, bConfigurationValue, bmAttributes, bMaxPower) \
0x09, /* bLength */ \
USB_DESCRIPTOR_TYPE_CONFIGURATION, /* bDescriptorType */ \
@@ -689,6 +723,13 @@ struct usb_desc_header {
WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \
bInterval /* bInterval */
+#define USB_ENDPOINT_COMPANION_DESCRIPTOR_INIT(bMaxBurst, bmAttributes, wBytesPerInterval) \
+ 0x06, /* bLength */ \
+ USB_DESCRIPTOR_TYPE_ENDPOINT_COMPANION, /* bDescriptorType */ \
+ bMaxBurst, /* bMaxBurst */ \
+ bmAttributes, /* bmAttributes */ \
+ WBVAL(wBytesPerInterval) /* wBytesPerInterval */
+
#define USB_IAD_DESCRIPTOR_INIT(bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass, bFunctionProtocol) \
0x08, /* bLength */ \
USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \
diff --git a/common/usb_hc.h b/common/usb_hc.h
index aa411eef..f24c337e 100644
--- a/common/usb_hc.h
+++ b/common/usb_hc.h
@@ -59,6 +59,23 @@ struct usbh_urb {
};
/**
+ * @brief USB host controller driver.
+ *
+ * Structure containing the USB host controller driver.
+ */
+struct usbh_hc_driver {
+ const char *driver_name;
+ const char *driver_desc;
+ int (*init)(struct usbh_bus *bus);
+ int (*deinit)(struct usbh_bus *bus);
+ uint16_t (*get_frame_number)(struct usbh_bus *bus);
+ int (*roothub_control)(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf);
+ int (*submit_urb)(struct usbh_urb *urb);
+ int (*kill_urb)(struct usbh_urb *urb);
+ void (*irq_handler)(uint8_t busid);
+};
+
+/**
* @brief usb host controller hardware init.
*
* @return On success will return 0, and others indicate fail.
diff --git a/common/usb_util.h b/common/usb_util.h
index 521bf27f..97e0917c 100644
--- a/common/usb_util.h
+++ b/common/usb_util.h
@@ -185,6 +185,26 @@
(field)[3] = (uint8_t)((value) >> 0); \
} while (0)
+#define GET_LE16(field) \
+ (((uint16_t)(field)[0] << 0) | ((uint16_t)(field)[1] << 8))
+
+#define GET_LE32(field) \
+ (((uint32_t)(field)[0] << 0) | ((uint32_t)(field)[1] << 8) | ((uint32_t)(field)[2] << 16) | ((uint32_t)(field)[3] << 24))
+
+#define SET_LE16(field, value) \
+ do { \
+ (field)[0] = (uint8_t)((value) >> 0); \
+ (field)[1] = (uint8_t)((value) >> 8); \
+ } while (0)
+
+#define SET_LE32(field, value) \
+ do { \
+ (field)[0] = (uint8_t)((value) >> 0); \
+ (field)[1] = (uint8_t)((value) >> 8); \
+ (field)[2] = (uint8_t)((value) >> 16); \
+ (field)[3] = (uint8_t)((value) >> 24); \
+ } while (0)
+
#define WBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF)
#define DBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF), (((x) >> 16) & 0xFF), (((x) >> 24) & 0xFF)
diff --git a/common/usb_vfs.h b/common/usb_vfs.h
new file mode 100644
index 00000000..0fd5a4ee
--- /dev/null
+++ b/common/usb_vfs.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2026, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ */
+#ifndef USB_VFS_H
+#define USB_VFS_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define VFS_O_RDONLY 0 /* +1 == FREAD, existing file only */
+#define VFS_O_WRONLY 1 /* +1 == FWRITE, create / truncate */
+#define VFS_O_RDWR 2 /* +1 == FREAD|FWRITE, create, no truncate */
+
+/* file mode bits, POSIX layout so they can go straight into the wire reply */
+#define VFS_S_IFMT 0170000 /* type of file */
+#define VFS_S_IFDIR 0040000 /* directory */
+#define VFS_S_IFCHR 0020000 /* character special */
+#define VFS_S_IFBLK 0060000 /* block special */
+#define VFS_S_IFREG 0100000 /* regular */
+#define VFS_S_IFLNK 0120000 /* symbolic link */
+#define VFS_S_IFSOCK 0140000 /* socket */
+#define VFS_S_IFIFO 0010000 /* fifo */
+#define VFS_S_IREAD 0000400 /* read permission, owner */
+#define VFS_S_IWRITE 0000200 /* write permission, owner */
+#define VFS_S_IEXEC 0000100 /* execute/search permission, owner */
+#define VFS_S_ENFMT 0002000 /* enforcement-mode locking */
+
+#define VFS_S_IRWXU (VFS_S_IRUSR | VFS_S_IWUSR | VFS_S_IXUSR)
+#define VFS_S_IRUSR 0000400 /* read permission, owner */
+#define VFS_S_IWUSR 0000200 /* write permission, owner */
+#define VFS_S_IXUSR 0000100 /* execute/search permission, owner */
+#define VFS_S_IRWXG (VFS_S_IRGRP | VFS_S_IWGRP | VFS_S_IXGRP)
+#define VFS_S_IRGRP 0000040 /* read permission, group */
+#define VFS_S_IWGRP 0000020 /* write permission, group */
+#define VFS_S_IXGRP 0000010 /* execute/search permission, group */
+#define VFS_S_IRWXO (VFS_S_IROTH | VFS_S_IWOTH | VFS_S_IXOTH)
+#define VFS_S_IROTH 0000004 /* read permission, other */
+#define VFS_S_IWOTH 0000002 /* write permission, other */
+#define VFS_S_IXOTH 0000001 /* execute/search permission, other */
+
+#define VFS_ERR_GENERIC (-1) /* unspecified */
+#define VFS_ERR_NOENT (-2) /* no such file or directory */
+#define VFS_ERR_IO (-3) /* low level I/O error */
+#define VFS_ERR_NOTDIR (-4) /* a path component is not a directory */
+#define VFS_ERR_ISDIR (-5) /* it is a directory, not a file */
+#define VFS_ERR_EXIST (-6) /* already exists */
+#define VFS_ERR_NOSPC (-7) /* no space left on device */
+#define VFS_ERR_ROFS (-8) /* read-only file system */
+#define VFS_ERR_INVAL (-9) /* invalid argument or invalid name */
+#define VFS_ERR_NOMEM (-10) /* out of memory */
+#define VFS_ERR_AGAIN (-11) /* busy, try again */
+#define VFS_ERR_NODEV (-12) /* no file system mounted on that path */
+
+#ifndef VFS_MAX_PATHNAME
+#define VFS_MAX_PATHNAME 256
+#endif
+
+typedef void VFS_DIR;
+
+struct vfs_statfs {
+ size_t f_bsize; /* block size */
+ size_t f_blocks; /* total data blocks in file system */
+ size_t f_bfree; /* free blocks in file system */
+};
+
+struct vfs_stat {
+ uint32_t st_dev;
+ uint32_t st_ino;
+ uint32_t st_mode;
+ uint32_t st_nlink;
+ uint32_t st_uid;
+ uint32_t st_gid;
+ size_t st_size;
+ size_t st_blksize;
+ size_t st_blocks;
+ uint32_t st_mtime;
+};
+
+struct vfs_dirent {
+ uint8_t d_type; /* The type of the file */
+ uint8_t d_namlen; /* The length of the not including the terminating null file name */
+ uint16_t d_reclen; /* length of this record */
+ char d_name[VFS_MAX_PATHNAME]; /* The null-terminated file name */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *vfs_get_fs_root_path(void);
+
+const char *vfs_get_fs_description(void);
+
+int vfs_mkdir(const char *path);
+int vfs_rmdir(const char *path);
+
+VFS_DIR *vfs_opendir(const char *name);
+int vfs_closedir(VFS_DIR *d);
+struct vfs_dirent *vfs_readdir(VFS_DIR *d);
+
+int vfs_statfs(const char *path, struct vfs_statfs *buf);
+int vfs_stat(const char *file, struct vfs_stat *buf);
+
+int vfs_open(const char *path, uint8_t mode);
+int vfs_close(int fd);
+int vfs_read(int fd, void *buf, size_t len);
+int vfs_write(int fd, const void *buf, size_t len);
+
+int vfs_unlink(const char *path);
+
+static inline const char *vfs_strerror(int err)
+{
+ switch (err) {
+ case 0:
+ return "success";
+ case VFS_ERR_NOENT:
+ return "no such file or directory";
+ case VFS_ERR_IO:
+ return "input/output error";
+ case VFS_ERR_NOTDIR:
+ return "not a directory";
+ case VFS_ERR_ISDIR:
+ return "is a directory";
+ case VFS_ERR_EXIST:
+ return "file exists";
+ case VFS_ERR_NOSPC:
+ return "no space left on device";
+ case VFS_ERR_ROFS:
+ return "read-only file system";
+ case VFS_ERR_INVAL:
+ return "invalid argument";
+ case VFS_ERR_NOMEM:
+ return "out of memory";
+ case VFS_ERR_AGAIN:
+ return "resource temporarily unavailable";
+ case VFS_ERR_NODEV:
+ return "no such device or address";
+ default:
+ return "unspecified error";
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USB_VFS_H */
diff --git a/core/usbd_core.c b/core/usbd_core.c
index a9ad67c4..b023fefc 100644
--- a/core/usbd_core.c
+++ b/core/usbd_core.c
@@ -31,8 +31,12 @@
struct usbd_tx_rx_msg {
uint8_t ep;
+ uint8_t ep_type;
uint8_t ep_mult;
uint16_t ep_mps;
+ uint8_t ep_interval;
+ uint8_t ep_maxburst;
+ uint8_t ep_maxstream;
uint32_t nbytes;
usbd_endpoint_callback cb;
};
@@ -62,8 +66,11 @@ USB_NOCACHE_RAM_SECTION struct usbd_core_priv {
bool self_powered;
bool remote_wakeup_support;
bool remote_wakeup_enabled;
+ bool u1_enable;
+ bool u2_enable;
bool is_suspend;
uint8_t speed;
+ uint16_t isoch_delay;
#ifdef CONFIG_USBDEV_TEST_MODE
bool test_req;
#endif
@@ -132,9 +139,13 @@ static bool usbd_set_endpoint(uint8_t busid, const struct usb_endpoint_descripto
if (ep->bEndpointAddress & 0x80) {
g_usbd_core[busid].tx_msg[ep->bEndpointAddress & 0x7f].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
g_usbd_core[busid].tx_msg[ep->bEndpointAddress & 0x7f].ep_mult = USB_GET_MULT(ep->wMaxPacketSize);
+ g_usbd_core[busid].tx_msg[ep->bEndpointAddress & 0x7f].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
+ g_usbd_core[busid].tx_msg[ep->bEndpointAddress & 0x7f].ep_interval = ep->bInterval;
} else {
g_usbd_core[busid].rx_msg[ep->bEndpointAddress & 0x7f].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
g_usbd_core[busid].rx_msg[ep->bEndpointAddress & 0x7f].ep_mult = USB_GET_MULT(ep->wMaxPacketSize);
+ g_usbd_core[busid].rx_msg[ep->bEndpointAddress & 0x7f].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
+ g_usbd_core[busid].rx_msg[ep->bEndpointAddress & 0x7f].ep_interval = ep->bInterval;
}
return usbd_ep_open(busid, ep) == 0 ? true : false;
@@ -160,6 +171,79 @@ static bool usbd_reset_endpoint(uint8_t busid, const struct usb_endpoint_descrip
}
/**
+ * @brief Set endpoint companion descriptor for the specified endpoint
+ */
+static bool usbd_set_endpoint_extra(uint8_t busid, const struct usb_endpoint_descriptor *ep, const struct usb_endpoint_companion_descriptor *ep_comp)
+{
+ USB_LOG_DBG("Set ep maxburst:%u bmAttributes:%u wBytesPerInterval:%u\r\n",
+ ep_comp->bMaxBurst,
+ ep_comp->bmAttributes,
+ ep_comp->wBytesPerInterval);
+
+ uint16_t wBytesPerInterval = 0;
+
+ (void)wBytesPerInterval;
+
+ if (ep->bEndpointAddress & 0x80) {
+ g_usbd_core[busid].tx_msg[ep->bEndpointAddress & 0x7f].ep_maxburst = ep_comp->bMaxBurst + 1;
+
+ switch (USB_GET_ENDPOINT_TYPE(ep->bmAttributes)) {
+ case USB_ENDPOINT_TYPE_BULK:
+ g_usbd_core[busid].tx_msg[ep->bEndpointAddress & 0x7f].ep_maxstream = 2 << (ep_comp->bmAttributes & 0x1f);
+ break;
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ g_usbd_core[busid].tx_msg[ep->bEndpointAddress & 0x7f].ep_maxstream = 0;
+
+ wBytesPerInterval = g_usbd_core[busid].tx_msg[ep->bEndpointAddress & 0x7f].ep_maxburst * USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
+ USB_ASSERT_MSG(wBytesPerInterval == ep_comp->wBytesPerInterval, "wBytesPerInterval mismatch");
+ break;
+
+ case USB_ENDPOINT_TYPE_ISOCHRONOUS:
+ g_usbd_core[busid].tx_msg[ep->bEndpointAddress & 0x7f].ep_maxstream = 0;
+
+ USB_ASSERT_MSG((USB_GET_MULT(ep->wMaxPacketSize) == (ep_comp->bmAttributes & 0x03)), "mult mismatch");
+ wBytesPerInterval = g_usbd_core[busid].tx_msg[ep->bEndpointAddress & 0x7f].ep_maxburst *
+ (USB_GET_MULT(ep->wMaxPacketSize) + 1) *
+ USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
+
+ USB_ASSERT_MSG(wBytesPerInterval == ep_comp->wBytesPerInterval, "wBytesPerInterval mismatch");
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ g_usbd_core[busid].rx_msg[ep->bEndpointAddress & 0x7f].ep_maxburst = ep_comp->bMaxBurst + 1;
+
+ switch (USB_GET_ENDPOINT_TYPE(ep->bmAttributes)) {
+ case USB_ENDPOINT_TYPE_BULK:
+ g_usbd_core[busid].rx_msg[ep->bEndpointAddress & 0x7f].ep_maxstream = 2 << (ep_comp->bmAttributes & 0x1f);
+ break;
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ g_usbd_core[busid].rx_msg[ep->bEndpointAddress & 0x7f].ep_maxstream = 0;
+
+ wBytesPerInterval = g_usbd_core[busid].rx_msg[ep->bEndpointAddress & 0x7f].ep_maxburst * USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
+ USB_ASSERT_MSG(wBytesPerInterval == ep_comp->wBytesPerInterval, "wBytesPerInterval mismatch");
+ break;
+
+ case USB_ENDPOINT_TYPE_ISOCHRONOUS:
+ g_usbd_core[busid].rx_msg[ep->bEndpointAddress & 0x7f].ep_maxstream = 0;
+
+ USB_ASSERT_MSG((USB_GET_MULT(ep->wMaxPacketSize) == (ep_comp->bmAttributes & 0x03)), "mult mismatch");
+ wBytesPerInterval = g_usbd_core[busid].rx_msg[ep->bEndpointAddress & 0x7f].ep_maxburst *
+ (USB_GET_MULT(ep->wMaxPacketSize) + 1) *
+ USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
+
+ USB_ASSERT_MSG(wBytesPerInterval == ep_comp->wBytesPerInterval, "wBytesPerInterval mismatch");
+ break;
+
+ default:
+ break;
+ }
+ }
+ return usbd_ep_open_extra(busid, ep, ep_comp) == 0 ? true : false;
+}
+/**
* @brief get specified USB descriptor
*
* This function parses the list of installed USB descriptors and attempts
@@ -372,8 +456,21 @@ static bool usbd_set_configuration(uint8_t busid, uint8_t config_index, uint8_t
}
found = usbd_set_endpoint(busid, (struct usb_endpoint_descriptor *)p);
- break;
+ if (g_usbd_core[busid].speed >= USB_SPEED_SUPER) {
+ const uint8_t *ep_comp_desc;
+
+ ep_comp_desc = p;
+ ep_comp_desc += p[DESC_bLength];
+
+ if (ep_comp_desc[DESC_bLength] == USB_SIZEOF_ENDPOINT_COMPANION_DESC &&
+ ep_comp_desc[DESC_bDescriptorType] == USB_DESCRIPTOR_TYPE_ENDPOINT_COMPANION) {
+ usbd_set_endpoint_extra(busid, (struct usb_endpoint_descriptor *)p, (struct usb_endpoint_companion_descriptor *)ep_comp_desc);
+ } else {
+ USB_ASSERT("Invalid endpoint companion descriptor");
+ }
+ }
+ break;
default:
break;
}
@@ -442,12 +539,25 @@ static bool usbd_set_interface(uint8_t busid, uint8_t iface, uint8_t alt_setting
ret = usbd_reset_endpoint(busid, ep_desc);
} else if (cur_alt_setting == alt_setting) {
ret = usbd_set_endpoint(busid, ep_desc);
+
+ if (g_usbd_core[busid].speed >= USB_SPEED_SUPER) {
+ const uint8_t *ep_comp_desc;
+
+ ep_comp_desc = p;
+ ep_comp_desc += p[DESC_bLength];
+
+ if (ep_comp_desc[DESC_bLength] == USB_SIZEOF_ENDPOINT_COMPANION_DESC &&
+ ep_comp_desc[DESC_bDescriptorType] == USB_DESCRIPTOR_TYPE_ENDPOINT_COMPANION) {
+ usbd_set_endpoint_extra(busid, ep_desc, (struct usb_endpoint_companion_descriptor *)ep_comp_desc);
+ } else {
+ USB_ASSERT("Invalid endpoint companion descriptor");
+ }
+ }
} else {
}
}
break;
-
default:
break;
}
@@ -491,6 +601,13 @@ static bool usbd_std_device_req_handler(uint8_t busid, struct usb_setup_packet *
if (g_usbd_core[busid].remote_wakeup_enabled) {
(*data)[0] |= USB_GETSTATUS_REMOTE_WAKEUP;
}
+ if (g_usbd_core[busid].u1_enable) {
+ (*data)[0] |= USB_GETSTATUS_U1_ENABLE;
+ }
+ if (g_usbd_core[busid].u2_enable) {
+ (*data)[0] |= USB_GETSTATUS_U2_ENABLE;
+ }
+
(*data)[1] = 0x00;
*len = 2;
break;
@@ -505,11 +622,28 @@ static bool usbd_std_device_req_handler(uint8_t busid, struct usb_setup_packet *
g_usbd_core[busid].remote_wakeup_enabled = false;
g_usbd_core[busid].event_handler(busid, USBD_EVENT_CLR_REMOTE_WAKEUP);
}
+ } else if (value == USB_FEATURE_U1_ENABLE) {
+ if (setup->bRequest == USB_REQUEST_SET_FEATURE) {
+ g_usbd_core[busid].u1_enable = true;
+ g_usbd_core[busid].event_handler(busid, USBD_EVENT_SET_U1_ENABLE);
+ } else {
+ g_usbd_core[busid].u1_enable = false;
+ g_usbd_core[busid].event_handler(busid, USBD_EVENT_CLR_U1_ENABLE);
+ }
+ } else if (value == USB_FEATURE_U2_ENABLE) {
+ if (setup->bRequest == USB_REQUEST_SET_FEATURE) {
+ g_usbd_core[busid].u2_enable = true;
+ g_usbd_core[busid].event_handler(busid, USBD_EVENT_SET_U2_ENABLE);
+ } else {
+ g_usbd_core[busid].u2_enable = false;
+ g_usbd_core[busid].event_handler(busid, USBD_EVENT_CLR_U2_ENABLE);
+ }
} else if (value == USB_FEATURE_TEST_MODE) {
#ifdef CONFIG_USBDEV_TEST_MODE
g_usbd_core[busid].test_req = true;
#endif
}
+
*len = 0;
break;
@@ -552,6 +686,11 @@ static bool usbd_std_device_req_handler(uint8_t busid, struct usb_setup_packet *
case USB_REQUEST_SET_INTERFACE:
ret = false;
break;
+ case USB_REQUEST_SET_SEL:
+ break;
+ case USB_REQUEST_SET_ISOCH_DLY:
+ g_usbd_core[busid].isoch_delay = value;
+ break;
default:
ret = false;
@@ -1244,6 +1383,11 @@ void usbd_add_endpoint(uint8_t busid, struct usbd_endpoint *ep)
}
}
+uint8_t usbd_get_device_speed(uint8_t busid)
+{
+ return g_usbd_core[busid].speed;
+}
+
uint16_t usbd_get_ep_mps(uint8_t busid, uint8_t ep)
{
if (ep & 0x80) {
@@ -1262,6 +1406,29 @@ uint8_t usbd_get_ep_mult(uint8_t busid, uint8_t ep)
}
}
+int usbd_get_ep_info(uint8_t busid, uint8_t ep, struct usbd_endpoint_info *ep_info)
+{
+ if (g_usbd_core[busid].configuration == 0)
+ return -1;
+
+ if (ep & 0x80) {
+ ep_info->ep_type = g_usbd_core[busid].tx_msg[ep & 0x7f].ep_type;
+ ep_info->ep_mult = g_usbd_core[busid].tx_msg[ep & 0x7f].ep_mult;
+ ep_info->ep_mps = g_usbd_core[busid].tx_msg[ep & 0x7f].ep_mps;
+ ep_info->ep_interval = g_usbd_core[busid].tx_msg[ep & 0x7f].ep_interval;
+ ep_info->ep_maxburst = g_usbd_core[busid].tx_msg[ep & 0x7f].ep_maxburst;
+ ep_info->ep_maxstream = g_usbd_core[busid].tx_msg[ep & 0x7f].ep_maxstream;
+ } else {
+ ep_info->ep_type = g_usbd_core[busid].rx_msg[ep & 0x7f].ep_type;
+ ep_info->ep_mult = g_usbd_core[busid].rx_msg[ep & 0x7f].ep_mult;
+ ep_info->ep_mps = g_usbd_core[busid].rx_msg[ep & 0x7f].ep_mps;
+ ep_info->ep_interval = g_usbd_core[busid].rx_msg[ep & 0x7f].ep_interval;
+ ep_info->ep_maxburst = g_usbd_core[busid].rx_msg[ep & 0x7f].ep_maxburst;
+ ep_info->ep_maxstream = g_usbd_core[busid].rx_msg[ep & 0x7f].ep_maxstream;
+ }
+ return 0;
+}
+
bool usb_device_is_configured(uint8_t busid)
{
return g_usbd_core[busid].configuration;
@@ -1346,20 +1513,21 @@ int usbd_initialize(uint8_t busid, uintptr_t reg_base, void (*event_handler)(uin
USB_ASSERT_MSG(busid < CONFIG_USBDEV_MAX_BUS, "bus overflow\r\n");
bus = &g_usbdev_bus[busid];
+ bus->busid = busid;
bus->reg_base = reg_base;
+#if defined(CONFIG_USBDEV_MULT_DC)
+ USB_ASSERT_MSG(g_usbdev_bus[busid].driver != NULL, "usb dc driver is not registered");
+#endif
#ifdef CONFIG_USBDEV_EP0_THREAD
g_usbd_core[busid].usbd_ep0_mq = usb_osal_mq_create(1);
if (g_usbd_core[busid].usbd_ep0_mq == NULL) {
- USB_LOG_ERR("No memory to alloc for g_usbd_core[busid].usbd_ep0_mq\r\n");
- while (1) {
- }
+ return -USB_ERR_NOMEM;
}
g_usbd_core[busid].usbd_ep0_thread = usb_osal_thread_create("usbd_ep0", CONFIG_USBDEV_EP0_STACKSIZE, CONFIG_USBDEV_EP0_PRIO, usbdev_ep0_thread, (void *)(uint32_t)busid);
if (g_usbd_core[busid].usbd_ep0_thread == NULL) {
- USB_LOG_ERR("No memory to alloc for g_usbd_core[busid].usbd_ep0_thread\r\n");
- while (1) {
- }
+ usb_osal_mq_delete(g_usbd_core[busid].usbd_ep0_mq);
+ return -USB_ERR_NOMEM;
}
#endif
@@ -1374,6 +1542,10 @@ int usbd_deinitialize(uint8_t busid)
{
USB_ASSERT_MSG(busid < CONFIG_USBDEV_MAX_BUS, "bus overflow\r\n");
+#if defined(CONFIG_USBDEV_MULT_DC)
+ USB_ASSERT_MSG(g_usbdev_bus[busid].driver != NULL, "usb dc driver is not registered");
+#endif
+
usb_dc_deinit(busid);
#ifdef CONFIG_USBDEV_EP0_THREAD
if (g_usbd_core[busid].usbd_ep0_thread) {
@@ -1387,3 +1559,256 @@ int usbd_deinitialize(uint8_t busid)
usbd_class_event_notify_handler(busid, USBD_EVENT_DEINIT, NULL);
return 0;
}
+
+#if !defined(CONFIG_USBDEV_MULT_DC)
+__WEAK int usbd_ep_open_extra(uint8_t busid, const struct usb_endpoint_descriptor *ep, const struct usb_endpoint_companion_descriptor *ep_comp)
+{
+ (void)busid;
+ (void)ep;
+ (void)ep_comp;
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_USBDEV_MULT_DC)
+void usbd_register_dc_driver(uint8_t busid, const struct usbd_dc_driver *driver)
+{
+ struct usbd_bus *bus;
+
+ USB_ASSERT_MSG(busid < CONFIG_USBDEV_MAX_BUS, "bus overflow\r\n");
+ USB_ASSERT_MSG(driver != NULL, "dc driver driver is NULL\r\n");
+
+ bus = &g_usbdev_bus[busid];
+
+ memset(bus, 0, sizeof(struct usbd_bus));
+ bus->busid = busid;
+ bus->driver = driver;
+}
+
+int usb_dc_init(uint8_t busid)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->init) {
+ return bus->driver->init(busid);
+ }
+ return -USB_ERR_INVAL;
+}
+
+int usb_dc_deinit(uint8_t busid)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->deinit) {
+ return bus->driver->deinit(busid);
+ }
+ return -USB_ERR_INVAL;
+}
+
+int usbd_set_address(uint8_t busid, const uint8_t addr)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->set_address) {
+ return bus->driver->set_address(busid, addr);
+ }
+ return -USB_ERR_INVAL;
+}
+
+int usbd_set_remote_wakeup(uint8_t busid)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->set_remote_wakeup) {
+ return bus->driver->set_remote_wakeup(busid);
+ }
+ return -USB_ERR_INVAL;
+}
+
+uint8_t usbd_get_port_speed(uint8_t busid)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->get_port_speed) {
+ return bus->driver->get_port_speed(busid);
+ }
+ return USB_SPEED_UNKNOWN;
+}
+
+int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->ep_open) {
+ return bus->driver->ep_open(busid, ep);
+ }
+ return -USB_ERR_INVAL;
+}
+
+int usbd_ep_open_extra(uint8_t busid, const struct usb_endpoint_descriptor *ep, const struct usb_endpoint_companion_descriptor *ep_comp)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->ep_open_extra) {
+ return bus->driver->ep_open_extra(busid, ep, ep_comp);
+ }
+ return -USB_ERR_INVAL;
+}
+
+int usbd_ep_close(uint8_t busid, const uint8_t ep)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->ep_close) {
+ return bus->driver->ep_close(busid, ep);
+ }
+ return -USB_ERR_INVAL;
+}
+
+int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->ep_set_stall) {
+ return bus->driver->ep_set_stall(busid, ep);
+ }
+ return -USB_ERR_INVAL;
+}
+
+int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->ep_clear_stall) {
+ return bus->driver->ep_clear_stall(busid, ep);
+ }
+ return -USB_ERR_INVAL;
+}
+
+int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->ep_is_stalled) {
+ return bus->driver->ep_is_stalled(busid, ep, stalled);
+ }
+ return -USB_ERR_INVAL;
+}
+
+int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->ep_start_write) {
+ return bus->driver->ep_start_write(busid, ep, data, data_len);
+ }
+ return -USB_ERR_INVAL;
+}
+
+int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return -USB_ERR_INVAL;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->ep_start_read) {
+ return bus->driver->ep_start_read(busid, ep, data, data_len);
+ }
+ return -USB_ERR_INVAL;
+}
+
+void USBD_IRQHandler(uint8_t busid)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->irq_handler) {
+ return bus->driver->irq_handler(busid);
+ }
+}
+
+#ifdef CONFIG_USBDEV_TEST_MODE
+void usbd_execute_test_mode(uint8_t busid, uint8_t test_mode)
+{
+ struct usbd_bus *bus;
+
+ if (busid >= CONFIG_USBDEV_MAX_BUS) {
+ return;
+ }
+
+ bus = &g_usbdev_bus[busid];
+ if (bus->driver && bus->driver->execute_test_mode) {
+ return bus->driver->execute_test_mode(busid, test_mode);
+ }
+}
+#endif
+
+#endif
diff --git a/core/usbd_core.h b/core/usbd_core.h
index ac9c58f1..4a2f5f2f 100644
--- a/core/usbd_core.h
+++ b/core/usbd_core.h
@@ -44,6 +44,10 @@ enum usbd_event_type {
USBD_EVENT_SET_INTERFACE, /** USB interface selected */
USBD_EVENT_SET_REMOTE_WAKEUP, /** USB set remote wakeup */
USBD_EVENT_CLR_REMOTE_WAKEUP, /** USB clear remote wakeup */
+ USBD_EVENT_SET_U1_ENABLE, /** USB U1 enable */
+ USBD_EVENT_SET_U2_ENABLE, /** USB U2 enable */
+ USBD_EVENT_CLR_U1_ENABLE, /** USB U1 disable */
+ USBD_EVENT_CLR_U2_ENABLE, /** USB U2 disable */
USBD_EVENT_INIT, /** USB init done when call usbd_initialize */
USBD_EVENT_DEINIT, /** USB deinit done when call usbd_deinitialize */
USBD_EVENT_UNKNOWN
@@ -60,6 +64,15 @@ typedef void (*usbd_endpoint_callback)(uint8_t busid, uint8_t ep, uint32_t nbyte
typedef void (*usbd_notify_handler)(uint8_t busid, uint8_t event, void *arg);
typedef void (*usbd_event_handler_t)(uint8_t busid, uint8_t event);
+struct usbd_endpoint_info {
+ uint8_t ep_type;
+ uint8_t ep_mult;
+ uint16_t ep_mps;
+ uint8_t ep_interval;
+ uint8_t ep_maxburst;
+ uint8_t ep_maxstream;
+};
+
struct usbd_endpoint {
uint8_t ep_addr;
usbd_endpoint_callback ep_cb;
@@ -90,6 +103,9 @@ struct usb_descriptor {
struct usbd_bus {
uint8_t busid;
uintptr_t reg_base;
+#if defined(CONFIG_USBDEV_MULT_DC)
+ const struct usbd_dc_driver *driver;
+#endif
};
extern struct usbd_bus g_usbdev_bus[];
@@ -103,13 +119,18 @@ void usbd_desc_register(uint8_t busid, const struct usb_descriptor *desc);
void usbd_add_interface(uint8_t busid, struct usbd_interface *intf);
void usbd_add_endpoint(uint8_t busid, struct usbd_endpoint *ep);
+uint8_t usbd_get_device_speed(uint8_t busid);
uint16_t usbd_get_ep_mps(uint8_t busid, uint8_t ep);
uint8_t usbd_get_ep_mult(uint8_t busid, uint8_t ep);
+int usbd_get_ep_info(uint8_t busid, uint8_t ep, struct usbd_endpoint_info *ep_info);
bool usb_device_is_configured(uint8_t busid);
bool usb_device_is_suspend(uint8_t busid);
int usbd_send_remote_wakeup(uint8_t busid);
uint8_t usbd_get_ep0_next_state(uint8_t busid);
+#if defined(CONFIG_USBDEV_MULT_DC)
+void usbd_register_dc_driver(uint8_t busid, const struct usbd_dc_driver *driver);
+#endif
int usbd_initialize(uint8_t busid, uintptr_t reg_base, usbd_event_handler_t event_handler);
int usbd_deinitialize(uint8_t busid);
diff --git a/core/usbh_core.c b/core/usbh_core.c
index b7f762ea..ba00d8f8 100644
--- a/core/usbh_core.c
+++ b/core/usbh_core.c
@@ -242,7 +242,7 @@ static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_config
return -USB_ERR_NOMEM;
}
- if (cur_ep_num >= CONFIG_USBHOST_MAX_ENDPOINTS) {
+ if (cur_ep_num > CONFIG_USBHOST_MAX_ENDPOINTS) {
USB_LOG_ERR("Endpoint num %d overflow\r\n", cur_ep_num);
return -USB_ERR_NOMEM;
}
@@ -272,6 +272,12 @@ static int parse_config_descriptor(struct usbh_hubport *hport, struct usb_config
return -USB_ERR_INVAL;
}
ep_desc = (struct usb_endpoint_descriptor *)p;
+
+ if (cur_ep >= CONFIG_USBHOST_MAX_ENDPOINTS) {
+ USB_LOG_ERR("Endpoint num %d overflow\r\n", cur_ep);
+ return -USB_ERR_NOMEM;
+ }
+
memcpy(&hport->config.intf[cur_iface].altsetting[cur_alt_setting].ep[cur_ep].ep_desc, ep_desc, 7);
cur_ep++;
break;
@@ -360,7 +366,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wLength = 8;
ret = usbh_control_transfer(hport, setup, ep0_request_buffer[hport->bus->busid]);
- if (ret < 0) {
+ if (ret < 8) {
USB_LOG_ERR("Failed to get device descriptor,errorcode:%d\r\n", ret);
goto errout;
}
@@ -420,7 +426,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wLength = USB_SIZEOF_DEVICE_DESC;
ret = usbh_control_transfer(hport, setup, ep0_request_buffer[hport->bus->busid]);
- if (ret < 0) {
+ if (ret < USB_SIZEOF_DEVICE_DESC) {
USB_LOG_ERR("Failed to get full device descriptor,errorcode:%d\r\n", ret);
goto errout;
}
@@ -444,7 +450,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wLength = USB_SIZEOF_CONFIG_DESC;
ret = usbh_control_transfer(hport, setup, ep0_request_buffer[hport->bus->busid]);
- if (ret < 0) {
+ if (ret < USB_SIZEOF_CONFIG_DESC) {
USB_LOG_ERR("Failed to get config descriptor,errorcode:%d\r\n", ret);
goto errout;
}
@@ -471,7 +477,7 @@ int usbh_enumerate(struct usbh_hubport *hport)
setup->wLength = wTotalLength;
ret = usbh_control_transfer(hport, setup, ep0_request_buffer[hport->bus->busid]);
- if (ret < 0) {
+ if (ret < wTotalLength) {
USB_LOG_ERR("Failed to get full config descriptor,errorcode:%d\r\n", ret);
goto errout;
}
@@ -628,11 +634,18 @@ void usbh_hubport_release(struct usbh_hubport *hport)
static void usbh_bus_init(struct usbh_bus *bus, uint8_t busid, uintptr_t reg_base)
{
+#if defined(CONFIG_USBHOST_MULT_HC)
+ const struct usbh_hc_driver *hc_driver = bus->hc_driver;
+ USB_ASSERT_MSG(hc_driver != NULL, "usb hc driver is not registered");
+#endif
+
memset(bus, 0, sizeof(struct usbh_bus));
bus->busid = busid;
bus->hcd.hcd_id = busid;
bus->hcd.reg_base = reg_base;
-
+#if defined(CONFIG_USBHOST_MULT_HC)
+ bus->hc_driver = hc_driver;
+#endif
/* devaddr 1 is for roothub */
bus->devgen.last = 0x7f;
@@ -680,6 +693,9 @@ int usbh_deinitialize(uint8_t busid)
USB_ASSERT_MSG(busid < CONFIG_USBHOST_MAX_BUS, "bus overflow\r\n");
bus = &g_usbhost_bus[busid];
+#if defined(CONFIG_USBHOST_MULT_HC)
+ USB_ASSERT_MSG(bus->hc_driver != NULL, "usb hc driver is not registered");
+#endif
usbh_hub_deinitialize(bus);
@@ -715,7 +731,7 @@ resubmit:
ret = urb->actual_length;
}
- if (ret < 0 && (ret != -USB_ERR_TIMEOUT)) {
+ if (ret < (int)sizeof(struct usb_setup_packet) && (ret != -USB_ERR_TIMEOUT)) {
retry--;
if (retry > 0) {
USB_LOG_WRN("Control transfer failed, errorcode %d, retrying...\r\n", ret);
@@ -724,7 +740,7 @@ resubmit:
}
usb_osal_mutex_give(hport->mutex);
- return ret;
+ return ret < (int)sizeof(struct usb_setup_packet) ? ret : (ret - (int)sizeof(struct usb_setup_packet));
}
int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *output, uint16_t output_len)
@@ -753,6 +769,13 @@ int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *out
dst = output;
len = src[0];
+ if (ret != len) {
+ USB_LOG_ERR("Get string descriptor failed, expect %d, actual %d\r\n", len, ret);
+ return -USB_ERR_IO;
+ }
+
+ memset(output, 0, output_len);
+
if (((len - 2) / 2) > output_len) {
return -USB_ERR_NOMEM;
}
@@ -1236,3 +1259,76 @@ __WEAK uint8_t usbh_get_hport_active_config_index(struct usbh_hubport *hport)
return 0; // Default to configuration index 0
}
+
+#if defined(CONFIG_USBHOST_MULT_HC)
+void usbh_register_hc_driver(uint8_t busid, const struct usbh_hc_driver *driver)
+{
+ USB_ASSERT_MSG(busid < CONFIG_USBHOST_MAX_BUS, "bus overflow\r\n");
+ USB_ASSERT_MSG(driver != NULL, "hc driver driver is NULL\r\n");
+
+ g_usbhost_bus[busid].hc_driver = driver;
+}
+
+int usb_hc_init(struct usbh_bus *bus)
+{
+ if (bus && bus->hc_driver && bus->hc_driver->init) {
+ return bus->hc_driver->init(bus);
+ } else {
+ return -USB_ERR_INVAL;
+ }
+}
+
+int usb_hc_deinit(struct usbh_bus *bus)
+{
+ if (bus && bus->hc_driver && bus->hc_driver->deinit) {
+ return bus->hc_driver->deinit(bus);
+ } else {
+ return -USB_ERR_INVAL;
+ }
+}
+
+uint16_t usbh_get_frame_number(struct usbh_bus *bus)
+{
+ if (bus && bus->hc_driver && bus->hc_driver->get_frame_number) {
+ return bus->hc_driver->get_frame_number(bus);
+ } else {
+ return 0;
+ }
+}
+
+int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf)
+{
+ if (bus && bus->hc_driver && bus->hc_driver->roothub_control) {
+ return bus->hc_driver->roothub_control(bus, setup, buf);
+ } else {
+ return -USB_ERR_INVAL;
+ }
+}
+
+int usbh_submit_urb(struct usbh_urb *urb)
+{
+ if (urb && urb->hport && urb->hport->bus && urb->hport->bus->hc_driver && urb->hport->bus->hc_driver->submit_urb) {
+ return urb->hport->bus->hc_driver->submit_urb(urb);
+ } else {
+ return -USB_ERR_INVAL;
+ }
+}
+
+int usbh_kill_urb(struct usbh_urb *urb)
+{
+ if (urb && urb->hport && urb->hport->bus && urb->hport->bus->hc_driver && urb->hport->bus->hc_driver->kill_urb) {
+ return urb->hport->bus->hc_driver->kill_urb(urb);
+ } else {
+ return -USB_ERR_INVAL;
+ }
+}
+
+void USBH_IRQHandler(uint8_t busid)
+{
+ USB_ASSERT_MSG(busid < CONFIG_USBHOST_MAX_BUS, "bus overflow\r\n");
+
+ if (g_usbhost_bus[busid].hc_driver && g_usbhost_bus[busid].hc_driver->irq_handler) {
+ g_usbhost_bus[busid].hc_driver->irq_handler(busid);
+ }
+}
+#endif
diff --git a/core/usbh_core.h b/core/usbh_core.h
index abd193df..c6c891f6 100644
--- a/core/usbh_core.h
+++ b/core/usbh_core.h
@@ -107,6 +107,7 @@ struct usbh_class_info {
struct usbh_hubport;
struct usbh_class_driver {
const char *driver_name;
+ const char *driver_desc;
int (*connect)(struct usbh_hubport *hport, uint8_t intf);
int (*disconnect)(struct usbh_hubport *hport, uint8_t intf);
};
@@ -205,6 +206,9 @@ struct usbh_bus {
usb_osal_mq_t hub_mq;
usb_osal_sem_t hub_sem;
usbh_event_handler_t event_handler;
+#if defined(CONFIG_USBHOST_MULT_HC)
+ const struct usbh_hc_driver *hc_driver;
+#endif
};
static inline void usbh_control_urb_fill(struct usbh_urb *urb,
@@ -311,6 +315,9 @@ int usbh_get_string_desc(struct usbh_hubport *hport, uint8_t index, uint8_t *out
*/
int usbh_set_interface(struct usbh_hubport *hport, uint8_t intf, uint8_t altsetting);
+#if defined(CONFIG_USBHOST_MULT_HC)
+void usbh_register_hc_driver(uint8_t busid, const struct usbh_hc_driver *driver);
+#endif
int usbh_initialize(uint8_t busid, uintptr_t reg_base, usbh_event_handler_t event_handler);
int usbh_deinitialize(uint8_t busid);
void *usbh_find_class_instance(const char *devname);
diff --git a/core/usbotg_core.c b/core/usbotg_core.c
index 54237e69..cf83f53a 100644
--- a/core/usbotg_core.c
+++ b/core/usbotg_core.c
@@ -88,17 +88,14 @@ int usbotg_initialize(uint8_t busid, uint32_t reg_base, usbd_event_handler_t dev
g_usbotg_core[busid].change_sem = usb_osal_sem_create(0);
if (g_usbotg_core[busid].change_sem == NULL) {
- USB_LOG_ERR("Failed to create change_sem\r\n");
- while (1) {
- }
+ return -USB_ERR_NOMEM;
}
snprintf(thread_name, 32, "usbotg%u", busid);
g_usbotg_core[busid].change_thread = usb_osal_thread_create(thread_name, 2048, 10, usbotg_rolechange_thread, (void *)(uintptr_t)busid);
if (g_usbotg_core[busid].change_thread == NULL) {
- USB_LOG_ERR("Failed to create usbotg thread\r\n");
- while (1) {
- }
+ usb_osal_sem_delete(g_usbotg_core[busid].change_sem);
+ return -USB_ERR_NOMEM;
}
usbotg_trigger_role_change(busid, default_role);
diff --git a/demo/adb/usbd_adb_template.c b/demo/adb_template.c
index acce1e35..871d41a7 100644
--- a/demo/adb/usbd_adb_template.c
+++ b/demo/adb_template.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, sakumisu
+ * Copyright (c) 2024 ~ 2026, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -18,12 +18,6 @@
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + 9 + 7 + 7)
-#ifdef CONFIG_USB_HS
-#define WINUSB_MAX_MPS 512
-#else
-#define WINUSB_MAX_MPS 64
-#endif
-
#define WCID_VENDOR_CODE 0x17
#define ADB_INTF_NUM 0
@@ -112,25 +106,28 @@ static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0100, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ ADB_DESCRIPTOR_INIT(ADB_INTF_NUM, WINUSB_IN_EP, WINUSB_OUT_EP, USB_BULK_EP_MPS_HS)
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
- ADB_DESCRIPTOR_INIT(ADB_INTF_NUM, WINUSB_IN_EP, WINUSB_OUT_EP, WINUSB_MAX_MPS)
+ ADB_DESCRIPTOR_INIT(ADB_INTF_NUM, WINUSB_IN_EP, WINUSB_OUT_EP, USB_BULK_EP_MPS_FS)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ ADB_DESCRIPTOR_INIT(ADB_INTF_NUM, WINUSB_IN_EP, WINUSB_OUT_EP, USB_BULK_EP_MPS_FS)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ ADB_DESCRIPTOR_INIT(ADB_INTF_NUM, WINUSB_IN_EP, WINUSB_OUT_EP, USB_BULK_EP_MPS_HS)
};
static const char *string_descriptors[] = {
@@ -142,21 +139,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -167,6 +187,7 @@ const struct usb_descriptor adb_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback,
.msosv1_descriptor = &msosv1_desc
};
@@ -199,27 +220,8 @@ static void usbd_event_handler(uint8_t busid, uint8_t event)
static struct usbd_interface intf0;
-#ifdef RT_USING_MSH
-extern void usbd_adb_shell_init(uint8_t in_ep, uint8_t out_ep);
-#else
-extern int shell_init(bool need_login);
-#endif
void cherryadb_init(uint8_t busid, uint32_t reg_base)
{
-#ifdef RT_USING_MSH
- usbd_adb_shell_init(WINUSB_IN_EP, WINUSB_OUT_EP);
-#else
- /* default password is : 12345678 */
- /* shell_init() must be called in-task */
- if (0 != shell_init(false)) {
- /* shell failed to be initialized */
- USB_LOG_RAW("Failed to initialize shell\r\n");
- for (;;) {
- ;
- }
- }
-#endif
-
usbd_desc_register(busid, &adb_descriptor);
usbd_add_interface(busid, usbd_adb_init_intf(busid, &intf0, WINUSB_IN_EP, WINUSB_OUT_EP));
diff --git a/demo/audio_v1_mic_multichan_template.c b/demo/audio_v1_mic_multichan_template.c
index a7f71121..4f879b49 100644
--- a/demo/audio_v1_mic_multichan_template.c
+++ b/demo/audio_v1_mic_multichan_template.c
@@ -11,11 +11,8 @@
#define USBD_MAX_POWER 100
#define USBD_LANGID_STRING 1033
-#ifdef CONFIG_USB_HS
-#define EP_INTERVAL 0x04
-#else
-#define EP_INTERVAL 0x01
-#endif
+#define EP_INTERVAL_FS 0x01
+#define EP_INTERVAL_HS 0x04
#define AUDIO_IN_EP 0x81
@@ -73,29 +70,44 @@ static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, 0x00, 0x01),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, IN_CHANNEL_NUM, INPUT_CH_ENABLE),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x01, 0x01, INPUT_CTRL),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID),
+ AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET, EP_INTERVAL_HS, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ))
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, 0x00, 0x01),
AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, IN_CHANNEL_NUM, INPUT_CH_ENABLE),
AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x01, 0x01, INPUT_CTRL),
AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID),
- AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET, EP_INTERVAL, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ))
+ AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET, EP_INTERVAL_FS, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ))
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, 0x00, 0x01),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, IN_CHANNEL_NUM, INPUT_CH_ENABLE),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x01, 0x01, INPUT_CTRL),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID),
+ AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET, EP_INTERVAL_FS, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ))
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, 0x00, 0x01),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, IN_CHANNEL_NUM, INPUT_CH_ENABLE),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x01, 0x01, INPUT_CTRL),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID),
+ AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET, EP_INTERVAL_HS, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ))
};
static const char *string_descriptors[] = {
@@ -107,21 +119,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -132,12 +167,14 @@ const struct usb_descriptor audio_v1_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
volatile bool tx_flag = 0;
volatile bool ep_tx_busy_flag = false;
volatile uint32_t s_mic_sample_rate;
+volatile float s_mic_volume_db;
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
@@ -198,6 +235,21 @@ uint32_t usbd_audio_get_sampling_freq(uint8_t busid, uint8_t ep)
return freq;
}
+void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, float volume_db)
+{
+ if (ep == AUDIO_IN_EP) {
+ s_mic_volume_db = volume_db;
+ }
+}
+
+float usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch)
+{
+ if (ep == AUDIO_IN_EP) {
+ return s_mic_volume_db;
+ }
+ return 0;
+}
+
void usbd_audio_iso_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
diff --git a/demo/audio_v1_mic_speaker_multichan_template.c b/demo/audio_v1_mic_speaker_multichan_template.c
index b1f15a8e..a547fc60 100644
--- a/demo/audio_v1_mic_speaker_multichan_template.c
+++ b/demo/audio_v1_mic_speaker_multichan_template.c
@@ -13,13 +13,10 @@
#define USBD_MAX_POWER 100
#define USBD_LANGID_STRING 1033
-#ifdef CONFIG_USB_HS
-#define EP_INTERVAL 0x04
-#define FEEDBACK_ENDP_PACKET_SIZE 0x04
-#else
-#define EP_INTERVAL 0x01
+#define EP_INTERVAL_FS 0x01
+#define EP_INTERVAL_HS 0x04
+
#define FEEDBACK_ENDP_PACKET_SIZE 0x03
-#endif
#define AUDIO_IN_EP 0x81
#define AUDIO_OUT_EP 0x02
@@ -135,7 +132,7 @@ static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x03, AUDIO_AC_SIZ, 0x00, 0x01, 0x02),
AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, IN_CHANNEL_NUM, INPUT_CH_ENABLE),
@@ -145,30 +142,78 @@ static const uint8_t config_descriptor[] = {
AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x04, 0x01, OUTPUT_CTRL),
AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID),
AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET,
- EP_INTERVAL, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ)),
+ EP_INTERVAL_HS, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ)),
#if USING_FEEDBACK == 0
AUDIO_AS_DESCRIPTOR_INIT(0x02, 0x04, OUT_CHANNEL_NUM, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET,
- EP_INTERVAL, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
+ EP_INTERVAL_HS, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
#else
AUDIO_AS_FEEDBACK_DESCRIPTOR_INIT(0x02, 0x04, OUT_CHANNEL_NUM, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, AUDIO_OUT_PACKET,
- EP_INTERVAL, AUDIO_OUT_FEEDBACK_EP, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
+ EP_INTERVAL_HS, AUDIO_OUT_FEEDBACK_EP, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
+#endif
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x03, AUDIO_AC_SIZ, 0x00, 0x01, 0x02),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, IN_CHANNEL_NUM, INPUT_CH_ENABLE),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x01, 0x01, INPUT_CTRL),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x04, 0x01, OUTPUT_CTRL),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID),
+ AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET,
+ EP_INTERVAL_FS, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ)),
+#if USING_FEEDBACK == 0
+ AUDIO_AS_DESCRIPTOR_INIT(0x02, 0x04, OUT_CHANNEL_NUM, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET,
+ EP_INTERVAL_FS, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
+#else
+ AUDIO_AS_FEEDBACK_DESCRIPTOR_INIT(0x02, 0x04, OUT_CHANNEL_NUM, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, AUDIO_OUT_PACKET,
+ EP_INTERVAL_FS, AUDIO_OUT_FEEDBACK_EP, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
#endif
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x03, AUDIO_AC_SIZ, 0x00, 0x01, 0x02),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, IN_CHANNEL_NUM, INPUT_CH_ENABLE),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x01, 0x01, INPUT_CTRL),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x04, 0x01, OUTPUT_CTRL),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID),
+ AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET,
+ EP_INTERVAL_FS, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ)),
+#if USING_FEEDBACK == 0
+ AUDIO_AS_DESCRIPTOR_INIT(0x02, 0x04, OUT_CHANNEL_NUM, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET,
+ EP_INTERVAL_FS, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
+#else
+ AUDIO_AS_FEEDBACK_DESCRIPTOR_INIT(0x02, 0x04, OUT_CHANNEL_NUM, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, AUDIO_OUT_PACKET,
+ EP_INTERVAL_FS, AUDIO_OUT_FEEDBACK_EP, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
+#endif
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x03, AUDIO_AC_SIZ, 0x00, 0x01, 0x02),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, IN_CHANNEL_NUM, INPUT_CH_ENABLE),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x01, 0x01, INPUT_CTRL),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x04, 0x01, OUTPUT_CTRL),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID),
+ AUDIO_AS_DESCRIPTOR_INIT(0x01, 0x03, IN_CHANNEL_NUM, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET,
+ EP_INTERVAL_HS, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ)),
+#if USING_FEEDBACK == 0
+ AUDIO_AS_DESCRIPTOR_INIT(0x02, 0x04, OUT_CHANNEL_NUM, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET,
+ EP_INTERVAL_HS, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
+#else
+ AUDIO_AS_FEEDBACK_DESCRIPTOR_INIT(0x02, 0x04, OUT_CHANNEL_NUM, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, AUDIO_OUT_PACKET,
+ EP_INTERVAL_HS, AUDIO_OUT_FEEDBACK_EP, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
+#endif
};
static const char *string_descriptors[] = {
@@ -180,21 +225,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -205,6 +273,7 @@ const struct usb_descriptor audio_v1_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
@@ -217,6 +286,9 @@ volatile bool rx_flag = 0;
volatile bool ep_tx_busy_flag = false;
volatile uint32_t s_mic_sample_rate;
volatile uint32_t s_speaker_sample_rate;
+volatile float s_mic_volume_db;
+volatile float s_speaker_volume_db;
+
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
@@ -298,6 +370,25 @@ uint32_t usbd_audio_get_sampling_freq(uint8_t busid, uint8_t ep)
return freq;
}
+void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, float volume_db)
+{
+ if (ep == AUDIO_IN_EP) {
+ s_mic_volume_db = volume_db;
+ } else if (ep == AUDIO_OUT_EP) {
+ s_speaker_volume_db = volume_db;
+ }
+}
+
+float usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch)
+{
+ if (ep == AUDIO_IN_EP) {
+ return s_mic_volume_db;
+ } else if (ep == AUDIO_OUT_EP) {
+ return s_speaker_volume_db;
+ }
+ return 0;
+}
+
void usbd_audio_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
diff --git a/demo/audio_v2_mic_multichan_template.c b/demo/audio_v2_mic_multichan_template.c
index 4fd156f7..cd6d8fb8 100644
--- a/demo/audio_v2_mic_multichan_template.c
+++ b/demo/audio_v2_mic_multichan_template.c
@@ -11,11 +11,8 @@
#define USBD_MAX_POWER 100
#define USBD_LANGID_STRING 1033
-#ifdef CONFIG_USB_HS
-#define EP_INTERVAL 0x04
-#else
-#define EP_INTERVAL 0x01
-#endif
+#define EP_INTERVAL_FS 0x01
+#define EP_INTERVAL_HS 0x04
#define AUDIO_IN_EP 0x81
@@ -76,30 +73,48 @@ static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, AUDIO_CATEGORY_MICROPHONE, 0x00, 0x00),
AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_IN_CLOCK_ID, 0x03, 0x03),
AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_INTERM_MIC, AUDIO_IN_CLOCK_ID, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x02, INPUT_CTRL),
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID, AUDIO_IN_CLOCK_ID, 0x0000),
- AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x04, IN_CHANNEL_NUM, INPUT_CH_ENABLE, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL)
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x04, IN_CHANNEL_NUM, INPUT_CH_ENABLE, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL_HS)
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, AUDIO_CATEGORY_MICROPHONE, 0x00, 0x00),
+ AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_IN_CLOCK_ID, 0x03, 0x03),
+ AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_INTERM_MIC, AUDIO_IN_CLOCK_ID, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
+ AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x02, INPUT_CTRL),
+ AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID, AUDIO_IN_CLOCK_ID, 0x0000),
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x04, IN_CHANNEL_NUM, INPUT_CH_ENABLE, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL_FS)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, AUDIO_CATEGORY_MICROPHONE, 0x00, 0x00),
+ AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_IN_CLOCK_ID, 0x03, 0x03),
+ AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_INTERM_MIC, AUDIO_IN_CLOCK_ID, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
+ AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x02, INPUT_CTRL),
+ AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID, AUDIO_IN_CLOCK_ID, 0x0000),
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x04, IN_CHANNEL_NUM, INPUT_CH_ENABLE, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL_FS)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, AUDIO_CATEGORY_MICROPHONE, 0x00, 0x00),
+ AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_IN_CLOCK_ID, 0x03, 0x03),
+ AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_INTERM_MIC, AUDIO_IN_CLOCK_ID, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
+ AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x02, INPUT_CTRL),
+ AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID, AUDIO_IN_CLOCK_ID, 0x0000),
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x04, IN_CHANNEL_NUM, INPUT_CH_ENABLE, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL_HS)
};
static const char *string_descriptors[] = {
@@ -111,21 +126,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -136,6 +174,7 @@ const struct usb_descriptor audio_v2_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
@@ -163,6 +202,7 @@ USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[AUDIO_IN_PACKET];
volatile bool tx_flag = 0;
volatile bool ep_tx_busy_flag = false;
volatile uint32_t s_mic_sample_rate;
+volatile float s_mic_volume_db;
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
@@ -221,6 +261,21 @@ uint32_t usbd_audio_get_sampling_freq(uint8_t busid, uint8_t ep)
return freq;
}
+void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, float volume_db)
+{
+ if (ep == AUDIO_IN_EP) {
+ s_mic_volume_db = volume_db;
+ }
+}
+
+float usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch)
+{
+ if (ep == AUDIO_IN_EP) {
+ return s_mic_volume_db;
+ }
+ return 0;
+}
+
void usbd_audio_get_sampling_freq_table(uint8_t busid, uint8_t ep, uint8_t **sampling_freq_table)
{
if (ep == AUDIO_IN_EP) {
diff --git a/demo/audio_v2_mic_speaker_multichan_template.c b/demo/audio_v2_mic_speaker_multichan_template.c
index d7059033..8916c8a0 100644
--- a/demo/audio_v2_mic_speaker_multichan_template.c
+++ b/demo/audio_v2_mic_speaker_multichan_template.c
@@ -13,13 +13,9 @@
#define USBD_MAX_POWER 100
#define USBD_LANGID_STRING 1033
-#ifdef CONFIG_USB_HS
-#define EP_INTERVAL 0x04
+#define EP_INTERVAL_FS 0x01
+#define EP_INTERVAL_HS 0x04
#define FEEDBACK_ENDP_PACKET_SIZE 0x04
-#else
-#define EP_INTERVAL 0x01
-#define FEEDBACK_ENDP_PACKET_SIZE 0x04
-#endif
#define AUDIO_OUT_EP 0x02
#define AUDIO_IN_EP 0x81
@@ -142,7 +138,7 @@ static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x03, AUDIO_AC_SIZ, AUDIO_CATEGORY_UNDEF, 0x00, 0x00),
AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_OUT_CLOCK_ID, 0x03, 0x03),
@@ -154,27 +150,72 @@ static const uint8_t config_descriptor[] = {
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x06, INPUT_CTRL),
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x08, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID, AUDIO_IN_CLOCK_ID, 0x0000),
#if USING_FEEDBACK == 0
- AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL),
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL_HS),
#else
- AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL, AUDIO_OUT_FEEDBACK_EP),
+ AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL_HS, AUDIO_OUT_FEEDBACK_EP),
#endif
- AUDIO_V2_AS_DESCRIPTOR_INIT(0x02, 0x08, IN_CHANNEL_NUM, INPUT_CH_ENABLE, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL)
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x02, 0x08, IN_CHANNEL_NUM, INPUT_CH_ENABLE, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL_HS)
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x03, AUDIO_AC_SIZ, AUDIO_CATEGORY_UNDEF, 0x00, 0x00),
+ AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_OUT_CLOCK_ID, 0x03, 0x03),
+ AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_TERMINAL_STREAMING, AUDIO_OUT_CLOCK_ID, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, 0x0000),
+ AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x02, OUTPUT_CTRL),
+ AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID, AUDIO_OUT_CLOCK_ID, 0x0000),
+ AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_IN_CLOCK_ID, 0x03, 0x03),
+ AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_INTERM_MIC, AUDIO_IN_CLOCK_ID, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
+ AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x06, INPUT_CTRL),
+ AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x08, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID, AUDIO_IN_CLOCK_ID, 0x0000),
+#if USING_FEEDBACK == 0
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL_FS),
+#else
+ AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL_FS, AUDIO_OUT_FEEDBACK_EP),
+#endif
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x02, 0x08, IN_CHANNEL_NUM, INPUT_CH_ENABLE, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL_FS)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x03, AUDIO_AC_SIZ, AUDIO_CATEGORY_UNDEF, 0x00, 0x00),
+ AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_OUT_CLOCK_ID, 0x03, 0x03),
+ AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_TERMINAL_STREAMING, AUDIO_OUT_CLOCK_ID, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, 0x0000),
+ AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x02, OUTPUT_CTRL),
+ AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID, AUDIO_OUT_CLOCK_ID, 0x0000),
+ AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_IN_CLOCK_ID, 0x03, 0x03),
+ AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_INTERM_MIC, AUDIO_IN_CLOCK_ID, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
+ AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x06, INPUT_CTRL),
+ AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x08, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID, AUDIO_IN_CLOCK_ID, 0x0000),
+#if USING_FEEDBACK == 0
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL_FS),
+#else
+ AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL_FS, AUDIO_OUT_FEEDBACK_EP),
+#endif
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x02, 0x08, IN_CHANNEL_NUM, INPUT_CH_ENABLE, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL_FS)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x03, AUDIO_AC_SIZ, AUDIO_CATEGORY_UNDEF, 0x00, 0x00),
+ AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_OUT_CLOCK_ID, 0x03, 0x03),
+ AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_TERMINAL_STREAMING, AUDIO_OUT_CLOCK_ID, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, 0x0000),
+ AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x02, OUTPUT_CTRL),
+ AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID, AUDIO_OUT_CLOCK_ID, 0x0000),
+ AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_IN_CLOCK_ID, 0x03, 0x03),
+ AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_INTERM_MIC, AUDIO_IN_CLOCK_ID, IN_CHANNEL_NUM, INPUT_CH_ENABLE, 0x0000),
+ AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_IN_FU_ID, 0x06, INPUT_CTRL),
+ AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x08, AUDIO_TERMINAL_STREAMING, AUDIO_IN_FU_ID, AUDIO_IN_CLOCK_ID, 0x0000),
+#if USING_FEEDBACK == 0
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL_HS),
+#else
+ AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL_HS, AUDIO_OUT_FEEDBACK_EP),
+#endif
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x02, 0x08, IN_CHANNEL_NUM, INPUT_CH_ENABLE, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, (AUDIO_IN_PACKET + 4), EP_INTERVAL_HS)
};
static const char *string_descriptors[] = {
@@ -186,21 +227,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -211,6 +275,7 @@ const struct usb_descriptor audio_v2_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
@@ -260,6 +325,8 @@ volatile bool rx_flag = 0;
volatile bool ep_tx_busy_flag = false;
volatile uint32_t s_mic_sample_rate;
volatile uint32_t s_speaker_sample_rate;
+volatile float s_mic_volume_db;
+volatile float s_speaker_volume_db;
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
@@ -293,13 +360,13 @@ void usbd_audio_open(uint8_t busid, uint8_t intf)
/* setup first out ep read transfer */
usbd_ep_start_read(busid, AUDIO_OUT_EP, read_buffer, AUDIO_OUT_PACKET);
#if USING_FEEDBACK == 1
-#ifdef CONFIG_USB_HS
- uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_HS(AUDIO_FREQ);
- AUDIO_FEEDBACK_TO_BUF_HS(s_speaker_feedback_buffer, feedback_value);
-#else
- uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_FS(AUDIO_FREQ);
- AUDIO_FEEDBACK_TO_BUF_FS(s_speaker_feedback_buffer, feedback_value);
-#endif
+ if (usbd_get_device_speed(busid) == USB_SPEED_HIGH) {
+ uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_HS(AUDIO_FREQ);
+ AUDIO_FEEDBACK_TO_BUF_HS(s_speaker_feedback_buffer, feedback_value);
+ } else {
+ uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_FS(AUDIO_FREQ);
+ AUDIO_FEEDBACK_TO_BUF_FS(s_speaker_feedback_buffer, feedback_value);
+ }
usbd_ep_start_write(busid, AUDIO_OUT_FEEDBACK_EP, s_speaker_feedback_buffer, FEEDBACK_ENDP_PACKET_SIZE);
#endif
USB_LOG_RAW("OPEN1\r\n");
@@ -354,6 +421,25 @@ void usbd_audio_get_sampling_freq_table(uint8_t busid, uint8_t ep, uint8_t **sam
}
}
+void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, float volume_db)
+{
+ if (ep == AUDIO_IN_EP) {
+ s_mic_volume_db = volume_db;
+ } else if (ep == AUDIO_OUT_EP) {
+ s_speaker_volume_db = volume_db;
+ }
+}
+
+float usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch)
+{
+ if (ep == AUDIO_IN_EP) {
+ return s_mic_volume_db;
+ } else if (ep == AUDIO_OUT_EP) {
+ return s_speaker_volume_db;
+ }
+ return 0;
+}
+
void usbd_audio_iso_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
@@ -370,13 +456,13 @@ void usbd_audio_iso_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
void usbd_audio_iso_out_feedback_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual feedback len:%d\r\n", nbytes);
-#ifdef CONFIG_USB_HS
- uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_HS(s_speaker_sample_rate);
- AUDIO_FEEDBACK_TO_BUF_HS(s_speaker_feedback_buffer, feedback_value);
-#else
- uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_FS(s_speaker_sample_rate);
- AUDIO_FEEDBACK_TO_BUF_FS(s_speaker_feedback_buffer, feedback_value);
-#endif
+ if (usbd_get_device_speed(busid) == USB_SPEED_HIGH) {
+ uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_HS(AUDIO_FREQ);
+ AUDIO_FEEDBACK_TO_BUF_HS(s_speaker_feedback_buffer, feedback_value);
+ } else {
+ uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_FS(AUDIO_FREQ);
+ AUDIO_FEEDBACK_TO_BUF_FS(s_speaker_feedback_buffer, feedback_value);
+ }
usbd_ep_start_write(busid, AUDIO_OUT_FEEDBACK_EP, s_speaker_feedback_buffer, FEEDBACK_ENDP_PACKET_SIZE);
}
#endif
diff --git a/demo/audio_v2_speaker_multichan_template.c b/demo/audio_v2_speaker_multichan_template.c
index 52bda373..37e84d1f 100644
--- a/demo/audio_v2_speaker_multichan_template.c
+++ b/demo/audio_v2_speaker_multichan_template.c
@@ -13,13 +13,9 @@
#define USBD_MAX_POWER 100
#define USBD_LANGID_STRING 1033
-#ifdef CONFIG_USB_HS
-#define EP_INTERVAL 0x04
+#define EP_INTERVAL_FS 0x01
+#define EP_INTERVAL_HS 0x04
#define FEEDBACK_ENDP_PACKET_SIZE 0x04
-#else
-#define EP_INTERVAL 0x01
-#define FEEDBACK_ENDP_PACKET_SIZE 0x04
-#endif
#define AUDIO_OUT_EP 0x01
#define AUDIO_OUT_FEEDBACK_EP 0x82
@@ -91,7 +87,7 @@ static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, AUDIO_CATEGORY_SPEAKER, 0x00, 0x00),
AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_OUT_CLOCK_ID, 0x03, 0x03),
@@ -99,26 +95,56 @@ static const uint8_t config_descriptor[] = {
AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x02, OUTPUT_CTRL),
AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID, AUDIO_OUT_CLOCK_ID, 0x0000),
#if USING_FEEDBACK == 0
- AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL),
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL_HS),
#else
- AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, AUDIO_OUT_PACKET, EP_INTERVAL, AUDIO_OUT_FEEDBACK_EP),
+ AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, AUDIO_OUT_PACKET, EP_INTERVAL_HS, AUDIO_OUT_FEEDBACK_EP),
+#endif
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, AUDIO_CATEGORY_SPEAKER, 0x00, 0x00),
+ AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_OUT_CLOCK_ID, 0x03, 0x03),
+ AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_TERMINAL_STREAMING, AUDIO_OUT_CLOCK_ID, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, 0x0000),
+ AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x02, OUTPUT_CTRL),
+ AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID, AUDIO_OUT_CLOCK_ID, 0x0000),
+#if USING_FEEDBACK == 0
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL_FS),
+#else
+ AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, AUDIO_OUT_PACKET, EP_INTERVAL_FS, AUDIO_OUT_FEEDBACK_EP),
#endif
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, AUDIO_CATEGORY_SPEAKER, 0x00, 0x00),
+ AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_OUT_CLOCK_ID, 0x03, 0x03),
+ AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_TERMINAL_STREAMING, AUDIO_OUT_CLOCK_ID, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, 0x0000),
+ AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x02, OUTPUT_CTRL),
+ AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID, AUDIO_OUT_CLOCK_ID, 0x0000),
+#if USING_FEEDBACK == 0
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL_FS),
+#else
+ AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, AUDIO_OUT_PACKET, EP_INTERVAL_FS, AUDIO_OUT_FEEDBACK_EP),
+#endif
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_V2_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, AUDIO_CATEGORY_SPEAKER, 0x00, 0x00),
+ AUDIO_V2_AC_CLOCK_SOURCE_DESCRIPTOR_INIT(AUDIO_OUT_CLOCK_ID, 0x03, 0x03),
+ AUDIO_V2_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x02, AUDIO_TERMINAL_STREAMING, AUDIO_OUT_CLOCK_ID, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, 0x0000),
+ AUDIO_V2_AC_FEATURE_UNIT_DESCRIPTOR_INIT(AUDIO_OUT_FU_ID, 0x02, OUTPUT_CTRL),
+ AUDIO_V2_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_OUTTERM_SPEAKER, AUDIO_OUT_FU_ID, AUDIO_OUT_CLOCK_ID, 0x0000),
+#if USING_FEEDBACK == 0
+ AUDIO_V2_AS_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET, EP_INTERVAL_HS),
+#else
+ AUDIO_V2_AS_FEEDBACK_DESCRIPTOR_INIT(0x01, 0x02, OUT_CHANNEL_NUM, OUTPUT_CH_ENABLE, HALF_WORD_BYTES, SAMPLE_BITS, AUDIO_OUT_EP, AUDIO_OUT_PACKET, EP_INTERVAL_HS, AUDIO_OUT_FEEDBACK_EP),
+#endif
};
static const char *string_descriptors[] = {
@@ -130,21 +156,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -155,6 +204,7 @@ const struct usb_descriptor audio_v2_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
@@ -182,6 +232,7 @@ USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t s_speaker_feedback_buffer[4];
volatile bool rx_flag = 0;
volatile uint32_t s_speaker_sample_rate;
+volatile float s_speaker_volume_db;
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
@@ -214,13 +265,13 @@ void usbd_audio_open(uint8_t busid, uint8_t intf)
/* setup first out ep read transfer */
usbd_ep_start_read(busid, AUDIO_OUT_EP, read_buffer, AUDIO_OUT_PACKET);
#if USING_FEEDBACK == 1
-#ifdef CONFIG_USB_HS
- uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_HS(s_speaker_sample_rate);
- AUDIO_FEEDBACK_TO_BUF_HS(s_speaker_feedback_buffer, feedback_value);
-#else
- uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_FS(s_speaker_sample_rate);
- AUDIO_FEEDBACK_TO_BUF_FS(s_speaker_feedback_buffer, feedback_value);
-#endif
+ if (usbd_get_device_speed(busid) == USB_SPEED_HIGH) {
+ uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_HS(AUDIO_FREQ);
+ AUDIO_FEEDBACK_TO_BUF_HS(s_speaker_feedback_buffer, feedback_value);
+ } else {
+ uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_FS(AUDIO_FREQ);
+ AUDIO_FEEDBACK_TO_BUF_FS(s_speaker_feedback_buffer, feedback_value);
+ }
usbd_ep_start_write(busid, AUDIO_OUT_FEEDBACK_EP, s_speaker_feedback_buffer, FEEDBACK_ENDP_PACKET_SIZE);
#endif
USB_LOG_RAW("OPEN\r\n");
@@ -259,6 +310,21 @@ void usbd_audio_get_sampling_freq_table(uint8_t busid, uint8_t ep, uint8_t **sam
}
}
+void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, float volume_db)
+{
+ if (ep == AUDIO_OUT_EP) {
+ s_speaker_volume_db = volume_db;
+ }
+}
+
+float usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch)
+{
+ if (ep == AUDIO_OUT_EP) {
+ return s_speaker_volume_db;
+ }
+ return 0;
+}
+
void usbd_audio_iso_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
@@ -269,13 +335,13 @@ void usbd_audio_iso_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
void usbd_audio_iso_out_feedback_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual feedback len:%d\r\n", (unsigned int)nbytes);
-#ifdef CONFIG_USB_HS
- uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_HS(s_speaker_sample_rate);
- AUDIO_FEEDBACK_TO_BUF_HS(s_speaker_feedback_buffer, feedback_value);
-#else
- uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_FS(s_speaker_sample_rate);
- AUDIO_FEEDBACK_TO_BUF_FS(s_speaker_feedback_buffer, feedback_value);
-#endif
+ if (usbd_get_device_speed(busid) == USB_SPEED_HIGH) {
+ uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_HS(AUDIO_FREQ);
+ AUDIO_FEEDBACK_TO_BUF_HS(s_speaker_feedback_buffer, feedback_value);
+ } else {
+ uint32_t feedback_value = AUDIO_FREQ_TO_FEEDBACK_FS(AUDIO_FREQ);
+ AUDIO_FEEDBACK_TO_BUF_FS(s_speaker_feedback_buffer, feedback_value);
+ }
usbd_ep_start_write(busid, AUDIO_OUT_FEEDBACK_EP, s_speaker_feedback_buffer, FEEDBACK_ENDP_PACKET_SIZE);
}
#endif
diff --git a/demo/bootuf2/msc_bootuf2_template.c b/demo/bootuf2/msc_bootuf2_template.c
index 73dfe577..65a1d1c8 100644
--- a/demo/bootuf2/msc_bootuf2_template.c
+++ b/demo/bootuf2/msc_bootuf2_template.c
@@ -17,35 +17,32 @@
#define USB_CONFIG_SIZE (9 + MSC_DESCRIPTOR_LEN)
-#ifdef CONFIG_USB_HS
-#define MSC_MAX_MPS 512
-#else
-#define MSC_MAX_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
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)
+ MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_HS, 0x02)
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ 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, USB_BULK_EP_MPS_FS, 0x02)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_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, USB_BULK_EP_MPS_FS, 0x02)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_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, USB_BULK_EP_MPS_HS, 0x02)
};
static const char *string_descriptors[] = {
@@ -57,21 +54,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -82,6 +102,7 @@ const struct usb_descriptor msc_bootuf2_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
diff --git a/demo/cdc_acm_hid_msc_template.c b/demo/cdc_acm_hid_msc_template.c
index 93f3fb3b..da73b3da 100644
--- a/demo/cdc_acm_hid_msc_template.c
+++ b/demo/cdc_acm_hid_msc_template.c
@@ -19,7 +19,7 @@
/*!< endpoint address */
#define HID_INT_EP 0x86
#define HID_INT_EP_SIZE 4
-#define HID_INT_EP_INTERVAL 10
+#define HID_INT_EP_INTERVAL 1
#define USBD_VID 0xFFFF
#define USBD_PID 0xFFFF
@@ -31,43 +31,40 @@
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN + MSC_DESCRIPTOR_LEN + 25)
-#ifdef CONFIG_USB_HS
-#define CDC_MAX_MPS 512
-#else
-#define CDC_MAX_MPS 64
-#endif
-
-#ifdef CONFIG_USB_HS
-#define MSC_MAX_MPS 512
-#else
-#define MSC_MAX_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x04, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
+ MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
+ HID_MOUSE_DESCRIPTOR_INIT(0x03, 0x01, HID_MOUSE_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x04, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
- CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
- MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
+ MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
HID_MOUSE_DESCRIPTOR_INIT(0x03, 0x01, HID_MOUSE_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x04, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
+ MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
+ HID_MOUSE_DESCRIPTOR_INIT(0x03, 0x01, HID_MOUSE_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x04, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
+ MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
+ HID_MOUSE_DESCRIPTOR_INIT(0x03, 0x01, HID_MOUSE_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
};
static const char *string_descriptors[] = {
@@ -79,21 +76,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -104,6 +124,7 @@ const struct usb_descriptor cdc_acm_hid_msc_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
diff --git a/demo/cdc_acm_mavlink_template.c b/demo/cdc_acm_mavlink_template.c
index c680b7e8..f2de2eb1 100644
--- a/demo/cdc_acm_mavlink_template.c
+++ b/demo/cdc_acm_mavlink_template.c
@@ -21,35 +21,32 @@
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN)
-#ifdef CONFIG_USB_HS
-#define CDC_MAX_MPS 512
-#else
-#define CDC_MAX_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
- CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02)
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02)
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02)
};
static const char *string_descriptors[] = {
@@ -61,19 +58,40 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
@@ -86,6 +104,7 @@ const struct usb_descriptor cdc_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
diff --git a/demo/cdc_acm_msc_template.c b/demo/cdc_acm_msc_template.c
index e8dc06ca..27817f2c 100644
--- a/demo/cdc_acm_msc_template.c
+++ b/demo/cdc_acm_msc_template.c
@@ -23,42 +23,36 @@
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN + MSC_DESCRIPTOR_LEN)
-#ifdef CONFIG_USB_HS
-#define CDC_MAX_MPS 512
-#else
-#define CDC_MAX_MPS 64
-#endif
-
-#ifdef CONFIG_USB_HS
-#define MSC_MAX_MPS 512
-#else
-#define MSC_MAX_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
+ MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_HS, 0x00)
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
- CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
- MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, MSC_MAX_MPS, 0x00)
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
+ MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_FS, 0x00)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
+ MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_FS, 0x00)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x03, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
+ MSC_DESCRIPTOR_INIT(0x02, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_HS, 0x00)
};
static const char *string_descriptors[] = {
@@ -70,19 +64,40 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
@@ -95,10 +110,11 @@ const struct usb_descriptor cdc_msc_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
-USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048]; /* 2048 is only for test speed , please use CDC_MAX_MPS for common*/
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048]; /* 2048 is only for test speed , please use the max mps for common*/
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
volatile bool ep_tx_busy_flag = false;
diff --git a/demo/cdc_acm_multi_template.c b/demo/cdc_acm_multi_template.c
index 7753439a..5538e662 100644
--- a/demo/cdc_acm_multi_template.c
+++ b/demo/cdc_acm_multi_template.c
@@ -31,38 +31,44 @@
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN * 4)
-#ifdef CONFIG_USB_HS
-#define CDC_MAX_MPS 512
-#else
-#define CDC_MAX_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x08, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
- CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
- CDC_ACM_DESCRIPTOR_INIT(0x02, CDC_INT_EP2, CDC_OUT_EP2, CDC_IN_EP2, CDC_MAX_MPS, 0x02),
- CDC_ACM_DESCRIPTOR_INIT(0x04, CDC_INT_EP3, CDC_OUT_EP3, CDC_IN_EP3, CDC_MAX_MPS, 0x02),
- CDC_ACM_DESCRIPTOR_INIT(0x06, CDC_INT_EP4, CDC_OUT_EP4, CDC_IN_EP4, CDC_MAX_MPS, 0x02)
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x02, CDC_INT_EP2, CDC_OUT_EP2, CDC_IN_EP2, USB_BULK_EP_MPS_HS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x04, CDC_INT_EP3, CDC_OUT_EP3, CDC_IN_EP3, USB_BULK_EP_MPS_HS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x06, CDC_INT_EP4, CDC_OUT_EP4, CDC_IN_EP4, USB_BULK_EP_MPS_HS, 0x02)
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x08, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x02, CDC_INT_EP2, CDC_OUT_EP2, CDC_IN_EP2, USB_BULK_EP_MPS_FS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x04, CDC_INT_EP3, CDC_OUT_EP3, CDC_IN_EP3, USB_BULK_EP_MPS_FS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x06, CDC_INT_EP4, CDC_OUT_EP4, CDC_IN_EP4, USB_BULK_EP_MPS_FS, 0x02)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x08, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x02, CDC_INT_EP2, CDC_OUT_EP2, CDC_IN_EP2, USB_BULK_EP_MPS_FS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x04, CDC_INT_EP3, CDC_OUT_EP3, CDC_IN_EP3, USB_BULK_EP_MPS_FS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x06, CDC_INT_EP4, CDC_OUT_EP4, CDC_IN_EP4, USB_BULK_EP_MPS_FS, 0x02)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x08, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x02, CDC_INT_EP2, CDC_OUT_EP2, CDC_IN_EP2, USB_BULK_EP_MPS_HS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x04, CDC_INT_EP3, CDC_OUT_EP3, CDC_IN_EP3, USB_BULK_EP_MPS_HS, 0x02),
+ CDC_ACM_DESCRIPTOR_INIT(0x06, CDC_INT_EP4, CDC_OUT_EP4, CDC_IN_EP4, USB_BULK_EP_MPS_HS, 0x02)
};
static const char *string_descriptors[] = {
@@ -74,19 +80,40 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
@@ -99,6 +126,7 @@ const struct usb_descriptor cdc_multi_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
@@ -149,7 +177,7 @@ void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
- if ((nbytes % CDC_MAX_MPS) == 0 && nbytes) {
+ if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
/* send zlp */
usbd_ep_start_write(CDC_IN_EP, NULL, 0);
} else {
diff --git a/demo/cdc_acm_rttchardev_template.c b/demo/cdc_acm_rttchardev_template.c
index d251f458..94d6a086 100644
--- a/demo/cdc_acm_rttchardev_template.c
+++ b/demo/cdc_acm_rttchardev_template.c
@@ -19,35 +19,32 @@
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN)
-#ifdef CONFIG_USB_HS
-#define CDC_MAX_MPS 512
-#else
-#define CDC_MAX_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
- CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02)
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02)
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02)
};
static const char *string_descriptors[] = {
@@ -59,19 +56,40 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
@@ -84,6 +102,7 @@ const struct usb_descriptor cdc_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
diff --git a/demo/cdc_acm_template.c b/demo/cdc_acm_template.c
index 610df928..acf492a2 100644
--- a/demo/cdc_acm_template.c
+++ b/demo/cdc_acm_template.c
@@ -19,35 +19,32 @@
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN)
-#ifdef CONFIG_USB_HS
-#define CDC_MAX_MPS 512
-#else
-#define CDC_MAX_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
- CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02)
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02)
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02)
};
static const char *string_descriptors[] = {
@@ -59,19 +56,40 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
@@ -84,10 +102,11 @@ const struct usb_descriptor cdc_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
-USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048]; /* 2048 is only for test speed , please use CDC_MAX_MPS for common*/
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[2048]; /* 2048 is only for test speed , please use the max mps for common*/
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[2048];
volatile bool ep_tx_busy_flag = false;
diff --git a/demo/cdc_ecm_template.c b/demo/cdc_ecm_template.c
index 512725ed..db17fb49 100644
--- a/demo/cdc_ecm_template.c
+++ b/demo/cdc_ecm_template.c
@@ -23,12 +23,6 @@
/*!< 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
-
/* str idx = 4 is for mac address: aa:bb:cc:dd:ee:ff*/
#define CDC_ECM_MAC_STRING_INDEX 4
@@ -36,25 +30,28 @@ static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ 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, USB_BULK_EP_MPS_HS, CDC_ECM_MAC_STRING_INDEX)
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
- CDC_ECM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, CDC_ECM_MAC_STRING_INDEX)
+ CDC_ECM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, CDC_ECM_MAC_STRING_INDEX)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_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, USB_BULK_EP_MPS_FS, CDC_ECM_MAC_STRING_INDEX)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_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, USB_BULK_EP_MPS_HS, CDC_ECM_MAC_STRING_INDEX)
};
static const char *string_descriptors[] = {
@@ -67,21 +64,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -92,6 +112,7 @@ const struct usb_descriptor cdc_ecm_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
diff --git a/demo/cdc_ncm_template.c b/demo/cdc_ncm_template.c
new file mode 100644
index 00000000..5d7ab1b8
--- /dev/null
+++ b/demo/cdc_ncm_template.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2026, 54fire
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_cdc_ncm.h"
+
+#ifndef CONFIG_USBDEV_CDC_NCM_USING_LWIP
+#error "Please enable CONFIG_USBDEV_CDC_NCM_USING_LWIP for this demo"
+#endif
+
+/*!< 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_NCM_DESCRIPTOR_LEN)
+
+/* str idx = 4 is for mac address: aa:bb:cc:dd:ee:ff*/
+#define CDC_NCM_MAC_STRING_INDEX 4
+
+static const uint8_t device_descriptor[] = {
+ USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
+};
+
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_NCM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, CDC_NCM_MAC_STRING_INDEX)
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_NCM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, CDC_NCM_MAC_STRING_INDEX)
+};
+
+static const uint8_t device_quality_descriptor[] = {
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_NCM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, CDC_NCM_MAC_STRING_INDEX)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_NCM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, CDC_NCM_MAC_STRING_INDEX)
+};
+
+static const char *string_descriptors[] = {
+ (const char[]){ 0x09, 0x04 }, /* Langid */
+ "CherryUSB", /* Manufacturer */
+ "CherryUSB CDC NCM DEMO", /* Product */
+ "2026123456", /* Serial Number */
+ "aabbccddeeff", /* ncm mac address */
+};
+
+static const uint8_t *device_descriptor_callback(uint8_t speed)
+{
+ (void)speed;
+
+ return device_descriptor;
+}
+
+static const uint8_t *config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
+static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
+{
+ (void)speed;
+
+ return device_quality_descriptor;
+}
+
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
+static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
+{
+ (void)speed;
+
+ if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
+ return NULL;
+ }
+ return string_descriptors[index];
+}
+
+const struct usb_descriptor cdc_ncm_descriptor = {
+ .device_descriptor_callback = device_descriptor_callback,
+ .config_descriptor_callback = config_descriptor_callback,
+ .device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
+ .string_descriptor_callback = string_descriptor_callback
+};
+
+uint8_t mac[6] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+
+#ifdef RT_USING_LWIP
+
+#ifndef RT_LWIP_DHCP
+#error cdc_ncm must enable RT_LWIP_DHCP
+#endif
+
+#ifndef LWIP_USING_DHCPD
+#error cdc_ncm must enable LWIP_USING_DHCPD
+#endif
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <netif/ethernetif.h>
+#include <dhcp_server.h>
+
+#define CDC_NCM_TX_TIMEOUT_MS 1000
+
+struct eth_device cdc_ncm_dev;
+static struct rt_semaphore cdc_ncm_tx_sem;
+
+void usbd_cdc_ncm_data_send_done(uint32_t len)
+{
+ (void)len;
+ rt_sem_release(&cdc_ncm_tx_sem);
+}
+
+static rt_err_t rt_usbd_cdc_ncm_control(rt_device_t dev, int cmd, void *args)
+{
+ switch (cmd) {
+ case NIOCTL_GADDR:
+
+ /* get mac address */
+ if (args) {
+ uint8_t *mac_dev = (uint8_t *)args;
+ rt_memcpy(mac_dev, mac, 6);
+ mac_dev[5] = ~mac_dev[5]; /* device mac can't same as host. */
+ } else
+ return -RT_ERROR;
+
+ break;
+
+ default:
+ break;
+ }
+
+ return RT_EOK;
+}
+
+struct pbuf *rt_usbd_cdc_ncm_eth_rx(rt_device_t dev)
+{
+ return usbd_cdc_ncm_eth_rx();
+}
+
+rt_err_t rt_usbd_cdc_ncm_eth_tx(rt_device_t dev, struct pbuf *p)
+{
+ int ret;
+
+ ret = usbd_cdc_ncm_eth_tx(p);
+ if (ret == 0) {
+ if (rt_sem_take(&cdc_ncm_tx_sem, rt_tick_from_millisecond(CDC_NCM_TX_TIMEOUT_MS)) != RT_EOK) {
+ return -RT_ETIMEOUT;
+ }
+ return RT_EOK;
+ } else
+ return -RT_ERROR;
+}
+
+void cdc_ncm_lwip_init(void)
+{
+ rt_sem_init(&cdc_ncm_tx_sem, "ncm_tx", 0, RT_IPC_FLAG_PRIO);
+
+ cdc_ncm_dev.parent.control = rt_usbd_cdc_ncm_control;
+ cdc_ncm_dev.eth_rx = rt_usbd_cdc_ncm_eth_rx;
+ cdc_ncm_dev.eth_tx = rt_usbd_cdc_ncm_eth_tx;
+
+ eth_device_init(&cdc_ncm_dev, "u0");
+
+ eth_device_linkchange(&cdc_ncm_dev, RT_TRUE);
+ dhcpd_start("u0");
+}
+
+void usbd_cdc_ncm_data_recv_done(uint32_t len)
+{
+ eth_device_ready(&cdc_ncm_dev);
+}
+
+#else
+#include "netif/etharp.h"
+#include "lwip/init.h"
+#include "lwip/netif.h"
+#include "lwip/pbuf.h"
+
+#include "dhserver.h"
+#include "dnserver.h"
+
+/* rough bounded wait for the polled demo; in a real application use an os semaphore with timeout */
+#define CDC_NCM_TX_TIMEOUT_LOOPS 1000000UL
+
+volatile bool cdc_ncm_tx_done = false;
+
+void usbd_cdc_ncm_data_send_done(uint32_t len)
+{
+ (void)len;
+ cdc_ncm_tx_done = true;
+}
+
+/*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)7
+#define IP_ADDR3 (uint8_t)1
+
+/*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)0
+#define GW_ADDR1 (uint8_t)0
+#define GW_ADDR2 (uint8_t)0
+#define GW_ADDR3 (uint8_t)0
+
+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);
+
+#define NUM_DHCP_ENTRY 3
+
+static dhcp_entry_t entries[NUM_DHCP_ENTRY] = {
+ /* mac ip address subnet mask lease time */
+ { { 0 }, { 192, 168, 7, 2 }, { 255, 255, 255, 0 }, 24 * 60 * 60 },
+ { { 0 }, { 192, 168, 7, 3 }, { 255, 255, 255, 0 }, 24 * 60 * 60 },
+ { { 0 }, { 192, 168, 7, 4 }, { 255, 255, 255, 0 }, 24 * 60 * 60 }
+};
+
+static dhcp_config_t dhcp_config = {
+ { 192, 168, 7, 1 }, /* server address */
+ 67, /* port */
+ { 192, 168, 7, 1 }, /* dns server */
+ "cherry", /* dns suffix */
+ NUM_DHCP_ENTRY, /* num entry */
+ entries /* entries */
+};
+
+static bool dns_query_proc(const char *name, ip_addr_t *addr)
+{
+ if (strcmp(name, "cdc_ncm.cherry") == 0 || strcmp(name, "www.cdc_ncm.cherry") == 0) {
+ addr->addr = ipaddr.addr;
+ return true;
+ }
+ return false;
+}
+
+static struct netif cdc_ncm_netif; //network interface
+
+/* Network interface name */
+#define IFNAME0 'N'
+#define IFNAME1 'X'
+
+err_t linkoutput_fn(struct netif *netif, struct pbuf *p)
+{
+ int ret;
+ uint32_t timeout = CDC_NCM_TX_TIMEOUT_LOOPS;
+
+ cdc_ncm_tx_done = false;
+ ret = usbd_cdc_ncm_eth_tx(p);
+ if (ret == 0) {
+ while (!cdc_ncm_tx_done) {
+ if (--timeout == 0) {
+ return ERR_TIMEOUT;
+ }
+ }
+ return ERR_OK;
+ } else
+ return ERR_BUF;
+}
+
+err_t cdc_ncm_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_ncm_if_input(struct netif *netif)
+{
+ err_t err;
+ struct pbuf *p;
+
+ p = usbd_cdc_ncm_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_ncm_lwip_init(void)
+{
+ struct netif *netif = &cdc_ncm_netif;
+
+ lwip_init();
+
+ netif->hwaddr_len = 6;
+ memcpy(netif->hwaddr, mac, 6);
+ netif->hwaddr[5] = ~netif->hwaddr[5]; /* device mac can't same as host. */
+
+ netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, cdc_ncm_if_init, netif_input);
+ netif_set_default(netif);
+ while (!netif_is_up(netif)) {
+ }
+
+ while (dhserv_init(&dhcp_config)) {
+ }
+
+ while (dnserv_init(IP_ADDR_ANY, 53, dns_query_proc)) {
+ }
+}
+
+void usbd_cdc_ncm_data_recv_done(uint32_t len)
+{
+}
+
+void cdc_ncm_input_poll(void)
+{
+ cdc_ncm_if_input(&cdc_ncm_netif);
+}
+#endif
+
+static void usbd_event_handler(uint8_t busid, uint8_t event)
+{
+ switch (event) {
+ case USBD_EVENT_RESET:
+ break;
+ case USBD_EVENT_CONNECTED:
+ break;
+ case USBD_EVENT_DISCONNECTED:
+ break;
+ case USBD_EVENT_RESUME:
+ break;
+ case USBD_EVENT_SUSPEND:
+ break;
+ case USBD_EVENT_CONFIGURED:
+ break;
+ case USBD_EVENT_SET_REMOTE_WAKEUP:
+ break;
+ case USBD_EVENT_CLR_REMOTE_WAKEUP:
+ break;
+
+ default:
+ break;
+ }
+}
+
+struct usbd_interface intf0;
+struct usbd_interface intf1;
+
+/* ncm is supported in linux, windows and macos. In linux, you should input the following command
+ *
+ * sudo ifconfig enxaabbccddeeff up
+ * sudo dhclient enxaabbccddeeff
+*/
+void cdc_ncm_init(uint8_t busid, uintptr_t reg_base)
+{
+ cdc_ncm_lwip_init();
+
+ usbd_desc_register(busid, &cdc_ncm_descriptor);
+
+ usbd_add_interface(busid, usbd_cdc_ncm_init_intf(&intf0, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, mac));
+ usbd_add_interface(busid, usbd_cdc_ncm_init_intf(&intf1, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, mac));
+ usbd_initialize(busid, reg_base, usbd_event_handler);
+}
diff --git a/demo/cdc_rndis_template.c b/demo/cdc_rndis_template.c
index 570064eb..8b2de671 100644
--- a/demo/cdc_rndis_template.c
+++ b/demo/cdc_rndis_template.c
@@ -23,35 +23,32 @@
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + CDC_RNDIS_DESCRIPTOR_LEN)
-#ifdef CONFIG_USB_HS
-#define CDC_MAX_MPS 512
-#else
-#define CDC_MAX_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_RNDIS_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02)
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
- CDC_RNDIS_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02)
+ CDC_RNDIS_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_RNDIS_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ CDC_RNDIS_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02)
};
static const char *string_descriptors[] = {
@@ -63,21 +60,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -88,6 +108,7 @@ const struct usb_descriptor cdc_rndis_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
diff --git a/demo/display/usbdisplay_template.c b/demo/display/usbdisplay_template.c
index be7ef3a0..8fda2283 100644
--- a/demo/display/usbdisplay_template.c
+++ b/demo/display/usbdisplay_template.c
@@ -16,37 +16,40 @@
#define USB_CONFIG_SIZE (9 + 9 + 7 + 7)
-#ifdef CONFIG_USB_HS
-#define DISPLAY_EP_MPS 512
-#else
-#define DISPLAY_EP_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0101, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_IN_EP, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_OUT_EP, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x00),
- USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_IN_EP, 0x02, DISPLAY_EP_MPS, 0x00),
- USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_OUT_EP, 0x02, DISPLAY_EP_MPS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_IN_EP, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_OUT_EP, 0x02, USB_BULK_EP_MPS_FS, 0x00),
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_IN_EP, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_OUT_EP, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0x00, 0x00, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_IN_EP, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(DISPLAY_OUT_EP, 0x02, USB_BULK_EP_MPS_HS, 0x00),
};
static const char *string_descriptors[] = {
@@ -59,21 +62,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -84,6 +110,7 @@ const struct usb_descriptor usbdisplay_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
diff --git a/demo/gs_usb_template.c b/demo/gs_usb_template.c
new file mode 100644
index 00000000..b82c41c8
--- /dev/null
+++ b/demo/gs_usb_template.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2026, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_gs_usb.h"
+
+#define GSUSB_ENDPOINT_IN 0x81
+#define GSUSB_ENDPOINT_OUT 0x02
+
+#define USBD_VID 0x1d50
+#define USBD_PID 0x606f
+#define USBD_MAX_POWER 100
+#define USBD_LANGID_STRING 1033
+
+#define USB_CONFIG_SIZE (9 + (9 + 7 + 7))
+
+#define LINUX_USBD_GS_CAN_VENDOR_CODE 0x20
+
+static const uint8_t linux_WCID_StringDescriptor_MSOS[18] = {
+ USB_MSOSV1_STRING_DESCRIPTOR_INIT(LINUX_USBD_GS_CAN_VENDOR_CODE)
+};
+
+static const uint8_t linux_WINUSB_WCIDDescriptor[] = {
+ /*
+ * WCID descriptor
+ */
+ 0x10 + 0x18, 0x00, 0x00, 0x00, /* dwLength */
+ 0x00, 0x01, /* bcdVersion */
+ 0x04, 0x00, /* wIndex */
+ 0x01, /* bCount */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* bReserved_7 */
+
+ /*
+ * WCID function descriptor
+ */
+ 0x00, /* bFirstInterfaceNumber */
+ 0x01, /* bReserved */
+ /* WINUSB */
+ 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, /* cCID_8 */
+ /* */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* cSubCID_8 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* bReserved_6 */
+};
+
+static const uint8_t linux_WINUSB_IF0_WCIDProperties[] = {
+ 0x92, 0x00, 0x00, 0x00, /* length */
+ 0x00, 0x01, /* version 1.0 */
+ 0x05, 0x00, /* descr index (0x0005) */
+ 0x01, 0x00, /* number of sections */
+ 0x88, 0x00, 0x00, 0x00, /* property section size */
+ 0x07, 0x00, 0x00, 0x00, /* property data type 7: Unicode REG_MULTI_SZ */
+ 0x2a, 0x00, /* property name length */
+
+ 0x44, 0x00, 0x65, 0x00, /* property name "DeviceInterfaceGUIDs" */
+ 0x76, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00, 0x65, 0x00,
+ 0x47, 0x00, 0x55, 0x00, 0x49, 0x00, 0x44, 0x00, 0x73, 0x00, 0x00, 0x00,
+
+ 0x50, 0x00, 0x00, 0x00, /* property data length */
+
+ 0x7b, 0x00, 0x63, 0x00, /* property name: "{c15b4308-04d3-11e6-b3ea-6057189e6443}\0\0" */
+ 0x31, 0x00, 0x35, 0x00, 0x62, 0x00, 0x34, 0x00, 0x33, 0x00, 0x30, 0x00, 0x38, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x34, 0x00, 0x64, 0x00, 0x33, 0x00, 0x2d, 0x00,
+ 0x31, 0x00, 0x31, 0x00, 0x65, 0x00, 0x36, 0x00, 0x2d, 0x00, 0x62, 0x00, 0x33, 0x00, 0x65, 0x00, 0x61, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x30, 0x00, 0x35, 0x00,
+ 0x37, 0x00, 0x31, 0x00, 0x38, 0x00, 0x39, 0x00, 0x65, 0x00, 0x36, 0x00, 0x34, 0x00, 0x34, 0x00, 0x33, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+const uint8_t *linux_WINUSB_IFx_WCIDProperties[] = {
+ linux_WINUSB_IF0_WCIDProperties,
+};
+
+struct usb_msosv1_descriptor linux_msosv1_desc = {
+ .string = linux_WCID_StringDescriptor_MSOS,
+ .vendor_code = LINUX_USBD_GS_CAN_VENDOR_CODE,
+ .compat_id = linux_WINUSB_WCIDDescriptor,
+ .comp_id_property = linux_WINUSB_IFx_WCIDProperties,
+};
+
+static const uint8_t linux_device_descriptor[] = {
+ USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0000, 0x01),
+};
+
+static const uint8_t linux_config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
+ USB_ENDPOINT_DESCRIPTOR_INIT(GSUSB_ENDPOINT_IN, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_HS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(GSUSB_ENDPOINT_OUT, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_HS, 0x00),
+};
+
+static const uint8_t linux_config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
+ USB_ENDPOINT_DESCRIPTOR_INIT(GSUSB_ENDPOINT_IN, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_FS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(GSUSB_ENDPOINT_OUT, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_FS, 0x00),
+};
+
+static const uint8_t linux_device_quality_descriptor[] = {
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t linux_other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 1, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
+ USB_ENDPOINT_DESCRIPTOR_INIT(GSUSB_ENDPOINT_IN, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_FS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(GSUSB_ENDPOINT_OUT, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_FS, 0x00),
+};
+
+static const uint8_t linux_other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 1, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
+ USB_ENDPOINT_DESCRIPTOR_INIT(GSUSB_ENDPOINT_IN, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_HS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(GSUSB_ENDPOINT_OUT, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_HS, 0x00),
+};
+
+static const char *linux_string_descriptors[] = {
+ (const char[]){ 0x09, 0x04 }, /* Langid */
+ "HScanT", /* Manufacturer */
+ "HScanT USB to CAN adapter", /* Product */
+ "2024051701", /* Serial Number */
+ "HScanT GS can0", /* intf */
+ "HScanT GS can1", /* intf */
+ "HScanT GS can2", /* intf */
+ "HScanT GS can3", /* intf */
+};
+
+static const uint8_t *linux_device_descriptor_callback(uint8_t speed)
+{
+ (void)speed;
+
+ return linux_device_descriptor;
+}
+
+static const uint8_t *linux_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return linux_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return linux_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
+static const uint8_t *linux_device_quality_descriptor_callback(uint8_t speed)
+{
+ (void)speed;
+
+ return linux_device_quality_descriptor;
+}
+
+static const uint8_t *linux_other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return linux_other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return linux_other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
+static const char *linux_string_descriptor_callback(uint8_t speed, uint8_t index)
+{
+ (void)speed;
+
+ if (index >= (sizeof(linux_string_descriptors) / sizeof(char *))) {
+ return NULL;
+ }
+ return linux_string_descriptors[index];
+}
+
+const struct usb_descriptor linux_gs_usb_descriptor = {
+ .device_descriptor_callback = linux_device_descriptor_callback,
+ .config_descriptor_callback = linux_config_descriptor_callback,
+ .device_quality_descriptor_callback = linux_device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = linux_other_speed_config_descriptor_callback,
+ .string_descriptor_callback = linux_string_descriptor_callback,
+ .msosv1_descriptor = &linux_msosv1_desc,
+};
+
+static void usbd_event_handler(uint8_t busid, uint8_t event)
+{
+ (void)busid;
+
+ 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 linux_gs_usb_winusb_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+ (void)busid;
+}
+
+void linux_gs_usb_winusb_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+ if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
+ /* send zlp */
+ usbd_ep_start_write(busid, ep, NULL, 0);
+ } else {
+ }
+}
+
+struct usbd_endpoint linux_gs_usb_out_ep = {
+ .ep_addr = GSUSB_ENDPOINT_OUT,
+ .ep_cb = linux_gs_usb_winusb_out
+};
+
+struct usbd_endpoint linux_gs_usb_in_ep = {
+ .ep_addr = GSUSB_ENDPOINT_IN,
+ .ep_cb = linux_gs_usb_winusb_in
+};
+
+struct usbd_interface linux_gs_usb_intf0;
+
+void linux_gs_usb_init(uint8_t busid, uint32_t reg_base)
+{
+ usbd_desc_register(busid, &linux_gs_usb_descriptor);
+
+ usbd_add_interface(busid, usbd_gs_can_init_intf(busid, &linux_gs_usb_intf0));
+ usbd_add_endpoint(busid, &linux_gs_usb_out_ep);
+ usbd_add_endpoint(busid, &linux_gs_usb_in_ep);
+
+ usbd_initialize(busid, reg_base, usbd_event_handler);
+}
diff --git a/demo/hid_custom_inout_template.c b/demo/hid_custom_inout_template.c
index f493bd6c..90a805f9 100644
--- a/demo/hid_custom_inout_template.c
+++ b/demo/hid_custom_inout_template.c
@@ -22,37 +22,36 @@
/*!< custom hid report descriptor size */
#define HID_CUSTOM_REPORT_DESC_SIZE 38
-#ifdef CONFIG_USB_HS
-#define HID_MAX_MPS 1024
+#define HID_MAX_MPS_FS 64
+#define HID_MAX_MPS_HS 1024
#define HIDRAW_IN_INTERVAL 1
-#else
-#define HID_MAX_MPS 64
-#define HIDRAW_IN_INTERVAL 1
-#endif
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0002, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ HID_CUSTOM_INOUT_DESCRIPTOR_INIT(0x00, 0x01, HID_CUSTOM_REPORT_DESC_SIZE, HIDRAW_OUT_EP, HIDRAW_IN_EP, HID_MAX_MPS_HS, HIDRAW_IN_INTERVAL),
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
- HID_CUSTOM_INOUT_DESCRIPTOR_INIT(0x00, 0x01, HID_CUSTOM_REPORT_DESC_SIZE, HIDRAW_OUT_EP, HIDRAW_IN_EP, HID_MAX_MPS, HIDRAW_IN_INTERVAL),
+ HID_CUSTOM_INOUT_DESCRIPTOR_INIT(0x00, 0x01, HID_CUSTOM_REPORT_DESC_SIZE, HIDRAW_OUT_EP, HIDRAW_IN_EP, HID_MAX_MPS_FS, HIDRAW_IN_INTERVAL),
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ HID_CUSTOM_INOUT_DESCRIPTOR_INIT(0x00, 0x01, HID_CUSTOM_REPORT_DESC_SIZE, HIDRAW_OUT_EP, HIDRAW_IN_EP, HID_MAX_MPS_FS, HIDRAW_IN_INTERVAL),
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ HID_CUSTOM_INOUT_DESCRIPTOR_INIT(0x00, 0x01, HID_CUSTOM_REPORT_DESC_SIZE, HIDRAW_OUT_EP, HIDRAW_IN_EP, HID_MAX_MPS_HS, HIDRAW_IN_INTERVAL),
};
static const char *string_descriptors[] = {
@@ -64,21 +63,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -89,60 +111,62 @@ const struct usb_descriptor hid_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
-/*!< custom hid report descriptor */
-static const uint8_t hid_custom_report_desc[HID_CUSTOM_REPORT_DESC_SIZE] = {
-#ifdef CONFIG_USB_HS
+/*!< custom hid report descriptor, full speed */
+static const uint8_t hid_custom_report_desc_fs[HID_CUSTOM_REPORT_DESC_SIZE] = {
/* USER CODE BEGIN 0 */
0x06, 0x00, 0xff, /* USAGE_PAGE (Vendor Defined Page 1) */
0x09, 0x01, /* USAGE (Vendor Usage 1) */
0xa1, 0x01, /* COLLECTION (Application) */
0x85, 0x02, /* REPORT ID (0x02) */
- 0x09, 0x02, /* USAGE (Vendor Usage 1) */
+ 0x09, 0x01, /* USAGE (Vendor Usage 1) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
- 0x25, 0xff, /*LOGICAL_MAXIMUM (255) */
+ 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */
+ 0x95, 0x40 - 1, /* REPORT_COUNT (63) */
0x75, 0x08, /* REPORT_SIZE (8) */
- 0x96, 0xff, 0x03, /* REPORT_COUNT (63) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
/* <___________________________________________________> */
0x85, 0x01, /* REPORT ID (0x01) */
- 0x09, 0x03, /* USAGE (Vendor Usage 1) */
+ 0x09, 0x01, /* USAGE (Vendor Usage 1) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
- 0x25, 0xff, /* LOGICAL_MAXIMUM (255) */
+ 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */
+ 0x95, 0x40 - 1, /* REPORT_COUNT (63) */
0x75, 0x08, /* REPORT_SIZE (8) */
- 0x96, 0xff, 0x03, /* REPORT_COUNT (63) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
/* USER CODE END 0 */
0xC0 /* END_COLLECTION */
-#else
+};
+
+/*!< custom hid report descriptor, high speed */
+static const uint8_t hid_custom_report_desc_hs[HID_CUSTOM_REPORT_DESC_SIZE] = {
/* USER CODE BEGIN 0 */
0x06, 0x00, 0xff, /* USAGE_PAGE (Vendor Defined Page 1) */
0x09, 0x01, /* USAGE (Vendor Usage 1) */
0xa1, 0x01, /* COLLECTION (Application) */
0x85, 0x02, /* REPORT ID (0x02) */
- 0x09, 0x01, /* USAGE (Vendor Usage 1) */
+ 0x09, 0x02, /* USAGE (Vendor Usage 1) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
- 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */
- 0x95, 0x40 - 1, /* REPORT_COUNT (63) */
+ 0x25, 0xff, /*LOGICAL_MAXIMUM (255) */
0x75, 0x08, /* REPORT_SIZE (8) */
+ 0x96, 0xff, 0x03, /* REPORT_COUNT (63) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
/* <___________________________________________________> */
0x85, 0x01, /* REPORT ID (0x01) */
- 0x09, 0x01, /* USAGE (Vendor Usage 1) */
+ 0x09, 0x03, /* USAGE (Vendor Usage 1) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
- 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */
- 0x95, 0x40 - 1, /* REPORT_COUNT (63) */
+ 0x25, 0xff, /* LOGICAL_MAXIMUM (255) */
0x75, 0x08, /* REPORT_SIZE (8) */
+ 0x96, 0xff, 0x03, /* REPORT_COUNT (63) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
/* USER CODE END 0 */
0xC0 /* END_COLLECTION */
-#endif
};
-USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[HID_MAX_MPS];
-USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t send_buffer[HID_MAX_MPS];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[1024];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t send_buffer[1024];
#define HID_STATE_IDLE 0
#define HID_STATE_BUSY 1
@@ -150,6 +174,8 @@ USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t send_buffer[HID_MAX_MPS];
/*!< hid state ! Data can be sent only when state is idle */
static volatile uint8_t custom_state;
+struct usbd_interface intf0;
+
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
switch (event) {
@@ -164,8 +190,16 @@ static void usbd_event_handler(uint8_t busid, uint8_t event)
case USBD_EVENT_SUSPEND:
break;
case USBD_EVENT_CONFIGURED:
+ /* the hid report descriptor depends on the negotiated speed, select it here */
+ if (usbd_get_device_speed(busid) == USB_SPEED_HIGH) {
+ intf0.hid_report_descriptor = hid_custom_report_desc_hs;
+ intf0.hid_report_descriptor_len = sizeof(hid_custom_report_desc_hs);
+ } else {
+ intf0.hid_report_descriptor = hid_custom_report_desc_fs;
+ intf0.hid_report_descriptor_len = sizeof(hid_custom_report_desc_fs);
+ }
/* setup first out ep read transfer */
- usbd_ep_start_read(busid, HIDRAW_OUT_EP, read_buffer, HID_MAX_MPS);
+ usbd_ep_start_read(busid, HIDRAW_OUT_EP, read_buffer, usbd_get_ep_mps(busid, HIDRAW_OUT_EP));
break;
case USBD_EVENT_SET_REMOTE_WAKEUP:
break;
@@ -188,7 +222,7 @@ static void usbd_hid_custom_in_callback(uint8_t busid, uint8_t ep, uint32_t nbyt
static void usbd_hid_custom_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual out len:%d\r\n", (unsigned int)nbytes);
- usbd_ep_start_read(busid, ep, read_buffer, HID_MAX_MPS);
+ usbd_ep_start_read(busid, ep, read_buffer, usbd_get_ep_mps(busid, ep));
read_buffer[0] = 0x02; /* IN: report id */
usbd_ep_start_write(busid, HIDRAW_IN_EP, read_buffer, nbytes);
}
@@ -210,13 +244,11 @@ static struct usbd_endpoint custom_out_ep = {
* @param[in] none
* @retval none
*/
-struct usbd_interface intf0;
-
void hid_custom_init(uint8_t busid, uintptr_t reg_base)
{
usbd_desc_register(busid, &hid_descriptor);
- usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf0, hid_custom_report_desc, HID_CUSTOM_REPORT_DESC_SIZE));
+ usbd_add_interface(busid, usbd_hid_init_intf(busid, &intf0, hid_custom_report_desc_fs, HID_CUSTOM_REPORT_DESC_SIZE));
usbd_add_endpoint(busid, &custom_in_ep);
usbd_add_endpoint(busid, &custom_out_ep);
diff --git a/demo/hid_keyboard_template.c b/demo/hid_keyboard_template.c
index 2faa6a5a..e8704e9c 100644
--- a/demo/hid_keyboard_template.c
+++ b/demo/hid_keyboard_template.c
@@ -13,7 +13,7 @@
#define HID_INT_EP 0x81
#define HID_INT_EP_SIZE 8
-#define HID_INT_EP_INTERVAL 10
+#define HID_INT_EP_INTERVAL 1
#define USB_CONFIG_SIZE 34
#define HID_KEYBOARD_REPORT_DESC_SIZE 63
diff --git a/demo/midi_template.c b/demo/midi_template.c
index 6e522d44..31133a78 100644
--- a/demo/midi_template.c
+++ b/demo/midi_template.c
@@ -22,45 +22,75 @@
MIDI_STANDARD_DESCRIPTOR_LEN + \
AUDIO_MS_SIZ)
-#ifdef CONFIG_USB_HS
-#define MIDI_EP_MPS 512
-#else
-#define MIDI_EP_MPS 64
-#endif
+/*!< max ep mps used to size the ram buffers */
+#define MIDI_EP_MPS_MAX USB_BULK_EP_MPS_HS
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0100, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, 0x00, 0x01),
MIDI_STANDARD_DESCRIPTOR_INIT(0x01, 0x02),
MIDI_CS_HEADER_DESCRIPTOR_INIT(AUDIO_MS_SIZ),
MIDI_JACK_DESCRIPTOR_INIT(0x01),
// OUT endpoint descriptor
- 0x09, 0x05, MIDI_OUT_EP, 0x02, WBVAL(MIDI_EP_MPS), 0x00, 0x00, 0x00,
+ 0x09, 0x05, MIDI_OUT_EP, 0x02, WBVAL(USB_BULK_EP_MPS_HS), 0x00, 0x00, 0x00,
0x05, 0x25, 0x01, 0x01, 0x01,
// IN endpoint descriptor
- 0x09, 0x05, MIDI_IN_EP, 0x02, WBVAL(MIDI_EP_MPS), 0x00, 0x00, 0x00,
+ 0x09, 0x05, MIDI_IN_EP, 0x02, WBVAL(USB_BULK_EP_MPS_HS), 0x00, 0x00, 0x00,
+ 0x05, 0x25, 0x01, 0x01, 0x03
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, 0x00, 0x01),
+ MIDI_STANDARD_DESCRIPTOR_INIT(0x01, 0x02),
+ MIDI_CS_HEADER_DESCRIPTOR_INIT(AUDIO_MS_SIZ),
+ MIDI_JACK_DESCRIPTOR_INIT(0x01),
+ // OUT endpoint descriptor
+ 0x09, 0x05, MIDI_OUT_EP, 0x02, WBVAL(USB_BULK_EP_MPS_FS), 0x00, 0x00, 0x00,
+ 0x05, 0x25, 0x01, 0x01, 0x01,
+
+ // IN endpoint descriptor
+ 0x09, 0x05, MIDI_IN_EP, 0x02, WBVAL(USB_BULK_EP_MPS_FS), 0x00, 0x00, 0x00,
0x05, 0x25, 0x01, 0x01, 0x03
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, 0x00, 0x01),
+ MIDI_STANDARD_DESCRIPTOR_INIT(0x01, 0x02),
+ MIDI_CS_HEADER_DESCRIPTOR_INIT(AUDIO_MS_SIZ),
+ MIDI_JACK_DESCRIPTOR_INIT(0x01),
+ // OUT endpoint descriptor
+ 0x09, 0x05, MIDI_OUT_EP, 0x02, WBVAL(USB_BULK_EP_MPS_FS), 0x00, 0x00, 0x00,
+ 0x05, 0x25, 0x01, 0x01, 0x01,
+
+ // IN endpoint descriptor
+ 0x09, 0x05, MIDI_IN_EP, 0x02, WBVAL(USB_BULK_EP_MPS_FS), 0x00, 0x00, 0x00,
+ 0x05, 0x25, 0x01, 0x01, 0x03
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ AUDIO_AC_DESCRIPTOR_INIT(0x00, 0x02, AUDIO_AC_SIZ, 0x00, 0x01),
+ MIDI_STANDARD_DESCRIPTOR_INIT(0x01, 0x02),
+ MIDI_CS_HEADER_DESCRIPTOR_INIT(AUDIO_MS_SIZ),
+ MIDI_JACK_DESCRIPTOR_INIT(0x01),
+ // OUT endpoint descriptor
+ 0x09, 0x05, MIDI_OUT_EP, 0x02, WBVAL(USB_BULK_EP_MPS_HS), 0x00, 0x00, 0x00,
+ 0x05, 0x25, 0x01, 0x01, 0x01,
+
+ // IN endpoint descriptor
+ 0x09, 0x05, MIDI_IN_EP, 0x02, WBVAL(USB_BULK_EP_MPS_HS), 0x00, 0x00, 0x00,
+ 0x05, 0x25, 0x01, 0x01, 0x03
};
static const char *string_descriptors[] = {
@@ -72,21 +102,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -97,11 +150,12 @@ const struct usb_descriptor midi_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
-USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[MIDI_EP_MPS];
-USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[MIDI_EP_MPS];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t read_buffer[MIDI_EP_MPS_MAX];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[MIDI_EP_MPS_MAX];
static void usbd_event_handler(uint8_t busid, uint8_t event)
{
@@ -117,7 +171,7 @@ static void usbd_event_handler(uint8_t busid, uint8_t event)
case USBD_EVENT_SUSPEND:
break;
case USBD_EVENT_CONFIGURED:
- usbd_ep_start_read(busid, MIDI_OUT_EP, read_buffer, MIDI_EP_MPS);
+ usbd_ep_start_read(busid, MIDI_OUT_EP, read_buffer, usbd_get_ep_mps(busid, MIDI_OUT_EP));
break;
case USBD_EVENT_SET_REMOTE_WAKEUP:
break;
@@ -131,7 +185,7 @@ static void usbd_event_handler(uint8_t busid, uint8_t event)
void usbd_midi_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
- usbd_ep_start_read(busid, MIDI_OUT_EP, read_buffer, MIDI_EP_MPS);
+ usbd_ep_start_read(busid, MIDI_OUT_EP, read_buffer, usbd_get_ep_mps(busid, MIDI_OUT_EP));
}
void usbd_midi_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
diff --git a/demo/msc_ram_template.c b/demo/msc_ram_template.c
index cd93b2b2..d3941af9 100644
--- a/demo/msc_ram_template.c
+++ b/demo/msc_ram_template.c
@@ -16,35 +16,32 @@
#define USB_CONFIG_SIZE (9 + MSC_DESCRIPTOR_LEN)
-#ifdef CONFIG_USB_HS
-#define MSC_MAX_MPS 512
-#else
-#define MSC_MAX_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0200, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ 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, USB_BULK_EP_MPS_HS, 0x02)
+};
+
+static const uint8_t config_descriptor_fs[] = {
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)
+ MSC_DESCRIPTOR_INIT(0x00, MSC_OUT_EP, MSC_IN_EP, USB_BULK_EP_MPS_FS, 0x02)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_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, USB_BULK_EP_MPS_FS, 0x02)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_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, USB_BULK_EP_MPS_HS, 0x02)
};
static const char *string_descriptors[] = {
@@ -56,21 +53,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -81,6 +101,7 @@ const struct usb_descriptor msc_ram_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
diff --git a/demo/tmc/tmc_template.c b/demo/tmc/tmc_template.c
new file mode 100644
index 00000000..d02306ab
--- /dev/null
+++ b/demo/tmc/tmc_template.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_tmc.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 + (9 + 7 + 7))
+
+static const uint8_t device_descriptor[] = {
+ USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0100, 0x01)
+};
+
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ TMC_DESCRIPTOR_INIT(0x00, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0X00),
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ TMC_DESCRIPTOR_INIT(0x00, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0X00),
+};
+
+static const uint8_t device_quality_descriptor[] = {
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ TMC_DESCRIPTOR_INIT(0x00, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0X00),
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ TMC_DESCRIPTOR_INIT(0x00, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0X00),
+};
+
+static const char *string_descriptors[] = {
+ (const char[]){ 0x09, 0x04 }, /* Langid */
+ "CherryUSB", /* Manufacturer */
+ "CherryUSB TMC DEMO", /* Product */
+ "2024051702", /* Serial Number */
+};
+
+static const uint8_t *device_descriptor_callback(uint8_t speed)
+{
+ (void)speed;
+
+ return device_descriptor;
+}
+
+static const uint8_t *config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
+static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
+{
+ (void)speed;
+
+ return device_quality_descriptor;
+}
+
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
+static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
+{
+ (void)speed;
+
+ if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
+ return NULL;
+ }
+ return string_descriptors[index];
+}
+
+const struct usb_descriptor cdc_descriptor = {
+ .device_descriptor_callback = device_descriptor_callback,
+ .config_descriptor_callback = config_descriptor_callback,
+ .device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
+ .string_descriptor_callback = string_descriptor_callback,
+};
+
+static void usbd_event_handler(uint8_t busid, uint8_t event)
+{
+ switch (event) {
+ case USBD_EVENT_RESET:
+ break;
+ case USBD_EVENT_CONNECTED:
+ break;
+ case USBD_EVENT_DISCONNECTED:
+ break;
+ case USBD_EVENT_RESUME:
+ break;
+ case USBD_EVENT_SUSPEND:
+ break;
+ case USBD_EVENT_CONFIGURED:
+ break;
+ case USBD_EVENT_SET_REMOTE_WAKEUP:
+ break;
+ case USBD_EVENT_CLR_REMOTE_WAKEUP:
+ break;
+
+ default:
+ break;
+ }
+}
+
+static const scpi_command_t scpi_commands[] = {
+ /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1) */
+ {
+ .pattern = "*CLS",
+ .callback = SCPI_CoreCls,
+ },
+ {
+ .pattern = "*ESE",
+ .callback = SCPI_CoreEse,
+ },
+ {
+ .pattern = "*ESE?",
+ .callback = SCPI_CoreEseQ,
+ },
+ {
+ .pattern = "*ESR?",
+ .callback = SCPI_CoreEsrQ,
+ },
+ {
+ .pattern = "*IDN?",
+ .callback = SCPI_CoreIdnQ,
+ },
+ {
+ .pattern = "*OPC",
+ .callback = SCPI_CoreOpc,
+ },
+ {
+ .pattern = "*OPC?",
+ .callback = SCPI_CoreOpcQ,
+ },
+ {
+ .pattern = "*RST",
+ .callback = SCPI_CoreRst,
+ },
+ {
+ .pattern = "*SRE",
+ .callback = SCPI_CoreSre,
+ },
+ {
+ .pattern = "*SRE?",
+ .callback = SCPI_CoreSreQ,
+ },
+ {
+ .pattern = "*STB?",
+ .callback = SCPI_CoreStbQ,
+ },
+ {
+ .pattern = "*TST?",
+ .callback = SCPI_CoreTstQ,
+ },
+ {
+ .pattern = "*WAI",
+ .callback = SCPI_CoreWai,
+ },
+
+ /* Required SCPI commands (SCPI std V1999.0 4.2.1) */
+ {
+ .pattern = "SYSTem:ERRor[:NEXT]?",
+ .callback = SCPI_SystemErrorNextQ,
+ },
+ {
+ .pattern = "SYSTem:ERRor:COUNt?",
+ .callback = SCPI_SystemErrorCountQ,
+ },
+ {
+ .pattern = "SYSTem:VERSion?",
+ .callback = SCPI_SystemVersionQ,
+ },
+
+ {
+ .pattern = "STATus:QUEStionable[:EVENt]?",
+ .callback = SCPI_StatusQuestionableEventQ,
+ },
+ {
+ .pattern = "STATus:QUEStionable:CONDition?",
+ .callback = SCPI_StatusQuestionableConditionQ,
+ },
+ {
+ .pattern = "STATus:QUEStionable:ENABle",
+ .callback = SCPI_StatusQuestionableEnable,
+ },
+ {
+ .pattern = "STATus:QUEStionable:ENABle?",
+ .callback = SCPI_StatusQuestionableEnableQ,
+ },
+
+ {
+ .pattern = "STATus:OPERation[:EVENt]?",
+ .callback = SCPI_StatusOperationEventQ,
+ },
+ {
+ .pattern = "STATus:OPERation:CONDition?",
+ .callback = SCPI_StatusOperationConditionQ,
+ },
+ {
+ .pattern = "STATus:OPERation:ENABle",
+ .callback = SCPI_StatusOperationEnable,
+ },
+ {
+ .pattern = "STATus:OPERation:ENABle?",
+ .callback = SCPI_StatusOperationEnableQ,
+ },
+
+ {
+ .pattern = "STATus:PRESet",
+ .callback = SCPI_StatusPreset,
+ },
+
+ {
+ .pattern = "STUB",
+ .callback = SCPI_Stub,
+ },
+ {
+ .pattern = "STUB?",
+ .callback = SCPI_StubQ,
+ },
+
+ SCPI_CMD_LIST_END
+};
+
+#define SCPI_IDN1 "cherry-embedded"
+#define SCPI_IDN2 "CherryUSB"
+#define SCPI_IDN3 "20250607123456"
+#define SCPI_IDN4 "v1.0.0"
+
+static const char *idn[] = {
+ SCPI_IDN1,
+ SCPI_IDN2,
+ SCPI_IDN3,
+ SCPI_IDN4,
+};
+
+static struct usbd_interface intf0;
+
+void tmc_init(uint8_t busid, uint32_t reg_base)
+{
+ usbd_desc_register(busid, &cdc_descriptor);
+ usbd_add_interface(busid, usbd_tmc_init_intf(busid, &intf0, CDC_OUT_EP, CDC_IN_EP, scpi_commands, idn));
+ usbd_initialize(busid, reg_base, usbd_event_handler);
+} \ No newline at end of file
diff --git a/docs/en/support/img/tmcdev1.png b/demo/tmc/tmcdev1.png
index 1eaf7155..1eaf7155 100755..100644
--- a/docs/en/support/img/tmcdev1.png
+++ b/demo/tmc/tmcdev1.png
Binary files differ
diff --git a/docs/en/support/img/tmcdev2.png b/demo/tmc/tmcdev2.png
index 97c8297b..97c8297b 100755..100644
--- a/docs/en/support/img/tmcdev2.png
+++ b/demo/tmc/tmcdev2.png
Binary files differ
diff --git a/demo/video_audiov1_hid_template.c b/demo/video_audiov1_hid_template.c
index 7a06aaa4..0645cc91 100644
--- a/demo/video_audiov1_hid_template.c
+++ b/demo/video_audiov1_hid_template.c
@@ -14,21 +14,9 @@
#define VIDEO_IN_EP 0x81
#define VIDEO_INT_EP 0x86
-#ifdef CONFIG_USB_HS
-#define MAX_PAYLOAD_SIZE 1024 // for high speed with one transcations every one micro frame
+#define MAX_PAYLOAD_SIZE 1020
#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
-// #define MAX_PAYLOAD_SIZE 2048 // for high speed with two transcations every one micro frame
-// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 2)) | (0x01 << 11))
-
-// #define MAX_PAYLOAD_SIZE 3072 // for high speed with three transcations every one micro frame
-// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 3)) | (0x02 << 11))
-
-#else
-#define MAX_PAYLOAD_SIZE 1020
-#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
-#endif
-
#define WIDTH (unsigned int)(640)
#define HEIGHT (unsigned int)(480)
@@ -62,11 +50,8 @@
#define USBD_MAX_POWER 100
#define USBD_LANGID_STRING 1033
-#ifdef CONFIG_USB_HS
-#define EP_INTERVAL 0x04
-#else
-#define EP_INTERVAL 0x01
-#endif
+#define EP_INTERVAL_FS 0x01
+#define EP_INTERVAL_HS 0x04
#define AUDIO_IN_EP 0x82
#define AUDIO_OUT_EP 0x03
@@ -107,7 +92,7 @@ static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x06, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
//VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
@@ -126,26 +111,89 @@ static const uint8_t config_descriptor[] = {
AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x05, 0x04, 0x01, 0x03, 0x00, 0x00),
AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_OUTTERM_SPEAKER, 0x05),
AUDIO_AS_DESCRIPTOR_INIT(0x03, 0x04, 0x02, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET,
- EP_INTERVAL, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
+ EP_INTERVAL_HS, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
AUDIO_AS_DESCRIPTOR_INIT(0x04, 0x03, 0x02, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET,
- EP_INTERVAL, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ)),
+ EP_INTERVAL_HS, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ)),
+ HID_KEYBOARD_DESCRIPTOR_INIT(0x05, 0x01, HID_KEYBOARD_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
+};
+
+static const uint8_t config_descriptor_fs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x06, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ //VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
+ VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
+ VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
+ VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, INTERVAL),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
+ /* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
+ USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01),
+ AUDIO_AC_DESCRIPTOR_INIT(0x02, 0x03, AUDIO_AC_SIZ, 0x00, 0x03, 0x04),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, 0x02, 0x0003),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x02, 0x01, 0x01, 0x03, 0x00, 0x00),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, 0x02),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, 0x02, 0x0003),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x05, 0x04, 0x01, 0x03, 0x00, 0x00),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_OUTTERM_SPEAKER, 0x05),
+ AUDIO_AS_DESCRIPTOR_INIT(0x03, 0x04, 0x02, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET,
+ EP_INTERVAL_FS, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
+ AUDIO_AS_DESCRIPTOR_INIT(0x04, 0x03, 0x02, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET,
+ EP_INTERVAL_FS, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ)),
HID_KEYBOARD_DESCRIPTOR_INIT(0x05, 0x01, HID_KEYBOARD_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x06, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ //VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
+ VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
+ VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
+ VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, INTERVAL),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
+ /* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
+ USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01),
+ AUDIO_AC_DESCRIPTOR_INIT(0x02, 0x03, AUDIO_AC_SIZ, 0x00, 0x03, 0x04),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, 0x02, 0x0003),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x02, 0x01, 0x01, 0x03, 0x00, 0x00),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, 0x02),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, 0x02, 0x0003),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x05, 0x04, 0x01, 0x03, 0x00, 0x00),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_OUTTERM_SPEAKER, 0x05),
+ AUDIO_AS_DESCRIPTOR_INIT(0x03, 0x04, 0x02, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET,
+ EP_INTERVAL_FS, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
+ AUDIO_AS_DESCRIPTOR_INIT(0x04, 0x03, 0x02, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET,
+ EP_INTERVAL_FS, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ)),
+ HID_KEYBOARD_DESCRIPTOR_INIT(0x05, 0x01, HID_KEYBOARD_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x06, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ //VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
+ VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
+ VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
+ VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, INTERVAL),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
+ /* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
+ USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01),
+ AUDIO_AC_DESCRIPTOR_INIT(0x02, 0x03, AUDIO_AC_SIZ, 0x00, 0x03, 0x04),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x01, AUDIO_INTERM_MIC, 0x02, 0x0003),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x02, 0x01, 0x01, 0x03, 0x00, 0x00),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x03, AUDIO_TERMINAL_STREAMING, 0x02),
+ AUDIO_AC_INPUT_TERMINAL_DESCRIPTOR_INIT(0x04, AUDIO_TERMINAL_STREAMING, 0x02, 0x0003),
+ AUDIO_AC_FEATURE_UNIT_DESCRIPTOR_INIT(0x05, 0x04, 0x01, 0x03, 0x00, 0x00),
+ AUDIO_AC_OUTPUT_TERMINAL_DESCRIPTOR_INIT(0x06, AUDIO_OUTTERM_SPEAKER, 0x05),
+ AUDIO_AS_DESCRIPTOR_INIT(0x03, 0x04, 0x02, AUDIO_SPEAKER_FRAME_SIZE_BYTE, AUDIO_SPEAKER_RESOLUTION_BIT, AUDIO_OUT_EP, 0x09, AUDIO_OUT_PACKET,
+ EP_INTERVAL_HS, AUDIO_SAMPLE_FREQ_3B(AUDIO_SPEAKER_FREQ)),
+ AUDIO_AS_DESCRIPTOR_INIT(0x04, 0x03, 0x02, AUDIO_MIC_FRAME_SIZE_BYTE, AUDIO_MIC_RESOLUTION_BIT, AUDIO_IN_EP, 0x05, AUDIO_IN_PACKET,
+ EP_INTERVAL_HS, AUDIO_SAMPLE_FREQ_3B(AUDIO_MIC_FREQ)),
+ HID_KEYBOARD_DESCRIPTOR_INIT(0x05, 0x01, HID_KEYBOARD_REPORT_DESC_SIZE, HID_INT_EP, HID_INT_EP_SIZE, HID_INT_EP_INTERVAL),
};
static const char *string_descriptors[] = {
@@ -157,21 +205,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -182,6 +253,7 @@ const struct usb_descriptor video_audio_hid_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
diff --git a/demo/video_static_h264_template.c b/demo/video_static_h264_template.c
index 8d4083e4..c772b2b9 100644
--- a/demo/video_static_h264_template.c
+++ b/demo/video_static_h264_template.c
@@ -10,21 +10,9 @@
#define VIDEO_IN_EP 0x81
#define VIDEO_INT_EP 0x83
-#ifdef CONFIG_USB_HS
-#define MAX_PAYLOAD_SIZE 1024 // for high speed with one transcations every one micro frame
+#define MAX_PAYLOAD_SIZE 1020
#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
-// #define MAX_PAYLOAD_SIZE 2048 // for high speed with two transcations every one micro frame
-// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 2)) | (0x01 << 11))
-
-// #define MAX_PAYLOAD_SIZE 3072 // for high speed with three transcations every one micro frame
-// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 3)) | (0x02 << 11))
-
-#else
-#define MAX_PAYLOAD_SIZE 1020
-#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
-#endif
-
#define WIDTH (unsigned int)(640)
#define HEIGHT (unsigned int)(480)
@@ -52,7 +40,20 @@ static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ //VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
+ VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
+ VIDEO_VS_FORMAT_H264_DESCRIPTOR_INIT(0x01, 0x01),
+ VIDEO_VS_FRAME_H264_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, INTERVAL),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
+ /* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
+ USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01)
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
//VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
@@ -66,19 +67,33 @@ static const uint8_t config_descriptor[] = {
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ //VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
+ VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
+ VIDEO_VS_FORMAT_H264_DESCRIPTOR_INIT(0x01, 0x01),
+ VIDEO_VS_FRAME_H264_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, INTERVAL),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
+ /* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
+ USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ //VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
+ VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
+ VIDEO_VS_FORMAT_H264_DESCRIPTOR_INIT(0x01, 0x01),
+ VIDEO_VS_FRAME_H264_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, INTERVAL),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
+ /* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
+ USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01)
};
static const char *string_descriptors[] = {
@@ -90,21 +105,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -115,6 +153,7 @@ const struct usb_descriptor video_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
diff --git a/demo/video_static_mjpeg_template.c b/demo/video_static_mjpeg_template.c
index 8ae8514b..97af9f98 100644
--- a/demo/video_static_mjpeg_template.c
+++ b/demo/video_static_mjpeg_template.c
@@ -10,21 +10,9 @@
#define VIDEO_IN_EP 0x81
#define VIDEO_INT_EP 0x83
-#ifdef CONFIG_USB_HS
-#define MAX_PAYLOAD_SIZE 1024 // for high speed with one transcations every one micro frame
+#define MAX_PAYLOAD_SIZE 1020
#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
-// #define MAX_PAYLOAD_SIZE 2048 // for high speed with two transcations every one micro frame
-// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 2)) | (0x01 << 11))
-
-// #define MAX_PAYLOAD_SIZE 3072 // for high speed with three transcations every one micro frame
-// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 3)) | (0x02 << 11))
-
-#else
-#define MAX_PAYLOAD_SIZE 1020
-#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
-#endif
-
#define WIDTH (unsigned int)(640)
#define HEIGHT (unsigned int)(480)
@@ -52,7 +40,20 @@ static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ //VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
+ VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
+ VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
+ VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, INTERVAL),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
+ /* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
+ USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01)
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
//VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
@@ -66,19 +67,33 @@ static const uint8_t config_descriptor[] = {
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ //VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
+ VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
+ VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
+ VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, INTERVAL),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
+ /* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
+ USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ //VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
+ VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
+ VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(0x01, 0x01),
+ VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, INTERVAL),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
+ /* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
+ USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01)
};
static const char *string_descriptors[] = {
@@ -90,21 +105,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -115,6 +153,7 @@ const struct usb_descriptor video_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
diff --git a/demo/video_static_yuyv_template.c b/demo/video_static_yuyv_template.c
index 1b7383ab..2f952def 100644
--- a/demo/video_static_yuyv_template.c
+++ b/demo/video_static_yuyv_template.c
@@ -10,21 +10,9 @@
#define VIDEO_IN_EP 0x81
#define VIDEO_INT_EP 0x83
-#ifdef CONFIG_USB_HS
-#define MAX_PAYLOAD_SIZE 1024 // for high speed with one transcations every one micro frame
+#define MAX_PAYLOAD_SIZE 1020
#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
-// #define MAX_PAYLOAD_SIZE 2048 // for high speed with two transcations every one micro frame
-// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 2)) | (0x01 << 11))
-
-// #define MAX_PAYLOAD_SIZE 3072 // for high speed with three transcations every one micro frame
-// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 3)) | (0x02 << 11))
-
-#else
-#define MAX_PAYLOAD_SIZE 1020
-#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
-#endif
-
#define WIDTH (unsigned int)(64)
#define HEIGHT (unsigned int)(48)
@@ -53,7 +41,22 @@ static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, USBD_VID, USBD_PID, 0x0001, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ //VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
+ VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
+ VIDEO_VS_FORMAT_UNCOMPRESSED_DESCRIPTOR_INIT(0x01, 0x01, VIDEO_GUID_YUY2),
+ VIDEO_VS_FRAME_UNCOMPRESSED_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, INTERVAL),
+ VIDEO_VS_COLOR_MATCHING_DESCRIPTOR_INIT(),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
+ /* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
+ USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01),
+
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
//VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
@@ -69,19 +72,37 @@ static const uint8_t config_descriptor[] = {
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xef, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ //VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
+ VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
+ VIDEO_VS_FORMAT_UNCOMPRESSED_DESCRIPTOR_INIT(0x01, 0x01, VIDEO_GUID_YUY2),
+ VIDEO_VS_FRAME_UNCOMPRESSED_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, INTERVAL),
+ VIDEO_VS_COLOR_MATCHING_DESCRIPTOR_INIT(),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
+ /* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
+ USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01),
+
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_VIDEO_DESC_SIZ, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ //VIDEO_VC_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VC_NOEP_DESCRIPTOR_INIT(0x00, VIDEO_INT_EP, 0x0100, VIDEO_VC_TERMINAL_LEN, 48000000, 0x02),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x00, 0x00),
+ VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(0x01, VS_HEADER_SIZ, VIDEO_IN_EP, 0x00),
+ VIDEO_VS_FORMAT_UNCOMPRESSED_DESCRIPTOR_INIT(0x01, 0x01, VIDEO_GUID_YUY2),
+ VIDEO_VS_FRAME_UNCOMPRESSED_DESCRIPTOR_INIT(0x01, WIDTH, HEIGHT, MIN_BIT_RATE, MAX_BIT_RATE, MAX_FRAME_SIZE, INTERVAL),
+ VIDEO_VS_COLOR_MATCHING_DESCRIPTOR_INIT(),
+ VIDEO_VS_DESCRIPTOR_INIT(0x01, 0x01, 0x01),
+ /* 1.2.2.2 Standard VideoStream Isochronous Video Data Endpoint Descriptor */
+ USB_ENDPOINT_DESCRIPTOR_INIT(VIDEO_IN_EP, 0x05, VIDEO_PACKET_SIZE, 0x01),
+
};
static const char *string_descriptors[] = {
@@ -93,21 +114,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -118,6 +162,7 @@ const struct usb_descriptor video_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback
};
diff --git a/demo/winusb1.0_template.c b/demo/winusb1.0_template.c
index 367d3da0..692bddc5 100644
--- a/demo/winusb1.0_template.c
+++ b/demo/winusb1.0_template.c
@@ -127,42 +127,60 @@ struct usb_msosv1_descriptor msosv1_desc = {
#define INTF_NUM 2
#endif
-#ifdef CONFIG_USB_HS
-#define WINUSB_EP_MPS 512
-#else
-#define WINUSB_EP_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+#if WINUSB_NUM == 2
+ USB_INTERFACE_DESCRIPTOR_INIT(0x01, 0x00, 0x02, 0xff, 0xff, 0x00, 0x05),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP2, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP2, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+#endif
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
- USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, 0x02, WINUSB_EP_MPS, 0x00),
- USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, 0x02, WINUSB_EP_MPS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, 0x02, USB_BULK_EP_MPS_FS, 0x00),
#if WINUSB_NUM == 2
USB_INTERFACE_DESCRIPTOR_INIT(0x01, 0x00, 0x02, 0xff, 0xff, 0x00, 0x05),
- USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP2, 0x02, WINUSB_EP_MPS, 0x00),
- USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP2, 0x02, WINUSB_EP_MPS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP2, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP2, 0x02, USB_BULK_EP_MPS_FS, 0x00),
#endif
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+#if WINUSB_NUM == 2
+ USB_INTERFACE_DESCRIPTOR_INIT(0x01, 0x00, 0x02, 0xff, 0xff, 0x00, 0x05),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP2, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP2, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+#endif
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+#if WINUSB_NUM == 2
+ USB_INTERFACE_DESCRIPTOR_INIT(0x01, 0x00, 0x02, 0xff, 0xff, 0x00, 0x05),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP2, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP2, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+#endif
};
static const char *string_descriptors[] = {
@@ -176,21 +194,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -201,6 +242,7 @@ const struct usb_descriptor winusbv1_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback,
.msosv1_descriptor = &msosv1_desc
};
@@ -257,7 +299,7 @@ void usbd_winusb_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
- if ((nbytes % WINUSB_EP_MPS) == 0 && nbytes) {
+ if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
/* send zlp */
usbd_ep_start_write(busid, WINUSB_IN_EP, NULL, 0);
} else {
diff --git a/demo/winusb2.0_cdc_template.c b/demo/winusb2.0_cdc_template.c
index 89441b8c..2cd66a42 100644
--- a/demo/winusb2.0_cdc_template.c
+++ b/demo/winusb2.0_cdc_template.c
@@ -44,42 +44,60 @@ const struct usb_bos_descriptor bos_desc = {
#define USB_CONFIG_SIZE (9 + 9 + 7 + 7 + CDC_ACM_DESCRIPTOR_LEN)
#define INTF_NUM 3
-#ifdef CONFIG_USB_HS
-#define WINUSB_EP_MPS 512
-#else
-#define WINUSB_EP_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ /* Configuration 0 */
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ /* Interface 0 */
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
+ /* Endpoint OUT 2 */
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_HS, 0x00),
+ /* Endpoint IN 1 */
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_HS, 0x00),
+ CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x00)
+};
+
+static const uint8_t config_descriptor_fs[] = {
/* Configuration 0 */
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
/* Interface 0 */
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
/* Endpoint OUT 2 */
- USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_FS, 0x00),
/* Endpoint IN 1 */
- USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, USB_ENDPOINT_TYPE_BULK, WINUSB_EP_MPS, 0x00),
- CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, WINUSB_EP_MPS, 0x00)
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_FS, 0x00),
+ CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x00)
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x10,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ /* Configuration 0 */
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ /* Interface 0 */
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
+ /* Endpoint OUT 2 */
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_FS, 0x00),
+ /* Endpoint IN 1 */
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_FS, 0x00),
+ CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x00)
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ /* Configuration 0 */
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ /* Interface 0 */
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02),
+ /* Endpoint OUT 2 */
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_HS, 0x00),
+ /* Endpoint IN 1 */
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, USB_ENDPOINT_TYPE_BULK, USB_BULK_EP_MPS_HS, 0x00),
+ CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x00)
};
static const char *string_descriptors[] = {
@@ -91,21 +109,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -116,6 +157,7 @@ const struct usb_descriptor winusbv2_cdc_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback,
.msosv2_descriptor = &msosv2_desc,
.bos_descriptor = &bos_desc
diff --git a/demo/winusb2.0_template.c b/demo/winusb2.0_template.c
index 2fde386f..8009a591 100644
--- a/demo/winusb2.0_template.c
+++ b/demo/winusb2.0_template.c
@@ -56,42 +56,60 @@ const struct usb_bos_descriptor bos_desc = {
#define INTF_NUM 2
#endif
-#ifdef CONFIG_USB_HS
-#define WINUSB_EP_MPS 512
-#else
-#define WINUSB_EP_MPS 64
-#endif
-
static const uint8_t device_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0001, 0x01)
};
-static const uint8_t config_descriptor[] = {
+static const uint8_t config_descriptor_hs[] = {
+ USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+#if WINUSB_NUM == 2
+ USB_INTERFACE_DESCRIPTOR_INIT(0x01, 0x00, 0x02, 0xff, 0xff, 0x00, 0x05),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP2, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP2, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+#endif
+};
+
+static const uint8_t config_descriptor_fs[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
- USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, 0x02, WINUSB_EP_MPS, 0x00),
- USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, 0x02, WINUSB_EP_MPS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, 0x02, USB_BULK_EP_MPS_FS, 0x00),
#if WINUSB_NUM == 2
USB_INTERFACE_DESCRIPTOR_INIT(0x01, 0x00, 0x02, 0xff, 0xff, 0x00, 0x05),
- USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP2, 0x02, WINUSB_EP_MPS, 0x00),
- USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP2, 0x02, WINUSB_EP_MPS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP2, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP2, 0x02, USB_BULK_EP_MPS_FS, 0x00),
#endif
};
static const uint8_t device_quality_descriptor[] = {
- ///////////////////////////////////////
- /// device qualifier descriptor
- ///////////////////////////////////////
- 0x0a,
- USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x00,
- 0x00,
+ USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_1, 0x00, 0x00, 0x00, 0x01),
+};
+
+static const uint8_t other_speed_config_descriptor_hs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+#if WINUSB_NUM == 2
+ USB_INTERFACE_DESCRIPTOR_INIT(0x01, 0x00, 0x02, 0xff, 0xff, 0x00, 0x05),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP2, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP2, 0x02, USB_BULK_EP_MPS_FS, 0x00),
+#endif
+};
+
+static const uint8_t other_speed_config_descriptor_fs[] = {
+ USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
+ USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xff, 0xff, 0x00, 0x04),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+#if WINUSB_NUM == 2
+ USB_INTERFACE_DESCRIPTOR_INIT(0x01, 0x00, 0x02, 0xff, 0xff, 0x00, 0x05),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_IN_EP2, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+ USB_ENDPOINT_DESCRIPTOR_INIT(WINUSB_OUT_EP2, 0x02, USB_BULK_EP_MPS_HS, 0x00),
+#endif
};
static const char *string_descriptors[] = {
@@ -105,21 +123,44 @@ static const char *string_descriptors[] = {
static const uint8_t *device_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
- return config_descriptor;
+ if (speed == USB_SPEED_HIGH) {
+ return config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return config_descriptor_fs;
+ } else {
+ return NULL;
+ }
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
{
+ (void)speed;
+
return device_quality_descriptor;
}
+static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed)
+{
+ if (speed == USB_SPEED_HIGH) {
+ return other_speed_config_descriptor_hs;
+ } else if (speed == USB_SPEED_FULL) {
+ return other_speed_config_descriptor_fs;
+ } else {
+ return NULL;
+ }
+}
+
static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
{
+ (void)speed;
+
if (index >= (sizeof(string_descriptors) / sizeof(char *))) {
return NULL;
}
@@ -130,6 +171,7 @@ const struct usb_descriptor winusbv2_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
+ .other_speed_descriptor_callback = other_speed_config_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback,
.msosv2_descriptor = &msosv2_desc,
.bos_descriptor = &bos_desc,
@@ -187,7 +229,7 @@ void usbd_winusb_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
USB_LOG_RAW("actual in len:%d\r\n", (unsigned int)nbytes);
- if ((nbytes % WINUSB_EP_MPS) == 0 && nbytes) {
+ if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
/* send zlp */
usbd_ep_start_write(busid, WINUSB_IN_EP, NULL, 0);
} else {
diff --git a/docs/assets/allwinnertech.jpg b/docs/assets/allwinnertech.jpg
new file mode 100644
index 00000000..8c407c66
--- /dev/null
+++ b/docs/assets/allwinnertech.jpg
Binary files differ
diff --git a/docs/assets/listenai.jpg b/docs/assets/listenai.jpg
new file mode 100644
index 00000000..819466d5
--- /dev/null
+++ b/docs/assets/listenai.jpg
Binary files differ
diff --git a/docs/assets/wch.jpg b/docs/assets/wch.jpg
new file mode 100644
index 00000000..ed94d048
--- /dev/null
+++ b/docs/assets/wch.jpg
Binary files differ
diff --git a/docs/en/api/api_device.rst b/docs/en/api/api_device.rst
index f44be9dd..5272b9fc 100755
--- a/docs/en/api/api_device.rst
+++ b/docs/en/api/api_device.rst
@@ -388,12 +388,26 @@ usbd_audio_set_volume
.. code-block:: C
- void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume_db);
+ void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, float volume_db);
- **busid** USB bus ID
- **ep** Endpoint to set volume
- **ch** Channel to set volume
-- **volume_db** Volume to set in decibels, range -100dB ~ 0dB
+- **volume_db** Volume to set in dB, default range -100 ~ 0
+
+usbd_audio_get_volume
+""""""""""""""""""""""""""""""""""""
+
+``usbd_audio_get_volume`` is used to get volume.
+
+.. code-block:: C
+
+ float usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch);
+
+- **busid** USB bus ID
+- **ep** Endpoint to get volume
+- **ch** Channel to get volume
+- **returns** Volume in dB, default range -100 ~ 0
usbd_audio_set_sampling_freq
""""""""""""""""""""""""""""""""""""
diff --git a/docs/en/support/index.rst b/docs/en/support/index.rst
index cc49dc4a..6c99550f 100755
--- a/docs/en/support/index.rst
+++ b/docs/en/support/index.rst
@@ -29,11 +29,6 @@ Demonstrates USB Host UVC driver with 648 * 480 YUV camera. FPS 30.
.. figure:: img/mtpdev.png
-- Device TMC class driver
-
-.. figure:: img/tmcdev1.png
-.. figure:: img/tmcdev2.png
-
- USB network class high-performance version optimization, includes CDC-NCM, CDC-RNDIS, proprietary class drivers (supports multi-packet transmission and reception), RNDIS example shown below
.. figure:: img/rndistx.png
diff --git a/docs/zh/api/api_device.rst b/docs/zh/api/api_device.rst
index 4c6617b1..ecc39a80 100644
--- a/docs/zh/api/api_device.rst
+++ b/docs/zh/api/api_device.rst
@@ -390,12 +390,27 @@ usbd_audio_set_volume
.. code-block:: C
- void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume_db);
+ void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, float volume_db);
- **busid** USB 总线 id
- **ep** 要设置音量的端点
- **ch** 要设置音量的通道
-- **volume_db** 要设置音量的分贝,单位 -100dB ~ 0dB
+- **volume_db** 要设置音量的 dB,默认范围 -100 ~ 0
+
+usbd_audio_get_volume
+""""""""""""""""""""""""""""""""""""
+
+``usbd_audio_get_volume`` 用来获取音量。
+
+.. code-block:: C
+
+ float usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch);
+
+- **busid** USB 总线 id
+- **ep** 要获取音量的端点
+- **ch** 要获取音量的通道
+- **返回** 音量的 dB,默认范围 -100 ~ 0
+
usbd_audio_set_sampling_freq
""""""""""""""""""""""""""""""""""""
diff --git a/docs/zh/api/api_host.rst b/docs/zh/api/api_host.rst
index ad93d2fb..393a6ff4 100644
--- a/docs/zh/api/api_host.rst
+++ b/docs/zh/api/api_host.rst
@@ -145,6 +145,20 @@ usbh_find_class_instance
- **devname** class 名称
- **return** class 结构体句柄
+usbh_control_transfer
+""""""""""""""""""""""""""""""""""""
+
+``usbh_control_transfer`` 用来发送控制传输请求。
+
+.. code-block:: C
+
+ int usbh_control_transfer(struct usbh_hubport *hport, struct usb_setup_packet *setup, void *buffer);
+
+- **hport** hubport 结构体句柄
+- **setup** 控制传输请求结构体指针
+- **buffer** 数据缓冲区指针
+- **return** 实际传输的数据长度或者错误码,不包含 setup 长度
+
lsusb
""""""""""""""""""""""""""""""""""""
diff --git a/docs/zh/demo/usbd_adb.rst b/docs/zh/demo/usbd_adb.rst
index 6855135d..3890d510 100644
--- a/docs/zh/demo/usbd_adb.rst
+++ b/docs/zh/demo/usbd_adb.rst
@@ -1,7 +1,7 @@
ADB Device
=================
-adb device demo 参考 `demo/adb/usbd_adb_template.c` 模板。默认适配 **cherrysh** (`platform/demo/adb/cherrysh_port.c`) 和 **rt-thread msh** (`platform/rtthread/usbd_adb_shell.c`),只需要在 main 中添加以下初始化即可。
+adb device demo 参考 `demo/adb_template.c` 模板。调用如下:
.. code-block:: C
@@ -11,11 +11,19 @@ adb device demo 参考 `demo/adb/usbd_adb_template.c` 模板。默认适配 **ch
.. figure:: img/rtt_adb_shell1.png
-进入 adb
---------------
+shell 使用
+-------------------
+
+默认支持 **cherrysh** 和 **rt-thread msh**,如果使用其他 shell,需自行适配。
+
+.. note:: 如使用 cherrysh,请将 class/adb/usbd_adb_cherrysh.c 加入到编译系统
+
+sync 使用
+-------------------
+
+默认支持 **fatfs** 和 **rt-thread dfs**。如果使用 fatfs, **需要在代码初始化之前 mount 文件系统,并且根路径为 "/" **。参考 **platform/fatfs/vfs_fatfs_port.c**。
-- 使用 **cherrysh** 时枚举完成以后自动进入 adb 模式
-- 使用 **msh** 需要在 **msh** 中输入 ``adb_enter`` 进入 adb 模式
+.. note:: 如使用 sync 功能和 fatfs,请将 class/adb/usbd_adb_sync.c,platform/fatfs/vfs_fatfs_port.c 加入到编译系统
退出 adb
--------------
diff --git a/docs/zh/quick_start/demo.rst b/docs/zh/quick_start/demo.rst
index d56839fb..9add40a4 100644
--- a/docs/zh/quick_start/demo.rst
+++ b/docs/zh/quick_start/demo.rst
@@ -14,7 +14,7 @@
* - Repo url
- USB IP
- Version
- * - https://github.com/CherryUSB/cherryusb_bouffalolab
+ * - https://github.com/bouffalolab/bouffalo_sdk
- FOTG210
- less than latest
@@ -28,11 +28,11 @@
* - Repo url
- USB IP
- Version
- * - https://github.com/CherryUSB/cherryusb_hpmicro
+ * - https://github.com/hpmicro/hpm_sdk
- CHIPIDEA
- less than latest
-基于 esp32s2/s3/p4 系列芯片(官方 SDK 支持)
+基于 ESPressif 系列芯片(官方 SDK 支持)
-------------------------------------------------
.. list-table::
@@ -105,7 +105,7 @@ ESP-Registry 可以参考官方文档,推荐使用 vscode + esp-idf 的开发�
- AIC/EHCI/OHCI
- less than latest
-基于 Kendryte canmv-k230 系列(官方 SDK 支持)
+基于 Kendryte K230 系列(官方 SDK 支持)
-----------------------------------------------
.. list-table::
@@ -115,7 +115,7 @@ ESP-Registry 可以参考官方文档,推荐使用 vscode + esp-idf 的开发�
* - Repo url
- USB IP
- Version
- * - https://github.com/CherryUSB/k230_sdk
+ * - https://www.kendryte.com/k230_rtos/zh/main/userguide/how_to_build.html
- DWC2
- less than latest
@@ -133,6 +133,20 @@ ESP-Registry 可以参考官方文档,推荐使用 vscode + esp-idf 的开发�
- MUSB
- less than latest
+基于 WCH 系列芯片
+--------------------------------------------
+
+.. list-table::
+ :widths: 10 10 10
+ :header-rows: 1
+
+ * - Repo url
+ - USB IP
+ - Version
+ * - https://github.com/CherryUSB/cherryusb_wch https://github.com/CherryUSB/wch-support-cherryusb
+ - WCH USBHS/USBFS/USBSS
+ - greater than v1.6.1
+
基于 NXP MCX 系列芯片
---------------------------
@@ -308,16 +322,6 @@ USB Host 移植要点
.. figure:: img/stm32_18.png
-基于 Actionstech 系列芯片(官方 SDK 支持)
-------------------------------------------------------
-
-Not opensource, 请联系 Actionstech 官方
-
-基于新塘系列芯片(官方 SDK 支持)
-------------------------------------------------------
-
-Not opensource, 请联系 新塘 官方
-
基于 Sophgo 系列芯片(官方 SDK 支持)
------------------------------------------------------
@@ -342,6 +346,26 @@ Not opensource, 请联系 新塘 官方
* - Repo url
- USB IP
- Version
- * - https://github.com/bekencorp/armino
+ * - https://github.com/bekencorp/bk_idk_ai
- MUSB
- equal to v0.7.0
+
+基于 Actionstech 系列芯片(官方 SDK 支持)
+------------------------------------------------------
+
+Not opensource, 请联系 Actionstech 官方
+
+基于 Nuvoton 系列芯片(官方 SDK 支持)
+------------------------------------------------------
+
+Not opensource, 请联系 Nuvoton 官方
+
+基于 AllwinnerTech 系列芯片(官方 SDK 支持)
+------------------------------------------------------
+
+Not opensource, 请联系 AllwinnerTech 官方
+
+基于 ListenAI 系列芯片(官方 SDK 支持)
+------------------------------------------------------
+
+Not opensource, 请联系 ListenAI 官方 \ No newline at end of file
diff --git a/docs/zh/quick_start/q&a.rst b/docs/zh/quick_start/q&a.rst
index 391b7037..821688ac 100644
--- a/docs/zh/quick_start/q&a.rst
+++ b/docs/zh/quick_start/q&a.rst
@@ -101,6 +101,7 @@ CONFIG_USB_HS 何时使用
----------------------------------------------------------------
当你的芯片硬件支持高速,并想初始化成高速模式时开启,相关 IP 会根据该宏配置内部或者外部 高速 PHY。
+需要注意,对于多 port 的情况,如果没有特别配置(比如某个口只支持全速,则该宏无效),否则所有 port 都会初始化成高速模式。
Failed to enable port
----------------------------------------------------------------
diff --git a/docs/zh/show/img/wch_speed.jpg b/docs/zh/show/img/wch_speed.jpg
new file mode 100644
index 00000000..e7fb6c63
--- /dev/null
+++ b/docs/zh/show/img/wch_speed.jpg
Binary files differ
diff --git a/docs/zh/show/index.rst b/docs/zh/show/index.rst
index c5d3f708..ed9e2a88 100644
--- a/docs/zh/show/index.rst
+++ b/docs/zh/show/index.rst
@@ -13,6 +13,9 @@ CDC ACM 通信
- HPM 系列(从机可以到 42MB/S, 主机 44MB/S, 已经达到硬件极限)
- BL 系列(从机 32MB/S, 主机 25MB/S, 已经达到硬件极限)
- STM32F4 全速(从机 900KB/S, 主机 1.12MB/S, 已经达到硬件极限)
+- WCH USBHS 高速(从机 46MB/S)
+
+.. figure:: img/wch_speed.jpg
从机测速demo: cdc_acm_template.c 并且关闭 log,脚本使用 `tools/test_srcipts/test_cdc_speed.py`
主机测速demo: usb_host.c 中 TEST_USBH_CDC_SPEED=1
diff --git a/docs/zh/support/img/tmcdev1.png b/docs/zh/support/img/tmcdev1.png
deleted file mode 100644
index 1eaf7155..00000000
--- a/docs/zh/support/img/tmcdev1.png
+++ /dev/null
Binary files differ
diff --git a/docs/zh/support/img/tmcdev2.png b/docs/zh/support/img/tmcdev2.png
deleted file mode 100644
index 97c8297b..00000000
--- a/docs/zh/support/img/tmcdev2.png
+++ /dev/null
Binary files differ
diff --git a/docs/zh/support/index.rst b/docs/zh/support/index.rst
index d029cbff..5e4475a3 100644
--- a/docs/zh/support/index.rst
+++ b/docs/zh/support/index.rst
@@ -59,11 +59,6 @@
.. figure:: img/mtpdev.png
-- 从机 TMC 类驱动
-
-.. figure:: img/tmcdev1.png
-.. figure:: img/tmcdev2.png
-
- USB 网卡类高性能版本优化,包含 CDC-NCM, CDC-RNDIS, 私有类驱动(支持多包发送和接收),下面举例 RNDIS
.. figure:: img/rndistx.png
diff --git a/docs/zh/version.rst b/docs/zh/version.rst
index 9e008f2f..d5019261 100644
--- a/docs/zh/version.rst
+++ b/docs/zh/version.rst
@@ -3,190 +3,257 @@
如果没有特别情况,请使用最新版本。下面只列举比较重要的更新,详细更新说明请参考 https://github.com/cherry-embedded/CherryUSB/releases。
-<= v0.10.2 初代版本
+小于等于 v0.10.2 版本
----------------------
-- **用于定基本的主从机框架,仅支持单 USB IP**。
-- **host 驱动每个 ep 占用一个 硬件 pipe,不支持动态使用硬件 pipe**。
-- 相关 porting 需要使用此版本,后续不再支持(比如 ch32,rp2040),以及旧版本pusb2 和 xhci(新版本不再提供源码)。
+- **主从机基本框架,API 定型,仅支持单个 USB IP**
+- host: **USBIP 驱动硬件 pipe 跟随 ep 固定分配,超出则无法使用**
v1.0.0 过度版本
----------------------
-- **host 支持动态使用硬件 pipe,不再固定**
+- device: usbd_ep_open 参数改成 struct usb_endpoint_descriptor
+- host: **USBIP 驱动重构,硬件 pipe 动态分配**
+- 增加 USB 专用 errorcode
v1.1.0 过度版本
----------------------
- **主从机支持多 USB IP 且要相同 IP**
-- **host 增加 bluetooth, ch340, ftdi, cp210x, asix 驱动**
-- device msc 支持多 lun,并且 CONFIG_USBDEV_MSC_BLOCK_SIZE 修改为 CONFIG_USBDEV_MSC_MAX_BUFSIZE
+- host: **增加 bluetooth, ch340, ftdi, cp210x, asix class 驱动**
+- device: **msc 支持多 lun**,并且 CONFIG_USBDEV_MSC_BLOCK_SIZE 修改为 CONFIG_USBDEV_MSC_MAX_BUFSIZE
v1.2.0
----------------------
-- **host 增加 rtl8152,cdc ncm 驱动**
-- host 增加 timer 去控制中断传输(hub修改为 timer 控制)
-- porting 增加 esp,aic 主机驱动
-- **优化 DWC2 优化代码方便阅读,并增加一些 FIFO 配置宏给用户(因为 dwc2 fifo 大小有限,以及配置方式很多,所以导出给用户配置,方便合理控制性能)**
-- 优化 ehci 驱动(qtd不再使用动态申请,绑定 qh),方便代码运行的更快
+- host: **增加 rtl8152,cdc ncm class 驱动**
+- host: 增加 timer 去控制中断传输(hub修改为 timer 控制)
+- port: **增加 esp,aic 主机驱动**
+- port: **优化 DWC2 代码方便阅读,并增加一些 FIFO 配置宏给用户(因为 dwc2 fifo 大小有限,以及配置方式很多,所以导出给用户配置,方便合理控制性能)**
+- port: 优化 ehci 驱动(qtd不再使用动态申请,绑定 qh),方便代码运行的更快,intr 传输使用统一的 qh head。
v1.3.0
----------------------
-- **device 支持多种速度描述符自动选择功能(开启 CONFIG_USBDEV_ADVANCE_DESC)**
-- device core 代码统一 ep0 buffer 的使用,用于美化代码
-- host 增加 pl2303 驱动;采用 id table 来支持多个 vid,pid;增加 user_data 给用户使用
-- host 网络 class 驱动增加 tx、rx buffer 的宏,增加 LWIP_TCPIP_CORE_LOCKING_INPUT 的使用,以便实现数据的零拷贝
-- porting 导入 bouffalo,aic,stm32f723 device驱动
-- **porting 中主机部分 urb->timeout 清0 的处理有点问题(大数据量传输时会出现 no pipe alloc 异常,主要原因是刚启动传输就完成了,还没判断 timeout就被修改为0了,没有进入 take sem 流程),此版本已修复**
-- ehci enable iaad in usbh_kill_urb,read ehci hcor offset from hccr caplength,enable ohci for ehci
+- device: **支持多种速度描述符自动选择功能(需开启 CONFIG_USBDEV_ADVANCE_DESC)**
+- device: 字符串描述符使用 string 形式
+- device: core 代码统一 ep0 buffer 的使用,用于美化代码
+- host: **增加 pl2303 驱动**
+- host: **采用 id table 来支持多个 vid,pid;增加 user_data 给用户使用**
+- host: 网络 class 驱动增加 tx、rx buffer 的宏,增加 LWIP_TCPIP_CORE_LOCKING_INPUT 的使用,以便实现数据的零拷贝
+- port: 导入 bouffalo,aic,stm32f723 device驱动
+- port: **主机部分 urb->timeout 清0 的处理有点问题(大数据量传输时会出现 no pipe alloc 异常,主要原因是刚启动传输就完成了,还没判断 timeout就被修改为0了,没有进入 take sem 流程),此版本已修复**
+- port: ehci enable iaad in usbh_kill_urb,read ehci hcor offset from hccr caplength,enable ohci for ehci
- 适配 nuttx os
v1.3.1
----------------------
-- bugfix(audio,video,cdc ecm 相关宏,结构体,api)
-- **host hub 枚举线程删除,使用 psc 线程,枚举方式更改为队列模式,取消同时枚举多个设备的功能**
-- host 扫描驱动信息和 instance 采用递归模式,删除链表扫描
-- host 网络 class 驱动优化,支持接收 16K 以上的数据(cdc ecm 不支持),采用高级 memcpy api
-- **device 协议栈中打印删除(中断中不再做打印)**
-- porting 中 musb fifo配置修改为从 fifo table 获取(此代码参考 linux),适配 es32,sunxi,beken
+- host: **hub 枚举线程删除,使用 psc 线程,枚举方式更改为队列模式,取消同时枚举多个设备的功能**
+- host: 扫描驱动信息和 instance 采用递归模式,删除链表扫描
+- host: 网络 class 驱动优化,支持接收 16K 以上的数据(cdc ecm 不支持),采用高级 memcpy api
+- device: **协议栈中打印删除(中断中不再做打印)**
+- port: **musb fifo配置修改为从 fifo table 获取(此代码参考 linux),适配 es32,sunxi,beken**
+- port: fix enter section before alloc pipe
v1.4.0
----------------------
-- **device 开始支持 remote wakeup 功能, hid request(0x21),完善 GET STATUS 请求(此版本开始可以通过 USB3CV 测试)**
-- device 增加 UF2, ADB, WEBUSB 功能; msc 增加裸机的读写 polling 功能,将读写放在 while1中执行; usbd_cdc 改名为 usbd_cdc_acm
-- host 增加 usbwifi(bl616), xbox驱动; **重构 USB3.0 枚举逻辑**
-- **host 中 cdc_acm,hid,msc,serial 传输共享 buffer,如果存在多个相同的设备会有问题,修改为单独的 buffer**
-- **porting 重构 XHCI/PUSB2 驱动,不开源**;ehci 和 ohci 文件改名;增加 remote wakeup api
-- esp 组件库支持
-- **chipidea 从机驱动支持,nxp mcx 系列主从支持**
+- device: **开始支持 remote wakeup 功能, hid request(0x21),完善 GET STATUS 请求(此版本开始可以通过 USB3CV 测试)**
+- device: **增加 UF2, ADB, WEBUSB 功能**; msc 增加裸机的读写 polling 功能,将读写放在 while1中执行; usbd_cdc 改名为 usbd_cdc_acm
+- host: **增加 usbwifi(bl616), xbox驱动**
+- host: **重构 USB3.0 枚举逻辑**
+- host: **修复 cdc_acm,hid,msc,serial 传输共享 buffer,如果存在多个相同的设备会有问题,修改为单独的 buffer**
+- port: **重构 XHCI/PUSB2 驱动,不开源**
+- port: ehci 和 ohci 文件改名
+- port: **增加 remote wakeup api**
+- port: **chipidea 从机驱动支持,nxp mcx 系列主从支持,esp32p4 支持**
- threadx os 支持
+- esp 组件库支持
v1.4.1
----------------------
-- **修复device 模式下使用多个 altsetting 时重复关闭端点问题,改成 altsetting 为0时关闭**
-- **重构主机 audio 解析描述符**
-- **增加 kinetis usbip**
-- 主机下 usbh_msc_get_maxlun 请求部分 U 盘不支持,不做错误返回
-- 主机下 usbh_hid_get_report_descriptor 导出给用户调用
+- device: **修复device 模式下使用多个 altsetting 时重复关闭端点问题,改成 altsetting 为0时关闭**
+- device: video 增加 usbd_video_stream_start_write 和 usbd_video_stream_split_transfer API,之前的 API 不再使用(占用太大)
+- host: **重构主机 audio 解析描述符,重构 usbh_audio_open api**
+- host: 主机下 usbh_msc_get_maxlun 请求部分 U 盘不支持,不做错误返回
+- host: 主机下 usbh_hid_get_report_descriptor 导出给用户调用
+- port: **增加 kinetis usbip**
- 静态代码检查
-- github action 功能
v1.4.2
----------------------
-- device 实现 USB_REQUEST_GET_INTERFACE 请求
-- **device video 传输重构,增加双缓冲功能**
-- device ecm 重构,保持和 rndis 类似 API
-- device 和 host audio 音量配置功能重构
-- host 增加 AOA 驱动
+- device: 实现 USB_REQUEST_GET_INTERFACE 请求
+- device: **video 传输继续重构,增加双缓冲功能,实现零 copy 功能**
+- device: ecm 重构,保持和 rndis 类似底层读写 API
+- device: **全面使用 usb_memcpy 替换 memcpy**
+- **device 和 host: audio 音量配置功能重构**
+- host: **增加 AOA 驱动**
+- port: **通用 OHCI 代码更新**
- 兼容 C++ 相关修改
-- fsdev 不支持 ISO 和 DWC2 高速 hub 不支持全速低速检查
-- **通用 OHCI 代码更新**
v1.4.3
----------------------
-- **device ep0 处理增加线程模式**
-- device audio feedback 宏和demo
-- device rndis 增加透传功能(无LWIP)
-- **host msc 将 scsi 初始化从枚举线程中移出,在mount阶段调用,并增加了testunity 多次尝试,兼容一部分 U 盘**
-- rp2040 主从支持
+- device: **ep0 处理增加线程模式**
+- device: 增加 audio feedback 宏和demo
+- device: rndis 增加透传功能(无LWIP)
+- device: **fix current_desc_len += p[DESC_bLength] before p+= p[DESC_bLength]**
+- host: **msc 将 scsi 初始化从枚举线程中移出,在mount阶段调用,并增加了testunity 多次尝试,兼容一部分 U 盘**
+- port: **rp2040 主从支持**
+- port: **dwc2、ehci、ohci 主机 dcache功能支持(v1.5.0 完善)**
+- port: 新增 t113、MCXA156、CH585、stm32h7r 支持
+- port: **修复 v1.4.1 中 altsetting 为0时应该关闭所有端点的问题**
- **nuttx fs,serial,net 组件支持**
-- dwc2、ehci、ohci 主机 dcache功能支持(v1.5.0 完善)
-- t113、MCXA156、CH585 、 **stm32h7r 支持**
-- 修复 v1.4.1 中 altsetting 为0时应该关闭所有端点的问题
+- 增加 usb_phyaddr2ramaddr 和 usb_ramaddr2phyaddr 宏
v1.5.0
----------------------
-- **协议栈内部全局 buffer 需要使用 USB_ALIGN_UP 对齐, 用于开启 dcache 并且不使能 nocache 时使用**
-- **完善 ehci/ohci dcache 模式下的处理**, add CONFIG_USB_EHCI_DESC_DCACHE_ENABLE for qh&qtd&itd, add CONFIG_USB_OHCI_DESC_DCACHE_ENABLE for ed&td
-- **平台代码更新,平台相关转移到 platform,增加 lvgl 键鼠支持,blackmagic 支持,filex 支持, zephyr disk支持,esp-idf netif支持**
-- **device sof callback 支持**
-- **dwc2 、fsdev st 下实现底层 API 和中断,直接调用 HAL_PCD_MSP 和 HAL_HCD_MSP,不需要用户复制粘贴**
-- **DWC2 实现 SPLIT 功能,高速模式下支持外部高速 hub 对接 FS/LS 设备**
-- liteos-m, zephyr os 支持
-- device msc 裸机读写采用变量模式,而不是ringbuffer
-- ehci qtd 使用 qtd alloc & free,节省内存,目前是 qh 携带 qtd
-- rndis/ECM device, msc demo 更新,支持 rt-thread 下免修改
+- **协议栈内部全局 buffer 需要使用 USB_ALIGN_UP 对齐, 用于开启 dcache 并且不使能 nocache ram 时使用**
+- device: **默认使能 CONFIG_USBDEV_ADVANCE_DESC**
+- device: **增加 ep0_next_state 状态记录,重构枚举过程 debug log**
+- device: msc 裸机读写采用变量模式,而不是ringbuffer
+- device: msc 支持 SCSI_CMD_SYNCHCACHE10 (0x35)
+- device: **重构 device mtp 驱动(收费使用)**
+- device: **device tmc 驱动(收费使用)**
+- device: **重构 device video 传输,直接在图像数据中填充 uvc header,达到zero memcpy**
+- host: **增加 usb_osal_thread_schedule_other api,用于在释放 class 资源之前,先释放所有 class 线程,避免释放 class 资源以后线程还在使用该 class 资源**
+- host: hid 增加 usbh_hid_get_protocol API
+- port: **完善 ehci/ohci dcache 模式下的对齐处理**, add CONFIG_USB_EHCI_DESC_DCACHE_ENABLE for qh&qtd&itd, add CONFIG_USB_OHCI_DESC_DCACHE_ENABLE for ed&td
+- port: **device sof callback 支持**
+- port: **dwc2 、fsdev 下实现底层 API 和中断,STM32 glue 直接调用 HAL_PCD_MSP 和 HAL_HCD_MSP,不再需要用户复制粘贴**
+- port: **DWC2 实现 SPLIT 功能,高速模式下支持外部高速 hub 对接 FS/LS 设备**
+- port: ehci qtd 使用 qtd alloc & free,节省内存,目前是 qh 携带 qtd
+- port: **dwc2 device 增加 dcache 支持**
+- port: **bouffalo/hpm/esp/st/nxp dcache api 支持**
+- port: N32H4/MM32F5 device 支持
+- platform: **平台代码更新,平台相关转移到 platform,增加 lvgl 键鼠支持,blackmagic 支持,filex 支持, zephyr disk支持,esp-idf netif支持**
- **memcpy 全部使用 usb_memcpy 替换,arm 库存在非对其访问问题**
-- **重构 device mtp 驱动(收费使用)**
-- **device tmc 驱动(收费使用)**
-- **重构device video 传输,直接在图像数据中填充 uvc header,达到zero memcpy**
-- **增加 usb_osal_thread_schedule_other api,用于在释放 class 资源之前,先释放所有 class 线程,避免释放 class 资源以后线程还在使用该 class 资源**
-- **dwc2 device 增加 dcache 功能,可用于 cortex-M7/ESP32P4**
-- **bouffalo/hpm/esp/st/nxp dcache api 支持**
-- ch32 device iso 更新,IP 目录重新分类
-- cmake,scons,kconfig 更新
- 使用 USB_ASSERT_MSG 对部分代码检查,全面性 warning 修复
-- N32H4/MM32F5 device 支持
-- 默认使能 CONFIG_USBDEV_ADVANCE_DESC
+- **增加 usb_osal_thread_schedule_other api,用于在释放 class 资源之前,先释放所有 class 线程,避免释放 class 资源以后线程还在使用该 class 资源**
+- liteos-m, zephyr os 支持
v1.5.1
----------------------
-- 支持 rt-thread 下使用 adb shell,host serial/device cdc_acm 对接 rtdevice 框架
-- **dwc2 增加多个 usbport 不同参数的配置功能,比如一个全速一个高速,fifo配置和phy配置不同**
-- **ehci 在控制传输中如果没有 nodata 阶段会导致 data qtd 未释放,导致内存泄漏**
-- **dwc2 读取 setup 使用 usbd_get_next_ep0_state 去判断,避免 setup 和 ep0 out 使用在 USB_OTG_DOEPINT_XFRC 状态下冲突**
-- sifli usb device 初步支持
+- host: urb interval 单位改成 ms 改成 us
+- port: **dwc2 增加多个 usbport 不同参数的配置功能(比如一个全速一个高速,fifo配置和phy配置不同),之前的 get gccfg API 作废,更新 at32,stm32,espressif glue**
+- port: **ehci 在控制传输中如果没有 nodata 阶段会导致 data qtd 未释放,导致内存泄漏,1.5.0带来的问题**
+- port: **dwc2 读取 setup 使用 usbd_get_next_ep0_state 去判断,避免 setup 和 ep0 out 在 USB_OTG_DOEPINT_XFRC 状态下冲突**
+- port: sifli usb device 初步支持
+- platform: 支持 rt-thread 下使用 adb shell,host serial/device cdc_acm 对接 rtdevice 框架
v1.5.2
----------------------
-- 对 1.5.1 下 rt-thread 组件的一些 bugfix
-- idf timer osal 替换为 esp timer,freertos timer会有启动失败的可能性;xTaskCreate 使用 xTaskCreatePinnedToCore 替换,方便多核使用
-- 主机枚举中,删除描述符溢出相关的 ASSERT 操作,改成返回错误。获取字符串描述符改成支持才获取。2 ms 延时改成 10ms,因为一些 os 使用的是 100hz,会造成延时失效
-- **dwc2 ep mult 支持,split 传输代码优化,对 split 相关的 cache 处理修改**
-- **dwc2 halt 中不能清除 USB_OTG_HCCHAR_EPDIR,reset port 中使用超时机制,防止在枚举时由于拔出而造成死等**
-- 更新 DWC2 中 at32,stm32,kendryte,espressif glue 代码
-- musb 对于标准的 IP 结构采用独立 EP 控制寄存器组,不使用 EPIDX 寄存器去控制
+- host: 主机枚举中,删除描述符溢出相关的 ASSERT 操作,改成返回错误。获取字符串描述符改成支持才获取。2 ms 延时改成 10ms,因为一些 os 使用的是 100hz,会造成延时失效
+- host: CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 默认使用 2 减少内存,只有 UVC 和UAC 使用(商业收费),所以不需要开很大
+- host: urb interval 从 u8 改 u32,最大支持 2^15 * 125us
+- port: **dwc2 ep mult 支持**
+- port: **dwc2 halt 中不能清除 USB_OTG_HCCHAR_EPDIR,会导致下次使用异常,因为当前传输还未停止**
+- port: **dwc2 reset port 中使用超时机制,防止在枚举时由于拔出而造成死等**
+- port: **优化 split 传输中 intr 传输处理和 cache 处理**
+- port: 更新 kendryte glue 代码,使用新的 dwc2 参数配置函数(v1.5.1 提供)
+- port: **musb 对于标准的 IP 结构采用独立 EP 控制寄存器组,不使用 EPIDX 寄存器去控制**
+- port: esp32p4 fs 支持
+- platform: 对 1.5.1 下 rt-thread 组件的一些 bugfix
- 删除所有 CONFIG_USBDEV_EP_NUM & CONFIG_USBHOST_PIPE_NUM,不再使用,因为 IP 本身会携带这些信息,或者厂家 SDK 提供了对应的宏
-- CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 默认使用 2 减少内存,只有 UVC 和UAC 使用(商业收费),所以不需要开很大
-- urb interval 从 u8 改 u32,最大支持 2^15 * 125us
+- idf timer osal 替换为 esp timer,freertos timer会有启动失败的可能性;xTaskCreate 使用 xTaskCreatePinnedToCore 替换,方便多核使用
v1.5.3
----------------------
+- device: **从机支持自定义 ep0 mps,仅支持商业性 IP**
+- host: **主机增加 UVC bulk支持**
+- host: 接口号匹配驱动功能
+- host: **主机分配地址功能改成循环自增模式**
+- host: 增加自定义 config index 选择
+- host: 重构 lsusb 命令
+- host: **主机控制传输增加 retry 机制,部分 device 通信不稳定,retry 次数参考 linux**
+- host: 主机 rndis 驱动增加非标 02/02/ff 接口驱动匹配规则
+- port: **musb IP 关闭 multipoint feature 支持**
+- port: **hpmicro、chipidea device dcache 支持**
+- port: 更新 hc32 glue 代码,使用新的 dwc2 参数配置函数(v1.5.1 提供)
+- port: **musb pipe 使用动态分配**
+- platform: **idf host msc 支持**
+- **otg: otg 框架重构,当前 port 仅支持 hpmicro**
+- CI 编译功能,支持 hpmicro,espressif,bouffalolab
- 增加 mongoose demo
-- **从机支持自定义 ep0 mps,仅支持商业性 IP**
-- 主机增加 UVC bulk支持, **接口号匹配驱动功能**, **主机分配地址功能改成循环自增模式** ,重构 lsusb 命令
-- 主机控制传输增加 retry 机制,部分 device 通信不稳定,retry 次数参考 linux
-- **主机 rndis 驱动增加非标 02/02/ff 接口驱动匹配**
-- musb IP 关闭 multipoint feature 支持
-- hpmicro、chipidea dcache 支持
-- idf host msc 支持
-- otg 框架重构,当前 port 仅支持 hpmicro
-- CI 编译功能,支持 hpmicro/espressif/bouffalolab
v1.5.3.99
----------------------
-bugfix for v1.5.3
+bugfix for v1.5.3。
+.. note:: 从这个版本开始,可以全面使用 dcache ram 取代 nocache ram,需要打开 **CONFIG_USB_DCACHE_ENABLE** 并配置 **CONFIG_USB_ALIGN_SIZE**
v1.6.0
----------------------
-- **host 增加 serial 框架,统一所有类串口驱动**
-- **host hid 增加报告描述符解析功能**
-- usbh_initialize 增加 event callback,用于通知用户主机事件变化,通常不需要使用,设置为 NULL 即可
-- 支持 gamepad device
-- 增加 ti xmc,infineon edge e8x port 支持
-- dwc2 增加 usbd_dwc2_get_system_clock 替换 SystemCoreClock;删除 __UNALIGNED_UINT32_READ 和 __UNALIGNED_UINT32_WRITE 宏;读取 setup 个数设置为 1个;第一次读取 setup 移动到 USB_OTG_GINTSTS_ENUMDNE 中断中
-- dwc2/ehci 增加 roothub 速度设置
+- device: **支持 gamepad device**
+- host: **增加 serial 框架,统一所有类串口驱动**
+- host: **增加 hid 报告描述符解析功能**
+- host: **usbh_initialize 增加 event callback,用于通知用户主机事件变化,通常不需要使用,设置为 NULL 即可**
+- port: **增加 ti xmc,infineon edge e8x port 支持**
+- port: dwc2 增加 usbd_dwc2_get_system_clock 替换 SystemCoreClock;删除 __UNALIGNED_UINT32_READ 和 __UNALIGNED_UINT32_WRITE 宏;读取 setup 个数设置为 1个;第一次读取 setup 移动到 USB_OTG_GINTSTS_ENUMDNE 中断中
+- port: dwc2/ehci 增加 roothub 速度设置
v1.6.1
----------------------
-- 新增 USB 副屏驱动
-- 重构 DFU device 驱动
-- 重构主机报告描述符解析驱动
-- cherryrb 和 cherrymp 组件内置
-- 主机 hub 线程释放改成使用 mq 替代互斥锁
-- 部分 bugfix 和安全性代码检查 \ No newline at end of file
+- device: **新增 USB 副屏驱动**
+- device: **重构 DFU device 驱动**
+- host: **重构 hid 报告描述符解析功能**
+- host: **主机 hub 线程释放改成使用 mq 退出,替代互斥锁**
+- host: **fix desc length parse**
+- port: **hpmicro: using sutw semaphore by isr handler for setup**
+- port: dwc2: add critical section for hc frame setting, make it more safely
+- platform: rtthread 文件添加 rt 前缀
+- **cherryrb 和 cherrymp 组件内置**
+- 部分 bugfix 和安全性代码检查
+
+v1.7.0
+----------------------
+
+- **新增注册驱动 API,从这个版本开始可以同时使用多个不同的 USBIP**
+- device: **新增 cdc ncm class 驱动**
+- device: **新增 tmc class 驱动**
+- device: **新增 usb3.0 request 和配置**
+- device: **重构 adb 驱动,添加 shell 和 sync 支持,并且不再支持裸机,os only**
+- device: **audio 新增 usbd_audio_get_volume_range,volume 读写改成 float 类型**
+- device: 新增获取 speed 和 ep info api
+- device: **新增 usb_vfs api, posix 标准接口**
+- device: msc 支持 SCSI_readCapacity16 命令
+- host: **重构 audio 驱动和 API,volume 配置范围改成 0~ 100,audio sample rate 最大支持 8个默认**
+- host: **serial 增加 RX 流控**
+- host: **简化 net class rx 接收,最大不再超过 16K**
+- host: **rndis msg resp 处理统一到 usbh_rndis_parse_resp**
+- host: rndis 驱动增加 Android RNDIS class code (0xEF/0x04/0x01) 匹配规则
+- host: 修复 hid API 漏掉的 **hport->intf**
+- host: only release hport in disconnect
+- port: **renesas 从机支持**
+- port: **esp32s31 支持**
+- port: **N32H49X和N32H7XX USBHS 支持**
+- port: **N32H4x (N32H47x_48x / N32H49x) FSDEV 支持**
+- port: **删除旧版本 wch 驱动,重构 usbfs,usbhs 主从驱动支持**
+- port: 统一 cache 处理到 usbh_submit_urb
+- port: 将部分 glue 文件放到厂家文件夹中
+- port: 修复 ehci setup cache 和 qh,qtd cache 处理
+- port: **fix usbd_ep_close for out ep, set global nak first then can disable ep**
+- port: **musb 增加 sifli 自定义 pipe 申请规则,修复 usbh_kill_urb 时错误关闭 ep0 中断和 flush 错误问题**
+- port: low level api from weak to extern, 防止用户没有实现而使用 weak api
+- platform: **zmk 支持**
+- platform: **zephyr 主机多 msc 设备支持**
+- platform: fix idf fatfs 旧版本兼容
+- platform: 修复 rtthread 驱动旧版本支持
+- platform: **rtthread adb shell 和 sync 支持**
+- **demo 删除 CONFIG_USB_HS,新增 config fs,hs 和 other speed 支持**
+- **video 宏中的 frame interval 改成只支持一个**
+- 新增 AUDIO_FEEDBACK_TO_BUF_HS_INTERVAL/AUDIO_FEEDBACK_TO_BUF_FS_INTERVAL 宏
+- 更新 usb 测速工具
+- CI 功能新增 wch,sifli,phytium 支持
+- osal 的部分修复
+- 安全性代码检查 \ No newline at end of file
diff --git a/osal/idf/usb_osal_idf.c b/osal/idf/usb_osal_idf.c
index 69f734e8..7cf9ab45 100644
--- a/osal/idf/usb_osal_idf.c
+++ b/osal/idf/usb_osal_idf.c
@@ -45,7 +45,7 @@ usb_osal_sem_t usb_osal_sem_create(uint32_t initial_count)
usb_osal_sem_t usb_osal_sem_create_counting(uint32_t max_count)
{
- return (usb_osal_sem_t)xSemaphoreCreateCounting(0, max_count);
+ return (usb_osal_sem_t)xSemaphoreCreateCounting(max_count, 0);
}
void usb_osal_sem_delete(usb_osal_sem_t sem)
diff --git a/osal/usb_osal_freertos.c b/osal/usb_osal_freertos.c
index f1ebf7fc..ed145291 100644
--- a/osal/usb_osal_freertos.c
+++ b/osal/usb_osal_freertos.c
@@ -57,11 +57,22 @@ void usb_osal_sem_delete(usb_osal_sem_t sem)
int usb_osal_sem_take(usb_osal_sem_t sem, uint32_t timeout)
{
- if (timeout == USB_OSAL_WAITING_FOREVER) {
- return (xSemaphoreTake((SemaphoreHandle_t)sem, portMAX_DELAY) == pdPASS) ? 0 : -USB_ERR_TIMEOUT;
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+ int ret;
+
+ if (xPortIsInsideInterrupt()) {
+ /* ISR context: only non-blocking take is allowed */
+ ret = xSemaphoreTakeFromISR((SemaphoreHandle_t)sem, &xHigherPriorityTaskWoken);
+ if (ret == pdPASS) {
+ portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+ }
+ } else if (timeout == USB_OSAL_WAITING_FOREVER) {
+ ret = xSemaphoreTake((SemaphoreHandle_t)sem, portMAX_DELAY);
} else {
- return (xSemaphoreTake((SemaphoreHandle_t)sem, pdMS_TO_TICKS(timeout)) == pdPASS) ? 0 : -USB_ERR_TIMEOUT;
+ ret = xSemaphoreTake((SemaphoreHandle_t)sem, pdMS_TO_TICKS(timeout));
}
+
+ return (ret == pdPASS) ? 0 : -USB_ERR_TIMEOUT;
}
int usb_osal_sem_give(usb_osal_sem_t sem)
@@ -206,7 +217,17 @@ void usb_osal_timer_start(struct usb_osal_timer *timer)
void usb_osal_timer_stop(struct usb_osal_timer *timer)
{
- xTimerStop(timer->timer, 0);
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+ int ret;
+
+ if (xPortIsInsideInterrupt()) {
+ ret = xTimerStopFromISR(timer->timer, &xHigherPriorityTaskWoken);
+ if (ret == pdPASS) {
+ portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+ }
+ } else {
+ xTimerStop(timer->timer, 0);
+ }
}
size_t usb_osal_enter_critical_section(void)
diff --git a/osal/usb_osal_rtthread.c b/osal/usb_osal_rtthread.c
index d649bba3..593ba194 100644
--- a/osal/usb_osal_rtthread.c
+++ b/osal/usb_osal_rtthread.c
@@ -24,8 +24,12 @@ usb_osal_thread_t usb_osal_thread_create(const char *name, uint32_t stack_size,
void usb_osal_thread_delete(usb_osal_thread_t thread)
{
if (thread == NULL) {
+#if (RTTHREAD_VERSION >= RT_VERSION_CHECK(3, 1, 5))
rt_thread_t self = rt_thread_self();
rt_thread_control(self, RT_THREAD_CTRL_CLOSE, RT_NULL);
+#else
+ rt_thread_exit();
+#endif
return;
}
diff --git a/osal/usb_osal_zephyr.c b/osal/usb_osal_zephyr.c
index fe2dc641..6b2a0fa4 100644
--- a/osal/usb_osal_zephyr.c
+++ b/osal/usb_osal_zephyr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, sakumisu
+ * Copyright (c) 2025-2026 sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -48,8 +48,12 @@ usb_osal_thread_t usb_osal_thread_create(const char *name, uint32_t stack_size,
static void release_thread_handler(struct k_work *work)
{
struct release_thread_work *release_work = (struct release_thread_work *)work;
- k_free(release_work->thread);
- k_work_cancel(work);
+
+ /* The workqueue may preempt the thread that queued this work. Wait until
+ * k_thread_abort() has completed before freeing its TCB and stack. */
+ if (k_thread_join(release_work->thread, K_FOREVER) == 0) {
+ k_free(release_work->thread);
+ }
k_free(release_work);
}
@@ -63,6 +67,10 @@ void usb_osal_thread_delete(usb_osal_thread_t thread)
thread = z_current_get();
#endif
release_work = k_malloc(sizeof(struct release_thread_work));
+ if (release_work == NULL) {
+ k_thread_abort(thread);
+ return;
+ }
release_work->thread = thread;
k_work_init(&release_work->work, release_thread_handler);
k_work_submit(&release_work->work);
@@ -309,4 +317,4 @@ void *usb_osal_malloc(size_t size)
void usb_osal_free(void *ptr)
{
k_free(ptr);
-} \ No newline at end of file
+}
diff --git a/platform/blackmagic/bmp_port_cdc_acm.c b/platform/blackmagic/bmp_port_cdc_acm.c
index ae4e5457..e1353d66 100644
--- a/platform/blackmagic/bmp_port_cdc_acm.c
+++ b/platform/blackmagic/bmp_port_cdc_acm.c
@@ -9,24 +9,16 @@
#include "usbd_cdc_acm.h"
#include "general.h"
#include "gdb_if.h"
-#include "hpm_l1c_drv.h"
+
+#define USBD_VID 0xffff
+#define USBD_PID 0xffff
+#define USBD_MAX_POWER 100
+#define USBD_LANGID_STRING 1033
#define CDC_IN_EP 0x81
#define CDC_OUT_EP 0x01
#define CDC_INT_EP 0x83
-#define CDC_MAX_PACKET_SIZE 512
-
-#ifdef CONFIG_USB_HS
-#if CDC_MAX_PACKET_SIZE != 512
-#error "CDC_MAX_PACKET_SIZE must be 512 in hs"
-#endif
-#else
-#if CDC_MAX_PACKET_SIZE != 64
-#error "CDC_MAX_PACKET_SIZE must be 64 in fs"
-#endif
-#endif
-
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN)
diff --git a/platform/daplink/dap_main.c b/platform/daplink/dap_main.c
index 27e0355b..b145c223 100644
--- a/platform/daplink/dap_main.c
+++ b/platform/daplink/dap_main.c
@@ -335,17 +335,16 @@ static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t USB_Request[DAP_PACKET_COU
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t USB_Response[DAP_PACKET_COUNT][DAP_PACKET_SIZE]; // Response Buffer
static uint16_t USB_RespSize[DAP_PACKET_COUNT]; // Response Size
-volatile struct cdc_line_coding g_cdc_lincoding;
-volatile uint8_t config_uart = 0;
-volatile uint8_t config_uart_transfer = 0;
-
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t uartrx_ringbuffer[CONFIG_UARTRX_RINGBUF_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usbrx_ringbuffer[CONFIG_USBRX_RINGBUF_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usb_tmpbuffer[DAP_PACKET_SIZE];
+static volatile struct cdc_line_coding g_cdc_lincoding;
+static volatile uint8_t config_uart = 0;
+static volatile uint8_t config_uart_transfer = 0;
static volatile uint8_t usbrx_idle_flag = 0;
-static volatile uint8_t usbtx_idle_flag = 0;
-static volatile uint8_t uarttx_idle_flag = 0;
+static volatile uint8_t usbtx_idle_flag = 1;
+static volatile uint8_t uarttx_idle_flag = 1;
USB_NOCACHE_RAM_SECTION chry_ringbuffer_t g_uartrx;
USB_NOCACHE_RAM_SECTION chry_ringbuffer_t g_usbrx;
@@ -356,9 +355,6 @@ void usbd_event_handler(uint8_t busid, uint8_t event)
switch (event) {
case USBD_EVENT_RESET:
usbrx_idle_flag = 0;
- usbtx_idle_flag = 0;
- uarttx_idle_flag = 0;
- config_uart_transfer = 0;
break;
case USBD_EVENT_CONNECTED:
break;
@@ -437,20 +433,13 @@ void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
(void)busid;
- uint32_t size;
- uint8_t *buffer;
chry_ringbuffer_linear_read_done(&g_uartrx, nbytes);
if ((nbytes % DAP_PACKET_SIZE) == 0 && nbytes) {
/* send zlp */
usbd_ep_start_write(0, CDC_IN_EP, NULL, 0);
} else {
- if (chry_ringbuffer_get_used(&g_uartrx)) {
- buffer = chry_ringbuffer_linear_read_setup(&g_uartrx, &size);
- usbd_ep_start_write(0, CDC_IN_EP, buffer, size);
- } else {
- usbtx_idle_flag = 1;
- }
+ usbtx_idle_flag = 1;
}
}
@@ -624,7 +613,8 @@ void chry_dap_handle(void)
void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding)
{
(void)busid;
- if (memcmp(line_coding, (uint8_t *)&g_cdc_lincoding, sizeof(struct cdc_line_coding)) != 0) {
+
+ if (memcmp((uint8_t *)&g_cdc_lincoding, line_coding, sizeof(struct cdc_line_coding)) != 0 && line_coding->dwDTERate != 0) {
memcpy((uint8_t *)&g_cdc_lincoding, line_coding, sizeof(struct cdc_line_coding));
config_uart = 1;
config_uart_transfer = 0;
@@ -642,6 +632,10 @@ void chry_dap_usb2uart_handle(void)
uint32_t size;
uint8_t *buffer;
+ if (usb_device_is_configured(0) == 0) {
+ return;
+ }
+
if (config_uart) {
/* disable irq here */
config_uart = 0;
@@ -700,16 +694,9 @@ __WEAK void chry_dap_usb2uart_uart_config_callback(struct cdc_line_coding *line_
/* called by user */
void chry_dap_usb2uart_uart_send_complete(uint32_t size)
{
- uint8_t *buffer;
-
chry_ringbuffer_linear_read_done(&g_usbrx, size);
- if (chry_ringbuffer_get_used(&g_usbrx)) {
- buffer = chry_ringbuffer_linear_read_setup(&g_usbrx, &size);
- chry_dap_usb2uart_uart_send_bydma(buffer, size);
- } else {
- uarttx_idle_flag = 1;
- }
+ uarttx_idle_flag = 1;
}
/* implment by user */
@@ -746,4 +733,4 @@ int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length)
memcpy(mass_block[sector].BlockSpace, buffer, length);
return 0;
}
-#endif
+#endif \ No newline at end of file
diff --git a/platform/fatfs/usbd_fatfs_mtp.c b/platform/fatfs/usbd_fatfs_mtp.c
deleted file mode 100644
index 8126e3d5..00000000
--- a/platform/fatfs/usbd_fatfs_mtp.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (c) 2025, sakumisu
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#include "ff.h"
-#include "diskio.h"
-#include "usbd_core.h"
-#include "usb_osal.h"
-#include "usbd_mtp.h"
-
-FATFS s_sd_disk;
-FIL s_file;
-BYTE work[FF_MAX_SS];
-
-const TCHAR driver_num_buf[3] = { '0', ':', '\0' };
-
-const char *show_error_string(FRESULT fresult);
-
-static FRESULT sd_mount_fs(void)
-{
- FRESULT fresult = f_mount(&s_sd_disk, driver_num_buf, 1);
- if (fresult == FR_OK) {
- printf("SD card has been mounted successfully\n");
- } else {
- printf("Failed to mount SD card, cause: %s\n", show_error_string(fresult));
- }
-
- return fresult;
-}
-
-#if 0
-static FRESULT sd_mkfs(void)
-{
- printf("Formatting the SD card, depending on the SD card capacity, the formatting process may take a long time\n");
- FRESULT fresult = f_mkfs(driver_num_buf, NULL, work, sizeof(work));
- if (fresult != FR_OK) {
- printf("Making File system failed, cause: %s\n", show_error_string(fresult));
- } else {
- printf("Making file system is successful\n");
- }
-
- return fresult;
-}
-#endif
-
-static FRESULT sd_write_file(void)
-{
- FRESULT fresult = f_open(&s_file, "0:/readme.txt", FA_WRITE | FA_CREATE_ALWAYS);
- if (fresult != FR_OK) {
- printf("Create new file failed, cause: %d\n", show_error_string(fresult));
- } else {
- printf("Create new file successfully, status=%d\n", fresult);
- }
- char hello_str[] = "Hello, this is SD card FATFS demo\n";
- UINT byte_written;
- fresult = f_write(&s_file, hello_str, sizeof(hello_str), &byte_written);
- if (fresult != FR_OK) {
- printf("Write file failed, cause: %s\n", show_error_string(fresult));
- } else {
- printf("Write file operation is successfully\n");
- }
-
- f_close(&s_file);
-
- return fresult;
-}
-
-const char *show_error_string(FRESULT fresult)
-{
- const char *result_str;
-
- switch (fresult) {
- case FR_OK:
- result_str = "succeeded";
- break;
- case FR_DISK_ERR:
- result_str = "A hard error occurred in the low level disk I/O level";
- break;
- case FR_INT_ERR:
- result_str = "Assertion failed";
- break;
- case FR_NOT_READY:
- result_str = "The physical drive cannot work";
- break;
- case FR_NO_FILE:
- result_str = "Could not find the file";
- break;
- case FR_NO_PATH:
- result_str = "Could not find the path";
- break;
- case FR_INVALID_NAME:
- result_str = "Tha path name format is invalid";
- break;
- case FR_DENIED:
- result_str = "Access denied due to prohibited access or directory full";
- break;
- case FR_EXIST:
- result_str = "Access denied due to prohibited access";
- break;
- case FR_INVALID_OBJECT:
- result_str = "The file/directory object is invalid";
- break;
- case FR_WRITE_PROTECTED:
- result_str = "The physical drive is write protected";
- break;
- case FR_INVALID_DRIVE:
- result_str = "The logical driver number is invalid";
- break;
- case FR_NOT_ENABLED:
- result_str = "The volume has no work area";
- break;
- case FR_NO_FILESYSTEM:
- result_str = "There is no valid FAT volume";
- break;
- case FR_MKFS_ABORTED:
- result_str = "THe f_mkfs() aborted due to any problem";
- break;
- case FR_TIMEOUT:
- result_str = "Could not get a grant to access the volume within defined period";
- break;
- case FR_LOCKED:
- result_str = "The operation is rejected according to the file sharing policy";
- break;
- case FR_NOT_ENOUGH_CORE:
- result_str = "LFN working buffer could not be allocated";
- break;
- case FR_TOO_MANY_OPEN_FILES:
- result_str = "Number of open files > FF_FS_LOCK";
- break;
- case FR_INVALID_PARAMETER:
- result_str = "Given parameter is invalid";
- break;
- default:
- result_str = "Unknown error";
- break;
- }
- return result_str;
-}
-
-const char *usbd_mtp_fs_root_path(void)
-{
- return driver_num_buf;
-}
-
-const char *usbd_mtp_fs_description(void)
-{
- return "CherryUSB MTP";
-}
-
-int usbd_mtp_mkdir(const char *path)
-{
- FRESULT result = f_mkdir(path);
- if (result != FR_OK) {
- printf("f_mkdir failed, cause: %s\n", show_error_string(result));
- return -1;
- }
- return 0; // Directory created successfully
-}
-
-int usbd_mtp_rmdir(const char *path)
-{
- FRESULT result = f_rmdir(path);
- if (result != FR_OK) {
- printf("f_mkdir failed, cause: %s\n", show_error_string(result));
- return -1;
- }
- return 0; // Directory created successfully
-}
-
-MTP_DIR *usbd_mtp_opendir(const char *name)
-{
- FRESULT result;
- DIR *dir;
-
- dir = usb_osal_malloc(sizeof(DIR));
- result = f_opendir(dir, name);
- if (result != FR_OK) {
- printf("f_opendir failed, cause: %s\n", show_error_string(result));
- usb_osal_free(dir);
- return NULL; // Failed to open directory
- }
- return (MTP_DIR *)dir;
-}
-
-int usbd_mtp_closedir(MTP_DIR *dir)
-{
- FRESULT result;
- result = f_closedir((DIR *)dir);
- if (result != FR_OK) {
- printf("f_closedir failed, cause: %s\n", show_error_string(result));
- return -1; // Failed to close directory
- }
- usb_osal_free(dir); // Free the directory structure
- return result;
-}
-
-struct mtp_dirent *usbd_mtp_readdir(MTP_DIR *dir)
-{
- FILINFO fno;
- FRESULT result;
-
- result = f_readdir((DIR *)dir, &fno);
- if (result != FR_OK || fno.fname[0] == 0)
- return NULL;
-
- static struct mtp_dirent dirent;
- memset(&dirent, 0, sizeof(struct mtp_dirent));
- strncpy(dirent.d_name, fno.fname, sizeof(dirent.d_name) - 1);
- dirent.d_name[sizeof(dirent.d_name) - 1] = '\0';
- dirent.d_namlen = strlen(dirent.d_name);
-
- return &dirent;
-}
-
-#undef SS
-#if FF_MAX_SS == FF_MIN_SS
-#define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */
-#else
-#define SS(fs) ((fs)->ssize) /* Variable sector size */
-#endif
-
-int usbd_mtp_stat(const char *path, struct mtp_stat *buf)
-{
- FILINFO file_info;
- FRESULT result;
- FATFS *f;
- f = &s_sd_disk;
-
- result = f_stat(path, &file_info);
- if (result != FR_OK) {
- printf("f_stat failed, cause: %s\n", show_error_string(result));
- return -1;
- }
- buf->st_mode = MTP_S_IFREG | MTP_S_IRUSR | MTP_S_IRGRP | MTP_S_IROTH |
- MTP_S_IWUSR | MTP_S_IWGRP | MTP_S_IWOTH;
- if (file_info.fattrib & AM_DIR) {
- buf->st_mode &= ~MTP_S_IFREG;
- buf->st_mode |= MTP_S_IFDIR | MTP_S_IXUSR | MTP_S_IXGRP | MTP_S_IXOTH;
- }
- if (file_info.fattrib & AM_RDO)
- buf->st_mode &= ~(MTP_S_IWUSR | MTP_S_IWGRP | MTP_S_IWOTH);
-
- buf->st_size = file_info.fsize;
- buf->st_blksize = f->csize * SS(f);
- if (file_info.fattrib & AM_ARC) {
- buf->st_blocks = file_info.fsize ? ((file_info.fsize - 1) / SS(f) / f->csize + 1) : 0;
- buf->st_blocks *= (buf->st_blksize / 512); // man say st_blocks is number of 512B blocks allocated
- } else {
- buf->st_blocks = f->csize;
- }
- return 0;
-}
-
-int usbd_mtp_statfs(const char *path, struct mtp_statfs *buf)
-{
- FATFS *f;
- FRESULT res;
- DWORD fre_clust, fre_sect, tot_sect;
-
- f = &s_sd_disk;
-
- res = f_getfree(path, &fre_clust, &f);
- if (res != FR_OK) {
- printf("f_getfree failed, cause: %s\n", show_error_string(res));
- return -1;
- }
- tot_sect = (f->n_fatent - 2) * f->csize;
- fre_sect = fre_clust * f->csize;
-
- buf->f_blocks = tot_sect;
- buf->f_bfree = fre_sect;
-#if FF_MAX_SS != FF_MIN_SS
- buf->f_bsize = f->ssize;
-#else
- buf->f_bsize = FF_MIN_SS;
-#endif
- return 0;
-}
-
-int usbd_mtp_open(const char *path, uint8_t mode)
-{
- BYTE flags;
-
- if (mode == MTP_O_RDONLY) {
- flags = FA_READ | FA_OPEN_EXISTING;
- } else if (mode == MTP_O_WRONLY) {
- flags = FA_WRITE | FA_OPEN_ALWAYS;
- } else if (mode == MTP_O_RDWR) {
- flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
- } else {
- return -1; // Invalid mode
- }
-
- FRESULT result = f_open(&s_file, path, flags);
- if (result != FR_OK) {
- printf("f_open failed, cause: %s\n", show_error_string(result));
- return -1;
- }
- return 0;
-}
-
-int usbd_mtp_close(int fd)
-{
- FRESULT result = f_close(&s_file);
- if (result != FR_OK) {
- printf("f_close failed, cause: %s\n", show_error_string(result));
- return -1;
- }
- return 0;
-}
-
-int usbd_mtp_read(int fd, void *buf, size_t len)
-{
- UINT bytes_read;
- FRESULT result = f_read(&s_file, buf, len, &bytes_read);
- if (result != FR_OK) {
- printf("f_read failed, cause: %s\n", show_error_string(result));
- return -1;
- }
- return bytes_read; // Return number of bytes read
-}
-
-int usbd_mtp_write(int fd, const void *buf, size_t len)
-{
- UINT bytes_written;
- FRESULT result = f_write(&s_file, buf, len, &bytes_written);
- if (result != FR_OK) {
- printf("f_write failed, cause: %s\n", show_error_string(result));
- return -1;
- }
- return bytes_written; // Return number of bytes written
-}
-
-int usbd_mtp_unlink(const char *path)
-{
- FRESULT result = f_unlink(path);
- if (result != FR_OK) {
- printf("f_unlink failed, cause: %s\n", show_error_string(result));
- return -1;
- }
- return 0; // File deleted successfully
-}
-
-void usbd_mtp_mount()
-{
- sd_mount_fs();
-
- // write a file to test the SD card
- sd_write_file();
-}
diff --git a/platform/fatfs/usbh_fatfs.c b/platform/fatfs/usbh_fatfs.c
index abb7181b..9c799d62 100644
--- a/platform/fatfs/usbh_fatfs.c
+++ b/platform/fatfs/usbh_fatfs.c
@@ -14,12 +14,17 @@ int USB_disk_initialize(void)
{
active_msc_class = (struct usbh_msc *)usbh_find_class_instance("/dev/sda");
if (active_msc_class == NULL) {
- printf("do not find /dev/sda\r\n");
+ USB_LOG_ERR("do not find /dev/sda\r\n");
return RES_NOTRDY;
}
if (usbh_msc_scsi_init(active_msc_class) < 0) {
return RES_NOTRDY;
}
+
+ if ((active_msc_class->blocksize < FF_MIN_SS) || (active_msc_class->blocksize > FF_MAX_SS)) {
+ USB_LOG_ERR("unsupported block size %u\r\n", (unsigned int)active_msc_class->blocksize);
+ return RES_NOTRDY;
+ }
return RES_OK;
}
@@ -38,7 +43,7 @@ int USB_disk_read(BYTE *buff, LBA_t sector, UINT count)
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
align_buf = (uint8_t *)aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * active_msc_class->blocksize);
if (!align_buf) {
- printf("msc get align buf failed\r\n");
+ USB_LOG_ERR("msc get align buf failed\r\n");
return -USB_ERR_NOMEM;
}
}
@@ -68,7 +73,7 @@ int USB_disk_write(const BYTE *buff, LBA_t sector, UINT count)
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
align_buf = (uint8_t *)aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * active_msc_class->blocksize);
if (!align_buf) {
- printf("msc get align buf failed\r\n");
+ USB_LOG_ERR("msc get align buf failed\r\n");
return -USB_ERR_NOMEM;
}
usb_memcpy(align_buf, buff, count * active_msc_class->blocksize);
diff --git a/platform/fatfs/vfs_fatfs_port.c b/platform/fatfs/vfs_fatfs_port.c
new file mode 100644
index 00000000..efb14d33
--- /dev/null
+++ b/platform/fatfs/vfs_fatfs_port.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2024 ~ 2026, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "ff.h"
+#include "diskio.h"
+#include "usbd_core.h"
+#include "usb_vfs.h"
+
+FATFS s_sd_disk;
+FIL s_file;
+BYTE work[FF_MAX_SS];
+
+const TCHAR driver_num_buf[4] = { DEV_SD + '0', ':', '/', '\0' };
+
+static const char *show_error_string(FRESULT fresult);
+
+static FRESULT sd_mount_fs(void)
+{
+ FRESULT fresult = f_mount(&s_sd_disk, driver_num_buf, 1);
+ if (fresult == FR_OK) {
+ printf("SD card has been mounted successfully\n");
+ } else {
+ printf("Failed to mount SD card, cause: %s\n", show_error_string(fresult));
+ }
+
+ fresult = f_chdrive(driver_num_buf);
+ return fresult;
+}
+
+#if 0
+static FRESULT sd_mkfs(void)
+{
+ printf("Formatting the SD card, depending on the SD card capacity, the formatting process may take a long time\n");
+ FRESULT fresult = f_mkfs(driver_num_buf, NULL, work, sizeof(work));
+ if (fresult != FR_OK) {
+ printf("Making File system failed, cause: %s\n", show_error_string(fresult));
+ } else {
+ printf("Making file system is successful\n");
+ }
+
+ return fresult;
+}
+#endif
+
+static FRESULT sd_write_file(void)
+{
+ FRESULT fresult = f_open(&s_file, "readme.txt", FA_WRITE | FA_CREATE_ALWAYS);
+ if (fresult != FR_OK) {
+ printf("Create new file failed, cause: %s\n", show_error_string(fresult));
+ } else {
+ printf("Create new file successfully, status=%d\n", fresult);
+ }
+ char hello_str[] = "Hello, this is SD card FATFS demo\n";
+ UINT byte_written;
+ fresult = f_write(&s_file, hello_str, sizeof(hello_str), &byte_written);
+ if (fresult != FR_OK) {
+ printf("Write file failed, cause: %s\n", show_error_string(fresult));
+ } else {
+ printf("Write file operation is successfully\n");
+ }
+
+ f_close(&s_file);
+
+ return fresult;
+}
+
+static const char *show_error_string(FRESULT fresult)
+{
+ const char *result_str;
+
+ switch (fresult) {
+ case FR_OK:
+ result_str = "succeeded";
+ break;
+ case FR_DISK_ERR:
+ result_str = "A hard error occurred in the low level disk I/O level";
+ break;
+ case FR_INT_ERR:
+ result_str = "Assertion failed";
+ break;
+ case FR_NOT_READY:
+ result_str = "The physical drive cannot work";
+ break;
+ case FR_NO_FILE:
+ result_str = "Could not find the file";
+ break;
+ case FR_NO_PATH:
+ result_str = "Could not find the path";
+ break;
+ case FR_INVALID_NAME:
+ result_str = "Tha path name format is invalid";
+ break;
+ case FR_DENIED:
+ result_str = "Access denied due to prohibited access or directory full";
+ break;
+ case FR_EXIST:
+ result_str = "Access denied due to prohibited access";
+ break;
+ case FR_INVALID_OBJECT:
+ result_str = "The file/directory object is invalid";
+ break;
+ case FR_WRITE_PROTECTED:
+ result_str = "The physical drive is write protected";
+ break;
+ case FR_INVALID_DRIVE:
+ result_str = "The logical driver number is invalid";
+ break;
+ case FR_NOT_ENABLED:
+ result_str = "The volume has no work area";
+ break;
+ case FR_NO_FILESYSTEM:
+ result_str = "There is no valid FAT volume";
+ break;
+ case FR_MKFS_ABORTED:
+ result_str = "THe f_mkfs() aborted due to any problem";
+ break;
+ case FR_TIMEOUT:
+ result_str = "Could not get a grant to access the volume within defined period";
+ break;
+ case FR_LOCKED:
+ result_str = "The operation is rejected according to the file sharing policy";
+ break;
+ case FR_NOT_ENOUGH_CORE:
+ result_str = "LFN working buffer could not be allocated";
+ break;
+ case FR_TOO_MANY_OPEN_FILES:
+ result_str = "Number of open files > FF_FS_LOCK";
+ break;
+ case FR_INVALID_PARAMETER:
+ result_str = "Given parameter is invalid";
+ break;
+ default:
+ result_str = "Unknown error";
+ break;
+ }
+ return result_str;
+}
+
+const char *vfs_get_fs_root_path(void)
+{
+ return "/";
+}
+
+const char *vfs_get_fs_description(void)
+{
+ return "CherryUSB VFS FATFS";
+}
+
+/* -------------------------------------------------------------------------
+ * helpers
+ * ---------------------------------------------------------------------- */
+
+/** FatFs result -> VFS_ERR_*, so the host gets a readable reason. */
+static int adb_err(FRESULT fr)
+{
+ switch (fr) {
+ case FR_OK:
+ return 0;
+ case FR_NO_FILE:
+ case FR_NO_PATH:
+ return VFS_ERR_NOENT;
+ case FR_EXIST:
+ return VFS_ERR_EXIST;
+ case FR_INVALID_NAME:
+ return VFS_ERR_INVAL;
+ case FR_INVALID_PARAMETER:
+ return VFS_ERR_INVAL;
+ case FR_INVALID_OBJECT:
+ return VFS_ERR_INVAL;
+ case FR_WRITE_PROTECTED:
+ return VFS_ERR_ROFS;
+ case FR_DENIED:
+ /* "access denied", which FatFs also uses for a full directory */
+ return VFS_ERR_ROFS;
+ case FR_INVALID_DRIVE:
+ case FR_NOT_ENABLED:
+ case FR_NO_FILESYSTEM:
+ case FR_NOT_READY:
+ return VFS_ERR_NODEV;
+ case FR_TIMEOUT:
+ case FR_LOCKED:
+ return VFS_ERR_AGAIN;
+ case FR_NOT_ENOUGH_CORE:
+ case FR_TOO_MANY_OPEN_FILES:
+ return VFS_ERR_NOMEM;
+ case FR_DISK_ERR:
+ case FR_INT_ERR:
+ default:
+ return VFS_ERR_IO;
+ }
+}
+
+/**
+ * days since 1970-01-01, proleptic gregorian (Howard Hinnant's algorithm).
+ * Kept here rather than pulling in <time.h>, which an RTOS may not have.
+ */
+static int days_from_civil(int y, unsigned m, unsigned d)
+{
+ int era;
+ unsigned yoe, doy, doe;
+
+ y -= (m <= 2u) ? 1 : 0;
+ era = (y >= 0 ? y : y - 399) / 400;
+ yoe = (unsigned)(y - era * 400);
+ doy = (153u * (m + (m > 2u ? (unsigned)-3 : 9u)) + 2u) / 5u + d - 1u;
+ doe = yoe * 365u + yoe / 4u - yoe / 100u + doy;
+
+ return era * 146097 + (int)doe - 719468;
+}
+
+/**
+ * FatFs date/time -> unix seconds.
+ *
+ * adb sync carries the file time in STAT and DENT records, but FatFs keeps a
+ * packed DOS timestamp, so it has to be converted somewhere. Doing it here
+ * keeps the protocol layer free of file system specifics.
+ */
+static uint32_t fat_time_to_unix(uint16_t fdate, uint16_t ftime)
+{
+ unsigned year = 1980u + ((fdate >> 9) & 0x7Fu);
+ unsigned month = (fdate >> 5) & 0x0Fu;
+ unsigned day = fdate & 0x1Fu;
+ unsigned hour = ((unsigned)ftime >> 11) & 0x1Fu;
+ unsigned minute = ((unsigned)ftime >> 5) & 0x3Fu;
+ unsigned second = ((unsigned)ftime & 0x1Fu) * 2u;
+
+ if ((fdate == 0) || (month == 0) || (day == 0)) {
+ return 0; /* FatFs stores 0 when there is no valid timestamp */
+ }
+
+ return (uint32_t)(days_from_civil((int)year, month, day) * 86400 +
+ (int)(hour * 3600u + minute * 60u + second));
+}
+
+int vfs_mkdir(const char *path)
+{
+ FRESULT result;
+
+ if (!path || !path[0]) {
+ return VFS_ERR_INVAL;
+ }
+
+ result = f_mkdir(path);
+ /* adb push of a directory tree re-sends SEND for directories it has already
+ * created, so "it is already there" has to count as success */
+ if ((result != FR_OK) && (result != FR_EXIST)) {
+ return adb_err(result);
+ }
+
+ return 0;
+}
+
+int vfs_rmdir(const char *path)
+{
+ FRESULT result = f_rmdir(path);
+
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return 0;
+}
+
+VFS_DIR *vfs_opendir(const char *name)
+{
+ FRESULT result;
+ DIR *dir;
+
+ if (!name || !name[0]) {
+ return NULL;
+ }
+
+ dir = usb_osal_malloc(sizeof(DIR));
+ if (!dir) {
+ return NULL;
+ }
+
+ result = f_opendir(dir, name);
+ if (result != FR_OK) {
+ usb_osal_free(dir);
+ return NULL;
+ }
+
+ return (VFS_DIR *)dir;
+}
+
+int vfs_closedir(VFS_DIR *dir)
+{
+ FRESULT result;
+
+ if (!dir) {
+ return VFS_ERR_INVAL;
+ }
+
+ result = f_closedir((DIR *)dir);
+ usb_osal_free(dir); /* release it either way */
+
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return 0;
+}
+
+struct vfs_dirent *vfs_readdir(VFS_DIR *dir)
+{
+ static struct vfs_dirent dirent;
+ FILINFO fno;
+ FRESULT result;
+
+ if (!dir) {
+ return NULL;
+ }
+
+ result = f_readdir((DIR *)dir, &fno);
+ if ((result != FR_OK) || (fno.fname[0] == 0)) {
+ return NULL; /* end of directory, or a hard error */
+ }
+
+ memset(&dirent, 0, sizeof(dirent));
+ strncpy(dirent.d_name, fno.fname, sizeof(dirent.d_name) - 1);
+ dirent.d_name[sizeof(dirent.d_name) - 1] = '\0';
+ dirent.d_namlen = (uint8_t)strlen(dirent.d_name);
+ /* d_type is just the type field of a mode shifted down, see vfs_posix.h */
+ dirent.d_type = (uint8_t)(((fno.fattrib & AM_DIR) ? VFS_S_IFDIR
+ : VFS_S_IFREG) >>
+ 12);
+
+ return &dirent;
+}
+
+#undef SS
+#if FF_MAX_SS == FF_MIN_SS
+#define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */
+#else
+#define SS(fs) ((fs)->ssize) /* Variable sector size */
+#endif
+
+int vfs_stat(const char *path, struct vfs_stat *buf)
+{
+ FILINFO file_info;
+ FRESULT result;
+ FATFS *f;
+
+ if (!path || !path[0] || !buf) {
+ return VFS_ERR_INVAL;
+ }
+
+ f = &s_sd_disk;
+
+ result = f_stat(path, &file_info);
+ if (result != FR_OK) {
+ /* Stay quiet on purpose: adb stats a path precisely to find out whether
+ * it exists, so "not found" is a normal answer and not an error. The
+ * service reports it to the host as "mode 0". */
+ return adb_err(result);
+ }
+
+ memset(buf, 0, sizeof(*buf));
+ buf->st_mode = VFS_S_IFREG | VFS_S_IRUSR | VFS_S_IRGRP | VFS_S_IROTH |
+ VFS_S_IWUSR | VFS_S_IWGRP | VFS_S_IWOTH;
+ if (file_info.fattrib & AM_DIR) {
+ buf->st_mode &= ~VFS_S_IFREG;
+ buf->st_mode |= VFS_S_IFDIR | VFS_S_IXUSR | VFS_S_IXGRP | VFS_S_IXOTH;
+ }
+ if (file_info.fattrib & AM_RDO) {
+ buf->st_mode &= ~(VFS_S_IWUSR | VFS_S_IWGRP | VFS_S_IWOTH);
+ }
+
+ buf->st_dev = 0;
+ buf->st_nlink = 1;
+ buf->st_size = file_info.fsize;
+ buf->st_blksize = f->csize * SS(f);
+ if (file_info.fattrib & AM_ARC) {
+ buf->st_blocks = file_info.fsize ? ((file_info.fsize - 1) / SS(f) / f->csize + 1) : 0;
+ buf->st_blocks *= (buf->st_blksize / 512); /* st_blocks is in 512B units */
+ } else {
+ buf->st_blocks = f->csize;
+ }
+ buf->st_mtime = fat_time_to_unix(file_info.fdate, file_info.ftime);
+ return 0;
+}
+
+int vfs_statfs(const char *path, struct vfs_statfs *buf)
+{
+ FATFS *f;
+ FRESULT res;
+ DWORD fre_clust, fre_sect, tot_sect;
+
+ if (!path || !path[0] || !buf) {
+ return VFS_ERR_INVAL;
+ }
+
+ f = &s_sd_disk;
+
+ res = f_getfree(path, &fre_clust, &f);
+ if (res != FR_OK) {
+ return adb_err(res);
+ }
+ tot_sect = (f->n_fatent - 2) * f->csize;
+ fre_sect = fre_clust * f->csize;
+
+ buf->f_blocks = tot_sect;
+ buf->f_bfree = fre_sect;
+#if FF_MAX_SS != FF_MIN_SS
+ buf->f_bsize = f->ssize;
+#else
+ buf->f_bsize = FF_MIN_SS;
+#endif
+ return 0;
+}
+
+int vfs_open(const char *path, uint8_t mode)
+{
+ FRESULT result;
+ BYTE flags;
+
+ if (!path || !path[0]) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (mode == VFS_O_RDONLY) {
+ flags = FA_READ | FA_OPEN_EXISTING;
+ } else if (mode == VFS_O_WRONLY) {
+ flags = FA_WRITE | FA_CREATE_ALWAYS;
+ } else if (mode == VFS_O_RDWR) {
+ flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
+ } else {
+ return VFS_ERR_INVAL;
+ }
+
+ result = f_open(&s_file, path, flags);
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return 0;
+}
+
+int vfs_close(int fd)
+{
+ FRESULT result;
+
+ (void)fd;
+
+ result = f_close(&s_file);
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return 0;
+}
+
+int vfs_read(int fd, void *buf, size_t len)
+{
+ UINT bytes_read;
+ FRESULT result;
+
+ (void)fd;
+
+ result = f_read(&s_file, buf, len, &bytes_read);
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return (int)bytes_read;
+}
+
+int vfs_write(int fd, const void *buf, size_t len)
+{
+ UINT bytes_written;
+ FRESULT result;
+
+ (void)fd;
+
+ result = f_write(&s_file, buf, len, &bytes_written);
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return (int)bytes_written;
+}
+
+int vfs_unlink(const char *path)
+{
+ FRESULT result = f_unlink(path);
+
+ if (result != FR_OK) {
+ return adb_err(result);
+ }
+
+ return 0;
+}
+
+void vfs_mount(void)
+{
+ //sd_mkfs();
+
+ sd_mount_fs();
+
+ sd_write_file();
+} \ No newline at end of file
diff --git a/platform/idf/usbh_fatfs.c b/platform/idf/usbh_fatfs.c
index fef0798f..ca2713ae 100644
--- a/platform/idf/usbh_fatfs.c
+++ b/platform/idf/usbh_fatfs.c
@@ -9,6 +9,7 @@
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
+#include "esp_idf_version.h"
#include "esp_log.h"
#include "esp_check.h"
#include "diskio_impl.h"
@@ -215,12 +216,16 @@ esp_err_t msc_host_vfs_register(struct usbh_msc *msc_class,
strcpy(vfs->base_path, base_path);
vfs->pdrv = pdrv;
+#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(6, 0, 0)
esp_vfs_fat_conf_t conf = {
.base_path = base_path,
.fat_drive = drive,
.max_files = mount_config->max_files,
};
ret = esp_vfs_fat_register(&conf, &fs);
+#else
+ ret = esp_vfs_fat_register(base_path, drive, mount_config->max_files, &fs);
+#endif
ESP_GOTO_ON_ERROR(ret, fail, TAG, "Failed to register filesystem, error=%s", esp_err_to_name(ret));
vfs->fs = fs;
diff --git a/platform/rtthread/rt_usbd_adb.c b/platform/rtthread/rt_usbd_adb_msh.c
index 4ab7f59a..d994894f 100644
--- a/platform/rtthread/rt_usbd_adb.c
+++ b/platform/rtthread/rt_usbd_adb_msh.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, sakumisu
+ * Copyright (c) 2024 ~ 2026, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -9,33 +9,21 @@
#include "usbd_core.h"
#include "usbd_adb.h"
+#ifdef RT_USING_FINSH
+#include <shell.h>
+#include <finsh.h>
+#endif
+
#ifndef CONFIG_USBDEV_SHELL_RX_BUFSIZE
#define CONFIG_USBDEV_SHELL_RX_BUFSIZE (2048)
#endif
struct usbd_adb_shell {
struct rt_device parent;
- usb_osal_sem_t tx_done;
struct rt_ringbuffer rx_rb;
rt_uint8_t rx_rb_buffer[CONFIG_USBDEV_SHELL_RX_BUFSIZE];
} g_usbd_adb_shell;
-void usbd_adb_notify_shell_read(uint8_t *data, uint32_t len)
-{
- rt_ringbuffer_put(&g_usbd_adb_shell.rx_rb, data, len);
-
- if (g_usbd_adb_shell.parent.rx_indicate) {
- g_usbd_adb_shell.parent.rx_indicate(&g_usbd_adb_shell.parent, len);
- }
-}
-
-void usbd_adb_notify_write_done(void)
-{
- if (g_usbd_adb_shell.tx_done) {
- usb_osal_sem_give(g_usbd_adb_shell.tx_done);
- }
-}
-
static rt_err_t usbd_adb_shell_open(struct rt_device *dev, rt_uint16_t oflag)
{
while (!usb_device_is_configured(0)) {
@@ -46,10 +34,6 @@ static rt_err_t usbd_adb_shell_open(struct rt_device *dev, rt_uint16_t oflag)
static rt_err_t usbd_adb_shell_close(struct rt_device *dev)
{
- if (g_usbd_adb_shell.tx_done) {
- usb_osal_sem_give(g_usbd_adb_shell.tx_done);
- }
-
return RT_EOK;
}
@@ -70,15 +54,7 @@ static rt_ssize_t usbd_adb_shell_write(struct rt_device *dev,
RT_ASSERT(dev != RT_NULL);
- if (!usb_device_is_configured(0)) {
- return size;
- }
-
- if (usbd_adb_can_write() && size) {
- usb_osal_sem_reset(g_usbd_adb_shell.tx_done);
- usbd_abd_write(ADB_SHELL_LOALID, buffer, size);
- usb_osal_sem_take(g_usbd_adb_shell.tx_done, 0xffffffff);
- }
+ usbd_adb_write(ADB_LOCALID_SHELL, buffer, size);
return size;
}
@@ -94,7 +70,7 @@ const static struct rt_device_ops usbd_adb_shell_ops = {
};
#endif
-void usbd_adb_shell_init(uint8_t in_ep, uint8_t out_ep)
+void rt_usbd_adb_shell_init(void)
{
rt_err_t ret;
struct rt_device *device;
@@ -125,31 +101,58 @@ void usbd_adb_shell_init(uint8_t in_ep, uint8_t out_ep)
device->fops = NULL;
#endif
- g_usbd_adb_shell.tx_done = usb_osal_sem_create(0);
rt_ringbuffer_init(&g_usbd_adb_shell.rx_rb, g_usbd_adb_shell.rx_rb_buffer, sizeof(g_usbd_adb_shell.rx_rb_buffer));
}
-static int adb_enter(int argc, char **argv)
+static void adb_shell_on_open(uint32_t remoteid)
{
- (void)argc;
- (void)argv;
-
+ USB_LOG_INFO("adb shell open, remoteid:%u\r\n", (unsigned)remoteid);
finsh_set_device("adb-sh");
rt_console_set_device("adb-sh");
+}
- return 0;
+static void adb_shell_on_close(uint32_t remoteid)
+{
+ USB_LOG_INFO("adb shell close, remoteid:%u\r\n", (unsigned)remoteid);
+}
+
+static void adb_shell_on_write(uint32_t remoteid, const uint8_t *data, uint32_t len)
+{
+ rt_size_t put;
+
+ put = rt_ringbuffer_put(&g_usbd_adb_shell.rx_rb, data, len);
+ if (g_usbd_adb_shell.parent.rx_indicate != RT_NULL) {
+ g_usbd_adb_shell.parent.rx_indicate(&g_usbd_adb_shell.parent, put);
+ }
+}
+
+static const struct adb_service adb_shell_service = {
+ .name = "shell:",
+ .localid = ADB_LOCALID_SHELL,
+ .on_open = adb_shell_on_open,
+ .on_close = adb_shell_on_close,
+ .on_write = adb_shell_on_write,
+};
+
+void usbd_adb_shell_init(void)
+{
+ if (usbd_adb_service_register(&adb_shell_service) != 0) {
+ USB_LOG_ERR("adb shell: register failed\r\n");
+ }
+ rt_usbd_adb_shell_init();
}
-MSH_CMD_EXPORT(adb_enter, adb_enter);
static int adb_exit(int argc, char **argv)
{
(void)argc;
(void)argv;
- usbd_adb_close(ADB_SHELL_LOALID);
+ usbd_adb_close(ADB_LOCALID_SHELL);
- finsh_set_device(RT_CONSOLE_DEVICE_NAME);
- rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
+ if (rt_console_get_device() != rt_device_find(RT_CONSOLE_DEVICE_NAME)) {
+ rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
+ finsh_set_device(RT_CONSOLE_DEVICE_NAME);
+ }
return 0;
}
diff --git a/platform/rtthread/rt_usbd_serial.c b/platform/rtthread/rt_usbd_serial.c
index 41fb01af..138f4cc8 100644
--- a/platform/rtthread/rt_usbd_serial.c
+++ b/platform/rtthread/rt_usbd_serial.c
@@ -258,6 +258,7 @@ void usbd_cdc_acm_serial_init(uint8_t busid, uint8_t in_ep, uint8_t out_ep)
serial->in_ep = in_ep;
serial->out_ep = out_ep;
serial->tx_done = usb_osal_sem_create(0);
+ USB_ASSERT(serial->tx_done != NULL);
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &serial->intf_ctrl));
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &serial->intf_data));
diff --git a/platform/rtthread/rt_usbh_msc.c b/platform/rtthread/rt_usbh_msc.c
index 77846665..aa2e4a8d 100644
--- a/platform/rtthread/rt_usbh_msc.c
+++ b/platform/rtthread/rt_usbh_msc.c
@@ -29,9 +29,13 @@ static rt_err_t rt_udisk_init(rt_device_t dev)
return RT_EOK;
}
-
+#if (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 0))
static rt_ssize_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void *buffer,
rt_size_t size)
+#else
+static rt_size_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void *buffer,
+ rt_size_t size)
+#endif
{
struct usbh_msc *msc_class = (struct usbh_msc *)dev->user_data;
int ret;
@@ -62,8 +66,13 @@ static rt_ssize_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void *buffer,
return size;
}
+#if (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 0, 0))
static rt_ssize_t rt_udisk_write(rt_device_t dev, rt_off_t pos, const void *buffer,
rt_size_t size)
+#else
+static rt_size_t rt_udisk_write(rt_device_t dev, rt_off_t pos, const void *buffer,
+ rt_size_t size)
+#endif
{
struct usbh_msc *msc_class = (struct usbh_msc *)dev->user_data;
int ret;
diff --git a/platform/rtthread/rt_vfs_dfs.c b/platform/rtthread/rt_vfs_dfs.c
new file mode 100644
index 00000000..6bd2f20f
--- /dev/null
+++ b/platform/rtthread/rt_vfs_dfs.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2026, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#include <string.h>
+#include <errno.h>
+
+#include <dfs_fs.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "usbd_core.h"
+#include "usb_vfs.h"
+
+#ifndef RT_USING_DFS
+#error "RT_USING_DFS must be enabled to use adb sync over the RT-Thread file system"
+#endif
+
+#ifndef CONFIG_USB_DFS_MOUNT_POINT
+#define CONFIG_USB_DFS_MOUNT_POINT "/"
+#endif
+
+/* -------------------------------------------------------------------------
+ * helpers
+ * ---------------------------------------------------------------------- */
+
+/**
+ * POSIX errno as a plain positive value.
+ *
+ * RT-Thread stores whatever code it was handed, and the DFS layer is not
+ * consistent about the sign, so it is normalised before being looked at.
+ */
+static int dfs_errno(void)
+{
+ int err = errno;
+
+ return (err < 0) ? -err : err;
+}
+
+/** errno -> VFS_ERR_*, so the host gets a readable reason. */
+static int dfs_errno_to_vfs(int err)
+{
+ switch (err) {
+ case ENOENT:
+ return VFS_ERR_NOENT;
+ case EEXIST:
+ return VFS_ERR_EXIST;
+ case EINVAL:
+ return VFS_ERR_INVAL;
+ case ENOTDIR:
+ return VFS_ERR_NOTDIR;
+ case EISDIR:
+ return VFS_ERR_ISDIR;
+ case ENOSPC:
+ return VFS_ERR_NOSPC;
+ case ENOMEM:
+ return VFS_ERR_NOMEM;
+ case EBUSY:
+ case EAGAIN:
+ return VFS_ERR_AGAIN;
+ case ENODEV:
+ return VFS_ERR_NODEV;
+ case EROFS:
+ case EACCES:
+ case EPERM:
+ return VFS_ERR_ROFS;
+ case EIO:
+ default:
+ return VFS_ERR_IO;
+ }
+}
+
+const char *vfs_get_fs_root_path(void)
+{
+ return CONFIG_USB_DFS_MOUNT_POINT;
+}
+
+const char *vfs_get_fs_description(void)
+{
+ return "CherryUSB VFS DFS";
+}
+
+int vfs_mkdir(const char *path)
+{
+ if (!path || !path[0]) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (mkdir(path, 0777) < 0) {
+ /* adb push of a directory tree re-sends SEND for directories it has
+ * already created, so "it is already there" has to count as success */
+ int err = dfs_errno();
+
+ if (err != EEXIST) {
+ return dfs_errno_to_vfs(err);
+ }
+ }
+
+ return 0;
+}
+
+int vfs_rmdir(const char *path)
+{
+ if (!path || !path[0]) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (rmdir(path) < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return 0;
+}
+
+VFS_DIR *vfs_opendir(const char *name)
+{
+ DIR *dir;
+
+ if (!name || !name[0]) {
+ return NULL;
+ }
+
+ dir = opendir(name);
+ if (!dir) {
+ return NULL;
+ }
+
+ return (VFS_DIR *)dir;
+}
+
+int vfs_closedir(VFS_DIR *dir)
+{
+ if (!dir) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (closedir((DIR *)dir) < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return 0;
+}
+
+struct vfs_dirent *vfs_readdir(VFS_DIR *dir)
+{
+ static struct vfs_dirent dirent;
+ struct dirent *entry;
+
+ if (!dir) {
+ return NULL;
+ }
+
+ entry = readdir((DIR *)dir);
+ if (!entry) {
+ return NULL; /* end of directory, or a hard error */
+ }
+
+ memset(&dirent, 0, sizeof(dirent));
+ strncpy(dirent.d_name, entry->d_name, sizeof(dirent.d_name) - 1);
+ dirent.d_name[sizeof(dirent.d_name) - 1] = '\0';
+ dirent.d_namlen = (uint8_t)strlen(dirent.d_name);
+ /* d_type is just the type field of a mode shifted down, see usb_vfs.h.
+ * RT-Thread hands back DT_*, so the two cases that matter are translated
+ * and anything else (including DT_UNKNOWN) falls back to a regular file. */
+ dirent.d_type = (entry->d_type == DT_DIR) ? (uint8_t)(VFS_S_IFDIR >> 12)
+ : (uint8_t)(VFS_S_IFREG >> 12);
+
+ return &dirent;
+}
+
+int vfs_stat(const char *path, struct vfs_stat *buf)
+{
+ struct stat st;
+
+ if (!path || !path[0] || !buf) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (stat(path, &st) < 0) {
+ /* Stay quiet on purpose: adb stats a path precisely to find out whether
+ * it exists, so "not found" is a normal answer and not an error. The
+ * service reports it to the host as "mode 0". */
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ memset(buf, 0, sizeof(*buf));
+ if (S_ISDIR(st.st_mode)) {
+ buf->st_mode = VFS_S_IFDIR | VFS_S_IRWXU | VFS_S_IRWXG | VFS_S_IRWXO;
+ } else {
+ buf->st_mode = VFS_S_IFREG | VFS_S_IRUSR | VFS_S_IRGRP | VFS_S_IROTH |
+ VFS_S_IWUSR | VFS_S_IWGRP | VFS_S_IWOTH;
+ }
+
+ buf->st_dev = 0;
+ buf->st_nlink = 1;
+ buf->st_size = st.st_size;
+ buf->st_mtime = st.st_mtime;
+ /* st_blksize/st_blocks are left at zero: RT-Thread's struct stat does not
+ * carry them consistently across DFS versions, and the adb STAT record
+ * only ever reports mode, size and mtime. */
+ return 0;
+}
+
+int vfs_statfs(const char *path, struct vfs_statfs *buf)
+{
+ struct statfs st;
+
+ if (!path || !path[0] || !buf) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (dfs_statfs(path, &st) < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ buf->f_bsize = st.f_bsize;
+ buf->f_blocks = st.f_blocks;
+ buf->f_bfree = st.f_bfree;
+ return 0;
+}
+
+int vfs_open(const char *path, uint8_t mode)
+{
+ int flags;
+ int fd;
+
+ if (!path || !path[0]) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (mode == VFS_O_RDONLY) {
+ flags = O_RDONLY; /* existing file only */
+ } else if (mode == VFS_O_WRONLY) {
+ flags = O_WRONLY | O_CREAT | O_TRUNC; /* create / truncate */
+ } else if (mode == VFS_O_RDWR) {
+ flags = O_RDWR | O_CREAT; /* create, no truncate */
+ } else {
+ return VFS_ERR_INVAL;
+ }
+
+ fd = open(path, flags, 0666);
+ if (fd < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return fd;
+}
+
+int vfs_close(int fd)
+{
+ if (fd < 0) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (close(fd) < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return 0;
+}
+
+int vfs_read(int fd, void *buf, size_t len)
+{
+ int ret;
+
+ if (fd < 0) {
+ return VFS_ERR_INVAL;
+ }
+
+ ret = (int)read(fd, buf, len);
+ if (ret < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return ret;
+}
+
+int vfs_write(int fd, const void *buf, size_t len)
+{
+ int ret;
+
+ if (fd < 0) {
+ return VFS_ERR_INVAL;
+ }
+
+ ret = (int)write(fd, buf, len);
+ if (ret < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return ret;
+}
+
+int vfs_unlink(const char *path)
+{
+ if (!path || !path[0]) {
+ return VFS_ERR_INVAL;
+ }
+
+ if (unlink(path) < 0) {
+ return dfs_errno_to_vfs(dfs_errno());
+ }
+
+ return 0;
+}
diff --git a/platform/zephyr/usbh_msc_disk.c b/platform/zephyr/usbh_msc_disk.c
index 6890f985..129cbfe4 100644
--- a/platform/zephyr/usbh_msc_disk.c
+++ b/platform/zephyr/usbh_msc_disk.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, sakumisu
+ * Copyright (c) 2025-2026 sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -13,16 +13,37 @@
#endif
#endif
-struct usbh_msc *active_msc_class;
+struct usbh_msc_disk_context {
+ struct usbh_msc *msc_class;
+ struct disk_info disk;
+ char name[CONFIG_USBHOST_DEV_NAMELEN];
+ char devname[CONFIG_USBHOST_DEV_NAMELEN];
+};
+
+static struct usbh_msc_disk_context
+ msc_disk_context[CONFIG_USBHOST_MAX_MSC_CLASS];
+
+static struct usbh_msc_disk_context *disk_msc_context(struct disk_info *disk)
+{
+ return CONTAINER_OF(disk, struct usbh_msc_disk_context, disk);
+}
+
+static bool disk_msc_connected(const struct usbh_msc *msc_class)
+{
+ return msc_class != NULL && msc_class->hport != NULL &&
+ msc_class->hport->connected;
+}
static int disk_msc_access_init(struct disk_info *disk)
{
- active_msc_class = (struct usbh_msc *)usbh_find_class_instance("/dev/sda");
- if (active_msc_class == NULL) {
- printf("do not find /dev/sda\r\n");
+ struct usbh_msc_disk_context *ctx = disk_msc_context(disk);
+
+ ctx->msc_class = (struct usbh_msc *)usbh_find_class_instance(ctx->devname);
+ if (ctx->msc_class == NULL) {
+ printf("do not find %s\r\n", ctx->devname);
return -ENODEV;
}
- if (usbh_msc_scsi_init(active_msc_class) < 0) {
+ if (usbh_msc_scsi_init(ctx->msc_class) < 0) {
return -EIO;
}
return 0;
@@ -30,6 +51,12 @@ static int disk_msc_access_init(struct disk_info *disk)
static int disk_msc_access_status(struct disk_info *disk)
{
+ struct usbh_msc_disk_context *ctx = disk_msc_context(disk);
+
+ if (!disk_msc_connected(ctx->msc_class)) {
+ return DISK_STATUS_NOMEDIA;
+ }
+
return DISK_STATUS_OK;
}
@@ -38,25 +65,30 @@ static int disk_msc_access_read(struct disk_info *disk, uint8_t *buff,
{
int ret;
uint8_t *align_buf;
+ struct usbh_msc_disk_context *ctx = disk_msc_context(disk);
+
+ if (!disk_msc_connected(ctx->msc_class)) {
+ return -ENODEV;
+ }
align_buf = (uint8_t *)buff;
#ifdef CONFIG_DCACHE
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
- align_buf = (uint8_t *)k_aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * active_msc_class->blocksize);
+ align_buf = (uint8_t *)k_aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * ctx->msc_class->blocksize);
if (!align_buf) {
printf("msc get align buf failed\r\n");
return -ENOMEM;
}
}
#endif
- if (usbh_msc_scsi_read10(active_msc_class, sector, align_buf, count) < 0) {
+ if (usbh_msc_scsi_read10(ctx->msc_class, sector, align_buf, count) < 0) {
ret = -EIO;
} else {
ret = 0;
}
#ifdef CONFIG_DCACHE
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
- usb_memcpy(buff, align_buf, count * active_msc_class->blocksize);
+ usb_memcpy(buff, align_buf, count * ctx->msc_class->blocksize);
k_free(align_buf);
}
#endif
@@ -68,19 +100,24 @@ static int disk_msc_access_write(struct disk_info *disk, const uint8_t *buff,
{
int ret;
uint8_t *align_buf;
+ struct usbh_msc_disk_context *ctx = disk_msc_context(disk);
+
+ if (!disk_msc_connected(ctx->msc_class)) {
+ return -ENODEV;
+ }
align_buf = (uint8_t *)buff;
#ifdef CONFIG_DCACHE
if ((uint32_t)buff & (CONFIG_USB_ALIGN_SIZE - 1)) {
- align_buf = (uint8_t *)k_aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * active_msc_class->blocksize);
+ align_buf = (uint8_t *)k_aligned_alloc(CONFIG_USB_ALIGN_SIZE, count * ctx->msc_class->blocksize);
if (!align_buf) {
printf("msc get align buf failed\r\n");
return -ENOMEM;
}
- usb_memcpy(align_buf, buff, count * active_msc_class->blocksize);
+ usb_memcpy(align_buf, buff, count * ctx->msc_class->blocksize);
}
#endif
- if (usbh_msc_scsi_write10(active_msc_class, sector, align_buf, count) < 0) {
+ if (usbh_msc_scsi_write10(ctx->msc_class, sector, align_buf, count) < 0) {
ret = -EIO;
} else {
ret = 0;
@@ -95,14 +132,22 @@ static int disk_msc_access_write(struct disk_info *disk, const uint8_t *buff,
static int disk_msc_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buff)
{
+ struct usbh_msc_disk_context *ctx = disk_msc_context(disk);
+
switch (cmd) {
case DISK_IOCTL_CTRL_SYNC:
break;
case DISK_IOCTL_GET_SECTOR_COUNT:
- *(uint32_t *)buff = active_msc_class->blocknum;
+ if (!disk_msc_connected(ctx->msc_class)) {
+ return -ENODEV;
+ }
+ *(uint32_t *)buff = ctx->msc_class->blocknum;
break;
case DISK_IOCTL_GET_SECTOR_SIZE:
- *(uint32_t *)buff = active_msc_class->blocksize;
+ if (!disk_msc_connected(ctx->msc_class)) {
+ return -ENODEV;
+ }
+ *(uint32_t *)buff = ctx->msc_class->blocksize;
break;
case DISK_IOCTL_GET_ERASE_BLOCK_SZ:
*(uint32_t *)buff = 1U;
@@ -126,17 +171,56 @@ static const struct disk_operations msc_disk_ops = {
.ioctl = disk_msc_access_ioctl,
};
-static struct disk_info usbh_msc_disk = {
- .name = "USB",
- .ops = &msc_disk_ops,
-};
+__WEAK void usbh_msc_app_run(struct usbh_msc *msc_class)
+{
+ (void)msc_class;
+}
+
+__WEAK void usbh_msc_app_stop(struct usbh_msc *msc_class)
+{
+ (void)msc_class;
+}
void usbh_msc_run(struct usbh_msc *msc_class)
{
- disk_access_register(&usbh_msc_disk);
+ uint8_t index;
+ struct usbh_msc_disk_context *ctx;
+
+ if (msc_class == NULL || msc_class->sdchar < 'a' ||
+ msc_class->sdchar >= 'a' + CONFIG_USBHOST_MAX_MSC_CLASS) {
+ return;
+ }
+
+ index = msc_class->sdchar - 'a';
+ ctx = &msc_disk_context[index];
+ memset(ctx, 0, sizeof(*ctx));
+ snprintf(ctx->name, sizeof(ctx->name), "USB%u", index);
+ snprintf(ctx->devname, sizeof(ctx->devname), "/dev/sd%c", msc_class->sdchar);
+ ctx->msc_class = msc_class;
+ ctx->disk.name = ctx->name;
+ ctx->disk.ops = &msc_disk_ops;
+
+ if (disk_access_register(&ctx->disk) < 0) {
+ return;
+ }
+
+ usbh_msc_app_run(msc_class);
}
void usbh_msc_stop(struct usbh_msc *msc_class)
{
- disk_access_unregister(&usbh_msc_disk);
-} \ No newline at end of file
+ uint8_t index;
+ struct usbh_msc_disk_context *ctx;
+
+ usbh_msc_app_stop(msc_class);
+
+ if (msc_class == NULL || msc_class->sdchar < 'a' ||
+ msc_class->sdchar >= 'a' + CONFIG_USBHOST_MAX_MSC_CLASS) {
+ return;
+ }
+
+ index = msc_class->sdchar - 'a';
+ ctx = &msc_disk_context[index];
+ disk_access_unregister(&ctx->disk);
+ ctx->msc_class = NULL;
+}
diff --git a/port/aic/README.md b/port/aic/README.md
new file mode 100644
index 00000000..efa88c45
--- /dev/null
+++ b/port/aic/README.md
@@ -0,0 +1,5 @@
+# Note
+
+## Support Chip List
+
+- ALL series (aic + EHCI + OHCI)
diff --git a/port/ehci/usb_glue_aic.c b/port/aic/usb_glue_aic.c
index 30a6beb2..30a6beb2 100644
--- a/port/ehci/usb_glue_aic.c
+++ b/port/aic/usb_glue_aic.c
diff --git a/port/bouffalolab/README.md b/port/bouffalolab/README.md
index 7779b2bb..fd1744ff 100644
--- a/port/bouffalolab/README.md
+++ b/port/bouffalolab/README.md
@@ -2,4 +2,4 @@
## Support Chip List
-- BL616/BL808
+- BL616/BL808 (fotg210 + EHCI)
diff --git a/port/ehci/usb_glue_bouffalo.c b/port/bouffalolab/usb_glue_bouffalo.c
index 03cd1f33..489e1b38 100644
--- a/port/ehci/usb_glue_bouffalo.c
+++ b/port/bouffalolab/usb_glue_bouffalo.c
@@ -125,6 +125,24 @@ void usb_hc_low_level_init(struct usbh_bus *bus)
regval |= USB_MOTG_INT;
regval &= ~USB_MHC_INT;
putreg32(regval, BLFB_USB_BASE + USB_GLB_INT_OFFSET);
+
+ regval = getreg32(BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
+ regval |= USB_A_BUS_DROP_HOV;
+ regval &= ~USB_A_BUS_REQ_HOV;
+ putreg32(regval, BLFB_USB_BASE + USB_OTG_CSR_OFFSET);
+}
+
+void usb_hc_low_level_deinit(struct usbh_bus *bus)
+{
+ uint32_t regval;
+
+ bflb_irq_disable(37);
+
+ regval = getreg32(BLFB_USB_BASE + USB_GLB_INT_OFFSET);
+ regval |= USB_MDEV_INT;
+ regval |= USB_MOTG_INT;
+ regval |= USB_MHC_INT;
+ putreg32(regval, BLFB_USB_BASE + USB_GLB_INT_OFFSET);
}
uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
diff --git a/port/ch32/README.md b/port/ch32/README.md
deleted file mode 100644
index 68a1ab76..00000000
--- a/port/ch32/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Note
-
-## Support Chip List
-
-## CH32FS
-
-- CH32V30X/CH32V20X/CH32V10X/CH32X035
-
-## CH32HS
-
-- CH32V30X
-
-## CH58X
-
-- CH57X/CH58X(usbfs)
-- CH585(usbhs)
diff --git a/port/ch32/ch32fs/usb_ch32_usbfs_reg.h b/port/ch32/ch32fs/usb_ch32_usbfs_reg.h
deleted file mode 100644
index 34a96072..00000000
--- a/port/ch32/ch32fs/usb_ch32_usbfs_reg.h
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Copyright (c) 2022, sakumisu
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#ifndef _USB_CH32_USBFS_REG_H
-#define _USB_CH32_USBFS_REG_H
-
-#define __IO volatile /* defines 'read / write' permissions */
-
-/* USBOTG_FS Registers */
-typedef struct
-{
- __IO uint8_t BASE_CTRL;
- __IO uint8_t UDEV_CTRL;
- __IO uint8_t INT_EN;
- __IO uint8_t DEV_ADDR;
- __IO uint8_t Reserve0;
- __IO uint8_t MIS_ST;
- __IO uint8_t INT_FG;
- __IO uint8_t INT_ST;
- __IO uint16_t RX_LEN;
- __IO uint16_t Reserve1;
- __IO uint8_t UEP4_1_MOD;
- __IO uint8_t UEP2_3_MOD;
- __IO uint8_t UEP5_6_MOD;
- __IO uint8_t UEP7_MOD;
- __IO uint32_t UEP0_DMA;
- __IO uint32_t UEP1_DMA;
- __IO uint32_t UEP2_DMA;
- __IO uint32_t UEP3_DMA;
- __IO uint32_t UEP4_DMA;
- __IO uint32_t UEP5_DMA;
- __IO uint32_t UEP6_DMA;
- __IO uint32_t UEP7_DMA;
- __IO uint16_t UEP0_TX_LEN;
- __IO uint8_t UEP0_TX_CTRL;
- __IO uint8_t UEP0_RX_CTRL;
- __IO uint16_t UEP1_TX_LEN;
- __IO uint8_t UEP1_TX_CTRL;
- __IO uint8_t UEP1_RX_CTRL;
- __IO uint16_t UEP2_TX_LEN;
- __IO uint8_t UEP2_TX_CTRL;
- __IO uint8_t UEP2_RX_CTRL;
- __IO uint16_t UEP3_TX_LEN;
- __IO uint8_t UEP3_TX_CTRL;
- __IO uint8_t UEP3_RX_CTRL;
- __IO uint16_t UEP4_TX_LEN;
- __IO uint8_t UEP4_TX_CTRL;
- __IO uint8_t UEP4_RX_CTRL;
- __IO uint16_t UEP5_TX_LEN;
- __IO uint8_t UEP5_TX_CTRL;
- __IO uint8_t UEP5_RX_CTRL;
- __IO uint16_t UEP6_TX_LEN;
- __IO uint8_t UEP6_TX_CTRL;
- __IO uint8_t UEP6_RX_CTRL;
- __IO uint16_t UEP7_TX_LEN;
- __IO uint8_t UEP7_TX_CTRL;
- __IO uint8_t UEP7_RX_CTRL;
- __IO uint32_t Reserve2;
- __IO uint32_t OTG_CR;
- __IO uint32_t OTG_SR;
-} USBOTG_FS_TypeDef;
-
-typedef struct __attribute__((packed)) {
- __IO uint8_t BASE_CTRL;
- __IO uint8_t HOST_CTRL;
- __IO uint8_t INT_EN;
- __IO uint8_t DEV_ADDR;
- __IO uint8_t Reserve0;
- __IO uint8_t MIS_ST;
- __IO uint8_t INT_FG;
- __IO uint8_t INT_ST;
- __IO uint16_t RX_LEN;
- __IO uint16_t Reserve1;
- __IO uint8_t Reserve2;
- __IO uint8_t HOST_EP_MOD;
- __IO uint16_t Reserve3;
- __IO uint32_t Reserve4;
- __IO uint32_t Reserve5;
- __IO uint32_t HOST_RX_DMA;
- __IO uint32_t HOST_TX_DMA;
- __IO uint32_t Reserve6;
- __IO uint32_t Reserve7;
- __IO uint32_t Reserve8;
- __IO uint32_t Reserve9;
- __IO uint32_t Reserve10;
- __IO uint16_t Reserve11;
- __IO uint16_t HOST_SETUP;
- __IO uint8_t HOST_EP_PID;
- __IO uint8_t Reserve12;
- __IO uint8_t Reserve13;
- __IO uint8_t HOST_RX_CTRL;
- __IO uint16_t HOST_TX_LEN;
- __IO uint8_t HOST_TX_CTRL;
- __IO uint8_t Reserve14;
- __IO uint32_t Reserve15;
- __IO uint32_t Reserve16;
- __IO uint32_t Reserve17;
- __IO uint32_t Reserve18;
- __IO uint32_t Reserve19;
- __IO uint32_t OTG_CR;
- __IO uint32_t OTG_SR;
-} USBOTGH_FS_TypeDef;
-
-typedef struct
-{
- __IO uint8_t BASE_CTRL; /*!< 0x40008000 */
- __IO uint8_t HOST_CTRL; /*!< 0x40008001 */
- __IO uint8_t INT_EN; /*!< 0x40008002 */
- __IO uint8_t DEV_ADDR; /*!< 0x40008003 */
- __IO uint8_t USB_STATUS0; /*!< 0x40008004 */
- __IO uint8_t MIS_ST; /*!< 0x40008005 */
- __IO uint8_t INT_FG; /*!< 0x40008006 */
- __IO uint8_t INT_ST; /*!< 0x40008007 */
- __IO uint8_t RX_LEN; /*!< 0x40008008 */
- __IO uint8_t Reserve1; /*!< 0x40008009 */
- __IO uint8_t Reserve2; /*!< 0x4000800a */
- __IO uint8_t Reserve3; /*!< 0x4000800b */
- __IO uint8_t UEP4_1_MOD; /*!< 0x4000800c */
- __IO uint8_t HOST_EP_MOD; /*!< 0x4000800d */
- __IO uint8_t UEP567_MOD; /*!< 0x4000800e */
- __IO uint8_t Reserve4; /*!< 0x4000800f */
- __IO uint16_t UEP0_DMA; /*!< 0x40008010 */
- __IO uint16_t Reserve5; /*!< 0x40008012 */
- __IO uint16_t UEP1_DMA; /*!< 0x40008014 */
- __IO uint16_t Reserve6; /*!< 0x40008016 */
- __IO uint16_t HOST_RX_DMA; /*!< 0x40008018 */
- __IO uint16_t Reserve7; /*!< 0x4000801a */
- __IO uint16_t HOST_TX_DMA; /*!< 0x4000801c */
- __IO uint16_t Reserve8; /*!< 0x4000801e */
- __IO uint8_t UEP0_T_LEN; /*!< 0x40008020 */
- __IO uint8_t Reserve9; /*!< 0x40008021 */
- __IO uint8_t UEP0_CTRL; /*!< 0x40008022 */
- __IO uint8_t Reserve10; /*!< 0x40008023 */
- __IO uint8_t UEP1_T_LEN; /*!< 0x40008024 */
- __IO uint8_t Reserve11; /*!< 0x40008025 */
- __IO uint8_t HOST_SETUP; /*!< 0x40008026 */
- __IO uint8_t Reserve12; /*!< 0x40008027 */
- __IO uint8_t HOST_EP_PID; /*!< 0x40008028 */
- __IO uint8_t Reserve13; /*!< 0x40008029 */
- __IO uint8_t HOST_RX_CTRL; /*!< 0x4000802a */
- __IO uint8_t Reserve14; /*!< 0x4000802b */
- __IO uint8_t HOST_TX_LEN; /*!< 0x4000802c */
- __IO uint8_t Reserve15; /*!< 0x4000802d */
- __IO uint8_t HOST_TX_CTRL; /*!< 0x4000802e */
- __IO uint8_t Reserve16; /*!< 0x4000802f */
- __IO uint8_t UEP4_T_LEN; /*!< 0x40008030 */
- __IO uint8_t Reserve17; /*!< 0x40008031 */
- __IO uint8_t UEP4_CTRL; /*!< 0x40008032 */
- __IO uint8_t Reserve18[33]; /*!< 0x40008033 */
- __IO uint16_t UEP5_DMA; /*!< 0x40008054 */
- __IO uint16_t Reserve19; /*!< 0x40008056 */
- __IO uint16_t UEP6_DMA; /*!< 0x40008058 */
- __IO uint16_t Reserve20; /*!< 0x4000805a */
- __IO uint16_t UEP7_DMA; /*!< 0x4000805c */
- __IO uint8_t Reserve21[6]; /*!< 0x4000805e */
- __IO uint8_t UEP5_T_LEN; /*!< 0x40008064 */
- __IO uint8_t Reserve22; /*!< 0x40008065 */
- __IO uint8_t UEP5_CTRL; /*!< 0x40008066 */
- __IO uint8_t Reserve23; /*!< 0x40008067 */
- __IO uint8_t UEP6_T_LEN; /*!< 0x40008068 */
- __IO uint8_t Reserve24; /*!< 0x40008069 */
- __IO uint8_t UEP6_CTRL; /*!< 0x4000806a */
- __IO uint8_t Reserve25; /*!< 0x4000806b */
- __IO uint8_t UEP7_T_LEN; /*!< 0x4000806c */
- __IO uint8_t Reserve26; /*!< 0x4000806d */
- __IO uint8_t UEP7_CTRL; /*!< 0x4000806e */
-} USB_FS_TypeDef;
-
-#define USBFS_BASE ((uint32_t)0x50000000)
-
-#define USBFS_DEVICE ((USBOTG_FS_TypeDef *)USBFS_BASE)
-#define USBFS_HOST ((USBOTGH_FS_TypeDef *)USBFS_BASE)
-
-/******************* GLOBAL ******************/
-
-/* BASE USB_CTRL */
-#define USBFS_BASE_CTRL_OFFSET 0x00 // USB base control
-#define USBFS_UC_HOST_MODE 0x80 // enable USB host mode: 0=device mode, 1=host mode
-#define USBFS_UC_LOW_SPEED 0x40 // enable USB low speed: 0=12Mbps, 1=1.5Mbps
-#define USBFS_UC_DEV_PU_EN 0x20 // USB device enable and internal pullup resistance enable
-#define USBFS_UC_SYS_CTRL1 0x20 // USB system control high bit
-#define USBFS_UC_SYS_CTRL0 0x10 // USB system control low bit
-#define USBFS_UC_SYS_CTRL_MASK 0x30 // bit mask of USB system control
-// UC_HOST_MODE & UC_SYS_CTRL1 & UC_SYS_CTRL0: USB system control
-// 0 00: disable USB device and disable internal pullup resistance
-// 0 01: enable USB device and disable internal pullup resistance, need external pullup resistance
-// 0 1x: enable USB device and enable internal pullup resistance
-// 1 00: enable USB host and normal status
-// 1 01: enable USB host and force UDP/UDM output SE0 state
-// 1 10: enable USB host and force UDP/UDM output J state
-// 1 11: enable USB host and force UDP/UDM output resume or K state
-#define USBFS_UC_INT_BUSY 0x08 // enable automatic responding busy for device mode or automatic pause for host mode during interrupt flag UIF_TRANSFER valid
-#define USBFS_UC_RESET_SIE 0x04 // force reset USB SIE, need software clear
-#define USBFS_UC_CLR_ALL 0x02 // force clear FIFO and count of USB
-#define USBFS_UC_DMA_EN 0x01 // DMA enable and DMA interrupt enable for USB
-
-/* USB INT EN */
-#define USBFS_INT_EN_OFFSET 0x02
-#define USBFS_UIE_DEV_SOF 0x80 // enable interrupt for SOF received for USB device mode
-#define USBFS_UIE_DEV_NAK 0x40 // enable interrupt for NAK responded for USB device mode
-#define USBFS_UIE_FIFO_OV 0x10 // enable interrupt for FIFO overflow
-#define USBFS_UIE_HST_SOF 0x08 // enable interrupt for host SOF timer action for USB host mode
-#define USBFS_UIE_SUSPEND 0x04 // enable interrupt for USB suspend or resume event
-#define USBFS_UIE_TRANSFER 0x02 // enable interrupt for USB transfer completion
-#define USBFS_UIE_DETECT 0x01 // enable interrupt for USB device detected event for USB host mode
-#define USBFS_UIE_BUS_RST 0x01 // enable interrupt for USB bus reset event for USB device mode
-/* USB_DEV_ADDR */
-#define USBFS_DEV_ADDR_OFFSET 0x03
-#define USBFS_UDA_GP_BIT 0x80 // general purpose bit
-#define USBFS_USB_ADDR_MASK 0x7F // bit mask for USB device address
-
-/* USB_STATUS */
-#define USBFS_USB_STATUS_OFFSET 0x04
-
-/* USB_MIS_ST */
-#define USBFS_MIS_ST_OFFSET 0x05
-#define USBFS_UMS_SOF_PRES 0x80 // RO, indicate host SOF timer presage status
-#define USBFS_UMS_SOF_ACT 0x40 // RO, indicate host SOF timer action status for USB host
-#define USBFS_UMS_SIE_FREE 0x20 // RO, indicate USB SIE free status
-#define USBFS_UMS_R_FIFO_RDY 0x10 // RO, indicate USB receiving FIFO ready status (not empty)
-#define USBFS_UMS_BUS_RESET 0x08 // RO, indicate USB bus reset status
-#define USBFS_UMS_SUSPEND 0x04 // RO, indicate USB suspend status
-#define USBFS_UMS_DM_LEVEL 0x02 // RO, indicate UDM level saved at device attached to USB host
-#define USBFS_UMS_DEV_ATTACH 0x01 // RO, indicate device attached status on USB host
-
-/* USB_INT_FG */
-#define USBFS_INT_FG_OFFSET 0x06
-#define USBFS_U_IS_NAK 0x80 // RO, indicate current USB transfer is NAK received
-#define USBFS_U_TOG_OK 0x40 // RO, indicate current USB transfer toggle is OK
-#define USBFS_U_SIE_FREE 0x20 // RO, indicate USB SIE free status
-#define USBFS_UIF_FIFO_OV 0x10 // FIFO overflow interrupt flag for USB, direct bit address clear or write 1 to clear
-#define USBFS_UIF_HST_SOF 0x08 // host SOF timer interrupt flag for USB host, direct bit address clear or write 1 to clear
-#define USBFS_UIF_SUSPEND 0x04 // USB suspend or resume event interrupt flag, direct bit address clear or write 1 to clear
-#define USBFS_UIF_TRANSFER 0x02 // USB transfer completion interrupt flag, direct bit address clear or write 1 to clear
-#define USBFS_UIF_DETECT 0x01 // device detected event interrupt flag for USB host mode, direct bit address clear or write 1 to clear
-#define USBFS_UIF_BUS_RST 0x01 // bus reset event interrupt flag for USB device mode, direct bit address clear or write 1 to clear
-
-/* USB_INT_ST */
-#define USBFS_INT_ST_OFFSET 0x07
-#define USBFS_UIS_IS_SETUP 0x80 // RO, indicate current USB transfer is setup received for USB device mode
-#define USBFS_UIS_IS_NAK 0x80 // RO, indicate current USB transfer is NAK received for USB device mode
-#define USBFS_UIS_TOG_OK 0x40 // RO, indicate current USB transfer toggle is OK
-#define USBFS_UIS_TOKEN1 0x20 // RO, current token PID code bit 1 received for USB device mode
-#define USBFS_UIS_TOKEN0 0x10 // RO, current token PID code bit 0 received for USB device mode
-#define USBFS_UIS_TOKEN_MASK 0x30 // RO, bit mask of current token PID code received for USB device mode
-#define USBFS_UIS_TOKEN_OUT 0x00
-#define USBFS_UIS_TOKEN_SOF 0x10
-#define USBFS_UIS_TOKEN_IN 0x20
-#define USBFS_UIS_TOKEN_SETUP 0x30
-// UIS_TOKEN1 & UIS_TOKEN0: current token PID code received for USB device mode
-// 00: OUT token PID received
-// 01: SOF token PID received
-// 10: IN token PID received
-// 11: SETUP token PID received
-#define USBFS_UIS_ENDP_MASK 0x0F // RO, bit mask of current transfer endpoint number for USB device mode
-/* USB_RX_LEN */
-#define USBFS_RX_LEN_OFFSET 0x08
-
-/******************* DEVICE ******************/
-
-/* UDEV_CTRL */
-#define USBFS_UDEV_CTRL_OFFSET 0x01
-#define USBFS_UD_PD_DIS 0x80 // disable USB UDP/UDM pulldown resistance: 0=enable pulldown, 1=disable
-#define USBFS_UD_DP_PIN 0x20 // ReadOnly: indicate current UDP pin level
-#define USBFS_UD_DM_PIN 0x10 // ReadOnly: indicate current UDM pin level
-#define USBFS_UD_LOW_SPEED 0x04 // enable USB physical port low speed: 0=full speed, 1=low speed
-#define USBFS_UD_GP_BIT 0x02 // general purpose bit
-#define USBFS_UD_PORT_EN 0x01 // enable USB physical port I/O: 0=disable, 1=enable
-
-/* UEP4_1_MOD */
-#define USBFS_UEP4_1_MOD_OFFSET 0x0C
-#define USBFS_UEP1_RX_EN 0x80 // enable USB endpoint 1 receiving (OUT)
-#define USBFS_UEP1_TX_EN 0x40 // enable USB endpoint 1 transmittal (IN)
-#define USBFS_UEP1_BUF_MOD 0x10 // buffer mode of USB endpoint 1
-// UEPn_RX_EN & UEPn_TX_EN & UEPn_BUF_MOD: USB endpoint 1/2/3 buffer mode, buffer start address is UEPn_DMA
-// 0 0 x: disable endpoint and disable buffer
-// 1 0 0: 64 bytes buffer for receiving (OUT endpoint)
-// 1 0 1: dual 64 bytes buffer by toggle bit bUEP_R_TOG selection for receiving (OUT endpoint), total=128bytes
-// 0 1 0: 64 bytes buffer for transmittal (IN endpoint)
-// 0 1 1: dual 64 bytes buffer by toggle bit bUEP_T_TOG selection for transmittal (IN endpoint), total=128bytes
-// 1 1 0: 64 bytes buffer for receiving (OUT endpoint) + 64 bytes buffer for transmittal (IN endpoint), total=128bytes
-// 1 1 1: dual 64 bytes buffer by bUEP_R_TOG selection for receiving (OUT endpoint) + dual 64 bytes buffer by bUEP_T_TOG selection for transmittal (IN endpoint), total=256bytes
-#define USBFS_UEP4_RX_EN 0x08 // enable USB endpoint 4 receiving (OUT)
-#define USBFS_UEP4_TX_EN 0x04 // enable USB endpoint 4 transmittal (IN)
-// UEP4_RX_EN & UEP4_TX_EN: USB endpoint 4 buffer mode, buffer start address is UEP0_DMA
-// 0 0: single 64 bytes buffer for endpoint 0 receiving & transmittal (OUT & IN endpoint)
-// 1 0: single 64 bytes buffer for endpoint 0 receiving & transmittal (OUT & IN endpoint) + 64 bytes buffer for endpoint 4 receiving (OUT endpoint), total=128bytes
-// 0 1: single 64 bytes buffer for endpoint 0 receiving & transmittal (OUT & IN endpoint) + 64 bytes buffer for endpoint 4 transmittal (IN endpoint), total=128bytes
-// 1 1: single 64 bytes buffer for endpoint 0 receiving & transmittal (OUT & IN endpoint)
-// + 64 bytes buffer for endpoint 4 receiving (OUT endpoint) + 64 bytes buffer for endpoint 4 transmittal (IN endpoint), total=192bytes
-
-/* UEP2_3_MOD */
-#define USBFS_UEP2_3_MOD_OFFSET 0x0D
-#define USBFS_UEP3_RX_EN 0x80 // enable USB endpoint 3 receiving (OUT)
-#define USBFS_UEP3_TX_EN 0x40 // enable USB endpoint 3 transmittal (IN)
-#define USBFS_UEP3_BUF_MOD 0x10 // buffer mode of USB endpoint 3
-#define USBFS_UEP2_RX_EN 0x08 // enable USB endpoint 2 receiving (OUT)
-#define USBFS_UEP2_TX_EN 0x04 // enable USB endpoint 2 transmittal (IN)
-#define USBFS_UEP2_BUF_MOD 0x01 // buffer mode of USB endpoint 2
-
-/* UEP5_6_MOD */
-#define USBFS_UEP5_6_MOD_OFFSET 0x0E
-#define USBFS_UEP6_RX_EN 0x80 // enable USB endpoint 6 receiving (OUT)
-#define USBFS_UEP6_TX_EN 0x40 // enable USB endpoint 6 transmittal (IN)
-#define USBFS_UEP6_BUF_MOD 0x10 // buffer mode of USB endpoint 6
-#define USBFS_UEP5_RX_EN 0x08 // enable USB endpoint 5 receiving (OUT)
-#define USBFS_UEP5_TX_EN 0x04 // enable USB endpoint 5 transmittal (IN)
-#define USBFS_UEP5_BUF_MOD 0x01 // buffer mode of USB endpoint 5
-
-/* UEP7_MOD */
-#define USBFS_UEP7_MOD_OFFSET 0x0F
-#define USBFS_UEP7_RX_EN 0x08 // enable USB endpoint 7 receiving (OUT)
-#define USBFS_UEP7_TX_EN 0x04 // enable USB endpoint 7 transmittal (IN)
-#define USBFS_UEP7_BUF_MOD 0x01 // buffer mode of USB endpoint 7
-
-/* USB_DMA */
-#define USBFS_UEPx_DMA_OFFSET(n) (0x10 + 4 * (n)) // endpoint x DMA buffer address
-#define USBFS_UEP0_DMA_OFFSET 0x10 // endpoint 0 DMA buffer address
-#define USBFS_UEP1_DMA_OFFSET 0x14 // endpoint 1 DMA buffer address
-#define USBFS_UEP2_DMA_OFFSET 0x18 // endpoint 2 DMA buffer address
-#define USBFS_UEP3_DMA_OFFSET 0x1c // endpoint 3 DMA buffer address
-#define USBFS_UEP4_DMA_OFFSET 0x20 // endpoint 4 DMA buffer address
-#define USBFS_UEP5_DMA_OFFSET 0x24 // endpoint 5 DMA buffer address
-#define USBFS_UEP6_DMA_OFFSET 0x28 // endpoint 6 DMA buffer address
-#define USBFS_UEP7_DMA_OFFSET 0x2c // endpoint 7 DMA buffer address
-/* USB_EP_CTRL */
-#define USBFS_UEPx_T_LEN_OFFSET(n) (0x30 + 4 * (n)) // endpoint x DMA buffer address
-#define USBFS_UEPx_TX_CTRL_OFFSET(n) (0x30 + 4 * (n) + 2) // endpoint x DMA buffer address
-#define USBFS_UEPx_RX_CTRL_OFFSET(n) (0x30 + 4 * (n) + 3) // endpoint x DMA buffer address
-
-#define USBFS_UEP_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion on endpoint 1/2/3: 0=manual toggle, 1=automatic toggle
-#define USBFS_UEP_R_TOG 0x04 // expected data toggle flag of USB endpoint X receiving (OUT): 0=DATA0, 1=DATA1
-#define USBFS_UEP_T_TOG 0x04 // prepared data toggle flag of USB endpoint X transmittal (IN): 0=DATA0, 1=DATA1
-
-#define USBFS_UEP_R_RES1 0x02 // handshake response type high bit for USB endpoint X receiving (OUT)
-#define USBFS_UEP_R_RES0 0x01 // handshake response type low bit for USB endpoint X receiving (OUT)
-#define USBFS_UEP_R_RES_MASK 0x03 // bit mask of handshake response type for USB endpoint X receiving (OUT)
-#define USBFS_UEP_R_RES_ACK 0x00
-#define USBFS_UEP_R_RES_TOUT 0x01
-#define USBFS_UEP_R_RES_NAK 0x02
-#define USBFS_UEP_R_RES_STALL 0x03
-// RB_UEP_R_RES1 & RB_UEP_R_RES0: handshake response type for USB endpoint X receiving (OUT)
-// 00: ACK (ready)
-// 01: no response, time out to host, for non-zero endpoint isochronous transactions
-// 10: NAK (busy)
-// 11: STALL (error)
-#define USBFS_UEP_T_RES1 0x02 // handshake response type high bit for USB endpoint X transmittal (IN)
-#define USBFS_UEP_T_RES0 0x01 // handshake response type low bit for USB endpoint X transmittal (IN)
-#define USBFS_UEP_T_RES_MASK 0x03 // bit mask of handshake response type for USB endpoint X transmittal (IN)
-#define USBFS_UEP_T_RES_ACK 0x00
-#define USBFS_UEP_T_RES_TOUT 0x01
-#define USBFS_UEP_T_RES_NAK 0x02
-#define USBFS_UEP_T_RES_STALL 0x03
-// bUEP_T_RES1 & bUEP_T_RES0: handshake response type for USB endpoint X transmittal (IN)
-// 00: DATA0 or DATA1 then expecting ACK (ready)
-// 01: DATA0 or DATA1 then expecting no response, time out from host, for non-zero endpoint isochronous transactions
-// 10: NAK (busy)
-// 11: TALL (error)
-
-/******************* HOST ******************/
-
-#define USBFS_UHOST_CTRL_OFFSET 0x01 // USB host physical prot control
-#define USBFS_UH_PD_DIS 0x80 // disable USB UDP/UDM pulldown resistance: 0=enable pulldown, 1=disable
-#define USBFS_UH_DP_PIN 0x20 // ReadOnly: indicate current UDP pin level
-#define USBFS_UH_DM_PIN 0x10 // ReadOnly: indicate current UDM pin level
-#define USBFS_UH_LOW_SPEED 0x04 // enable USB port low speed: 0=full speed, 1=low speed
-#define USBFS_UH_BUS_RESET 0x02 // control USB bus reset: 0=normal, 1=force bus reset
-#define USBFS_UH_PORT_EN 0x01 // enable USB port: 0=disable, 1=enable port, automatic disabled if USB device detached
-
-#define USBFS_UH_EP_MOD_OFFSET USBFS_UEP2_3_MOD_OFFSET
-#define USBFS_UH_EP_TX_EN 0x40 // enable USB host OUT endpoint transmittal
-#define USBFS_UH_EP_TBUF_MOD 0x10 // buffer mode of USB host OUT endpoint
-// bUH_EP_TX_EN & bUH_EP_TBUF_MOD: USB host OUT endpoint buffer mode, buffer start address is UH_TX_DMA
-// 0 x: disable endpoint and disable buffer
-// 1 0: 64 bytes buffer for transmittal (OUT endpoint)
-// 1 1: dual 64 bytes buffer by toggle bit bUH_T_TOG selection for transmittal (OUT endpoint), total=128bytes
-#define USBFS_UH_EP_RX_EN 0x08 // enable USB host IN endpoint receiving
-#define USBFS_UH_EP_RBUF_MOD 0x01 // buffer mode of USB host IN endpoint
-// bUH_EP_RX_EN & bUH_EP_RBUF_MOD: USB host IN endpoint buffer mode, buffer start address is UH_RX_DMA
-// 0 x: disable endpoint and disable buffer
-// 1 0: 64 bytes buffer for receiving (IN endpoint)
-// 1 1: dual 64 bytes buffer by toggle bit bUH_R_TOG selection for receiving (IN endpoint), total=128bytes
-
-#define USBFS_UH_RX_DMA_OFFSET USBFS_UEPx_DMA_OFFSET(2) // host rx endpoint buffer high address
-#define USBFS_UH_TX_DMA_OFFSET USBFS_UEPx_DMA_OFFSET(3) // host tx endpoint buffer high address
-
-#define USBFS_UH_SETUP_OFFSET USBFS_UEPx_TX_CTRL_OFFSET(1)
-#define USBFS_UH_PRE_PID_EN 0x0400 // USB host PRE PID enable for low speed device via hub
-#define USBFS_UH_SOF_EN 0x04 // USB host automatic SOF enable
-
-#define USBFS_UH_EP_PID_OFFSET USBFS_UEPx_T_LEN_OFFSET(2)
-#define USBFS_UH_TOKEN_MASK 0xF0 // bit mask of token PID for USB host transfer
-#define USBFS_UH_ENDP_MASK 0x0F // bit mask of endpoint number for USB host transfer
-
-#define USBFS_UH_RX_CTRL_OFFSET USBFS_UEPx_RX_CTRL_OFFSET(2) // host receiver endpoint control
-#define USBFS_UH_R_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion: 0=manual toggle, 1=automatic toggle
-#define USBFS_UH_R_TOG 0x04 // expected data toggle flag of host receiving (IN): 0=DATA0, 1=DATA1
-#define USBFS_UH_R_RES 0x01 // prepared handshake response type for host receiving (IN): 0=ACK (ready), 1=no response, time out to device, for isochronous transactions
-
-#define USBFS_UH_TX_LEN_OFFSET USBFS_UEPx_T_LEN_OFFSET(3)
-
-#define USBFS_UH_TX_CTRL_OFFSET USBFS_UEPx_TX_CTRL_OFFSET(3) // host transmittal endpoint control
-#define USBFS_UH_T_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion: 0=manual toggle, 1=automatic toggle
-#define USBFS_UH_T_TOG 0x04 // prepared data toggle flag of host transmittal (SETUP/OUT): 0=DATA0, 1=DATA1
-#define USBFS_UH_T_RES 0x01 // expected handshake response type for host transmittal (SETUP/OUT): 0=ACK (ready), 1=no response, time out from device, for isochronous transactions
-
-#endif
diff --git a/port/ch32/ch32fs/usb_dc_usbfs.c b/port/ch32/ch32fs/usb_dc_usbfs.c
deleted file mode 100644
index 8047d42d..00000000
--- a/port/ch32/ch32fs/usb_dc_usbfs.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Copyright (c) 2022, sakumisu
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#include "usbd_core.h"
-#include "usb_ch32_usbfs_reg.h"
-
-#ifdef CONFIG_USB_HS
-#error "usb fs do not support hs"
-#endif
-
-#ifndef USB_NUM_BIDIR_ENDPOINTS
-#define USB_NUM_BIDIR_ENDPOINTS 8
-#endif
-
-#define USB_SET_DMA(ep_idx, addr) (*(volatile uint32_t *)((uint32_t)(&USBFS_DEVICE->UEP0_DMA) + 4 * ep_idx) = addr)
-#define USB_SET_TX_LEN(ep_idx, len) (*(volatile uint16_t *)((uint32_t)(&USBFS_DEVICE->UEP0_TX_LEN) + 4 * ep_idx) = len)
-#define USB_GET_TX_LEN(ep_idx) (*(volatile uint16_t *)((uint32_t)(&USBFS_DEVICE->UEP0_TX_LEN) + 4 * ep_idx))
-#define USB_SET_TX_CTRL(ep_idx, val) (*(volatile uint8_t *)((uint32_t)(&USBFS_DEVICE->UEP0_TX_CTRL) + 4 * ep_idx) = val)
-#define USB_GET_TX_CTRL(ep_idx) (*(volatile uint8_t *)((uint32_t)(&USBFS_DEVICE->UEP0_TX_CTRL) + 4 * ep_idx))
-#define USB_SET_RX_CTRL(ep_idx, val) (*(volatile uint8_t *)((uint32_t)(&USBFS_DEVICE->UEP0_RX_CTRL) + 4 * ep_idx) = val)
-#define USB_GET_RX_CTRL(ep_idx) (*(volatile uint8_t *)((uint32_t)(&USBFS_DEVICE->UEP0_RX_CTRL) + 4 * ep_idx))
-
-/* Endpoint state */
-struct ch32_usbfs_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;
-};
-
-/* Driver state */
-struct ch32_usbfs_udc {
- __attribute__((aligned(4))) struct usb_setup_packet setup;
- volatile uint8_t dev_addr;
- struct ch32_usbfs_ep_state in_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< IN endpoint parameters*/
- struct ch32_usbfs_ep_state out_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< OUT endpoint parameters */
- __attribute__((aligned(4))) uint8_t ep_databuf[USB_NUM_BIDIR_ENDPOINTS - 1][64 + 64]; //epx_out(64)+epx_in(64)
-} g_ch32_usbfs_udc;
-
-volatile bool ep0_rx_data_toggle;
-volatile bool ep0_tx_data_toggle;
-
-__WEAK void usb_dc_low_level_init(void)
-{
-}
-
-__WEAK void usb_dc_low_level_deinit(void)
-{
-}
-
-int usb_dc_init(uint8_t busid)
-{
- usb_dc_low_level_init();
-
- USBFS_DEVICE->BASE_CTRL = 0x00;
-
- USBFS_DEVICE->UEP4_1_MOD = USBFS_UEP4_RX_EN | USBFS_UEP4_TX_EN | USBFS_UEP1_RX_EN | USBFS_UEP1_TX_EN;
- USBFS_DEVICE->UEP2_3_MOD = USBFS_UEP2_RX_EN | USBFS_UEP2_TX_EN | USBFS_UEP3_RX_EN | USBFS_UEP3_TX_EN;
- USBFS_DEVICE->UEP5_6_MOD = USBFS_UEP5_RX_EN | USBFS_UEP5_TX_EN | USBFS_UEP6_RX_EN | USBFS_UEP6_TX_EN;
- USBFS_DEVICE->UEP7_MOD = USBFS_UEP7_RX_EN | USBFS_UEP7_TX_EN;
-
- USBFS_DEVICE->UEP1_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[0];
- USBFS_DEVICE->UEP2_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[1];
- USBFS_DEVICE->UEP3_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[2];
- USBFS_DEVICE->UEP4_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[3];
- USBFS_DEVICE->UEP5_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[4];
- USBFS_DEVICE->UEP6_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[5];
- USBFS_DEVICE->UEP7_DMA = (uint32_t)g_ch32_usbfs_udc.ep_databuf[6];
-
- USBFS_DEVICE->INT_FG = 0xFF;
- USBFS_DEVICE->INT_EN = USBFS_UIE_SUSPEND | USBFS_UIE_BUS_RST | USBFS_UIE_TRANSFER;
- USBFS_DEVICE->DEV_ADDR = 0x00;
-
- USBFS_DEVICE->BASE_CTRL = USBFS_UC_DEV_PU_EN | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN;
- USBFS_DEVICE->UDEV_CTRL = USBFS_UD_PD_DIS | USBFS_UD_PORT_EN;
- return 0;
-}
-
-int usb_dc_deinit(uint8_t busid)
-{
- return 0;
-}
-
-int usbd_set_address(uint8_t busid, const uint8_t addr)
-{
- if (addr == 0) {
- USBFS_DEVICE->DEV_ADDR = (USBFS_DEVICE->DEV_ADDR & USBFS_UDA_GP_BIT) | 0;
- }
- g_ch32_usbfs_udc.dev_addr = addr;
- return 0;
-}
-
-int usbd_set_remote_wakeup(uint8_t busid)
-{
- return -1;
-}
-
-uint8_t usbd_get_port_speed(uint8_t busid)
-{
- return USB_SPEED_FULL;
-}
-
-int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
-{
- uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
-
- if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
- g_ch32_usbfs_udc.out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
- g_ch32_usbfs_udc.out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
- g_ch32_usbfs_udc.out_ep[ep_idx].ep_enable = true;
- USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_NAK | USBFS_UEP_AUTO_TOG);
- } else {
- g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
- g_ch32_usbfs_udc.in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
- g_ch32_usbfs_udc.in_ep[ep_idx].ep_enable = true;
- USB_SET_TX_CTRL(ep_idx, USBFS_UEP_T_RES_NAK | USBFS_UEP_AUTO_TOG);
- }
- return 0;
-}
-int usbd_ep_close(uint8_t busid, const uint8_t ep)
-{
- return 0;
-}
-int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
-{
- uint8_t ep_idx = USB_EP_GET_IDX(ep);
-
- if (USB_EP_DIR_IS_OUT(ep)) {
- if (ep_idx == 0) {
- USBFS_DEVICE->UEP0_RX_CTRL = USBFS_UEP_R_TOG | USBFS_UEP_R_RES_STALL;
- } else {
- USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_STALL);
- }
- } else {
- if (ep_idx == 0) {
- USBFS_DEVICE->UEP0_TX_CTRL = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_STALL;
- } else {
- USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_STALL);
- }
- }
-
- if (ep_idx == 0) {
- USB_SET_DMA(ep_idx, (uint32_t)&g_ch32_usbfs_udc.setup);
- USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_ACK);
- }
- return 0;
-}
-
-int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
-{
- uint8_t ep_idx = USB_EP_GET_IDX(ep);
-
- if (ep_idx == 0) {
- return 0;
- }
-
- if (USB_EP_DIR_IS_OUT(ep)) {
- USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~(USBFS_UEP_R_TOG | USBFS_UEP_R_RES_MASK)) | USBFS_UEP_R_RES_ACK);
- } else {
- USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~(USBFS_UEP_T_TOG | USBFS_UEP_T_RES_MASK)) | USBFS_UEP_T_RES_NAK);
- }
- return 0;
-}
-
-int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
-{
- return 0;
-}
-
-int usbd_ep_start_write(uint8_t busid, 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_ch32_usbfs_udc.in_ep[ep_idx].ep_enable) {
- return -2;
- }
-
- if ((uint32_t)data & 0x03) {
- printf("data do not align4\r\n");
- return -3;
- }
-
- g_ch32_usbfs_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data;
- g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len = data_len;
- g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len = 0;
-
- if (ep_idx == 0) {
- if (data_len == 0) {
- USB_SET_TX_LEN(ep_idx, 0);
- } else {
- data_len = MIN(data_len, g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps);
- USB_SET_TX_LEN(ep_idx, data_len);
- USB_SET_DMA(ep_idx, (uint32_t)data);
- }
- if (ep0_tx_data_toggle) {
- USB_SET_TX_CTRL(ep_idx, USBFS_UEP_T_TOG | USBFS_UEP_T_RES_ACK);
- } else {
- USB_SET_TX_CTRL(ep_idx, USBFS_UEP_T_RES_ACK);
- }
-
- } else {
- if (data_len == 0) {
- USB_SET_TX_LEN(ep_idx, 0);
- } else {
- data_len = MIN(data_len, g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps);
- USB_SET_TX_LEN(ep_idx, data_len);
- memcpy(&g_ch32_usbfs_udc.ep_databuf[ep_idx - 1][64], data, data_len);
- }
- USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_ACK);
- }
- return 0;
-}
-
-int usbd_ep_start_read(uint8_t busid, 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_ch32_usbfs_udc.out_ep[ep_idx].ep_enable) {
- return -2;
- }
- if ((uint32_t)data & 0x03) {
- printf("data do not align4\r\n");
- return -3;
- }
-
- g_ch32_usbfs_udc.out_ep[ep_idx].xfer_buf = (uint8_t *)data;
- g_ch32_usbfs_udc.out_ep[ep_idx].xfer_len = data_len;
- g_ch32_usbfs_udc.out_ep[ep_idx].actual_xfer_len = 0;
-
- if (ep_idx == 0) {
- if (data_len == 0) {
- } else {
- USB_SET_DMA(ep_idx, (uint32_t)data);
- }
- if (ep0_rx_data_toggle) {
- USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_TOG | USBFS_UEP_R_RES_ACK);
- } else {
- USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_ACK);
- }
- return 0;
- } else {
- USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_ACK);
- }
-
- return 0;
-}
-
-void USBD_IRQHandler(uint8_t busid)
-{
- uint32_t ep_idx = 0, token, write_count, read_count;
- uint8_t intflag = 0;
-
- intflag = USBFS_DEVICE->INT_FG;
-
- if (intflag & USBFS_UIF_TRANSFER) {
- token = USBFS_DEVICE->INT_ST & USBFS_UIS_TOKEN_MASK;
- ep_idx = USBFS_DEVICE->INT_ST & USBFS_UIS_ENDP_MASK;
-
- USBFS_DEVICE->INT_FG = USBFS_UIF_TRANSFER;
-
- switch (token) {
- case USBFS_UIS_TOKEN_SETUP:
- USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_NAK);
- usbd_event_ep0_setup_complete_handler(0, (uint8_t *)&g_ch32_usbfs_udc.setup);
- break;
-
- 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) {
- 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;
- } else {
- g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len;
- g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len = 0;
- ep0_tx_data_toggle = true;
- }
-
- usbd_event_ep_in_complete_handler(0, ep_idx | 0x80, g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len);
-
- if (g_ch32_usbfs_udc.dev_addr > 0) {
- USBFS_DEVICE->DEV_ADDR = (USBFS_DEVICE->DEV_ADDR & USBFS_UDA_GP_BIT) | g_ch32_usbfs_udc.dev_addr;
- g_ch32_usbfs_udc.dev_addr = 0;
- }
-
- if (g_ch32_usbfs_udc.setup.wLength && ((g_ch32_usbfs_udc.setup.bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_OUT)) {
- /* In status, start reading setup */
- USB_SET_DMA(ep_idx, (uint32_t)&g_ch32_usbfs_udc.setup);
- USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_ACK);
- ep0_tx_data_toggle = true;
-
- } else if (g_ch32_usbfs_udc.setup.wLength == 0) {
- /* In status, start reading setup */
- USB_SET_DMA(ep_idx, (uint32_t)&g_ch32_usbfs_udc.setup);
- USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_ACK);
- ep0_tx_data_toggle = true;
- }
- } else {
- USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_NAK);
-
- 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_buf += 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;
-
- write_count = MIN(g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len, g_ch32_usbfs_udc.in_ep[ep_idx].ep_mps);
- USB_SET_TX_LEN(ep_idx, write_count);
- memcpy(&g_ch32_usbfs_udc.ep_databuf[ep_idx - 1][64], g_ch32_usbfs_udc.in_ep[ep_idx].xfer_buf, write_count);
-
- USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_ACK);
- } else {
- g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len;
- g_ch32_usbfs_udc.in_ep[ep_idx].xfer_len = 0;
- usbd_event_ep_in_complete_handler(0, ep_idx | 0x80, g_ch32_usbfs_udc.in_ep[ep_idx].actual_xfer_len);
- }
- }
- break;
- case USBFS_UIS_TOKEN_OUT:
- if (ep_idx == 0x00) {
- USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_NAK);
-
- read_count = USBFS_DEVICE->RX_LEN;
-
- g_ch32_usbfs_udc.out_ep[ep_idx].actual_xfer_len += read_count;
- g_ch32_usbfs_udc.out_ep[ep_idx].xfer_len -= read_count;
-
- usbd_event_ep_out_complete_handler(0, 0x00, g_ch32_usbfs_udc.out_ep[ep_idx].actual_xfer_len);
-
- if (read_count == 0) {
- /* Out status, start reading setup */
- USB_SET_DMA(ep_idx, (uint32_t)&g_ch32_usbfs_udc.setup);
- USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_ACK);
- ep0_rx_data_toggle = true;
- ep0_tx_data_toggle = true;
- } else {
- ep0_rx_data_toggle ^= 1;
- }
- } else {
- if (USBFS_DEVICE->INT_ST & USBFS_UIS_TOG_OK) {
- USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_NAK);
- read_count = USBFS_DEVICE->RX_LEN;
-
- memcpy(g_ch32_usbfs_udc.out_ep[ep_idx].xfer_buf, &g_ch32_usbfs_udc.ep_databuf[ep_idx - 1][0], read_count);
-
- g_ch32_usbfs_udc.out_ep[ep_idx].xfer_buf += read_count;
- g_ch32_usbfs_udc.out_ep[ep_idx].actual_xfer_len += read_count;
- g_ch32_usbfs_udc.out_ep[ep_idx].xfer_len -= read_count;
-
- if ((read_count < g_ch32_usbfs_udc.out_ep[ep_idx].ep_mps) || (g_ch32_usbfs_udc.out_ep[ep_idx].xfer_len == 0)) {
- usbd_event_ep_out_complete_handler(0, ep_idx, g_ch32_usbfs_udc.out_ep[ep_idx].actual_xfer_len);
- } else {
- USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_ACK);
- }
- }
- }
- break;
-
- case USBFS_UIS_TOKEN_SOF:
-
- break;
-
- default:
- break;
- }
-
- } else if (intflag & USBFS_UIF_BUS_RST) {
- USBFS_DEVICE->INT_FG = USBFS_UIF_BUS_RST;
-
- USBFS_DEVICE->UEP0_TX_LEN = 0;
- USBFS_DEVICE->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK;
- USBFS_DEVICE->UEP0_RX_CTRL = USBFS_UEP_R_RES_NAK;
-
- for (uint8_t ep_idx = 1; ep_idx < USB_NUM_BIDIR_ENDPOINTS; ep_idx++) {
- USB_SET_TX_LEN(ep_idx, 0);
- USB_SET_TX_CTRL(ep_idx, USBFS_UEP_T_RES_NAK | USBFS_UEP_AUTO_TOG);
- USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_NAK | USBFS_UEP_AUTO_TOG);
- }
-
- ep0_tx_data_toggle = true;
- ep0_rx_data_toggle = true;
-
- memset(&g_ch32_usbfs_udc, 0, sizeof(struct ch32_usbfs_udc));
- usbd_event_reset_handler(0);
- USB_SET_DMA(ep_idx, (uint32_t)&g_ch32_usbfs_udc.setup);
- USB_SET_RX_CTRL(ep_idx, USBFS_UEP_R_RES_ACK);
- } else if (intflag & USBFS_UIF_SUSPEND) {
- if (USBFS_DEVICE->MIS_ST & USBFS_UMS_SUSPEND) {
- } else {
- }
- USBFS_DEVICE->INT_FG = USBFS_UIF_SUSPEND;
- } else {
- USBFS_DEVICE->INT_FG = intflag;
- }
-}
-
-void USBFS_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
-void USBFS_IRQHandler(void)
-{
- extern void USBD_IRQHandler(uint8_t busid);
- USBD_IRQHandler(0);
-} \ No newline at end of file
diff --git a/port/ch32/ch32hs/usb_ch32_usbhs_reg.h b/port/ch32/ch32hs/usb_ch32_usbhs_reg.h
deleted file mode 100644
index 1dca5d1b..00000000
--- a/port/ch32/ch32hs/usb_ch32_usbhs_reg.h
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * Copyright (c) 2022, sakumisu
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#ifndef _USB_CH32_USBHS_REG_H
-#define _USB_CH32_USBHS_REG_H
-
-#define __IO volatile /* defines 'read / write' permissions */
-
-/* USBHS Registers */
-typedef struct
-{
- __IO uint8_t CONTROL;
- __IO uint8_t HOST_CTRL;
- __IO uint8_t INT_EN;
- __IO uint8_t DEV_AD;
- __IO uint16_t FRAME_NO;
- __IO uint8_t SUSPEND;
- __IO uint8_t RESERVED0;
- __IO uint8_t SPEED_TYPE;
- __IO uint8_t MIS_ST;
- __IO uint8_t INT_FG;
- __IO uint8_t INT_ST;
- __IO uint16_t RX_LEN;
- __IO uint16_t RESERVED1;
- __IO uint32_t ENDP_CONFIG;
- __IO uint32_t ENDP_TYPE;
- __IO uint32_t BUF_MODE;
- __IO uint32_t UEP0_DMA;
- __IO uint32_t UEP1_RX_DMA;
- __IO uint32_t UEP2_RX_DMA;
- __IO uint32_t UEP3_RX_DMA;
- __IO uint32_t UEP4_RX_DMA;
- __IO uint32_t UEP5_RX_DMA;
- __IO uint32_t UEP6_RX_DMA;
- __IO uint32_t UEP7_RX_DMA;
- __IO uint32_t UEP8_RX_DMA;
- __IO uint32_t UEP9_RX_DMA;
- __IO uint32_t UEP10_RX_DMA;
- __IO uint32_t UEP11_RX_DMA;
- __IO uint32_t UEP12_RX_DMA;
- __IO uint32_t UEP13_RX_DMA;
- __IO uint32_t UEP14_RX_DMA;
- __IO uint32_t UEP15_RX_DMA;
- __IO uint32_t UEP1_TX_DMA;
- __IO uint32_t UEP2_TX_DMA;
- __IO uint32_t UEP3_TX_DMA;
- __IO uint32_t UEP4_TX_DMA;
- __IO uint32_t UEP5_TX_DMA;
- __IO uint32_t UEP6_TX_DMA;
- __IO uint32_t UEP7_TX_DMA;
- __IO uint32_t UEP8_TX_DMA;
- __IO uint32_t UEP9_TX_DMA;
- __IO uint32_t UEP10_TX_DMA;
- __IO uint32_t UEP11_TX_DMA;
- __IO uint32_t UEP12_TX_DMA;
- __IO uint32_t UEP13_TX_DMA;
- __IO uint32_t UEP14_TX_DMA;
- __IO uint32_t UEP15_TX_DMA;
- __IO uint16_t UEP0_MAX_LEN;
- __IO uint16_t RESERVED2;
- __IO uint16_t UEP1_MAX_LEN;
- __IO uint16_t RESERVED3;
- __IO uint16_t UEP2_MAX_LEN;
- __IO uint16_t RESERVED4;
- __IO uint16_t UEP3_MAX_LEN;
- __IO uint16_t RESERVED5;
- __IO uint16_t UEP4_MAX_LEN;
- __IO uint16_t RESERVED6;
- __IO uint16_t UEP5_MAX_LEN;
- __IO uint16_t RESERVED7;
- __IO uint16_t UEP6_MAX_LEN;
- __IO uint16_t RESERVED8;
- __IO uint16_t UEP7_MAX_LEN;
- __IO uint16_t RESERVED9;
- __IO uint16_t UEP8_MAX_LEN;
- __IO uint16_t RESERVED10;
- __IO uint16_t UEP9_MAX_LEN;
- __IO uint16_t RESERVED11;
- __IO uint16_t UEP10_MAX_LEN;
- __IO uint16_t RESERVED12;
- __IO uint16_t UEP11_MAX_LEN;
- __IO uint16_t RESERVED13;
- __IO uint16_t UEP12_MAX_LEN;
- __IO uint16_t RESERVED14;
- __IO uint16_t UEP13_MAX_LEN;
- __IO uint16_t RESERVED15;
- __IO uint16_t UEP14_MAX_LEN;
- __IO uint16_t RESERVED16;
- __IO uint16_t UEP15_MAX_LEN;
- __IO uint16_t RESERVED17;
- __IO uint16_t UEP0_TX_LEN;
- __IO uint8_t UEP0_TX_CTRL;
- __IO uint8_t UEP0_RX_CTRL;
- __IO uint16_t UEP1_TX_LEN;
- __IO uint8_t UEP1_TX_CTRL;
- __IO uint8_t UEP1_RX_CTRL;
- __IO uint16_t UEP2_TX_LEN;
- __IO uint8_t UEP2_TX_CTRL;
- __IO uint8_t UEP2_RX_CTRL;
- __IO uint16_t UEP3_TX_LEN;
- __IO uint8_t UEP3_TX_CTRL;
- __IO uint8_t UEP3_RX_CTRL;
- __IO uint16_t UEP4_TX_LEN;
- __IO uint8_t UEP4_TX_CTRL;
- __IO uint8_t UEP4_RX_CTRL;
- __IO uint16_t UEP5_TX_LEN;
- __IO uint8_t UEP5_TX_CTRL;
- __IO uint8_t UEP5_RX_CTRL;
- __IO uint16_t UEP6_TX_LEN;
- __IO uint8_t UEP6_TX_CTRL;
- __IO uint8_t UEP6_RX_CTRL;
- __IO uint16_t UEP7_TX_LEN;
- __IO uint8_t UEP7_TX_CTRL;
- __IO uint8_t UEP7_RX_CTRL;
- __IO uint16_t UEP8_TX_LEN;
- __IO uint8_t UEP8_TX_CTRL;
- __IO uint8_t UEP8_RX_CTRL;
- __IO uint16_t UEP9_TX_LEN;
- __IO uint8_t UEP9_TX_CTRL;
- __IO uint8_t UEP9_RX_CTRL;
- __IO uint16_t UEP10_TX_LEN;
- __IO uint8_t UEP10_TX_CTRL;
- __IO uint8_t UEP10_RX_CTRL;
- __IO uint16_t UEP11_TX_LEN;
- __IO uint8_t UEP11_TX_CTRL;
- __IO uint8_t UEP11_RX_CTRL;
- __IO uint16_t UEP12_TX_LEN;
- __IO uint8_t UEP12_TX_CTRL;
- __IO uint8_t UEP12_RX_CTRL;
- __IO uint16_t UEP13_TX_LEN;
- __IO uint8_t UEP13_TX_CTRL;
- __IO uint8_t UEP13_RX_CTRL;
- __IO uint16_t UEP14_TX_LEN;
- __IO uint8_t UEP14_TX_CTRL;
- __IO uint8_t UEP14_RX_CTRL;
- __IO uint16_t UEP15_TX_LEN;
- __IO uint8_t UEP15_TX_CTRL;
- __IO uint8_t UEP15_RX_CTRL;
-} USBHSD_TypeDef;
-
-typedef struct __attribute__((packed)) {
- __IO uint8_t CONTROL;
- __IO uint8_t HOST_CTRL;
- __IO uint8_t INT_EN;
- __IO uint8_t DEV_AD;
- __IO uint16_t FRAME_NO;
- __IO uint8_t SUSPEND;
- __IO uint8_t RESERVED0;
- __IO uint8_t SPEED_TYPE;
- __IO uint8_t MIS_ST;
- __IO uint8_t INT_FG;
- __IO uint8_t INT_ST;
- __IO uint16_t RX_LEN;
- __IO uint16_t RESERVED1;
- __IO uint32_t HOST_EP_CONFIG;
- __IO uint32_t HOST_EP_TYPE;
- __IO uint32_t RESERVED2;
- __IO uint32_t RESERVED3;
- __IO uint32_t RESERVED4;
- __IO uint32_t HOST_RX_DMA;
- __IO uint32_t RESERVED5;
- __IO uint32_t RESERVED6;
- __IO uint32_t RESERVED7;
- __IO uint32_t RESERVED8;
- __IO uint32_t RESERVED9;
- __IO uint32_t RESERVED10;
- __IO uint32_t RESERVED11;
- __IO uint32_t RESERVED12;
- __IO uint32_t RESERVED13;
- __IO uint32_t RESERVED14;
- __IO uint32_t RESERVED15;
- __IO uint32_t RESERVED16;
- __IO uint32_t RESERVED17;
- __IO uint32_t RESERVED18;
- __IO uint32_t RESERVED19;
- __IO uint32_t HOST_TX_DMA;
- __IO uint32_t RESERVED20;
- __IO uint32_t RESERVED21;
- __IO uint32_t RESERVED22;
- __IO uint32_t RESERVED23;
- __IO uint32_t RESERVED24;
- __IO uint32_t RESERVED25;
- __IO uint32_t RESERVED26;
- __IO uint32_t RESERVED27;
- __IO uint32_t RESERVED28;
- __IO uint32_t RESERVED29;
- __IO uint32_t RESERVED30;
- __IO uint32_t RESERVED31;
- __IO uint32_t RESERVED32;
- __IO uint32_t RESERVED33;
- __IO uint16_t HOST_RX_MAX_LEN;
- __IO uint16_t RESERVED34;
- __IO uint32_t RESERVED35;
- __IO uint32_t RESERVED36;
- __IO uint32_t RESERVED37;
- __IO uint32_t RESERVED38;
- __IO uint32_t RESERVED39;
- __IO uint32_t RESERVED40;
- __IO uint32_t RESERVED41;
- __IO uint32_t RESERVED42;
- __IO uint32_t RESERVED43;
- __IO uint32_t RESERVED44;
- __IO uint32_t RESERVED45;
- __IO uint32_t RESERVED46;
- __IO uint32_t RESERVED47;
- __IO uint32_t RESERVED48;
- __IO uint32_t RESERVED49;
- __IO uint8_t HOST_EP_PID;
- __IO uint8_t RESERVED50;
- __IO uint8_t RESERVED51;
- __IO uint8_t HOST_RX_CTRL;
- __IO uint16_t HOST_TX_LEN;
- __IO uint8_t HOST_TX_CTRL;
- __IO uint8_t RESERVED52;
- __IO uint16_t HOST_SPLIT_DATA;
-} USBHSH_TypeDef;
-
-#define USBHS_BASE ((uint32_t)(0x40000000 + 0x23400))
-
-#define USBHS_DEVICE ((USBHSD_TypeDef *)USBHS_BASE)
-#define USBHS_HOST ((USBHSH_TypeDef *)USBHS_BASE)
-
-/******************* GLOBAL ******************/
-
-// USB CONTROL
-#define USBHS_CONTROL_OFFSET 0x00
-#define USBHS_DMA_EN (1 << 0)
-#define USBHS_ALL_CLR (1 << 1)
-#define USBHS_FORCE_RST (1 << 2)
-#define USBHS_INT_BUSY_EN (1 << 3)
-#define USBHS_DEV_PU_EN (1 << 4)
-#define USBHS_SPEED_MASK (3 << 5)
-#define USBHS_FULL_SPEED (0 << 5)
-#define USBHS_HIGH_SPEED (1 << 5)
-#define USBHS_LOW_SPEED (2 << 5)
-#define USBHS_HOST_MODE (1 << 7)
-
-// USB_INT_EN
-#define USBHS_INT_EN_OFFSET 0x02
-#define USBHS_BUS_RST_EN (1 << 0)
-#define USBHS_DETECT_EN (1 << 0)
-#define USBHS_TRANSFER_EN (1 << 1)
-#define USBHS_SUSPEND_EN (1 << 2)
-#define USBHS_SOF_ACT_EN (1 << 3)
-#define USBHS_FIFO_OV_EN (1 << 4)
-#define USBHS_SETUP_ACT_EN (1 << 5)
-#define USBHS_ISO_ACT_EN (1 << 6)
-#define USBHS_DEV_NAK_EN (1 << 7)
-
-// USB DEV AD
-#define USBHS_DEV_AD_OFFSET 0x03
-// USB FRAME_NO
-#define USBHS_FRAME_NO_OFFSET 0x04
-// USB SUSPEND
-#define USBHS_SUSPEND_OFFSET 0x06
-#define USBHS_DEV_REMOTE_WAKEUP (1 << 2)
-#define USBHS_LINESTATE_MASK (2 << 4) /* Read Only */
-
-// RESERVED0
-
-// USB SPEED TYPE
-#define USBHS_SPEED_TYPE_OFFSET 0x08
-#define USBSPEED_MASK (0x03)
-
-// USB_MIS_ST
-#define USBHS_MIS_ST_OFFSET 0x09
-#define USBHS_SPLIT_CAN (1 << 0)
-#define USBHS_ATTACH (1 << 1)
-#define USBHS_SUSPEND (1 << 2)
-#define USBHS_BUS_RESET (1 << 3)
-#define USBHS_R_FIFO_RDY (1 << 4)
-#define USBHS_SIE_FREE (1 << 5)
-#define USBHS_SOF_ACT (1 << 6)
-#define USBHS_SOF_PRES (1 << 7)
-
-// INT_FLAG
-#define USBHS_INT_FLAG_OFFSET 0x0A
-#define USBHS_BUS_RST_FLAG (1 << 0)
-#define USBHS_DETECT_FLAG (1 << 0)
-#define USBHS_TRANSFER_FLAG (1 << 1)
-#define USBHS_SUSPEND_FLAG (1 << 2)
-#define USBHS_HST_SOF_FLAG (1 << 3)
-#define USBHS_FIFO_OV_FLAG (1 << 4)
-#define USBHS_SETUP_FLAG (1 << 5)
-#define USBHS_ISO_ACT_FLAG (1 << 6)
-
-// INT_ST
-#define USBHS_INT_ST_OFFSET 0x0B
-#define USBHS_DEV_UIS_IS_NAK (1 << 7)
-#define USBHS_DEV_UIS_TOG_OK (1 << 6)
-#define MASK_UIS_TOKEN (3 << 4)
-#define MASK_UIS_ENDP (0x0F)
-#define MASK_UIS_H_RES (0x0F)
-
-#define USBHS_TOGGLE_OK (0x40)
-#define USBHS_HOST_RES (0x0f)
-
-//USB_RX_LEN
-#define USBHS_RX_LEN_OFFSET 0x0C
-/******************* DEVICE ******************/
-
-//UEP_CONFIG
-#define USBHS_UEP_CONFIG_OFFSET 0x10
-#define USBHS_EP0_T_EN (1 << 0)
-#define USBHS_EP0_R_EN (1 << 16)
-
-#define USBHS_EP1_T_EN (1 << 1)
-#define USBHS_EP1_R_EN (1 << 17)
-
-#define USBHS_EP2_T_EN (1 << 2)
-#define USBHS_EP2_R_EN (1 << 18)
-
-#define USBHS_EP3_T_EN (1 << 3)
-#define USBHS_EP3_R_EN (1 << 19)
-
-#define USBHS_EP4_T_EN (1 << 4)
-#define USBHS_EP4_R_EN (1 << 20)
-
-#define USBHS_EP5_T_EN (1 << 5)
-#define USBHS_EP5_R_EN (1 << 21)
-
-#define USBHS_EP6_T_EN (1 << 6)
-#define USBHS_EP6_R_EN (1 << 22)
-
-#define USBHS_EP7_T_EN (1 << 7)
-#define USBHS_EP7_R_EN (1 << 23)
-
-#define USBHS_EP8_T_EN (1 << 8)
-#define USBHS_EP8_R_EN (1 << 24)
-
-#define USBHS_EP9_T_EN (1 << 9)
-#define USBHS_EP9_R_EN (1 << 25)
-
-#define USBHS_EP10_T_EN (1 << 10)
-#define USBHS_EP10_R_EN (1 << 26)
-
-#define USBHS_EP11_T_EN (1 << 11)
-#define USBHS_EP11_R_EN (1 << 27)
-
-#define USBHS_EP12_T_EN (1 << 12)
-#define USBHS_EP12_R_EN (1 << 28)
-
-#define USBHS_EP13_T_EN (1 << 13)
-#define USBHS_EP13_R_EN (1 << 29)
-
-#define USBHS_EP14_T_EN (1 << 14)
-#define USBHS_EP14_R_EN (1 << 30)
-
-#define USBHS_EP15_T_EN (1 << 15)
-#define USBHS_EP15_R_EN (1 << 31)
-
-//UEP_TYPE
-#define USBHS_UEP_TYPE_OFFSET 0x14
-#define USBHS_EP0_T_TYP (1 << 0)
-#define USBHS_EP0_R_TYP (1 << 16)
-
-#define USBHS_EP1_T_TYP (1 << 1)
-#define USBHS_EP1_R_TYP (1 << 17)
-
-#define USBHS_EP2_T_TYP (1 << 2)
-#define USBHS_EP2_R_TYP (1 << 18)
-
-#define USBHS_EP3_T_TYP (1 << 3)
-#define USBHS_EP3_R_TYP (1 << 19)
-
-#define USBHS_EP4_T_TYP (1 << 4)
-#define USBHS_EP4_R_TYP (1 << 20)
-
-#define USBHS_EP5_T_TYP (1 << 5)
-#define USBHS_EP5_R_TYP (1 << 21)
-
-#define USBHS_EP6_T_TYP (1 << 6)
-#define USBHS_EP6_R_TYP (1 << 22)
-
-#define USBHS_EP7_T_TYP (1 << 7)
-#define USBHS_EP7_R_TYP (1 << 23)
-
-#define USBHS_EP8_T_TYP (1 << 8)
-#define USBHS_EP8_R_TYP (1 << 24)
-
-#define USBHS_EP9_T_TYP (1 << 8)
-#define USBHS_EP9_R_TYP (1 << 25)
-
-#define USBHS_EP10_T_TYP (1 << 10)
-#define USBHS_EP10_R_TYP (1 << 26)
-
-#define USBHS_EP11_T_TYP (1 << 11)
-#define USBHS_EP11_R_TYP (1 << 27)
-
-#define USBHS_EP12_T_TYP (1 << 12)
-#define USBHS_EP12_R_TYP (1 << 28)
-
-#define USBHS_EP13_T_TYP (1 << 13)
-#define USBHS_EP13_R_TYP (1 << 29)
-
-#define USBHS_EP14_T_TYP (1 << 14)
-#define USBHS_EP14_R_TYP (1 << 30)
-
-#define USBHS_EP15_T_TYP (1 << 15)
-#define USBHS_EP15_R_TYP (1 << 31)
-
-/* BUF_MOD UEP1~15 */
-#define USBHS_BUF_MOD_OFFSET 0x18
-#define USBHS_EP0_BUF_MOD (1 << 0)
-#define USBHS_EP0_ISO_BUF_MOD (1 << 16)
-
-#define USBHS_EP1_BUF_MOD (1 << 1)
-#define USBHS_EP1_ISO_BUF_MOD (1 << 17)
-
-#define USBHS_EP2_BUF_MOD (1 << 2)
-#define USBHS_EP2_ISO_BUF_MOD (1 << 18)
-
-#define USBHS_EP3_BUF_MOD (1 << 3)
-#define USBHS_EP3_ISO_BUF_MOD (1 << 19)
-
-#define USBHS_EP4_BUF_MOD (1 << 4)
-#define USBHS_EP4_ISO_BUF_MOD (1 << 20)
-
-#define USBHS_EP5_BUF_MOD (1 << 5)
-#define USBHS_EP5_ISO_BUF_MOD (1 << 21)
-
-#define USBHS_EP6_BUF_MOD (1 << 6)
-#define USBHS_EP6_ISO_BUF_MOD (1 << 22)
-
-#define USBHS_EP7_BUF_MOD (1 << 7)
-#define USBHS_EP7_ISO_BUF_MOD (1 << 23)
-
-#define USBHS_EP8_BUF_MOD (1 << 8)
-#define USBHS_EP8_ISO_BUF_MOD (1 << 24)
-
-#define USBHS_EP9_BUF_MOD (1 << 9)
-#define USBHS_EP9_ISO_BUF_MOD (1 << 25)
-
-#define USBHS_EP10_BUF_MOD (1 << 10)
-#define USBHS_EP10_ISO_BUF_MOD (1 << 26)
-
-#define USBHS_EP11_BUF_MOD (1 << 11)
-#define USBHS_EP11_ISO_BUF_MOD (1 << 27)
-
-#define USBHS_EP12_BUF_MOD (1 << 12)
-#define USBHS_EP12_ISO_BUF_MOD (1 << 28)
-
-#define USBHS_EP13_BUF_MOD (1 << 13)
-#define USBHS_EP13_ISO_BUF_MOD (1 << 29)
-
-#define USBHS_EP14_BUF_MOD (1 << 14)
-#define USBHS_EP14_ISO_BUF_MOD (1 << 30)
-
-#define USBHS_EP15_BUF_MOD (1 << 15)
-#define USBHS_EP15_ISO_BUF_MOD (1 << 31)
-//USBHS_EPn_T_EN USBHS_EPn_R_EN USBHS_EPn_BUF_MOD 锟斤拷锟斤拷锟斤拷锟斤拷UEPn_DMA为锟斤拷始锟斤拷址锟缴碉拷锟斤拷锟斤拷锟斤拷锟�
-// 0 0 x 锟剿点被锟斤拷锟矫o拷未锟矫碉拷UEPn_*_DMA锟斤拷锟斤拷锟斤拷锟斤拷
-// 1 0 0 锟斤拷锟秸o拷OUT锟斤拷锟斤拷锟斤拷锟斤拷锟阶碉拷址为UEPn_RX_DMA
-// 1 0 1 bUEPn_RX_TOG[0]=0,使锟矫伙拷锟斤拷锟斤拷UEPn_RX_DMA锟斤拷bUEPn_RX_TOG[0]=1,使锟矫伙拷锟斤拷锟斤拷UEPn_TX_DMA
-// 0 1 0 锟斤拷锟斤拷(IN)锟斤拷锟斤拷锟斤拷锟阶碉拷址为UEPn_TX_DMA锟斤拷
-// 0 1 1 bUEPn_TX_TOG[0]=0,使锟矫伙拷锟斤拷锟斤拷UEPn_TX_DMA锟斤拷bUEPn_TX_TOG[0]=1,使锟矫伙拷锟斤拷锟斤拷UEPn_RX_DMA
-
-/* USB0_DMA */
-#define USBHS_UEP0_DMA_OFFSET(n) (0x1C) // endpoint 0 DMA buffer address
-
-/* USBX_RX_DMA */
-#define USBHS_UEPx_RX_DMA_OFFSET(n) (0x1C + 4 * (n)) // endpoint x DMA buffer address
-
-#define USBHS_UEPx_TX_DMA_OFFSET(n) (0x58 + 4 * (n)) // endpoint x DMA buffer address
-
-#define USBHS_UEPx_MAX_LEN_OFFSET(n) (0x98 + 4 * (n)) // endpoint x DMA buffer address
-
-#define USBHS_UEPx_T_LEN_OFFSET(n) (0xD8 + 4 * (n)) // endpoint x DMA buffer address
-#define USBHS_UEPx_TX_CTRL_OFFSET(n) (0xD8 + 4 * (n) + 2) // endpoint x DMA buffer address
-#define USBHS_UEPx_RX_CTRL_OFFSET(n) (0xD8 + 4 * (n) + 3) // endpoint x DMA buffer address
-
-// UEPn_T_LEN
-#define USBHS_EP_T_LEN_MASK (0x7FF)
-
-//UEPn_TX_CTRL
-#define USBHS_EP_T_RES_MASK (3 << 0)
-#define USBHS_EP_T_RES_ACK (0 << 0)
-#define USBHS_EP_T_RES_NYET (1 << 0)
-#define USBHS_EP_T_RES_NAK (2 << 0)
-#define USBHS_EP_T_RES_STALL (3 << 0)
-
-#define USBHS_EP_T_TOG_MASK (3 << 3)
-#define USBHS_EP_T_TOG_0 (0 << 3)
-#define USBHS_EP_T_TOG_1 (1 << 3)
-#define USBHS_EP_T_TOG_2 (2 << 3)
-#define USBHS_EP_T_TOG_M (3 << 3)
-
-#define USBHS_EP_T_AUTOTOG (1 << 5)
-
-//UEPn_RX_CTRL
-#define USBHS_EP_R_RES_MASK (3 << 0)
-#define USBHS_EP_R_RES_ACK (0 << 0)
-#define USBHS_EP_R_RES_NYET (1 << 0)
-#define USBHS_EP_R_RES_NAK (2 << 0)
-#define USBHS_EP_R_RES_STALL (3 << 0)
-
-#define USBHS_EP_R_TOG_MASK (3 << 3)
-#define USBHS_EP_R_TOG_0 (0 << 3)
-#define USBHS_EP_R_TOG_1 (1 << 3)
-#define USBHS_EP_R_TOG_2 (2 << 3)
-#define USBHS_EP_R_TOG_M (3 << 3)
-
-#define USBHS_EP_R_AUTOTOG (1 << 5)
-
-#define USBHS_TOG_MATCH (1 << 6)
-
-/******************* HOST ******************/
-// USB HOST_CTRL
-#define USBHS_SEND_BUS_RESET (1 << 0)
-#define USBHS_SEND_BUS_SUSPEND (1 << 1)
-#define USBHS_SEND_BUS_RESUME (1 << 2)
-#define USBHS_REMOTE_WAKE (1 << 3)
-#define USBHS_PHY_SUSPENDM (1 << 4)
-#define USBHS_UH_SOFT_FREE (1 << 6)
-#define USBHS_SEND_SOF_EN (1 << 7)
-
-//UH_CONFIG
-#define USBHS_HOST_TX_EN (1 << 3)
-#define USBHS_HOST_RX_EN (1 << 18)
-
-// HOST_EP_TYPE
-#define USBHS_ENDP_TX_ISO (1 << 3)
-#define USBHS_ENDP_RX_ISO (1 << (16 + 2))
-
-// R32_UH_EP_PID
-#define USBHS_HOST_MASK_TOKEN (0x0f)
-#define USBHS_HOST_MASK_ENDP (0x0f << 4)
-
-//R8_UH_RX_CTRL
-#define USBHS_EP_R_RES_MASK (3 << 0)
-#define USBHS_EP_R_RES_ACK (0 << 0)
-#define USBHS_EP_R_RES_NYET (1 << 0)
-#define USBHS_EP_R_RES_NAK (2 << 0)
-#define USBHS_EP_R_RES_STALL (3 << 0)
-
-#define USBHS_UH_R_RES_NO (1 << 2)
-#define USBHS_UH_R_TOG_1 (1 << 3)
-#define USBHS_UH_R_TOG_2 (2 << 3)
-#define USBHS_UH_R_TOG_3 (3 << 3)
-#define USBHS_UH_R_TOG_AUTO (1 << 5)
-#define USBHS_UH_R_DATA_NO (1 << 6)
-//R8_UH_TX_CTRL
-#define USBHS_UH_T_RES_MASK (3 << 0)
-#define USBHS_UH_T_RES_ACK (0 << 0)
-#define USBHS_UH_T_RES_NYET (1 << 0)
-#define USBHS_UH_T_RES_NAK (2 << 0)
-#define USBHS_UH_T_RES_STALL (3 << 0)
-
-#define USBHS_UH_T_RES_NO (1 << 2)
-#define USBHS_UH_T_TOG_1 (1 << 3)
-#define USBHS_UH_T_TOG_2 (2 << 3)
-#define USBHS_UH_T_TOG_3 (3 << 3)
-#define USBHS_UH_T_TOG_AUTO (1 << 5)
-#define USBHS_UH_T_DATA_NO (1 << 6)
-
-// 00: OUT, 01:SOF, 10:IN, 11:SETUP
-#define PID_OUT 0
-#define PID_SOF 1
-#define PID_IN 2
-#define PID_SETUP 3
-
-#endif
diff --git a/port/ch32/ch32hs/usb_dc_usbhs.c b/port/ch32/ch32hs/usb_dc_usbhs.c
deleted file mode 100644
index b882baf6..00000000
--- a/port/ch32/ch32hs/usb_dc_usbhs.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * Copyright (c) 2022, sakumisu
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#include "usbd_core.h"
-#include "usb_ch32_usbhs_reg.h"
-
-#ifndef USB_NUM_BIDIR_ENDPOINTS
-#define USB_NUM_BIDIR_ENDPOINTS 16
-#endif
-
-#define USB_SET_RX_DMA(ep_idx, addr) (*(volatile uint32_t *)((uint32_t)(&USBHS_DEVICE->UEP1_RX_DMA) + 4 * (ep_idx - 1)) = addr)
-#define USB_SET_TX_DMA(ep_idx, addr) (*(volatile uint32_t *)((uint32_t)(&USBHS_DEVICE->UEP1_TX_DMA) + 4 * (ep_idx - 1)) = addr)
-#define USB_SET_MAX_LEN(ep_idx, len) (*(volatile uint16_t *)((uint32_t)(&USBHS_DEVICE->UEP0_MAX_LEN) + 4 * ep_idx) = len)
-#define USB_SET_TX_LEN(ep_idx, len) (*(volatile uint16_t *)((uint32_t)(&USBHS_DEVICE->UEP0_TX_LEN) + 4 * ep_idx) = len)
-#define USB_GET_TX_LEN(ep_idx) (*(volatile uint16_t *)((uint32_t)(&USBHS_DEVICE->UEP0_TX_LEN) + 4 * ep_idx))
-#define USB_SET_TX_CTRL(ep_idx, val) (*(volatile uint8_t *)((uint32_t)(&USBHS_DEVICE->UEP0_TX_CTRL) + 4 * ep_idx) = val)
-#define USB_GET_TX_CTRL(ep_idx) (*(volatile uint8_t *)((uint32_t)(&USBHS_DEVICE->UEP0_TX_CTRL) + 4 * ep_idx))
-#define USB_SET_RX_CTRL(ep_idx, val) (*(volatile uint8_t *)((uint32_t)(&USBHS_DEVICE->UEP0_RX_CTRL) + 4 * ep_idx) = val)
-#define USB_GET_RX_CTRL(ep_idx) (*(volatile uint8_t *)((uint32_t)(&USBHS_DEVICE->UEP0_RX_CTRL) + 4 * ep_idx))
-
-/* Endpoint state */
-struct ch32_usbhs_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;
-};
-
-/* Driver state */
-struct ch32_usbhs_udc {
- __attribute__((aligned(4))) struct usb_setup_packet setup;
- volatile uint8_t dev_addr;
- struct ch32_usbhs_ep_state in_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< IN endpoint parameters*/
- struct ch32_usbhs_ep_state out_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< OUT endpoint parameters */
-} g_ch32_usbhs_udc;
-
-volatile uint8_t mps_over_flag = 0;
-volatile bool ep0_rx_data_toggle;
-volatile bool ep0_tx_data_toggle;
-volatile bool epx_tx_data_toggle[USB_NUM_BIDIR_ENDPOINTS - 1];
-
-__WEAK void usb_dc_low_level_init(void)
-{
-}
-
-__WEAK void usb_dc_low_level_deinit(void)
-{
-}
-
-int usb_dc_init(uint8_t busid)
-{
- usb_dc_low_level_init();
-
- USBHS_DEVICE->HOST_CTRL = 0x00;
- USBHS_DEVICE->HOST_CTRL = USBHS_PHY_SUSPENDM;
-
- USBHS_DEVICE->CONTROL = 0;
-#ifdef CONFIG_USB_HS
- USBHS_DEVICE->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
-#else
- USBHS_DEVICE->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED;
-#endif
-
- USBHS_DEVICE->INT_FG = 0xff;
- USBHS_DEVICE->INT_EN = 0;
- USBHS_DEVICE->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_DETECT_EN;
-
- USBHS_DEVICE->ENDP_TYPE = 0x00;
- USBHS_DEVICE->BUF_MODE = 0x00;
-
- USBHS_DEVICE->CONTROL |= USBHS_DEV_PU_EN;
-
- return 0;
-}
-
-int usb_dc_deinit(uint8_t busid)
-{
- return 0;
-}
-
-int usbd_set_address(uint8_t busid, const uint8_t addr)
-{
- if (addr == 0) {
- USBHS_DEVICE->DEV_AD = addr & 0xff;
- }
- g_ch32_usbhs_udc.dev_addr = addr;
- return 0;
-}
-
-int usbd_set_remote_wakeup(uint8_t busid)
-{
- return -1;
-}
-
-uint8_t usbd_get_port_speed(uint8_t busid)
-{
- return USB_SPEED_HIGH;
-}
-
-int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
-{
- uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
-
- if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
- g_ch32_usbhs_udc.out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
- g_ch32_usbhs_udc.out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
- g_ch32_usbhs_udc.out_ep[ep_idx].ep_enable = true;
- if (g_ch32_usbhs_udc.out_ep[ep_idx].ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- USBHS_DEVICE->ENDP_TYPE |= (1 << (ep_idx + 16));
- } else {
- USBHS_DEVICE->ENDP_TYPE &= ~(1 << (ep_idx + 16));
- }
- USBHS_DEVICE->ENDP_CONFIG |= (1 << (ep_idx + 16));
- USB_SET_RX_CTRL(ep_idx, USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0 | USBHS_EP_R_AUTOTOG);
- } else {
- g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
- g_ch32_usbhs_udc.in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
- g_ch32_usbhs_udc.in_ep[ep_idx].ep_enable = true;
- if (g_ch32_usbhs_udc.in_ep[ep_idx].ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- USBHS_DEVICE->ENDP_TYPE |= (1 << (ep_idx));
- USB_SET_TX_CTRL(ep_idx, USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0);
- } else {
- USBHS_DEVICE->ENDP_TYPE &= ~(1 << (ep_idx));
- USB_SET_TX_CTRL(ep_idx, USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0 | USBHS_EP_T_AUTOTOG);
- }
- USBHS_DEVICE->ENDP_CONFIG |= (1 << (ep_idx));
- }
- USB_SET_MAX_LEN(ep_idx, USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize));
- return 0;
-}
-
-int usbd_ep_close(uint8_t busid, const uint8_t ep)
-{
- uint8_t ep_idx = USB_EP_GET_IDX(ep);
- if (USB_EP_DIR_IS_OUT(ep)) {
- USBHS_DEVICE->ENDP_CONFIG &= ~(1 << (ep_idx + 16));
- } else {
- USBHS_DEVICE->ENDP_CONFIG &= ~(1 << (ep_idx));
- }
- return 0;
-}
-
-int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
-{
- uint8_t ep_idx = USB_EP_GET_IDX(ep);
-
- if (USB_EP_DIR_IS_OUT(ep)) {
- if (ep_idx == 0) {
- USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_STALL;
- } else {
- USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_STALL);
- }
- } else {
- if (ep_idx == 0) {
- USBHS_DEVICE->UEP0_TX_CTRL = USBHS_EP_T_RES_STALL;
- } else {
- USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBHS_EP_T_RES_MASK) | USBHS_EP_T_RES_STALL);
- }
- }
-
- return 0;
-}
-
-int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
-{
- uint8_t ep_idx = USB_EP_GET_IDX(ep);
-
- if (USB_EP_DIR_IS_OUT(ep)) {
- USB_SET_RX_CTRL(ep_idx, USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0);
- } else {
- USB_SET_TX_CTRL(ep_idx, USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0);
- }
- return 0;
-}
-
-int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
-{
- uint8_t ep_idx = USB_EP_GET_IDX(ep);
-
- if (USB_EP_DIR_IS_OUT(ep)) {
- *stalled = USB_GET_RX_CTRL(ep_idx) & USBHS_EP_R_RES_STALL ? 1 : 0;
- } else {
- *stalled = USB_GET_TX_CTRL(ep_idx) & USBHS_EP_T_RES_STALL ? 1 : 0;
- }
- return 0;
-}
-
-int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len)
-{
- uint8_t ep_idx = USB_EP_GET_IDX(ep);
- uint32_t tmp;
-
- if (!data && data_len) {
- return -1;
- }
- if (!g_ch32_usbhs_udc.in_ep[ep_idx].ep_enable) {
- return -2;
- }
- if ((uint32_t)data & 0x03) {
- return -3;
- }
-
- g_ch32_usbhs_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data;
- g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len = data_len;
- g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len = 0;
-
- if (ep_idx == 0) {
- if (data_len == 0) {
- USB_SET_TX_LEN(ep_idx, 0);
- } else {
- data_len = MIN(data_len, g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps);
- USB_SET_TX_LEN(ep_idx, data_len);
- USBHS_DEVICE->UEP0_DMA = (uint32_t)data;
- }
- tmp = ep0_tx_data_toggle ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0;
- USBHS_DEVICE->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | tmp;
- } else {
- if (data_len == 0) {
- USB_SET_TX_LEN(ep_idx, 0);
- } else {
- data_len = MIN(data_len, g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps);
- USB_SET_TX_LEN(ep_idx, data_len);
- USB_SET_TX_DMA(ep_idx, (uint32_t)data);
- }
- tmp = USB_GET_TX_CTRL(ep_idx);
- tmp &= ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK);
- tmp |= USBHS_EP_T_RES_ACK;
- if (g_ch32_usbhs_udc.in_ep[ep_idx].ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- tmp |= USBHS_EP_T_TOG_0;
- } else {
- tmp |= (epx_tx_data_toggle[ep_idx - 1] ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
- }
- USB_SET_TX_CTRL(ep_idx, tmp);
- }
- return 0;
-}
-
-int usbd_ep_start_read(uint8_t busid, 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_ch32_usbhs_udc.out_ep[ep_idx].ep_enable) {
- return -2;
- }
- if ((uint32_t)data & 0x03) {
- return -3;
- }
-
- g_ch32_usbhs_udc.out_ep[ep_idx].xfer_buf = (uint8_t *)data;
- g_ch32_usbhs_udc.out_ep[ep_idx].xfer_len = data_len;
- g_ch32_usbhs_udc.out_ep[ep_idx].actual_xfer_len = 0;
-
- if (ep_idx == 0) {
- if (data_len == 0) {
- USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_1;
- } else {
- USBHS_DEVICE->UEP0_DMA = (uint32_t)data;
- USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | (ep0_rx_data_toggle ? USBHS_EP_R_TOG_1 : USBHS_EP_R_TOG_0);
- }
- return 0;
- } else {
- USB_SET_RX_DMA(ep_idx, (uint32_t)data);
- if (g_ch32_usbhs_udc.out_ep[ep_idx].ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~(USBHS_EP_R_RES_MASK | USBHS_EP_R_TOG_MASK)) | USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0);
- } else {
- USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_ACK);
- }
- }
-
- return 0;
-}
-
-void USBD_IRQHandler(uint8_t busid)
-{
- uint32_t ep_idx, token, write_count, read_count;
- uint8_t intflag = 0;
-
- intflag = USBHS_DEVICE->INT_FG;
-
- if (intflag & USBHS_TRANSFER_FLAG) {
- ep_idx = (USBHS_DEVICE->INT_ST) & MASK_UIS_ENDP;
- token = (((USBHS_DEVICE->INT_ST) & MASK_UIS_TOKEN) >> 4) & 0x03;
-
- USBHS_DEVICE->INT_FG = USBHS_TRANSFER_FLAG;
-
- if (token == PID_IN) {
- USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0);
- 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) {
- 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;
- } else {
- g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len;
- g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len = 0;
- ep0_tx_data_toggle = true;
- }
-
- usbd_event_ep_in_complete_handler(0, ep_idx | 0x80, g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len);
-
- if (g_ch32_usbhs_udc.dev_addr > 0) {
- USBHS_DEVICE->DEV_AD = g_ch32_usbhs_udc.dev_addr & 0xff;
- g_ch32_usbhs_udc.dev_addr = 0;
- }
-
- if (g_ch32_usbhs_udc.setup.wLength && ((g_ch32_usbhs_udc.setup.bmRequestType & USB_REQUEST_DIR_MASK) == USB_REQUEST_DIR_OUT)) {
- /* In status, start reading setup */
- USBHS_DEVICE->UEP0_DMA = (uint32_t)&g_ch32_usbhs_udc.setup;
- USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
- ep0_tx_data_toggle = true;
-
- } else if (g_ch32_usbhs_udc.setup.wLength == 0) {
- /* In status, start reading setup */
- USBHS_DEVICE->UEP0_DMA = (uint32_t)&g_ch32_usbhs_udc.setup;
- USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
- ep0_tx_data_toggle = true;
- }
- } else {
- 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_buf += 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;
- epx_tx_data_toggle[ep_idx - 1] ^= 1;
-
- write_count = MIN(g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len, g_ch32_usbhs_udc.in_ep[ep_idx].ep_mps);
- USB_SET_TX_LEN(ep_idx, write_count);
- USB_SET_TX_DMA(ep_idx, (uint32_t)g_ch32_usbhs_udc.in_ep[ep_idx].xfer_buf);
-
- uint32_t tmp = USB_GET_TX_CTRL(ep_idx);
- tmp &= ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK);
- tmp |= USBHS_EP_T_RES_ACK;
-
- if (g_ch32_usbhs_udc.in_ep[ep_idx].ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- tmp |= USBHS_EP_T_TOG_0;
- } else {
- tmp |= (epx_tx_data_toggle[ep_idx - 1] ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
- }
-
- USB_SET_TX_CTRL(ep_idx, tmp);
- } else {
- g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len += g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len;
- g_ch32_usbhs_udc.in_ep[ep_idx].xfer_len = 0;
- epx_tx_data_toggle[ep_idx - 1] ^= 1;
- usbd_event_ep_in_complete_handler(0, ep_idx | 0x80, g_ch32_usbhs_udc.in_ep[ep_idx].actual_xfer_len);
- }
- }
- } else if (token == PID_OUT) {
- USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_NAK);
- if (ep_idx == 0x00) {
- read_count = USBHS_DEVICE->RX_LEN;
-
- g_ch32_usbhs_udc.out_ep[ep_idx].actual_xfer_len += read_count;
- g_ch32_usbhs_udc.out_ep[ep_idx].xfer_len -= read_count;
-
- usbd_event_ep_out_complete_handler(0, 0x00, g_ch32_usbhs_udc.out_ep[ep_idx].actual_xfer_len);
-
- if (read_count == 0) {
- /* Out status, start reading setup */
- USBHS_DEVICE->UEP0_DMA = (uint32_t)&g_ch32_usbhs_udc.setup;
- USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
- ep0_rx_data_toggle = true;
- ep0_tx_data_toggle = true;
- } else {
- ep0_rx_data_toggle ^= 1;
- }
- } else {
- if (USBHS_DEVICE->INT_ST & USBHS_DEV_UIS_TOG_OK) {
- read_count = USBHS_DEVICE->RX_LEN;
-
- g_ch32_usbhs_udc.out_ep[ep_idx].xfer_buf += read_count;
- g_ch32_usbhs_udc.out_ep[ep_idx].actual_xfer_len += read_count;
- g_ch32_usbhs_udc.out_ep[ep_idx].xfer_len -= read_count;
-
- if ((read_count < g_ch32_usbhs_udc.out_ep[ep_idx].ep_mps) || (g_ch32_usbhs_udc.out_ep[ep_idx].xfer_len == 0)) {
- usbd_event_ep_out_complete_handler(0, ep_idx, g_ch32_usbhs_udc.out_ep[ep_idx].actual_xfer_len);
- } else {
- USB_SET_RX_DMA(ep_idx, (uint32_t)g_ch32_usbhs_udc.out_ep[ep_idx].xfer_buf);
- USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_ACK);
- }
- }
- }
- }
- }
-
- if (intflag & USBHS_SETUP_FLAG) {
- USBHS_DEVICE->INT_FG = USBHS_SETUP_FLAG;
- usbd_event_ep0_setup_complete_handler(0, (uint8_t *)&g_ch32_usbhs_udc.setup);
- }
-
- if (intflag & USBHS_DETECT_FLAG) {
- USBHS_DEVICE->INT_FG = USBHS_DETECT_FLAG;
-
- USBHS_DEVICE->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
-
- USBHS_DEVICE->UEP0_TX_LEN = 0;
- USBHS_DEVICE->UEP0_TX_CTRL = USBHS_EP_T_RES_NAK;
-
- ep0_tx_data_toggle = true;
- ep0_rx_data_toggle = true;
-
- for (uint8_t ep_idx = 1; ep_idx < USB_NUM_BIDIR_ENDPOINTS; ep_idx++) {
- USB_SET_TX_LEN(ep_idx, 0);
- USB_SET_TX_CTRL(ep_idx, USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK); // autotog does not work
- USB_SET_RX_CTRL(ep_idx, USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK);
- epx_tx_data_toggle[ep_idx - 1] = false;
- }
-
- memset(&g_ch32_usbhs_udc, 0, sizeof(struct ch32_usbhs_udc));
- usbd_event_reset_handler(0);
- USBHS_DEVICE->UEP0_DMA = (uint32_t)&g_ch32_usbhs_udc.setup;
- USBHS_DEVICE->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
- }
-}
-
-void USBHS_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
-void USBHS_IRQHandler(void)
-{
- extern void USBD_IRQHandler(uint8_t busid);
- USBD_IRQHandler(0);
-}
diff --git a/port/ch32/ch58x/usb_ch585_usbhs_dc.c b/port/ch32/ch58x/usb_ch585_usbhs_dc.c
deleted file mode 100644
index 2e6724c2..00000000
--- a/port/ch32/ch58x/usb_ch585_usbhs_dc.c
+++ /dev/null
@@ -1,526 +0,0 @@
-#include "usbd_core.h"
-#include "usb_ch585_usbhs_reg.h"
-
-/**
- * @brief Related register macro
- */
-#define USB_BASE 0x40009000u
-#define CH585_USBHS_DEV ((USBHSD_TypeDef *)USB_BASE)
-
-#define R16_PIN_CONFIG (*((PUINT16V)0x4000101A))
-#define R32_PIN_CONFIG (*((PUINT32V)0x40001018)) // RW, I/O pin configuration
-#define RB_PIN_USB2_EN 0x20
-
-#define USB_SET_RX_DMA(ep_idx, addr) (*(volatile uint32_t *)((uint32_t)(&CH585_USBHS_DEV->UEP1_RX_DMA) + 4 * (ep_idx - 1)) = addr)
-#define USB_SET_TX_DMA(ep_idx, addr) (*(volatile uint32_t *)((uint32_t)(&CH585_USBHS_DEV->UEP1_TX_DMA) + 4 * (ep_idx - 1)) = addr)
-
-#define USB_SET_MAX_LEN(ep_idx, len) (*(volatile uint16_t *)((uint32_t)(&CH585_USBHS_DEV->UEP0_MAX_LEN) + 4 * ep_idx) = len)
-#define USB_SET_TX_LEN(ep_idx, len) (*(volatile uint16_t *)((uint32_t)(&CH585_USBHS_DEV->UEP0_TX_LEN) + 4 * ep_idx) = len)
-#define USB_GET_TX_LEN(ep_idx) (*(volatile uint16_t *)((uint32_t)(&CH585_USBHS_DEV->UEP0_TX_LEN) + 4 * ep_idx))
-#define USB_SET_TX_CTRL(ep_idx, val) (*(volatile uint8_t *)((uint32_t)(&CH585_USBHS_DEV->UEP0_TX_CTRL) + 4 * ep_idx) = val)
-#define USB_GET_TX_CTRL(ep_idx) (*(volatile uint8_t *)((uint32_t)(&CH585_USBHS_DEV->UEP0_TX_CTRL) + 4 * ep_idx))
-#define USB_SET_RX_CTRL(ep_idx, val) (*(volatile uint8_t *)((uint32_t)(&CH585_USBHS_DEV->UEP0_RX_CTRL) + 4 * ep_idx) = val)
-#define USB_GET_RX_CTRL(ep_idx) (*(volatile uint8_t *)((uint32_t)(&CH585_USBHS_DEV->UEP0_RX_CTRL) + 4 * ep_idx))
-#define EPn_SET_TX_NAK(ep_idx) USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_NAK)
-#define EPn_SET_TX_VALID(ep_idx) USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK)
-#define EPn_SET_RX_NAK(ep_idx) USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_NAK)
-#define EPn_SET_RX_VALID(ep_idx) USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_ACK)
-#define EPn_GET_RX_LEN(ep_idx) (*(volatile uint16_t *)((uint32_t)(&CH585_USBHS_DEV->USB_EP0_RX_LEN) + 4 * ep_idx))
-#define EPn_SET_TX_LEN(ep_idx, len) (*(volatile uint16_t *)((uint32_t)(&CH585_USBHS_DEV->UEP0_TX_LEN) + 4 * ep_idx) = len)
-#define EPn_CLEAR_TX_DONE(ep_idx) USB_SET_TX_CTRL(ep_idx, USB_GET_TX_CTRL(ep_idx) & ~USBHS_UEP_T_DONE)
-#define EPn_CLEAR_RX_DONE(ep_idx) USB_SET_RX_CTRL(ep_idx, USB_GET_RX_CTRL(ep_idx) & ~USBHS_UEP_R_DONE)
-#define EPn_SET_TX_ISO_VALID(ep_idx)
-#define EPn_SET_RX_ISO_VALID(ep_idx)
-
-/* ep nums */
-#ifndef CONFIG_USBDEV_EP_NUM
-#define CONFIG_USBDEV_EP_NUM 8
-#endif
-
-/**
- * @brief Endpoint information structure
- */
-typedef struct _usbd_ep_info {
- uint8_t mps; /* Maximum packet length of endpoint */
- uint8_t eptype; /* Endpoint Type */
- uint8_t ep_enable; /* Endpoint enable */
- uint8_t *xfer_buf;
- uint32_t xfer_len;
- uint32_t actual_xfer_len;
-} usbd_ep_info;
-
-/* ch58x usb */
-static struct _ch58x_core_prvi {
- uint8_t address; /* Address */
- usbd_ep_info ep_in[CONFIG_USBDEV_EP_NUM];
- usbd_ep_info ep_out[CONFIG_USBDEV_EP_NUM];
- struct usb_setup_packet setup;
-} usb_dc_cfg;
-
-__WEAK void usb_dc_low_level_init(void)
-{
-}
-
-__WEAK void usb_dc_low_level_deinit(void)
-{
-}
-
-/**
- * @brief USB initialization
- * @pre None
- * @param[in] None
- * @retval >=0 success otherwise failure
- */
-int usb_dc_init(uint8_t busid)
-{
- R8_USBHS_PLL_CTRL = USBHS_PLL_EN;
- R16_PIN_CONFIG |= RB_PIN_USB2_EN;
- CH585_USBHS_DEV->CONTROL = USBHS_UD_RST_LINK | USBHS_UD_PHY_SUSPENDM;
- CH585_USBHS_DEV->INT_EN = USBHS_UDIE_BUS_RST | USBHS_UDIE_SUSPEND | USBHS_UDIE_BUS_SLEEP | USBHS_UDIE_LPM_ACT | USBHS_UDIE_TRANSFER | USBHS_UDIE_LINK_RDY;
- /* Enable all end points */
- CH585_USBHS_DEV->UEP_TX_EN = 0xffff;
- CH585_USBHS_DEV->UEP_RX_EN = 0xffff;
-
- CH585_USBHS_DEV->BASE_MODE = USBHS_UD_SPEED_HIGH;
- CH585_USBHS_DEV->CONTROL = USBHS_UD_DEV_EN | USBHS_UD_DMA_EN | USBHS_UD_LPM_EN | USBHS_UD_PHY_SUSPENDM;
-
- CH585_USBHS_DEV->UEP_T_TOG_AUTO = 0xfe;
- CH585_USBHS_DEV->UEP_R_TOG_AUTO = 0xfe;
- usb_dc_low_level_init();
- return 0;
-}
-
-int usb_dc_deinit(uint8_t busid)
-{
- R8_USBHS_PLL_CTRL &= ~USBHS_PLL_EN;
- R32_PIN_CONFIG &= ~RB_PIN_USB2_EN;
-
- CH585_USBHS_DEV->CONTROL |= USBHS_UD_RST_SIE;
- CH585_USBHS_DEV->CONTROL &= ~USBHS_UD_RST_SIE;
- usb_dc_low_level_deinit();
- return 0;
-}
-
-/**
- * @brief Set address
- * @pre None
- * @param[in] address :8-bit valid address
- * @retval >=0 success otherwise failure
- */
-int usbd_set_address(uint8_t busid, const uint8_t address)
-{
- if (address == 0) {
- CH585_USBHS_DEV->DEV_AD = (CH585_USBHS_DEV->DEV_AD & 0x80) | address;
- }
- usb_dc_cfg.address = address;
- return 0;
-}
-
-int usbd_set_remote_wakeup(uint8_t busid)
-{
- return -1;
-}
-
-uint8_t usbd_get_port_speed(uint8_t busid)
-{
- return USB_SPEED_HIGH;
-}
-
-/**
- * @brief Open endpoint
- * @pre None
- * @param[in] ep_cfg : Endpoint configuration structure pointer
- * @retval >=0 success otherwise failure
- */
-int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
-{
- uint8_t epid = USB_EP_GET_IDX(ep->bEndpointAddress);
- if (epid > (CONFIG_USBDEV_EP_NUM - 1)) {
- /**
- * If you use ch58x, you can change the CONFIG_USBDEV_EP_NUM set to 8
- */
- USB_LOG_ERR("Ep addr %02x overflow\r\n", ep->bEndpointAddress);
- return -1;
- }
-
- uint8_t mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
- USB_SET_MAX_LEN(epid, mps);
-
- if (USB_EP_DIR_IS_IN(ep->bEndpointAddress)) {
- usb_dc_cfg.ep_in[epid].ep_enable = true;
- usb_dc_cfg.ep_in[epid].mps = mps;
- usb_dc_cfg.ep_in[epid].eptype = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
- USB_SET_TX_CTRL(epid, USBHS_UEP_T_RES_NAK);
- EPn_CLEAR_TX_DONE(epid);
- } else if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
- usb_dc_cfg.ep_out[epid].ep_enable = true;
- usb_dc_cfg.ep_out[epid].mps = mps;
- usb_dc_cfg.ep_out[epid].eptype = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
- USB_SET_RX_CTRL(epid, USBHS_UEP_R_RES_NAK);
- }
-
- return 0;
-}
-
-/**
- * @brief Close endpoint
- * @pre None
- * @param[in] ep : Endpoint address
- * @retval >=0 success otherwise failure
- */
-int usbd_ep_close(uint8_t busid, const uint8_t ep)
-{
- uint8_t epid = USB_EP_GET_IDX(ep);
- if (USB_EP_DIR_IS_IN(ep)) {
- usb_dc_cfg.ep_in[epid].ep_enable = false;
- } else if (USB_EP_DIR_IS_OUT(ep)) {
- usb_dc_cfg.ep_out[epid].ep_enable = false;
- }
- return 0;
-}
-
-/**
- * @brief Endpoint setting stall
- * @pre None
- * @param[in] ep : Endpoint address
- * @retval >=0 success otherwise failure
- */
-int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
-{
- uint8_t ep_idx = USB_EP_GET_IDX(ep);
- if (USB_EP_DIR_IS_OUT(ep)) {
- if (ep_idx == 0) {
- CH585_USBHS_DEV->UEP0_RX_CTRL = USBHS_UEP_R_RES_STALL;
- } else {
- USB_SET_RX_CTRL(ep_idx, (USB_GET_RX_CTRL(ep_idx) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_STALL);
- }
- } else {
- if (ep_idx == 0) {
- CH585_USBHS_DEV->UEP0_TX_CTRL = USBHS_UEP_T_RES_STALL;
- } else {
- USB_SET_TX_CTRL(ep_idx, (USB_GET_TX_CTRL(ep_idx) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_STALL);
- }
- }
- return 0;
-}
-
-/**
- * @brief Endpoint clear stall
- * @pre None
- * @param[in] ep : Endpoint address
- * @retval >=0 success otherwise failure
- */
-int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
-{
- uint8_t ep_idx = USB_EP_GET_IDX(ep);
-
- if (USB_EP_DIR_IS_OUT(ep)) {
- USB_SET_RX_CTRL(ep_idx, USBHS_UEP_R_RES_ACK | USBHS_UEP_R_TOG_DATA0);
- } else {
- USB_SET_TX_CTRL(ep_idx, USBHS_UEP_T_RES_NAK | USBHS_UEP_T_TOG_DATA0);
- }
- return 0;
-}
-
-/**
- * @brief Check endpoint status
- * @pre None
- * @param[in] ep : Endpoint address
- * @param[out] stalled : Outgoing endpoint status
- * @retval >=0 success otherwise failure
- */
-int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
-{
- if (USB_EP_DIR_IS_OUT(ep)) {
- } else {
- }
- return 0;
-}
-
-/**
- * @brief Setup in ep transfer setting and start transfer.
- *
- * This function is asynchronous.
- * This function is similar to uart with tx dma.
- *
- * This function is called to write data to the specified endpoint. The
- * supplied usbd_endpoint_callback function will be called when data is transmitted
- * out.
- *
- * @param[in] ep Endpoint address corresponding to the one
- * listed in the device configuration table
- * @param[in] data Pointer to data to write
- * @param[in] data_len Length of the data requested to write. This may
- * be zero for a zero length status packet.
- * @return 0 on success, negative errno code on fail.
- */
-int usbd_ep_start_write(uint8_t busid, 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 (!usb_dc_cfg.ep_in[ep_idx].ep_enable) {
- return -2;
- }
- if ((uint32_t)data & 0x03) {
- return -3;
- }
-
- usb_dc_cfg.ep_in[ep_idx].xfer_buf = (uint8_t *)data;
- usb_dc_cfg.ep_in[ep_idx].xfer_len = data_len;
- usb_dc_cfg.ep_in[ep_idx].actual_xfer_len = 0;
-
- if (ep_idx == 0) {
- if (data_len == 0) {
- USB_SET_TX_LEN(ep_idx, 0);
- } else {
- data_len = MIN(data_len, usb_dc_cfg.ep_in[ep_idx].mps);
- USB_SET_TX_LEN(ep_idx, data_len);
- CH585_USBHS_DEV->UEP0_DMA = (uint32_t)data;
- }
- } else {
- if (data_len == 0) {
- USB_SET_TX_LEN(ep_idx, 0);
- } else {
- data_len = MIN(data_len, usb_dc_cfg.ep_in[ep_idx].mps);
- USB_SET_TX_LEN(ep_idx, data_len);
- USB_SET_TX_DMA(ep_idx, (uint32_t)data);
- }
- }
-
- EPn_SET_TX_VALID(ep_idx);
- return 0;
-}
-
-/**
- * @brief Setup out ep transfer setting and start transfer.
- *
- * This function is asynchronous.
- * This function is similar to uart with rx dma.
- *
- * This function is called to read data to the specified endpoint. The
- * supplied usbd_endpoint_callback function will be called when data is received
- * in.
- *
- * @param[in] ep Endpoint address corresponding to the one
- * listed in the device configuration table
- * @param[in] data Pointer to data to read
- * @param[in] data_len Max length of the data requested to read.
- *
- * @return 0 on success, negative errno code on fail.
- */
-int usbd_ep_start_read(uint8_t busid, 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 (!usb_dc_cfg.ep_out[ep_idx].ep_enable) {
- return -2;
- }
- if ((uint32_t)data & 0x03) {
- return -3;
- }
-
- usb_dc_cfg.ep_out[ep_idx].xfer_buf = (uint8_t *)data;
- usb_dc_cfg.ep_out[ep_idx].xfer_len = data_len;
- usb_dc_cfg.ep_out[ep_idx].actual_xfer_len = 0;
-
- if (ep_idx == 0) {
- if (data_len == 0) {
- } else {
- CH585_USBHS_DEV->UEP0_DMA = (uint32_t)data;
- }
- } else {
- USB_SET_RX_DMA(ep_idx, (uint32_t)data);
- }
-
- EPn_SET_RX_VALID(ep_idx);
- return 0;
-}
-
-static inline void handle_ep0_in(void)
-{
- switch (usb_dc_cfg.setup.bmRequestType >> USB_REQUEST_DIR_SHIFT) {
- case 1:
- CH585_USBHS_DEV->UEP0_TX_CTRL ^= USBHS_UEP_T_TOG_DATA1;
- EPn_SET_TX_NAK(0);
- if (usb_dc_cfg.ep_in[0].xfer_len > usb_dc_cfg.ep_in[0].mps) {
- usb_dc_cfg.ep_in[0].xfer_len -= usb_dc_cfg.ep_in[0].mps;
- usb_dc_cfg.ep_in[0].actual_xfer_len += usb_dc_cfg.ep_in[0].mps;
- usbd_event_ep_in_complete_handler(0, 0 | 0x80, usb_dc_cfg.ep_in[0].actual_xfer_len);
- } else {
- usb_dc_cfg.ep_in[0].actual_xfer_len += usb_dc_cfg.ep_in[0].xfer_len;
- usb_dc_cfg.ep_in[0].xfer_len = 0;
- usbd_event_ep_in_complete_handler(0, 0 | 0x80, usb_dc_cfg.ep_in[0].actual_xfer_len);
- }
- break;
- case 0:
- /* Set */
- switch (usb_dc_cfg.setup.bRequest) {
- case USB_REQUEST_SET_ADDRESS:
- /* Fill in the equipment address */
- CH585_USBHS_DEV->DEV_AD = usb_dc_cfg.address;
- CH585_USBHS_DEV->UEP0_DMA = (uint32_t)&usb_dc_cfg.setup;
- EPn_SET_TX_NAK(0);
- EPn_SET_RX_VALID(0);
- break;
- default:
- /* Normal out state phase */
- CH585_USBHS_DEV->UEP0_DMA = (uint32_t)&usb_dc_cfg.setup;
- EPn_SET_TX_NAK(0);
- EPn_SET_RX_VALID(0);
- break;
- }
- break;
- }
-}
-
-static inline void handle_non_ep0_in(uint8_t epid)
-{
- EPn_SET_TX_NAK(epid);
- if (usb_dc_cfg.ep_in[epid].xfer_len > usb_dc_cfg.ep_in[epid].mps) {
- /* Need start in again */
- usb_dc_cfg.ep_in[epid].xfer_buf += usb_dc_cfg.ep_in[epid].mps;
- usb_dc_cfg.ep_in[epid].xfer_len -= usb_dc_cfg.ep_in[epid].mps;
- usb_dc_cfg.ep_in[epid].actual_xfer_len += usb_dc_cfg.ep_in[epid].mps;
-
- uint32_t write_count = MIN(usb_dc_cfg.ep_in[epid].xfer_len, usb_dc_cfg.ep_in[epid].mps);
- USB_SET_TX_LEN(epid, write_count);
- USB_SET_TX_DMA(epid, (uint32_t)usb_dc_cfg.ep_in[epid].xfer_buf);
-
- if (usb_dc_cfg.ep_in[epid].eptype != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- EPn_SET_TX_VALID(epid);
- } else {
- EPn_SET_TX_ISO_VALID(epid);
- }
- } else {
- usb_dc_cfg.ep_in[epid].actual_xfer_len += usb_dc_cfg.ep_in[epid].xfer_len;
- usb_dc_cfg.ep_in[epid].xfer_len = 0;
- usbd_event_ep_in_complete_handler(0, epid | 0x80, usb_dc_cfg.ep_in[epid].actual_xfer_len);
- }
-}
-
-static inline void usb_process_ep_in(uint8_t epid)
-{
- if (epid == 0) {
- handle_ep0_in();
- } else {
- handle_non_ep0_in(epid);
- }
-
- EPn_CLEAR_TX_DONE(epid);
-}
-
-static inline void usb_process_ep_out(uint8_t epid)
-{
- EPn_SET_RX_NAK(epid);
- if (epid == 0) {
- if (CH585_USBHS_DEV->UEP0_RX_CTRL & USBHS_UEP_R_SETUP_IS) {
- CH585_USBHS_DEV->UEP0_RX_CTRL |= USBHS_UEP_R_TOG_DATA1;
- CH585_USBHS_DEV->UEP0_TX_CTRL |= USBHS_UEP_T_TOG_DATA1;
- if (usb_dc_cfg.setup.bmRequestType >> USB_REQUEST_DIR_SHIFT == 0) {
- /**
- * Ep0 The next in must be the status stage.
- * The device must reply to the host data 0 length packet.
- * Here, set the transmission length to 0 and the transmission status to ACK,
- * and wait for the host to send the in token to retrieve
- */
- EPn_SET_TX_LEN(0, 0);
- EPn_SET_TX_VALID(0);
- }
- usbd_event_ep0_setup_complete_handler(0, (uint8_t *)&usb_dc_cfg.setup);
- } else {
- CH585_USBHS_DEV->UEP0_RX_CTRL ^= USBHS_UEP_R_TOG_DATA1;
- uint32_t read_count = EPn_GET_RX_LEN(0);
- usb_dc_cfg.ep_out[0].actual_xfer_len += read_count;
- usb_dc_cfg.ep_out[0].xfer_len -= read_count;
- usbd_event_ep_out_complete_handler(0, 0x00, usb_dc_cfg.ep_out[0].actual_xfer_len);
- if (read_count == 0) {
- /* Out status, start reading setup */
- CH585_USBHS_DEV->UEP0_DMA = (uint32_t)&usb_dc_cfg.setup;
- EPn_SET_RX_VALID(0);
- }
- }
- } else {
- if (USB_GET_RX_CTRL(epid) & USBHS_UEP_R_TOG_MATCH) {
- uint32_t read_count = EPn_GET_RX_LEN(epid);
- usb_dc_cfg.ep_out[epid].xfer_buf += read_count;
- usb_dc_cfg.ep_out[epid].actual_xfer_len += read_count;
- usb_dc_cfg.ep_out[epid].xfer_len -= read_count;
-
- if ((read_count < usb_dc_cfg.ep_out[epid].mps) || (usb_dc_cfg.ep_out[epid].xfer_len == 0)) {
- usbd_event_ep_out_complete_handler(0, ((epid) & 0x7f), usb_dc_cfg.ep_out[epid].actual_xfer_len);
- } else {
- USB_SET_RX_DMA(epid, (uint32_t)usb_dc_cfg.ep_out[epid].xfer_buf);
- if (usb_dc_cfg.ep_out[epid].eptype != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- EPn_SET_RX_VALID(epid);
- } else {
- EPn_SET_RX_ISO_VALID(epid);
- }
- }
- }
- }
-
- EPn_CLEAR_RX_DONE(epid);
-}
-
-static inline void usb_trans_end_process(void)
-{
- uint8_t epid = (CH585_USBHS_DEV->INT_ST & USBHS_UDIS_EP_ID_MASK);
- switch (CH585_USBHS_DEV->INT_ST & USBHS_UDIS_EP_DIR) {
- case USBHS_UDIS_EP_DIR: /* in */
- usb_process_ep_in(epid);
- break;
- case 0: /* setup or out */
- usb_process_ep_out(epid);
- break;
- default:
- break;
- }
-}
-
-/**
- * @brief USB interrupt processing function
- * @pre None
- * @param[in] None
- * @retval None
- */
-void USBD_IRQHandler(uint8_t busid)
-{
- volatile uint8_t intflag = 0;
- intflag = CH585_USBHS_DEV->INT_FG;
-
- if (intflag & USBHS_UDIF_TRANSFER) {
- usb_trans_end_process();
- } else if (intflag & USBHS_UDIF_BUS_RST) {
- /* Reset */
- CH585_USBHS_DEV->DEV_AD = 0;
- usbd_event_reset_handler(0);
- /* Set ep0 rx vaild to start receive setup packet */
- CH585_USBHS_DEV->UEP0_DMA = (uint32_t)&usb_dc_cfg.setup;
- // EPn_SET_RX_VALID(0);
- R8_U2EP0_TX_CTRL = USBHS_UEP_T_RES_NAK;
- R8_U2EP0_RX_CTRL = USBHS_UEP_R_RES_ACK;
- CH585_USBHS_DEV->INT_FG = USBHS_UDIF_BUS_RST;
- } else if (intflag & USBHS_UDIF_SUSPEND) {
- if (CH585_USBHS_DEV->MIS_ST & USBHS_UDMS_SUSPEND) {
- /* Suspend */
- } else {
- /* Wake up */
- }
- CH585_USBHS_DEV->INT_FG = USBHS_UDIF_SUSPEND;
- } else {
- CH585_USBHS_DEV->INT_FG = intflag;
- }
-}
-
-void USB2_DEVICE_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))) __attribute__((section(".highcode")));
-void USB2_DEVICE_IRQHandler(void)
-{
- extern void USBD_IRQHandler(uint8_t busid);
- USBD_IRQHandler(0);
-} \ No newline at end of file
diff --git a/port/ch32/ch58x/usb_ch585_usbhs_reg.h b/port/ch32/ch58x/usb_ch585_usbhs_reg.h
deleted file mode 100644
index cfec7f75..00000000
--- a/port/ch32/ch58x/usb_ch585_usbhs_reg.h
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * Copyright (c) 2024, sakumisu
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#pragma once
-
-/**********************************/
-/*********USB high speed**********/
-/**********************************/
-typedef volatile unsigned short *PUINT16V;
-typedef volatile unsigned long *PUINT32V;
-typedef volatile unsigned char *PUINT8V;
-
-/* USB high speed device register */
-#define R8_USB2_CTRL (*((PUINT8V)0x40009000)) // RW, USB_high_speed control register
-#define USBHS_UD_LPM_EN 0x80 // RW, enable LPM
-#define USBHS_UD_DEV_EN 0x20 // RW, enable USB equipment
-#define USBHS_UD_DMA_EN 0x10 // RW, enable DMA transmit
-#define USBHS_UD_PHY_SUSPENDM 0x08 // RW, suspeng USB PHY
-#define USBHS_UD_CLR_ALL 0x04 // RW, clear all interupt flag
-#define USBHS_UD_RST_SIE 0x02 // RW, reset USB protocol processor,including end point register
-#define USBHS_UD_RST_LINK 0x01 // RW, enable LNK layer reset
-#define R8_USB2_BASE_MODE (*((PUINT8V)0x40009001)) // RW, USB_high_speed mode control register
-#define USBHS_UD_SPEED_FULL 0x00
-#define USBHS_UD_SPEED_HIGH 0x01
-#define USBHS_UD_SPEED_LOW 0x02
-#define USBHS_UD_SPEED_TYPE 0x03 // RW, speed mode excpeted by the equipment,00:full speed, 01:high speed, 10:low speed
-#define R8_USB2_INT_EN (*((PUINT8V)0x40009002)) // RW, USB_high_speed intreurpt enable register
-#define USBHS_UDIE_FIFO_OVER 0x80 // RW, enable fifo overflow interupt
-#define USBHS_UDIE_LINK_RDY 0x40 // RW, enable USB conect interupt
-#define USBHS_UDIE_SOF_ACT 0x20 // RW, enable SOF package received interupt
-#define USBHS_UDIE_TRANSFER 0x10 // RW, enable USB transmit end interupt
-#define USBHS_UDIE_LPM_ACT 0x08 // RW, enable lpm transmit end interupt
-#define USBHS_UDIE_BUS_SLEEP 0x04 // RW, enable usb bus sleep interupt
-#define USBHS_UDIE_SUSPEND 0x02 // RW, enable usb bus suspend interupt
-#define USBHS_UDIE_BUS_RST 0x01 // RW, enable usb bus reset interupt
-#define R8_USB2_DEV_AD (*((PUINT8V)0x40009003)) // RW, USB_high_speed device adress register
-#define USBHS_UD_DEV_ADDR 0x7F // RW, adress of usb equipment
-#define R8_USB2_WAKE_CTRL (*((PUINT8V)0x40009004)) // RW, USB_high_speed wake up remotely register
-#define USBHS_UD_UD_REMOTE_WKUP 0x01 // RW1, wake up remotely and auto reset hardware
-#define R8_USB2_TEST_MODE (*((PUINT8V)0x40009005)) // RW, USB_high_speed test mode register
-#define USBHS_UD_TEST_EN 0x80 // RW, enable test mode
-#define USBHS_UD_TEST_SE0NAK 0x08 // RW, output SE0 when in test mode
-#define USBHS_UD_TEST_PKT 0x04 // RW, output one package(including DATA0,data and length of end pont4) when in test mode,not work on virtual equipment
-#define USBHS_UD_TEST_K 0x02 // RW, output K when in test mode
-#define USBHS_UD_TEST_J 0x01 // RW, output J when in test mode
-#define R16_USB2_LPM_DATA (*((PUINT16V)0x40009006)) // RW, USB_high_speed power control register
-#define USBHS_UD_LPM_BUSY 0x8000 // RW, power control busy
-#define USBHS_UD_LPM_DATA 0x07FF // RO, power control data
-#define R8_USB2_INT_FG (*((PUINT8V)0x40009008)) // RW, USB_high_speed interupt flag register
-#define USBHS_UDIF_FIFO_OV 0x80 // RW1, clear fifo overflow interupt flag
-#define USBHS_UDIF_LINK_RDY 0x40 // RW1, clear USB conect interupt flag
-#define USBHS_UDIF_RX_SOF 0x20 // RW1, clear SOF package received interupt flag
-#define USBHS_UDIF_TRANSFER 0x10 // RO, USB transmit end interupt flag,cleared by USBHS_UDMS_HS_MOD
-#define USBHS_UDIF_LPM_ACT 0x08 // RW1, clear lpm transmit end interupt flag
-#define USBHS_UDIF_BUS_SLEEP 0x04 // RW1, clear usb bus sleep interupt flag
-#define USBHS_UDIF_SUSPEND 0x02 // RW1, clear usb bus suspend interupt flag
-#define USBHS_UDIF_BUS_RST 0x01 // RW1, clear usb bus reset interupt flag
-#define R8_USB2_INT_ST (*((PUINT8V)0x40009009)) // RW, USB_high_speed interupt status register
-#define USBHS_UDIS_EP_DIR 0x10 // RO, end point tranfer diector of data
-#define USBHS_UDIS_EP_ID_MASK 0x07 // RO, number of end point which data transmission occured
-#define R8_USB2_MIS_ST (*((PUINT8V)0x4000900A)) // RW, USB_high_speed miscellaneous register
-#define USBHS_UDMS_HS_MOD 0x80 // RO, host with high speed
-#define USBHS_UDMS_SUSP_REQ 0x10 // RO, requirment of suspending USB
-#define USBHS_UDMS_SIE_FREE 0x08 // RO, USB free state
-#define USBHS_UDMS_SLEEP 0x04 // RO, USB sleep state
-#define USBHS_UDMS_SUSPEND 0x02 // RO, USB in suspend state
-#define USBHS_UDMS_READY 0x01 // RO, USB in connected state
-#define R16_USB2_FRAME_NO (*((PUINT16V)0x4000900C)) // RW, USB_high_speed frame number register
-#define USBHS_UD_MFRAME_NO 0xE000
-#define USBHS_UD_FRAME_NO 0x07FF
-#define R16_USB2_BUS (*((PUINT16V)0x4000900E)) // RW, USB_high_speed bus status register
-#define USBHS_USB_DM_ST 0x08
-#define USBHS_USB_DP_ST 0x04
-#define USB_WAKEUP 0x01
-#define R16_U2EP_TX_EN (*((PUINT16V)0x40009010)) // RW, USB_high_speed end point transmit enable register
-/* Bit definition for R16_U2EP_TX_EN & R16_U2EP_RX_EN register */
-#define RB_EP0_EN 0x0001
-#define RB_EP1_EN 0x0002
-#define RB_EP2_EN 0x0004
-#define RB_EP3_EN 0x0008
-#define RB_EP4_EN 0x0010
-#define RB_EP5_EN 0x0020
-#define RB_EP6_EN 0x0040
-#define RB_EP7_EN 0x0080
-#define RB_EP8_EN 0x0100
-#define RB_EP9_EN 0x0200
-#define RB_EP10_EN 0x0400
-#define RB_EP11_EN 0x0800
-#define RB_EP12_EN 0x1000
-#define RB_EP13_EN 0x2000
-#define RB_EP14_EN 0x4000
-#define RB_EP15_EN 0x8000
-
-#define R16_U2EP_RX_EN (*((PUINT16V)0x40009012)) // RW, USB_high_speed end point receive enableregister
-#define USBHS_UEP_RX_EN 0xFFFF
-#define R16_U2EP_T_TOG_AUTO (*((PUINT16V)0x40009014)) // RW, USB_high_speed end point transmit auto toggle enable register
-#define USBHS_UEP_T_TOG_AUTO 0xFF
-#define R16_U2EP_R_TOG_AUTO (*((PUINT16V)0x40009016)) // RW, USB_high_speed end point receive auto toggle enable register
-#define USBHS_UEP_R_TOG_AUTO 0xFF
-#define R8_U2EP_T_BURST (*((PUINT8V)0x40009018)) // RW, USB_high_speed end point transmit burst register
-#define USBHS_UEP_T_BURST_EN 0xFF
-#define R8_U2EP_T_BURST_MODE (*((PUINT8V)0x40009019)) // RW, USB_high_speed end point transmit burst mode register
-#define USBHS_UEP_T_BURST_MODE 0xFF
-#define R8_U2EP_R_BURST (*((PUINT8V)0x4000901A)) // RW, USB_high_speed end point receive burst register
-#define USBHS_UEP_R_BURST_EN 0xFF
-#define R8_U2EP_R_RES_MODE (*((PUINT8V)0x4000901B)) // RW, USB_high_speed end point transmit reply mode register
-#define USBHS_UEP_R_RES_MODE 0xFF
-#define R32_U2EP_AF_MODE (*((PUINT32V)0x4000901C)) // RW, USB_high_speed end point multiplexing register
-#define USBHS_UEP_T_AF 0xFE
-#define R32_U2EP0_DMA (*((PUINT32V)0x40009020)) // RW, USB_high_speed end point0 begin adress of DMA buffer register
-#define UEPn_DMA 0x01FFFF
-#define R32_U2EP1_RX_DMA (*((PUINT32V)0x40009024)) // RW, USB_high_speed end point1 begin adress of DMA receive buffer register
-#define R32_U2EP2_RX_DMA (*((PUINT32V)0x40009028)) // RW, USB_high_speed end point2 begin adress of DMA receive buffer register
-#define R32_U2EP3_RX_DMA (*((PUINT32V)0x4000902C)) // RW, USB_high_speed end point3 begin adress of DMA receive buffer register
-#define R32_U2EP4_RX_DMA (*((PUINT32V)0x40009030)) // RW, USB_high_speed end point4 begin adress of DMA receive buffer register
-#define R32_U2EP5_RX_DMA (*((PUINT32V)0x40009034)) // RW, USB_high_speed end point5 begin adress of DMA receive buffer register
-#define R32_U2EP6_RX_DMA (*((PUINT32V)0x40009038)) // RW, USB_high_speed end point6 begin adress of DMA receive buffer register
-#define R32_U2EP7_RX_DMA (*((PUINT32V)0x4000903C)) // RW, USB_high_speed end point7 begin adress of DMA receive buffer register
-#define UEPn_RX_DMA 0x01FFFF
-#define R32_U2EP1_TX_DMA (*((PUINT32V)0x40009040)) // RW, USB_high_speed end point1 begin adress of DMA transmit buffer register
-#define R32_U2EP2_TX_DMA (*((PUINT32V)0x40009044)) // RW, USB_high_speed end point2 begin adress of DMA transmit buffer register
-#define R32_U2EP3_TX_DMA (*((PUINT32V)0x40009048)) // RW, USB_high_speed end point3 begin adress of DMA transmit buffer register
-#define R32_U2EP4_TX_DMA (*((PUINT32V)0x4000904C)) // RW, USB_high_speed end point4 begin adress of DMA transmit buffer register
-#define R32_U2EP5_TX_DMA (*((PUINT32V)0x40009050)) // RW, USB_high_speed end point5 begin adress of DMA transmit buffer register
-#define R32_U2EP6_TX_DMA (*((PUINT32V)0x40009054)) // RW, USB_high_speed end point6 begin adress of DMA transmit buffer register
-#define R32_U2EP7_TX_DMA (*((PUINT32V)0x40009058)) // RW, USB_high_speed end point7 begin adress of DMA transmit buffer register
-#define UEPn_TX_DMA 0x01FFFF
-#define R32_U2EP0_MAX_LEN (*((PUINT32V)0x4000905C)) // RW, USB_high_speed end point0 max length package register
-#define R32_U2EP1_MAX_LEN (*((PUINT32V)0x40009060)) // RW, USB_high_speed end point1 max length package register
-#define R32_U2EP2_MAX_LEN (*((PUINT32V)0x40009064)) // RW, USB_high_speed end point2 max length package register
-#define R32_U2EP3_MAX_LEN (*((PUINT32V)0x40009068)) // RW, USB_high_speed end point3 max length package register
-#define R32_U2EP4_MAX_LEN (*((PUINT32V)0x4000906C)) // RW, USB_high_speed end point4 max length package register
-#define R32_U2EP5_MAX_LEN (*((PUINT32V)0x40009070)) // RW, USB_high_speed end point5 max length package register
-#define R32_U2EP6_MAX_LEN (*((PUINT32V)0x40009074)) // RW, USB_high_speed end point6 max length package register
-#define R32_U2EP7_MAX_LEN (*((PUINT32V)0x40009078)) // RW, USB_high_speed end point7 max length package register
-#define UEPn_MAX_LEN 0x007F
-#define R16_U2EP0_RX_LEN (*((PUINT16V)0x4000907C)) // RW, USB_high_speed end point0 length of receive register
-#define UEP0_RX_LEN 0x007F
-#define R16_U2EP1_RX_LEN (*((PUINT16V)0x40009080)) // RW, USB_high_speed end point1 single received length register
-#define R16_U2EP1_R_SIZE (*((PUINT16V)0x40009082)) // RW, USB_high_speed end point1 total received length register
-#define R16_U2EP2_RX_LEN (*((PUINT16V)0x40009084)) // RW, USB_high_speed end point2 single received length register
-#define R16_U2EP2_R_SIZE (*((PUINT16V)0x40009086)) // RW, USB_high_speed end point2 total received length register
-#define R16_U2EP3_RX_LEN (*((PUINT16V)0x40009088)) // RW, USB_high_speed end point3 single received length register
-#define R16_U2EP3_R_SIZE (*((PUINT16V)0x4000908A)) // RW, USB_high_speed end point3 total received length register
-#define R16_U2EP4_RX_LEN (*((PUINT16V)0x4000908C)) // RW, USB_high_speed end point4 single received length register
-#define R16_U2EP4_R_SIZE (*((PUINT16V)0x4000908E)) // RW, USB_high_speed end point4 total received length register
-#define R16_U2EP5_RX_LEN (*((PUINT16V)0x40009090)) // RW, USB_high_speed end point5 single received length register
-#define R16_U2EP5_R_SIZE (*((PUINT16V)0x40009092)) // RW, USB_high_speed end point5 total received length register
-#define R16_U2EP6_RX_LEN (*((PUINT16V)0x40009094)) // RW, USB_high_speed end point6 single received length register
-#define R16_U2EP6_R_SIZE (*((PUINT16V)0x40009096)) // RW, USB_high_speed end point6 total received length register
-#define R16_U2EP7_RX_LEN (*((PUINT16V)0x40009098)) // RW, USB_high_speed end point7 single received length register
-#define R16_U2EP7_R_SIZE (*((PUINT16V)0x4000909A)) // RW, USB_high_speed end point7 total received length register
-#define UEPn_RX_LEN 0xFFFF
-#define UEPn_R_SIZE 0xFFFF
-#define R16_U2EP0_T_LEN (*((PUINT16V)0x4000909C)) // RW, USB_high_speed end point0 length of transmission register
-#define UEP0_T_LEN 0x7F
-#define R8_U2EP0_TX_CTRL (*((PUINT8V)0x4000909E)) // RW, USB_high_speed end point0 transmit control register
-#define R8_U2EP0_RX_CTRL (*((PUINT8V)0x4000909F)) // RW, USB_high_speed end point0 receive control register
-#define R16_U2EP1_T_LEN (*((PUINT16V)0x400090A0)) // RW, USB_high_speed end point1 length of transmission register
-#define R8_U2EP1_TX_CTRL (*((PUINT8V)0x400090A2)) // RW, USB_high_speed end point1 transmit control register
-#define R8_U2EP1_RX_CTRL (*((PUINT8V)0x400090A3)) // RW, USB_high_speed end point1 receive control register
-#define R16_U2EP2_T_LEN (*((PUINT16V)0x400090A4)) // RW, USB_high_speed end point2 length of transmission register
-#define R8_U2EP2_TX_CTRL (*((PUINT8V)0x400090A6)) // RW, USB_high_speed end point2 transmit control register
-#define R8_U2EP2_RX_CTRL (*((PUINT8V)0x400090A7)) // RW, USB_high_speed end point2 receive control register
-#define R16_U2EP3_T_LEN (*((PUINT16V)0x400090A8)) // RW, USB_high_speed end point3 length of transmission register
-#define R8_U2EP3_TX_CTRL (*((PUINT8V)0x400090AA)) // RW, USB_high_speed end point3 transmit control register
-#define R8_U2EP3_RX_CTRL (*((PUINT8V)0x400090AB)) // RW, USB_high_speed end point3 receive control register
-#define R16_U2EP4_T_LEN (*((PUINT16V)0x400090AC)) // RW, USB_high_speed end point4 length of transmission register
-#define R8_U2EP4_TX_CTRL (*((PUINT8V)0x400090AE)) // RW, USB_high_speed end point4 transmit control register
-#define R8_U2EP4_RX_CTRL (*((PUINT8V)0x400090AF)) // RW, USB_high_speed end point4 receive control register
-#define R16_U2EP5_T_LEN (*((PUINT16V)0x400090B0)) // RW, USB_high_speed end point5 length of transmission register
-#define R8_U2EP5_TX_CTRL (*((PUINT8V)0x400090B2)) // RW, USB_high_speed end point5 transmit control register
-#define R8_U2EP5_RX_CTRL (*((PUINT8V)0x400090B3)) // RW, USB_high_speed end point5 receive control register
-#define R16_U2EP6_T_LEN (*((PUINT16V)0x400090B4)) // RW, USB_high_speed end point6 length of transmission register
-#define R8_U2EP6_TX_CTRL (*((PUINT8V)0x400090B6)) // RW, USB_high_speed end point6 transmit control register
-#define R8_U2EP6_RX_CTRL (*((PUINT8V)0x400090B7)) // RW, USB_high_speed end point6 receive control register
-#define R16_U2EP7_T_LEN (*((PUINT16V)0x400090B8)) // RW, USB_high_speed end point7 length of transmission register
-#define R8_U2EP7_TX_CTRL (*((PUINT8V)0x400090BA)) // RW, USB_high_speed end point7 transmit control register
-#define R8_U2EP7_RX_CTRL (*((PUINT8V)0x400090BB)) // RW, USB_high_speed end point7 receive control register
-/**R16_UEPn_T_LEN**/
-#define UEPn_T_LEN 0xFFFF
-/**R8_UEPn_TX_CTRL**/
-#define USBHS_UEP_T_DONE 0x80
-#define USBHS_UEP_T_NAK_ACT 0x40
-#define USBHS_UEP_T_TOG_MASK 0x0C
-#define USBHS_UEP_T_TOG_MDATA 0x0C
-#define USBHS_UEP_T_TOG_DATA2 0x08
-#define USBHS_UEP_T_TOG_DATA1 0x04
-#define USBHS_UEP_T_TOG_DATA0 0x00
-#define USBHS_UEP_T_RES_MASK 0x03
-#define USBHS_UEP_T_RES_ACK 0x02
-#define USBHS_UEP_T_RES_STALL 0x01
-#define USBHS_UEP_T_RES_NAK 0x00
-
-/**R8_UEPn_RX_CTRL**/
-#define USBHS_UEP_R_DONE 0x80
-#define USBHS_UEP_R_NAK_ACT 0x40
-#define USBHS_UEP_R_NAK_TOG 0x20
-#define USBHS_UEP_R_TOG_MATCH 0x10
-#define USBHS_UEP_R_SETUP_IS 0x08
-#define USBHS_UEP_R_TOG_MASK 0x0C
-#define USBHS_UEP_R_TOG_MDATA 0x0C
-#define USBHS_UEP_R_TOG_DATA2 0x08
-#define USBHS_UEP_R_TOG_DATA1 0x04
-#define USBHS_UEP_R_TOG_DATA0 0x00
-#define USBHS_UEP_R_RES_MASK 0x03
-#define USBHS_UEP_R_RES_ACK 0x02
-#define USBHS_UEP_R_RES_STALL 0x01
-#define USBHS_UEP_R_RES_NAK 0x00
-
-#define R16_U2EP_T_ISO (*((PUINT16V)0x400090BC)) // RW, USB_high_speed end point transmit sync mode register
-#define USBHS_UEP1_T_ISO_EN 0x02
-#define USBHS_UEP2_T_ISO_EN 0x04
-#define USBHS_UEP3_T_ISO_EN 0x08
-#define USBHS_UEP4_T_ISO_EN 0x10
-#define USBHS_UEP5_T_ISO_EN 0x20
-#define USBHS_UEP6_T_ISO_EN 0x40
-#define USBHS_UEP7_T_ISO_EN 0x80
-#define R16_U2EP_R_ISO (*((PUINT16V)0x400090BE)) // RW, USB_high_speed end point receive sync mode register
-#define USBHS_UEP1_R_ISO_EN 0x02
-#define USBHS_UEP2_R_ISO_EN 0x04
-#define USBHS_UEP3_R_ISO_EN 0x08
-#define USBHS_UEP4_R_ISO_EN 0x10
-#define USBHS_UEP5_R_ISO_EN 0x20
-#define USBHS_UEP6_R_ISO_EN 0x40
-#define USBHS_UEP7_R_ISO_EN 0x80
-
-/* USB high speed host register */
-#define R8_U2H_CFG (*((PUINT8V)0x40009100)) // RW, USB_high_speed register
-#define USBHS_UH_LPM_EN 0x80
-#define USBHS_UH_FORCE_FS 0x40
-#define USBHS_UH_SOF_EN 0x20
-#define USBHS_UH_DMA_EN 0x10
-#define USBHS_UH_PHY_SUSPENDM 0x08
-#define USBHS_UH_CLR_ALL 0x04
-#define USBHS_RST_SIE 0x02
-#define USBHS_RST_LINK 0x01
-#define R8_U2H_INT_EN (*((PUINT8V)0x40009102)) // RW, USB_high_speed register
-#define USBHS_UHIE_FIFO_OVER 0x80
-#define USBHS_UHIE_TX_HALT 0x40
-#define USBHS_UHIE_SOF_ACT 0x20
-#define USBHS_UHIE_TRANSFER 0x10
-#define USBHS_UHIE_RESUME_ACT 0x08
-#define USBHS_UHIE_WKUP_ACT 0x04
-#define R8_U2H_DEV_AD (*((PUINT8V)0x40009103)) // RW, USB_high_speed register
-#define USBHS_UH_DEV_ADDR 0xFF
-#define R32_U2H_CONTROL (*((PUINT32V)0x40009104)) // RW, USB_high_speed register
-#define USBHS_UH_RX_NO_RES 0x800000
-#define USBHS_UH_TX_NO_RES 0x400000
-#define USBHS_UH_RX_NO_DATA 0x200000
-#define USBHS_UH_TX_NO_DATA 0x100000
-#define USBHS_UH_PRE_PID_EN 0x080000
-#define USBHS_UH_SPLIT_VALID 0x040000
-#define USBHS_UH_LPM_VALID 0x020000
-#define USBHS_UH_HOST_ACTION 0x010000
-#define USBHS_UH_BUF_MODE 0x0400
-#define USBHS_UH_T_TOG_MASK 0x0300
-#define USBHS_UH_T_TOG_MDATA 0x0300
-#define USBHS_UH_T_TOG_DATA2 0x0200
-#define USBHS_UH_T_TOG_DATA1 0x0100
-#define USBHS_UH_T_TOG_DATA0 0x0000
-#define USBHS_UH_T_ENDP_MASK 0xF0
-#define USBHS_UH_T_TOKEN_MASK 0x0F
-
-#define R8_U2H_INT_FLAG (*((PUINT8V)0x40009108)) // RW, USB_high_speed register
-#define USBHS_UHIF_FIFO_OVER 0x80
-#define USBHS_UHIF_TX_HALT 0x40
-#define USBHS_UHIF_SOF_ACT 0x20
-#define USBHS_UHIF_TRANSFER 0x10
-#define USBHS_UHIF_RESUME_ACT 0x08
-#define USBHS_UHIF_WKUP_ACT 0x04
-#define R8_U2H_INT_ST (*((PUINT8V)0x40009109)) // RW, USB_high_speed register
-#define USBHS_UHIF_PORT_RX_RESUME 0x10
-#define USBHS_UH_R_TOKEN_MASK 0x0F
-#define R8_U2H_MIS_ST (*((PUINT8V)0x4000910A)) // RW, USB_high_speed register
-#define USBHS_UHMS_BUS_SE0 0x80
-#define USBHS_UHMS_BUS_J 0x40
-#define USBHS_UHMS_LINESTATE 0x30
-#define USBHS_UHMS_USB_WAKEUP 0x08
-#define USBHS_UHMS_SOF_ACT 0x04
-#define USBHS_UHMS_SOF_PRE 0x02
-#define USBHS_UHMS_SOF_FREE 0x01
-#define R32_U2H_LPM_DATA (*((PUINT32V)0x4000910C)) // RW, USB_high_speed register
-#define USBHS_UH_LPM_DATA 0x07FF
-#define R32_U2H_SPLIT_DATA (*((PUINT32V)0x40009110)) // RW, USB_high_speed register
-#define USBHS_UH_SPLIT_DATA 0x07FFFF
-#define R32_U2H_FRAME (*((PUINT32V)0x40009114)) // RW, USB_high_speed register
-#define USBHS_UH_SOF_CNT_CLR 0x02000000
-#define USBHS_UH_SOF_CNT_EN 0x01000000
-#define USBHS_UH_MFRAME_NO 0x070000
-#define USBHS_UH_FRAME_NO 0x07FF
-#define R32_U2H_TX_LEN (*((PUINT32V)0x40009118)) // RW, USB_high_speed register
-#define USBHS_UH_TX_LEN 0x07FF
-#define R32_U2H_RX_LEN (*((PUINT32V)0x4000911C)) // RW, USB_high_speed register
-#define USBHS_UH_RX_LEN 0x07FF
-#define R32_U2H_RX_MAX_LEN (*((PUINT32V)0x40009120)) // RW, USB_high_speed register
-#define USBHS_UH_RX_MAX_LEN 0x07FF
-#define R32_U2H_RX_DMA (*((PUINT32V)0x40009124)) // RW, USB_high_speed register
-#define USBHS_R32_UH_RX_DMA 0x01FFFF
-#define R32_U2H_TX_DMA (*((PUINT32V)0x40009128)) // RW, USB_high_speed register
-#define USBHS_R32_UH_TX_DMA 0x01FFFF
-#define R32_U2H_PORT_CTRL (*((PUINT32V)0x4000912C)) // RW, USB_high_speed register
-#define USBHS_UH_BUS_RST_LONG 0x010000
-#define USBHS_UH_PORT_SLEEP_BESL 0xF000
-#define USBHS_UH_CLR_PORT_SLEEP 0x0100
-#define USBHS_UH_CLR_PORT_CONNECT 0x20
-#define USBHS_UH_CLR_PORT_EN 0x10
-#define USBHS_UH_SET_PORT_SLEEP 0x08
-#define USBHS_UH_CLR_PORT_SUSP 0x04
-#define USBHS_UH_SET_PORT_SUSP 0x02
-#define USBHS_UH_SET_PORT_RESET 0x01
-#define R8_U2H_PORT_CFG (*((PUINT8V)0x40009130)) // RW, USB_high_speed register
-#define USBHS_UH_PD_EN 0x80
-#define USBHS_UH_HOST_EN 0x01
-#define R8_U2H_PORT_INT_EN (*((PUINT8V)0x40009132)) // RW, USB_high_speed register
-#define USBHS_UHIE_PORT_SLP 0x20
-#define USBHS_UHIE_PORT_RESET 0x10
-#define USBHS_UHIE_PORT_SUSP 0x04
-#define USBHS_UHIE_PORT_EN 0x02
-#define USBHS_UHIE_PORT_CONNECT 0x01
-#define R8_U2H_PORT_TEST_CT (*((PUINT8V)0x40009133)) // RW, USB_high_speed register
-#define USBHS_UH_TEST_FORCE_EN 0x04
-#define USBHS_UH_TEST_K 0x02
-#define USBHS_UH_TEST_J 0x01
-#define R16_U2H_PORT_ST (*((PUINT16V)0x40009134)) // RW, USB_high_speed register
-#define USBHS_UHIS_PORT_TEST 0x0800
-#define USBHS_UHIS_PORT_SPEED_MASK 0x0600
-#define USBHS_UHIS_PORT_HS 0x0400
-#define USBHS_UHIS_PORT_LS 0x0200
-#define USBHS_UHIS_PORT_FS 0x0000
-#define USBHS_UHIS_PORT_SLP 0x20
-#define USBHS_UHIS_PORT_RST 0x10
-#define USBHS_UHIS_PORT_SUSP 0x04
-#define USBHS_UHIS_PORT_EN 0x02
-#define USBHS_UHIS_PORT_CONNECT 0x01
-#define R8_U2H_PORT_CHG (*((PUINT8V)0x40009136))
-#define USBHS_UHIF_PORT_SLP 0x20
-#define USBHS_UHIF_PORT_RESET 0x10
-#define USBHS_UHIF_PORT_SUSP 0x04
-#define USBHS_UHIF_PORT_EN 0x02
-#define USBHS_UHIF_PORT_CONNECT 0x01
-#define R32_U2H_BC_CTRL (*((PUINT32V)0x4000913C))
-#define UDM_VSRC_ACT 0x0400
-#define UDM_BC_VSRC 0x0200
-#define UDP_BC_VSRC 0x0100
-#define BC_AUTO_MODE 0x40
-#define UDM_BC_CMPE 0x20
-#define UDP_BC_CMPE 0x10
-#define UDM_BC_CMPO 0x02
-#define UDP_BC_CMPO 0x01
-#define R8_USBHS_PLL_CTRL (*((PUINT8V)0x40009200))
-#define USBHS_PLL_EN 0x04
-#define USBHS_PLL_LOWPOW 0x02
-#define USBHS_PLL_CKSEL 0x01
-
-#define __IO volatile /* defines 'read / write' permissions */
-
-typedef struct
-{
- __IO uint8_t CONTROL; /* 0x40009000 */
- __IO uint8_t BASE_MODE; /* 0x40009001 */
- __IO uint8_t INT_EN; /* 0x40009002 */
- __IO uint8_t DEV_AD; /* 0x40009003 */
- __IO uint8_t WAKE_CTRL; /* 0x40009004 远程唤醒寄存器 */
- __IO uint8_t TEST_MODE; /* 0x40009005 测试模式寄存器 */
- __IO uint16_t LPM_DATA; /* 0x40009006 */
- __IO uint8_t INT_FG; /* 0x40009008 */
- __IO uint8_t INT_ST; /* 0x40009009 */
- __IO uint8_t MIS_ST; /* 0x4000900a */
- __IO uint8_t RESERVE0; /* 0x4000900b */
- __IO uint16_t FRAME_NO; /* 0x4000900c */
- __IO uint16_t USB_BUS; /* 0x4000900e */
- __IO uint16_t UEP_TX_EN; /* 0x40009010 */
- __IO uint16_t UEP_RX_EN; /* 0x40009012 */
-
- __IO uint16_t UEP_T_TOG_AUTO; /* 0x40009014 */
- __IO uint16_t UEP_R_TOG_AUTO; /* 0x40009016 */
- __IO uint8_t UEP_T_BURST; /* 0x40009018 */
- __IO uint8_t UEP_T_BURST_MODE; /* 0x40009019 */
- __IO uint8_t UEP_R_BURST; /* 0x4000901a */
- __IO uint8_t UEP_R_RES_MODE; /* 0x4000901b */
- __IO uint32_t UEP_AF_MODE; /* 0x4000901c */
-
- __IO uint32_t UEP0_DMA; /* 0x40009020 */
- __IO uint32_t UEP1_RX_DMA; /* 0x40009024 */
- __IO uint32_t UEP2_RX_DMA; /* 0x40009028 */
- __IO uint32_t UEP3_RX_DMA; /* 0x4000902c */
- __IO uint32_t UEP4_RX_DMA; /* 0x40009030 */
- __IO uint32_t UEP5_RX_DMA; /* 0x40009034 */
- __IO uint32_t UEP6_RX_DMA; /* 0x40009038 */
- __IO uint32_t UEP7_RX_DMA; /* 0x4000903c */
-
- __IO uint32_t UEP1_TX_DMA; /* 0x40009040 */
- __IO uint32_t UEP2_TX_DMA; /* 0x40009044 */
- __IO uint32_t UEP3_TX_DMA; /* 0x40009048 */
- __IO uint32_t UEP4_TX_DMA; /* 0x4000904c */
- __IO uint32_t UEP5_TX_DMA; /* 0x40009050 */
- __IO uint32_t UEP6_TX_DMA; /* 0x40009054 */
- __IO uint32_t UEP7_TX_DMA; /* 0x40009058 */
-
- __IO uint32_t UEP0_MAX_LEN; /* 0x4000905c */
- __IO uint32_t UEP1_MAX_LEN; /* 0x40009060 */
- __IO uint32_t UEP2_MAX_LEN; /* 0x40009064 */
- __IO uint32_t UEP3_MAX_LEN; /* 0x40009068 */
- __IO uint32_t UEP4_MAX_LEN; /* 0x4000906c */
- __IO uint32_t UEP5_MAX_LEN; /* 0x40009070 */
- __IO uint32_t UEP6_MAX_LEN; /* 0x40009074 */
- __IO uint32_t UEP7_MAX_LEN; /* 0x40009078 */
-
- __IO uint16_t USB_EP0_RX_LEN; /* 0x4000907c */
- __IO uint16_t RESERVE1; /* 0x4000907e */
- __IO uint16_t UEP1_RX_LEN; /* 0x40009080 */
- __IO uint16_t UEP1_R_SIZE; /* 0x40009082 */
- __IO uint16_t UEP2_RX_LEN; /* 0x40009084 */
- __IO uint16_t UEP2_R_SIZE; /* 0x40009086 */
- __IO uint16_t UEP3_RX_LEN; /* 0x40009088 */
- __IO uint16_t UEP3_R_SIZE; /* 0x4000908a */
- __IO uint16_t UEP4_RX_LEN; /* 0x4000908c */
- __IO uint16_t UEP4_R_SIZE; /* 0x4000908e */
- __IO uint16_t UEP5_RX_LEN; /* 0x40009090 */
- __IO uint16_t UEP5_R_SIZE; /* 0x40009092 */
- __IO uint16_t UEP6_RX_LEN; /* 0x40009094 */
- __IO uint16_t UEP6_R_SIZE; /* 0x40009096 */
- __IO uint16_t UEP7_RX_LEN; /* 0x40009098 */
- __IO uint16_t UEP7_R_SIZE; /* 0x4000909a */
-
- __IO uint16_t UEP0_TX_LEN; /* 0x4000909c */
- __IO uint8_t UEP0_TX_CTRL; /* 0x4000909e */
- __IO uint8_t UEP0_RX_CTRL; /* 0x4000909f */
- __IO uint16_t UEP1_TX_LEN; /* 0x400090a0 */
- __IO uint8_t UEP1_TX_CTRL; /* 0x400090a2 */
- __IO uint8_t UEP1_RX_CTRL; /* 0x400090a3 */
- __IO uint16_t UEP2_TX_LEN; /* 0x400090a4 */
- __IO uint8_t UEP2_TX_CTRL; /* 0x400090a6 */
- __IO uint8_t UEP2_RX_CTRL; /* 0x400090a7 */
- __IO uint16_t UEP3_TX_LEN; /* 0x400090a8 */
- __IO uint8_t UEP3_TX_CTRL; /* 0x400090aa */
- __IO uint8_t UEP3_RX_CTRL; /* 0x400090ab */
- __IO uint16_t UEP4_TX_LEN; /* 0x400090ac */
- __IO uint8_t UEP4_TX_CTRL; /* 0x400090ae */
- __IO uint8_t UEP4_RX_CTRL; /* 0x400090af */
- __IO uint16_t UEP5_TX_LEN; /* 0x400090b0 */
- __IO uint8_t UEP5_TX_CTRL; /* 0x400090b2 */
- __IO uint8_t UEP5_RX_CTRL; /* 0x400090b3 */
- __IO uint16_t UEP6_TX_LEN; /* 0x400090b4 */
- __IO uint8_t UEP6_TX_CTRL; /* 0x400090b6 */
- __IO uint8_t UEP6_RX_CTRL; /* 0x400090b7 */
- __IO uint16_t UEP7_TX_LEN; /* 0x400090b8 */
- __IO uint8_t UEP7_TX_CTRL; /* 0x400090ba */
- __IO uint8_t UEP7_RX_CTRL; /* 0x400090bb */
- __IO uint16_t UEP_TX_ISO; /* 0x400090bc */
- __IO uint16_t UEP_RX_ISO; /* 0x400090be */
-} USBHSD_TypeDef; \ No newline at end of file
diff --git a/port/ch32/ch58x/usb_ch58x_dc_usbfs.c b/port/ch32/ch58x/usb_ch58x_dc_usbfs.c
deleted file mode 100644
index e86f4188..00000000
--- a/port/ch32/ch58x/usb_ch58x_dc_usbfs.c
+++ /dev/null
@@ -1,640 +0,0 @@
-/*
- * Copyright (c) 2022, sakumisu
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#include "usbd_core.h"
-#include "usb_ch58x_usbfs_reg.h"
-
-/**
- * @brief Related register macro
- */
-#define USB0_BASE 0x40008000u
-#define USB1_BASE 0x40008400u
-
-#ifndef USBD
-#define USBD USB0_BASE
-#endif
-#define CH58x_USBFS_DEV ((USB_FS_TypeDef *)USBD)
-
-/*!< 8-bit value of endpoint control register */
-#define EPn_CTRL(epid) \
- *(volatile uint8_t *)(&(CH58x_USBFS_DEV->UEP0_CTRL) + epid * 4 + (epid / 5) * 48)
-
-/*!< The length register value of the endpoint send buffer */
-#define EPn_TX_LEN(epid) \
- *(volatile uint8_t *)(&(CH58x_USBFS_DEV->UEP0_T_LEN) + epid * 4 + (epid / 5) * 48)
-
-/*!< Read setup packet to use in ep0 in */
-#define GET_SETUP_PACKET(data_add) \
- *(struct usb_setup_packet *)data_add
-
-/*!< Set epid ep tx valid // Not an isochronous endpoint */
-#define EPn_SET_TX_VALID(epid) \
- EPn_CTRL(epid) = (EPn_CTRL(epid) & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
-/*!< Set epid ep rx valid // Not an isochronous endpoint */
-#define EPn_SET_RX_VALID(epid) \
- EPn_CTRL(epid) = (EPn_CTRL(epid) & ~MASK_UEP_R_RES) | UEP_R_RES_ACK;
-/*!< Set epid ep tx valid // Isochronous endpoint */
-#define EPn_SET_TX_ISO_VALID(epid) \
- EPn_CTRL(epid) = (EPn_CTRL(epid) & ~MASK_UEP_T_RES) | UEP_T_RES_TOUT;
-/*!< Set epid ep rx valid // Isochronous endpoint */
-#define EPn_SET_RX_ISO_VALID(epid) \
- EPn_CTRL(epid) = (EPn_CTRL(epid) & ~MASK_UEP_R_RES) | UEP_R_RES_TOUT;
-/*!< Set epid ep tx nak */
-#define EPn_SET_TX_NAK(epid) \
- EPn_CTRL(epid) = (EPn_CTRL(epid) & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
-/*!< Set epid ep rx nak */
-#define EPn_SET_RX_NAK(epid) \
- EPn_CTRL(epid) = (EPn_CTRL(epid) & ~MASK_UEP_R_RES) | UEP_R_RES_NAK;
-/*!< Set epid ep tx stall */
-#define EPn_SET_TX_STALL(epid) \
- EPn_CTRL(epid) = (EPn_CTRL(epid) & ~MASK_UEP_T_RES) | UEP_T_RES_STALL
-/*!< Set epid ep rx stall */
-#define EPn_SET_RX_STALL(epid) \
- EPn_CTRL(epid) = (EPn_CTRL(epid) & ~MASK_UEP_R_RES) | UEP_R_RES_STALL
-/*!< Clear epid ep tx stall */
-#define EPn_CLR_TX_STALL(epid) \
- EPn_CTRL(epid) = (EPn_CTRL(epid) & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK
-/*!< Clear epid ep rx stall */
-#define EPn_CLR_RX_STALL(epid) \
- EPn_CTRL(epid) = (EPn_CTRL(epid) & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK
-/*!< Set epid ep tx len */
-#define EPn_SET_TX_LEN(epid, len) \
- EPn_TX_LEN(epid) = len
-/*!< Get epid ep rx len */
-#define EPn_GET_RX_LEN(epid) \
- CH58x_USBFS_DEV->USB_RX_LEN
-
-/*!< ep nums */
-#ifndef CONFIG_USBDEV_EP_NUM
-#define CONFIG_USBDEV_EP_NUM 5
-#endif
-/*!< ep mps */
-#define EP_MPS 64
-/*!< set ep4 in mps 64 */
-#define EP4_IN_MPS EP_MPS
-/*!< set ep4 out mps 64 */
-#define EP4_OUT_MPS EP_MPS
-
-/*!< User defined assignment endpoint RAM */
-__attribute__((aligned(4))) uint8_t ep0_data_buff[64 + EP4_OUT_MPS + EP4_IN_MPS]; /*!< ep0(64)+ep4_out(64)+ep4_in(64) */
-__attribute__((aligned(4))) uint8_t ep1_data_buff[64 + 64]; /*!< ep1_out(64)+ep1_in(64) */
-__attribute__((aligned(4))) uint8_t ep2_data_buff[64 + 64]; /*!< ep2_out(64)+ep2_in(64) */
-__attribute__((aligned(4))) uint8_t ep3_data_buff[64 + 64]; /*!< ep3_out(64)+ep3_in(64) */
-#if (CONFIG_USBDEV_EP_NUM == 8)
-/**
- * This dcd porting can be used on ch581, ch582, ch583,
- * and also on ch571, ch572, and ch573. Note that only five endpoints are available for ch571, ch572, and ch573.
- */
-__attribute__((aligned(4))) uint8_t ep5_data_buff[64 + 64]; /*!< ep5_out(64)+ep5_in(64) */
-__attribute__((aligned(4))) uint8_t ep6_data_buff[64 + 64]; /*!< ep6_out(64)+ep6_in(64) */
-__attribute__((aligned(4))) uint8_t ep7_data_buff[64 + 64]; /*!< ep7_out(64)+ep7_in(64) */
-#endif
-/**
- * @brief Endpoint information structure
- */
-typedef struct _usbd_ep_info {
- uint8_t mps; /*!< Maximum packet length of endpoint */
- uint8_t eptype; /*!< Endpoint Type */
- uint8_t *ep_ram_addr; /*!< Endpoint buffer address */
-
- uint8_t ep_enable; /* Endpoint enable */
- uint8_t *xfer_buf;
- uint32_t xfer_len;
- uint32_t actual_xfer_len;
-} usbd_ep_info;
-
-/*!< ch58x usb */
-static struct _ch58x_core_prvi {
- uint8_t address; /*!< Address */
- usbd_ep_info ep_in[CONFIG_USBDEV_EP_NUM];
- usbd_ep_info ep_out[CONFIG_USBDEV_EP_NUM];
- struct usb_setup_packet setup;
-} usb_dc_cfg;
-
-__WEAK void usb_dc_low_level_init(void)
-{
-}
-
-__WEAK void usb_dc_low_level_deinit(void)
-{
-}
-
-/**
- * @brief USB initialization
- * @pre None
- * @param[in] None
- * @retval >=0 success otherwise failure
- */
-int usb_dc_init(uint8_t busid)
-{
- usb_dc_cfg.ep_in[0].ep_ram_addr = ep0_data_buff;
- usb_dc_cfg.ep_out[0].ep_ram_addr = ep0_data_buff;
-
- usb_dc_cfg.ep_in[1].ep_ram_addr = ep1_data_buff + 64;
- usb_dc_cfg.ep_out[1].ep_ram_addr = ep1_data_buff;
-
- usb_dc_cfg.ep_in[2].ep_ram_addr = ep2_data_buff + 64;
- usb_dc_cfg.ep_out[2].ep_ram_addr = ep2_data_buff;
-
- usb_dc_cfg.ep_in[3].ep_ram_addr = ep3_data_buff + 64;
- usb_dc_cfg.ep_out[3].ep_ram_addr = ep3_data_buff;
-
- usb_dc_cfg.ep_in[4].ep_ram_addr = ep0_data_buff + 64 + EP4_OUT_MPS;
- usb_dc_cfg.ep_out[4].ep_ram_addr = ep0_data_buff + 64;
-#if (CONFIG_USBDEV_EP_NUM == 8)
- usb_dc_cfg.ep_in[5].ep_ram_addr = ep5_data_buff + 64;
- usb_dc_cfg.ep_out[5].ep_ram_addr = ep5_data_buff;
-
- usb_dc_cfg.ep_in[6].ep_ram_addr = ep6_data_buff + 64;
- usb_dc_cfg.ep_out[6].ep_ram_addr = ep6_data_buff;
-
- usb_dc_cfg.ep_in[7].ep_ram_addr = ep7_data_buff + 64;
- usb_dc_cfg.ep_out[7].ep_ram_addr = ep7_data_buff;
-#endif
- /*!< Set the mode first and cancel RB_UC_CLR_ALL */
- CH58x_USBFS_DEV->USB_CTRL = 0x00;
- CH58x_USBFS_DEV->UEP4_1_MOD = RB_UEP4_RX_EN | RB_UEP4_TX_EN | RB_UEP1_RX_EN | RB_UEP1_TX_EN; /*!< EP4 OUT+IN EP1 OUT+IN */
- CH58x_USBFS_DEV->UEP2_3_MOD = RB_UEP2_RX_EN | RB_UEP2_TX_EN | RB_UEP3_RX_EN | RB_UEP3_TX_EN; /*!< EP2 OUT+IN EP3 OUT+IN */
-#if (CONFIG_USBDEV_EP_NUM == 8)
- CH58x_USBFS_DEV->UEP567_MOD = RB_UEP5_RX_EN | RB_UEP5_TX_EN | RB_UEP6_RX_EN | RB_UEP6_TX_EN | RB_UEP7_RX_EN | RB_UEP7_TX_EN; /*!< EP5 EP6 EP7 OUT+IN */
-#endif
- CH58x_USBFS_DEV->UEP0_DMA = (uint16_t)(uint32_t)ep0_data_buff;
- CH58x_USBFS_DEV->UEP1_DMA = (uint16_t)(uint32_t)ep1_data_buff;
- CH58x_USBFS_DEV->UEP2_DMA = (uint16_t)(uint32_t)ep2_data_buff;
- CH58x_USBFS_DEV->UEP3_DMA = (uint16_t)(uint32_t)ep3_data_buff;
-#if (CONFIG_USBDEV_EP_NUM == 8)
- CH58x_USBFS_DEV->UEP5_DMA = (uint16_t)(uint32_t)ep5_data_buff;
- CH58x_USBFS_DEV->UEP6_DMA = (uint16_t)(uint32_t)ep6_data_buff;
- CH58x_USBFS_DEV->UEP7_DMA = (uint16_t)(uint32_t)ep7_data_buff;
-#endif
- CH58x_USBFS_DEV->UEP0_CTRL = UEP_R_RES_NAK | UEP_T_RES_NAK;
- CH58x_USBFS_DEV->UEP1_CTRL = UEP_R_RES_NAK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
- CH58x_USBFS_DEV->UEP2_CTRL = UEP_R_RES_NAK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
- CH58x_USBFS_DEV->UEP3_CTRL = UEP_R_RES_NAK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
- CH58x_USBFS_DEV->UEP4_CTRL = UEP_R_RES_NAK | UEP_T_RES_NAK;
-#if (CONFIG_USBDEV_EP_NUM == 8)
- CH58x_USBFS_DEV->UEP5_CTRL = UEP_R_RES_NAK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
- CH58x_USBFS_DEV->UEP6_CTRL = UEP_R_RES_NAK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
- CH58x_USBFS_DEV->UEP7_CTRL = UEP_R_RES_NAK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
-#endif
- CH58x_USBFS_DEV->USB_DEV_AD = 0x00;
-
- /*!< Start the USB device and DMA, and automatically return to NAK before the interrupt flag is cleared during the interrupt */
- CH58x_USBFS_DEV->USB_CTRL = RB_UC_DEV_PU_EN | RB_UC_INT_BUSY | RB_UC_DMA_EN;
- if ((uint32_t) & (CH58x_USBFS_DEV->USB_CTRL) == (uint32_t)USB0_BASE) {
- /*!< USB0 */
- R16_PIN_ANALOG_IE |= RB_PIN_USB_IE | RB_PIN_USB_DP_PU;
- } else if ((uint32_t) & (CH58x_USBFS_DEV->USB_CTRL) == (uint32_t)USB1_BASE) {
- /*!< USB1 */
- R16_PIN_ANALOG_IE |= RB_PIN_USB2_IE | RB_PIN_USB2_DP_PU;
- }
-
- CH58x_USBFS_DEV->USB_INT_FG = 0xff; /*!< Clear interrupt flag */
- CH58x_USBFS_DEV->UDEV_CTRL = RB_UD_PD_DIS | RB_UD_PORT_EN; /*!< Allow USB port */
- CH58x_USBFS_DEV->USB_INT_EN = RB_UIE_SUSPEND | RB_UIE_BUS_RST | RB_UIE_TRANSFER;
-
- usb_dc_low_level_init();
- return 0;
-}
-
-int usb_dc_deinit(uint8_t busid)
-{
- return 0;
-}
-
-/**
- * @brief Set address
- * @pre None
- * @param[in] address :8-bit valid address
- * @retval >=0 success otherwise failure
- */
-int usbd_set_address(uint8_t busid, const uint8_t address)
-{
- if (address == 0) {
- CH58x_USBFS_DEV->USB_DEV_AD = (CH58x_USBFS_DEV->USB_DEV_AD & 0x80) | address;
- }
- usb_dc_cfg.address = address;
- return 0;
-}
-
-int usbd_set_remote_wakeup(uint8_t busid)
-{
- return -1;
-}
-
-uint8_t usbd_get_port_speed(uint8_t busid)
-{
- return USB_SPEED_FULL;
-}
-
-/**
- * @brief Open endpoint
- * @pre None
- * @param[in] ep_cfg : Endpoint configuration structure pointer
- * @retval >=0 success otherwise failure
- */
-int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
-{
- /*!< ep id */
- uint8_t epid = USB_EP_GET_IDX(ep->bEndpointAddress);
- if (epid > (CONFIG_USBDEV_EP_NUM - 1)) {
- /**
- * If you use ch58x, you can change the CONFIG_USBDEV_EP_NUM set to 8
- */
- USB_LOG_ERR("Ep addr %02x overflow\r\n", ep->bEndpointAddress);
- return -1;
- }
-
- /*!< ep max packet length */
- uint8_t mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
- /*!< update ep max packet length */
- if (USB_EP_DIR_IS_IN(ep->bEndpointAddress)) {
- /*!< in */
- usb_dc_cfg.ep_in[epid].ep_enable = true;
- usb_dc_cfg.ep_in[epid].mps = mps;
- usb_dc_cfg.ep_in[epid].eptype = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
- } else if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
- /*!< out */
- usb_dc_cfg.ep_out[epid].ep_enable = true;
- usb_dc_cfg.ep_out[epid].mps = mps;
- usb_dc_cfg.ep_out[epid].eptype = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
- }
- return 0;
-}
-
-/**
- * @brief Close endpoint
- * @pre None
- * @param[in] ep : Endpoint address
- * @retval >=0 success otherwise failure
- */
-int usbd_ep_close(uint8_t busid, const uint8_t ep)
-{
- /*!< ep id */
- uint8_t epid = USB_EP_GET_IDX(ep);
- if (USB_EP_DIR_IS_IN(ep)) {
- /*!< in */
- usb_dc_cfg.ep_in[epid].ep_enable = false;
- } else if (USB_EP_DIR_IS_OUT(ep)) {
- /*!< out */
- usb_dc_cfg.ep_out[epid].ep_enable = false;
- }
- return 0;
-}
-
-
-/**
- * @brief Endpoint setting stall
- * @pre None
- * @param[in] ep : Endpoint address
- * @retval >=0 success otherwise failure
- */
-int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
-{
- /*!< ep id */
- uint8_t epid = USB_EP_GET_IDX(ep);
- if (USB_EP_DIR_IS_OUT(ep)) {
- EPn_SET_RX_STALL(epid);
- } else {
- EPn_SET_TX_STALL(epid);
- }
- return 0;
-}
-
-/**
- * @brief Endpoint clear stall
- * @pre None
- * @param[in] ep : Endpoint address
- * @retval >=0 success otherwise failure
- */
-int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
-{
- uint8_t epid = USB_EP_GET_IDX(ep);
- if (USB_EP_DIR_IS_OUT(ep)) {
- EPn_CLR_RX_STALL(epid);
- } else {
- EPn_CLR_TX_STALL(epid);
- }
- return 0;
-}
-
-/**
- * @brief Check endpoint status
- * @pre None
- * @param[in] ep : Endpoint address
- * @param[out] stalled : Outgoing endpoint status
- * @retval >=0 success otherwise failure
- */
-int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
-{
- if (USB_EP_DIR_IS_OUT(ep)) {
- } else {
- }
- return 0;
-}
-
-/**
- * @brief Setup in ep transfer setting and start transfer.
- *
- * This function is asynchronous.
- * This function is similar to uart with tx dma.
- *
- * This function is called to write data to the specified endpoint. The
- * supplied usbd_endpoint_callback function will be called when data is transmitted
- * out.
- *
- * @param[in] ep Endpoint address corresponding to the one
- * listed in the device configuration table
- * @param[in] data Pointer to data to write
- * @param[in] data_len Length of the data requested to write. This may
- * be zero for a zero length status packet.
- * @return 0 on success, negative errno code on fail.
- */
-int usbd_ep_start_write(uint8_t busid, 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 (!usb_dc_cfg.ep_in[ep_idx].ep_enable) {
- return -2;
- }
- if ((uint32_t)data & 0x03) {
- return -3;
- }
-
- usb_dc_cfg.ep_in[ep_idx].xfer_buf = (uint8_t *)data;
- usb_dc_cfg.ep_in[ep_idx].xfer_len = data_len;
- usb_dc_cfg.ep_in[ep_idx].actual_xfer_len = 0;
-
- if (data_len == 0) {
- /*!< write 0 len data */
- EPn_SET_TX_LEN(ep_idx, 0);
- /*!< enable tx */
- if (usb_dc_cfg.ep_in[ep_idx].eptype != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- EPn_SET_TX_VALID(ep_idx);
- } else {
- EPn_SET_TX_ISO_VALID(ep_idx);
- }
- /*!< return */
- return 0;
- } else {
- /*!< Not zlp */
- data_len = MIN(data_len, usb_dc_cfg.ep_in[ep_idx].mps);
- /*!< write buff */
- memcpy(usb_dc_cfg.ep_in[ep_idx].ep_ram_addr, data, data_len);
- /*!< write real_wt_nums len data */
- EPn_SET_TX_LEN(ep_idx, data_len);
- /*!< enable tx */
- if (usb_dc_cfg.ep_in[ep_idx].eptype != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- EPn_SET_TX_VALID(ep_idx);
- } else {
- EPn_SET_TX_ISO_VALID(ep_idx);
- }
- }
- return 0;
-}
-
-/**
- * @brief Setup out ep transfer setting and start transfer.
- *
- * This function is asynchronous.
- * This function is similar to uart with rx dma.
- *
- * This function is called to read data to the specified endpoint. The
- * supplied usbd_endpoint_callback function will be called when data is received
- * in.
- *
- * @param[in] ep Endpoint address corresponding to the one
- * listed in the device configuration table
- * @param[in] data Pointer to data to read
- * @param[in] data_len Max length of the data requested to read.
- *
- * @return 0 on success, negative errno code on fail.
- */
-int usbd_ep_start_read(uint8_t busid, 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 (!usb_dc_cfg.ep_out[ep_idx].ep_enable) {
- return -2;
- }
- if ((uint32_t)data & 0x03) {
- return -3;
- }
-
- usb_dc_cfg.ep_out[ep_idx].xfer_buf = (uint8_t *)data;
- usb_dc_cfg.ep_out[ep_idx].xfer_len = data_len;
- usb_dc_cfg.ep_out[ep_idx].actual_xfer_len = 0;
-
- if (data_len == 0) {
- } else {
- data_len = MIN(data_len, usb_dc_cfg.ep_out[ep_idx].mps);
- }
-
- if (usb_dc_cfg.ep_out[ep_idx].eptype != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- EPn_SET_RX_VALID(ep_idx);
- } else {
- EPn_SET_RX_ISO_VALID(ep_idx);
- }
- return 0;
-}
-
-/**
- * @brief USB interrupt processing function
- * @pre None
- * @param[in] None
- * @retval None
- */
-void USBD_IRQHandler(uint8_t busid)
-{
- volatile uint8_t intflag = 0;
- intflag = CH58x_USBFS_DEV->USB_INT_FG;
-
- if (intflag & RB_UIF_TRANSFER) {
- if ((CH58x_USBFS_DEV->USB_INT_ST & MASK_UIS_TOKEN) != MASK_UIS_TOKEN) {
- uint8_t epid = ((CH58x_USBFS_DEV->USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP)) & 0x0f);
- switch ((CH58x_USBFS_DEV->USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP)) & 0xf0) {
- case UIS_TOKEN_IN:
- if (epid == 0) {
- /**
- * IN The host takes away the data that has been stored in FIFO
- */
- switch (usb_dc_cfg.setup.bmRequestType >> USB_REQUEST_DIR_SHIFT) {
- case 1:
- /*!< Get */
- CH58x_USBFS_DEV->UEP0_CTRL ^= RB_UEP_T_TOG;
- /**
- * Here is to take away the last data, and the IN interrupt will be triggered only after it is successfully taken away.
- * Therefore, the status of the in endpoint is set to NAK here. If there is data transmission,
- * the endpoint status will be set to ack again in the in handler of EP0.
- */
- EPn_SET_TX_NAK(0);
-
- /*!< IN */
- if (usb_dc_cfg.ep_in[0].xfer_len > usb_dc_cfg.ep_in[0].mps) {
- usb_dc_cfg.ep_in[0].xfer_len -= usb_dc_cfg.ep_in[0].mps;
- usb_dc_cfg.ep_in[0].actual_xfer_len += usb_dc_cfg.ep_in[0].mps;
- usbd_event_ep_in_complete_handler(0, 0 | 0x80, usb_dc_cfg.ep_in[0].actual_xfer_len);
- } else {
- usb_dc_cfg.ep_in[0].actual_xfer_len += usb_dc_cfg.ep_in[0].xfer_len;
- usb_dc_cfg.ep_in[0].xfer_len = 0;
- usbd_event_ep_in_complete_handler(0, 0 | 0x80, usb_dc_cfg.ep_in[0].actual_xfer_len);
- }
- break;
- case 0:
- /*!< Set */
- switch (usb_dc_cfg.setup.bRequest) {
- case USB_REQUEST_SET_ADDRESS:
- /*!< Fill in the equipment address */
- CH58x_USBFS_DEV->USB_DEV_AD = (CH58x_USBFS_DEV->USB_DEV_AD & RB_UDA_GP_BIT) | usb_dc_cfg.address;
- /**
- * In the state phase after setting the address, the host has sent an in token packet of data1 to take the packet of 0 length,
- * Ch58x USB IP needs to manually set the status of the in endpoint to NAK
- */
- EPn_SET_TX_NAK(0);
- EPn_SET_RX_VALID(0);
- break;
- default:
- /*!< Normal out state phase */
- /**
- * The host has sent an in token packet of data1 and taken the packet of 0 length.
- * Here, you only need to set the status of the in endpoint to NAK and out endpoint ACK
- */
- EPn_SET_TX_NAK(0);
- EPn_SET_RX_VALID(0);
- break;
- }
- break;
- }
- } else {
- if (epid == 4) {
- CH58x_USBFS_DEV->UEP4_CTRL ^= RB_UEP_T_TOG;
- }
- EPn_SET_TX_NAK(epid);
- if (usb_dc_cfg.ep_in[epid].xfer_len > usb_dc_cfg.ep_in[epid].mps) {
- /*!< Need start in again */
- usb_dc_cfg.ep_in[epid].xfer_buf += usb_dc_cfg.ep_in[epid].mps;
- usb_dc_cfg.ep_in[epid].xfer_len -= usb_dc_cfg.ep_in[epid].mps;
- usb_dc_cfg.ep_in[epid].actual_xfer_len += usb_dc_cfg.ep_in[epid].mps;
- if (usb_dc_cfg.ep_in[epid].xfer_len > usb_dc_cfg.ep_in[epid].mps) {
- memcpy(usb_dc_cfg.ep_in[epid].ep_ram_addr, usb_dc_cfg.ep_in[epid].xfer_buf, usb_dc_cfg.ep_in[epid].mps);
- EPn_SET_TX_LEN(epid, usb_dc_cfg.ep_in[epid].mps);
- } else {
- memcpy(usb_dc_cfg.ep_in[epid].ep_ram_addr, usb_dc_cfg.ep_in[epid].xfer_buf, usb_dc_cfg.ep_in[epid].xfer_len);
- EPn_SET_TX_LEN(epid, usb_dc_cfg.ep_in[epid].xfer_len);
- }
- if (usb_dc_cfg.ep_in[epid].eptype != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- EPn_SET_TX_VALID(epid);
- } else {
- EPn_SET_TX_ISO_VALID(epid);
- }
- } else {
- usb_dc_cfg.ep_in[epid].actual_xfer_len += usb_dc_cfg.ep_in[epid].xfer_len;
- usb_dc_cfg.ep_in[epid].xfer_len = 0;
- usbd_event_ep_in_complete_handler(0, epid | 0x80, usb_dc_cfg.ep_in[epid].actual_xfer_len);
- }
- }
- break;
- case UIS_TOKEN_OUT:
- if (epid == 0) {
- /*!< ep0 out */
- CH58x_USBFS_DEV->UEP0_CTRL ^= RB_UEP_R_TOG;
- EPn_SET_RX_NAK(epid);
- uint32_t read_count = EPn_GET_RX_LEN(0);
- memcpy(usb_dc_cfg.ep_out[epid].xfer_buf, usb_dc_cfg.ep_out[epid].ep_ram_addr, read_count);
-
- usb_dc_cfg.ep_out[0].actual_xfer_len += read_count;
- usb_dc_cfg.ep_out[0].xfer_len -= read_count;
- usbd_event_ep_out_complete_handler(0, 0x00, usb_dc_cfg.ep_out[0].actual_xfer_len);
- if (read_count == 0) {
- /*!< Out status, start reading setup */
- EPn_SET_RX_VALID(0);
- }
- } else {
- if ((CH58x_USBFS_DEV->USB_INT_ST) & RB_UIS_TOG_OK) {
- if (epid == 4) {
- CH58x_USBFS_DEV->UEP4_CTRL ^= RB_UEP_R_TOG;
- }
- EPn_SET_RX_NAK(epid);
- uint32_t read_count = EPn_GET_RX_LEN(epid);
- memcpy(usb_dc_cfg.ep_out[epid].xfer_buf, usb_dc_cfg.ep_out[epid].ep_ram_addr, read_count);
- usb_dc_cfg.ep_out[epid].xfer_buf += read_count;
- usb_dc_cfg.ep_out[epid].actual_xfer_len += read_count;
- usb_dc_cfg.ep_out[epid].xfer_len -= read_count;
-
- if ((read_count < usb_dc_cfg.ep_out[epid].mps) || (usb_dc_cfg.ep_out[epid].xfer_len == 0)) {
- usbd_event_ep_out_complete_handler(0, ((epid)&0x7f), usb_dc_cfg.ep_out[epid].actual_xfer_len);
- } else {
- if (usb_dc_cfg.ep_out[epid].eptype != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- EPn_SET_RX_VALID(epid);
- } else {
- EPn_SET_RX_ISO_VALID(epid);
- }
- }
- }
- }
- break;
- default:
- break;
- }
- CH58x_USBFS_DEV->USB_INT_FG = RB_UIF_TRANSFER;
- }
-
- if (CH58x_USBFS_DEV->USB_INT_ST & RB_UIS_SETUP_ACT) {
- /*!< Setup */
- /**
- * Setup the device must respond with ACK, and the next data phase is DATA1
- * If it is sent, the data1 packet will be sent.
- * If it is received, the data1 packet is expected to be received.
- * If it is in, the host will send the data1 out packet to complete the status phase after the in completes.
- * If it is out, the host will send the data1 in packet to complete the status phase after the out completes.
- */
- CH58x_USBFS_DEV->UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_T_RES_NAK;
- /*!< get setup packet */
- usb_dc_cfg.setup = GET_SETUP_PACKET(usb_dc_cfg.ep_out[0].ep_ram_addr);
- if (usb_dc_cfg.setup.bmRequestType >> USB_REQUEST_DIR_SHIFT == 0) {
- /**
- * Ep0 The next in must be the status stage.
- * The device must reply to the host data 0 length packet.
- * Here, set the transmission length to 0 and the transmission status to ACK,
- * and wait for the host to send the in token to retrieve
- */
- EPn_SET_TX_LEN(0, 0);
- EPn_SET_TX_VALID(0);
- }
- EPn_SET_RX_NAK(0);
- usbd_event_ep0_setup_complete_handler(0, (uint8_t *)&(usb_dc_cfg.setup));
- CH58x_USBFS_DEV->USB_INT_FG = RB_UIF_TRANSFER;
- }
- } else if (intflag & RB_UIF_BUS_RST) {
- /*!< Reset */
- CH58x_USBFS_DEV->USB_DEV_AD = 0;
- usbd_event_reset_handler(0);
- /*!< Set ep0 rx vaild to start receive setup packet */
- EPn_SET_RX_VALID(0);
- CH58x_USBFS_DEV->USB_INT_FG = RB_UIF_BUS_RST;
- } else if (intflag & RB_UIF_SUSPEND) {
- if (CH58x_USBFS_DEV->USB_MIS_ST & RB_UMS_SUSPEND) {
- /*!< Suspend */
- } else {
- /*!< Wake up */
- }
- CH58x_USBFS_DEV->USB_INT_FG = RB_UIF_SUSPEND;
- } else {
- CH58x_USBFS_DEV->USB_INT_FG = intflag;
- }
-}
-
-void USB_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))) __attribute__((section(".highcode")));
-void USB_IRQHandler(void)
-{
- extern void USBD_IRQHandler(uint8_t busid);
- USBD_IRQHandler(0);
-}
diff --git a/port/ch32/ch58x/usb_ch58x_usbfs_reg.h b/port/ch32/ch58x/usb_ch58x_usbfs_reg.h
deleted file mode 100644
index f7fda8c6..00000000
--- a/port/ch32/ch58x/usb_ch58x_usbfs_reg.h
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (c) 2022, sakumisu
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#pragma once
-
-#define __IO volatile
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define RB_UC_HOST_MODE 0x80 // enable USB host mode: 0=device mode, 1=host mode
-#define RB_UC_LOW_SPEED 0x40 // enable USB low speed: 0=12Mbps, 1=1.5Mbps
-#define RB_UC_DEV_PU_EN 0x20 // USB device enable and internal pullup resistance enable
-#define RB_UC_SYS_CTRL1 0x20 // USB system control high bit
-#define RB_UC_SYS_CTRL0 0x10 // USB system control low bit
-#define MASK_UC_SYS_CTRL 0x30 // bit mask of USB system control
-#define RB_UC_INT_BUSY 0x08 // enable automatic responding busy for device mode or automatic pause for host mode during interrupt flag UIF_TRANSFER valid
-#define RB_UC_RESET_SIE 0x04 // force reset USB SIE, need software clear
-#define RB_UC_CLR_ALL 0x02 // force clear FIFO and count of USB
-#define RB_UC_DMA_EN 0x01 // DMA enable and DMA interrupt enable for USB
-
-#define RB_UD_PD_DIS 0x80 // disable USB UDP/UDM pulldown resistance: 0=enable pulldown, 1=disable
-#define RB_UD_DP_PIN 0x20 // ReadOnly: indicate current UDP pin level
-#define RB_UD_DM_PIN 0x10 // ReadOnly: indicate current UDM pin level
-#define RB_UD_LOW_SPEED 0x04 // enable USB physical port low speed: 0=full speed, 1=low speed
-#define RB_UD_GP_BIT 0x02 // general purpose bit
-#define RB_UD_PORT_EN 0x01 // enable USB physical port I/O: 0=disable, 1=enable
-
-#define RB_UH_PD_DIS 0x80 // disable USB UDP/UDM pulldown resistance: 0=enable pulldown, 1=disable
-#define RB_UH_DP_PIN 0x20 // ReadOnly: indicate current UDP pin level
-#define RB_UH_DM_PIN 0x10 // ReadOnly: indicate current UDM pin level
-#define RB_UH_LOW_SPEED 0x04 // enable USB port low speed: 0=full speed, 1=low speed
-#define RB_UH_BUS_RESET 0x02 // control USB bus reset: 0=normal, 1=force bus reset
-#define RB_UH_PORT_EN 0x01 // enable USB port: 0=disable, 1=enable port, automatic disabled if USB device detached
-
-#define RB_UIE_DEV_SOF 0x80 // enable interrupt for SOF received for USB device mode
-#define RB_UIE_DEV_NAK 0x40 // enable interrupt for NAK responded for USB device mode
-#define RB_UIE_FIFO_OV 0x10 // enable interrupt for FIFO overflow
-#define RB_UIE_HST_SOF 0x08 // enable interrupt for host SOF timer action for USB host mode
-#define RB_UIE_SUSPEND 0x04 // enable interrupt for USB suspend or resume event
-#define RB_UIE_TRANSFER 0x02 // enable interrupt for USB transfer completion
-#define RB_UIE_DETECT 0x01 // enable interrupt for USB device detected event for USB host mode
-#define RB_UIE_BUS_RST 0x01 // enable interrupt for USB bus reset event for USB device mode
-
-#define RB_UDA_GP_BIT 0x80 // general purpose bit
-#define MASK_USB_ADDR 0x7F // bit mask for USB device address
-
-#define RB_UMS_SOF_PRES 0x80 // RO, indicate host SOF timer presage status
-#define RB_UMS_SOF_ACT 0x40 // RO, indicate host SOF timer action status for USB host
-#define RB_UMS_SIE_FREE 0x20 // RO, indicate USB SIE free status
-#define RB_UMS_R_FIFO_RDY 0x10 // RO, indicate USB receiving FIFO ready status (not empty)
-#define RB_UMS_BUS_RESET 0x08 // RO, indicate USB bus reset status
-#define RB_UMS_SUSPEND 0x04 // RO, indicate USB suspend status
-#define RB_UMS_DM_LEVEL 0x02 // RO, indicate UDM level saved at device attached to USB host
-#define RB_UMS_DEV_ATTACH 0x01 // RO, indicate device attached status on USB host
-
-#define RB_U_IS_NAK 0x80 // RO, indicate current USB transfer is NAK received
-#define RB_U_TOG_OK 0x40 // RO, indicate current USB transfer toggle is OK
-#define RB_U_SIE_FREE 0x20 // RO, indicate USB SIE free status
-#define RB_UIF_FIFO_OV 0x10 // FIFO overflow interrupt flag for USB, direct bit address clear or write 1 to clear
-#define RB_UIF_HST_SOF 0x08 // host SOF timer interrupt flag for USB host, direct bit address clear or write 1 to clear
-#define RB_UIF_SUSPEND 0x04 // USB suspend or resume event interrupt flag, direct bit address clear or write 1 to clear
-#define RB_UIF_TRANSFER 0x02 // USB transfer completion interrupt flag, direct bit address clear or write 1 to clear
-#define RB_UIF_DETECT 0x01 // device detected event interrupt flag for USB host mode, direct bit address clear or write 1 to clear
-#define RB_UIF_BUS_RST 0x01 // bus reset event interrupt flag for USB device mode, direct bit address clear or write 1 to clear
-
-#define RB_UIS_SETUP_ACT 0x80 // RO, indicate SETUP token & 8 bytes setup request received for USB device mode
-#define RB_UIS_TOG_OK 0x40 // RO, indicate current USB transfer toggle is OK
-#define RB_UIS_TOKEN1 0x20 // RO, current token PID code bit 1 received for USB device mode
-#define RB_UIS_TOKEN0 0x10 // RO, current token PID code bit 0 received for USB device mode
-#define MASK_UIS_TOKEN 0x30 // RO, bit mask of current token PID code received for USB device mode
-#define UIS_TOKEN_OUT 0x00
-#define UIS_TOKEN_SOF 0x10
-#define UIS_TOKEN_IN 0x20
-#define UIS_TOKEN_SETUP 0x30
-
-#define MASK_UIS_ENDP 0x0F // RO, bit mask of current transfer endpoint number for USB device mode
-#define MASK_UIS_H_RES 0x0F // RO, bit mask of current transfer handshake response for USB host mode: 0000=no response, time out from device, others=handshake response PID received
-
-#define R8_USB_RX_LEN (*((uint8_t *)0x40008008)) // USB receiving length
-#define RB_UEP1_RX_EN 0x80 // enable USB endpoint 1 receiving (OUT)
-#define RB_UEP1_TX_EN 0x40 // enable USB endpoint 1 transmittal (IN)
-#define RB_UEP1_BUF_MOD 0x10 // buffer mode of USB endpoint 1
-
-#define RB_UEP4_RX_EN 0x08 // enable USB endpoint 4 receiving (OUT)
-#define RB_UEP4_TX_EN 0x04 // enable USB endpoint 4 transmittal (IN)
-
-#define RB_UEP3_RX_EN 0x80 // enable USB endpoint 3 receiving (OUT)
-#define RB_UEP3_TX_EN 0x40 // enable USB endpoint 3 transmittal (IN)
-#define RB_UEP3_BUF_MOD 0x10 // buffer mode of USB endpoint 3
-#define RB_UEP2_RX_EN 0x08 // enable USB endpoint 2 receiving (OUT)
-#define RB_UEP2_TX_EN 0x04 // enable USB endpoint 2 transmittal (IN)
-#define RB_UEP2_BUF_MOD 0x01 // buffer mode of USB endpoint 2
-
-#define RB_UEP7_RX_EN 0x20 // enable USB endpoint 7 receiving (OUT)
-#define RB_UEP7_TX_EN 0x10 // enable USB endpoint 7 transmittal (IN)
-#define RB_UEP6_RX_EN 0x08 // enable USB endpoint 6 receiving (OUT)
-#define RB_UEP6_TX_EN 0x04 // enable USB endpoint 6 transmittal (IN)
-#define RB_UEP5_RX_EN 0x02 // enable USB endpoint 5 receiving (OUT)
-#define RB_UEP5_TX_EN 0x01 // enable USB endpoint 5 transmittal (IN)
-
-#define RB_UH_EP_TX_EN 0x40 // enable USB host OUT endpoint transmittal
-#define RB_UH_EP_TBUF_MOD 0x10 // buffer mode of USB host OUT endpoint
-
-#define RB_UH_EP_RX_EN 0x08 // enable USB host IN endpoint receiving
-#define RB_UH_EP_RBUF_MOD 0x01 // buffer mode of USB host IN endpoint
-
-#define RB_UEP_R_TOG 0x80 // expected data toggle flag of USB endpoint X receiving (OUT): 0=DATA0, 1=DATA1
-#define RB_UEP_T_TOG 0x40 // prepared data toggle flag of USB endpoint X transmittal (IN): 0=DATA0, 1=DATA1
-#define RB_UEP_AUTO_TOG 0x10 // enable automatic toggle after successful transfer completion on endpoint 1/2/3: 0=manual toggle, 1=automatic toggle
-#define RB_UEP_R_RES1 0x08 // handshake response type high bit for USB endpoint X receiving (OUT)
-#define RB_UEP_R_RES0 0x04 // handshake response type low bit for USB endpoint X receiving (OUT)
-#define MASK_UEP_R_RES 0x0C // bit mask of handshake response type for USB endpoint X receiving (OUT)
-#define UEP_R_RES_ACK 0x00
-#define UEP_R_RES_TOUT 0x04
-#define UEP_R_RES_NAK 0x08
-#define UEP_R_RES_STALL 0x0C
-
-#define RB_UEP_T_RES1 0x02 // handshake response type high bit for USB endpoint X transmittal (IN)
-#define RB_UEP_T_RES0 0x01 // handshake response type low bit for USB endpoint X transmittal (IN)
-#define MASK_UEP_T_RES 0x03 // bit mask of handshake response type for USB endpoint X transmittal (IN)
-#define UEP_T_RES_ACK 0x00
-#define UEP_T_RES_TOUT 0x01
-#define UEP_T_RES_NAK 0x02
-#define UEP_T_RES_STALL 0x03
-
-#define RB_UH_PRE_PID_EN 0x80 // USB host PRE PID enable for low speed device via hub
-#define RB_UH_SOF_EN 0x40 // USB host automatic SOF enable
-
-#define R8_UH_EP_PID R8_UEP2_T_LEN // host endpoint and PID
-#define MASK_UH_TOKEN 0xF0 // bit mask of token PID for USB host transfer
-#define MASK_UH_ENDP 0x0F // bit mask of endpoint number for USB host transfer
-
-#define R8_UH_RX_CTRL R8_UEP2_CTRL // host receiver endpoint control
-#define RB_UH_R_TOG 0x80 // expected data toggle flag of host receiving (IN): 0=DATA0, 1=DATA1
-#define RB_UH_R_AUTO_TOG 0x10 // enable automatic toggle after successful transfer completion: 0=manual toggle, 1=automatic toggle
-#define RB_UH_R_RES 0x04 // prepared handshake response type for host receiving (IN): 0=ACK (ready), 1=no response, time out to device, for isochronous transactions
-
-#define R8_UH_TX_LEN R8_UEP3_T_LEN // host transmittal endpoint transmittal length
-
-#define RB_UH_T_TOG 0x40 // prepared data toggle flag of host transmittal (SETUP/OUT): 0=DATA0, 1=DATA1
-#define RB_UH_T_AUTO_TOG 0x10 // enable automatic toggle after successful transfer completion: 0=manual toggle, 1=automatic toggle
-#define RB_UH_T_RES 0x01 // expected handshake response type for host transmittal (SETUP/OUT): 0=ACK (ready), 1=no response, time out from device, for isochronous transactions
-
-#define R16_PIN_ANALOG_IE (*((uint16_t *)0x4000101A)) // RW, analog pin enable and digital input disable
-#define RB_PIN_USB_IE 0x80 // RW, USB analog I/O enable: 0=analog I/O disable, 1=analog I/O enable
-#define RB_PIN_USB_DP_PU 0x40 // RW, USB UDP internal pullup resistance enable: 0=enable/disable by RB_UC_DEV_PU_EN, 1=enable pullup, replace RB_UC_DEV_PU_EN under sleep mode
-#define RB_PIN_USB2_IE 0x20 // RW, USB2 analog I/O enable: 0=analog I/O disable, 1=analog I/O enable
-#define RB_PIN_USB2_DP_PU 0x10 // RW, USB2 UDP internal pullup resistance enable: 0=enable/disable by RB_UC_DEV_PU_EN, 1=enable pullup, replace RB_UC_DEV_PU_EN under sleep mode
-/*!< USB Regs */
-typedef struct
-{
- __IO uint8_t USB_CTRL; /*!< 0x40008000 */
- union {
- __IO uint8_t UDEV_CTRL; /*!< 0x40008001 */
- __IO uint8_t UHOST_CTRL; /*!< 0x40008001 */
- };
- __IO uint8_t USB_INT_EN; /*!< 0x40008002 */
- __IO uint8_t USB_DEV_AD; /*!< 0x40008003 */
- __IO uint8_t USB_STATUS0; /*!< 0x40008004 */
- __IO uint8_t USB_MIS_ST; /*!< 0x40008005 */
- __IO uint8_t USB_INT_FG; /*!< 0x40008006 */
- __IO uint8_t USB_INT_ST; /*!< 0x40008007 */
- __IO uint8_t USB_RX_LEN; /*!< 0x40008008 */
- __IO uint8_t Reserve1; /*!< 0x40008009 */
- __IO uint8_t Reserve2; /*!< 0x4000800a */
- __IO uint8_t Reserve3; /*!< 0x4000800b */
- __IO uint8_t UEP4_1_MOD; /*!< 0x4000800c */
- union {
- __IO uint8_t UEP2_3_MOD; /*!< 0x4000800d */
- __IO uint8_t UH_EP_MOD; /*!< 0x4000800d */
- };
- __IO uint8_t UEP567_MOD; /*!< 0x4000800e */
- __IO uint8_t Reserve4; /*!< 0x4000800f */
- __IO uint16_t UEP0_DMA; /*!< 0x40008010 */
- __IO uint16_t Reserve5; /*!< 0x40008012 */
- __IO uint16_t UEP1_DMA; /*!< 0x40008014 */
- __IO uint16_t Reserve6; /*!< 0x40008016 */
- union {
- __IO uint16_t UEP2_DMA; /*!< 0x40008018 */
- __IO uint16_t UH_RX_DMA; /*!< 0x40008018 */
- };
- __IO uint16_t Reserve7; /*!< 0x4000801a */
- union {
- __IO uint16_t UEP3_DMA; /*!< 0x4000801c */
- __IO uint16_t UH_TX_DMA; /*!< 0x4000801c */
- };
- __IO uint16_t Reserve8; /*!< 0x4000801e */
- __IO uint8_t UEP0_T_LEN; /*!< 0x40008020 */
- __IO uint8_t Reserve9; /*!< 0x40008021 */
- __IO uint8_t UEP0_CTRL; /*!< 0x40008022 */
- __IO uint8_t Reserve10; /*!< 0x40008023 */
- __IO uint8_t UEP1_T_LEN; /*!< 0x40008024 */
- __IO uint8_t Reserve11; /*!< 0x40008025 */
- union {
- __IO uint8_t UEP1_CTRL; /*!< 0x40008026 */
- __IO uint8_t UH_SETUP; /*!< 0x40008026 */
- };
- __IO uint8_t Reserve12; /*!< 0x40008027 */
- union {
- __IO uint8_t UEP2_T_LEN; /*!< 0x40008028 */
- __IO uint8_t UH_EP_PID; /*!< 0x40008028 */
- };
- __IO uint8_t Reserve13; /*!< 0x40008029 */
- union {
- __IO uint8_t UEP2_CTRL; /*!< 0x4000802a */
- __IO uint8_t UH_RX_CTRL; /*!< 0x4000802a */
- };
- __IO uint8_t Reserve14; /*!< 0x4000802b */
- union {
- __IO uint8_t UEP3_T_LEN; /*!< 0x4000802c */
- __IO uint8_t UH_TX_LEN; /*!< 0x4000802c */
- };
- __IO uint8_t Reserve15; /*!< 0x4000802d */
- union {
- __IO uint8_t UEP3_CTRL; /*!< 0x4000802e */
- __IO uint8_t UH_TX_CTRL; /*!< 0x4000802e */
- };
- __IO uint8_t Reserve16; /*!< 0x4000802f */
- __IO uint8_t UEP4_T_LEN; /*!< 0x40008030 */
- __IO uint8_t Reserve17; /*!< 0x40008031 */
- __IO uint8_t UEP4_CTRL; /*!< 0x40008032 */
- __IO uint8_t Reserve18[33]; /*!< 0x40008033 */
- __IO uint16_t UEP5_DMA; /*!< 0x40008054 */
- __IO uint16_t Reserve19; /*!< 0x40008056 */
- __IO uint16_t UEP6_DMA; /*!< 0x40008058 */
- __IO uint16_t Reserve20; /*!< 0x4000805a */
- __IO uint16_t UEP7_DMA; /*!< 0x4000805c */
- __IO uint8_t Reserve21[6]; /*!< 0x4000805e */
- __IO uint8_t UEP5_T_LEN; /*!< 0x40008064 */
- __IO uint8_t Reserve22; /*!< 0x40008065 */
- __IO uint8_t UEP5_CTRL; /*!< 0x40008066 */
- __IO uint8_t Reserve23; /*!< 0x40008067 */
- __IO uint8_t UEP6_T_LEN; /*!< 0x40008068 */
- __IO uint8_t Reserve24; /*!< 0x40008069 */
- __IO uint8_t UEP6_CTRL; /*!< 0x4000806a */
- __IO uint8_t Reserve25; /*!< 0x4000806b */
- __IO uint8_t UEP7_T_LEN; /*!< 0x4000806c */
- __IO uint8_t Reserve26; /*!< 0x4000806d */
- __IO uint8_t UEP7_CTRL; /*!< 0x4000806e */
-} USB_FS_TypeDef;
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/port/chipidea/usb_dc_chipidea.c b/port/chipidea/usb_dc_chipidea.c
index 06b9a3d8..425003e8 100644
--- a/port/chipidea/usb_dc_chipidea.c
+++ b/port/chipidea/usb_dc_chipidea.c
@@ -440,13 +440,8 @@ static bool chipidea_start_xfer(uint8_t busid, uint8_t ep_addr, uint8_t *buffer,
return true;
}
-__WEAK void usb_dc_low_level_init(uint8_t busid)
-{
-}
-
-__WEAK void usb_dc_low_level_deinit(uint8_t busid)
-{
-}
+extern void usb_dc_low_level_init(uint8_t busid);
+extern void usb_dc_low_level_deinit(uint8_t busid);
int usb_dc_init(uint8_t busid)
{
diff --git a/port/dwc2/usb_dc_dwc2.c b/port/dwc2/usb_dc_dwc2.c
index 24fcb926..c59f248d 100644
--- a/port/dwc2/usb_dc_dwc2.c
+++ b/port/dwc2/usb_dc_dwc2.c
@@ -36,6 +36,11 @@ USB_NOCACHE_RAM_SECTION struct dwc2_udc {
struct dwc2_ep_state out_ep[16]; /*!< OUT endpoint parameters */
} g_dwc2_udc[CONFIG_USBDEV_MAX_BUS];
+extern void usb_dc_low_level_init(uint8_t busid);
+extern void usb_dc_low_level_deinit(uint8_t busid);
+extern void usbd_dwc2_delay_ms(uint8_t ms);
+extern uint32_t usbd_dwc2_get_system_clock(void);
+
static inline int dwc2_reset(uint8_t busid)
{
volatile uint32_t count = 0U;
@@ -620,10 +625,13 @@ int usb_dc_deinit(uint8_t busid)
USB_OTG_GLB->GAHBCFG &= ~USB_OTG_GAHBCFG_GINT;
USB_OTG_DEV->DCTL |= USB_OTG_DCTL_SDIS;
- /* Clear Pending interrupt */
for (uint8_t i = 0U; i < 15U; i++) {
+ USB_OTG_INEP(i)->DIEPCTL = 0;
+ USB_OTG_OUTEP(i)->DOEPCTL = USB_OTG_DOEPCTL_SNAK;
USB_OTG_INEP(i)->DIEPINT = 0xFB7FU;
USB_OTG_OUTEP(i)->DOEPINT = 0xFB7FU;
+ USB_OTG_INEP(i)->DIEPTSIZ = 0U;
+ USB_OTG_OUTEP(i)->DOEPTSIZ = 0U;
}
/* Clear interrupt masks */
@@ -771,6 +779,15 @@ int usbd_ep_close(uint8_t busid, const uint8_t ep)
if (USB_EP_DIR_IS_OUT(ep)) {
if (USB_OTG_OUTEP(ep_idx)->DOEPCTL & USB_OTG_DOEPCTL_EPENA) {
+ /* An OUT endpoint is only disabled while Global OUT NAK is in effect */
+ USB_OTG_DEV->DCTL |= USB_OTG_DCTL_SGONAK;
+ count = 0;
+ do {
+ if (++count > 50000) {
+ break;
+ }
+ } while ((USB_OTG_GLB->GINTSTS & USB_OTG_GINTSTS_BOUTNAKEFF) != USB_OTG_GINTSTS_BOUTNAKEFF);
+
USB_OTG_OUTEP(ep_idx)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
USB_OTG_OUTEP(ep_idx)->DOEPCTL |= USB_OTG_DOEPCTL_EPDIS;
@@ -784,6 +801,8 @@ int usbd_ep_close(uint8_t busid, const uint8_t ep)
/* Clear and unmask endpoint disabled interrupt */
USB_OTG_OUTEP(ep_idx)->DOEPINT = USB_OTG_DOEPINT_EPDISD;
+
+ USB_OTG_DEV->DCTL |= USB_OTG_DCTL_CGONAK;
}
USB_OTG_DEV->DEACHMSK &= ~(USB_OTG_DAINTMSK_OEPM & ((uint32_t)(1UL << (ep_idx & 0x07)) << 16));
@@ -1004,8 +1023,6 @@ int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t
pktcnt = 0x3FF; // pktcnt 10bits
}
- data_len = pktcnt * g_dwc2_udc[busid].out_ep[ep_idx].ep_mps;
-
USB_OTG_OUTEP(ep_idx)->DOEPTSIZ |= (USB_OTG_DOEPTSIZ_PKTCNT & (pktcnt << 19));
USB_OTG_OUTEP(ep_idx)->DOEPTSIZ |= (USB_OTG_DOEPTSIZ_XFRSIZ & data_len);
}
@@ -1159,25 +1176,12 @@ process_setup:
dwc2_flush_rxfifo(busid);
for (uint8_t i = 0U; i < (g_dwc2_udc[busid].hw_params.num_dev_ep + 1); i++) {
- if (i == 0U) {
- USB_OTG_INEP(i)->DIEPCTL = USB_OTG_DIEPCTL_SNAK;
- USB_OTG_OUTEP(i)->DOEPCTL = USB_OTG_DOEPCTL_SNAK;
- } else {
- if (USB_OTG_INEP(i)->DIEPCTL & USB_OTG_DIEPCTL_EPENA) {
- USB_OTG_INEP(i)->DIEPCTL = (USB_OTG_DIEPCTL_EPDIS | USB_OTG_DIEPCTL_SNAK);
- } else {
- USB_OTG_INEP(i)->DIEPCTL = 0;
- }
- if (USB_OTG_OUTEP(i)->DOEPCTL & USB_OTG_DOEPCTL_EPENA) {
- USB_OTG_OUTEP(i)->DOEPCTL = (USB_OTG_DOEPCTL_EPDIS | USB_OTG_DOEPCTL_SNAK);
- } else {
- USB_OTG_OUTEP(i)->DOEPCTL = 0;
- }
- }
+ USB_OTG_INEP(i)->DIEPCTL = 0;
+ USB_OTG_OUTEP(i)->DOEPCTL = USB_OTG_DOEPCTL_SNAK;
+ USB_OTG_INEP(i)->DIEPINT = 0xFB7FU;
+ USB_OTG_OUTEP(i)->DOEPINT = 0xFB7FU;
USB_OTG_INEP(i)->DIEPTSIZ = 0U;
- USB_OTG_INEP(i)->DIEPINT = 0xFBFFU;
USB_OTG_OUTEP(i)->DOEPTSIZ = 0U;
- USB_OTG_OUTEP(i)->DOEPINT = 0xFBFFU;
}
USB_OTG_DEV->DAINTMSK |= 0x10001U;
diff --git a/port/dwc2/usb_dwc2_param.h b/port/dwc2/usb_dwc2_param.h
index 74e436c2..24d523ab 100644
--- a/port/dwc2/usb_dwc2_param.h
+++ b/port/dwc2/usb_dwc2_param.h
@@ -295,13 +295,22 @@ static inline void dwc2_get_hwparams(uint32_t reg_base, struct dwc2_hw_params *h
unsigned int width;
uint32_t snpsid, hwcfg1, hwcfg2, hwcfg3, hwcfg4;
+#if defined(CONFIG_USB_DWC2_GD)
+ extern void dwc2_get_gd_reg(uint32_t reg_base,
+ uint32_t *snpsid,
+ uint32_t *hwcfg1,
+ uint32_t *hwcfg2,
+ uint32_t *hwcfg3,
+ uint32_t *hwcfg4);
+ dwc2_get_gd_reg(reg_base, &snpsid, &hwcfg1, &hwcfg2, &hwcfg3, &hwcfg4);
+#else
snpsid = dwc2_readl(reg_base + GSNPSID_OFFSET);
hwcfg1 = dwc2_readl(reg_base + GHWCFG1_OFFSET);
hwcfg2 = dwc2_readl(reg_base + GHWCFG2_OFFSET);
hwcfg3 = dwc2_readl(reg_base + GHWCFG3_OFFSET);
hwcfg4 = dwc2_readl(reg_base + GHWCFG4_OFFSET);
-
+#endif
/* snpsid */
hw->snpsid = snpsid;
diff --git a/port/dwc2/usb_dwc2_reg.h b/port/dwc2/usb_dwc2_reg.h
index 69b09600..851ad94d 100644
--- a/port/dwc2/usb_dwc2_reg.h
+++ b/port/dwc2/usb_dwc2_reg.h
@@ -1730,9 +1730,4 @@ typedef struct
#define USB_UNMASK_HALT_HC_INT(chnum) (USB_OTG_HC(chnum)->HCINTMSK |= USB_OTG_HCINTMSK_CHHM)
#define CLEAR_HC_INT(chnum, __INTERRUPT__) (USB_OTG_HC(chnum)->HCINT = (__INTERRUPT__))
-void usb_dc_low_level_init(uint8_t busid);
-void usb_dc_low_level_deinit(uint8_t busid);
-void usbd_dwc2_delay_ms(uint8_t ms);
-uint32_t usbd_dwc2_get_system_clock(void);
-
#endif
diff --git a/port/dwc2/usb_glue_gd.c b/port/dwc2/usb_glue_gd.c
index 1a236862..a702515c 100644
--- a/port/dwc2/usb_glue_gd.c
+++ b/port/dwc2/usb_glue_gd.c
@@ -3,41 +3,65 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
-#include "usb_config.h"
-#include "stdint.h"
-#include "usb_dwc2_reg.h"
+#include "usbd_core.h"
+#include "usbh_core.h"
+#include "usb_dwc2_param.h"
-#if 1
-#error you need to modify some usb register values then use this chip
+#if !defined(CONFIG_USB_DWC2_GD)
+#error must define CONFIG_USB_DWC2_GD when use GD32 chips
#endif
-#if CONFIG_USBDEV_EP_NUM != 4 && CONFIG_USBDEV_EP_NUM != 6
-#error "gd32 only has 4 endpoints for pa11/pa12 and 6 endpoints for pb14/pb15"
-#endif
+// TODO: Implement this function to read the GD32-specific USB controller registers.
+void dwc2_get_gd_reg(uint32_t reg_base,
+ uint32_t *snpsid,
+ uint32_t *hwcfg1,
+ uint32_t *hwcfg2,
+ uint32_t *hwcfg3,
+ uint32_t *hwcfg4)
+{
+}
-/* you can find this config in function:usb_core_init, file:drv_usb_core.c, for example:
- *
- * usb_regs->gr->GCCFG |= GCCFG_PWRON | GCCFG_VBUSACEN | GCCFG_VBUSBCEN;
- *
-*/
+// TODO
+void usb_dc_low_level_init(uint8_t busid)
+{
+}
-uint32_t usbd_get_dwc2_gccfg_conf(uint32_t reg_base)
+// TODO
+void usb_dc_low_level_deinit(uint8_t busid)
{
-#ifdef CONFIG_USB_HS
- return 0;
-#else
- return ((1 << 16) | (1 << 18) | (1 << 19) | (1 << 21));
-#endif
}
-uint32_t usbh_get_dwc2_gccfg_conf(uint32_t reg_base)
+// TODO
+void usb_hc_low_level_init(struct usbh_bus *bus)
{
-#ifdef CONFIG_USB_HS
- return 0;
-#else
- return ((1 << 16) | (1 << 18) | (1 << 19) | (1 << 21));
+}
+
+// TODO
+void usb_hc_low_level_deinit(struct usbh_bus *bus)
+{
+}
+
+// TODO
+#ifndef CONFIG_USB_DWC2_CUSTOM_PARAM
+void dwc2_get_user_params(uint32_t reg_base, struct dwc2_user_params *params)
+{
+ // if (reg_base == 0x40040000UL) { // USB_OTG_HS_PERIPH_BASE
+ // memcpy(params, &param_pb14_pb15, sizeof(struct dwc2_user_params));
+ // } else {
+ // memcpy(params, &param_pa11_pa12, sizeof(struct dwc2_user_params));
+ // }
+#ifdef CONFIG_USB_DWC2_CUSTOM_FIFO
+ struct usb_dwc2_user_fifo_config s_dwc2_fifo_config;
+
+ dwc2_get_user_fifo_config(reg_base, &s_dwc2_fifo_config);
+
+ params->device_rx_fifo_size = s_dwc2_fifo_config.device_rx_fifo_size;
+ for (uint8_t i = 0; i < MAX_EPS_CHANNELS; i++) {
+ params->device_tx_fifo_size[i] = s_dwc2_fifo_config.device_tx_fifo_size[i];
+ }
#endif
}
+#endif
extern uint32_t SystemCoreClock;
@@ -48,3 +72,25 @@ void usbd_dwc2_delay_ms(uint8_t ms)
__asm volatile("nop");
}
}
+
+uint32_t usbd_dwc2_get_system_clock(void)
+{
+ return SystemCoreClock;
+}
+
+#ifdef CONFIG_USB_DCACHE_ENABLE
+void usb_dcache_clean(uintptr_t addr, size_t size)
+{
+ SCB_CleanDCache_by_Addr((void *)addr, size);
+}
+
+void usb_dcache_invalidate(uintptr_t addr, size_t size)
+{
+ SCB_InvalidateDCache_by_Addr((void *)addr, size);
+}
+
+void usb_dcache_flush(uintptr_t addr, size_t size)
+{
+ SCB_CleanInvalidateDCache_by_Addr((void *)addr, size);
+}
+#endif \ No newline at end of file
diff --git a/port/dwc2/usb_hc_dwc2.c b/port/dwc2/usb_hc_dwc2.c
index 11616c76..1490f394 100644
--- a/port/dwc2/usb_hc_dwc2.c
+++ b/port/dwc2/usb_hc_dwc2.c
@@ -658,15 +658,8 @@ static void dwc2_iso_urb_init(struct usbh_bus *bus, uint8_t chidx, struct usbh_u
}
#endif
-__WEAK void usb_hc_low_level_init(struct usbh_bus *bus)
-{
- (void)bus;
-}
-
-__WEAK void usb_hc_low_level_deinit(struct usbh_bus *bus)
-{
- (void)bus;
-}
+extern void usb_hc_low_level_init(struct usbh_bus *bus);
+extern void usb_hc_low_level_deinit(struct usbh_bus *bus);
int usb_hc_init(struct usbh_bus *bus)
{
@@ -696,6 +689,7 @@ int usb_hc_init(struct usbh_bus *bus)
for (uint8_t chidx = 0; chidx < g_dwc2_hcd[bus->hcd.hcd_id].hw_params.host_channels; chidx++) {
g_dwc2_hcd[bus->hcd.hcd_id].chan_pool[chidx].waitsem = usb_osal_sem_create(0);
+ USB_ASSERT(g_dwc2_hcd[bus->hcd.hcd_id].chan_pool[chidx].waitsem != NULL);
}
USB_LOG_INFO("dwc2 has %d channels and dfifo depth(32-bit words) is %d\r\n",
@@ -1042,21 +1036,14 @@ int usbh_submit_urb(struct usbh_urb *urb)
if (urb->setup) {
usb_dcache_clean((uintptr_t)urb->setup, USB_ALIGN_UP(sizeof(struct usb_setup_packet), CONFIG_USB_ALIGN_SIZE));
+ }
- if (urb->transfer_buffer) {
- if (urb->setup->bmRequestType & 0x80) {
- usb_dcache_invalidate((uintptr_t)urb->transfer_buffer, USB_ALIGN_UP(urb->transfer_buffer_length, CONFIG_USB_ALIGN_SIZE));
- } else {
- usb_dcache_clean((uintptr_t)urb->transfer_buffer, USB_ALIGN_UP(urb->transfer_buffer_length, CONFIG_USB_ALIGN_SIZE));
- }
- }
- } else if (urb->transfer_buffer && (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) != USB_ENDPOINT_TYPE_ISOCHRONOUS)) {
- if (urb->ep->bEndpointAddress & 0x80) {
+ if (urb->transfer_buffer) {
+ if ((urb->setup && urb->setup->bmRequestType & 0x80) || (urb->ep->bEndpointAddress & 0x80)) {
usb_dcache_invalidate((uintptr_t)urb->transfer_buffer, USB_ALIGN_UP(urb->transfer_buffer_length, CONFIG_USB_ALIGN_SIZE));
} else {
usb_dcache_clean((uintptr_t)urb->transfer_buffer, USB_ALIGN_UP(urb->transfer_buffer_length, CONFIG_USB_ALIGN_SIZE));
}
- } else {
}
switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
@@ -1107,10 +1094,15 @@ int usbh_kill_urb(struct usbh_urb *urb)
flags = usb_osal_enter_critical_section();
chan = (struct dwc2_chan *)urb->hcpriv;
+ if (!chan) {
+ usb_osal_leave_critical_section(flags);
+ return -USB_ERR_INVAL;
+ }
dwc2_halt(bus, chan->chidx);
urb->errorcode = -USB_ERR_SHUTDOWN;
+ usb_osal_leave_critical_section(flags);
if (urb->timeout) {
usb_osal_sem_give(chan->waitsem);
@@ -1122,8 +1114,6 @@ int usbh_kill_urb(struct usbh_urb *urb)
urb->complete(urb->arg, urb->errorcode);
}
- usb_osal_leave_critical_section(flags);
-
return 0;
}
diff --git a/port/ehci/README.md b/port/ehci/README.md
index 753fc446..e1bd5a3a 100644
--- a/port/ehci/README.md
+++ b/port/ehci/README.md
@@ -4,15 +4,15 @@
### BouffaloLab
-- BouffaloLab BL616/BL808 (bouffalolab + EHCI)
+- BouffaloLab BL616/BL808 (fotg210 + EHCI)
### HPMicro
-- HPM all series (hpmicro + EHCI)
+- HPM all series (chipidea + EHCI)
### AllwinnerTech
-- F133/T113
+- Except F1Cxxx, F2Cxxx (musb + EHCI+ OHCI)
### Nuvoton
@@ -20,7 +20,7 @@
### Artinchip
-- d13x, d21x
+- ALL series (aic + EHCI + OHCI)
### NXP
diff --git a/port/ehci/usb_glue_intel.c b/port/ehci/usb_glue_intel.c
deleted file mode 100644
index 74ed3786..00000000
--- a/port/ehci/usb_glue_intel.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifdef __rtems__
-
-#include <rtems.h>
-#include <rtems/pci.h>
-#include <bsp/irq.h>
-#include "usbh_core.h"
-
-uint32_t echi_base;
-static int ehci_bus;
-static int ehci_slot;
-static int ehci_function;
-static int ehci_vector;
-
-extern void USBH_IRQHandler(uint8_t busid);
-
-void ehci_pci_scan(int bus, int slot, int fun, int vector)
-{
- ehci_bus = bus;
- ehci_slot = slot;
- ehci_function = fun;
- ehci_vector = vector;
- pci_read_config_dword(bus, slot, fun, PCI_BASE_ADDRESS_0, &echi_base);
-}
-void usb_hc_low_level_init(struct usbh_bus *bus)
-{
- //set software own ehci
- uint32_t legacy_val;
- pci_write_config_dword(ehci_bus, ehci_slot, ehci_function, 0x68, 1 << 24);
- pci_read_config_dword(ehci_bus, ehci_slot, ehci_function, 0x68, &legacy_val);
- if ((legacy_val & 0x01010000) == 0x01000000)
- printf("OS owned echi\n");
- else
- printf("BIOS owned echi\n");
-
- rtems_status_code sc;
- sc = rtems_interrupt_handler_install(
- ehci_vector,
- "USBirq",
- RTEMS_INTERRUPT_SHARED,
- USBH_IRQHandler,
- (void *)0);
-
- if (sc != RTEMS_SUCCESSFUL) {
- printf("USB install isr falied,%s\n", rtems_status_text(sc));
- return;
- }
-}
-
-uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
-{
- printf("USB_SPEED_HIGH present\n");
- return USB_SPEED_HIGH;
-}
-
-#endif \ No newline at end of file
diff --git a/port/ehci/usb_glue_ma35d0.c b/port/ehci/usb_glue_ma35d0.c
deleted file mode 100644
index 3e03bbd8..00000000
--- a/port/ehci/usb_glue_ma35d0.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/**************************************************************************/ /**
-*
-* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
-*
-* SPDX-License-Identifier: Apache-2.0
-*
-* Change Logs:
-* Date Author Notes
-* 2023-8-8 Wayne First version
-*
-******************************************************************************/
-#include "rtthread.h"
-
-#include "NuMicro.h"
-#include "rthw.h"
-#include "drv_sys.h"
-
-#define LOG_TAG "drv.cherry"
-#define DBG_ENABLE
-#define DBG_SECTION_NAME LOG_TAG
-#define DBG_LEVEL DBG_LOG
-#define DBG_COLOR
-#include <rtdbg.h>
-
-#if defined(PKG_CHERRYUSB_HOST)
-
-#include "usbh_core.h"
-
-static void nu_echi_isr(int vector, void *param)
-{
- uint8_t busid = (uint8_t)param;
- extern void USBH_IRQHandler(uint8_t busid);
- USBH_IRQHandler(busid);
-}
-
-static void nu_ochi_isr(int vector, void *param)
-{
-}
-
-void usb_hc_low_level_init(struct usbh_bus *bus)
-{
- int timeout = 100;
-
- if (bus->hcd.reg_base == HSUSBH0_BASE) {
- /* Enable USBH clock */
- CLK_EnableModuleClock(HUSBH0_MODULE);
- SYS_ResetModule(HSUSBH0_RST);
-
- /* Clock engine clock Configuration */
- SYS->USBPMISCR &= ~(SYS_USBPMISCR_PHY0POR_Msk | SYS_USBPMISCR_PHY0COMN_Msk);
- rt_thread_mdelay(20);
- SYS->USBPMISCR |= SYS_USBPMISCR_PHY0SUSPEND_Msk | SYS_USBPMISCR_PHY0COMN_Msk;
-
- /* set UHOVRCURH(SYS_MISCFCR0[12]) 1 => USBH Host over-current detect is high-active */
- /* 0 => USBH Host over-current detect is low-active */
- //SYS->MISCFCR0 |= SYS_MISCFCR0_UHOVRCURH_Msk;
- SYS->MISCFCR0 &= ~SYS_MISCFCR0_UHOVRCURH_Msk;
- while (1) {
- rt_thread_mdelay(1);
- if (SYS->USBPMISCR & SYS_USBPMISCR_PHY0HSTCKSTB_Msk)
- break; /* both USB PHY0 and PHY1 clock 60MHz UTMI clock stable */
-
- timeout--;
- if (timeout == 0) {
- rt_kprintf("USB PHY reset failed. USBPMISCR = 0x%08x\n", SYS->USBPMISCR);
- return;
- }
- }
-
- /* Register interrupt service routine. */
- rt_hw_interrupt_install(HSUSBH0_IRQn, nu_echi_isr, (void *)bus->hcd.hcd_id, "ehci0");
-
- /* Enable interrupt */
- rt_hw_interrupt_umask(HSUSBH0_IRQn);
- } else if (bus->hcd.reg_base == HSUSBH1_BASE) {
- /* Enable USBH clock */
- CLK_EnableModuleClock(HUSBH1_MODULE);
- SYS_ResetModule(HSUSBH1_RST);
-
- /* Clock engine clock Configuration */
- SYS->USBPMISCR &= ~(SYS_USBPMISCR_PHY1POR_Msk | SYS_USBPMISCR_PHY1COMN_Msk);
- rt_thread_mdelay(20);
- SYS->USBPMISCR |= SYS_USBPMISCR_PHY1SUSPEND_Msk | SYS_USBPMISCR_PHY1COMN_Msk;
-
- /* set UHOVRCURH(SYS_MISCFCR0[12]) 1 => USBH Host over-current detect is high-active */
- /* 0 => USBH Host over-current detect is low-active */
- //SYS->MISCFCR0 |= SYS_MISCFCR0_UHOVRCURH_Msk;
- SYS->MISCFCR0 &= ~SYS_MISCFCR0_UHOVRCURH_Msk;
- while (1) {
- rt_thread_mdelay(1);
- if (SYS->USBPMISCR & SYS_USBPMISCR_PHY1HSTCKSTB_Msk)
- break; /* both USB PHY0 and PHY1 clock 60MHz UTMI clock stable */
-
- timeout--;
- if (timeout == 0) {
- rt_kprintf("USB PHY reset failed. USBPMISCR = 0x%08x\n", SYS->USBPMISCR);
- return;
- }
- }
- /* Register interrupt service routine. */
- rt_hw_interrupt_install(HSUSBH1_IRQn, nu_echi_isr, (void *)bus->hcd.hcd_id, "ehci1");
-
- /* Enable interrupt */
- rt_hw_interrupt_umask(HSUSBH1_IRQn);
- }
-}
-
-void usb_hc_low_level2_init(struct usbh_bus *bus)
-{
-}
-
-uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
-{
- return USB_SPEED_HIGH;
-}
-
-#endif
diff --git a/port/ehci/usb_glue_nuc980.c b/port/ehci/usb_glue_nuc980.c
deleted file mode 100644
index 4b8a8b33..00000000
--- a/port/ehci/usb_glue_nuc980.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/**************************************************************************/ /**
-*
-* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
-*
-* SPDX-License-Identifier: Apache-2.0
-*
-* Change Logs:
-* Date Author Notes
-* 2023-8-8 Wayne First version
-*
-******************************************************************************/
-#include "rtthread.h"
-
-#include "NuMicro.h"
-#include "rthw.h"
-#include "drv_sys.h"
-
-#define LOG_TAG "drv.cherry"
-#define DBG_ENABLE
-#define DBG_SECTION_NAME LOG_TAG
-#define DBG_LEVEL DBG_LOG
-#define DBG_COLOR
-#include <rtdbg.h>
-
-#if defined(PKG_CHERRYUSB_HOST)
-#include "usbh_core.h"
-
-static void nu_ehci_isr(int vector, void *param)
-{
- extern void USBH_IRQHandler(uint8_t busid);
- USBH_IRQHandler(0);
-}
-
-void usb_hc_low_level_init(struct usbh_bus *bus)
-{
- LOG_D("%s %d", __FUNCTION__, __LINE__);
-
- rt_hw_interrupt_mask(IRQ_EHCI);
-
- /* Enable USBH clock */
- nu_sys_ipclk_enable(USBHCKEN);
- nu_sys_ip_reset(USBHRST);
-
- outpw(0xB0015000 + 0xC4, 0x160); //HSUSBH->USBPCR0 = 0x160; /* enable PHY 0 */
- outpw(0xB0015000 + 0xC8, 0x520); //HSUSBH->USBPCR1 = 0x520; /* enable PHY 1 */
-
- //USBH->HcMiscControl |= USBH_HcMiscControl_OCAL_Msk; /* Over-current active low */
- //outpw(0xB0017000 + 0x204, inpw(0xB0017000 + 0x204) | (0x1ul << 3));
-
- //USBH->HcMiscControl &= ~USBH_HcMiscControl_OCAL_Msk; /* Over-current active high */
- outpw(0xB0017000 + 0x204, inpw(0xB0017000 + 0x204) & (~(0x1ul << 3)));
-
- rt_hw_interrupt_install(IRQ_EHCI, nu_ehci_isr, NULL, "ehci-1");
- rt_hw_interrupt_set_priority(IRQ_EHCI, IRQ_LEVEL_1);
- rt_hw_interrupt_umask(IRQ_EHCI);
-}
-
-uint8_t usbh_get_port_speed(struct usbh_bus *bus, const uint8_t port)
-{
- return USB_SPEED_HIGH;
-}
-#endif \ No newline at end of file
diff --git a/port/ehci/usb_hc_ehci.c b/port/ehci/usb_hc_ehci.c
index fd72907f..eaef8aad 100644
--- a/port/ehci/usb_hc_ehci.c
+++ b/port/ehci/usb_hc_ehci.c
@@ -8,6 +8,18 @@
#include "usb_hc_ohci.h"
#endif
+#if defined(CONFIG_USBHOST_MULT_HC)
+#define usb_hc_init usbh_ehci_hc_init
+#define usb_hc_deinit usbh_ehci_hc_deinit
+#define usbh_get_frame_number usbh_ehci_get_frame_number
+#define usbh_roothub_control usbh_ehci_roothub_control
+#define usbh_submit_urb usbh_ehci_submit_urb
+#define usbh_kill_urb usbh_ehci_kill_urb
+#define USBH_IRQHandler usbh_ehci_irq_handler
+
+int usbh_ehci_kill_urb(struct usbh_urb *urb);
+#endif
+
#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
#define EHCI_TUNE_RL_TT 0
@@ -137,8 +149,6 @@ static inline void ehci_qh_add_head(struct ehci_qh_hw *head, struct ehci_qh_hw *
n->hw.hlp = head->hw.hlp;
usb_ehci_qh_qtd_flush(n);
- usb_dcache_flush((uintptr_t)n->urb->transfer_buffer, USB_ALIGN_UP(n->urb->transfer_buffer_length, CONFIG_USB_ALIGN_SIZE));
-
head->hw.hlp = QH_HLP_QH(n);
#if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE)
usb_dcache_clean((uintptr_t)&head->hw, CONFIG_USB_EHCI_ALIGN_SIZE);
@@ -154,6 +164,9 @@ static inline void ehci_qh_remove(struct ehci_qh_hw *head, struct ehci_qh_hw *n)
}
if (tmp) {
+#if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE)
+ usb_dcache_invalidate((uintptr_t)&n->hw, CONFIG_USB_EHCI_ALIGN_SIZE);
+#endif
tmp->hw.hlp = n->hw.hlp;
#if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE)
usb_dcache_clean((uintptr_t)&tmp->hw, CONFIG_USB_EHCI_ALIGN_SIZE);
@@ -623,6 +636,30 @@ static void ehci_urb_waitup(struct usbh_bus *bus, struct usbh_urb *urb)
qh->remove_in_iaad = 0;
+ if (qh->killed == 1U) {
+ qh->killed = 2U;
+ return;
+ }
+
+#ifdef CONFIG_USB_DCACHE_ENABLE
+ if (urb->transfer_buffer &&
+ ((urb->setup && urb->setup->bmRequestType & 0x80) || (urb->ep->bEndpointAddress & 0x80)) &&
+ urb->errorcode == 0) {
+ switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
+ case USB_ENDPOINT_TYPE_CONTROL:
+ usb_dcache_invalidate((uintptr_t)urb->transfer_buffer, USB_ALIGN_UP(urb->actual_length - 8, CONFIG_USB_ALIGN_SIZE));
+ break;
+ case USB_ENDPOINT_TYPE_BULK:
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ usb_dcache_invalidate((uintptr_t)urb->transfer_buffer, USB_ALIGN_UP(urb->actual_length, CONFIG_USB_ALIGN_SIZE));
+ break;
+
+ default:
+ break;
+ }
+ }
+#endif
+
if (urb->timeout) {
usb_osal_sem_give(qh->waitsem);
} else {
@@ -751,21 +788,14 @@ static int usbh_reset_port(struct usbh_bus *bus, const uint8_t port)
return 0;
}
-__WEAK void usb_hc_low_level_init(struct usbh_bus *bus)
-{
- (void)bus;
-}
+extern void usb_hc_low_level_init(struct usbh_bus *bus);
+extern void usb_hc_low_level_deinit(struct usbh_bus *bus);
__WEAK void usb_hc_low_level2_init(struct usbh_bus *bus)
{
(void)bus;
}
-__WEAK void usb_hc_low_level_deinit(struct usbh_bus *bus)
-{
- (void)bus;
-}
-
int usb_hc_init(struct usbh_bus *bus)
{
struct ehci_qh_hw *qh;
@@ -799,6 +829,7 @@ int usb_hc_init(struct usbh_bus *bus)
for (uint8_t index = 0; index < CONFIG_USB_EHCI_QH_NUM; index++) {
qh = &ehci_qh_pool[bus->hcd.hcd_id][index];
qh->waitsem = usb_osal_sem_create(0);
+ USB_ASSERT(qh->waitsem != NULL);
}
memset(&g_async_qh_head[bus->hcd.hcd_id], 0, sizeof(struct ehci_qh_hw));
@@ -1241,6 +1272,18 @@ int usbh_submit_urb(struct usbh_urb *urb)
usb_osal_leave_critical_section(flags);
+ if (urb->setup) {
+ usb_dcache_clean((uintptr_t)urb->setup, USB_ALIGN_UP(sizeof(struct usb_setup_packet), CONFIG_USB_ALIGN_SIZE));
+ }
+
+ if (urb->transfer_buffer) {
+ if ((urb->setup && urb->setup->bmRequestType & 0x80) || (urb->ep->bEndpointAddress & 0x80)) {
+ usb_dcache_invalidate((uintptr_t)urb->transfer_buffer, USB_ALIGN_UP(urb->transfer_buffer_length, CONFIG_USB_ALIGN_SIZE));
+ } else {
+ usb_dcache_clean((uintptr_t)urb->transfer_buffer, USB_ALIGN_UP(urb->transfer_buffer_length, CONFIG_USB_ALIGN_SIZE));
+ }
+ }
+
switch (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes)) {
case USB_ENDPOINT_TYPE_CONTROL:
qh = ehci_control_urb_init(bus, urb, urb->setup, urb->transfer_buffer, urb->transfer_buffer_length);
@@ -1307,10 +1350,17 @@ int usbh_kill_urb(struct usbh_urb *urb)
#endif
flags = usb_osal_enter_critical_section();
+ if (!urb->hcpriv) {
+ usb_osal_leave_critical_section(flags);
+ return -USB_ERR_INVAL;
+ }
EHCI_HCOR->usbcmd &= ~(EHCI_USBCMD_PSEN | EHCI_USBCMD_ASEN);
if ((USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_CONTROL) || (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_BULK)) {
+#if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE)
+ usb_dcache_invalidate((uintptr_t)&g_async_qh_head[bus->hcd.hcd_id].hw, CONFIG_USB_EHCI_ALIGN_SIZE);
+#endif
qh = EHCI_ADDR2QH(g_async_qh_head[bus->hcd.hcd_id].hw.hlp);
while ((qh != &g_async_qh_head[bus->hcd.hcd_id]) && qh) {
if (qh->urb == urb) {
@@ -1320,6 +1370,9 @@ int usbh_kill_urb(struct usbh_urb *urb)
qh = EHCI_ADDR2QH(qh->hw.hlp);
}
} else if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
+#if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE)
+ usb_dcache_invalidate((uintptr_t)&g_periodic_qh_head[bus->hcd.hcd_id].hw, CONFIG_USB_EHCI_ALIGN_SIZE);
+#endif
qh = EHCI_ADDR2QH(g_periodic_qh_head[bus->hcd.hcd_id].hw.hlp);
while (qh) {
if (qh->urb == urb) {
@@ -1339,36 +1392,38 @@ int usbh_kill_urb(struct usbh_urb *urb)
EHCI_HCOR->usbcmd |= (EHCI_USBCMD_PSEN | EHCI_USBCMD_ASEN);
qh = (struct ehci_qh_hw *)urb->hcpriv;
- qh->remove_in_iaad = 0;
urb->errorcode = -USB_ERR_SHUTDOWN;
- if (urb->timeout) {
- usb_osal_sem_give(qh->waitsem);
- } else {
- ehci_qh_free(bus, qh);
- }
-
if (remove_in_iaad) {
- volatile uint32_t timeout = 0;
- EHCI_HCOR->usbsts = EHCI_USBSTS_IAA;
+ qh->killed = 1U; /* trigger iaad isr and wait isr done */
+ qh->remove_in_iaad = 1;
EHCI_HCOR->usbcmd |= EHCI_USBCMD_IAAD;
- while (!(EHCI_HCOR->usbsts & EHCI_USBSTS_IAA)) {
+ usb_osal_leave_critical_section(flags);
+
+ volatile uint32_t timeout = 0;
+ while (qh->killed != 2) {
timeout++;
- if (timeout > 200000) {
- USB_LOG_ERR("iaad timeout\r\n");
- usb_osal_leave_critical_section(flags);
+ if (timeout > 200000U) {
+ qh->remove_in_iaad = 0;
+ qh->killed = 0;
return -USB_ERR_TIMEOUT;
}
}
- EHCI_HCOR->usbsts = EHCI_USBSTS_IAA;
+ qh->killed = 0;
+ } else {
+ usb_osal_leave_critical_section(flags);
+ }
+
+ if (urb->timeout) {
+ usb_osal_sem_give(qh->waitsem);
+ } else {
+ ehci_qh_free(bus, qh);
}
if (urb->complete) {
urb->complete(urb->arg, urb->errorcode);
}
- usb_osal_leave_critical_section(flags);
-
return 0;
}
@@ -1376,6 +1431,9 @@ static void ehci_scan_async_list(struct usbh_bus *bus)
{
struct ehci_qh_hw *qh;
+#if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE)
+ usb_dcache_invalidate((uintptr_t)&g_async_qh_head[bus->hcd.hcd_id].hw, CONFIG_USB_EHCI_ALIGN_SIZE);
+#endif
qh = EHCI_ADDR2QH(g_async_qh_head[bus->hcd.hcd_id].hw.hlp);
while ((qh != &g_async_qh_head[bus->hcd.hcd_id]) && qh) {
if (qh->urb) {
@@ -1389,6 +1447,9 @@ static void ehci_scan_periodic_list(struct usbh_bus *bus)
{
struct ehci_qh_hw *qh;
+#if defined(CONFIG_USB_EHCI_DESC_DCACHE_ENABLE)
+ usb_dcache_invalidate((uintptr_t)&g_periodic_qh_head[bus->hcd.hcd_id].hw, CONFIG_USB_EHCI_ALIGN_SIZE);
+#endif
qh = EHCI_ADDR2QH(g_periodic_qh_head[bus->hcd.hcd_id].hw.hlp);
while (qh) {
if (qh->urb) {
@@ -1454,4 +1515,18 @@ void USBH_IRQHandler(uint8_t busid)
if (usbsts & EHCI_USBSTS_FATAL) {
}
-} \ No newline at end of file
+}
+
+#if defined(CONFIG_USBHOST_MULT_HC)
+struct usbh_hc_driver ehci_hc_driver = {
+ .driver_name = "ehci_hcd",
+ .driver_desc = "EHCI Host Controller",
+ .init = usb_hc_init,
+ .deinit = usb_hc_deinit,
+ .get_frame_number = usbh_get_frame_number,
+ .roothub_control = usbh_roothub_control,
+ .submit_urb = usbh_submit_urb,
+ .kill_urb = usbh_kill_urb,
+ .irq_handler = USBH_IRQHandler,
+};
+#endif
diff --git a/port/ehci/usb_hc_ehci.h b/port/ehci/usb_hc_ehci.h
index 3d4cb8cd..8e040489 100644
--- a/port/ehci/usb_hc_ehci.h
+++ b/port/ehci/usb_hc_ehci.h
@@ -64,6 +64,7 @@ struct ehci_qh_hw {
struct usbh_urb *urb;
usb_osal_sem_t waitsem;
uint8_t remove_in_iaad;
+ volatile uint8_t killed; /* only used in usbh_kill_urb */
} __attribute__((aligned(CONFIG_USB_EHCI_ALIGN_SIZE)));
struct ehci_itd_hw {
diff --git a/port/fsdev/README.md b/port/fsdev/README.md
index 95e9ac2e..f7a876f8 100644
--- a/port/fsdev/README.md
+++ b/port/fsdev/README.md
@@ -28,3 +28,11 @@
## CH32
- CH32F10x、CH32V10x
+
+## N32
+
+- N32H473、N32H474、N32H475、N32H481、N32H482、N32H480、N32H487、N32H488
+
+- N32H49X
+
+
diff --git a/port/fsdev/usb_dc_fsdev.c b/port/fsdev/usb_dc_fsdev.c
index 3e1fa22b..a4a2445a 100644
--- a/port/fsdev/usb_dc_fsdev.c
+++ b/port/fsdev/usb_dc_fsdev.c
@@ -52,18 +52,33 @@ struct fsdev_udc {
struct fsdev_ep_state out_ep[CONFIG_USBDEV_EP_NUM]; /*!< OUT endpoint parameters */
} g_fsdev_udc;
-__WEAK void usb_dc_low_level_init(void)
-{
-}
-
-__WEAK void usb_dc_low_level_deinit(void)
-{
-}
+extern void usb_dc_low_level_init(uint8_t busid);
+extern void usb_dc_low_level_deinit(uint8_t busid);
+/**
+ * @brief Initialize the USB device controller.
+ * @param busid USB bus index (fsdev supports a single instance, bus 0).
+ * @retval 0 on success.
+ */
int usb_dc_init(uint8_t busid)
{
- usb_dc_low_level_init();
+ usb_dc_low_level_init(busid);
+
+#if defined(N32H4X_FSDEV)
+ /* N32H4x power-on sequence: the USB_CTRL reset value is 0x0300
+ * -- PD(bit9, power-down) and FRST(bit8, force-reset) are both set.
+ * 1. Clear PD, wait for the internal analog voltage reference to settle.
+ * 2. Clear FRST.
+ * 3. Clear the STS register to drop pending interrupts. */
+ USB->CNTR &= (uint32_t)~USB_CNTR_PDWN; /* exit power-down */
+ /* Wait for the internal reference voltage to stabilise. */
+ for (volatile uint32_t i = 0U; i < 1000U; i++) {
+ }
+
+ USB->CNTR &= (uint32_t)~USB_CNTR_FRES; /* clear force-reset flag */
+ USB->ISTR = 0U; /* clear pending interrupts */
+#else
/* Init Device */
/* CNTR_FRES = 1 */
USB->CNTR = (uint16_t)USB_CNTR_FRES;
@@ -73,6 +88,7 @@ int usb_dc_init(uint8_t busid)
/* Clear pending interrupts */
USB->ISTR = 0U;
+#endif
/*Set Btable Address*/
USB->BTABLE = BTABLE_ADDRESS;
@@ -91,8 +107,13 @@ int usb_dc_init(uint8_t busid)
/* Set interrupt mask */
USB->CNTR = (uint16_t)winterruptmask;
+#if defined(N32H4X_FSDEV)
+ /* Enabling DP Pull-UP through USB_CTRL.PU */
+ USB->CNTR |= (uint32_t)USB_CNTR_PU;
+#else
/* Enabling DP Pull-UP bit to Connect internal PU resistor on USB DP line */
USB->BCDR |= (uint16_t)USB_BCDR_DPPU;
+#endif
return 0;
}
@@ -107,8 +128,8 @@ int usb_dc_deinit(uint8_t busid)
/* switch-off device */
USB->CNTR = (uint16_t)(USB_CNTR_FRES | USB_CNTR_PDWN);
+ usb_dc_low_level_deinit(busid);
- usb_dc_low_level_deinit();
return 0;
}
@@ -325,6 +346,10 @@ int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t
return 0;
}
+/**
+ * @brief USB FS device interrupt handler: dispatches ISTR events.
+ * @param busid USB bus index (fsdev supports a single instance, bus 0).
+ */
void USBD_IRQHandler(uint8_t busid)
{
uint16_t wIstr, wEPVal;
@@ -339,7 +364,13 @@ void USBD_IRQHandler(uint8_t busid)
wIstr = USB->ISTR;
/* extract highest priority endpoint number */
+#if defined(N32H4X_FSDEV)
+ /* EP_ID is at STS bits [11:8] */
+ ep_idx = (uint8_t)((wIstr & USB_ISTR_EP_ID) >> USB_ISTR_EP_ID_Pos);
+#else
+ /* ST: EP_ID is at ISTR bits [3:0] */
ep_idx = (uint8_t)(wIstr & USB_ISTR_EP_ID);
+#endif
if (ep_idx == 0U) {
if ((wIstr & USB_ISTR_DIR) == 0U) {
diff --git a/port/fsdev/usb_fsdev_reg.h b/port/fsdev/usb_fsdev_reg.h
index c67cf573..22e657f1 100644
--- a/port/fsdev/usb_fsdev_reg.h
+++ b/port/fsdev/usb_fsdev_reg.h
@@ -11,6 +11,40 @@
* @brief Universal Serial Bus Full Speed Device
*/
+/* N32H4x family detection (N32H47x_48x + N32H49x). */
+#if defined(N32H473) || defined(N32H474) || defined(N32H475) || \
+ defined(N32H481) || defined(N32H482) || defined(N32H480) || \
+ defined(N32H487) || defined(N32H488) || defined(N32H49X)
+#define N32H4X_FSDEV 1
+#endif
+
+#if defined(N32H4X_FSDEV)
+/* N32H4x re-arranged the Synopsys USBFS registers:
+ * - USB_EPn is a 32-bit register (no reserved words), EPn at 0x00 + n*4
+ * - CTRL@0x40 (named CNTR here to keep usb_dc_fsdev.c unchanged)
+ * - STS @0x44 (named ISTR here), BUFTAB@0x48 (named BTABLE), FN@0x4C, ADDR@0x50
+ * - No BCDR register: the DP pull-up moved to CTRL.PU (bit13)
+ * The buffer descriptor table layout (n*16 per endpoint) matches the ST macro
+ * addressing with PMA_ACCESS=2, so PCD_* btable macros are reused as-is.
+ */
+typedef struct
+{
+ __IO uint32_t EP0R; /*!< USB_EP0, Address offset: 0x00 */
+ __IO uint32_t EP1R; /*!< USB_EP1, Address offset: 0x04 */
+ __IO uint32_t EP2R; /*!< USB_EP2, Address offset: 0x08 */
+ __IO uint32_t EP3R; /*!< USB_EP3, Address offset: 0x0C */
+ __IO uint32_t EP4R; /*!< USB_EP4, Address offset: 0x10 */
+ __IO uint32_t EP5R; /*!< USB_EP5, Address offset: 0x14 */
+ __IO uint32_t EP6R; /*!< USB_EP6, Address offset: 0x18 */
+ __IO uint32_t EP7R; /*!< USB_EP7, Address offset: 0x1C */
+ __IO uint32_t RESERVED0[8]; /*!< Reserved Address offset: 0x20 .. 0x3C */
+ __IO uint32_t CNTR; /*!< USB_CTRL, Address offset: 0x40 */
+ __IO uint32_t ISTR; /*!< USB_STS, Address offset: 0x44 */
+ __IO uint32_t BTABLE; /*!< USB_BUFTAB, Address offset: 0x48 */
+ __IO uint32_t FN; /*!< USB_FN, Address offset: 0x4C */
+ __IO uint32_t DADDR; /*!< USB_ADDR, Address offset: 0x50 */
+} USB_TypeDef;
+#else
typedef struct
{
__IO uint16_t EP0R; /*!< USB Endpoint 0 register, Address offset: 0x00 */
@@ -44,6 +78,7 @@ typedef struct
__IO uint16_t BCDR; /*!< Battery Charging detector register, Address offset: 0x58 */
__IO uint16_t RESERVEDE; /*!< Reserved */
} USB_TypeDef;
+#endif
/******************************************************************************/
/* */
@@ -52,6 +87,7 @@ typedef struct
/******************************************************************************/
/*!< Endpoint-specific registers */
+#if !defined(N32H4X_FSDEV)
#define USB_EP0R USB_BASE /*!< Endpoint 0 register address */
#define USB_EP1R (USB_BASE + 0x00000004) /*!< Endpoint 1 register address */
#define USB_EP2R (USB_BASE + 0x00000008) /*!< Endpoint 2 register address */
@@ -1133,9 +1169,316 @@ typedef struct
#define USB_COUNT7_RX_1_BLSIZE_1 0x80000000U /*!< BLock SIZE (high) */
-/**
- * @}
- */
+#endif /* !(N32H4X_FSDEV) */
+
+#if defined(N32H4X_FSDEV)
+/* ===========================================================================
+ * N32H4x (N32H47x_48x / N32H49x) USBFS register bit re-mapping.
+ *
+ * Nations kept the Synopsys USBFS core but re-arranged every non-reserved
+ * bit field. This block re-defines the common macros used by
+ * usb_dc_fsdev.c with the N32H4x layout.
+ *
+ * USB_EPn register bits:
+ * STS_TX[15:14] | DATTOG_TX[13] | CTRS_TX[12] | STS_RX[11:10] | DATTOG_RX[9]
+ * CTRS_RX[8] | EP_TYPE[7:6] | EP_KIND[5] | SETUP[4] | EPADDR[3:0]
+ * ===========================================================================
+ */
+#undef USB_EP_CTR_RX_Pos
+#undef USB_EP_CTR_RX_Msk
+#undef USB_EP_CTR_RX
+#define USB_EP_CTR_RX_Pos (8U) /* CTRS_RX */
+#define USB_EP_CTR_RX_Msk (0x1UL << USB_EP_CTR_RX_Pos)
+#define USB_EP_CTR_RX USB_EP_CTR_RX_Msk
+#undef USB_EP_DTOG_RX_Pos
+#undef USB_EP_DTOG_RX_Msk
+#undef USB_EP_DTOG_RX
+#define USB_EP_DTOG_RX_Pos (9U) /* DATTOG_RX */
+#define USB_EP_DTOG_RX_Msk (0x1UL << USB_EP_DTOG_RX_Pos)
+#define USB_EP_DTOG_RX USB_EP_DTOG_RX_Msk
+#undef USB_EPRX_STAT_Pos
+#undef USB_EPRX_STAT_Msk
+#undef USB_EPRX_STAT
+#define USB_EPRX_STAT_Pos (10U) /* STS_RX[1:0] */
+#define USB_EPRX_STAT_Msk (0x3UL << USB_EPRX_STAT_Pos)
+#define USB_EPRX_STAT USB_EPRX_STAT_Msk
+#undef USB_EP_SETUP_Pos
+#undef USB_EP_SETUP_Msk
+#undef USB_EP_SETUP
+#define USB_EP_SETUP_Pos (4U) /* SETUP */
+#define USB_EP_SETUP_Msk (0x1UL << USB_EP_SETUP_Pos)
+#define USB_EP_SETUP USB_EP_SETUP_Msk
+#undef USB_EP_T_FIELD_Pos
+#undef USB_EP_T_FIELD_Msk
+#undef USB_EP_T_FIELD
+#define USB_EP_T_FIELD_Pos (6U) /* EP_TYPE[1:0] */
+#define USB_EP_T_FIELD_Msk (0x3UL << USB_EP_T_FIELD_Pos)
+#define USB_EP_T_FIELD USB_EP_T_FIELD_Msk
+#undef USB_EP_KIND_Pos
+#undef USB_EP_KIND_Msk
+#undef USB_EP_KIND
+#define USB_EP_KIND_Pos (5U) /* EP_KIND */
+#define USB_EP_KIND_Msk (0x1UL << USB_EP_KIND_Pos)
+#define USB_EP_KIND USB_EP_KIND_Msk
+#undef USB_EP_CTR_TX_Pos
+#undef USB_EP_CTR_TX_Msk
+#undef USB_EP_CTR_TX
+#define USB_EP_CTR_TX_Pos (12U) /* CTRS_TX */
+#define USB_EP_CTR_TX_Msk (0x1UL << USB_EP_CTR_TX_Pos)
+#define USB_EP_CTR_TX USB_EP_CTR_TX_Msk
+#undef USB_EP_DTOG_TX_Pos
+#undef USB_EP_DTOG_TX_Msk
+#undef USB_EP_DTOG_TX
+#define USB_EP_DTOG_TX_Pos (13U) /* DATTOG_TX */
+#define USB_EP_DTOG_TX_Msk (0x1UL << USB_EP_DTOG_TX_Pos)
+#define USB_EP_DTOG_TX USB_EP_DTOG_TX_Msk
+#undef USB_EPTX_STAT_Pos
+#undef USB_EPTX_STAT_Msk
+#undef USB_EPTX_STAT
+#define USB_EPTX_STAT_Pos (14U) /* STS_TX[1:0] */
+#define USB_EPTX_STAT_Msk (0x3UL << USB_EPTX_STAT_Pos)
+#define USB_EPTX_STAT USB_EPTX_STAT_Msk
+/* EPADDR[3:0] stays at bit 0 */
+
+/* EndPoint REGister MASK (no toggle/status fields) */
+#undef USB_EPREG_MASK
+#define USB_EPREG_MASK (USB_EP_CTR_RX|USB_EP_SETUP|USB_EP_T_FIELD|USB_EP_KIND|USB_EP_CTR_TX|USB_EPADDR_FIELD)
+
+#undef USB_EP_TYPE_MASK_Pos
+#undef USB_EP_TYPE_MASK_Msk
+#undef USB_EP_TYPE_MASK
+#define USB_EP_TYPE_MASK_Pos (6U)
+#define USB_EP_TYPE_MASK_Msk (0x3UL << USB_EP_TYPE_MASK_Pos)
+#define USB_EP_TYPE_MASK USB_EP_TYPE_MASK_Msk
+#undef USB_EP_BULK
+#undef USB_EP_CONTROL
+#undef USB_EP_ISOCHRONOUS
+#undef USB_EP_INTERRUPT
+#define USB_EP_BULK (0UL << USB_EP_T_FIELD_Pos) /* 00 */
+#define USB_EP_CONTROL (1UL << USB_EP_T_FIELD_Pos) /* 01 */
+#define USB_EP_ISOCHRONOUS (2UL << USB_EP_T_FIELD_Pos) /* 10 */
+#define USB_EP_INTERRUPT (3UL << USB_EP_T_FIELD_Pos) /* 11 */
+#undef USB_EP_T_MASK
+#define USB_EP_T_MASK (~USB_EP_T_FIELD & USB_EPREG_MASK)
+#undef USB_EPKIND_MASK
+#define USB_EPKIND_MASK (~USB_EP_KIND & USB_EPREG_MASK)
+
+/* STS_TX[1:0] bit15:14: 00 DIS / 01 STALL / 10 NAK / 11 VALID */
+#undef USB_EP_TX_DIS
+#undef USB_EP_TX_STALL
+#undef USB_EP_TX_NAK
+#undef USB_EP_TX_VALID
+#undef USB_EPTX_DTOG1
+#undef USB_EPTX_DTOG2
+#undef USB_EPTX_DTOGMASK
+#define USB_EP_TX_DIS (0UL << USB_EPTX_STAT_Pos)
+#define USB_EP_TX_STALL (1UL << USB_EPTX_STAT_Pos)
+#define USB_EP_TX_NAK (2UL << USB_EPTX_STAT_Pos)
+#define USB_EP_TX_VALID (3UL << USB_EPTX_STAT_Pos)
+#define USB_EPTX_DTOG1 (1UL << USB_EPTX_STAT_Pos)
+#define USB_EPTX_DTOG2 (2UL << USB_EPTX_STAT_Pos)
+#define USB_EPTX_DTOGMASK (USB_EPTX_STAT|USB_EPREG_MASK)
+
+/* STS_RX[1:0] bit11:10: 00 DIS / 01 STALL / 10 NAK / 11 VALID */
+#undef USB_EP_RX_DIS
+#undef USB_EP_RX_STALL
+#undef USB_EP_RX_NAK
+#undef USB_EP_RX_VALID
+#undef USB_EPRX_DTOG1
+#undef USB_EPRX_DTOG2
+#undef USB_EPRX_DTOGMASK
+#define USB_EP_RX_DIS (0UL << USB_EPRX_STAT_Pos)
+#define USB_EP_RX_STALL (1UL << USB_EPRX_STAT_Pos)
+#define USB_EP_RX_NAK (2UL << USB_EPRX_STAT_Pos)
+#define USB_EP_RX_VALID (3UL << USB_EPRX_STAT_Pos)
+#define USB_EPRX_DTOG1 (1UL << USB_EPRX_STAT_Pos)
+#define USB_EPRX_DTOG2 (2UL << USB_EPRX_STAT_Pos)
+#define USB_EPRX_DTOGMASK (USB_EPRX_STAT|USB_EPREG_MASK)
+
+/* USB_CTRL register bits: PU[13] RESUM[12] FSUSPD[11] LP_MODE[10] PD[9] FRST[8]
+ * PMAOM[7] CTRSM[6] ERRORM[5] WKUPM[4] SUSPDM[3] RSTM[2] SOFM[1] ESOFM[0]
+ * Default value 0x0300 -> PD and FRST are set after reset.
+ */
+#undef USB_CNTR_FRES_Pos
+#undef USB_CNTR_FRES_Msk
+#undef USB_CNTR_FRES
+#define USB_CNTR_FRES_Pos (8U) /* FRST */
+#define USB_CNTR_FRES_Msk (0x1UL << USB_CNTR_FRES_Pos)
+#define USB_CNTR_FRES USB_CNTR_FRES_Msk
+#undef USB_CNTR_PDWN_Pos
+#undef USB_CNTR_PDWN_Msk
+#undef USB_CNTR_PDWN
+#define USB_CNTR_PDWN_Pos (9U) /* PD */
+#define USB_CNTR_PDWN_Msk (0x1UL << USB_CNTR_PDWN_Pos)
+#define USB_CNTR_PDWN USB_CNTR_PDWN_Msk
+#undef USB_CNTR_LP_MODE_Pos
+#undef USB_CNTR_LP_MODE_Msk
+#undef USB_CNTR_LP_MODE
+#define USB_CNTR_LP_MODE_Pos (10U) /* LP_MODE */
+#define USB_CNTR_LP_MODE_Msk (0x1UL << USB_CNTR_LP_MODE_Pos)
+#define USB_CNTR_LP_MODE USB_CNTR_LP_MODE_Msk
+#undef USB_CNTR_FSUSP_Pos
+#undef USB_CNTR_FSUSP_Msk
+#undef USB_CNTR_FSUSP
+#define USB_CNTR_FSUSP_Pos (11U) /* FSUSPD */
+#define USB_CNTR_FSUSP_Msk (0x1UL << USB_CNTR_FSUSP_Pos)
+#define USB_CNTR_FSUSP USB_CNTR_FSUSP_Msk
+#undef USB_CNTR_RESUME_Pos
+#undef USB_CNTR_RESUME_Msk
+#undef USB_CNTR_RESUME
+#define USB_CNTR_RESUME_Pos (12U) /* RESUM */
+#define USB_CNTR_RESUME_Msk (0x1UL << USB_CNTR_RESUME_Pos)
+#define USB_CNTR_RESUME USB_CNTR_RESUME_Msk
+#define USB_CNTR_PU_Pos (13U) /* PU (DP pull-up, replaces ST BCDR.DPPU) */
+#define USB_CNTR_PU_Msk (0x1UL << USB_CNTR_PU_Pos)
+#define USB_CNTR_PU USB_CNTR_PU_Msk
+#undef USB_CNTR_ESOFM_Pos
+#undef USB_CNTR_ESOFM_Msk
+#undef USB_CNTR_ESOFM
+#define USB_CNTR_ESOFM_Pos (0U) /* ESOFM */
+#define USB_CNTR_ESOFM_Msk (0x1UL << USB_CNTR_ESOFM_Pos)
+#define USB_CNTR_ESOFM USB_CNTR_ESOFM_Msk
+#undef USB_CNTR_SOFM_Pos
+#undef USB_CNTR_SOFM_Msk
+#undef USB_CNTR_SOFM
+#define USB_CNTR_SOFM_Pos (1U) /* SOFM */
+#define USB_CNTR_SOFM_Msk (0x1UL << USB_CNTR_SOFM_Pos)
+#define USB_CNTR_SOFM USB_CNTR_SOFM_Msk
+#undef USB_CNTR_RESETM_Pos
+#undef USB_CNTR_RESETM_Msk
+#undef USB_CNTR_RESETM
+#define USB_CNTR_RESETM_Pos (2U) /* RSTM */
+#define USB_CNTR_RESETM_Msk (0x1UL << USB_CNTR_RESETM_Pos)
+#define USB_CNTR_RESETM USB_CNTR_RESETM_Msk
+#undef USB_CNTR_SUSPM_Pos
+#undef USB_CNTR_SUSPM_Msk
+#undef USB_CNTR_SUSPM
+#define USB_CNTR_SUSPM_Pos (3U) /* SUSPDM */
+#define USB_CNTR_SUSPM_Msk (0x1UL << USB_CNTR_SUSPM_Pos)
+#define USB_CNTR_SUSPM USB_CNTR_SUSPM_Msk
+#undef USB_CNTR_WKUPM_Pos
+#undef USB_CNTR_WKUPM_Msk
+#undef USB_CNTR_WKUPM
+#define USB_CNTR_WKUPM_Pos (4U) /* WKUPM */
+#define USB_CNTR_WKUPM_Msk (0x1UL << USB_CNTR_WKUPM_Pos)
+#define USB_CNTR_WKUPM USB_CNTR_WKUPM_Msk
+#undef USB_CNTR_ERRM_Pos
+#undef USB_CNTR_ERRM_Msk
+#undef USB_CNTR_ERRM
+#define USB_CNTR_ERRM_Pos (5U) /* ERRORM */
+#define USB_CNTR_ERRM_Msk (0x1UL << USB_CNTR_ERRM_Pos)
+#define USB_CNTR_ERRM USB_CNTR_ERRM_Msk
+#undef USB_CNTR_PMAOVRM_Pos
+#undef USB_CNTR_PMAOVRM_Msk
+#undef USB_CNTR_PMAOVRM
+#define USB_CNTR_PMAOVRM_Pos (7U) /* PMAOM */
+#define USB_CNTR_PMAOVRM_Msk (0x1UL << USB_CNTR_PMAOVRM_Pos)
+#define USB_CNTR_PMAOVRM USB_CNTR_PMAOVRM_Msk
+#undef USB_CNTR_CTRM_Pos
+#undef USB_CNTR_CTRM_Msk
+#undef USB_CNTR_CTRM
+#define USB_CNTR_CTRM_Pos (6U) /* CTRSM */
+#define USB_CNTR_CTRM_Msk (0x1UL << USB_CNTR_CTRM_Pos)
+#define USB_CNTR_CTRM USB_CNTR_CTRM_Msk
+
+/* USB_STS register bits: DIR[12] EP_ID[11:8] PMAO[7] CTRS[6] ERROR[5] WKUP[4]
+ * SUSPD[3] RST[2] SOF[1] ESOF[0]
+ */
+#undef USB_ISTR_EP_ID_Pos
+#undef USB_ISTR_EP_ID_Msk
+#undef USB_ISTR_EP_ID
+#define USB_ISTR_EP_ID_Pos (8U)
+#define USB_ISTR_EP_ID_Msk (0xFUL << USB_ISTR_EP_ID_Pos)
+#define USB_ISTR_EP_ID USB_ISTR_EP_ID_Msk
+#undef USB_ISTR_DIR_Pos
+#undef USB_ISTR_DIR_Msk
+#undef USB_ISTR_DIR
+#define USB_ISTR_DIR_Pos (12U)
+#define USB_ISTR_DIR_Msk (0x1UL << USB_ISTR_DIR_Pos)
+#define USB_ISTR_DIR USB_ISTR_DIR_Msk
+#undef USB_ISTR_ESOF_Pos
+#undef USB_ISTR_ESOF_Msk
+#undef USB_ISTR_ESOF
+#define USB_ISTR_ESOF_Pos (0U)
+#define USB_ISTR_ESOF_Msk (0x1UL << USB_ISTR_ESOF_Pos)
+#define USB_ISTR_ESOF USB_ISTR_ESOF_Msk
+#undef USB_ISTR_SOF_Pos
+#undef USB_ISTR_SOF_Msk
+#undef USB_ISTR_SOF
+#define USB_ISTR_SOF_Pos (1U)
+#define USB_ISTR_SOF_Msk (0x1UL << USB_ISTR_SOF_Pos)
+#define USB_ISTR_SOF USB_ISTR_SOF_Msk
+#undef USB_ISTR_RESET_Pos
+#undef USB_ISTR_RESET_Msk
+#undef USB_ISTR_RESET
+#define USB_ISTR_RESET_Pos (2U)
+#define USB_ISTR_RESET_Msk (0x1UL << USB_ISTR_RESET_Pos)
+#define USB_ISTR_RESET USB_ISTR_RESET_Msk
+#undef USB_ISTR_SUSP_Pos
+#undef USB_ISTR_SUSP_Msk
+#undef USB_ISTR_SUSP
+#define USB_ISTR_SUSP_Pos (3U)
+#define USB_ISTR_SUSP_Msk (0x1UL << USB_ISTR_SUSP_Pos)
+#define USB_ISTR_SUSP USB_ISTR_SUSP_Msk
+#undef USB_ISTR_WKUP_Pos
+#undef USB_ISTR_WKUP_Msk
+#undef USB_ISTR_WKUP
+#define USB_ISTR_WKUP_Pos (4U)
+#define USB_ISTR_WKUP_Msk (0x1UL << USB_ISTR_WKUP_Pos)
+#define USB_ISTR_WKUP USB_ISTR_WKUP_Msk
+#undef USB_ISTR_ERR_Pos
+#undef USB_ISTR_ERR_Msk
+#undef USB_ISTR_ERR
+#define USB_ISTR_ERR_Pos (5U)
+#define USB_ISTR_ERR_Msk (0x1UL << USB_ISTR_ERR_Pos)
+#define USB_ISTR_ERR USB_ISTR_ERR_Msk
+#undef USB_ISTR_PMAOVR_Pos
+#undef USB_ISTR_PMAOVR_Msk
+#undef USB_ISTR_PMAOVR
+#define USB_ISTR_PMAOVR_Pos (7U)
+#define USB_ISTR_PMAOVR_Msk (0x1UL << USB_ISTR_PMAOVR_Pos)
+#define USB_ISTR_PMAOVR USB_ISTR_PMAOVR_Msk
+#undef USB_ISTR_CTR_Pos
+#undef USB_ISTR_CTR_Msk
+#undef USB_ISTR_CTR
+#define USB_ISTR_CTR_Pos (6U)
+#define USB_ISTR_CTR_Msk (0x1UL << USB_ISTR_CTR_Pos)
+#define USB_ISTR_CTR USB_ISTR_CTR_Msk
+
+/* The ST bank above is skipped under N32, so re-provide the macros whose bit
+ * positions are identical on N32 (so the later PCD_* macros still resolve):
+
+ * USB_EPADDR[3:0] -- same as ST (endpoint address). */
+#undef USB_EPADDR_FIELD_Pos
+#undef USB_EPADDR_FIELD_Msk
+#undef USB_EPADDR_FIELD
+#define USB_EPADDR_FIELD_Pos (0U)
+#define USB_EPADDR_FIELD_Msk (0xFUL << USB_EPADDR_FIELD_Pos)
+#define USB_EPADDR_FIELD USB_EPADDR_FIELD_Msk
+
+/* USB_ADDR (device address): EFUC[7] ADDR[6:0], same as ST USB_DADDR. */
+#undef USB_DADDR_ADD_Pos
+#undef USB_DADDR_ADD_Msk
+#undef USB_DADDR_ADD
+#define USB_DADDR_ADD_Pos (0U)
+#define USB_DADDR_ADD_Msk (0x7FUL << USB_DADDR_ADD_Pos)
+#define USB_DADDR_ADD USB_DADDR_ADD_Msk
+#undef USB_DADDR_EF_Pos
+#undef USB_DADDR_EF_Msk
+#undef USB_DADDR_EF
+#define USB_DADDR_EF_Pos (7U) /* EFUC */
+#define USB_DADDR_EF_Msk (0x1UL << USB_DADDR_EF_Pos)
+#define USB_DADDR_EF USB_DADDR_EF_Msk
+
+/* USB_BUFTAB: BUFTAB[15:3] (8-byte aligned), same as ST USB_BTABLE. */
+#undef USB_BTABLE_BTABLE_Pos
+#undef USB_BTABLE_BTABLE_Msk
+#undef USB_BTABLE_BTABLE
+#define USB_BTABLE_BTABLE_Pos (3U)
+#define USB_BTABLE_BTABLE_Msk (0x1FFFUL << USB_BTABLE_BTABLE_Pos)
+#define USB_BTABLE_BTABLE USB_BTABLE_BTABLE_Msk
+
+#endif /* N32H4X_FSDEV */
#define BTABLE_ADDRESS 0x000U
@@ -1146,11 +1489,22 @@ typedef struct
#define USB_CNTRX_NBLK_MSK (0x1FU << 10)
#define USB_CNTRX_BLSIZE (0x1U << 15)
+#if defined(N32H4X_FSDEV)
+/* N32H4x: USB_EPn are 32-bit registers at 0x00 + n*4 (no reserved words),
+ * so each endpoint is a single 32-bit step. */
+
+/* SetENDPOINT */
+#define PCD_SET_ENDPOINT(USBx, bEpNum, wRegValue) (*(__IO uint32_t *)(&(USBx)->EP0R + ((bEpNum) * 1U)) = (uint32_t)(wRegValue))
+
+/* GetENDPOINT */
+#define PCD_GET_ENDPOINT(USBx, bEpNum) (*(__IO uint32_t *)(&(USBx)->EP0R + ((bEpNum) * 1U)))
+#else
/* SetENDPOINT */
#define PCD_SET_ENDPOINT(USBx, bEpNum, wRegValue) (*(__IO uint16_t *)(&(USBx)->EP0R + ((bEpNum) * 2U)) = (uint16_t)(wRegValue))
/* GetENDPOINT */
#define PCD_GET_ENDPOINT(USBx, bEpNum) (*(__IO uint16_t *)(&(USBx)->EP0R + ((bEpNum) * 2U)))
+#endif
/**
* @brief sets the type in the endpoint register(bits EP_TYPE[1:0])
@@ -1353,6 +1707,26 @@ typedef struct
* @param bEpNum Endpoint Number.
* @retval None
*/
+#if defined(N32H4X_FSDEV)
+/* N32H4x: CTRS_RX is bit8, CTRS_TX is bit12 (rc_w0, write-0 to clear). */
+#define PCD_CLEAR_RX_EP_CTR(USBx, bEpNum) \
+ do { \
+ uint16_t _wRegVal; \
+ \
+ _wRegVal = PCD_GET_ENDPOINT((USBx), (bEpNum)) & (0xFEFFU & USB_EPREG_MASK); \
+ \
+ PCD_SET_ENDPOINT((USBx), (bEpNum), (_wRegVal | USB_EP_CTR_TX)); \
+ } while(0) /* PCD_CLEAR_RX_EP_CTR */
+
+#define PCD_CLEAR_TX_EP_CTR(USBx, bEpNum) \
+ do { \
+ uint16_t _wRegVal; \
+ \
+ _wRegVal = PCD_GET_ENDPOINT((USBx), (bEpNum)) & (0xEFFFU & USB_EPREG_MASK); \
+ \
+ PCD_SET_ENDPOINT((USBx), (bEpNum), (_wRegVal | USB_EP_CTR_RX)); \
+ } while(0) /* PCD_CLEAR_TX_EP_CTR */
+#else
#define PCD_CLEAR_RX_EP_CTR(USBx, bEpNum) \
do { \
uint16_t _wRegVal; \
@@ -1370,6 +1744,7 @@ typedef struct
\
PCD_SET_ENDPOINT((USBx), (bEpNum), (_wRegVal | USB_EP_CTR_RX)); \
} while(0) /* PCD_CLEAR_TX_EP_CTR */
+#endif
/**
* @brief Toggles DTOG_RX / DTOG_TX bit in the endpoint register.
diff --git a/port/fsdev/usb_glue_nation.c b/port/fsdev/usb_glue_nation.c
new file mode 100644
index 00000000..d51652a2
--- /dev/null
+++ b/port/fsdev/usb_glue_nation.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2025, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+
+/* N32H4x family detection (N32H47x_48x + N32H49x): same part-macro list as
+ * the SDKs (n32h47x_48x.h typedef enum IRQn, n32h49x.h) and as
+ * usb_fsdev_reg.h. Defined here locally so this file never needs to include
+ * usb_fsdev_reg.h next to the SDK headers (which would re-define e.g.
+ * USB_EP_SETUP). */
+#if defined(N32H473) || defined(N32H474) || defined(N32H475) || \
+ defined(N32H481) || defined(N32H482) || defined(N32H480) || \
+ defined(N32H487) || defined(N32H488) || defined(N32H49X)
+#define N32H4X_FSDEV 1
+#endif
+
+#if defined(N32H4X_FSDEV)
+
+#if defined(N32H473) || defined(N32H474) || defined(N32H475) || \
+ defined(N32H481) || defined(N32H482) || defined(N32H480) || \
+ defined(N32H487) || defined(N32H488)
+#include "n32h47x_48x_rcc.h"
+#include "n32h47x_48x_gpio.h"
+#include "misc.h"
+
+#define USBFS_REG_BASE 0x40004800UL
+#define USBFS_SRAM_BASE 0x40004C00UL
+#define USBFS_APB1_CLK RCC_APB1_PERIPH_USBFS
+
+#elif defined(N32H49X)
+#include "n32h49x_rcc.h"
+#include "n32h49x_gpio.h"
+#include "misc.h"
+
+#define USBFS_REG_BASE 0x40004800UL
+#define USBFS_SRAM_BASE 0x40004C00UL
+#define USBFS_APB1_CLK RCC_APB1_PERIPHEN_USBFS
+
+#else
+#error "unsupported N32H4x part: define a N32H47x_48x part macro (N32H473/474/475/481/482/480/487/488) or N32H49X"
+#endif /* N32H473..N32H488 (48x SDK) / N32H49X (49x SDK) */
+
+/*
+ * N32H4x (N32H47x_48x / N32H49x) USB Full-Speed Device (USB_FS_Device).
+ *
+ * The USBFS core is the same Synopsys USBFS as STM32, but Nations re-arranged
+ * every register/bit field. The re-map lives in usb_fsdev_reg.h; this file
+ * only does the chip-level bring-up (clock, GPIO, NVIC, interrupt dispatch)
+ * and mirrors the Nations USBFSD examples (HID_CDC_Composite): hw_config.c
+ * (USBFS_IO_Configure / Set_USBClock / USB_Config) and n32h47x_48x_it.c /
+ * n32h49x_it.c (USB_FS_LP_IRQHandler).
+ *
+ * USBFS:
+ * - register base : 0x40004800 (USB_BASE)
+ * - packet buffer : 0x40004C00 (USB_SRAM_BASE, 512 bytes)
+ * - APB1 peripheral; USBFS needs a precise 48 MHz USB clock derived from
+ * PLLCLK (48/96/144/192/240 MHz -> DIV1/2/3/4/5).
+ * - IRQ : USB_FS_LP_IRQn (20, low priority, used here) ; USB_FS_HP_IRQn
+ * (19, high priority, iso/double-buffer only)
+ */
+
+/**
+ * @brief Configure the USBFS 48 MHz clock from the actual PLLCLK.
+ *
+ * The prescaler source is derived from SystemCoreClock at runtime, so the
+ * divider always matches the frequency the board is actually running at
+ * (no per-part compile-time table to keep in sync with the PLL setup).
+ * Supported PLLCLK values: 48/96/144/192/240 MHz -> DIV1/2/3/4/5.
+ * Unsupported frequencies leave the prescaler untouched and must be fixed
+ * in the board clock configuration (48 MHz USB clock is then not guaranteed).
+ */
+static void Set_USBClock(void)
+{
+ switch (SystemCoreClock) {
+ case 48000000: /* SYSCLK_VALUE_48MHz -> DIV1 */
+ RCC_ConfigUSBPLLPresClk(RCC_USBPLLCLK_SRC_PLL, RCC_USBPLLCLK_DIV1);
+ RCC->CFG3 &= ~RCC_CFG3_USBFSTM;
+ break;
+
+ case 96000000: /* SYSCLK_VALUE_96MHz -> DIV2 */
+ RCC_ConfigUSBPLLPresClk(RCC_USBPLLCLK_SRC_PLL, RCC_USBPLLCLK_DIV2);
+ RCC->CFG3 &= ~RCC_CFG3_USBFSTM;
+ break;
+
+ case 144000000: /* SYSCLK_VALUE_144MHz -> DIV3 */
+ RCC_ConfigUSBPLLPresClk(RCC_USBPLLCLK_SRC_PLL, RCC_USBPLLCLK_DIV3);
+ RCC->CFG3 |= RCC_CFG3_USBFSTM;
+ break;
+
+ case 192000000: /* SYSCLK_VALUE_192MHz -> DIV4 */
+ RCC_ConfigUSBPLLPresClk(RCC_USBPLLCLK_SRC_PLL, RCC_USBPLLCLK_DIV4);
+ RCC->CFG3 |= RCC_CFG3_USBFSTM;
+ break;
+
+ case 240000000: /* SYSCLK_VALUE_240MHz -> DIV5 */
+ RCC_ConfigUSBPLLPresClk(RCC_USBPLLCLK_SRC_PLL, RCC_USBPLLCLK_DIV5);
+ RCC->CFG3 |= RCC_CFG3_USBFSTM;
+ break;
+
+ default:
+ USB_LOG_ERR("Unsupported system clock %u Hz for USBFS 48 MHz clock (supported: 48/96/144/192/240 MHz)\r\n",
+ (unsigned int)SystemCoreClock);
+ break;
+ }
+}
+
+/**
+ * @brief Configure the USB DM/DP pins.
+ *
+ * Defaults to the EVAL board mapping (PA11 = DM, PA12 = DP, AF10).
+ * Marked __WEAK so the board layer can override it for other pin maps.
+ */
+__WEAK void n32h4xx_usbfs_gpio_init(void)
+{
+ RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA, ENABLE);
+
+ GPIO_InitType GPIO_InitStructure;
+ GPIO_InitStruct(&GPIO_InitStructure);
+
+ GPIO_InitStructure.Pin = GPIO_PIN_11;
+ GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStructure.GPIO_Alternate = GPIO_AF10;
+ GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
+
+ GPIO_InitStructure.Pin = GPIO_PIN_12;
+ GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStructure.GPIO_Alternate = GPIO_AF10;
+ GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
+}
+
+/**
+ * @brief Low-level USBFS initialization: clock, GPIO and interrupt channel.
+ *
+ * Signature must match the __WEAK stub in usb_dc_fsdev.c (no parameter),
+ * so the fsdev port always talks to bus 0.
+ */
+void usb_dc_low_level_init(uint8_t busid)
+{
+ if (g_usbdev_bus[0].reg_base != USBFS_REG_BASE) {
+ return;
+ }
+
+ /* 1. USBFS 48 MHz clock: source select, PLL prescaler, APB1 enable. */
+ RCC_ConfigUSBFSClk(RCC_USBFS_CLKSRC_PLLPRES);
+ Set_USBClock();
+ RCC_EnableAPB1PeriphClk(USBFS_APB1_CLK, ENABLE);
+
+ /* 2. USB DM/DP pins (weak hook, override in the board layer). */
+ n32h4xx_usbfs_gpio_init();
+
+ /* 3. Low-priority USB FS interrupt (all FS device events, including the
+ * USB_STS.WKUP/SUSPD bits handled by usb_dc_fsdev.c). Priority-group
+ * selection stays with the board/application startup code. */
+ NVIC_InitType NVIC_InitStructure;
+
+ NVIC_InitStructure.NVIC_IRQChannel = USB_FS_LP_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+}
+
+/**
+ * @brief Low-level USBFS deinitialization: disable interrupt and APB1 clock.
+ */
+void usb_dc_low_level_deinit(uint8_t busid)
+{
+ if (g_usbdev_bus[0].reg_base != USBFS_REG_BASE) {
+ return;
+ }
+
+ NVIC_InitType NVIC_InitStructure;
+
+ NVIC_InitStructure.NVIC_IRQChannel = USB_FS_LP_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ RCC_EnableAPB1PeriphClk(USBFS_APB1_CLK, DISABLE);
+}
+
+/**
+ * @brief Low-priority USB FS interrupt: dispatches all FS device events.
+ */
+void USB_FS_LP_IRQHandler(void)
+{
+ USBD_IRQHandler(0);
+}
+
+#endif /* N32H4X_FSDEV */
diff --git a/port/hpmicro/usb_dc_hpm.c b/port/hpmicro/usb_dc_hpm.c
index 60af1187..8ece72a3 100644
--- a/port/hpmicro/usb_dc_hpm.c
+++ b/port/hpmicro/usb_dc_hpm.c
@@ -7,11 +7,6 @@
#include "usbd_core.h"
#include "hpm_usb_device.h"
#include "usb_glue_hpm.h"
-#include "hpm_sdk_version.h"
-
-#if SDK_VERSION_NUMBER < 0x10C00
-#error "Please use SDK version 1.12.0 or later because of USB api modification"
-#endif
#define USB_NUM_BIDIR_ENDPOINTS USB_SOC_DCD_MAX_ENDPOINT_COUNT
diff --git a/port/kinetis/usb_dc_kinetis.c b/port/kinetis/usb_dc_kinetis.c
index 6cbf5356..2dd1ba61 100644
--- a/port/kinetis/usb_dc_kinetis.c
+++ b/port/kinetis/usb_dc_kinetis.c
@@ -83,13 +83,8 @@ static void kinetis_read_setup(uint8_t busid)
kinetis_start_transfer(busid, USB_CONTROL_OUT_EP0, setup_packet[busid], 8);
}
-__WEAK void usb_dc_low_level_init(uint8_t busid)
-{
-}
-
-__WEAK void usb_dc_low_level_deinit(uint8_t busid)
-{
-}
+extern void usb_dc_low_level_init(uint8_t busid);
+extern void usb_dc_low_level_deinit(uint8_t busid);
int usb_dc_init(uint8_t busid)
{
diff --git a/port/kinetis/usb_glue_mm32.c b/port/kinetis/usb_glue_mm32.c
deleted file mode 100644
index 75e722c4..00000000
--- a/port/kinetis/usb_glue_mm32.c
+++ /dev/null
@@ -1,36 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-
-#include "mm32_device.h"
-#include "hal_rcc.h"
-#include "usbd_core.h"
-
-void usb_dc_low_level_init(uint8_t busid)
-{
- /* Select USBCLK source */
- // RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div1);
- RCC->CFGR &= ~(0x3 << 22);
- RCC->CFGR |= (0x1 << 22);
-
- /* Enable USB clock */
- RCC->AHB2ENR |= 0x1 << 7;
-
-#define USB_DEVICE_INTERRUPT_PRIORITY (7U)
- NVIC_SetPriority((IRQn_Type)USB_OTGFS_IRQn, USB_DEVICE_INTERRUPT_PRIORITY);
- NVIC_EnableIRQ(USB_OTGFS_IRQn);
-}
-
-void usb_dc_low_level_deinit(uint8_t busid)
-{
- RCC->AHB2ENR &= ~(0x1 << 7);
-}
-
-void USB_OTGFS_IRQHandler(void)
-{
- USBD_IRQHandler(0);
-}
-
-void usbd_kinetis_delay_ms(uint8_t ms)
-{
- //delay_ms(ms);
-}
diff --git a/port/musb/README.md b/port/musb/README.md
index 7c7b4305..7fc8a966 100644
--- a/port/musb/README.md
+++ b/port/musb/README.md
@@ -18,6 +18,7 @@
### AllwinnerTech
- F1Cxxx, F2Cxxx
+- Except F1Cxxx, F2Cxxx (musb + EHCI+ OHCI)
### SIFLI
diff --git a/port/musb/usb_dc_musb.c b/port/musb/usb_dc_musb.c
index de45b97b..c35a85c4 100644
--- a/port/musb/usb_dc_musb.c
+++ b/port/musb/usb_dc_musb.c
@@ -301,13 +301,8 @@ static uint32_t usbd_musb_fifo_config(struct musb_fifo_cfg *cfg, uint32_t offset
return (offset + fifo_used);
}
-__WEAK void usb_dc_low_level_init(void)
-{
-}
-
-__WEAK void usb_dc_low_level_deinit(void)
-{
-}
+extern void usb_dc_low_level_init(uint8_t busid);
+extern void usb_dc_low_level_deinit(uint8_t busid);
int usb_dc_init(uint8_t busid)
{
@@ -315,7 +310,7 @@ int usb_dc_init(uint8_t busid)
uint8_t cfg_num;
struct musb_fifo_cfg *cfg;
- usb_dc_low_level_init();
+ usb_dc_low_level_init(busid);
#ifdef CONFIG_USB_HS
HWREGB(USB_BASE + MUSB_POWER_OFFSET) |= USB_POWER_HSENAB;
@@ -357,7 +352,7 @@ int usb_dc_deinit(uint8_t busid)
HWREGB(USB_BASE + MUSB_POWER_OFFSET) &= ~USB_POWER_SOFTCONN;
- usb_dc_low_level_deinit();
+ usb_dc_low_level_deinit(busid);
return 0;
}
diff --git a/port/musb/usb_glue_bk.c b/port/musb/usb_glue_bk.c
index 728b4473..1e16818b 100644
--- a/port/musb/usb_glue_bk.c
+++ b/port/musb/usb_glue_bk.c
@@ -247,7 +247,7 @@ static void bk_analog_layer_usb_sys_related_ops(uint32_t usb_mode, bool ops)
}
}
-void usb_dc_low_level_init(void)
+void usb_dc_low_level_init(uint8_t busid)
{
#if CONFIG_SYS_CPU0
bk_pm_module_vote_sleep_ctrl(PM_SLEEP_MODULE_NAME_USB_1, 0x0, 0x0);
@@ -266,7 +266,7 @@ void usb_dc_low_level_init(void)
bk_int_set_priority(INT_SRC_USB, 2);
}
-void usb_dc_low_level_deinit(void)
+void usb_dc_low_level_deinit(uint8_t busid)
{
bk_pm_module_vote_cpu_freq(PM_DEV_ID_USB_1, PM_CPU_FRQ_DEFAULT);
sys_hal_usb_analog_phy_en(false);
diff --git a/port/musb/usb_glue_ti.c b/port/musb/usb_glue_ti.c
index 576a517f..fe19f0db 100644
--- a/port/musb/usb_glue_ti.c
+++ b/port/musb/usb_glue_ti.c
@@ -90,7 +90,7 @@ void usbd_musb_delay_ms(uint8_t ms)
/* implement later */
}
-void usb_dc_low_level_init(void)
+void usb_dc_low_level_init(uint8_t busid)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
@@ -119,7 +119,7 @@ void usb_dc_low_level_init(void)
IntEnable(INT_USB0);
}
-void usb_dc_low_level_deinit(void)
+void usb_dc_low_level_deinit(uint8_t busid)
{
IntDisable(INT_USB0);
g_usb_irq_handler = NULL;
diff --git a/port/musb/usb_hc_musb.c b/port/musb/usb_hc_musb.c
index daa0f056..259c3dbc 100644
--- a/port/musb/usb_hc_musb.c
+++ b/port/musb/usb_hc_musb.c
@@ -16,6 +16,15 @@
#define USB_BASE (bus->hcd.reg_base)
+#if defined(CONFIG_USB_MUSB_SIFLI) && (defined(SF32LB52X) || defined(SF32LB56X))
+#define MUSB_SIFLI_EP_MAP
+/* Host channel/slot layout: IN pool = ch1..ch4, OUT pool = ch5..ch7
+ * (ch0 is reserved for EP0). */
+#define MUSB_IN_SLOT_NUM (4)
+#define MUSB_OUT_SLOT_NUM (3)
+#define MUSB_EP_SLOT_NUM (MUSB_IN_SLOT_NUM + MUSB_OUT_SLOT_NUM)
+#endif
+
#if defined(CONFIG_USB_MUSB_SUNXI)
#define MUSB_FADDR_OFFSET 0x98
#define MUSB_POWER_OFFSET 0x40
@@ -169,6 +178,9 @@ struct musb_hcd {
volatile bool port_pec;
volatile bool port_pe;
struct musb_pipe pipe_pool[CONFIG_USB_MUSB_PIPE_NUM];
+#ifdef MUSB_SIFLI_EP_MAP
+ uint8_t sifli_ep_map[MUSB_EP_SLOT_NUM]; /* slot layout: 0-3 = IN (ch1..ch4), 4-6 = OUT (ch5..ch7) */
+#endif
} g_musb_hcd[CONFIG_USBHOST_MAX_BUS];
/* get current active ep */
@@ -188,14 +200,14 @@ static void musb_fifo_flush(struct usbh_bus *bus, uint8_t ep)
uint8_t ep_idx = ep & 0x7f;
if (ep_idx == 0) {
if ((HWREGB(USB_TXCSRL_BASE(ep_idx)) & (USB_CSRL0_RXRDY | USB_CSRL0_TXRDY)) != 0)
- HWREGB(USB_RXCSRL_BASE(ep_idx)) |= USB_CSRH0_FLUSH;
+ HWREGB(USB_TXCSRH_BASE(ep_idx)) |= USB_CSRH0_FLUSH;
} else {
if (ep & 0x80) {
- if (HWREGB(USB_TXCSRL_BASE(ep_idx)) & USB_TXCSRL1_TXRDY)
- HWREGB(USB_TXCSRL_BASE(ep_idx)) |= USB_TXCSRL1_FLUSH;
- } else {
if (HWREGB(USB_RXCSRL_BASE(ep_idx)) & USB_RXCSRL1_RXRDY)
HWREGB(USB_RXCSRL_BASE(ep_idx)) |= USB_RXCSRL1_FLUSH;
+ } else {
+ if (HWREGB(USB_TXCSRL_BASE(ep_idx)) & USB_TXCSRL1_TXRDY)
+ HWREGB(USB_TXCSRL_BASE(ep_idx)) |= USB_TXCSRL1_FLUSH;
}
}
}
@@ -339,6 +351,8 @@ void musb_control_urb_init(struct usbh_bus *bus, uint8_t chidx, struct usbh_urb
HWREGB(USB_TXHUBPORT_BASE(chidx)) = 0;
#endif
+ HWREGH(USB_BASE + MUSB_TXIE_OFFSET) |= USB_TXIE_EP0;
+
musb_write_packet(bus, chidx, (uint8_t *)setup, 8);
HWREGB(USB_TXCSRL_BASE(chidx)) = USB_CSRL0_TXRDY | USB_CSRL0_SETUP;
musb_set_active_ep(bus, old_ep_index);
@@ -539,11 +553,67 @@ static int musb_pipe_alloc(struct usbh_bus *bus)
return -1;
}
+#ifdef MUSB_SIFLI_EP_MAP
+static int sifli_ep_map_take_slot(struct musb_hcd *hcd, uint8_t map_base, uint8_t ch_base, uint8_t ep_num)
+{
+ uint8_t slot_cnt = (map_base == 0U) ? MUSB_IN_SLOT_NUM : MUSB_OUT_SLOT_NUM;
+
+ for (uint8_t i = 0; i < slot_cnt; i++) {
+ uint8_t *slot = &hcd->sifli_ep_map[map_base + i];
+
+ if (*slot == 0xFF) {
+ *slot = ep_num;
+ return ch_base + i;
+ }
+ }
+
+ return -USB_ERR_RANGE;
+}
+
+static int sifli_ep_map_alloc(struct usbh_bus *bus, uint8_t ep_num, bool is_in)
+{
+ if (ep_num == 0U) {
+ return ep_num;
+ }
+
+ struct musb_hcd *hcd = &g_musb_hcd[bus->hcd.hcd_id];
+ uint8_t map_base = is_in ? 0 : MUSB_IN_SLOT_NUM;
+ uint8_t ch_base = is_in ? 1 : (1 + MUSB_IN_SLOT_NUM);
+ uint8_t slot_cnt = is_in ? MUSB_IN_SLOT_NUM : MUSB_OUT_SLOT_NUM;
+
+ for (uint8_t i = 0; i < slot_cnt; i++) {
+ if (hcd->sifli_ep_map[map_base + i] == ep_num) {
+ return ch_base + i;
+ }
+ }
+
+ return sifli_ep_map_take_slot(hcd, map_base, ch_base, ep_num);
+}
+
+static void sifli_ep_map_free(struct usbh_bus *bus, uint8_t chidx)
+{
+ if (chidx < 1 || chidx > MUSB_EP_SLOT_NUM) {
+ return;
+ }
+
+ struct musb_hcd *hcd = &g_musb_hcd[bus->hcd.hcd_id];
+ uint8_t idx = chidx - 1;
+
+ hcd->sifli_ep_map[idx] = 0xFF;
+}
+#endif
+
static void musb_pipe_free(struct musb_pipe *pipe)
{
uintptr_t flags;
flags = usb_osal_enter_critical_section();
+#ifdef MUSB_SIFLI_EP_MAP
+ if (pipe->urb && pipe->urb->ep && pipe->urb->hport && pipe->urb->hport->bus &&
+ (USB_GET_ENDPOINT_TYPE(pipe->urb->ep->bmAttributes) != USB_ENDPOINT_TYPE_CONTROL)) {
+ sifli_ep_map_free(pipe->urb->hport->bus, pipe->chidx);
+ }
+#endif
if (pipe->urb) {
pipe->urb->hcpriv = NULL;
pipe->urb = NULL;
@@ -553,15 +623,8 @@ static void musb_pipe_free(struct musb_pipe *pipe)
usb_osal_leave_critical_section(flags);
}
-__WEAK void usb_hc_low_level_init(struct usbh_bus *bus)
-{
- (void)bus;
-}
-
-__WEAK void usb_hc_low_level_deinit(struct usbh_bus *bus)
-{
- (void)bus;
-}
+extern void usb_hc_low_level_init(struct usbh_bus *bus);
+extern void usb_hc_low_level_deinit(struct usbh_bus *bus);
int usb_hc_init(struct usbh_bus *bus)
{
@@ -574,8 +637,15 @@ int usb_hc_init(struct usbh_bus *bus)
memset(&g_musb_hcd[bus->hcd.hcd_id], 0, sizeof(struct musb_hcd));
+#ifdef MUSB_SIFLI_EP_MAP
+ for (uint8_t i = 0; i < MUSB_EP_SLOT_NUM; i++) {
+ g_musb_hcd[bus->hcd.hcd_id].sifli_ep_map[i] = 0xFF;
+ }
+#endif
+
for (uint8_t i = 0; i < CONFIG_USB_MUSB_PIPE_NUM; i++) {
g_musb_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem = usb_osal_sem_create(0);
+ USB_ASSERT(g_musb_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem != NULL);
}
cfg_num = usbh_get_musb_fifo_cfg(&cfg);
@@ -766,10 +836,44 @@ int usbh_submit_urb(struct usbh_urb *urb)
if (USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes) == USB_ENDPOINT_TYPE_CONTROL) {
chidx = 0;
} else {
+#ifdef MUSB_SIFLI_EP_MAP
+ bool in = (urb->ep->bEndpointAddress & 0x80) ? true : false;
+ uint8_t ep_num = (urb->ep->bEndpointAddress & 0x0f);
+ size_t alloc_flags;
+
+ alloc_flags = usb_osal_enter_critical_section();
+ chidx = sifli_ep_map_alloc(bus, ep_num, in);
+ USB_LOG_DBG("sifli_ep_map_alloc: ep_num=%d, in=%d, chidx=%d\r\n", ep_num, in, chidx);
+ if (chidx >= 0) {
+ if (g_musb_hcd[bus->hcd.hcd_id].pipe_pool[chidx].inuse) {
+ struct usbh_urb *owner = g_musb_hcd[bus->hcd.hcd_id].pipe_pool[chidx].urb;
+
+ USB_LOG_ERR("MUSB busy req=0x%02x %s ch=%d owner=0x%02x %s\r\n",
+ urb->ep->bEndpointAddress,
+ in ? "IN" : "OUT",
+ chidx,
+ owner && owner->ep ? owner->ep->bEndpointAddress : 0,
+ owner && owner->ep && (owner->ep->bEndpointAddress & 0x80) ? "IN" : "OUT");
+ chidx = -USB_ERR_BUSY;
+ } else {
+ g_musb_hcd[bus->hcd.hcd_id].pipe_pool[chidx].inuse = true;
+ }
+ } else {
+ USB_LOG_ERR("MUSB map fail ep=0x%02x %s ret=%d\r\n",
+ urb->ep->bEndpointAddress,
+ in ? "IN" : "OUT",
+ chidx);
+ }
+ usb_osal_leave_critical_section(alloc_flags);
+ if (chidx < 0) {
+ return chidx;
+ }
+#else
chidx = musb_pipe_alloc(bus);
if (chidx == -1) {
return -USB_ERR_NOMEM;
}
+#endif
}
flags = usb_osal_enter_critical_section();
@@ -843,17 +947,32 @@ int usbh_kill_urb(struct usbh_urb *urb)
flags = usb_osal_enter_critical_section();
pipe = (struct musb_pipe *)urb->hcpriv;
+ if (!pipe) {
+ usb_osal_leave_critical_section(flags);
+ return -USB_ERR_INVAL;
+ }
+
urb->errorcode = -USB_ERR_SHUTDOWN;
+#ifdef MUSB_SIFLI_EP_MAP
+ uint8_t chidx = pipe->chidx;
+ uint8_t fifo_ep = (urb->ep->bEndpointAddress & 0x80) | chidx;
+#else
+ uint8_t chidx = (urb->ep->bEndpointAddress & 0x0f);
+ uint8_t fifo_ep = urb->ep->bEndpointAddress;
+#endif
+
if (urb->ep->bEndpointAddress & 0x80) {
- HWREGH(USB_BASE + MUSB_RXIE_OFFSET) &= ~(1 << (urb->ep->bEndpointAddress & 0x0f));
- HWREGH(USB_BASE + MUSB_RXIS_OFFSET) = (1 << (urb->ep->bEndpointAddress & 0x0f));
+ HWREGH(USB_BASE + MUSB_RXIE_OFFSET) &= ~(1 << chidx);
+ HWREGH(USB_BASE + MUSB_RXIS_OFFSET) = (1 << chidx);
} else {
- HWREGH(USB_BASE + MUSB_TXIE_OFFSET) &= ~(1 << (urb->ep->bEndpointAddress & 0x0f));
- HWREGH(USB_BASE + MUSB_TXIS_OFFSET) = (1 << (urb->ep->bEndpointAddress & 0x0f));
+ HWREGH(USB_BASE + MUSB_TXIE_OFFSET) &= ~(1 << chidx);
+ HWREGH(USB_BASE + MUSB_TXIS_OFFSET) = (1 << chidx);
}
- musb_fifo_flush(bus, urb->ep->bEndpointAddress);
+ musb_fifo_flush(bus, fifo_ep);
+
+ usb_osal_leave_critical_section(flags);
if (urb->timeout) {
usb_osal_sem_give(pipe->waitsem);
@@ -865,7 +984,6 @@ int usbh_kill_urb(struct usbh_urb *urb)
urb->complete(urb->arg, urb->errorcode);
}
- usb_osal_leave_critical_section(flags);
return 0;
}
diff --git a/port/nuvoton/README.md b/port/nuvoton/README.md
index a91c8fae..379f4e4a 100644
--- a/port/nuvoton/README.md
+++ b/port/nuvoton/README.md
@@ -1,7 +1 @@
-# Note
-
-## Support Chip List
-
-- M032 Series
-- M480 Series
-
+**You can get source from official sdk.** \ No newline at end of file
diff --git a/port/nuvoton/usb_dc_usbfs.c b/port/nuvoton/usb_dc_usbfs.c
deleted file mode 100644
index ca2b6021..00000000
--- a/port/nuvoton/usb_dc_usbfs.c
+++ /dev/null
@@ -1,455 +0,0 @@
-#include <stdint.h>
-#include "NuMicro.h"
-#include "usbd_core.h"
-
-#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 usbd_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(uint8_t busid)
-{
- 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(uint8_t busid)
-{
- USBD->ATTR = 0x00000040;
- /* Force SE0 */
- USBD_SET_SE0();
-
- return 0;
-}
-
-int usbd_set_address(uint8_t busid, const uint8_t addr)
-{
- uint8_t usbd_addr = USBD_GET_ADDR();
- if ((usbd_addr == 0) && (usbd_addr != addr)) {
- g_nuvoton_udc.dev_addr = addr;
- usbd_set_address_flag = 1;
- }
-
- return 0;
-}
-
-int usbd_set_remote_wakeup(uint8_t busid)
-{
- return -1;
-}
-
-uint8_t usbd_get_port_speed(uint8_t busid)
-{
- return USB_SPEED_FULL;
-}
-
-int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
-{
- uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
-
- if (USB_EP_DIR_IS_IN(ep->bEndpointAddress)) {
- uint8_t epnum = USBD_EPNUM_FROM_IN_EPIDX(ep_idx);
-
- g_nuvoton_udc.in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
- g_nuvoton_udc.in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
- 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 = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
- g_nuvoton_udc.out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
- 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(uint8_t busid, 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(uint8_t busid, const uint8_t ep)
-{
- USBD_SET_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep));
- return 0;
-}
-
-int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
-{
- USBD_CLR_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep));
- return 0;
-}
-
-int usbd_ep_is_stalled(uint8_t busid, 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(uint8_t busid, 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(uint8_t busid, 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(uint8_t busid)
-{
- 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(0);
- } else {
- /* USB Un-plug */
- USBD_DISABLE_USB();
- usbd_event_disconnect_handler(0);
- }
- }
-
- //------------------------------------------------------------------
- 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(0);
- }
-
- if (bus_state & USBD_STATE_SUSPEND) {
- /* Enable USB but disable PHY */
- USBD_DISABLE_PHY();
- usbd_event_suspend_handler(0);
- }
- if (bus_state & USBD_STATE_RESUME) {
- /* Enable USB and enable PHY */
- USBD_ENABLE_USB();
- usbd_event_resume_handler(0);
- }
- }
-
- //------------------------------------------------------------------
- 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(0, (uint8_t *)(USBD_BUF_BASE));
- }
-
- if (int_flag & USBD_INTSTS_EP0) {
- /* In ACK for Set address */
- if (usbd_set_address_flag == 1) {
- USBD_SET_ADDR(g_nuvoton_udc.dev_addr);
- usbd_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(0, 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(0, ep_idx | 0x80, g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len);
- }
- }
- }
- }
- }
-}
diff --git a/port/ohci/README.md b/port/ohci/README.md
index 928eb0c3..f708fe86 100644
--- a/port/ohci/README.md
+++ b/port/ohci/README.md
@@ -8,7 +8,7 @@ This OHCI is a companion controller of EHCI. But you can use OHCI only without C
### AllwinnerTech
-- F133(EHCI + OHCI)
+- Except F1Cxxx, F2Cxxx (musb + EHCI+ OHCI)
### Nuvoton
@@ -16,7 +16,7 @@ This OHCI is a companion controller of EHCI. But you can use OHCI only without C
### Artinchip
-- d13x, d21x(EHCI + OHCI)
+- ALL series (aic + EHCI + OHCI)
### NXP
diff --git a/port/ohci/usb_hc_ohci.c b/port/ohci/usb_hc_ohci.c
index 2bec2a03..6194ec84 100644
--- a/port/ohci/usb_hc_ohci.c
+++ b/port/ohci/usb_hc_ohci.c
@@ -50,6 +50,7 @@ int ohci_init(struct usbh_bus *bus)
for (uint8_t index = 0; index < CONFIG_USB_OHCI_ED_NUM; index++) {
ed = &g_ohci_ed_pool[bus->hcd.hcd_id][index];
ed->waitsem = usb_osal_sem_create(0);
+ USB_ASSERT(ed->waitsem != NULL);
}
USB_LOG_INFO("OHCI hcrevision:0x%02x\r\n", (unsigned int)OHCI_HCOR->hcrevision);
@@ -308,15 +309,8 @@ void OHCI_IRQHandler(uint8_t busid)
}
#ifndef CONFIG_USB_EHCI_WITH_OHCI
-__WEAK void usb_hc_low_level_init(struct usbh_bus *bus)
-{
- (void)bus;
-}
-
-__WEAK void usb_hc_low_level_deinit(struct usbh_bus *bus)
-{
- (void)bus;
-}
+extern void usb_hc_low_level_init(struct usbh_bus *bus);
+extern void usb_hc_low_level_deinit(struct usbh_bus *bus);
int usb_hc_init(struct usbh_bus *bus)
{
diff --git a/port/pusb2/README.md b/port/pusb2/README.md
index f8137afe..ba91ef0b 100644
--- a/port/pusb2/README.md
+++ b/port/pusb2/README.md
@@ -7,17 +7,17 @@
- Host 模式
-- - 1. [FreeRTOS 上作为主机使用键盘/鼠标/U盘](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/pusb2_host/README.md)
+- - 1. [FreeRTOS 上作为主机使用键盘/鼠标/U盘](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_host/README.md)
- - 5. [RT-Thread 上作为主机识别键盘/鼠标/U盘](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
---------------------------------------------
- Device 模式
-- - 1. [裸机上模拟为一个 U 盘](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/pusb2_device/README.md)
-- - 2. [裸机上模拟为一个虚拟串口](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/pusb2_device/README.md)
-- - 3. [FreeRTOS 上模拟为一个 U 盘](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/pusb2_device/README.md)
-- - 4. [FreeRTOS 上模拟为虚拟串口](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/pusb2_device/README.md)
+- - 1. [裸机上模拟为一个 U 盘](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/usb_device/README.md)
+- - 2. [裸机上模拟为一个虚拟串口](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/usb_device/README.md)
+- - 3. [FreeRTOS 上模拟为一个 U 盘](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_device/README.md)
+- - 4. [FreeRTOS 上模拟为虚拟串口](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_device/README.md)
- - 5. [RT-Thread 上模拟为一个 U 盘](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
---------------------------------------------
@@ -41,16 +41,16 @@
- Host Mode
- - 1. [Using a keyboard/mouse/USB flash drive as a host on FreeRTOS](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/pusb2_host/README.md)
+ - 1. [Using a keyboard/mouse/USB flash drive as a host on FreeRTOS](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_host/README.md)
- 5. [Recognizing a keyboard/mouse/USB flash drive as a host on RT-Thread](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
---------------------------------------------
- Device Mode
- - 1. [Simulating as a USB flash drive on a standalone system](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/pusb2_device/README.md)
- - 2. [Simulating as a virtual serial port on a standalone system](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/pusb2_device/README.md)
- - 3. [Simulating as a USB flash drive on FreeRTOS](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/pusb2_device/README.md)
- - 4. [Simulating as a virtual serial port on FreeRTOS](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/pusb2_device/README.md)
+ - 1. [Simulating as a USB flash drive on a standalone system](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/usb_device/README.md)
+ - 2. [Simulating as a virtual serial port on a standalone system](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/usb_device/README.md)
+ - 3. [Simulating as a USB flash drive on FreeRTOS](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_device/README.md)
+ - 4. [Simulating as a virtual serial port on FreeRTOS](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_device/README.md)
- 5. [Simulating as a USB flash drive on RT-Thread](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
---------------------------------------------
diff --git a/port/pusb2/freertos/usb_config.h b/port/pusb2/freertos/usb_config.h
index 760759f8..13303785 100644
--- a/port/pusb2/freertos/usb_config.h
+++ b/port/pusb2/freertos/usb_config.h
@@ -25,13 +25,16 @@ void *usb_sys_mem_malloc(size_t size);
void usb_sys_mem_free(void *ptr);
void *usb_sys_malloc_align(size_t align, size_t size);
-#define usb_malloc(size) usb_sys_mem_malloc(size)
-#define usb_free(ptr) usb_sys_mem_free(ptr)
-#define usb_align(align, size) usb_sys_malloc_align(align, size)
+#define usb_malloc(size) usb_sys_mem_malloc(size)
+#define usb_free(ptr) usb_sys_mem_free(ptr)
+#define usb_align(align, size) usb_sys_malloc_align(align, size)
unsigned long usb_hc_get_register_base(uint32_t id);
unsigned long usb_dc_get_register_base(uint32_t id);
+void cps_otg_switch_to_host(uintptr_t reg_base);
+void cps_otg_switch_to_device(uintptr_t reg_base);
+
#ifndef CONFIG_USB_DBG_LEVEL
#if defined(CONFIG_LOG_ERROR)
#define CONFIG_USB_DBG_LEVEL USB_DBG_ERROR
@@ -275,7 +278,7 @@ unsigned long usb_dc_get_register_base(uint32_t id);
#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
/* ---------------- PUSB2 Configuration ---------------- */
-#define CONFIG_USB_PUSB2_BUS_NUM 3U
-#define CONFIG_USB_PUSB2_BUS_ID 0U
+#define CONFIG_USB_PUSB2_BUS_NUM 3U
+#define CONFIG_USB_PUSB2_BUS_ID 0U
#endif
diff --git a/port/pusb2/freertos/usb_dc_glue_phytium.c b/port/pusb2/freertos/usb_dc_glue_phytium.c
index 4e674ecd..6013e443 100644
--- a/port/pusb2/freertos/usb_dc_glue_phytium.c
+++ b/port/pusb2/freertos/usb_dc_glue_phytium.c
@@ -1,11 +1,11 @@
/*
- * Copyright : (C) 2024 Phytium Information Technology, Inc.
+ * Copyright : (C) 2024 Phytium Information Technology, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
- * Modify History:
- * Ver   Who        Date         Changes
- * ----- ------     --------    --------------------------------------
+ * Modify History:
+ * Ver Who Date Changes
+ * ----- ------ -------- --------------------------------------
* 1.0 zhugengyu 2024/6/26 first commit
*/
@@ -19,123 +19,89 @@
#include "fcpu_info.h"
#include "fdebug.h"
#include "fcache.h"
-#include "fmemory_pool.h"
#include "usbd_core.h"
-/************************** Constant Definitions *****************************/
-#define USB_MEMP_TOTAL_SIZE SZ_1M
-
-/**************************** Type Definitions *******************************/
+/************************** Function Declarations ***************************/
void USBD_IRQHandler(uint8_t busid);
-/************************** Variable Definitions *****************************/
-static FMemp memp;
-static u8 memp_buf[USB_MEMP_TOTAL_SIZE] __attribute__((aligned(8))) = {0};
-
-void usb_sys_mem_init(void)
-{
- if (FT_COMPONENT_IS_READY != memp.is_ready)
- {
- USB_ASSERT(FT_SUCCESS == FMempInit(&memp, &memp_buf[0], &memp_buf[0] + USB_MEMP_TOTAL_SIZE));
- }
-}
-
-void usb_sys_mem_deinit(void)
-{
- if (FT_COMPONENT_IS_READY == memp.is_ready)
- {
- FMempDeinit(&memp);
- }
-}
-
-void *usb_sys_malloc_align(size_t align, size_t size)
-{
- void *result = FMempMallocAlign(&memp, size, align);
+extern void usb_sys_mem_init(void);
+extern void usb_sys_mem_deinit(void);
+extern void usb_sys_mem_inc_ref(void);
+extern u32 usb_sys_mem_dec_ref(void);
+extern u8 usb_otg_is_active(void);
- if (result)
- {
- memset(result, 0U, size);
- }
-
- return result;
-}
-
-void *usb_sys_mem_malloc(size_t size)
-{
- return usb_sys_malloc_align(sizeof(void *), size);
-}
-
-void usb_sys_mem_free(void *ptr)
-{
- if (NULL != ptr)
- {
- FMempFree(&memp, ptr);
- }
-}
-
-void usb_assert(const char *filename, int linenum)
-{
- FAssert(filename, linenum, 0xff);
-}
+/************************** Function Implementations *************************/
static void usb_dc_pusb2_interrupt_handler(s32 vector, void *param)
{
+ (void)param;
+ FASSERT(vector == FUSB2_0_VHUB_IRQ_NUM);
USBD_IRQHandler(CONFIG_USB_PUSB2_BUS_ID);
}
static void usb_dc_setup_pusb2_interrupt(u32 id)
{
u32 cpu_id;
- USB_ASSERT(id == FUSB2_ID_VHUB_0);
- u32 irq_num = FUSB2_0_VHUB_IRQ_NUM;
+ FASSERT(id == CONFIG_USB_PUSB2_BUS_ID);
u32 irq_priority = 13U;
GetCpuId(&cpu_id);
- InterruptSetTargetCpus(irq_num, cpu_id);
+ InterruptSetTargetCpus(FUSB2_0_VHUB_IRQ_NUM, cpu_id);
- InterruptSetPriority(irq_num, irq_priority);
+ InterruptSetPriority(FUSB2_0_VHUB_IRQ_NUM, irq_priority);
/* register intr callback */
- InterruptInstall(irq_num,
+ InterruptInstall(FUSB2_0_VHUB_IRQ_NUM,
usb_dc_pusb2_interrupt_handler,
NULL,
NULL);
/* enable irq */
- InterruptUmask(irq_num);
+ InterruptUmask(FUSB2_0_VHUB_IRQ_NUM);
}
static void usb_dc_revoke_pusb2_interrupt(u32 id)
{
- USB_ASSERT(id == FUSB2_ID_VHUB_0);
- u32 irq_num = FUSB2_0_VHUB_IRQ_NUM;
+ FASSERT(id == CONFIG_USB_PUSB2_BUS_ID);
/* disable irq */
- InterruptMask(irq_num);
-}
-
-extern int vApplicationInIrq(void);
-int xPortIsInsideInterrupt(void)
-{
- return vApplicationInIrq();
+ InterruptMask(FUSB2_0_VHUB_IRQ_NUM);
}
unsigned long usb_dc_get_register_base(uint32_t id)
{
- USB_ASSERT(id == FUSB2_ID_VHUB_0);
+ FASSERT(id == CONFIG_USB_PUSB2_BUS_ID);
return FUSB2_0_VHUB_BASE_ADDR;
}
/* implement cherryusb weak functions */
-void usb_dc_low_level_init()
+void usb_dc_low_level_init(void)
{
+ /* Initialize shared memory pool if not already done */
usb_sys_mem_init();
+ usb_sys_mem_inc_ref();
+
+ /* In OTG mode, the OTG interrupt handler is already installed by usb_otg_init.
+ * Skip installing DC-specific handler to avoid conflicts. */
+ if (usb_otg_is_active()) {
+ return;
+ }
+
usb_dc_setup_pusb2_interrupt(CONFIG_USB_PUSB2_BUS_ID);
}
void usb_dc_low_level_deinit(void)
{
+ /* Release memory pool if last user */
+ if (usb_sys_mem_dec_ref()) {
+ usb_sys_mem_deinit();
+ }
+
+ /* In OTG mode, do not revoke interrupt - OTG handles it */
+ if (usb_otg_is_active()) {
+ return;
+ }
+
usb_dc_revoke_pusb2_interrupt(CONFIG_USB_PUSB2_BUS_ID);
- usb_sys_mem_deinit();
-}
+} \ No newline at end of file
diff --git a/port/pusb2/freertos/usb_glue_phytium.c b/port/pusb2/freertos/usb_glue_phytium.c
new file mode 100644
index 00000000..b61f4001
--- /dev/null
+++ b/port/pusb2/freertos/usb_glue_phytium.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright : (C) 2024 Phytium Information Technology, Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Modify History:
+ * Ver Who Date Changes
+ * ----- ------ -------- --------------------------------------
+ * 1.0 zhugengyu 2024/6/26 first commit
+ */
+
+/***************************** Include Files *********************************/
+#include <stdio.h>
+#include <string.h>
+
+#include "fassert.h"
+#include "fparameters.h"
+#include "finterrupt.h"
+#include "fcpu_info.h"
+#include "fdebug.h"
+#include "fcache.h"
+#include "fmemory_pool.h"
+#include "usb_config.h"
+
+#ifdef CONFIG_USB_OTG_ENABLE
+#include "FreeRTOS.h"
+#include "task.h"
+#include "usbotg_core.h"
+#endif
+
+extern void cps_otg_switch_to_host(uintptr_t reg_base);
+extern void cps_otg_switch_to_device(uintptr_t reg_base);
+extern uint8_t cps_otg_read_state(uintptr_t reg_base);
+
+/************************** Constant Definitions *****************************/
+#define USB_MEMP_TOTAL_SIZE SZ_1M
+
+/**************************** Type Definitions *******************************/
+
+/************************** Variable Definitions *****************************/
+static FMemp memp;
+static u8 memp_buf[USB_MEMP_TOTAL_SIZE] __attribute__((aligned(8))) = { 0 };
+
+/* Memory pool reference counter - shared between DC and HC */
+static u32 memp_ref_cnt = 0;
+
+/* OTG mode flag: set when OTG is initialized */
+static u8 g_otg_mode_active = 0;
+
+/************************** Function Implementations *************************/
+
+/**
+ * @brief Initialize USB system memory pool
+ *
+ * Called by both DC and HC low_level_init. Memory pool is created on first call.
+ */
+void usb_sys_mem_init(void)
+{
+ if (FT_COMPONENT_IS_READY != memp.is_ready) {
+ FASSERT(FT_SUCCESS == FMempInit(&memp, &memp_buf[0], &memp_buf[0] + USB_MEMP_TOTAL_SIZE));
+ }
+}
+
+/**
+ * @brief Deinitialize USB system memory pool
+ *
+ * Called by both DC and HC low_level_deinit. Memory pool is destroyed when
+ * last user releases it.
+ */
+void usb_sys_mem_deinit(void)
+{
+ if (FT_COMPONENT_IS_READY == memp.is_ready) {
+ FMempDeinit(&memp);
+ }
+}
+
+/**
+ * @brief Allocate aligned memory from USB memory pool
+ */
+void *usb_sys_malloc_align(size_t align, size_t size)
+{
+ void *result = FMempMallocAlign(&memp, size, align);
+
+ if (result) {
+ memset(result, 0U, size);
+ }
+
+ return result;
+}
+
+/**
+ * @brief Allocate memory from USB memory pool (aligned to void*)
+ */
+void *usb_sys_mem_malloc(size_t size)
+{
+ return usb_sys_malloc_align(sizeof(void *), size);
+}
+
+/**
+ * @brief Free memory back to USB memory pool
+ */
+void usb_sys_mem_free(void *ptr)
+{
+ if (NULL != ptr) {
+ FMempFree(&memp, ptr);
+ }
+}
+
+/**
+ * @brief USB assert handler
+ */
+void usb_assert(const char *filename, int linenum)
+{
+ FAssert(filename, linenum, 0xff);
+}
+
+/**
+ * @brief Increment memory pool reference counter
+ *
+ * Called by DC/HC low_level_init to track memory pool users.
+ */
+void usb_sys_mem_inc_ref(void)
+{
+ memp_ref_cnt++;
+}
+
+/**
+ * @brief Decrement memory pool reference counter
+ *
+ * Called by DC/HC low_level_deinit. When counter reaches 0,
+ * memory pool is deinitialized.
+ * @return 1 if this was the last user (pool deinitialized), 0 otherwise
+ */
+u32 usb_sys_mem_dec_ref(void)
+{
+ if (memp_ref_cnt > 0) {
+ memp_ref_cnt--;
+ }
+ return (memp_ref_cnt == 0) ? 1 : 0;
+}
+
+/**
+ * @brief Get current memory pool reference count
+ */
+u32 usb_sys_mem_get_ref(void)
+{
+ return memp_ref_cnt;
+}
+
+/**
+ * @brief Check if running inside interrupt context
+ */
+extern int vApplicationInIrq(void);
+int xPortIsInsideInterrupt(void)
+{
+ return vApplicationInIrq();
+}
+
+/**
+ * @brief Check if OTG mode is active
+ */
+u8 usb_otg_is_active(void)
+{
+ return g_otg_mode_active;
+}
+
+/**
+ * @brief Set OTG mode active flag
+ */
+void usb_otg_set_active(u8 active)
+{
+ g_otg_mode_active = active;
+}
+
+#ifdef CONFIG_USB_OTG_ENABLE
+/**
+ * @brief Get USB OTG register base address
+ */
+unsigned long usb_otg_get_register_base(uint32_t id)
+{
+ FASSERT(id == CONFIG_USB_PUSB2_BUS_ID);
+ return FUSB2_0_VHUB_BASE_ADDR;
+}
+
+/* External declaration for OTG IRQ handler provided by usbotg_core.c */
+extern void USBOTG_IRQHandler(uint8_t busid);
+
+/**
+ * @brief OTG interrupt handler for PUSB2
+ */
+static void usb_otg_pusb2_interrupt_handler(s32 vector, void *param)
+{
+ (void)param;
+ FASSERT(vector == FUSB2_0_VHUB_IRQ_NUM);
+ USBOTG_IRQHandler((uint8_t)CONFIG_USB_PUSB2_BUS_ID);
+}
+
+/**
+ * @brief Install OTG interrupt for PUSB2
+ */
+static void usb_otg_setup_interrupt(void)
+{
+ u32 cpu_id;
+ u32 irq_num = FUSB2_0_VHUB_IRQ_NUM;
+ u32 irq_priority = 13U;
+
+ GetCpuId(&cpu_id);
+ InterruptSetTargetCpus(irq_num, cpu_id);
+
+ InterruptSetPriority(irq_num, irq_priority);
+
+ /* Register OTG interrupt callback */
+ InterruptInstall(irq_num,
+ usb_otg_pusb2_interrupt_handler,
+ NULL,
+ NULL);
+
+ /* Enable IRQ */
+ InterruptUmask(irq_num);
+
+ FT_DEBUG_PRINT_I("OTG-GLUE", "Installed OTG interrupt, irq=%d\r\n", irq_num);
+}
+
+/**
+ * @brief Initialize USB OTG hardware
+ */
+int usb_otg_init(uint8_t busid)
+{
+ FASSERT(busid == CONFIG_USB_PUSB2_BUS_ID);
+
+ /* Install OTG interrupt handler */
+ usb_otg_setup_interrupt();
+
+ usb_otg_set_active(1);
+ return 0;
+}
+
+/**
+ * @brief Deinitialize USB OTG hardware
+ */
+int usb_otg_deinit(uint8_t busid)
+{
+ FASSERT(busid == CONFIG_USB_PUSB2_BUS_ID);
+ usb_otg_set_active(0);
+ return 0;
+}
+
+/**
+ * @brief Switch USB OTG to Host mode
+ */
+void usb_otg_switch_to_host(uint8_t busid)
+{
+ uintptr_t reg_base = usb_otg_get_register_base(busid);
+ cps_otg_switch_to_host(reg_base);
+}
+
+/**
+ * @brief Switch USB OTG to Device mode
+ */
+void usb_otg_switch_to_device(uint8_t busid)
+{
+ uintptr_t reg_base = usb_otg_get_register_base(busid);
+ cps_otg_switch_to_device(reg_base);
+}
+
+/* ==================== OTG Auto (software polling) ==================== */
+
+#define OTG_AUTO_POLL_MS 500
+
+enum {
+ OTG_STATE_A_IDLE = 0x00,
+ OTG_STATE_A_HOST = 0x03,
+ OTG_STATE_B_IDLE = 0x10,
+ OTG_STATE_B_PERIPHERAL = 0x11,
+};
+
+static int otg_auto_running = 0;
+static uint8_t otg_auto_role = USBOTG_MODE_HOST;
+
+static void otg_auto_poll_task(void *param)
+{
+ uint8_t busid = *(uint8_t *)param;
+ uintptr_t reg_base = usb_otg_get_register_base(busid);
+ int idle_ticks = 0;
+
+ vTaskDelay(pdMS_TO_TICKS(300));
+
+ while (otg_auto_running) {
+ uint8_t state = cps_otg_read_state(reg_base);
+ uint8_t role = 0;
+ int need_switch = 0;
+ int target_role = 0;
+
+ switch (state) {
+ case OTG_STATE_A_HOST:
+ role = USBOTG_MODE_HOST;
+ break;
+ case OTG_STATE_B_PERIPHERAL:
+ role = USBOTG_MODE_DEVICE;
+ break;
+ default:
+ break;
+ }
+
+ if (role) {
+ /* hardware detected a role: Host (U-disk) or Device (PC) */
+ idle_ticks = 0;
+ if (otg_auto_role != role) {
+ need_switch = 1;
+ target_role = role;
+ }
+ } else if (otg_auto_role == USBOTG_MODE_DEVICE) {
+ /* role == 0 means nothing connected to either side.
+ * If we're in Device mode, Host was killed; re-init so
+ * VBUS comes back and U-disk can be powered/detected. */
+ idle_ticks++;
+ if (idle_ticks >= 1) {
+ need_switch = 1;
+ target_role = USBOTG_MODE_HOST;
+ idle_ticks = 0;
+ }
+ }
+
+ if (need_switch) {
+ otg_auto_role = target_role;
+ usbotg_trigger_role_change(busid, target_role);
+ FT_DEBUG_PRINT_I("OTG-AUTO", "-> %s\r\n",
+ target_role == USBOTG_MODE_HOST ? "Host" : "Device");
+ }
+
+ vTaskDelay(pdMS_TO_TICKS(OTG_AUTO_POLL_MS));
+ }
+ vTaskDelete(NULL);
+}
+
+static TaskHandle_t g_otg_poll_task = NULL;
+
+int usb_otg_auto_poll_start(uint8_t busid, int default_role)
+{
+ static uint8_t busid_arg;
+
+ otg_auto_role = default_role;
+ otg_auto_running = 1;
+ busid_arg = busid;
+
+ (void)xTaskCreate(otg_auto_poll_task,
+ "otgapol",
+ 4096U,
+ &busid_arg,
+ configMAX_PRIORITIES - 2,
+ &g_otg_poll_task);
+ return 0;
+}
+
+void usb_otg_auto_poll_stop(void)
+{
+ otg_auto_running = 0;
+ if (g_otg_poll_task) {
+ vTaskDelay(pdMS_TO_TICKS(OTG_AUTO_POLL_MS + 100));
+ g_otg_poll_task = NULL;
+ }
+}
+
+uint8_t usb_otg_auto_get_role(void)
+{
+ return otg_auto_role;
+}
+
+#endif /* CONFIG_USB_OTG_ENABLE */ \ No newline at end of file
diff --git a/port/pusb2/freertos/usb_hc_glue_phytium.c b/port/pusb2/freertos/usb_hc_glue_phytium.c
index 58a90af1..617837a3 100644
--- a/port/pusb2/freertos/usb_hc_glue_phytium.c
+++ b/port/pusb2/freertos/usb_hc_glue_phytium.c
@@ -1,11 +1,11 @@
/*
- * Copyright : (C) 2024 Phytium Information Technology, Inc.
+ * Copyright : (C) 2024 Phytium Information Technology, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
- * Modify History:
- * Ver   Who        Date         Changes
- * ----- ------     --------    --------------------------------------
+ * Modify History:
+ * Ver Who Date Changes
+ * ----- ------ -------- --------------------------------------
* 1.0 zhugengyu 2024/6/26 first commit
*/
@@ -19,72 +19,27 @@
#include "fcpu_info.h"
#include "fdebug.h"
#include "fcache.h"
-#include "fmemory_pool.h"
#include "usbh_core.h"
-/************************** Constant Definitions *****************************/
-#define USB_MEMP_TOTAL_SIZE SZ_1M
-
-/**************************** Type Definitions *******************************/
-void USBH_IRQHandler(uint8_t busid);
+/************************** Function Declarations ***************************/
+extern void USBH_IRQHandler(uint8_t busid);
+extern void usb_sys_mem_init(void);
+extern void usb_sys_mem_deinit(void);
+extern void usb_sys_mem_inc_ref(void);
+extern u32 usb_sys_mem_dec_ref(void);
+extern u8 usb_otg_is_active(void);
/************************** Variable Definitions *****************************/
-static FMemp memp;
-static u8 memp_buf[USB_MEMP_TOTAL_SIZE] __attribute__((aligned(8))) = {0};
-static u32 memp_ref_cnt = 0;
static const u32 irq_nums[] = {
FUSB2_0_VHUB_IRQ_NUM, FUSB2_1_IRQ_NUM, FUSB2_2_IRQ_NUM
};
-void usb_sys_mem_init(void)
-{
- if (FT_COMPONENT_IS_READY != memp.is_ready)
- {
- USB_ASSERT(FT_SUCCESS == FMempInit(&memp, &memp_buf[0], &memp_buf[0] + USB_MEMP_TOTAL_SIZE));
- }
-}
-
-void usb_sys_mem_deinit(void)
-{
- if (FT_COMPONENT_IS_READY == memp.is_ready)
- {
- FMempDeinit(&memp);
- }
-}
-
-void *usb_sys_malloc_align(size_t align, size_t size)
-{
- void *result = FMempMallocAlign(&memp, size, align);
-
- if (result)
- {
- memset(result, 0U, size);
- }
-
- return result;
-}
-
-void *usb_sys_mem_malloc(size_t size)
-{
- return usb_sys_malloc_align(sizeof(void *), size);
-}
-
-void usb_sys_mem_free(void *ptr)
-{
- if (NULL != ptr)
- {
- FMempFree(&memp, ptr);
- }
-}
-
-void usb_assert(const char *filename, int linenum)
-{
- FAssert(filename, linenum, 0xff);
-}
+/************************** Function Implementations *************************/
static void usb_hc_pusb2_interrupt_handler(s32 vector, void *param)
{
+ (void)param;
if (vector == FUSB2_0_VHUB_IRQ_NUM) {
USBH_IRQHandler(FUSB2_ID_VHUB_0);
} else if (vector == FUSB2_1_IRQ_NUM) {
@@ -127,23 +82,29 @@ static void usb_hc_revoke_pusb2_interrupt(u32 id)
void usb_hc_low_level_init(struct usbh_bus *bus)
{
- if (memp_ref_cnt == 0) {
- usb_sys_mem_init(); /* create memory pool before first bus init */
- }
-
- memp_ref_cnt++; /* one more bus is using the memory pool */
+ /* Initialize shared memory pool if not already done */
+ usb_sys_mem_init();
+ usb_sys_mem_inc_ref();
+ /* In OTG mode, the OTG interrupt handler is already installed by usb_otg_init.
+ * Skip installing HC-specific handler to avoid conflicts. */
+ if (usb_otg_is_active()) {
+ return;
+ }
usb_hc_setup_pusb2_interrupt(bus->busid);
}
void usb_hc_low_level_deinit(struct usbh_bus *bus)
{
- memp_ref_cnt--; /* one more bus is leaving */
-
- if (memp_ref_cnt == 0) {
- usb_sys_mem_deinit(); /* release memory pool after the last bus left */
+ /* Release memory pool if last user */
+ if (usb_sys_mem_dec_ref()) {
+ usb_sys_mem_deinit();
}
+ /* In OTG mode, do not revoke interrupt - OTG handles it */
+ if (usb_otg_is_active()) {
+ return;
+ }
usb_hc_revoke_pusb2_interrupt(bus->busid);
}
@@ -156,10 +117,5 @@ unsigned long usb_hc_get_register_base(uint32_t id)
} else if (id == FUSB2_ID_2) {
return FUSB2_2_BASE_ADDR;
}
-}
-
-extern int vApplicationInIrq(void);
-int xPortIsInsideInterrupt(void)
-{
- return vApplicationInIrq();
+ return 0;
} \ No newline at end of file
diff --git a/port/pusb2/libpusb2_dc_a32_hardfp.a b/port/pusb2/libpusb2_dc_a32_hardfp.a
index 685de412..ed767f7f 100644
--- a/port/pusb2/libpusb2_dc_a32_hardfp.a
+++ b/port/pusb2/libpusb2_dc_a32_hardfp.a
Binary files differ
diff --git a/port/pusb2/libpusb2_dc_a32_softfp_crypto-neon-fp-armv8.a b/port/pusb2/libpusb2_dc_a32_softfp_crypto-neon-fp-armv8.a
new file mode 100644
index 00000000..f690766c
--- /dev/null
+++ b/port/pusb2/libpusb2_dc_a32_softfp_crypto-neon-fp-armv8.a
Binary files differ
diff --git a/port/pusb2/libpusb2_dc_a32_softfp_crypto_neon.a b/port/pusb2/libpusb2_dc_a32_softfp_crypto_neon.a
deleted file mode 100644
index f0e1ceb7..00000000
--- a/port/pusb2/libpusb2_dc_a32_softfp_crypto_neon.a
+++ /dev/null
Binary files differ
diff --git a/port/pusb2/libpusb2_dc_a32_softfp_neon.a b/port/pusb2/libpusb2_dc_a32_softfp_neon.a
deleted file mode 100644
index f4d15803..00000000
--- a/port/pusb2/libpusb2_dc_a32_softfp_neon.a
+++ /dev/null
Binary files differ
diff --git a/port/pusb2/libpusb2_dc_a64.a b/port/pusb2/libpusb2_dc_a64.a
index 3e4ea124..67a7627a 100644
--- a/port/pusb2/libpusb2_dc_a64.a
+++ b/port/pusb2/libpusb2_dc_a64.a
Binary files differ
diff --git a/port/pusb2/libpusb2_hc_a32_hardfp.a b/port/pusb2/libpusb2_hc_a32_hardfp.a
index 7e029a61..ed96171d 100644
--- a/port/pusb2/libpusb2_hc_a32_hardfp.a
+++ b/port/pusb2/libpusb2_hc_a32_hardfp.a
Binary files differ
diff --git a/port/pusb2/libpusb2_hc_a32_softfp_crypto-neon-fp-armv8.a b/port/pusb2/libpusb2_hc_a32_softfp_crypto-neon-fp-armv8.a
new file mode 100644
index 00000000..c3d1ce8f
--- /dev/null
+++ b/port/pusb2/libpusb2_hc_a32_softfp_crypto-neon-fp-armv8.a
Binary files differ
diff --git a/port/pusb2/libpusb2_hc_a32_softfp_crypto_neon.a b/port/pusb2/libpusb2_hc_a32_softfp_crypto_neon.a
deleted file mode 100644
index dea366e9..00000000
--- a/port/pusb2/libpusb2_hc_a32_softfp_crypto_neon.a
+++ /dev/null
Binary files differ
diff --git a/port/pusb2/libpusb2_hc_a32_softfp_neon.a b/port/pusb2/libpusb2_hc_a32_softfp_neon.a
deleted file mode 100644
index 172f9695..00000000
--- a/port/pusb2/libpusb2_hc_a32_softfp_neon.a
+++ /dev/null
Binary files differ
diff --git a/port/pusb2/libpusb2_hc_a64.a b/port/pusb2/libpusb2_hc_a64.a
index 575d1dca..f65fabbf 100644
--- a/port/pusb2/libpusb2_hc_a64.a
+++ b/port/pusb2/libpusb2_hc_a64.a
Binary files differ
diff --git a/port/pusb2/libpusb2_otg_a32_hardfp.a b/port/pusb2/libpusb2_otg_a32_hardfp.a
new file mode 100644
index 00000000..cf65d4c5
--- /dev/null
+++ b/port/pusb2/libpusb2_otg_a32_hardfp.a
Binary files differ
diff --git a/port/pusb2/libpusb2_otg_a32_softfp_crypto-neon-fp-armv8.a b/port/pusb2/libpusb2_otg_a32_softfp_crypto-neon-fp-armv8.a
new file mode 100644
index 00000000..dbd769a3
--- /dev/null
+++ b/port/pusb2/libpusb2_otg_a32_softfp_crypto-neon-fp-armv8.a
Binary files differ
diff --git a/port/pusb2/libpusb2_otg_a64.a b/port/pusb2/libpusb2_otg_a64.a
new file mode 100644
index 00000000..b36cf5c3
--- /dev/null
+++ b/port/pusb2/libpusb2_otg_a64.a
Binary files differ
diff --git a/port/pusb2/rt-thread/usb_config.h b/port/pusb2/rt-thread/usb_config.h
index ec8faa2e..2682d0a2 100644
--- a/port/pusb2/rt-thread/usb_config.h
+++ b/port/pusb2/rt-thread/usb_config.h
@@ -12,7 +12,6 @@
#define CHERRYUSB_CONFIG_H
#include "rtconfig.h"
-#include <rtthread.h>
/* ================ USB common Configuration ================ */
@@ -22,9 +21,9 @@ void *usb_sys_mem_malloc(size_t size);
void usb_sys_mem_free(void *ptr);
void *usb_sys_malloc_align(size_t align, size_t size);
-#define usb_malloc(size) usb_sys_mem_malloc(size)
-#define usb_free(ptr) usb_sys_mem_free(ptr)
-#define usb_align(align, size) usb_sys_malloc_align(align, size)
+#define usb_malloc(size) usb_sys_mem_malloc(size)
+#define usb_free(ptr) usb_sys_mem_free(ptr)
+#define usb_align(align, size) usb_sys_malloc_align(align, size)
unsigned long usb_hc_get_register_base(uint32_t id);
unsigned long usb_dc_get_register_base(uint32_t id);
@@ -260,7 +259,7 @@ unsigned long usb_dc_get_register_base(uint32_t id);
#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
/* ---------------- PUSB2 Configuration ---------------- */
-#define CONFIG_USB_PUSB2_BUS_NUM 3U
-#define CONFIG_USB_PUSB2_BUS_ID 0U
+#define CONFIG_USB_PUSB2_BUS_NUM 3U
+#define CONFIG_USB_PUSB2_BUS_ID 0U
#endif
diff --git a/port/pusb2/rt-thread/usb_dc_glue_phytium.c b/port/pusb2/rt-thread/usb_dc_glue_phytium.c
index 49088d95..fdcf3004 100644
--- a/port/pusb2/rt-thread/usb_dc_glue_phytium.c
+++ b/port/pusb2/rt-thread/usb_dc_glue_phytium.c
@@ -86,9 +86,4 @@ void *usb_sys_malloc_align(size_t align, size_t size)
}
return buf;
-}
-
-int usbd_set_remote_wakeup(uint8_t busid)
-{
- return -1;
} \ No newline at end of file
diff --git a/port/pusb2/standalone/usb_config.h b/port/pusb2/standalone/usb_config.h
index e4fbc4e7..7e6bd902 100644
--- a/port/pusb2/standalone/usb_config.h
+++ b/port/pusb2/standalone/usb_config.h
@@ -21,9 +21,9 @@ void *usb_sys_mem_malloc(size_t size);
void usb_sys_mem_free(void *ptr);
void *usb_sys_malloc_align(size_t align, size_t size);
-#define usb_malloc(size) usb_sys_mem_malloc(size)
-#define usb_free(ptr) usb_sys_mem_free(ptr)
-#define usb_align(align, size) usb_sys_malloc_align(align, size)
+#define usb_malloc(size) usb_sys_mem_malloc(size)
+#define usb_free(ptr) usb_sys_mem_free(ptr)
+#define usb_align(align, size) usb_sys_malloc_align(align, size)
unsigned long usb_dc_get_register_base(uint32_t id);
@@ -269,7 +269,7 @@ void usb_osal_leave_critical_section(size_t flag);
#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
/* ---------------- PUSB2 Configuration ---------------- */
-#define CONFIG_USB_PUSB2_BUS_NUM 1U
-#define CONFIG_USB_PUSB2_BUS_ID 0U
+#define CONFIG_USB_PUSB2_BUS_NUM 1U
+#define CONFIG_USB_PUSB2_BUS_ID 0U
#endif
diff --git a/port/pusb2/standalone/usb_dc_glue_phytium.c b/port/pusb2/standalone/usb_dc_glue_phytium.c
index b21375c9..bf5f8cb3 100644
--- a/port/pusb2/standalone/usb_dc_glue_phytium.c
+++ b/port/pusb2/standalone/usb_dc_glue_phytium.c
@@ -19,32 +19,31 @@
#include "fdebug.h"
#include "fcache.h"
#include "fmemory_pool.h"
+#include "fsleep.h"
#include "usbd_core.h"
/************************** Constant Definitions *****************************/
-#define USB_MEMP_TOTAL_SIZE SZ_1M
+#define USB_MEMP_TOTAL_SIZE SZ_1M
/**************************** Type Definitions *******************************/
void USBD_IRQHandler(uint8_t busid);
/************************** Variable Definitions *****************************/
static FMemp memp;
-static u8 memp_buf[USB_MEMP_TOTAL_SIZE] __attribute__((aligned(8))) = {0};
+static u8 memp_buf[USB_MEMP_TOTAL_SIZE] __attribute__((aligned(8))) = { 0 };
static void usb_sys_mem_init(void)
{
- if (FT_COMPONENT_IS_READY != memp.is_ready)
- {
+ if (FT_COMPONENT_IS_READY != memp.is_ready) {
USB_ASSERT(FT_SUCCESS == FMempInit(&memp, &memp_buf[0], &memp_buf[0] + USB_MEMP_TOTAL_SIZE));
}
}
static void usb_sys_mem_deinit(void)
{
- if (FT_COMPONENT_IS_READY == memp.is_ready)
- {
- FMempRemove(&memp);
+ if (FT_COMPONENT_IS_READY == memp.is_ready) {
+ FMempDeinit(&memp);
}
}
@@ -52,8 +51,7 @@ void *usb_sys_malloc_align(size_t align, size_t size)
{
void *result = FMempMallocAlign(&memp, size, align);
- if (result)
- {
+ if (result) {
memset(result, 0U, size);
}
@@ -67,8 +65,7 @@ void *usb_sys_mem_malloc(size_t size)
void usb_sys_mem_free(void *ptr)
{
- if (NULL != ptr)
- {
+ if (NULL != ptr) {
FMempFree(&memp, ptr);
}
}
@@ -133,12 +130,16 @@ void usb_dc_low_level_deinit(void)
usb_dc_revoke_pusb2_interrupt(CONFIG_USB_PUSB2_BUS_ID);
}
-size_t usb_osal_enter_critical_section(void)
+size_t usb_osal_enter_critical_section(void)
{
return 0;
}
-void usb_osal_leave_critical_section(size_t flag)
+void usb_osal_leave_critical_section(size_t flag)
{
-
+}
+
+void usb_osal_msleep(uint32_t delay)
+{
+ fsleep_millisec(delay);
} \ No newline at end of file
diff --git a/port/pusb3/README.md b/port/pusb3/README.md
new file mode 100644
index 00000000..05610d81
--- /dev/null
+++ b/port/pusb3/README.md
@@ -0,0 +1,57 @@
+# USB OTG 控制器 (PUSB3)
+
+- PD2408 平台上提供 PUSB3 接口,例程包括
+
+---------------------------------------------
+
+- Host 模式
+
+- - 1. [FreeRTOS 上作为主机使用键盘/鼠标/U盘](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_host/README.md)
+- - 2. [RT-Thread 上作为主机识别键盘/鼠标/U盘](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
+
+---------------------------------------------
+
+- Device 模式
+
+- - 1. [裸机上模拟为一个 U 盘](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/usb_device/README.md)
+- - 2. [裸机上模拟为一个虚拟串口](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/usb_device/README.md)
+- - 3. [FreeRTOS 上模拟为一个 U 盘](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_device/README.md)
+- - 4. [FreeRTOS 上模拟为虚拟串口](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_device/README.md)
+- - 5. [RT-Thread 上模拟为一个 U 盘](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
+
+---------------------------------------------
+
+- PUSB3 的驱动功能以静态库的方式提供,
+- - libpusb3_hc_a64.a : AARCH64 主机模式驱动库
+- - libpusb3_dc_a64.a : AARCH64 从机模式驱动库
+
+需要获取源代码请联系 `[email protected]` 获取
+
+# USB OTG Controller (PUSB3)
+
+- PD2408 platform provides PUSB3 interface. Example programs include:
+
+---
+
+### Host Mode
+1. [Use keyboard/mouse/USB drive as host on FreeRTOS](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_host/README.md)
+2. [Recognize keyboard/mouse/USB drive as host on RT-Thread](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
+
+---
+
+### Device Mode
+1. [Emulate USB drive on bare-metal](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/usb_device/README.md)
+2. [Emulate virtual serial port on bare-metal](https://gitee.com/phytium_embedded/phytium-standalone-sdk/tree/master/example/peripherals/usb/usb_device/README.md)
+3. [Emulate USB drive on FreeRTOS](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_device/README.md)
+4. [Emulate virtual serial port on FreeRTOS](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_device/README.md)
+5. [Emulate USB drive on RT-Thread](https://github.com/RT-Thread/rt-thread/blob/master/bsp/phytium/doc/use_cherryusb.md)
+
+---
+
+### Driver Libraries
+PUSB3 driver is provided as static libraries:
+- `libpusb3_hc_a64.a`: AARCH64 host mode driver
+- `libpusb3_dc_a64.a`: AARCH64 device mode driver
+
+**Source Code Access**
+Contact [`[email protected]`](mailto:[email protected]) \ No newline at end of file
diff --git a/port/pusb3/freertos/usb_config.h b/port/pusb3/freertos/usb_config.h
new file mode 100644
index 00000000..5162e197
--- /dev/null
+++ b/port/pusb3/freertos/usb_config.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef CHERRYUSB_CONFIG_H
+#define CHERRYUSB_CONFIG_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "sdkconfig.h"
+#include "fparameters.h"
+
+/* ================ USB common Configuration ================ */
+
+#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__)
+
+void *usb_sys_mem_malloc(size_t size);
+void usb_sys_mem_free(void *ptr);
+void *usb_sys_malloc_align(size_t align, size_t size);
+unsigned long usb_hc_get_register_base(uint32_t id);
+unsigned long usb_dc_get_register_base(uint32_t id);
+unsigned long usb_otg_get_register_base(uint32_t id);
+void usb_dc_disable_interrupt(uint32_t id);
+void usb_dc_enable_interrupt(uint32_t id);
+void usb_hc_disable_interrupt(uint32_t id);
+void usb_hc_enable_interrupt(uint32_t id);
+
+#define usb_malloc(size) usb_sys_mem_malloc(size)
+#define usb_calloc(num, size) usb_sys_mem_malloc((num) * (size))
+#define usb_free(ptr) usb_sys_mem_free(ptr)
+#define usb_align(align, size) usb_sys_malloc_align(align, size)
+
+#ifndef CONFIG_USB_DBG_LEVEL
+#if defined(CONFIG_LOG_ERROR)
+#define CONFIG_USB_DBG_LEVEL USB_DBG_ERROR
+#elif defined(CONFIG_LOG_WARN)
+#define CONFIG_USB_DBG_LEVEL USB_DBG_WARNING
+#elif defined(CONFIG_LOG_INFO)
+#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
+#elif defined(CONFIG_LOG_DEBUG) || defined(CONFIG_LOG_VERBOS)
+#define CONFIG_USB_DBG_LEVEL USB_DBG_LOG
+#elif defined(CONFIG_LOG_NONE)
+#define CONFIG_USB_DBG_LEVEL USB_DBG_ERROR
+#undef CONFIG_USB_PRINTF
+#define CONFIG_USB_PRINTF(...)
+#else
+#define CONFIG_USB_DBG_LEVEL USB_DBG_ERROR
+#endif
+#endif
+
+#define CONFIG_USBDEV_ADVANCE_DESC
+
+/* Enable print with color */
+#define CONFIG_USB_PRINTF_COLOR_ENABLE
+
+/* data align size when use dma or use dcache */
+#ifndef CONFIG_USB_ALIGN_SIZE
+#define CONFIG_USB_ALIGN_SIZE 4
+#endif
+
+/* attribute data into no cache ram */
+#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
+
+/* ================= USB Device Stack Configuration ================ */
+
+/* Ep0 in and out transfer buffer */
+#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
+#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
+#endif
+
+#ifndef CONFIG_USBDEV_EP0_PRIO
+#define CONFIG_USBDEV_EP0_PRIO 4
+#endif
+
+#ifndef CONFIG_USBDEV_EP0_STACKSIZE
+#define CONFIG_USBDEV_EP0_STACKSIZE 2048
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MAX_LUN
+#define CONFIG_USBDEV_MSC_MAX_LUN 1
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
+#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 8192
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
+#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
+#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
+#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_PRIO
+#define CONFIG_USBDEV_MSC_PRIO 4
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_STACKSIZE
+#define CONFIG_USBDEV_MSC_STACKSIZE 2048
+#endif
+
+/* ================ USB HOST Stack Configuration ================== */
+
+#define CONFIG_USBHOST_MAX_RHPORTS 2
+#define CONFIG_USBHOST_MAX_EXTHUBS 4
+#define CONFIG_USBHOST_MAX_EHPORTS 8
+#define CONFIG_USBHOST_MAX_INTERFACES 8
+#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
+#define CONFIG_USBHOST_MAX_ENDPOINTS 8
+
+#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_DEV_NAMELEN 16
+
+#ifndef CONFIG_USBHOST_PSC_PRIO
+#define CONFIG_USBHOST_PSC_PRIO 0
+#endif
+#ifndef CONFIG_USBHOST_PSC_STACKSIZE
+#define CONFIG_USBHOST_PSC_STACKSIZE 8192
+#endif
+
+#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE
+#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
+#endif
+
+/* Ep0 max transfer buffer */
+#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN
+#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512
+#endif
+
+#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
+#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
+#endif
+
+#ifndef CONFIG_USBHOST_MSC_TIMEOUT
+#define CONFIG_USBHOST_MSC_TIMEOUT 0xffffffff
+#endif
+
+#ifndef CONFIG_INPUT_MOUSE_WHEEL
+#define CONFIG_INPUT_MOUSE_WHEEL
+#endif
+
+/* ================ USB Device Port Configuration ================*/
+
+#ifndef CONFIG_USBDEV_MAX_BUS
+#define CONFIG_USBDEV_MAX_BUS 1 /* for now, bus num must be 1 except hpm ip */
+#endif
+
+#ifndef CONFIG_USBDEV_EP_NUM
+#define CONFIG_USBDEV_EP_NUM 8
+#endif
+
+/* When your chip hardware supports high-speed and wants to initialize it in high-speed mode, the relevant IP will configure the internal or external high-speed PHY according to CONFIG_USB_HS. */
+#ifndef CONFIG_USB_HS
+#define CONFIG_USB_HS
+#endif
+
+/* ================ USB Host Port Configuration ==================*/
+#ifndef CONFIG_USBHOST_MAX_BUS
+#define CONFIG_USBHOST_MAX_BUS 7
+#endif
+
+#ifndef CONFIG_USBHOST_OTG_BUS_ID
+#define CONFIG_USBHOST_OTG_BUS_ID 0
+#endif
+
+#ifndef CONFIG_USBHOST_PIPE_NUM
+#define CONFIG_USBHOST_PIPE_NUM 10
+#endif
+
+/* XHCI deferred interrupt thread priority (0 = highest, CherryUSB
+ * convention; must match hub priority PSC_PRIO) */
+#ifndef CONFIG_USB_XHCI_IRQ_PRIO
+#define CONFIG_USB_XHCI_IRQ_PRIO 0
+#endif
+
+/* GIC interrupt priority: must be >= configMAX_API_CALL_INTERRUPT_PRIORITY
+ * so xSemaphoreGiveFromISR from a hard ISR is well-defined */
+#define USB_XHCI_GIC_IRQ_PRIO 13U
+#ifdef configMAX_API_CALL_INTERRUPT_PRIORITY
+_Static_assert(USB_XHCI_GIC_IRQ_PRIO >= configMAX_API_CALL_INTERRUPT_PRIORITY,
+ "XHCI GIC irq priority must be >= configMAX_API_CALL_INTERRUPT_PRIORITY");
+#endif
+
+/* ================ USB Dcache Configuration ==================*/
+
+#endif \ No newline at end of file
diff --git a/port/pusb3/freertos/usb_glue_dc_phytium.c b/port/pusb3/freertos/usb_glue_dc_phytium.c
new file mode 100644
index 00000000..0e2f9949
--- /dev/null
+++ b/port/pusb3/freertos/usb_glue_dc_phytium.c
@@ -0,0 +1,38 @@
+#include "usbd_core.h"
+#include "ftypes.h"
+#include "fparameters.h"
+
+void usb_sys_mem_init(void);
+void usb_sys_mem_deinit(void);
+void usb_dc_setup_pusb3_interrupt(u32 id);
+void usb_dc_revoke_pusb3_interrupt(u32 id);
+
+extern u8 usb_otg_is_active(void);
+extern void usb_dc_setup_pusb3_dev_interrupt(u32 id);
+
+void usb_dc_low_level_init(void)
+{
+ usb_sys_mem_init();
+
+ if (usb_otg_is_active()) {
+ /* OTG IRQ already installed by usb_otg_init.
+ * Only install the DC IRQ here. */
+ usb_dc_setup_pusb3_dev_interrupt(FUSB_ID_0);
+ } else {
+ usb_dc_setup_pusb3_interrupt(FUSB_ID_0);
+ }
+}
+
+void usb_dc_low_level_deinit(void)
+{
+ usb_dc_revoke_pusb3_interrupt(FUSB_ID_0);
+ usb_sys_mem_deinit();
+}
+
+__WEAK void USBOTG_IRQHandler(uint8_t busid)
+{
+}
+
+__WEAK void USBD_IRQHandler(uint8_t busid)
+{
+}
diff --git a/port/pusb3/freertos/usb_glue_hc_phytium.c b/port/pusb3/freertos/usb_glue_hc_phytium.c
new file mode 100644
index 00000000..90314c70
--- /dev/null
+++ b/port/pusb3/freertos/usb_glue_hc_phytium.c
@@ -0,0 +1,43 @@
+#include "usbh_core.h"
+#include "ftypes.h"
+
+static u32 memp_ref_cnt = 0;
+
+void usb_sys_mem_init(void);
+void usb_sys_mem_deinit(void);
+void usb_hc_setup_interrupt(u32 id);
+void usb_hc_revoke_interrupt(u32 id);
+void usb_hc_port_poll_stop(u32 id);
+void cusb_callout_drain_resource_init(void);
+
+void usb_hc_low_level_init(struct usbh_bus *bus)
+{
+ if (memp_ref_cnt == 0) {
+ usb_sys_mem_init(); /* create memory pool before first bus init */
+ cusb_callout_drain_resource_init(); /* init global drain lock/semaphore */
+ }
+
+ memp_ref_cnt++; /* one more bus is using the memory pool */
+
+ usb_hc_setup_interrupt(bus->busid);
+}
+
+void usb_hc_low_level_deinit(struct usbh_bus *bus)
+{
+ memp_ref_cnt--; /* one more bus is leaving */
+
+ usb_hc_port_poll_stop(bus->busid);
+ usb_hc_revoke_interrupt(bus->busid);
+
+ if (memp_ref_cnt == 0) {
+ usb_sys_mem_deinit(); /* release memory pool after the last bus left */
+ }
+}
+
+__WEAK void USBOTG_IRQHandler(uint8_t busid)
+{
+}
+
+__WEAK void USBH_IRQHandler(uint8_t busid)
+{
+} \ No newline at end of file
diff --git a/port/pusb3/freertos/usb_glue_phytium.c b/port/pusb3/freertos/usb_glue_phytium.c
new file mode 100644
index 00000000..033b8573
--- /dev/null
+++ b/port/pusb3/freertos/usb_glue_phytium.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright : (C) 2024 Phytium Information Technology, Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Modify History:
+ * Ver   Who        Date         Changes
+ * ----- ------     --------    --------------------------------------
+ * 1.0 zhugengyu 2024/6/26 first commit
+ */
+/***************************** Include Files *********************************/
+#include <stdio.h>
+#include <string.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+#include "timers.h"
+#include "usb_config.h"
+#include "usb_log.h"
+#include "usb_osal.h"
+#include "fassert.h"
+#include "fparameters.h"
+#include "finterrupt.h"
+#include "fcpu_info.h"
+#include "fdebug.h"
+#include "fcache.h"
+#include "fmemory_pool.h"
+#include "fsleep.h"
+
+/************************** Constant Definitions *****************************/
+#define USB_MEMP_TOTAL_SIZE SZ_1M
+
+/**************************** Type Definitions *******************************/
+void USBD_IRQHandler(uint8_t busid);
+void USBOTG_IRQHandler(uint8_t busid);
+
+/************************** Variable Definitions *****************************/
+static FMemp memp;
+static u8 memp_buf[USB_MEMP_TOTAL_SIZE] __attribute__((section(".noncacheable"), aligned(8))) = { 0 };
+
+/* XHCI deferred interrupt thread + port poll timer: hard ISR only
+ * wakes the IRQ task, so lock/semaphore calls run in thread context */
+#define USB_XHCI_IRQ_TASK_STACK 8192U
+static SemaphoreHandle_t s_xhci_irq_sem[FUSB_TOT_NUM] = { NULL };
+static TimerHandle_t s_port_poll_timer[FUSB_TOT_NUM] = { NULL };
+
+/* OTG mode flag: set by usb_otg_init so glue layers can skip duplicate IRQ setup */
+static u8 g_otg_mode_active = 0;
+
+u8 usb_otg_is_active(void)
+{
+ return g_otg_mode_active;
+}
+
+void usb_otg_set_active(u8 active)
+{
+ g_otg_mode_active = active;
+}
+
+void usb_sys_mem_init(void)
+{
+ if (FT_COMPONENT_IS_READY != memp.is_ready) {
+ FASSERT(FT_SUCCESS == FMempInit(&memp, &memp_buf[0], &memp_buf[0] + USB_MEMP_TOTAL_SIZE));
+ }
+}
+
+void usb_sys_mem_deinit(void)
+{
+ if (FT_COMPONENT_IS_READY == memp.is_ready) {
+ FMempDeinit(&memp);
+ }
+}
+
+void *usb_sys_malloc_align(size_t align, size_t size)
+{
+ void *result = FMempMallocAlign(&memp, size, align);
+
+ if (result) {
+ memset(result, 0U, size);
+ } else {
+ USB_LOG_ERR("malloc_align: fail size=%u align=%u\n", (unsigned)size, (unsigned)align);
+ }
+
+ return result;
+}
+
+void *usb_sys_mem_malloc(size_t size)
+{
+ return usb_sys_malloc_align(sizeof(void *), size);
+}
+
+void usb_sys_mem_free(void *ptr)
+{
+ if (NULL != ptr) {
+ FMempFree(&memp, ptr);
+ }
+}
+
+void usb_assert(const char *filename, int linenum)
+{
+ FAssert(filename, linenum, 0xff);
+}
+
+unsigned long usb_get_register_base(uint32_t id)
+{
+ unsigned long base_reg[FUSB_TOT_NUM] = {
+ FUSB_0_BASE_ADDR,
+ FUSB_1_BASE_ADDR,
+ FUSB_2_BASE_ADDR,
+ FUSB_3_BASE_ADDR,
+ FUSB_4_BASE_ADDR,
+ FUSB_5_BASE_ADDR,
+ FUSB_6_BASE_ADDR,
+ };
+
+ FASSERT(id < FUSB_TOT_NUM);
+ return base_reg[id];
+}
+
+unsigned long usb_otg_get_register_base(uint32_t id)
+{
+ return usb_get_register_base(id) + FUSB_OTG_REG_OFF;
+}
+
+unsigned long usb_dc_get_register_base(uint32_t id)
+{
+ return usb_get_register_base(id) + FUSB_OTG_DC_REG_OFF;
+}
+
+unsigned long usb_hc_get_register_base(uint32_t id)
+{
+ return usb_get_register_base(id) + FUSB_OTG_HC_REG_OFFSET;
+}
+
+uint32_t usb_dc_get_dev_irq_num(uint32_t id)
+{
+ uint32_t irq_num[FUSB3_OTG_3X2_GEN2_NUM] = {
+ FUSB_0_HC_DC_IRQ_NUM,
+ };
+
+ FASSERT(id < FUSB3_OTG_3X2_GEN2_NUM);
+ return irq_num[id];
+}
+
+uint32_t usb_hc_get_irq_num(uint32_t id)
+{
+ uint32_t irq_num[FUSB_TOT_NUM] = {
+ FUSB_0_HC_DC_IRQ_NUM,
+ FUSB_1_IRQ_NUM,
+ FUSB_2_IRQ_NUM,
+ FUSB_3_IRQ_NUM,
+ FUSB_4_IRQ_NUM,
+ FUSB_5_IRQ_NUM,
+ FUSB_6_IRQ_NUM
+ };
+
+ FASSERT(id < FUSB_TOT_NUM);
+ return irq_num[id];
+}
+
+uint32_t usb_dc_get_otg_irq_num(uint32_t id)
+{
+ uint32_t irq_num[FUSB_TOT_NUM] = {
+ FUSB_0_OTG_IRQ_NUM,
+ };
+
+ FASSERT(id < FUSB_TOT_NUM);
+ return irq_num[id];
+}
+
+static void usb_pusb3_dc_interrupt_handler(s32 vector, void *param)
+{
+ (void)vector;
+ USBD_IRQHandler((uint8_t)(uintptr_t)param);
+}
+
+static void usb_pusb3_otg_interrupt_handler(s32 vector, void *param)
+{
+ (void)vector;
+ USBOTG_IRQHandler((uint8_t)(uintptr_t)param);
+}
+
+void usb_dc_disable_interrupt(u32 id)
+{
+ u32 irq_num = usb_dc_get_dev_irq_num(id);
+
+ InterruptMask(irq_num);
+}
+
+void usb_dc_enable_interrupt(u32 id)
+{
+ u32 irq_num = usb_dc_get_dev_irq_num(id);
+
+ InterruptUmask(irq_num);
+}
+
+void usb_dc_setup_pusb3_interrupt(u32 id)
+{
+ u32 cpu_id;
+ u32 irq_num = usb_dc_get_dev_irq_num(id);
+ u32 irq_priority = USB_XHCI_GIC_IRQ_PRIO;
+
+ GetCpuId(&cpu_id);
+ InterruptSetTargetCpus(irq_num, cpu_id);
+
+ InterruptSetPriority(irq_num, irq_priority);
+
+ /* register intr callback */
+ InterruptInstall(irq_num,
+ usb_pusb3_dc_interrupt_handler,
+ (void *)(uintptr_t)id,
+ NULL);
+
+ irq_num = usb_dc_get_otg_irq_num(id);
+
+ InterruptSetTargetCpus(irq_num, cpu_id);
+
+ InterruptSetPriority(irq_num, irq_priority);
+
+ /* register intr callback */
+ InterruptInstall(irq_num,
+ usb_pusb3_otg_interrupt_handler,
+ (void *)(uintptr_t)id,
+ NULL);
+}
+
+void usb_dc_setup_pusb3_dev_interrupt(u32 id)
+{
+ u32 cpu_id;
+ u32 irq_num = usb_dc_get_dev_irq_num(id);
+ u32 irq_priority = USB_XHCI_GIC_IRQ_PRIO;
+
+ GetCpuId(&cpu_id);
+ InterruptSetTargetCpus(irq_num, cpu_id);
+ InterruptSetPriority(irq_num, irq_priority);
+
+ InterruptInstall(irq_num,
+ usb_pusb3_dc_interrupt_handler,
+ (void *)(uintptr_t)id,
+ NULL);
+}
+
+void usb_dc_revoke_pusb3_interrupt(u32 id)
+{
+ u32 irq_num = usb_dc_get_dev_irq_num(id);
+
+ /* disable irq */
+ InterruptMask(irq_num);
+}
+
+void usb_hc_disable_interrupt(u32 id)
+{
+ u32 irq_num = usb_hc_get_irq_num(id);
+
+ InterruptMask(irq_num);
+}
+
+void usb_hc_enable_interrupt(u32 id)
+{
+ u32 irq_num = usb_hc_get_irq_num(id);
+
+ InterruptUmask(irq_num);
+}
+
+/* Port poll timer callback: forwards pending PORTSC change bits */
+static void cusb_port_poll_timer_cb(TimerHandle_t handle)
+{
+ extern void cusb_xhci_port_poll(uint8_t busid);
+
+ cusb_xhci_port_poll((uint8_t)(uintptr_t)pvTimerGetTimerID(handle));
+}
+
+/* Deferred IRQ task: runs USBH_IRQHandler in thread context */
+static void usb_hc_xhci_irq_task(void *arg)
+{
+ uint32_t id = (uint32_t)(uintptr_t)arg;
+ extern void USBH_IRQHandler(uint8_t busid);
+
+ for (;;) {
+ if (s_xhci_irq_sem[id] == NULL) {
+ USB_LOG_ERR("xhci_irq sem NULL id=%lu\n", (unsigned long)id);
+ while (1)
+ ;
+ }
+ xSemaphoreTake(s_xhci_irq_sem[id], portMAX_DELAY);
+ USBH_IRQHandler((uint8_t)id);
+ }
+}
+
+static void usb_hc_xhci_interrupt_handler(s32 vector, void *param)
+{
+ uint32_t id = (uint32_t)(uintptr_t)param;
+ BaseType_t higher_prio_woken = pdFALSE;
+ extern void cusb_xhci_irq_ack(uint8_t busid);
+
+ (void)vector;
+
+ /* Ack at controller level only (IMAN.IP); port changes arrive as
+ * PSC TRBs on the event ring and are handled in the IRQ thread. */
+ cusb_xhci_irq_ack((uint8_t)id);
+
+ if (s_xhci_irq_sem[id] != NULL) {
+ xSemaphoreGiveFromISR(s_xhci_irq_sem[id], &higher_prio_woken);
+ portYIELD_FROM_ISR(higher_prio_woken);
+ }
+}
+
+void usb_hc_setup_interrupt(u32 id)
+{
+ u32 cpu_id;
+ u32 irq_num = usb_hc_get_irq_num(id);
+ u32 irq_priority = USB_XHCI_GIC_IRQ_PRIO;
+ char task_name[configMAX_TASK_NAME_LEN];
+
+ if (s_xhci_irq_sem[id] == NULL) {
+ s_xhci_irq_sem[id] = xSemaphoreCreateBinary();
+ FASSERT(s_xhci_irq_sem[id] != NULL);
+ snprintf(task_name, sizeof(task_name), "xhci_irq%lu", (unsigned long)id);
+ FASSERT(usb_osal_thread_create(task_name, USB_XHCI_IRQ_TASK_STACK,
+ CONFIG_USB_XHCI_IRQ_PRIO, usb_hc_xhci_irq_task,
+ (void *)(uintptr_t)id) != NULL);
+ }
+
+ /* Port poll timer: deterministic event fallback; deinit stops it
+ * but never deletes it. */
+ if (s_port_poll_timer[id] == NULL) {
+ s_port_poll_timer[id] = xTimerCreate("usb_poll",
+ pdMS_TO_TICKS(100), pdTRUE,
+ (void *)(uintptr_t)id, cusb_port_poll_timer_cb);
+ FASSERT(s_port_poll_timer[id] != NULL);
+ }
+ xTimerStart(s_port_poll_timer[id], portMAX_DELAY);
+
+ GetCpuId(&cpu_id);
+ InterruptSetTargetCpus(irq_num, cpu_id);
+
+ InterruptSetPriority(irq_num, irq_priority);
+
+ /* register intr callback */
+ InterruptInstall(irq_num,
+ usb_hc_xhci_interrupt_handler,
+ (void *)(uintptr_t)id,
+ NULL);
+}
+
+void usb_hc_port_poll_stop(u32 id)
+{
+ /* stop polling so it cannot wake the hub after detach */
+ if (s_port_poll_timer[id] != NULL) {
+ xTimerStop(s_port_poll_timer[id], portMAX_DELAY);
+ }
+}
+
+void usb_hc_revoke_interrupt(u32 id)
+{
+ u32 irq_num = usb_hc_get_irq_num(id);
+
+ /* disable irq */
+ InterruptMask(irq_num);
+
+ irq_num = usb_dc_get_otg_irq_num(id);
+
+ /* disable irq */
+ InterruptMask(irq_num);
+}
+
+extern int vApplicationInIrq(void);
+int xPortIsInsideInterrupt(void)
+{
+ return vApplicationInIrq();
+}
+
+void usb_pusb3_msleep(uint32_t delay)
+{
+ fsleep_millisec(delay);
+}
+
+#ifdef CONFIG_USB_OTG_ENABLE
+
+extern void USBOTG_IRQHandler(uint8_t busid);
+
+static void usb_pusb3_otg_irq_handler(s32 vector, void *param)
+{
+ (void)vector;
+ USBOTG_IRQHandler((uint8_t)(uintptr_t)param);
+}
+
+int usb_otg_init(uint8_t busid)
+{
+ u32 cpu_id;
+ u32 irq_num = FUSB_0_OTG_IRQ_NUM;
+
+ FASSERT(busid == FUSB_ID_0);
+ usb_otg_set_active(1);
+
+ GetCpuId(&cpu_id);
+ InterruptSetTargetCpus(irq_num, cpu_id);
+ InterruptSetPriority(irq_num, USB_XHCI_GIC_IRQ_PRIO);
+ InterruptInstall(irq_num, usb_pusb3_otg_irq_handler, (void *)(uintptr_t)busid, NULL);
+ InterruptUmask(irq_num);
+
+ return 0;
+}
+
+int usb_otg_deinit(uint8_t busid)
+{
+ FASSERT(busid == FUSB_ID_0);
+ InterruptMask(FUSB_0_OTG_IRQ_NUM);
+ usb_otg_set_active(0);
+ return 0;
+}
+
+/* PUSB3 does not support AUTO mode. Provide stubs so common OTG
+ * code (status command, stop) can call these unconditionally. */
+#define USBOTG_MODE_HOST 0
+#define USBOTG_MODE_DEVICE 1
+
+int usb_otg_auto_poll_start(uint8_t busid, int default_role)
+{
+ (void)busid;
+ (void)default_role;
+ printf("OTG Auto mode is not supported on PUSB3, use manual mode\n");
+ return -1;
+}
+
+void usb_otg_auto_poll_stop(void)
+{
+}
+
+uint8_t usb_otg_auto_get_role(void)
+{
+ return USBOTG_MODE_HOST;
+}
+
+#endif /* CONFIG_USB_OTG_ENABLE */
+
+/* Strong dcache definitions override the weak empty stubs in
+ * fpusb3/core.c, required by the device framework DMA map pre/post sync. */
+void xhci_dcache_flush(void *addr, size_t size)
+{
+ FCacheDCacheFlushRange((uintptr_t)addr, size);
+}
+
+void xhci_dcache_invalidate(void *addr, size_t size)
+{
+ FCacheDCacheInvalidateRange((uintptr_t)addr, size);
+} \ No newline at end of file
diff --git a/port/pusb3/libpusb3_dc_a64.a b/port/pusb3/libpusb3_dc_a64.a
new file mode 100644
index 00000000..eb1f81ee
--- /dev/null
+++ b/port/pusb3/libpusb3_dc_a64.a
Binary files differ
diff --git a/port/pusb3/libpusb3_hc_a64.a b/port/pusb3/libpusb3_hc_a64.a
new file mode 100644
index 00000000..d84e860a
--- /dev/null
+++ b/port/pusb3/libpusb3_hc_a64.a
Binary files differ
diff --git a/port/pusb3/libpusb3_otg_a64.a b/port/pusb3/libpusb3_otg_a64.a
new file mode 100644
index 00000000..720c6689
--- /dev/null
+++ b/port/pusb3/libpusb3_otg_a64.a
Binary files differ
diff --git a/port/pusb3/standalone/usb_config.h b/port/pusb3/standalone/usb_config.h
new file mode 100644
index 00000000..9bb677c7
--- /dev/null
+++ b/port/pusb3/standalone/usb_config.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2022, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef CHERRYUSB_CONFIG_H
+#define CHERRYUSB_CONFIG_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "sdkconfig.h"
+#include "fparameters.h"
+
+/* ================ USB common Configuration ================ */
+#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__)
+
+void *usb_sys_mem_malloc(size_t size);
+void usb_sys_mem_free(void *ptr);
+void *usb_sys_malloc_align(size_t align, size_t size);
+unsigned long usb_dc_get_register_base(uint32_t id);
+unsigned long usb_otg_get_register_base(uint32_t id);
+void usb_dc_disable_interrupt(uint32_t id);
+void usb_dc_enable_interrupt(uint32_t id);
+
+#define usb_malloc(size) usb_sys_mem_malloc(size)
+#define usb_calloc(num, size) usb_sys_mem_malloc((num) * (size))
+#define usb_free(ptr) usb_sys_mem_free(ptr)
+#define usb_align(align, size) usb_sys_malloc_align(align, size)
+
+#ifndef CONFIG_USB_DBG_LEVEL
+#if defined(CONFIG_LOG_ERROR)
+#define CONFIG_USB_DBG_LEVEL USB_DBG_ERROR
+#elif defined(CONFIG_LOG_WARN)
+#define CONFIG_USB_DBG_LEVEL USB_DBG_WARNING
+#elif defined(CONFIG_LOG_INFO)
+#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
+#elif defined(CONFIG_LOG_DEBUG) || defined(CONFIG_LOG_VERBOS)
+#define CONFIG_USB_DBG_LEVEL USB_DBG_LOG
+#elif defined(CONFIG_LOG_NONE)
+#define CONFIG_USB_DBG_LEVEL USB_DBG_ERROR
+#undef CONFIG_USB_PRINTF
+#define CONFIG_USB_PRINTF(...)
+#else
+#define CONFIG_USB_DBG_LEVEL USB_DBG_ERROR
+#endif
+#endif
+
+#ifndef CONFIG_USB_HS
+#define CONFIG_USB_HS
+#endif
+
+#define CONFIG_USBDEV_ADVANCE_DESC
+
+/* Enable print with color */
+#define CONFIG_USB_PRINTF_COLOR_ENABLE
+
+/* data align size when use dma or use dcache */
+#ifndef CONFIG_USB_ALIGN_SIZE
+#define CONFIG_USB_ALIGN_SIZE 4
+#endif
+
+//#define CONFIG_USB_DCACHE_ENABLE
+
+/* attribute data into no cache ram */
+#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
+
+/* ================= USB Device Stack Configuration ================ */
+
+/* Ep0 in and out transfer buffer */
+#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
+#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
+#endif
+
+#ifndef CONFIG_USBDEV_EP0_PRIO
+#define CONFIG_USBDEV_EP0_PRIO 4
+#endif
+
+#ifndef CONFIG_USBDEV_EP0_STACKSIZE
+#define CONFIG_USBDEV_EP0_STACKSIZE 2048
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MAX_LUN
+#define CONFIG_USBDEV_MSC_MAX_LUN 1
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
+#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 8192
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
+#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
+#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
+#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_PRIO
+#define CONFIG_USBDEV_MSC_PRIO 4
+#endif
+
+#ifndef CONFIG_USBDEV_MSC_STACKSIZE
+#define CONFIG_USBDEV_MSC_STACKSIZE 2048
+#endif
+
+/* ================ USB HOST Stack Configuration ================== */
+
+/* ================ USB Device Port Configuration ================*/
+
+#ifndef CONFIG_USBDEV_MAX_BUS
+#define CONFIG_USBDEV_MAX_BUS 1 /* for now, bus num must be 1 except hpm ip */
+#endif
+
+#ifndef CONFIG_USBDEV_EP_NUM
+#define CONFIG_USBDEV_EP_NUM 8
+#endif
+
+/* When your chip hardware supports high-speed and wants to initialize it in high-speed mode, the relevant IP will configure the internal or external high-speed PHY according to CONFIG_USB_HS. */
+#ifndef CONFIG_USB_HS
+#define CONFIG_USB_HS
+#endif
+
+/* ================ USB Dcache Configuration ==================*/
+
+#endif
diff --git a/port/pusb3/standalone/usb_glue_phytium.c b/port/pusb3/standalone/usb_glue_phytium.c
new file mode 100644
index 00000000..984fb3b7
--- /dev/null
+++ b/port/pusb3/standalone/usb_glue_phytium.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright : (C) 2024 Phytium Information Technology, Inc.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Modify History:
+ * Ver   Who        Date         Changes
+ * ----- ------     --------    --------------------------------------
+ * 1.0 zhugengyu 2024/6/26 first commit
+ */
+/***************************** Include Files *********************************/
+#include <stdio.h>
+#include <string.h>
+
+#include "fassert.h"
+#include "fparameters.h"
+#include "finterrupt.h"
+#include "fcpu_info.h"
+#include "fdebug.h"
+#include "fcache.h"
+#include "fsleep.h"
+#include "fmemory_pool.h"
+
+#include "usbd_core.h"
+
+/************************** Constant Definitions *****************************/
+#define USB_MEMP_TOTAL_SIZE SZ_1M
+
+/**************************** Type Definitions *******************************/
+void USBD_IRQHandler(uint8_t busid);
+void USBOTG_IRQHandler(uint8_t busid);
+
+/************************** Variable Definitions *****************************/
+static FMemp memp;
+static u8 memp_buf[USB_MEMP_TOTAL_SIZE] __attribute__((aligned(8))) = { 0 };
+
+static void usb_sys_mem_init(void)
+{
+ if (FT_COMPONENT_IS_READY != memp.is_ready) {
+ FASSERT(FT_SUCCESS == FMempInit(&memp, &memp_buf[0], &memp_buf[0] + USB_MEMP_TOTAL_SIZE));
+ }
+}
+
+static void usb_sys_mem_deinit(void)
+{
+ if (FT_COMPONENT_IS_READY == memp.is_ready) {
+ FMempDeinit(&memp);
+ }
+}
+
+void *usb_sys_malloc_align(size_t align, size_t size)
+{
+ void *result = FMempMallocAlign(&memp, size, align);
+
+ if (result) {
+ memset(result, 0U, size);
+ }
+
+ return result;
+}
+
+void *usb_sys_mem_malloc(size_t size)
+{
+ return usb_sys_malloc_align(sizeof(void *), size);
+}
+
+void usb_sys_mem_free(void *ptr)
+{
+ if (NULL != ptr) {
+ FMempFree(&memp, ptr);
+ }
+}
+
+void usb_assert(const char *filename, int linenum)
+{
+ FAssert(filename, linenum, 0xff);
+}
+
+unsigned long usb_get_register_base(uint32_t id)
+{
+ unsigned long base_reg[FUSB_TOT_NUM] = {
+ FUSB_0_BASE_ADDR,
+ FUSB_1_BASE_ADDR,
+ FUSB_2_BASE_ADDR,
+ FUSB_3_BASE_ADDR,
+ FUSB_4_BASE_ADDR,
+ FUSB_5_BASE_ADDR,
+ FUSB_6_BASE_ADDR,
+ };
+
+ FASSERT(id < FUSB_TOT_NUM);
+ return base_reg[id];
+}
+
+unsigned long usb_otg_get_register_base(uint32_t id)
+{
+ FASSERT(id < FUSB3_OTG_3X2_GEN2_NUM);
+ return usb_get_register_base(id) + FUSB_OTG_REG_OFF;
+}
+
+unsigned long usb_dc_get_register_base(uint32_t id)
+{
+ FASSERT(id < FUSB3_OTG_3X2_GEN2_NUM);
+ return usb_get_register_base(id) + FUSB_OTG_DC_REG_OFF;
+}
+
+unsigned long usb_hc_get_register_base(uint32_t id)
+{
+ return usb_get_register_base(id) + FUSB_OTG_HC_REG_OFFSET;
+}
+
+uint32_t usb_dc_get_dev_irq_num(uint32_t id)
+{
+ uint32_t irq_num[FUSB3_OTG_3X2_GEN2_NUM] = {
+ FUSB_0_HC_DC_IRQ_NUM,
+ };
+
+ FASSERT(id < FUSB3_OTG_3X2_GEN2_NUM);
+ return irq_num[id];
+}
+
+uint32_t usb_dc_get_otg_irq_num(uint32_t id)
+{
+ uint32_t irq_num[FUSB3_OTG_3X2_GEN2_NUM] = {
+ FUSB_0_OTG_IRQ_NUM,
+ };
+
+ FASSERT(id < FUSB3_OTG_3X2_GEN2_NUM);
+ return irq_num[id];
+}
+
+static void usb_pusb3_dc_interrupt_handler(s32 vector, void *param)
+{
+ uintptr_t bus_id = (uintptr_t)param;
+ USBD_IRQHandler((uint8_t)bus_id);
+}
+
+static void usb_pusb3_otg_interrupt_handler(s32 vector, void *param)
+{
+ uintptr_t bus_id = (uintptr_t)param;
+ USBOTG_IRQHandler((uint8_t)bus_id);
+}
+
+void usb_dc_disable_interrupt(u32 id)
+{
+ u32 irq_num = usb_dc_get_dev_irq_num(id);
+
+ InterruptMask(irq_num);
+}
+
+void usb_dc_enable_interrupt(u32 id)
+{
+ u32 irq_num = usb_dc_get_dev_irq_num(id);
+
+ InterruptUmask(irq_num);
+}
+
+static void usb_dc_setup_pusb3_interrupt(u32 id)
+{
+ u32 cpu_id;
+ u32 irq_num = usb_dc_get_dev_irq_num(id);
+ u32 irq_priority = 0U;
+
+ GetCpuId(&cpu_id);
+ InterruptSetTargetCpus(irq_num, cpu_id);
+
+ InterruptSetPriority(irq_num, irq_priority);
+
+ /* register intr callback */
+ InterruptInstall(irq_num,
+ usb_pusb3_dc_interrupt_handler,
+ (void *)(uintptr_t)id,
+ NULL);
+
+ irq_num = usb_dc_get_otg_irq_num(id);
+
+ InterruptSetTargetCpus(irq_num, cpu_id);
+
+ InterruptSetPriority(irq_num, irq_priority);
+
+ /* register intr callback */
+ InterruptInstall(irq_num,
+ usb_pusb3_otg_interrupt_handler,
+ (void *)(uintptr_t)id,
+ NULL);
+}
+
+static void usb_dc_revoke_pusb3_interrupt(u32 id)
+{
+ u32 irq_num = usb_dc_get_dev_irq_num(id);
+
+ /* disable irq */
+ InterruptMask(irq_num);
+
+ irq_num = usb_dc_get_otg_irq_num(id);
+
+ /* disable irq */
+ InterruptMask(irq_num);
+}
+
+void usb_dc_low_level_init(void)
+{
+ usb_sys_mem_init();
+ usb_dc_setup_pusb3_interrupt(0U);
+}
+
+void usb_dc_low_level_deinit(void)
+{
+ usb_dc_revoke_pusb3_interrupt(0U);
+ usb_sys_mem_deinit();
+}
+
+void usb_pusb3_msleep(uint32_t delay)
+{
+ fsleep_millisec(delay);
+}
+
+__WEAK void USBOTG_IRQHandler(uint8_t busid)
+{
+}
+
+__WEAK void USBD_IRQHandler(uint8_t busid)
+{
+}
+
+__WEAK void USBH_IRQHandler(uint8_t busid)
+{
+} \ No newline at end of file
diff --git a/port/rp2040/usb_hc_rp2040.c b/port/rp2040/usb_hc_rp2040.c
index e9751b88..4f4bd974 100644
--- a/port/rp2040/usb_hc_rp2040.c
+++ b/port/rp2040/usb_hc_rp2040.c
@@ -292,10 +292,7 @@ int usb_hc_init(struct usbh_bus *bus)
for (uint8_t i = 0; i <= USB_HOST_INTERRUPT_ENDPOINTS; i++) {
g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem = usb_osal_sem_create(0);
- if (g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem == NULL) {
- USB_LOG_ERR("Failed to create waitsem\r\n");
- return -USB_ERR_NOMEM;
- }
+ USB_ASSERT(g_rp2040_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem != NULL);
}
g_rp2040_hcd[bus->hcd.hcd_id].ep0_mutex = usb_osal_mutex_create();
@@ -591,6 +588,11 @@ int usbh_kill_urb(struct usbh_urb *urb)
flags = usb_osal_enter_critical_section();
pipe = (struct rp2040_pipe *)urb->hcpriv;
+ if (!pipe) {
+ usb_osal_leave_critical_section(flags);
+ return -USB_ERR_INVAL;
+ }
+
urb->errorcode = -USB_ERR_SHUTDOWN;
usb_hw_clear->int_ep_ctrl = 1 << pipe->chidx;
@@ -599,6 +601,8 @@ int usbh_kill_urb(struct usbh_urb *urb)
*pipe->endpoint_control = 0;
*pipe->buffer_control = 0;
+ usb_osal_leave_critical_section(flags);
+
if (urb->timeout) {
usb_osal_sem_give(pipe->waitsem);
} else {
@@ -609,8 +613,6 @@ int usbh_kill_urb(struct usbh_urb *urb)
urb->complete(urb->arg, urb->errorcode);
}
- usb_osal_leave_critical_section(flags);
-
return 0;
}
diff --git a/port/sunxi/README.md b/port/sunxi/README.md
new file mode 100644
index 00000000..379f4e4a
--- /dev/null
+++ b/port/sunxi/README.md
@@ -0,0 +1 @@
+**You can get source from official sdk.** \ No newline at end of file
diff --git a/port/wch/README.md b/port/wch/README.md
new file mode 100644
index 00000000..12141a70
--- /dev/null
+++ b/port/wch/README.md
@@ -0,0 +1,24 @@
+# Note
+
+> To compile support for CherryUSB on WCH chips, please refer to the repository: https://github.com/Links0617/wch-support-cherryusb.git
+
+## Support Chip List
+
+## USBFS
+
+- CH32L103
+- CH32M103
+- CH32F20x
+- CH32V20x
+- CH32V30x
+- CH32V31x
+- CH32H417
+
+## USBHS
+
+- CH32V205
+- CH32V4x7
+- CH32H417
+- CH32X305
+- CH58x
+- CH645
diff --git a/port/wch/usbfs/usb_dc_usbfs.c b/port/wch/usbfs/usb_dc_usbfs.c
new file mode 100644
index 00000000..bc3f3c94
--- /dev/null
+++ b/port/wch/usbfs/usb_dc_usbfs.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 2026, Links ([email protected])
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "usbd_core.h"
+#include "usb_usbfs_reg.h"
+
+#if defined(CONFIG_USBDEV_MULT_DC)
+#define usb_dc_init usbd_wch_usbfs_dc_init
+#define usb_dc_deinit usbd_wch_usbfs_dc_deinit
+#define usbd_set_address usbd_wch_usbfs_set_address
+#define usbd_set_remote_wakeup usbd_wch_usbfs_set_remote_wakeup
+#define usbd_get_port_speed usbd_wch_usbfs_get_port_speed
+#define usbd_ep_open usbd_wch_usbfs_ep_open
+#define usbd_ep_open_extra usbd_wch_usbfs_ep_open_extra
+#define usbd_ep_close usbd_wch_usbfs_ep_close
+#define usbd_ep_set_stall usbd_wch_usbfs_ep_set_stall
+#define usbd_ep_clear_stall usbd_wch_usbfs_ep_clear_stall
+#define usbd_ep_is_stalled usbd_wch_usbfs_ep_is_stalled
+#define usbd_ep_start_write usbd_wch_usbfs_ep_start_write
+#define usbd_ep_start_read usbd_wch_usbfs_ep_start_read
+#define USBD_IRQHandler usbd_wch_usbfs_irq_handler
+#endif
+
+#ifndef CONFIG_USBDEV_EP_NUM
+#define CONFIG_USBDEV_EP_NUM 8
+#endif
+
+#define USBFSD ((USBFSD_TypeDef *)g_usbdev_bus[busid].reg_base)
+#define ENDP_TX_LEN(ep) *((volatile uint16_t *)&(USBFSD->UEP0_TX_LEN) + (ep)*2)
+#define ENDP_TX_CTRL(ep) *((volatile uint8_t *)&(USBFSD->UEP0_TX_CTRL) + (ep)*4)
+#define ENDP_RX_CTRL(ep) *((volatile uint8_t *)&(USBFSD->UEP0_RX_CTRL) + (ep)*4)
+
+struct ch32_usbfs_ep_state {
+ uint8_t ep_type;
+ uint16_t ep_mps;
+ uint8_t *xfer_buf;
+ uint32_t xfer_len;
+ uint32_t actual_xfer_len;
+};
+
+struct ch32_usbfs_udc {
+ uint8_t dev_addr;
+ __attribute__((aligned(4))) struct usb_setup_packet setup;
+ struct ch32_usbfs_ep_state ep_in[CONFIG_USBDEV_EP_NUM];
+ struct ch32_usbfs_ep_state ep_out[CONFIG_USBDEV_EP_NUM];
+} g_ch32_usbfs_udc[CONFIG_USBDEV_MAX_BUS];
+
+static const uint32_t endp_mode_reg_offset[] = {
+ 0,
+ offsetof(USBFSD_TypeDef, UEP4_1_MOD),
+ offsetof(USBFSD_TypeDef, UEP2_3_MOD),
+ offsetof(USBFSD_TypeDef, UEP2_3_MOD),
+ offsetof(USBFSD_TypeDef, UEP4_1_MOD),
+ offsetof(USBFSD_TypeDef, UEP5_6_MOD),
+ offsetof(USBFSD_TypeDef, UEP5_6_MOD),
+ offsetof(USBFSD_TypeDef, UEP7_MOD),
+};
+
+static const uint8_t endp_mode_tx_en[] = {
+ 0,
+ USBFS_UEP1_TX_EN,
+ USBFS_UEP2_TX_EN,
+ USBFS_UEP3_TX_EN,
+ USBFS_UEP4_TX_EN,
+ USBFS_UEP5_TX_EN,
+ USBFS_UEP6_TX_EN,
+ USBFS_UEP7_TX_EN,
+};
+
+static const uint8_t endp_mode_rx_en[] = {
+ 0,
+ USBFS_UEP1_RX_EN,
+ USBFS_UEP2_RX_EN,
+ USBFS_UEP3_RX_EN,
+ USBFS_UEP4_RX_EN,
+ USBFS_UEP5_RX_EN,
+ USBFS_UEP6_RX_EN,
+ USBFS_UEP7_RX_EN,
+};
+
+static uint8_t *endp_tx_bufs[CONFIG_USBDEV_EP_NUM - 1];
+static uint8_t *endp_rx_bufs[CONFIG_USBDEV_EP_NUM - 1];
+static __attribute__((aligned(4))) uint8_t endp_xfer_bufs[CONFIG_USBDEV_EP_NUM - 1][64 + 64];
+
+extern void usb_dc_low_level_init(uint8_t busid);
+extern void usb_dc_low_level_deinit(uint8_t busid);
+
+int usb_dc_init(uint8_t busid)
+{
+ usb_dc_low_level_init(busid);
+
+ USBFSD->BASE_CTRL = 0x00;
+
+ USBFSD->UEP4_1_MOD = 0x00;
+ USBFSD->UEP2_3_MOD = 0x00;
+ USBFSD->UEP5_6_MOD = 0x00;
+ USBFSD->UEP7_MOD = 0x00;
+
+ USBFSD->UEP1_DMA = (uint32_t)endp_xfer_bufs[0];
+ USBFSD->UEP2_DMA = (uint32_t)endp_xfer_bufs[1];
+ USBFSD->UEP3_DMA = (uint32_t)endp_xfer_bufs[2];
+ USBFSD->UEP4_DMA = (uint32_t)endp_xfer_bufs[3];
+ USBFSD->UEP5_DMA = (uint32_t)endp_xfer_bufs[4];
+ USBFSD->UEP6_DMA = (uint32_t)endp_xfer_bufs[5];
+ USBFSD->UEP7_DMA = (uint32_t)endp_xfer_bufs[6];
+
+ USBFSD->INT_FG = 0xFF;
+ USBFSD->DEV_ADDR = 0x00;
+ USBFSD->INT_EN = USBFS_UIE_SUSPEND | USBFS_UIE_BUS_RST | USBFS_UIE_TRANSFER;
+
+ USBFSD->BASE_CTRL = USBFS_UC_DEV_PU_EN | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN;
+ USBFSD->UDEV_CTRL = USBFS_UD_PD_DIS | USBFS_UD_PORT_EN;
+ return 0;
+}
+
+int usb_dc_deinit(uint8_t busid)
+{
+ USBFSD->BASE_CTRL = 0;
+ usb_dc_low_level_deinit(busid);
+ return 0;
+}
+
+int usbd_set_address(uint8_t busid, const uint8_t addr)
+{
+ g_ch32_usbfs_udc[busid].dev_addr = addr;
+ return 0;
+}
+
+int usbd_set_remote_wakeup(uint8_t busid)
+{
+ return -1;
+}
+
+uint8_t usbd_get_port_speed(uint8_t busid)
+{
+ return (USBFSD->UDEV_CTRL & USBFS_UD_LOW_SPEED) ? USB_SPEED_LOW : USB_SPEED_FULL;
+}
+
+static inline void ch32_usbfs_update_ep_buf(uint8_t busid, uint8_t epid)
+{
+ __IO uint8_t *endp_mode_reg = (__IO uint8_t *)((uint32_t)USBFSD + endp_mode_reg_offset[epid]);
+ endp_rx_bufs[epid - 1] = &endp_xfer_bufs[epid - 1][0];
+ endp_tx_bufs[epid - 1] = (*endp_mode_reg & endp_mode_rx_en[epid]) ? &endp_xfer_bufs[epid - 1][64] : &endp_xfer_bufs[epid - 1][0];
+}
+
+int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
+{
+ uint8_t epid = USB_EP_GET_IDX(ep->bEndpointAddress);
+
+ if (epid >= CONFIG_USBDEV_EP_NUM) {
+ USB_LOG_ERR("Ep addr %02x overflow\r\n", ep->bEndpointAddress);
+ return -1;
+ }
+
+ __IO uint8_t *endp_mode_reg = (__IO uint8_t *)((uint32_t)USBFSD + endp_mode_reg_offset[epid]);
+
+ if (USB_EP_DIR_IS_IN(ep->bEndpointAddress)) {
+ g_ch32_usbfs_udc[busid].ep_in[epid].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
+ g_ch32_usbfs_udc[busid].ep_in[epid].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
+ if (epid) {
+ *endp_mode_reg |= endp_mode_tx_en[epid];
+ ch32_usbfs_update_ep_buf(busid, epid);
+ }
+ if (g_ch32_usbfs_udc[busid].ep_in[epid].ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ ENDP_TX_CTRL(epid) = USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_RES_NAK;
+ } else {
+ ENDP_TX_CTRL(epid) = USBFS_UEP_T_RES_NONE;
+ }
+ } else {
+ g_ch32_usbfs_udc[busid].ep_out[epid].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
+ g_ch32_usbfs_udc[busid].ep_out[epid].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
+ if (epid) {
+ *endp_mode_reg |= endp_mode_rx_en[epid];
+ ch32_usbfs_update_ep_buf(busid, epid);
+ }
+ if (g_ch32_usbfs_udc[busid].ep_out[epid].ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ ENDP_RX_CTRL(epid) = USBFS_UEP_R_AUTO_TOG | USBFS_UEP_R_RES_NAK;
+ } else {
+ ENDP_RX_CTRL(epid) = USBFS_UEP_R_RES_NONE;
+ }
+ }
+ return 0;
+}
+
+int usbd_ep_close(uint8_t busid, const uint8_t ep)
+{
+ uint8_t epid = USB_EP_GET_IDX(ep);
+
+ if (epid >= CONFIG_USBDEV_EP_NUM) {
+ USB_LOG_ERR("Ep addr %02x invalid\r\n", ep);
+ return -1;
+ }
+
+ if (epid) {
+ __IO uint8_t *endp_mode_reg = (__IO uint8_t *)((uint32_t)USBFSD + endp_mode_reg_offset[epid]);
+ if (USB_EP_DIR_IS_IN(ep)) {
+ *endp_mode_reg &= ~endp_mode_tx_en[epid];
+ } else {
+ *endp_mode_reg &= ~endp_mode_rx_en[epid];
+ }
+ ch32_usbfs_update_ep_buf(busid, epid);
+ }
+ return 0;
+}
+
+int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
+{
+ uint8_t ep_idx = USB_EP_GET_IDX(ep);
+ if (USB_EP_DIR_IS_OUT(ep)) {
+ ENDP_RX_CTRL(ep_idx) = (ENDP_RX_CTRL(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_STALL;
+ } else {
+ ENDP_TX_CTRL(ep_idx) = (ENDP_TX_CTRL(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_STALL;
+ }
+ return 0;
+}
+
+int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
+{
+ uint8_t ep_idx = USB_EP_GET_IDX(ep);
+ if (USB_EP_DIR_IS_OUT(ep)) {
+ ENDP_RX_CTRL(ep_idx) &= ~USBFS_UEP_R_AUTO_TOG;
+ ENDP_RX_CTRL(ep_idx) = USBFS_UEP_R_AUTO_TOG | USBFS_UEP_R_RES_ACK;
+ ENDP_RX_CTRL(ep_idx) |= USBFS_UEP_R_AUTO_TOG;
+ } else {
+ ENDP_TX_CTRL(ep_idx) &= ~USBFS_UEP_T_AUTO_TOG;
+ ENDP_TX_CTRL(ep_idx) = USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_RES_NAK;
+ ENDP_TX_CTRL(ep_idx) |= USBFS_UEP_T_AUTO_TOG;
+ }
+ return 0;
+}
+
+int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
+{
+ if (USB_EP_DIR_IS_OUT(ep)) {
+ *stalled = (ENDP_RX_CTRL(USB_EP_GET_IDX(ep)) & USBFS_UEP_R_RES_MASK) == USBFS_UEP_R_RES_STALL;
+ } else {
+ *stalled = (ENDP_TX_CTRL(USB_EP_GET_IDX(ep)) & USBFS_UEP_T_RES_MASK) == USBFS_UEP_T_RES_STALL;
+ }
+ return 0;
+}
+
+int usbd_ep_start_write(uint8_t busid, 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;
+ }
+ __IO uint8_t *endp_mode_reg = (__IO uint8_t *)((uint32_t)USBFSD + endp_mode_reg_offset[ep_idx]);
+ if (ep_idx && !(*endp_mode_reg & endp_mode_tx_en[ep_idx])) {
+ return -2;
+ }
+ if ((uint32_t)data & 0x03) {
+ return -3;
+ }
+ if (g_ch32_usbfs_udc[busid].ep_in[ep_idx].ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS &&
+ (ENDP_TX_CTRL(ep_idx) & USBFS_UEP_T_RES_MASK) != USBFS_UEP_T_RES_NAK) {
+ return -4;
+ }
+
+ g_ch32_usbfs_udc[busid].ep_in[ep_idx].xfer_buf = (uint8_t *)data;
+ g_ch32_usbfs_udc[busid].ep_in[ep_idx].xfer_len = data_len;
+ g_ch32_usbfs_udc[busid].ep_in[ep_idx].actual_xfer_len = 0;
+ data_len = MIN(data_len, g_ch32_usbfs_udc[busid].ep_in[ep_idx].ep_mps);
+
+ if (ep_idx == 0) {
+ USBFSD->UEP0_DMA = (uint32_t)data;
+ } else {
+ memcpy(endp_tx_bufs[ep_idx - 1], g_ch32_usbfs_udc[busid].ep_in[ep_idx].xfer_buf, data_len);
+ }
+
+ ENDP_TX_LEN(ep_idx) = data_len;
+ if (g_ch32_usbfs_udc[busid].ep_in[ep_idx].ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ ENDP_TX_CTRL(ep_idx) = (ENDP_TX_CTRL(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_ACK;
+ } else {
+ ENDP_TX_CTRL(ep_idx) = (ENDP_TX_CTRL(ep_idx) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_NONE;
+ }
+ return 0;
+}
+
+int usbd_ep_start_read(uint8_t busid, 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;
+ }
+ __IO uint8_t *endp_mode_reg = (__IO uint8_t *)((uint32_t)USBFSD + endp_mode_reg_offset[ep_idx]);
+ if (ep_idx && !(*endp_mode_reg & endp_mode_rx_en[ep_idx])) {
+ return -2;
+ }
+ if ((uint32_t)data & 0x03) {
+ return -3;
+ }
+
+ g_ch32_usbfs_udc[busid].ep_out[ep_idx].xfer_buf = data;
+ g_ch32_usbfs_udc[busid].ep_out[ep_idx].xfer_len = data_len;
+ g_ch32_usbfs_udc[busid].ep_out[ep_idx].actual_xfer_len = 0;
+
+ if (ep_idx == 0) {
+ USBFSD->UEP0_DMA = (uint32_t)data;
+ }
+
+ if (g_ch32_usbfs_udc[busid].ep_out[ep_idx].ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ ENDP_RX_CTRL(ep_idx) = (ENDP_RX_CTRL(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_ACK;
+ } else {
+ ENDP_RX_CTRL(ep_idx) = (ENDP_RX_CTRL(ep_idx) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_NONE;
+ }
+ return 0;
+}
+
+void USBD_IRQHandler(uint8_t busid)
+{
+ uint8_t flag = USBFSD->INT_FG;
+
+ if (flag & USBFS_UIF_TRANSFER) {
+ uint8_t status = USBFSD->INT_ST;
+ uint8_t endp = status & USBFS_UIS_ENDP_MASK;
+ uint8_t token = status & USBFS_UIS_TOKEN_MASK;
+
+ switch (token) {
+ case USBFS_UIS_TOKEN_SETUP:
+ ENDP_TX_CTRL(0) = (ENDP_TX_CTRL(0) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_NAK | USBFS_UEP_T_TOG;
+ ENDP_RX_CTRL(0) = (ENDP_RX_CTRL(0) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_NAK | USBFS_UEP_R_TOG;
+ usbd_event_ep0_setup_complete_handler(busid, (uint8_t *)&g_ch32_usbfs_udc[busid].setup);
+ break;
+
+ case USBFS_UIS_TOKEN_OUT:
+ if (status & USBFS_UIS_TOG_OK) {
+ if (endp == 0) {
+ USBFSD->UEP0_RX_CTRL ^= USBFS_UEP_R_TOG;
+ uint32_t read_count = USBFSD->RX_LEN;
+ read_count = MIN(read_count, g_ch32_usbfs_udc[busid].ep_out[endp].xfer_len);
+ g_ch32_usbfs_udc[busid].ep_out[0].actual_xfer_len += read_count;
+ g_ch32_usbfs_udc[busid].ep_out[0].xfer_len -= read_count;
+ usbd_event_ep_out_complete_handler(busid, 0x00, g_ch32_usbfs_udc[busid].ep_out[0].actual_xfer_len);
+ if (read_count == 0) {
+ USBFSD->UEP0_DMA = (uint32_t)&g_ch32_usbfs_udc[busid].setup;
+ ENDP_RX_CTRL(0) = (ENDP_RX_CTRL(0) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_ACK;
+ }
+ } else {
+ if (g_ch32_usbfs_udc[busid].ep_out[endp].ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ ENDP_RX_CTRL(endp) = (ENDP_RX_CTRL(endp) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_NAK;
+ }
+ uint32_t read_count = USBFSD->RX_LEN;
+ read_count = MIN(read_count, g_ch32_usbfs_udc[busid].ep_out[endp].xfer_len);
+ memcpy(g_ch32_usbfs_udc[busid].ep_out[endp].xfer_buf, endp_rx_bufs[endp - 1], read_count);
+ g_ch32_usbfs_udc[busid].ep_out[endp].xfer_buf += read_count;
+ g_ch32_usbfs_udc[busid].ep_out[endp].actual_xfer_len += read_count;
+ g_ch32_usbfs_udc[busid].ep_out[endp].xfer_len -= read_count;
+ if ((read_count < g_ch32_usbfs_udc[busid].ep_out[endp].ep_mps) || (g_ch32_usbfs_udc[busid].ep_out[endp].xfer_len == 0)) {
+ usbd_event_ep_out_complete_handler(busid, endp, g_ch32_usbfs_udc[busid].ep_out[endp].actual_xfer_len);
+ } else if (g_ch32_usbfs_udc[busid].ep_out[endp].ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ ENDP_RX_CTRL(endp) = (ENDP_RX_CTRL(endp) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_ACK;
+ } else {
+ ENDP_RX_CTRL(endp) = (ENDP_RX_CTRL(endp) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_NONE;
+ }
+ }
+ } else {
+ // OUT transfer toggle mismatch
+ ENDP_RX_CTRL(endp) = (ENDP_RX_CTRL(endp) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_ACK;
+ }
+ break;
+
+ case USBFS_UIS_TOKEN_IN:
+ if (g_ch32_usbfs_udc[busid].ep_in[endp].ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ ENDP_TX_CTRL(endp) = (ENDP_TX_CTRL(endp) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_NAK;
+ }
+ if (endp == 0) {
+ if (g_ch32_usbfs_udc[busid].setup.bmRequestType & 0x80) {
+ if (g_ch32_usbfs_udc[busid].ep_in[0].xfer_len >= g_ch32_usbfs_udc[busid].ep_in[0].ep_mps) {
+ g_ch32_usbfs_udc[busid].ep_in[0].xfer_len -= g_ch32_usbfs_udc[busid].ep_in[0].ep_mps;
+ g_ch32_usbfs_udc[busid].ep_in[0].actual_xfer_len += g_ch32_usbfs_udc[busid].ep_in[0].ep_mps;
+ } else {
+ g_ch32_usbfs_udc[busid].ep_in[0].actual_xfer_len += g_ch32_usbfs_udc[busid].ep_in[0].xfer_len;
+ g_ch32_usbfs_udc[busid].ep_in[0].xfer_len = 0;
+ }
+
+ USBFSD->UEP0_TX_CTRL ^= USBFS_UEP_T_TOG;
+ usbd_event_ep_in_complete_handler(busid, 0x80, g_ch32_usbfs_udc[busid].ep_in[0].actual_xfer_len);
+ } else {
+ USBFSD->UEP0_DMA = (uint32_t)&g_ch32_usbfs_udc[busid].setup;
+ ENDP_RX_CTRL(0) = (ENDP_RX_CTRL(0) & ~USBFS_UEP_R_RES_MASK) | USBFS_UEP_R_RES_ACK;
+ }
+ } else if (g_ch32_usbfs_udc[busid].ep_in[endp].xfer_len > g_ch32_usbfs_udc[busid].ep_in[endp].ep_mps) {
+ g_ch32_usbfs_udc[busid].ep_in[endp].xfer_buf += g_ch32_usbfs_udc[busid].ep_in[endp].ep_mps;
+ g_ch32_usbfs_udc[busid].ep_in[endp].xfer_len -= g_ch32_usbfs_udc[busid].ep_in[endp].ep_mps;
+ g_ch32_usbfs_udc[busid].ep_in[endp].actual_xfer_len += g_ch32_usbfs_udc[busid].ep_in[endp].ep_mps;
+
+ uint32_t write_count = MIN(g_ch32_usbfs_udc[busid].ep_in[endp].xfer_len, g_ch32_usbfs_udc[busid].ep_in[endp].ep_mps);
+ ENDP_TX_LEN(endp) = write_count;
+ memcpy(endp_tx_bufs[endp - 1], g_ch32_usbfs_udc[busid].ep_in[endp].xfer_buf, write_count);
+ if (g_ch32_usbfs_udc[busid].ep_in[endp].ep_type != USB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ ENDP_TX_CTRL(endp) = (ENDP_TX_CTRL(endp) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_ACK;
+ } else {
+ ENDP_TX_CTRL(endp) = (ENDP_TX_CTRL(endp) & ~USBFS_UEP_T_RES_MASK) | USBFS_UEP_T_RES_NONE;
+ }
+ } else {
+ g_ch32_usbfs_udc[busid].ep_in[endp].actual_xfer_len += g_ch32_usbfs_udc[busid].ep_in[endp].xfer_len;
+ g_ch32_usbfs_udc[busid].ep_in[endp].xfer_len = 0;
+ usbd_event_ep_in_complete_handler(busid, 0x80 | endp, g_ch32_usbfs_udc[busid].ep_in[endp].actual_xfer_len);
+ }
+
+ if (g_ch32_usbfs_udc[busid].dev_addr) {
+ USBFSD->DEV_ADDR = g_ch32_usbfs_udc[busid].dev_addr;
+ g_ch32_usbfs_udc[busid].dev_addr = 0;
+ }
+ break;
+
+ case USBFS_UIS_TOKEN_SOF:
+ break;
+ }
+ USBFSD->INT_FG = USBFS_UIF_TRANSFER;
+ } else if (flag & USBFS_UIF_BUS_RST) {
+ USBFSD->DEV_ADDR = 0;
+ USBFSD->UEP0_DMA = (uint32_t)&g_ch32_usbfs_udc[busid].setup;
+ USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK;
+ USBFSD->UEP0_RX_CTRL = USBFS_UEP_R_RES_ACK;
+ usbd_event_reset_handler(busid);
+ USBFSD->INT_FG = USBFS_UIF_BUS_RST;
+ } else if (flag & USBFS_UIF_SUSPEND) {
+ if (USBFSD->MIS_ST & USBFS_UMS_SUSPEND) {
+ usbd_event_suspend_handler(busid);
+ }
+ USBFSD->INT_FG = USBFS_UIF_SUSPEND;
+ } else {
+ USBFSD->INT_FG = flag;
+ }
+}
+
+#if defined(CONFIG_USBDEV_MULT_DC)
+struct usbd_dc_driver wch_usbfs_dc_driver = {
+ .driver_name = "wch_usbfs_dcd",
+ .driver_desc = "WCH USBFS Device Controller",
+ .init = usb_dc_init,
+ .deinit = usb_dc_deinit,
+ .set_address = usbd_set_address,
+ .set_remote_wakeup = usbd_set_remote_wakeup,
+ .get_port_speed = usbd_get_port_speed,
+ .ep_open = usbd_ep_open,
+ .ep_close = usbd_ep_close,
+ .ep_set_stall = usbd_ep_set_stall,
+ .ep_clear_stall = usbd_ep_clear_stall,
+ .ep_is_stalled = usbd_ep_is_stalled,
+ .ep_start_write = usbd_ep_start_write,
+ .ep_start_read = usbd_ep_start_read,
+ .irq_handler = USBD_IRQHandler,
+};
+#endif
diff --git a/port/wch/usbfs/usb_hc_usbfs.c b/port/wch/usbfs/usb_hc_usbfs.c
new file mode 100644
index 00000000..b985956d
--- /dev/null
+++ b/port/wch/usbfs/usb_hc_usbfs.c
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2026, Links ([email protected])
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "usbh_core.h"
+#include "usbh_hub.h"
+#include "usb_usbfs_reg.h"
+
+#if defined(CONFIG_USBHOST_MULT_HC)
+#define usb_hc_init usbh_wch_usbfs_hc_init
+#define usb_hc_deinit usbh_wch_usbfs_hc_deinit
+#define usbh_get_frame_number usbh_wch_usbfs_get_frame_number
+#define usbh_roothub_control usbh_wch_usbfs_roothub_control
+#define usbh_submit_urb usbh_wch_usbfs_submit_urb
+#define usbh_kill_urb usbh_wch_usbfs_kill_urb
+#define USBH_IRQHandler usbh_wch_usbfs_irq_handler
+
+int usbh_wch_usbfs_kill_urb(struct usbh_urb *urb);
+#endif
+
+#define USBFSH ((USBFSH_TypeDef *)bus->hcd.reg_base)
+
+typedef enum {
+ USB_EP0_STATE_SETUP,
+ USB_EP0_STATE_DATA,
+ USB_EP0_STATE_STATUS,
+} ep0_state_t;
+
+typedef enum {
+ XFER_STATE_IDLE,
+ XFER_STATE_BUSY,
+ XFER_STATE_COMP,
+} xfer_state_t;
+
+typedef enum {
+ ENDP_TOG_DATA0,
+ ENDP_TOG_DATA1,
+ ENDP_TOG_DATA2,
+ ENDP_TOG_MDATA,
+} endp_tog_t;
+
+struct usbfs_pipe;
+
+typedef struct usbfs_xfer {
+ uint8_t pre;
+ uint8_t endp;
+ uint8_t token;
+ uint8_t toggle;
+ uint8_t dev_addr;
+ uint8_t xfer_state;
+ uint16_t length;
+ uint8_t *buffer;
+ struct usbfs_pipe *pipe;
+ struct usbfs_xfer *next;
+} usbfs_xfer_t;
+
+struct usbfs_pipe {
+ bool used;
+ bool killed;
+ uint8_t type;
+ uint8_t ep0_state;
+ uint32_t tick;
+ uint32_t interval;
+ usb_osal_sem_t waitsem;
+ usbfs_xfer_t xfer;
+ struct usbh_urb *urb;
+ struct usbfs_pipe *prev;
+ struct usbfs_pipe *next;
+};
+
+struct usbfs_hcd {
+ bool sof_act;
+ bool port_csc;
+ uint8_t speed;
+ uint32_t tick;
+ usbfs_xfer_t *curr_xfer;
+ struct usbfs_pipe *pipe_list[4];
+ struct usbfs_pipe pipe_pool[8];
+} g_usbfs_hcd[CONFIG_USBHOST_MAX_BUS];
+
+static struct usbfs_pipe *usbfs_pipe_alloc(struct usbh_bus *bus, struct usbh_urb *urb, struct usb_endpoint_descriptor *ep)
+{
+ for (size_t chidx = 0; chidx < sizeof(g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool) / sizeof(struct usbfs_pipe); chidx++) {
+ if (!g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].used) {
+ uint8_t type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].used = true;
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].killed = false;
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].type = type;
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].ep0_state = USB_EP0_STATE_SETUP;
+ if (type == USB_ENDPOINT_TYPE_ISOCHRONOUS || type == USB_ENDPOINT_TYPE_INTERRUPT) {
+ uint8_t interval = ep->bInterval;
+ if (type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].interval = 1 << (interval - 1);
+ } else {
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].interval = interval;
+ }
+ } else {
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].interval = 0;
+ }
+
+ memset(&g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].xfer, 0, sizeof(usbfs_xfer_t));
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].urb = urb;
+ if (g_usbfs_hcd[bus->hcd.hcd_id].pipe_list[type] == NULL) {
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].prev = NULL;
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_list[type] = &g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx];
+ } else {
+ struct usbfs_pipe *ppipe = g_usbfs_hcd[bus->hcd.hcd_id].pipe_list[type];
+ while (ppipe->next) {
+ ppipe = ppipe->next;
+ }
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].prev = ppipe;
+ ppipe->next = &g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx];
+ }
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].next = NULL;
+ return &g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[chidx];
+ }
+ }
+
+ return NULL;
+}
+
+static void usbfs_pipe_free(struct usbh_bus *bus, struct usbfs_pipe *pipe, uint8_t type)
+{
+ usbfs_xfer_t *xfer = &pipe->xfer;
+
+ size_t flags = usb_osal_enter_critical_section();
+
+ if (xfer->xfer_state != XFER_STATE_BUSY) {
+ if (pipe->prev) {
+ pipe->prev->next = pipe->next;
+ } else {
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_list[type] = pipe->next;
+ }
+
+ if (pipe->next) {
+ pipe->next->prev = pipe->prev;
+ }
+
+ pipe->used = false;
+ } else {
+ pipe->killed = true;
+ }
+
+ usb_osal_leave_critical_section(flags);
+}
+
+static usbfs_xfer_t **usbfs_xfer_process(struct usbh_bus *bus, usbfs_xfer_t **last_xfer, uint8_t type)
+{
+ struct usbfs_pipe *pipe = g_usbfs_hcd[bus->hcd.hcd_id].pipe_list[type];
+
+ while (pipe) {
+ usbfs_xfer_t *xfer = &pipe->xfer;
+ if (xfer->xfer_state != XFER_STATE_COMP) {
+ struct usbh_urb *urb = pipe->urb;
+ if (urb->hport->speed != g_usbfs_hcd[bus->hcd.hcd_id].speed) {
+ xfer->pre = 1;
+ }
+
+ xfer->dev_addr = urb->hport->dev_addr;
+ xfer->pipe = pipe;
+
+ if (type == USB_ENDPOINT_TYPE_CONTROL) {
+ xfer->endp = 0;
+ switch (pipe->ep0_state) {
+ case USB_EP0_STATE_SETUP:
+ xfer->token = USB_PID_SETUP;
+ xfer->toggle = ENDP_TOG_DATA0;
+ xfer->length = sizeof(struct usb_setup_packet);
+ xfer->buffer = (uint8_t *)(urb->setup);
+ break;
+
+ case USB_EP0_STATE_DATA:
+ xfer->token = urb->setup->bmRequestType & 0x80 ? USB_PID_IN : USB_PID_OUT;
+ xfer->toggle = urb->data_toggle;
+ xfer->length = MIN(urb->transfer_buffer_length - (urb->actual_length - sizeof(struct usb_setup_packet)),
+ USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize));
+ xfer->buffer = urb->transfer_buffer + urb->actual_length - sizeof(struct usb_setup_packet);
+ break;
+
+ case USB_EP0_STATE_STATUS:
+ xfer->token = urb->setup->bmRequestType & 0x80 ? USB_PID_OUT : USB_PID_IN;
+ xfer->toggle = ENDP_TOG_DATA1;
+ xfer->length = 0;
+ xfer->buffer = NULL;
+ break;
+ }
+
+ xfer->xfer_state = XFER_STATE_BUSY;
+ *last_xfer = xfer;
+ last_xfer = &xfer->next;
+ } else if (pipe->interval == 0 || g_usbfs_hcd[bus->hcd.hcd_id].tick - pipe->tick >= pipe->interval) {
+ pipe->tick = g_usbfs_hcd[bus->hcd.hcd_id].tick;
+ xfer->endp = USB_EP_GET_IDX(urb->ep->bEndpointAddress);
+ xfer->token = USB_EP_GET_DIR(urb->ep->bEndpointAddress) ? USB_PID_IN : USB_PID_OUT;
+ xfer->toggle = urb->data_toggle;
+ xfer->length = MIN(urb->transfer_buffer_length - urb->actual_length, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize));
+ xfer->buffer = urb->transfer_buffer + urb->actual_length;
+
+ xfer->xfer_state = XFER_STATE_BUSY;
+ *last_xfer = xfer;
+ last_xfer = &xfer->next;
+ }
+ }
+
+ pipe = pipe->next;
+ }
+
+ return last_xfer;
+}
+
+static void usbfs_transfer_start(struct usbh_bus *bus)
+{
+ if ((USBFSH->HOST_EP_PID != 0) || (USBFSH->INT_FG & USBFS_UIF_TRANSFER) || !(USBFSH->MIS_ST & USBFS_UMS_DEV_ATTACH)) {
+ return;
+ }
+
+ if (g_usbfs_hcd[bus->hcd.hcd_id].sof_act || !g_usbfs_hcd[bus->hcd.hcd_id].curr_xfer) {
+ g_usbfs_hcd[bus->hcd.hcd_id].curr_xfer = NULL;
+ usbfs_xfer_t **last_xfer = &g_usbfs_hcd[bus->hcd.hcd_id].curr_xfer;
+
+ if (g_usbfs_hcd[bus->hcd.hcd_id].sof_act) {
+ g_usbfs_hcd[bus->hcd.hcd_id].sof_act = 0;
+ last_xfer = usbfs_xfer_process(bus, last_xfer, USB_ENDPOINT_TYPE_ISOCHRONOUS);
+ last_xfer = usbfs_xfer_process(bus, last_xfer, USB_ENDPOINT_TYPE_INTERRUPT);
+ }
+
+ last_xfer = usbfs_xfer_process(bus, last_xfer, USB_ENDPOINT_TYPE_CONTROL);
+ last_xfer = usbfs_xfer_process(bus, last_xfer, USB_ENDPOINT_TYPE_BULK);
+ *last_xfer = NULL;
+ }
+
+ if (g_usbfs_hcd[bus->hcd.hcd_id].curr_xfer) {
+ usbfs_xfer_t *xfer = g_usbfs_hcd[bus->hcd.hcd_id].curr_xfer;
+ uint8_t type = USB_GET_ENDPOINT_TYPE(xfer->pipe->type);
+
+ USBFSH->DEV_ADDR = xfer->dev_addr;
+ if (xfer->pre || g_usbfs_hcd[bus->hcd.hcd_id].speed == USB_SPEED_LOW) {
+ USBFSH->BASE_CTRL |= USBFS_UC_LOW_SPEED;
+ USBFSH->HOST_SETUP |= USBFS_UH_PRE_PID_EN;
+ } else {
+ USBFSH->BASE_CTRL &= ~USBFS_UC_LOW_SPEED;
+ USBFSH->HOST_SETUP &= ~USBFS_UH_PRE_PID_EN;
+ }
+
+ if (xfer->token == USB_PID_IN) {
+ USBFSH->HOST_RX_DMA = (uint32_t)xfer->buffer;
+ USBFSH->HOST_RX_CTRL = (xfer->toggle == ENDP_TOG_DATA1 ? USBFS_UH_R_TOG : 0) |
+ (type == USB_ENDPOINT_TYPE_ISOCHRONOUS ? USBFS_UH_R_RES : 0);
+ USBFSH->HOST_EP_PID = (xfer->token << 4) | xfer->endp;
+ } else {
+ USBFSH->HOST_TX_LEN = xfer->length;
+ USBFSH->HOST_TX_DMA = (uint32_t)xfer->buffer;
+ USBFSH->HOST_TX_CTRL = (xfer->toggle == ENDP_TOG_DATA1 ? USBFS_UH_T_TOG : 0) |
+ (type == USB_ENDPOINT_TYPE_ISOCHRONOUS ? USBFS_UH_T_RES : 0);
+ USBFSH->HOST_EP_PID = (xfer->token << 4) | xfer->endp;
+ }
+ }
+}
+
+static void usbfs_transfer_complete(struct usbh_bus *bus, uint8_t recv_pid, size_t recv_len)
+{
+ static const uint8_t tog_pid[] = { USB_PID_DATA0, USB_PID_DATA1, USB_PID_DATA2, USB_PID_MDATA };
+
+ usbfs_xfer_t *xfer = g_usbfs_hcd[bus->hcd.hcd_id].curr_xfer;
+ struct usbfs_pipe *pipe = xfer->pipe;
+
+ xfer->xfer_state = XFER_STATE_IDLE;
+ if (pipe->killed) {
+ usbfs_pipe_free(bus, pipe, pipe->type);
+ return;
+ }
+
+ struct usbh_urb *urb = pipe->urb;
+ if (recv_pid == USB_PID_ACK || recv_pid == USB_PID_NYET || recv_pid == tog_pid[xfer->toggle]) {
+ size_t len = xfer->token == USB_PID_IN ? recv_len : xfer->length;
+ urb->actual_length += len;
+
+ if (xfer->endp != 0) {
+ urb->data_toggle ^= ENDP_TOG_DATA1;
+ if (len < USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize) || urb->actual_length >= urb->transfer_buffer_length) {
+ urb->errorcode = 0;
+ goto end;
+ }
+ } else if (pipe->ep0_state == USB_EP0_STATE_SETUP) {
+ urb->data_toggle = ENDP_TOG_DATA1;
+ pipe->ep0_state = urb->transfer_buffer_length ? USB_EP0_STATE_DATA : USB_EP0_STATE_STATUS;
+ } else if (pipe->ep0_state == USB_EP0_STATE_DATA) {
+ if (len < USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize) ||
+ (urb->actual_length - sizeof(struct usb_setup_packet)) >= urb->transfer_buffer_length) {
+ urb->data_toggle = ENDP_TOG_DATA1;
+ pipe->ep0_state = USB_EP0_STATE_STATUS;
+ } else {
+ urb->data_toggle ^= ENDP_TOG_DATA1;
+ }
+ } else {
+ urb->errorcode = 0;
+ goto end;
+ }
+ } else if (recv_pid == USB_PID_STALL) {
+ urb->errorcode = -USB_ERR_STALL;
+ goto end;
+ } else if (recv_pid == USB_PID_NAK) {
+ if (xfer->endp != 0) {
+ urb->errorcode = -USB_ERR_NAK;
+ goto end;
+ }
+ } else {
+ urb->errorcode = -USB_ERR_IO;
+ goto end;
+ }
+ return;
+
+end:
+ xfer->xfer_state = XFER_STATE_COMP;
+ if (urb->timeout) {
+ usb_osal_sem_give(pipe->waitsem);
+ } else {
+ usbfs_pipe_free(bus, pipe, pipe->type);
+ }
+
+ if (urb->complete) {
+ if (urb->errorcode < 0) {
+ urb->complete(urb->arg, urb->errorcode);
+ } else {
+ urb->complete(urb->arg, urb->actual_length);
+ }
+ }
+}
+
+extern void usb_hc_low_level_init(struct usbh_bus *bus);
+extern void usb_hc_low_level_deinit(struct usbh_bus *bus);
+
+int usb_hc_init(struct usbh_bus *bus)
+{
+ memset(&g_usbfs_hcd[bus->hcd.hcd_id], 0, sizeof(struct usbfs_hcd));
+ usb_hc_low_level_init(bus);
+
+ for (uint8_t i = 0; i < sizeof(g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool) / sizeof(struct usbfs_pipe); i++) {
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem = usb_osal_sem_create(0);
+ USB_ASSERT(g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem != NULL);
+ }
+
+ USBFSH->BASE_CTRL = USBFS_UC_HOST_MODE;
+ while (!(USBFSH->BASE_CTRL & USBFS_UC_HOST_MODE))
+ ;
+ USBFSH->HOST_CTRL = 0;
+ USBFSH->DEV_ADDR = 0;
+ USBFSH->HOST_EP_MOD = USBFS_UH_EP_TX_EN | USBFS_UH_EP_RX_EN;
+ USBFSH->HOST_SETUP = USBFS_UH_SOF_EN;
+
+ USBFSH->HOST_RX_CTRL = 0;
+ USBFSH->HOST_TX_CTRL = 0;
+ USBFSH->BASE_CTRL = USBFS_UC_HOST_MODE | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN;
+
+ USBFSH->INT_FG = 0xFF;
+ USBFSH->INT_EN = USBFS_UIE_HST_SOF | USBFS_UIE_TRANSFER | USBFS_UIE_DETECT;
+ return 0;
+}
+
+int usb_hc_deinit(struct usbh_bus *bus)
+{
+ USBFSH->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL;
+ usb_osal_msleep(1);
+ USBFSH->BASE_CTRL = 0;
+
+ for (uint8_t i = 0; i < sizeof(g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool) / sizeof(struct usbfs_pipe); i++) {
+ if (g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem) {
+ usb_osal_sem_delete(g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem);
+ g_usbfs_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem = NULL;
+ }
+ }
+
+ usb_hc_low_level_deinit(bus);
+ return 0;
+}
+
+uint16_t usbh_get_frame_number(struct usbh_bus *bus)
+{
+ return 0;
+}
+
+int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf)
+{
+ uint8_t nports;
+ uint8_t port;
+ uint32_t status;
+
+ nports = CONFIG_USBHOST_MAX_RHPORTS;
+ port = setup->wIndex;
+ if ((setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) == USB_REQUEST_RECIPIENT_DEVICE) {
+ switch (setup->bRequest) {
+ case HUB_REQUEST_CLEAR_FEATURE:
+ switch (setup->wValue) {
+ case HUB_FEATURE_HUB_C_LOCALPOWER:
+ break;
+ case HUB_FEATURE_HUB_C_OVERCURRENT:
+ break;
+ default:
+ return -USB_ERR_NOTSUPP;
+ }
+ break;
+ case HUB_REQUEST_SET_FEATURE:
+ switch (setup->wValue) {
+ case HUB_FEATURE_HUB_C_LOCALPOWER:
+ break;
+ case HUB_FEATURE_HUB_C_OVERCURRENT:
+ break;
+ default:
+ return -USB_ERR_NOTSUPP;
+ }
+ break;
+ case HUB_REQUEST_GET_DESCRIPTOR:
+ break;
+ case HUB_REQUEST_GET_STATUS:
+ memset(buf, 0, 4);
+ break;
+ default:
+ break;
+ }
+ } else if ((setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) == USB_REQUEST_RECIPIENT_OTHER) {
+ uint16_t port_status;
+ switch (setup->bRequest) {
+ case HUB_REQUEST_CLEAR_FEATURE:
+ if (!port || port > nports) {
+ return -USB_ERR_INVAL;
+ }
+
+ switch (setup->wValue) {
+ case HUB_PORT_FEATURE_ENABLE:
+ break;
+ case HUB_PORT_FEATURE_SUSPEND:
+ break;
+ case HUB_PORT_FEATURE_C_SUSPEND:
+ break;
+ case HUB_PORT_FEATURE_POWER:
+ break;
+ case HUB_PORT_FEATURE_C_CONNECTION:
+ g_usbfs_hcd[bus->hcd.hcd_id].port_csc = 0;
+ break;
+ case HUB_PORT_FEATURE_C_ENABLE:
+ break;
+ case HUB_PORT_FEATURE_C_OVER_CURREN:
+ break;
+ case HUB_PORT_FEATURE_C_RESET:
+ break;
+ default:
+ return -USB_ERR_NOTSUPP;
+ }
+ break;
+ case HUB_REQUEST_SET_FEATURE:
+ if (!port || port > nports) {
+ return -USB_ERR_INVAL;
+ }
+
+ switch (setup->wValue) {
+ case HUB_PORT_FEATURE_SUSPEND:
+ break;
+ case HUB_PORT_FEATURE_POWER:
+ break;
+ case HUB_PORT_FEATURE_RESET:
+ USBFSH->INT_EN = 0;
+ USBFSH->HOST_CTRL = USBFS_UH_BUS_RESET;
+ usb_osal_msleep(15);
+ USBFSH->HOST_CTRL = 0;
+ usb_osal_msleep(2);
+ if (USBFSH->MIS_ST & USBFS_UMS_DM_LEVEL) {
+ USBFSH->HOST_CTRL = USBFS_UH_LOW_SPEED;
+ }
+ USBFSH->INT_FG = 0xFF;
+ USBFSH->INT_EN = USBFS_UIE_HST_SOF | USBFS_UIE_TRANSFER | USBFS_UIE_DETECT;
+ USBFSH->HOST_CTRL |= USBFS_UH_PORT_EN;
+ break;
+
+ default:
+ return -USB_ERR_NOTSUPP;
+ }
+ break;
+ case HUB_REQUEST_GET_STATUS:
+ if (!port || port > nports) {
+ return -USB_ERR_INVAL;
+ }
+
+ status = 0;
+ if (g_usbfs_hcd[bus->hcd.hcd_id].port_csc)
+ status |= (1 << HUB_PORT_FEATURE_C_CONNECTION);
+
+ port_status = USBFSH->MIS_ST;
+ status |= (1 << HUB_PORT_FEATURE_POWER);
+
+ if (port_status & USBFS_UMS_DEV_ATTACH)
+ status |= (1 << HUB_PORT_FEATURE_CONNECTION);
+ if (USBFSH->HOST_CTRL & USBFS_UH_PORT_EN)
+ status |= (1 << HUB_PORT_FEATURE_ENABLE);
+ if (port_status & USBFS_UMS_SUSPEND)
+ status |= (1 << HUB_PORT_FEATURE_SUSPEND);
+ if (port_status & USBFS_UMS_BUS_RESET)
+ status |= (1 << HUB_PORT_FEATURE_RESET);
+ if (port_status & USBFS_UMS_DM_LEVEL) {
+ status |= (1 << HUB_PORT_FEATURE_LOWSPEED);
+ g_usbfs_hcd[bus->hcd.hcd_id].speed = USB_SPEED_LOW;
+ } else {
+ g_usbfs_hcd[bus->hcd.hcd_id].speed = USB_SPEED_FULL;
+ }
+
+ memcpy(buf, &status, 4);
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+int usbh_submit_urb(struct usbh_urb *urb)
+{
+ if (!urb || !urb->hport || !urb->ep || !urb->hport->bus) {
+ return -USB_ERR_INVAL;
+ }
+
+ int ret = 0;
+ struct usbh_bus *bus = urb->hport->bus;
+
+ /* dma addr must be aligned 4 bytes */
+ USB_ASSERT_MSG(!((uintptr_t)urb->setup % 4) && !((uintptr_t)urb->transfer_buffer % 4),
+ "urb->setup or urb->transfer_buffer is not aligned 4 bytes");
+
+ if (!urb->hport->connected) {
+ return -USB_ERR_NOTCONN;
+ }
+
+ if (urb->errorcode == -USB_ERR_BUSY) {
+ return -USB_ERR_BUSY;
+ }
+
+ size_t flags = usb_osal_enter_critical_section();
+ struct usbfs_pipe *pipe = usbfs_pipe_alloc(bus, urb, urb->ep);
+ if (!pipe) {
+ usb_osal_leave_critical_section(flags);
+ return -USB_ERR_NOMEM;
+ }
+
+ urb->hcpriv = pipe;
+ urb->errorcode = -USB_ERR_BUSY;
+ urb->actual_length = 0;
+ usbfs_transfer_start(bus);
+ usb_osal_leave_critical_section(flags);
+
+ if (urb->timeout > 0) {
+ /* wait until timeout or sem give */
+ ret = usb_osal_sem_take(pipe->waitsem, urb->timeout);
+ if (ret < 0) {
+ goto errout_timeout;
+ }
+ urb->timeout = 0;
+ ret = urb->errorcode;
+
+ /* we can free pipe when waitsem is done */
+ usbfs_pipe_free(bus, pipe, pipe->type);
+ }
+ return ret;
+
+errout_timeout:
+ urb->timeout = 0;
+ usbh_kill_urb(urb);
+ return ret;
+}
+
+int usbh_kill_urb(struct usbh_urb *urb)
+{
+ if (!urb || !urb->hcpriv || !urb->hport->bus) {
+ return -USB_ERR_INVAL;
+ }
+
+ size_t flags = usb_osal_enter_critical_section();
+
+ struct usbfs_pipe *pipe = urb->hcpriv;
+ if (!pipe) {
+ usb_osal_leave_critical_section(flags);
+ return -USB_ERR_INVAL;
+ }
+
+ urb->errorcode = -USB_ERR_SHUTDOWN;
+
+ usb_osal_leave_critical_section(flags);
+
+ if (urb->timeout) {
+ usb_osal_sem_give(pipe->waitsem);
+ } else {
+ usbfs_pipe_free(urb->hport->bus, pipe, USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes));
+ }
+
+ if (urb->complete) {
+ urb->complete(urb->arg, urb->errorcode);
+ }
+
+ return 0;
+}
+
+void USBH_IRQHandler(uint8_t busid)
+{
+ struct usbh_bus *bus = &g_usbhost_bus[busid];
+
+ /* Get the interrupt flag */
+ uint8_t int_flag = USBFSH->INT_FG;
+
+ if (int_flag & USBFS_UIF_HST_SOF) {
+ g_usbfs_hcd[bus->hcd.hcd_id].tick++;
+ g_usbfs_hcd[bus->hcd.hcd_id].sof_act = true;
+ usbfs_transfer_start(bus);
+ USBFSH->INT_FG = USBFS_UIF_HST_SOF;
+ } else if (int_flag & USBFS_UIF_TRANSFER) {
+ USBFSH->HOST_EP_PID = 0x00;
+ usbfs_transfer_complete(bus, USBFSH->INT_ST & 0x0F, USBFSH->RX_LEN);
+ g_usbfs_hcd[bus->hcd.hcd_id].curr_xfer = g_usbfs_hcd[bus->hcd.hcd_id].curr_xfer->next;
+ USBFSH->INT_FG = USBFS_UIF_TRANSFER;
+ usbfs_transfer_start(bus);
+ } else if (int_flag & USBFS_UIF_DETECT) {
+ g_usbfs_hcd[bus->hcd.hcd_id].port_csc = 1;
+ bus->hcd.roothub.int_buffer[0] = (1 << 1);
+ usbh_hub_thread_wakeup(&bus->hcd.roothub);
+ USBFSH->INT_FG = USBFS_UIF_DETECT;
+ } else {
+ USBFSH->INT_FG = int_flag;
+ }
+}
+
+#if defined(CONFIG_USBHOST_MULT_HC)
+struct usbh_hc_driver wch_usbfs_hc_driver = {
+ .driver_name = "wch_usbfs_hcd",
+ .driver_desc = "WCH USBFS Host Controller",
+ .init = usb_hc_init,
+ .deinit = usb_hc_deinit,
+ .get_frame_number = usbh_get_frame_number,
+ .roothub_control = usbh_roothub_control,
+ .submit_urb = usbh_submit_urb,
+ .kill_urb = usbh_kill_urb,
+ .irq_handler = USBH_IRQHandler,
+};
+#endif
diff --git a/port/wch/usbfs/usb_usbfs_reg.h b/port/wch/usbfs/usb_usbfs_reg.h
new file mode 100644
index 00000000..da5fa0e2
--- /dev/null
+++ b/port/wch/usbfs/usb_usbfs_reg.h
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2026, Links ([email protected])
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef USB_USBFS_REG_H
+#define USB_USBFS_REG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* @include */
+#include <stdint.h>
+
+/*******************************************************************************/
+/* USBFS Related Register Macro Definition */
+
+/* R8_USB_CTRL */
+#define USBFS_UC_HOST_MODE 0x80
+#define USBFS_UC_LOW_SPEED 0x40
+#define USBFS_UC_DEV_PU_EN 0x20
+#define USBFS_UC_SYS_CTRL_MASK 0x30
+#define USBFS_UC_SYS_CTRL0 0x00
+#define USBFS_UC_SYS_CTRL1 0x10
+#define USBFS_UC_SYS_CTRL2 0x20
+#define USBFS_UC_SYS_CTRL3 0x30
+#define USBFS_UC_INT_BUSY 0x08
+#define USBFS_UC_RESET_SIE 0x04
+#define USBFS_UC_CLR_ALL 0x02
+#define USBFS_UC_DMA_EN 0x01
+
+/* R8_USB_INT_EN */
+#define USBFS_UIE_DEV_SOF 0x80
+#define USBFS_UIE_DEV_NAK 0x40
+#define USBFS_U_1WIRE_MODE 0x20
+#define USBFS_UIE_FIFO_OV 0x10
+#define USBFS_UIE_HST_SOF 0x08
+#define USBFS_UIE_SUSPEND 0x04
+#define USBFS_UIE_TRANSFER 0x02
+#define USBFS_UIE_DETECT 0x01
+#define USBFS_UIE_BUS_RST 0x01
+
+/* R8_USB_DEV_AD */
+#define USBFS_UDA_GP_BIT 0x80
+#define USBFS_USB_ADDR_MASK 0x7F
+
+/* R8_USB_MIS_ST */
+#define USBFS_UMS_SOF_PRES 0x80
+#define USBFS_UMS_SOF_ACT 0x40
+#define USBFS_UMS_SIE_FREE 0x20
+#define USBFS_UMS_R_FIFO_RDY 0x10
+#define USBFS_UMS_BUS_RESET 0x08
+#define USBFS_UMS_SUSPEND 0x04
+#define USBFS_UMS_DM_LEVEL 0x02
+#define USBFS_UMS_DEV_ATTACH 0x01
+
+/* R8_USB_INT_FG */
+#define USBFS_U_IS_NAK 0x80 // RO, indicate current USB transfer is NAK received
+#define USBFS_U_TOG_OK 0x40 // RO, indicate current USB transfer toggle is OK
+#define USBFS_U_SIE_FREE 0x20 // RO, indicate USB SIE free status
+#define USBFS_UIF_FIFO_OV 0x10 // FIFO overflow interrupt flag for USB, direct bit address clear or write 1 to clear
+#define USBFS_UIF_HST_SOF 0x08 // host SOF timer interrupt flag for USB host, direct bit address clear or write 1 to clear
+#define USBFS_UIF_SUSPEND 0x04 // USB suspend or resume event interrupt flag, direct bit address clear or write 1 to clear
+#define USBFS_UIF_TRANSFER 0x02 // USB transfer completion interrupt flag, direct bit address clear or write 1 to clear
+#define USBFS_UIF_DETECT 0x01 // device detected event interrupt flag for USB host mode, direct bit address clear or write 1 to clear
+#define USBFS_UIF_BUS_RST 0x01 // bus reset event interrupt flag for USB device mode, direct bit address clear or write 1 to clear
+
+/* R8_USB_INT_ST */
+#define USBFS_UIS_IS_NAK 0x80 // RO, indicate current USB transfer is NAK received for USB device mode
+#define USBFS_UIS_TOG_OK 0x40 // RO, indicate current USB transfer toggle is OK
+#define USBFS_UIS_TOKEN_MASK 0x30 // RO, bit mask of current token PID code received for USB device mode
+#define USBFS_UIS_TOKEN_OUT 0x00
+#define USBFS_UIS_TOKEN_SOF 0x10
+#define USBFS_UIS_TOKEN_IN 0x20
+#define USBFS_UIS_TOKEN_SETUP 0x30
+// bUIS_TOKEN1 & bUIS_TOKEN0: current token PID code received for USB device mode
+// 00: OUT token PID received
+// 01: SOF token PID received
+// 10: IN token PID received
+// 11: SETUP token PID received
+#define USBFS_UIS_ENDP_MASK 0x0F // RO, bit mask of current transfer endpoint number for USB device mode
+#define USBFS_UIS_H_RES_MASK 0x0F // RO, bit mask of current transfer handshake response for USB host mode: 0000=no response, time out from device, others=handshake response PID received
+
+/* R32_USB_OTG_CR */
+#define USBFS_CR_SESS_VTH 0x20
+#define USBFS_CR_VBUS_VTH 0x10
+#define USBFS_CR_OTG_EN 0x08
+#define USBFS_CR_IDPU 0x04
+#define USBFS_CR_CHARGE_VBUS 0x02
+#define USBFS_CR_DISCHAR_VBUS 0x01
+
+/* R32_USB_OTG_SR */
+#define USBFS_SR_ID_DIG 0x08
+#define USBFS_SR_SESS_END 0x04
+#define USBFS_SR_SESS_VLD 0x02
+#define USBFS_SR_VBUS_VLD 0x01
+
+/* R8_UDEV_CTRL */
+#define USBFS_UD_PD_DIS 0x80 // disable USB UDP/UDM pulldown resistance: 0=enable pulldown, 1=disable
+#define USBFS_UD_DP_PIN 0x20 // ReadOnly: indicate current UDP pin level
+#define USBFS_UD_DM_PIN 0x10 // ReadOnly: indicate current UDM pin level
+#define USBFS_UD_LOW_SPEED 0x04 // enable USB physical port low speed: 0=full speed, 1=low speed
+#define USBFS_UD_GP_BIT 0x02 // general purpose bit
+#define USBFS_UD_PORT_EN 0x01 // enable USB physical port I/O: 0=disable, 1=enable
+
+/* R8_UEP4_1_MOD */
+#define USBFS_UEP1_RX_EN 0x80 // enable USB endpoint 1 receiving (OUT)
+#define USBFS_UEP1_TX_EN 0x40 // enable USB endpoint 1 transmittal (IN)
+#define USBFS_UEP1_BUF_MOD 0x10 // buffer mode of USB endpoint 1
+#define USBFS_UEP4_RX_EN 0x08 // enable USB endpoint 4 receiving (OUT)
+#define USBFS_UEP4_TX_EN 0x04 // enable USB endpoint 4 transmittal (IN)
+#define USBFS_UEP4_BUF_MOD 0x01
+
+/* R8_UEP2_3_MOD */
+#define USBFS_UEP3_RX_EN 0x80 // enable USB endpoint 3 receiving (OUT)
+#define USBFS_UEP3_TX_EN 0x40 // enable USB endpoint 3 transmittal (IN)
+#define USBFS_UEP3_BUF_MOD 0x10 // buffer mode of USB endpoint 3
+#define USBFS_UEP2_RX_EN 0x08 // enable USB endpoint 2 receiving (OUT)
+#define USBFS_UEP2_TX_EN 0x04 // enable USB endpoint 2 transmittal (IN)
+#define USBFS_UEP2_BUF_MOD 0x01 // buffer mode of USB endpoint 2
+
+/* R8_UEP5_6_MOD */
+#define USBFS_UEP6_RX_EN 0x80 // enable USB endpoint 6 receiving (OUT)
+#define USBFS_UEP6_TX_EN 0x40 // enable USB endpoint 6 transmittal (IN)
+#define USBFS_UEP6_BUF_MOD 0x10 // buffer mode of USB endpoint 6
+#define USBFS_UEP5_RX_EN 0x08 // enable USB endpoint 5 receiving (OUT)
+#define USBFS_UEP5_TX_EN 0x04 // enable USB endpoint 5 transmittal (IN)
+#define USBFS_UEP5_BUF_MOD 0x01 // buffer mode of USB endpoint 5
+
+/* R8_UEP7_MOD */
+#define USBFS_UEP7_RX_EN 0x08 // enable USB endpoint 7 receiving (OUT)
+#define USBFS_UEP7_TX_EN 0x04 // enable USB endpoint 7 transmittal (IN)
+#define USBFS_UEP7_BUF_MOD 0x01 // buffer mode of USB endpoint 7
+
+/* R8_UEPn_TX_CTRL */
+#define USBFS_UEP_T_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion on endpoint 1/2/3: 0=manual toggle, 1=automatic toggle
+#define USBFS_UEP_T_TOG 0x04 // prepared data toggle flag of USB endpoint X transmittal (IN): 0=DATA0, 1=DATA1
+#define USBFS_UEP_T_RES_MASK 0x03 // bit mask of handshake response type for USB endpoint X transmittal (IN)
+#define USBFS_UEP_T_RES_ACK 0x00
+#define USBFS_UEP_T_RES_NONE 0x01
+#define USBFS_UEP_T_RES_NAK 0x02
+#define USBFS_UEP_T_RES_STALL 0x03
+// bUEP_T_RES1 & bUEP_T_RES0: handshake response type for USB endpoint X transmittal (IN)
+// 00: DATA0 or DATA1 then expecting ACK (ready)
+// 01: DATA0 or DATA1 then expecting no response, time out from host, for non-zero endpoint isochronous transactions
+// 10: NAK (busy)
+// 11: STALL (error)
+// host aux setup
+
+/* R8_UEPn_RX_CTRL, n=0-7 */
+#define USBFS_UEP_R_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion on endpoint 1/2/3: 0=manual toggle, 1=automatic toggle
+#define USBFS_UEP_R_TOG 0x04 // expected data toggle flag of USB endpoint X receiving (OUT): 0=DATA0, 1=DATA1
+#define USBFS_UEP_R_RES_MASK 0x03 // bit mask of handshake response type for USB endpoint X receiving (OUT)
+#define USBFS_UEP_R_RES_ACK 0x00
+#define USBFS_UEP_R_RES_NONE 0x01
+#define USBFS_UEP_R_RES_NAK 0x02
+#define USBFS_UEP_R_RES_STALL 0x03
+// RB_UEP_R_RES1 & RB_UEP_R_RES0: handshake response type for USB endpoint X receiving (OUT)
+// 00: ACK (ready)
+// 01: no response, time out to host, for non-zero endpoint isochronous transactions
+// 10: NAK (busy)
+// 11: STALL (error)
+
+/* R8_UHOST_CTRL */
+#define USBFS_UH_PD_DIS 0x80 // disable USB UDP/UDM pulldown resistance: 0=enable pulldown, 1=disable
+#define USBFS_UH_DP_PIN 0x20 // ReadOnly: indicate current UDP pin level
+#define USBFS_UH_DM_PIN 0x10 // ReadOnly: indicate current UDM pin level
+#define USBFS_UH_LOW_SPEED 0x04 // enable USB port low speed: 0=full speed, 1=low speed
+#define USBFS_UH_BUS_RESET 0x02 // control USB bus reset: 0=normal, 1=force bus reset
+#define USBFS_UH_PORT_EN 0x01 // enable USB port: 0=disable, 1=enable port, automatic disabled if USB device detached
+
+/* R32_UH_EP_MOD */
+#define USBFS_UH_EP_TX_EN 0x40 // enable USB host OUT endpoint transmittal
+#define USBFS_UH_EP_TBUF_MOD 0x10 // buffer mode of USB host OUT endpoint
+// bUH_EP_TX_EN & bUH_EP_TBUF_MOD: USB host OUT endpoint buffer mode, buffer start address is UH_TX_DMA
+// 0 x: disable endpoint and disable buffer
+// 1 0: 64 bytes buffer for transmittal (OUT endpoint)
+// 1 1: dual 64 bytes buffer by toggle bit bUH_T_TOG selection for transmittal (OUT endpoint), total=128bytes
+#define USBFS_UH_EP_RX_EN 0x08 // enable USB host IN endpoint receiving
+#define USBFS_UH_EP_RBUF_MOD 0x01 // buffer mode of USB host IN endpoint
+// bUH_EP_RX_EN & bUH_EP_RBUF_MOD: USB host IN endpoint buffer mode, buffer start address is UH_RX_DMA
+// 0 x: disable endpoint and disable buffer
+// 1 0: 64 bytes buffer for receiving (IN endpoint)
+// 1 1: dual 64 bytes buffer by toggle bit bUH_R_TOG selection for receiving (IN endpoint), total=128bytes
+
+/* R16_UH_SETUP */
+#define USBFS_UH_PRE_PID_EN 0x0400 // USB host PRE PID enable for low speed device via hub
+#define USBFS_UH_SOF_EN 0x0004 // USB host automatic SOF enable
+
+/* R8_UH_EP_PID */
+#define USBFS_UH_TOKEN_MASK 0xF0 // bit mask of token PID for USB host transfer
+#define USBFS_UH_ENDP_MASK 0x0F // bit mask of endpoint number for USB host transfer
+
+/* R8_UH_RX_CTRL */
+#define USBFS_UH_R_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion: 0=manual toggle, 1=automatic toggle
+#define USBFS_UH_R_TOG 0x04 // expected data toggle flag of host receiving (IN): 0=DATA0, 1=DATA1
+#define USBFS_UH_R_RES 0x01 // prepared handshake response type for host receiving (IN): 0=ACK (ready), 1=no response, time out to device, for isochronous transactions
+
+/* R8_UH_TX_CTRL */
+#define USBFS_UH_T_AUTO_TOG 0x08 // enable automatic toggle after successful transfer completion: 0=manual toggle, 1=automatic toggle
+#define USBFS_UH_T_TOG 0x04 // prepared data toggle flag of host transmittal (SETUP/OUT): 0=DATA0, 1=DATA1
+#define USBFS_UH_T_RES 0x01 // expected handshake response type for host transmittal (SETUP/OUT): 0=ACK (ready), 1=no response, time out from device, for isochronous transactions
+
+/* IO definitions */
+#ifdef __cplusplus
+#define __I volatile
+#else
+#define __I volatile const
+#endif
+
+#define __O volatile
+#define __IO volatile
+
+/* USBFS Device Registers */
+typedef struct
+{
+ __IO uint8_t BASE_CTRL;
+ __IO uint8_t UDEV_CTRL;
+ __IO uint8_t INT_EN;
+ __IO uint8_t DEV_ADDR;
+ __IO uint8_t Reserve0;
+ __IO uint8_t MIS_ST;
+ __IO uint8_t INT_FG;
+ __IO uint8_t INT_ST;
+ __IO uint32_t RX_LEN;
+ __IO uint8_t UEP4_1_MOD;
+ __IO uint8_t UEP2_3_MOD;
+ __IO uint8_t UEP5_6_MOD;
+ __IO uint8_t UEP7_MOD;
+ __IO uint32_t UEP0_DMA;
+ __IO uint32_t UEP1_DMA;
+ __IO uint32_t UEP2_DMA;
+ __IO uint32_t UEP3_DMA;
+ __IO uint32_t UEP4_DMA;
+ __IO uint32_t UEP5_DMA;
+ __IO uint32_t UEP6_DMA;
+ __IO uint32_t UEP7_DMA;
+ __IO uint16_t UEP0_TX_LEN;
+ union {
+ __IO uint16_t UEP0_CTRL;
+ struct {
+ __IO uint8_t UEP0_TX_CTRL;
+ __IO uint8_t UEP0_RX_CTRL;
+ };
+ };
+ __IO uint16_t UEP1_TX_LEN;
+ union {
+ __IO uint16_t UEP1_CTRL;
+ struct {
+ __IO uint8_t UEP1_TX_CTRL;
+ __IO uint8_t UEP1_RX_CTRL;
+ };
+ };
+ __IO uint16_t UEP2_TX_LEN;
+ union {
+ __IO uint16_t UEP2_CTRL;
+ struct {
+ __IO uint8_t UEP2_TX_CTRL;
+ __IO uint8_t UEP2_RX_CTRL;
+ };
+ };
+ __IO uint16_t UEP3_TX_LEN;
+ union {
+ __IO uint16_t UEP3_CTRL;
+ struct {
+ __IO uint8_t UEP3_TX_CTRL;
+ __IO uint8_t UEP3_RX_CTRL;
+ };
+ };
+ __IO uint16_t UEP4_TX_LEN;
+ union {
+ __IO uint16_t UEP4_CTRL;
+ struct {
+ __IO uint8_t UEP4_TX_CTRL;
+ __IO uint8_t UEP4_RX_CTRL;
+ };
+ };
+ __IO uint16_t UEP5_TX_LEN;
+ union {
+ __IO uint16_t UEP5_CTRL;
+ struct {
+ __IO uint8_t UEP5_TX_CTRL;
+ __IO uint8_t UEP5_RX_CTRL;
+ };
+ };
+ __IO uint16_t UEP6_TX_LEN;
+ union {
+ __IO uint16_t UEP6_CTRL;
+ struct {
+ __IO uint8_t UEP6_TX_CTRL;
+ __IO uint8_t UEP6_RX_CTRL;
+ };
+ };
+ __IO uint16_t UEP7_TX_LEN;
+ union {
+ __IO uint16_t UEP7_CTRL;
+ struct {
+ __IO uint8_t UEP7_TX_CTRL;
+ __IO uint8_t UEP7_RX_CTRL;
+ };
+ };
+ __IO uint32_t Reserve1;
+ __IO uint32_t OTG_CR;
+ __IO uint32_t OTG_SR;
+} USBFSD_TypeDef;
+
+/* USBFS Host Registers */
+typedef struct
+{
+ __IO uint8_t BASE_CTRL;
+ __IO uint8_t HOST_CTRL;
+ __IO uint8_t INT_EN;
+ __IO uint8_t DEV_ADDR;
+ __IO uint8_t Reserve0;
+ __IO uint8_t MIS_ST;
+ __IO uint8_t INT_FG;
+ __IO uint8_t INT_ST;
+ __IO uint16_t RX_LEN;
+ __IO uint16_t Reserve1;
+ __IO uint8_t Reserve2;
+ __IO uint8_t HOST_EP_MOD;
+ __IO uint16_t Reserve3;
+ __IO uint32_t Reserve4;
+ __IO uint32_t Reserve5;
+ __IO uint32_t HOST_RX_DMA;
+ __IO uint32_t HOST_TX_DMA;
+ __IO uint32_t Reserve6;
+ __IO uint32_t Reserve7;
+ __IO uint32_t Reserve8;
+ __IO uint32_t Reserve9;
+ __IO uint32_t Reserve10;
+ __IO uint16_t Reserve11;
+ __IO uint16_t HOST_SETUP;
+ __IO uint8_t HOST_EP_PID;
+ __IO uint8_t Reserve12;
+ __IO uint8_t Reserve13;
+ __IO uint8_t HOST_RX_CTRL;
+ __IO uint16_t HOST_TX_LEN;
+ __IO uint8_t HOST_TX_CTRL;
+ __IO uint8_t Reserve14;
+ __IO uint32_t Reserve15;
+ __IO uint32_t Reserve16;
+ __IO uint32_t Reserve17;
+ __IO uint32_t Reserve18;
+ __IO uint32_t Reserve19;
+ __IO uint32_t OTG_CR;
+ __IO uint32_t OTG_SR;
+} USBFSH_TypeDef;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/port/wch/usbhs/usb_dc_usbhs.c b/port/wch/usbhs/usb_dc_usbhs.c
new file mode 100644
index 00000000..ccb08020
--- /dev/null
+++ b/port/wch/usbhs/usb_dc_usbhs.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2026, Links ([email protected])
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "usbd_core.h"
+#include "usb_usbhs_reg.h"
+
+#if defined(CONFIG_USBDEV_MULT_DC)
+#define usb_dc_init usbd_wch_usbhs_dc_init
+#define usb_dc_deinit usbd_wch_usbhs_dc_deinit
+#define usbd_set_address usbd_wch_usbhs_set_address
+#define usbd_set_remote_wakeup usbd_wch_usbhs_set_remote_wakeup
+#define usbd_get_port_speed usbd_wch_usbhs_get_port_speed
+#define usbd_ep_open usbd_wch_usbhs_ep_open
+#define usbd_ep_open_extra usbd_wch_usbhs_ep_open_extra
+#define usbd_ep_close usbd_wch_usbhs_ep_close
+#define usbd_ep_set_stall usbd_wch_usbhs_ep_set_stall
+#define usbd_ep_clear_stall usbd_wch_usbhs_ep_clear_stall
+#define usbd_ep_is_stalled usbd_wch_usbhs_ep_is_stalled
+#define usbd_ep_start_write usbd_wch_usbhs_ep_start_write
+#define usbd_ep_start_read usbd_wch_usbhs_ep_start_read
+#define USBD_IRQHandler usbd_wch_usbhs_irq_handler
+#endif
+
+#ifndef CONFIG_USBDEV_EP_NUM
+#define CONFIG_USBDEV_EP_NUM 8
+#endif
+
+#define USBHSD ((USBHSD_TypeDef *)g_usbdev_bus[busid].reg_base)
+#define ENDP_MAX_LEN(ep) *((__IO uint32_t *)&(USBHSD->UEP0_MAX_LEN) + (ep))
+#define ENDP_TX_LEN(ep) *((__IO uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2)
+#define ENDP_RX_LEN(ep) *((__IO uint16_t *)&(USBHSD->UEP0_RX_LEN) + (ep) * 2)
+#define ENDP_RX_SIZE(ep) *((__IO uint16_t *)&(USBHSD->UEP1_RX_SIZE) + (ep - 1) * 2)
+#define ENDP_TX_CTRL(ep) *((__IO uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4)
+#define ENDP_RX_CTRL(ep) *((__IO uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4)
+#define ENDP_TX_DMA(ep) *((__IO uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1))
+#define ENDP_RX_DMA(ep) *((__IO uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1))
+
+struct ch32_usbhs_ep_state {
+ uint16_t ep_mps;
+ uint32_t xfer_len;
+ uint32_t actual_xfer_len;
+};
+
+struct ch32_usbhs_udc {
+ uint8_t dev_addr;
+ __attribute__((aligned(4))) struct usb_setup_packet setup;
+ struct ch32_usbhs_ep_state ep_in[CONFIG_USBDEV_EP_NUM];
+ struct ch32_usbhs_ep_state ep_out[CONFIG_USBDEV_EP_NUM];
+} g_ch32_usbhs_udc[CONFIG_USBDEV_MAX_BUS];
+
+extern void usb_dc_low_level_init(uint8_t busid);
+extern void usb_dc_low_level_deinit(uint8_t busid);
+
+int usb_dc_init(uint8_t busid)
+{
+ usb_dc_low_level_init(busid);
+
+ USBHSD->CONTROL = USBHS_UD_RST_LINK | USBHS_UD_PHY_SUSPENDM;
+ USBHSD->INT_EN = USBHS_UDIE_BUS_RST | USBHS_UDIE_SUSPEND | USBHS_UDIE_BUS_SLEEP | USBHS_UDIE_LPM_ACT |
+ USBHS_UDIE_TRANSFER | USBHS_UDIE_LINK_RDY;
+
+ USBHSD->UEP_TX_EN = 0;
+ USBHSD->UEP_RX_EN = 0;
+ USBHSD->UEP_TX_TOG_AUTO = 0;
+ USBHSD->UEP_RX_TOG_AUTO = 0;
+ USBHSD->UEP_TX_ISO = 0;
+ USBHSD->UEP_RX_ISO = 0;
+
+ USBHSD->DEV_AD = 0x00;
+
+#ifdef CONFIG_USB_HS
+ USBHSD->BASE_MODE = USBHS_UD_SPEED_HIGH;
+#else
+ USBHSD->BASE_MODE = USBHS_UD_SPEED_FULL;
+#endif
+
+ USBHSD->CONTROL = USBHS_UD_DEV_EN | USBHS_UD_DMA_EN | USBHS_UD_LPM_EN | USBHS_UD_PHY_SUSPENDM;
+ return 0;
+}
+
+int usb_dc_deinit(uint8_t busid)
+{
+ USBHSD->CONTROL = USBHS_UD_RST_SIE | USBHS_UD_RST_LINK;
+ usb_dc_low_level_deinit(busid);
+ return 0;
+}
+
+int usbd_set_address(uint8_t busid, const uint8_t addr)
+{
+ g_ch32_usbhs_udc[busid].dev_addr = addr;
+ return 0;
+}
+
+int usbd_set_remote_wakeup(uint8_t busid)
+{
+ USBHSD->WAKE_CTRL |= USBHS_UD_REMOTE_WKUP;
+ return 0;
+}
+
+uint8_t usbd_get_port_speed(uint8_t busid)
+{
+ if (USBHSD->MIS_ST & USBHS_UDMS_HS_MOD) {
+ return USB_SPEED_HIGH;
+ } else if ((USBHSD->BASE_MODE & USBHS_UD_SPEED_TYPE) == USBHS_UD_SPEED_LOW) {
+ return USB_SPEED_LOW;
+ } else {
+ return USB_SPEED_FULL;
+ }
+}
+
+int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
+{
+ uint8_t epid = USB_EP_GET_IDX(ep->bEndpointAddress);
+
+ if (epid >= CONFIG_USBDEV_EP_NUM) {
+ USB_LOG_ERR("Ep addr %02x overflow\r\n", ep->bEndpointAddress);
+ return -1;
+ }
+
+ uint8_t ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
+ uint16_t ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
+ uint32_t bit = 1 << epid;
+
+ if (USB_EP_DIR_IS_IN(ep->bEndpointAddress)) {
+ g_ch32_usbhs_udc[busid].ep_in[epid].ep_mps = ep_mps;
+ USBHSD->UEP_TX_EN |= bit;
+ USBHSD->UEP_TX_TOG_AUTO |= bit;
+ USBHSD->UEP_TX_ISO = ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS ? USBHSD->UEP_TX_ISO | bit : USBHSD->UEP_TX_ISO & ~bit;
+ if (ep_type == USB_ENDPOINT_TYPE_BULK) {
+ ENDP_MAX_LEN(epid) = ep_mps;
+ // No send ZLP.
+ USBHSD->UEP_TX_BURST |= bit;
+ USBHSD->UEP_TX_BURST_MODE |= bit;
+ } else {
+ USBHSD->UEP_TX_BURST &= ~bit;
+ USBHSD->UEP_TX_BURST_MODE &= ~bit;
+ }
+ ENDP_TX_CTRL(epid) = USBHS_UEP_T_RES_NAK;
+ } else {
+ g_ch32_usbhs_udc[busid].ep_out[epid].ep_mps = ep_mps;
+ ENDP_MAX_LEN(epid) = ep_mps;
+ USBHSD->UEP_RX_EN |= bit;
+ USBHSD->UEP_RX_TOG_AUTO |= bit;
+ USBHSD->UEP_RX_ISO = ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS ? USBHSD->UEP_RX_ISO | bit : USBHSD->UEP_RX_ISO & ~bit;
+ if (ep_type == USB_ENDPOINT_TYPE_BULK) {
+ // Response NYTE.
+ USBHSD->UEP_RX_BURST |= bit;
+ USBHSD->UEP_RX_RES_MODE |= bit;
+ } else {
+ USBHSD->UEP_RX_BURST &= ~bit;
+ USBHSD->UEP_RX_RES_MODE &= ~bit;
+ }
+ ENDP_RX_CTRL(epid) = USBHS_UEP_R_RES_NAK;
+ }
+
+ return 0;
+}
+
+int usbd_ep_close(uint8_t busid, const uint8_t ep)
+{
+ uint8_t epid = USB_EP_GET_IDX(ep);
+ uint32_t bit = 1 << epid;
+ if (USB_EP_DIR_IS_IN(ep)) {
+ USBHSD->UEP_TX_EN &= ~bit;
+ USBHSD->UEP_TX_TOG_AUTO &= ~bit;
+ USBHSD->UEP_TX_ISO &= ~bit;
+ USBHSD->UEP_TX_BURST &= ~bit;
+ } else {
+ USBHSD->UEP_RX_EN &= ~bit;
+ USBHSD->UEP_RX_TOG_AUTO &= ~bit;
+ USBHSD->UEP_RX_ISO &= ~bit;
+ USBHSD->UEP_RX_BURST &= ~bit;
+ }
+ return 0;
+}
+
+int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
+{
+ uint8_t ep_idx = USB_EP_GET_IDX(ep);
+ if (USB_EP_DIR_IS_OUT(ep)) {
+ ENDP_RX_CTRL(ep_idx) = (ENDP_RX_CTRL(ep_idx) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_STALL;
+ } else {
+ ENDP_TX_CTRL(ep_idx) = (ENDP_TX_CTRL(ep_idx) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_STALL;
+ }
+ return 0;
+}
+
+int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
+{
+ uint8_t ep_idx = USB_EP_GET_IDX(ep);
+ if (USB_EP_DIR_IS_OUT(ep)) {
+ USBHSD->UEP_RX_TOG_AUTO &= ~(1 << ep_idx);
+ ENDP_RX_CTRL(ep_idx) = USBHS_UEP_R_RES_ACK | USBHS_UEP_R_TOG_DATA0;
+ USBHSD->UEP_RX_TOG_AUTO |= 1 << ep_idx;
+ } else {
+ USBHSD->UEP_TX_TOG_AUTO &= ~(1 << ep_idx);
+ ENDP_TX_CTRL(ep_idx) = USBHS_UEP_T_RES_NAK | USBHS_UEP_T_TOG_DATA0;
+ USBHSD->UEP_TX_TOG_AUTO |= 1 << ep_idx;
+ }
+ return 0;
+}
+
+int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
+{
+ if (USB_EP_DIR_IS_OUT(ep)) {
+ *stalled = (ENDP_RX_CTRL(USB_EP_GET_IDX(ep)) & USBHS_UEP_R_RES_MASK) == USBHS_UEP_R_RES_STALL;
+ } else {
+ *stalled = (ENDP_TX_CTRL(USB_EP_GET_IDX(ep)) & USBHS_UEP_T_RES_MASK) == USBHS_UEP_T_RES_STALL;
+ }
+ return 0;
+}
+
+int usbd_ep_start_write(uint8_t busid, 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 (!(USBHSD->UEP_TX_EN & (1 << ep_idx))) {
+ return -2;
+ }
+ if ((uint32_t)data & 0x03) {
+ return -3;
+ }
+ if ((ENDP_TX_CTRL(ep_idx) & USBHS_UEP_T_RES_MASK) != USBHS_UEP_T_RES_NAK) {
+ return -4;
+ }
+
+ g_ch32_usbhs_udc[busid].ep_in[ep_idx].xfer_len = data_len;
+ g_ch32_usbhs_udc[busid].ep_in[ep_idx].actual_xfer_len = 0;
+
+ if (ep_idx == 0) {
+ USBHSD->UEP0_DMA = (uint32_t)data;
+ } else {
+ ENDP_TX_DMA(ep_idx) = (uint32_t)data;
+ }
+
+ if (USBHSD->UEP_TX_BURST & (1 << ep_idx)) {
+ ENDP_TX_LEN(ep_idx) = data_len;
+ } else {
+ ENDP_TX_LEN(ep_idx) = MIN(data_len, g_ch32_usbhs_udc[busid].ep_in[ep_idx].ep_mps);
+ }
+ ENDP_TX_CTRL(ep_idx) = (ENDP_TX_CTRL(ep_idx) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK;
+ return 0;
+}
+
+int usbd_ep_start_read(uint8_t busid, 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 (!(USBHSD->UEP_RX_EN & (1 << ep_idx))) {
+ return -2;
+ }
+ if ((uint32_t)data & 0x03) {
+ return -3;
+ }
+
+ g_ch32_usbhs_udc[busid].ep_out[ep_idx].xfer_len = data_len;
+ g_ch32_usbhs_udc[busid].ep_out[ep_idx].actual_xfer_len = 0;
+
+ if (ep_idx == 0) {
+ USBHSD->UEP0_DMA = (uint32_t)data;
+ } else {
+ ENDP_RX_DMA(ep_idx) = (uint32_t)data;
+ }
+
+ if (USBHSD->UEP_RX_BURST & (1 << ep_idx)) {
+ ENDP_RX_SIZE(ep_idx) = data_len;
+ } else {
+ ENDP_RX_SIZE(ep_idx) = MIN(data_len, g_ch32_usbhs_udc[busid].ep_out[ep_idx].ep_mps);
+ }
+ ENDP_RX_CTRL(ep_idx) = (ENDP_RX_CTRL(ep_idx) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_ACK;
+ return 0;
+}
+
+static inline void handle_ep0_in(uint8_t busid)
+{
+ if (g_ch32_usbhs_udc[busid].setup.bmRequestType & 0x80) {
+ USBHSD->UEP0_TX_CTRL ^= USBHS_UEP_T_TOG_DATA1;
+ ENDP_TX_CTRL(0) = (ENDP_TX_CTRL(0) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_NAK;
+
+ if (g_ch32_usbhs_udc[busid].ep_in[0].xfer_len > g_ch32_usbhs_udc[busid].ep_in[0].ep_mps) {
+ g_ch32_usbhs_udc[busid].ep_in[0].xfer_len -= g_ch32_usbhs_udc[busid].ep_in[0].ep_mps;
+ g_ch32_usbhs_udc[busid].ep_in[0].actual_xfer_len += g_ch32_usbhs_udc[busid].ep_in[0].ep_mps;
+ usbd_event_ep_in_complete_handler(busid, 0x80, g_ch32_usbhs_udc[busid].ep_in[0].actual_xfer_len);
+ } else {
+ g_ch32_usbhs_udc[busid].ep_in[0].actual_xfer_len += g_ch32_usbhs_udc[busid].ep_in[0].xfer_len;
+ g_ch32_usbhs_udc[busid].ep_in[0].xfer_len = 0;
+ usbd_event_ep_in_complete_handler(busid, 0x80, g_ch32_usbhs_udc[busid].ep_in[0].actual_xfer_len);
+ }
+ } else {
+ USBHSD->UEP0_DMA = (uint32_t)&g_ch32_usbhs_udc[busid].setup;
+ ENDP_TX_CTRL(0) = (ENDP_TX_CTRL(0) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_NAK;
+ ENDP_RX_CTRL(0) = (ENDP_RX_CTRL(0) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_ACK;
+ }
+}
+
+static inline void handle_non_ep0_in(uint8_t busid, uint8_t epid)
+{
+ ENDP_TX_CTRL(epid) = (ENDP_TX_CTRL(epid) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_NAK;
+
+ if (USBHSD->UEP_TX_BURST & (1 << epid)) {
+ usbd_event_ep_in_complete_handler(busid, 0x80 | epid, g_ch32_usbhs_udc[busid].ep_in[epid].xfer_len);
+ } else if (g_ch32_usbhs_udc[busid].ep_in[epid].xfer_len > g_ch32_usbhs_udc[busid].ep_in[epid].ep_mps) {
+ g_ch32_usbhs_udc[busid].ep_in[epid].xfer_len -= g_ch32_usbhs_udc[busid].ep_in[epid].ep_mps;
+ g_ch32_usbhs_udc[busid].ep_in[epid].actual_xfer_len += g_ch32_usbhs_udc[busid].ep_in[epid].ep_mps;
+
+ uint32_t write_count = MIN(g_ch32_usbhs_udc[busid].ep_in[epid].xfer_len, g_ch32_usbhs_udc[busid].ep_in[epid].ep_mps);
+ ENDP_TX_LEN(epid) = write_count;
+ ENDP_TX_DMA(epid) += g_ch32_usbhs_udc[busid].ep_in[epid].ep_mps;
+ ENDP_TX_CTRL(epid) = (ENDP_TX_CTRL(epid) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK;
+ } else {
+ g_ch32_usbhs_udc[busid].ep_in[epid].actual_xfer_len += g_ch32_usbhs_udc[busid].ep_in[epid].xfer_len;
+ g_ch32_usbhs_udc[busid].ep_in[epid].xfer_len = 0;
+ usbd_event_ep_in_complete_handler(busid, 0x80 | epid, g_ch32_usbhs_udc[busid].ep_in[epid].actual_xfer_len);
+ }
+}
+
+static inline void handle_ep0_out(uint8_t busid)
+{
+ USBHSD->UEP0_RX_CTRL ^= USBHS_UEP_R_TOG_DATA1;
+
+ uint32_t read_count = ENDP_RX_LEN(0);
+ read_count = MIN(read_count, g_ch32_usbhs_udc[busid].ep_out[0].xfer_len);
+ g_ch32_usbhs_udc[busid].ep_out[0].actual_xfer_len += read_count;
+ g_ch32_usbhs_udc[busid].ep_out[0].xfer_len -= read_count;
+ usbd_event_ep_out_complete_handler(busid, 0x00, g_ch32_usbhs_udc[busid].ep_out[0].actual_xfer_len);
+ if (read_count == 0) {
+ USBHSD->UEP0_DMA = (uint32_t)&g_ch32_usbhs_udc[busid].setup;
+ ENDP_RX_CTRL(0) = (ENDP_RX_CTRL(0) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_ACK;
+ }
+}
+
+static inline void handle_non_ep0_out(uint8_t busid, uint8_t epid)
+{
+ uint32_t read_count = ENDP_RX_LEN(epid);
+ read_count = MIN(read_count, g_ch32_usbhs_udc[busid].ep_out[epid].xfer_len);
+ if (USBHSD->UEP_RX_BURST & (1 << epid)) {
+ usbd_event_ep_out_complete_handler(busid, epid, read_count);
+ } else {
+ g_ch32_usbhs_udc[busid].ep_out[epid].actual_xfer_len += read_count;
+ g_ch32_usbhs_udc[busid].ep_out[epid].xfer_len -= read_count;
+ if ((read_count < g_ch32_usbhs_udc[busid].ep_out[epid].ep_mps) || (g_ch32_usbhs_udc[busid].ep_out[epid].xfer_len == 0)) {
+ usbd_event_ep_out_complete_handler(busid, epid, g_ch32_usbhs_udc[busid].ep_out[epid].actual_xfer_len);
+ } else {
+ ENDP_RX_DMA(epid) += g_ch32_usbhs_udc[busid].ep_out[epid].ep_mps;
+ ENDP_RX_SIZE(epid) = MIN(g_ch32_usbhs_udc[busid].ep_out[epid].xfer_len, g_ch32_usbhs_udc[busid].ep_out[epid].ep_mps);
+ ENDP_RX_CTRL(epid) = (ENDP_RX_CTRL(epid) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_ACK;
+ }
+ }
+}
+
+void USBD_IRQHandler(uint8_t busid)
+{
+ uint8_t flag = USBHSD->INT_FG;
+
+ if (flag & USBHS_UDIF_TRANSFER) {
+ uint8_t status = USBHSD->INT_ST;
+ uint8_t endp = status & USBHS_UDIS_EP_ID_MASK;
+ uint8_t dir = status & USBHS_UDIS_EP_DIR;
+
+ // SETUP packet received
+ if (endp == 0x00 && !dir && (ENDP_RX_CTRL(0) & USBHS_UEP_R_SETUP_IS)) {
+ ENDP_TX_CTRL(0) = (ENDP_TX_CTRL(0) & ~USBHS_UEP_T_TOG_MASK) | USBHS_UEP_T_TOG_DATA1;
+ ENDP_RX_CTRL(0) = (ENDP_RX_CTRL(0) & ~USBHS_UEP_R_TOG_MASK) | USBHS_UEP_R_TOG_DATA1;
+ if (!(g_ch32_usbhs_udc[busid].setup.bmRequestType & 0x80)) {
+ ENDP_TX_LEN(0) = 0;
+ ENDP_TX_CTRL(0) = (ENDP_TX_CTRL(0) & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK;
+ }
+ usbd_event_ep0_setup_complete_handler(busid, (uint8_t *)&g_ch32_usbhs_udc[busid].setup);
+ ENDP_RX_CTRL(0) = (ENDP_RX_CTRL(0) & ~USBHS_UEP_R_DONE);
+ }
+ // IN transfer
+ else if (dir) {
+ if (endp == 0) {
+ handle_ep0_in(busid);
+ } else {
+ handle_non_ep0_in(busid, endp);
+ }
+
+ if (g_ch32_usbhs_udc[busid].dev_addr) {
+ USBHSD->DEV_AD = g_ch32_usbhs_udc[busid].dev_addr;
+ g_ch32_usbhs_udc[busid].dev_addr = 0;
+ }
+
+ ENDP_TX_CTRL(endp) = (ENDP_TX_CTRL(endp) & ~USBHS_UEP_T_DONE);
+ }
+ // OUT transfer
+ else if (ENDP_RX_CTRL(endp) & USBHS_UEP_R_TOG_MATCH) {
+ if (endp == 0) {
+ handle_ep0_out(busid);
+ } else {
+ handle_non_ep0_out(busid, endp);
+ }
+ ENDP_RX_LEN(endp) = 0;
+ ENDP_RX_CTRL(endp) = (ENDP_RX_CTRL(endp) & ~USBHS_UEP_R_DONE);
+ } else {
+ // OUT transfer toggle mismatch
+ ENDP_RX_CTRL(endp) = (ENDP_RX_CTRL(endp) & ~(USBHS_UEP_R_DONE | USBHS_UEP_R_RES_MASK)) | USBHS_UEP_R_RES_ACK;
+ }
+ } else if (flag & USBHS_UDIF_BUS_RST) {
+ USBHSD->DEV_AD = 0;
+ USBHSD->UEP0_DMA = (uint32_t)&g_ch32_usbhs_udc[busid].setup;
+ USBHSD->UEP0_TX_CTRL = USBHS_UEP_T_RES_NAK;
+ USBHSD->UEP0_RX_CTRL = USBHS_UEP_R_RES_ACK;
+ usbd_event_reset_handler(busid);
+ USBHSD->INT_FG = USBHS_UDIF_BUS_RST;
+ } else if (flag & USBHS_UDIF_SUSPEND) {
+ if (USBHSD->MIS_ST & USBHS_UDMS_SUSPEND) {
+ usbd_event_suspend_handler(busid);
+ }
+ USBHSD->INT_FG = USBHS_UDIF_SUSPEND;
+ } else {
+ USBHSD->INT_FG = flag;
+ }
+}
+
+#if defined(CONFIG_USBDEV_MULT_DC)
+struct usbd_dc_driver wch_usbhs_dc_driver = {
+ .driver_name = "wch_usbhs_dcd",
+ .driver_desc = "WCH USBHS Device Controller",
+ .init = usb_dc_init,
+ .deinit = usb_dc_deinit,
+ .set_address = usbd_set_address,
+ .set_remote_wakeup = usbd_set_remote_wakeup,
+ .get_port_speed = usbd_get_port_speed,
+ .ep_open = usbd_ep_open,
+ .ep_close = usbd_ep_close,
+ .ep_set_stall = usbd_ep_set_stall,
+ .ep_clear_stall = usbd_ep_clear_stall,
+ .ep_is_stalled = usbd_ep_is_stalled,
+ .ep_start_write = usbd_ep_start_write,
+ .ep_start_read = usbd_ep_start_read,
+ .irq_handler = USBD_IRQHandler,
+};
+#endif
diff --git a/port/wch/usbhs/usb_hc_usbhs.c b/port/wch/usbhs/usb_hc_usbhs.c
new file mode 100644
index 00000000..53b7ef84
--- /dev/null
+++ b/port/wch/usbhs/usb_hc_usbhs.c
@@ -0,0 +1,827 @@
+/*
+ * Copyright (c) 2026, Links ([email protected])
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "usbh_core.h"
+#include "usbh_hub.h"
+#include "usb_usbhs_reg.h"
+
+#if defined(CONFIG_USBHOST_MULT_HC)
+#define usb_hc_init usbh_wch_usbhs_hc_init
+#define usb_hc_deinit usbh_wch_usbhs_hc_deinit
+#define usbh_get_frame_number usbh_wch_usbhs_get_frame_number
+#define usbh_roothub_control usbh_wch_usbhs_roothub_control
+#define usbh_submit_urb usbh_wch_usbhs_submit_urb
+#define usbh_kill_urb usbh_wch_usbhs_kill_urb
+#define USBH_IRQHandler usbh_wch_usbhs_irq_handler
+
+int usbh_wch_usbhs_kill_urb(struct usbh_urb *urb);
+#endif
+
+#define USBHSH ((USBHSH_TypeDef *)bus->hcd.reg_base)
+
+#define SPLIT_MAX_RETRY 6
+#define HIGH_SPLIT_ISO_OUT_MAX_SIZE 188
+
+typedef enum {
+ USB_EP0_STATE_SETUP,
+ USB_EP0_STATE_DATA,
+ USB_EP0_STATE_STATUS,
+} ep0_state_t;
+
+typedef enum {
+ XFER_STATE_IDLE,
+ XFER_STATE_BUSY,
+ XFER_STATE_COMP,
+} xfer_state_t;
+
+typedef enum {
+ ENDP_TOG_DATA0,
+ ENDP_TOG_DATA1,
+ ENDP_TOG_DATA2,
+ ENDP_TOG_MDATA,
+} endp_tog_t;
+
+struct usbhs_pipe;
+
+typedef struct
+{
+ union {
+ uint32_t split_data;
+
+ struct
+ {
+ uint32_t hub_addr : 7;
+ uint32_t sc : 1;
+ uint32_t port : 7;
+ uint32_t s : 1;
+ uint32_t e : 1;
+ uint32_t et : 2;
+ uint32_t reserved : 13;
+ };
+ };
+
+ uint16_t iso_out_length;
+ uint16_t iso_out_offset;
+} split_data_t;
+
+typedef struct usbhs_xfer {
+ uint8_t pre;
+ uint8_t endp;
+ uint8_t token;
+ uint8_t toggle;
+ uint8_t dev_addr;
+ uint8_t xfer_state;
+ uint8_t split_retry;
+ uint8_t split_mframe;
+ uint16_t length;
+ uint8_t *buffer;
+ split_data_t split_data;
+ struct usbhs_pipe *pipe;
+ struct usbhs_xfer *next;
+} usbhs_xfer_t;
+
+struct usbhs_pipe {
+ bool used;
+ bool killed;
+ bool ping;
+ bool ping_en;
+ uint8_t type;
+ uint8_t ep0_state;
+ uint32_t tick;
+ uint32_t interval;
+ usb_osal_sem_t waitsem;
+ usbhs_xfer_t xfer;
+ struct usbh_urb *urb;
+ struct usbhs_pipe *prev;
+ struct usbhs_pipe *next;
+};
+
+struct usbhs_hcd {
+ bool sof_act;
+ bool port_csc;
+ bool port_pec;
+ bool port_ssc;
+ bool port_rsc;
+ uint8_t speed;
+ uint32_t tick;
+ usbhs_xfer_t *curr_xfer;
+ struct usbhs_pipe *pipe_list[4];
+ struct usbhs_pipe pipe_pool[8];
+} g_usbhs_hcd[CONFIG_USBHOST_MAX_BUS];
+
+static struct usbhs_pipe *usbhs_pipe_alloc(struct usbh_bus *bus, struct usbh_urb *urb, struct usb_endpoint_descriptor *ep)
+{
+ for (size_t chidx = 0; chidx < sizeof(g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool) / sizeof(struct usbhs_pipe); chidx++) {
+ if (!g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].used) {
+ uint8_t type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].used = true;
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].killed = false;
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].ping = false;
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].type = type;
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].ep0_state = USB_EP0_STATE_SETUP;
+ if (g_usbhs_hcd[bus->hcd.hcd_id].speed == USB_SPEED_HIGH &&
+ (type == USB_ENDPOINT_TYPE_CONTROL || type == USB_ENDPOINT_TYPE_BULK)) {
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].ping_en = true;
+ } else {
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].ping_en = false;
+ }
+ if (type == USB_ENDPOINT_TYPE_ISOCHRONOUS || type == USB_ENDPOINT_TYPE_INTERRUPT) {
+ uint8_t interval = ep->bInterval;
+ if (g_usbhs_hcd[bus->hcd.hcd_id].speed == USB_SPEED_HIGH) {
+ if (urb->hport->speed == USB_SPEED_HIGH) {
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].interval = 1 << (interval - 1);
+ } else if (type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].interval = (1 << (interval - 1)) << 3;
+ } else {
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].interval = interval << 3;
+ }
+ } else if (type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].interval = 1 << (interval - 1);
+ } else {
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].interval = interval;
+ }
+ } else {
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].interval = 0;
+ }
+
+ memset(&g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].xfer, 0, sizeof(usbhs_xfer_t));
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].urb = urb;
+ if (g_usbhs_hcd[bus->hcd.hcd_id].pipe_list[type] == NULL) {
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].prev = NULL;
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_list[type] = &g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx];
+ } else {
+ struct usbhs_pipe *ppipe = g_usbhs_hcd[bus->hcd.hcd_id].pipe_list[type];
+ while (ppipe->next) {
+ ppipe = ppipe->next;
+ }
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].prev = ppipe;
+ ppipe->next = &g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx];
+ }
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx].next = NULL;
+ return &g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[chidx];
+ }
+ }
+
+ return NULL;
+}
+
+static void usbhs_pipe_free(struct usbh_bus *bus, struct usbhs_pipe *pipe, uint8_t type)
+{
+ usbhs_xfer_t *xfer = &pipe->xfer;
+
+ size_t flags = usb_osal_enter_critical_section();
+
+ if (xfer->xfer_state != XFER_STATE_BUSY) {
+ if (pipe->prev) {
+ pipe->prev->next = pipe->next;
+ } else {
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_list[type] = pipe->next;
+ }
+
+ if (pipe->next) {
+ pipe->next->prev = pipe->prev;
+ }
+
+ pipe->used = false;
+ } else {
+ pipe->killed = true;
+ }
+ usb_osal_leave_critical_section(flags);
+}
+
+static usbhs_xfer_t **usbhs_xfer_process(struct usbh_bus *bus, usbhs_xfer_t **last_xfer, uint8_t type)
+{
+ struct usbhs_pipe *pipe = g_usbhs_hcd[bus->hcd.hcd_id].pipe_list[type];
+
+ while (pipe) {
+ usbhs_xfer_t *xfer = &pipe->xfer;
+ if (xfer->xfer_state != XFER_STATE_COMP) {
+ struct usbh_urb *urb = pipe->urb;
+ if (urb->hport->speed != g_usbhs_hcd[bus->hcd.hcd_id].speed) {
+ if (g_usbhs_hcd[bus->hcd.hcd_id].speed == USB_SPEED_FULL) {
+ xfer->pre = 1;
+ } else {
+ split_data_t *split = &xfer->split_data;
+ uint8_t mframe = (USBHSH->FRAME & USBHS_UH_MFRAME_NO) >> 16;
+
+ if (split->sc == 1 || split->iso_out_offset) {
+ if (mframe != xfer->split_mframe) {
+ xfer->split_mframe = mframe;
+ xfer->xfer_state = XFER_STATE_BUSY;
+ *last_xfer = xfer;
+ last_xfer = &xfer->next;
+ }
+
+ pipe = pipe->next;
+ continue;
+ }
+
+ static const uint8_t valid_microframe[] = { 6, 1, 6, 2 };
+ if (mframe >= valid_microframe[type]) {
+ pipe = pipe->next;
+ continue;
+ }
+
+ struct usbh_hubport *port = urb->hport;
+ while (port->parent && port->parent->speed != USB_SPEED_HIGH) {
+ port = port->parent->parent;
+ }
+
+ split->hub_addr = port->parent->hub_addr;
+ split->sc = 0;
+ split->port = port->port;
+ split->s = urb->hport->speed == USB_SPEED_LOW ? 1 : 0;
+ split->e = 0;
+ split->et = type;
+
+ if (type == USB_ENDPOINT_TYPE_ISOCHRONOUS && xfer->token == USB_PID_OUT) {
+ split->iso_out_length = MIN(urb->transfer_buffer_length - urb->actual_length, 1023);
+ split->iso_out_offset = 0;
+ split->s = 1;
+ split->e = split->iso_out_length <= HIGH_SPLIT_ISO_OUT_MAX_SIZE ? 1 : 0;
+ }
+ }
+ }
+
+ if (pipe->ping) {
+ xfer->token = USB_PID_PING;
+ xfer->xfer_state = XFER_STATE_BUSY;
+ *last_xfer = xfer;
+ last_xfer = &xfer->next;
+ pipe = pipe->next;
+ continue;
+ }
+
+ xfer->dev_addr = urb->hport->dev_addr;
+ xfer->pipe = pipe;
+
+ if (type == USB_ENDPOINT_TYPE_CONTROL) {
+ xfer->endp = 0;
+ switch (pipe->ep0_state) {
+ case USB_EP0_STATE_SETUP:
+ xfer->token = USB_PID_SETUP;
+ xfer->toggle = ENDP_TOG_DATA0;
+ xfer->length = sizeof(struct usb_setup_packet);
+ xfer->buffer = (uint8_t *)(urb->setup);
+ break;
+
+ case USB_EP0_STATE_DATA:
+ xfer->token = urb->setup->bmRequestType & 0x80 ? USB_PID_IN : USB_PID_OUT;
+ xfer->toggle = urb->data_toggle;
+ xfer->length = MIN(urb->transfer_buffer_length - (urb->actual_length - sizeof(struct usb_setup_packet)),
+ USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize));
+ xfer->buffer = urb->transfer_buffer + urb->actual_length - sizeof(struct usb_setup_packet);
+ break;
+
+ case USB_EP0_STATE_STATUS:
+ xfer->token = urb->setup->bmRequestType & 0x80 ? USB_PID_OUT : USB_PID_IN;
+ xfer->toggle = ENDP_TOG_DATA1;
+ xfer->length = 0;
+ xfer->buffer = NULL;
+ break;
+ }
+
+ xfer->xfer_state = XFER_STATE_BUSY;
+ *last_xfer = xfer;
+ last_xfer = &xfer->next;
+ } else if (pipe->interval == 0 || g_usbhs_hcd[bus->hcd.hcd_id].tick - pipe->tick >= pipe->interval) {
+ pipe->tick = g_usbhs_hcd[bus->hcd.hcd_id].tick;
+ xfer->endp = USB_EP_GET_IDX(urb->ep->bEndpointAddress);
+ xfer->token = USB_EP_GET_DIR(urb->ep->bEndpointAddress) ? USB_PID_IN : USB_PID_OUT;
+ xfer->toggle = urb->data_toggle;
+ xfer->length = MIN(urb->transfer_buffer_length - urb->actual_length, USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize));
+ xfer->buffer = urb->transfer_buffer + urb->actual_length;
+
+ xfer->xfer_state = XFER_STATE_BUSY;
+ *last_xfer = xfer;
+ last_xfer = &xfer->next;
+ }
+ }
+
+ pipe = pipe->next;
+ }
+
+ return last_xfer;
+}
+
+static void usbhs_transfer_start(struct usbh_bus *bus)
+{
+ if ((USBHSH->CONTROL & USBHS_UH_HOST_ACTION) || (USBHSH->INT_FLAG & USBHS_UHIF_TRANSFER) ||
+ !(USBHSH->PORT_STATUS & USBHS_UHIS_PORT_CONNECT)) {
+ return;
+ }
+
+ if (g_usbhs_hcd[bus->hcd.hcd_id].sof_act || !g_usbhs_hcd[bus->hcd.hcd_id].curr_xfer) {
+ g_usbhs_hcd[bus->hcd.hcd_id].curr_xfer = NULL;
+ usbhs_xfer_t **last_xfer = &g_usbhs_hcd[bus->hcd.hcd_id].curr_xfer;
+
+ if (g_usbhs_hcd[bus->hcd.hcd_id].sof_act) {
+ g_usbhs_hcd[bus->hcd.hcd_id].sof_act = 0;
+ last_xfer = usbhs_xfer_process(bus, last_xfer, USB_ENDPOINT_TYPE_ISOCHRONOUS);
+ last_xfer = usbhs_xfer_process(bus, last_xfer, USB_ENDPOINT_TYPE_INTERRUPT);
+ }
+
+ last_xfer = usbhs_xfer_process(bus, last_xfer, USB_ENDPOINT_TYPE_CONTROL);
+ last_xfer = usbhs_xfer_process(bus, last_xfer, USB_ENDPOINT_TYPE_BULK);
+ *last_xfer = NULL;
+ }
+
+ if (g_usbhs_hcd[bus->hcd.hcd_id].curr_xfer) {
+ usbhs_xfer_t *xfer = g_usbhs_hcd[bus->hcd.hcd_id].curr_xfer;
+ uint32_t supplement = 0;
+ if (xfer->split_data.split_data) {
+ split_data_t *split = &xfer->split_data;
+ USBHSH->SPLIT = split->split_data;
+
+ if (split->sc == 0) {
+ if (split->et == USB_ENDPOINT_TYPE_ISOCHRONOUS || split->et == USB_ENDPOINT_TYPE_INTERRUPT) {
+ supplement = USBHS_UH_SPLIT_VALID | USBHS_UH_TX_NO_RES | USBHS_UH_RX_NO_DATA;
+ } else {
+ supplement = USBHS_UH_SPLIT_VALID | USBHS_UH_RX_NO_DATA;
+ }
+ } else {
+ supplement = USBHS_UH_SPLIT_VALID | USBHS_UH_RX_NO_RES | USBHS_UH_TX_NO_DATA;
+ }
+ } else if (xfer->pre) {
+ supplement = USBHS_UH_PRE_PID_EN;
+ }
+
+ if (xfer->pipe->type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
+ supplement |= USBHS_UH_RX_NO_RES | USBHS_UH_TX_NO_RES;
+ }
+
+ USBHSH->DEV_ADDR = xfer->dev_addr;
+ if (xfer->token == USB_PID_IN) {
+ USBHSH->RX_MAX_LEN = xfer->length;
+ USBHSH->RX_DMA = (uint32_t)xfer->buffer;
+ USBHSH->CONTROL = USBHS_UH_HOST_ACTION | xfer->token | (xfer->endp << 4) | supplement;
+ } else if (xfer->token == USB_PID_OUT || xfer->token == USB_PID_SETUP) {
+ USBHSH->TX_LEN = xfer->length;
+ USBHSH->TX_DMA = (uint32_t)xfer->buffer;
+ USBHSH->CONTROL = USBHS_UH_HOST_ACTION | xfer->token | (xfer->endp << 4) | (xfer->toggle << 8) | supplement;
+ } else if (xfer->token == USB_PID_PING) {
+ USBHSH->TX_LEN = 0;
+ USBHSH->TX_DMA = 0;
+ USBHSH->CONTROL = USBHS_UH_HOST_ACTION | xfer->token | (xfer->endp << 4);
+ }
+ }
+}
+
+static bool usbhs_split_transfer_complete(struct usbh_bus *bus, usbhs_xfer_t *xfer, uint8_t recv_pid)
+{
+ split_data_t *split = &xfer->split_data;
+
+ if (split->sc == 0) {
+ if (split->iso_out_length) {
+ split->iso_out_offset += xfer->length;
+
+ if (split->iso_out_offset >= split->iso_out_length) {
+ xfer->length = split->iso_out_offset;
+ split->iso_out_offset = 0;
+ return true;
+ }
+
+ xfer->buffer += xfer->length;
+
+ uint16_t remaining_length = split->iso_out_length - split->iso_out_offset;
+ if (remaining_length <= HIGH_SPLIT_ISO_OUT_MAX_SIZE) {
+ split->s = 0;
+ split->e = 1;
+ xfer->length = remaining_length;
+ } else {
+ split->s = 0;
+ split->e = 0;
+ xfer->length = HIGH_SPLIT_ISO_OUT_MAX_SIZE;
+ }
+
+ return false;
+ }
+
+ if (split->et == USB_ENDPOINT_TYPE_INTERRUPT || split->et == USB_ENDPOINT_TYPE_ISOCHRONOUS || recv_pid == USB_PID_ACK) {
+ split->sc = 1;
+ xfer->split_retry = 0;
+ xfer->split_mframe = (USBHSH->FRAME & USBHS_UH_MFRAME_NO) >> 16;
+ return false;
+ }
+ } else if (recv_pid == USB_PID_NYET) {
+ xfer->split_retry++;
+ if (xfer->split_retry >= SPLIT_MAX_RETRY) {
+ split->sc = 0;
+ }
+ return false;
+ } else if (recv_pid == USB_PID_MDATA) {
+ xfer->buffer += xfer->length;
+ return false;
+ }
+
+ split->sc = 0;
+ return true;
+}
+
+static void usbhs_transfer_complete(struct usbh_bus *bus, uint8_t recv_pid, size_t recv_len)
+{
+ static const uint8_t tog_pid[] = { USB_PID_DATA0, USB_PID_DATA1, USB_PID_DATA2, USB_PID_MDATA };
+
+ usbhs_xfer_t *xfer = g_usbhs_hcd[bus->hcd.hcd_id].curr_xfer;
+ struct usbhs_pipe *pipe = xfer->pipe;
+
+ xfer->xfer_state = XFER_STATE_IDLE;
+ if (pipe->killed) {
+ usbhs_pipe_free(bus, pipe, pipe->type);
+ return;
+ }
+
+ if (xfer->split_data.split_data && !usbhs_split_transfer_complete(bus, xfer, recv_pid)) {
+ return;
+ }
+
+ struct usbh_urb *urb = pipe->urb;
+ if (recv_pid == USB_PID_ACK || recv_pid == USB_PID_NYET || recv_pid == tog_pid[xfer->toggle]) {
+ if (xfer->token == USB_PID_PING) {
+ pipe->ping = false;
+ return;
+ }
+
+ if (recv_pid == USB_PID_NYET) {
+ pipe->ping = true;
+ }
+
+ size_t len = xfer->token == USB_PID_IN ? recv_len : xfer->length;
+ urb->actual_length += len;
+
+ if (xfer->endp != 0) {
+ urb->data_toggle ^= ENDP_TOG_DATA1;
+ if (len < USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize) || urb->actual_length >= urb->transfer_buffer_length) {
+ urb->errorcode = 0;
+ goto end;
+ }
+ } else if (pipe->ep0_state == USB_EP0_STATE_SETUP) {
+ urb->data_toggle = ENDP_TOG_DATA1;
+ pipe->ep0_state = urb->transfer_buffer_length ? USB_EP0_STATE_DATA : USB_EP0_STATE_STATUS;
+ } else if (pipe->ep0_state == USB_EP0_STATE_DATA) {
+ if (len < USB_GET_MAXPACKETSIZE(urb->ep->wMaxPacketSize) ||
+ (urb->actual_length - sizeof(struct usb_setup_packet)) >= urb->transfer_buffer_length) {
+ urb->data_toggle = ENDP_TOG_DATA1;
+ pipe->ep0_state = USB_EP0_STATE_STATUS;
+ } else {
+ urb->data_toggle ^= ENDP_TOG_DATA1;
+ }
+ } else {
+ urb->errorcode = 0;
+ goto end;
+ }
+ } else if (recv_pid == USB_PID_STALL) {
+ urb->errorcode = -USB_ERR_STALL;
+ goto end;
+ } else if (recv_pid == USB_PID_NAK) {
+ if (pipe->ping_en && xfer->token == USB_PID_OUT) {
+ pipe->ping = true;
+ }
+ } else {
+ urb->errorcode = -USB_ERR_IO;
+ goto end;
+ }
+ return;
+
+end:
+ xfer->xfer_state = XFER_STATE_COMP;
+ if (urb->timeout) {
+ usb_osal_sem_give(pipe->waitsem);
+ } else {
+ usbhs_pipe_free(bus, pipe, pipe->type);
+ }
+
+ if (urb->complete) {
+ if (urb->errorcode < 0) {
+ urb->complete(urb->arg, urb->errorcode);
+ } else {
+ urb->complete(urb->arg, urb->actual_length);
+ }
+ }
+}
+
+extern void usb_hc_low_level_init(struct usbh_bus *bus);
+extern void usb_hc_low_level_deinit(struct usbh_bus *bus);
+
+int usb_hc_init(struct usbh_bus *bus)
+{
+ memset(&g_usbhs_hcd[bus->hcd.hcd_id], 0, sizeof(struct usbhs_hcd));
+ usb_hc_low_level_init(bus);
+
+ for (uint8_t i = 0; i < sizeof(g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool) / sizeof(struct usbhs_pipe); i++) {
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem = usb_osal_sem_create(0);
+ USB_ASSERT(g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem != NULL);
+ }
+
+ USBHSH->CFG = USBHS_RST_LINK | USBHS_UH_PHY_SUSPENDM;
+ USBHSH->PORT_CFG = USBHS_UH_PD_EN | USBHS_UH_HOST_EN;
+ USBHSH->FRAME |= USBHS_UH_SOF_CNT_EN;
+ USBHSH->CFG = USBHS_UH_SOF_EN | USBHS_UH_DMA_EN | USBHS_UH_PHY_SUSPENDM;
+ USBHSH->INT_EN = USBHS_UHIE_SOF_ACT | USBHS_UHIE_TRANSFER;
+ USBHSH->PORT_INT_EN = USBHS_UHIE_PORT_RESET | USBHS_UHIE_PORT_SUSP | USBHS_UHIE_PORT_EN | USBHS_UHIE_PORT_CONNECT;
+ return 0;
+}
+
+int usb_hc_deinit(struct usbh_bus *bus)
+{
+ USBHSH->CFG = USBHS_RST_LINK | USBHS_RST_SIE | USBHS_UH_CLR_ALL;
+
+ for (uint8_t i = 0; i < sizeof(g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool) / sizeof(struct usbhs_pipe); i++) {
+ if (g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem) {
+ usb_osal_sem_delete(g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem);
+ g_usbhs_hcd[bus->hcd.hcd_id].pipe_pool[i].waitsem = NULL;
+ }
+ }
+
+ usb_hc_low_level_deinit(bus);
+ return 0;
+}
+
+uint16_t usbh_get_frame_number(struct usbh_bus *bus)
+{
+ return USBHSH->FRAME & USBHS_UH_FRAME_NO;
+}
+
+int usbh_roothub_control(struct usbh_bus *bus, struct usb_setup_packet *setup, uint8_t *buf)
+{
+ uint8_t nports;
+ uint8_t port;
+ uint32_t status;
+
+ nports = CONFIG_USBHOST_MAX_RHPORTS;
+ port = setup->wIndex;
+ if ((setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) == USB_REQUEST_RECIPIENT_DEVICE) {
+ switch (setup->bRequest) {
+ case HUB_REQUEST_CLEAR_FEATURE:
+ switch (setup->wValue) {
+ case HUB_FEATURE_HUB_C_LOCALPOWER:
+ break;
+ case HUB_FEATURE_HUB_C_OVERCURRENT:
+ break;
+ default:
+ return -USB_ERR_NOTSUPP;
+ }
+ break;
+ case HUB_REQUEST_SET_FEATURE:
+ switch (setup->wValue) {
+ case HUB_FEATURE_HUB_C_LOCALPOWER:
+ break;
+ case HUB_FEATURE_HUB_C_OVERCURRENT:
+ break;
+ default:
+ return -USB_ERR_NOTSUPP;
+ }
+ break;
+ case HUB_REQUEST_GET_DESCRIPTOR:
+ break;
+ case HUB_REQUEST_GET_STATUS:
+ memset(buf, 0, 4);
+ break;
+ default:
+ break;
+ }
+ } else if ((setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) == USB_REQUEST_RECIPIENT_OTHER) {
+ uint16_t port_status;
+ switch (setup->bRequest) {
+ case HUB_REQUEST_CLEAR_FEATURE:
+ if (!port || port > nports) {
+ return -USB_ERR_INVAL;
+ }
+
+ switch (setup->wValue) {
+ case HUB_PORT_FEATURE_ENABLE:
+ break;
+ case HUB_PORT_FEATURE_SUSPEND:
+ break;
+ case HUB_PORT_FEATURE_C_SUSPEND:
+ g_usbhs_hcd[bus->hcd.hcd_id].port_ssc = 0;
+ break;
+ case HUB_PORT_FEATURE_POWER:
+ break;
+ case HUB_PORT_FEATURE_C_CONNECTION:
+ g_usbhs_hcd[bus->hcd.hcd_id].port_csc = 0;
+ break;
+ case HUB_PORT_FEATURE_C_ENABLE:
+ g_usbhs_hcd[bus->hcd.hcd_id].port_pec = 0;
+ break;
+ case HUB_PORT_FEATURE_C_OVER_CURREN:
+ break;
+ case HUB_PORT_FEATURE_C_RESET:
+ g_usbhs_hcd[bus->hcd.hcd_id].port_rsc = 0;
+ break;
+ default:
+ return -USB_ERR_NOTSUPP;
+ }
+ break;
+ case HUB_REQUEST_SET_FEATURE:
+ if (!port || port > nports) {
+ return -USB_ERR_INVAL;
+ }
+
+ switch (setup->wValue) {
+ case HUB_PORT_FEATURE_SUSPEND:
+ break;
+ case HUB_PORT_FEATURE_POWER:
+ break;
+ case HUB_PORT_FEATURE_RESET:
+ USBHSH->PORT_CTRL |= USBHS_UH_SET_PORT_RESET;
+ break;
+
+ default:
+ return -USB_ERR_NOTSUPP;
+ }
+ break;
+ case HUB_REQUEST_GET_STATUS:
+ if (!port || port > nports) {
+ return -USB_ERR_INVAL;
+ }
+ status = 0;
+
+ if (g_usbhs_hcd[bus->hcd.hcd_id].port_csc)
+ status |= (1 << HUB_PORT_FEATURE_C_CONNECTION);
+ if (g_usbhs_hcd[bus->hcd.hcd_id].port_pec)
+ status |= (1 << HUB_PORT_FEATURE_C_ENABLE);
+ if (g_usbhs_hcd[bus->hcd.hcd_id].port_ssc)
+ status |= (1 << HUB_PORT_FEATURE_C_SUSPEND);
+ if (g_usbhs_hcd[bus->hcd.hcd_id].port_rsc)
+ status |= (1 << HUB_PORT_FEATURE_C_RESET);
+
+ port_status = USBHSH->PORT_STATUS;
+ status |= (1 << HUB_PORT_FEATURE_POWER);
+ if (port_status & USBHS_UHIS_PORT_CONNECT)
+ status |= (1 << HUB_PORT_FEATURE_CONNECTION);
+ if (port_status & USBHS_UHIS_PORT_EN)
+ status |= (1 << HUB_PORT_FEATURE_ENABLE);
+ if (port_status & USBHS_UHIS_PORT_SUSP)
+ status |= (1 << HUB_PORT_FEATURE_SUSPEND);
+ if (port_status & USBHS_UHIS_PORT_RST)
+ status |= (1 << HUB_PORT_FEATURE_RESET);
+ if (port_status & USBHS_UHIS_PORT_LS)
+ status |= (1 << HUB_PORT_FEATURE_LOWSPEED);
+ if (port_status & USBHS_UHIS_PORT_HS)
+ status |= (1 << HUB_PORT_FEATURE_HIGHSPEED);
+ if (port_status & USBHS_UHIS_PORT_TEST)
+ status |= (1 << HUB_PORT_FEATURE_TEST);
+
+ if (port_status & USBHS_UHIS_PORT_HS)
+ g_usbhs_hcd[bus->hcd.hcd_id].speed = USB_SPEED_HIGH;
+ else if (port_status & USBHS_UHIS_PORT_LS)
+ g_usbhs_hcd[bus->hcd.hcd_id].speed = USB_SPEED_LOW;
+ else
+ g_usbhs_hcd[bus->hcd.hcd_id].speed = USB_SPEED_FULL;
+
+ memcpy(buf, &status, 4);
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+int usbh_submit_urb(struct usbh_urb *urb)
+{
+ if (!urb || !urb->hport || !urb->ep || !urb->hport->bus) {
+ return -USB_ERR_INVAL;
+ }
+
+ int ret = 0;
+ struct usbh_bus *bus = urb->hport->bus;
+
+ /* dma addr must be aligned 4 bytes */
+ USB_ASSERT_MSG(!((uintptr_t)urb->setup % 4) && !((uintptr_t)urb->transfer_buffer % 4),
+ "urb->setup or urb->transfer_buffer is not aligned 4 bytes");
+
+ if (!urb->hport->connected) {
+ return -USB_ERR_NOTCONN;
+ }
+
+ if (urb->errorcode == -USB_ERR_BUSY) {
+ return -USB_ERR_BUSY;
+ }
+
+ size_t flags = usb_osal_enter_critical_section();
+ struct usbhs_pipe *pipe = usbhs_pipe_alloc(bus, urb, urb->ep);
+ if (!pipe) {
+ usb_osal_leave_critical_section(flags);
+ return -USB_ERR_NOMEM;
+ }
+
+ urb->hcpriv = pipe;
+ urb->errorcode = -USB_ERR_BUSY;
+ urb->actual_length = 0;
+ usbhs_transfer_start(bus);
+ usb_osal_leave_critical_section(flags);
+
+ if (urb->timeout > 0) {
+ /* wait until timeout or sem give */
+ ret = usb_osal_sem_take(pipe->waitsem, urb->timeout);
+ if (ret < 0) {
+ goto errout_timeout;
+ }
+ urb->timeout = 0;
+ ret = urb->errorcode;
+
+ /* we can free pipe when waitsem is done */
+ usbhs_pipe_free(bus, pipe, pipe->type);
+ }
+ return ret;
+
+errout_timeout:
+ urb->timeout = 0;
+ usbh_kill_urb(urb);
+ return ret;
+}
+
+int usbh_kill_urb(struct usbh_urb *urb)
+{
+ if (!urb || !urb->hcpriv || !urb->hport->bus) {
+ return -USB_ERR_INVAL;
+ }
+
+ size_t flags = usb_osal_enter_critical_section();
+
+ struct usbhs_pipe *pipe = urb->hcpriv;
+ if (!pipe) {
+ usb_osal_leave_critical_section(flags);
+ return -USB_ERR_INVAL;
+ }
+
+ urb->errorcode = -USB_ERR_SHUTDOWN;
+ usb_osal_leave_critical_section(flags);
+
+ if (urb->timeout) {
+ usb_osal_sem_give(pipe->waitsem);
+ } else {
+ usbhs_pipe_free(urb->hport->bus, pipe, USB_GET_ENDPOINT_TYPE(urb->ep->bmAttributes));
+ }
+
+ if (urb->complete) {
+ urb->complete(urb->arg, urb->errorcode);
+ }
+
+ return 0;
+}
+
+void USBH_IRQHandler(uint8_t busid)
+{
+ struct usbh_bus *bus = &g_usbhost_bus[busid];
+
+ /* Get the interrupt flag */
+ uint8_t int_flag = USBHSH->INT_FLAG;
+
+ if (int_flag & USBHS_UHIF_SOF_ACT) {
+ g_usbhs_hcd[bus->hcd.hcd_id].tick++;
+ g_usbhs_hcd[bus->hcd.hcd_id].sof_act = true;
+ usbhs_transfer_start(bus);
+ USBHSH->INT_FLAG = USBHS_UHIF_SOF_ACT;
+ } else if (int_flag & USBHS_UHIF_TRANSFER) {
+ usbhs_transfer_complete(bus, USBHSH->INT_ST & 0x0F, USBHSH->RX_LEN);
+ g_usbhs_hcd[bus->hcd.hcd_id].curr_xfer = g_usbhs_hcd[bus->hcd.hcd_id].curr_xfer->next;
+ USBHSH->INT_FLAG = USBHS_UHIF_TRANSFER;
+ usbhs_transfer_start(bus);
+ }
+
+ /* Get the port change status */
+ uint8_t port_change = USBHSH->PORT_STATUS_CHG;
+
+ if (port_change) {
+ bus->hcd.roothub.int_buffer[0] = (1 << 1);
+ usbh_hub_thread_wakeup(&bus->hcd.roothub);
+
+ if (port_change & USBHS_UHIF_PORT_CONNECT) {
+ g_usbhs_hcd[bus->hcd.hcd_id].port_csc = 1;
+ }
+
+ if (port_change & USBHS_UHIF_PORT_EN) {
+ g_usbhs_hcd[bus->hcd.hcd_id].port_pec = 1;
+ }
+
+ if (port_change & USBHS_UHIF_PORT_SUSP) {
+ g_usbhs_hcd[bus->hcd.hcd_id].port_ssc = 1;
+ }
+
+ if (port_change & USBHS_UHIF_PORT_RESET) {
+ g_usbhs_hcd[bus->hcd.hcd_id].port_rsc = 1;
+ }
+
+ USBHSH->PORT_STATUS_CHG = port_change;
+ }
+}
+
+#if defined(CONFIG_USBHOST_MULT_HC)
+struct usbh_hc_driver wch_usbhs_hc_driver = {
+ .driver_name = "wch_usbhs_hcd",
+ .driver_desc = "WCH USBHS Host Controller",
+ .init = usb_hc_init,
+ .deinit = usb_hc_deinit,
+ .get_frame_number = usbh_get_frame_number,
+ .roothub_control = usbh_roothub_control,
+ .submit_urb = usbh_submit_urb,
+ .kill_urb = usbh_kill_urb,
+ .irq_handler = USBH_IRQHandler,
+};
+#endif
diff --git a/port/wch/usbhs/usb_usbhs_reg.h b/port/wch/usbhs/usb_usbhs_reg.h
new file mode 100644
index 00000000..e4fd8df0
--- /dev/null
+++ b/port/wch/usbhs/usb_usbhs_reg.h
@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 2026, Links ([email protected])
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef USB_USBHS_REG_H
+#define USB_USBHS_REG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* @include */
+#include <stdint.h>
+
+/*******************************************************************************/
+/* USBHS Related Register Macro Definition */
+
+/* R8_USB_CTRL */
+#define USBHS_UD_LPM_EN 0x80
+#define USBHS_UD_DEV_EN 0x20
+#define USBHS_UD_DMA_EN 0x10
+#define USBHS_UD_PHY_SUSPENDM 0x08
+#define USBHS_UD_CLR_ALL 0x04
+#define USBHS_UD_RST_SIE 0x02
+#define USBHS_UD_RST_LINK 0x01
+
+/* R8_USB_BASE_MODE */
+#define USBHS_UD_SPEED_FULL 0x00
+#define USBHS_UD_SPEED_HIGH 0x01
+#define USBHS_UD_SPEED_LOW 0x02
+#define USBHS_UD_SPEED_TYPE 0x03
+
+/* R8_USB_INT_EN */
+#define USBHS_UDIE_FIFO_OVER 0x80
+#define USBHS_UDIE_LINK_RDY 0x40
+#define USBHS_UDIE_SOF_ACT 0x20
+#define USBHS_UDIE_TRANSFER 0x10
+#define USBHS_UDIE_LPM_ACT 0x08
+#define USBHS_UDIE_BUS_SLEEP 0x04
+#define USBHS_UDIE_SUSPEND 0x02
+#define USBHS_UDIE_BUS_RST 0x01
+
+/* R8_USB_DEV_AD */
+#define USBHS_UD_DEV_ADDR 0x7F
+
+/* R8_USB_WAKE_CTRL */
+#define USBHS_UD_REMOTE_WKUP 0x01
+
+/* R8_USB_TEST_MODE */
+#define USBHS_UD_TEST_EN 0x80
+#define USBHS_UD_TEST_SE0NAK 0x08
+#define USBHS_UD_TEST_PKT 0x04
+#define USBHS_UD_TEST_K 0x02
+#define USBHS_UD_TEST_J 0x01
+
+/* R16_USB_LPM_DATA */
+#define USBHS_UD_LPM_BUSY 0x8000
+#define USBHS_UD_LPM_DATA 0x07FF
+
+/* R8_USB_INT_FG */
+#define USBHS_UDIF_FIFO_OV 0x80
+#define USBHS_UDIF_LINK_RDY 0x40
+#define USBHS_UDIF_RX_SOF 0x20
+#define USBHS_UDIF_TRANSFER 0x10
+#define USBHS_UDIF_RTX_ACT 0x10
+#define USBHS_UDIF_LPM_ACT 0x08
+#define USBHS_UDIF_BUS_SLEEP 0x04
+#define USBHS_UDIF_SUSPEND 0x02
+#define USBHS_UDIF_BUS_RST 0x01
+
+/* R8_USB_INT_ST */
+#define USBHS_UDIS_EP_DIR 0x10
+#define USBHS_UDIS_EP_ID_MASK 0x07
+
+/* R8_USB_MIS_ST */
+#define USBHS_UDMS_HS_MOD 0x80
+#define USBHS_UDMS_SUSP_REQ 0x10
+#define USBHS_UDMS_SIE_FREE 0x08
+#define USBHS_UDMS_SLEEP 0x04
+#define USBHS_UDMS_SUSPEND 0x02
+#define USBHS_UDMS_READY 0x01
+
+/* R16_USB_FRAME_NO */
+#define USBHS_UD_MFRAME_NO 0xE000
+#define USBHS_UD_FRAME_NO 0x07FF
+
+/* R16_USB_BUS */
+#define USBHS_USB_DM_ST 0x08
+#define USBHS_USB_DP_ST 0x04
+#define USB_WAKEUP 0x01
+
+/* R16_UEP_TX_EN */
+#define USBHS_UEP0_T_EN 0x0001
+#define USBHS_UEP1_T_EN 0x0002
+#define USBHS_UEP2_T_EN 0x0004
+#define USBHS_UEP3_T_EN 0x0008
+#define USBHS_UEP4_T_EN 0x0010
+#define USBHS_UEP5_T_EN 0x0020
+#define USBHS_UEP6_T_EN 0x0040
+#define USBHS_UEP7_T_EN 0x0080
+#define USBHS_UEP8_T_EN 0x0100
+#define USBHS_UEP9_T_EN 0x0200
+#define USBHS_UEP10_T_EN 0x0400
+#define USBHS_UEP11_T_EN 0x0800
+#define USBHS_UEP12_T_EN 0x1000
+#define USBHS_UEP13_T_EN 0x2000
+#define USBHS_UEP14_T_EN 0x4000
+#define USBHS_UEP15_T_EN 0x8000
+
+/* R16_UEP_RX_EN */
+#define USBHS_UEP0_R_EN 0x0001
+#define USBHS_UEP1_R_EN 0x0002
+#define USBHS_UEP2_R_EN 0x0004
+#define USBHS_UEP3_R_EN 0x0008
+#define USBHS_UEP4_R_EN 0x0010
+#define USBHS_UEP5_R_EN 0x0020
+#define USBHS_UEP6_R_EN 0x0040
+#define USBHS_UEP7_R_EN 0x0080
+#define USBHS_UEP8_R_EN 0x0100
+#define USBHS_UEP9_R_EN 0x0200
+#define USBHS_UEP10_R_EN 0x0400
+#define USBHS_UEP11_R_EN 0x0800
+#define USBHS_UEP12_R_EN 0x1000
+#define USBHS_UEP13_R_EN 0x2000
+#define USBHS_UEP14_R_EN 0x4000
+#define USBHS_UEP15_R_EN 0x8000
+
+/* R16_UEP_T_TOG_AUTO */
+#define USBHS_UEP_T_TOG_AUTO 0xFF
+
+/* R16_UEP_R_TOG_AUTO */
+#define USBHS_UEP_R_TOG_AUTO 0xFF
+
+/* R8_UEP_T_BURST */
+#define USBHS_UEP_T_BURST_EN 0xFF
+
+/* R8_UEP_T_BURST_MODE */
+#define USBHS_UEP_T_BURST_MODE 0xFF
+
+/* R8_UEP_R_BURST */
+#define USBHS_UEP_R_BURST_EN 0xFF
+
+/* R8_UEP_R_RES_MODE */
+#define USBHS_UEP_R_RES_MODE 0xFF
+
+/* R32_UEP_AF_MODE */
+#define USBHS_UEP_T_AF 0xFE
+
+/* R32_UEP0_DMA */
+#define UEPn_DMA 0xFFFFFF
+
+/* R32_UEPn_RX_DMA */
+#define UEPn_RX_DMA 0xFFFFFF
+
+/* R32_UEPn_TX_DMA */
+#define UEPn_TX_DMA 0xFFFFFF
+
+/* R32_UEPn_MAX_LEN */
+#define USBHS_UEP0_MAX_LEN 0x007F
+#define USBHS_UEPn_MAX_LEN 0x07FF
+
+/* R16_UEPn_RX_LEN */
+#define USBHS_UEP0_RX_LEN 0x007F
+
+/* R16_UEPn_RX_LEN */
+#define USBHS_UEPn_RX_LEN 0xFFFF
+
+/* R16_UEPn_R_SIZE */
+#define USBHS_UEPn_R_SIZE 0xFFFF
+
+/* R16_UEP0_T_LEN */
+#define USBHS_UEP0_T_LEN 0x7F
+
+/**R16_UEPn_T_LEN**/
+#define USBHS_UEPn_T_LEN 0xFFFF
+
+/**R8_UEPn_TX_CTRL**/
+#define USBHS_UEP_T_DONE 0x80
+#define USBHS_UEP_T_NAK_ACT 0x40
+#define USBHS_UEP_T_TOG_MASK 0x0C
+#define USBHS_UEP_T_TOG_MDATA 0x0C
+#define USBHS_UEP_T_TOG_DATA2 0x08
+#define USBHS_UEP_T_TOG_DATA1 0x04
+#define USBHS_UEP_T_TOG_DATA0 0x00
+#define USBHS_UEP_T_RES_MASK 0x03
+#define USBHS_UEP_T_RES_ACK 0x02
+#define USBHS_UEP_T_RES_STALL 0x01
+#define USBHS_UEP_T_RES_NAK 0x00
+
+/**R8_UEP0_RX_CTRL**/
+
+/**R8_UEPn_RX_CTRL**/
+#define USBHS_UEP_R_DONE 0x80
+#define USBHS_UEP_R_NAK_ACT 0x40
+#define USBHS_UEP_R_NAK_TOG 0x20
+#define USBHS_UEP_R_TOG_MATCH 0x10
+#define USBHS_UEP_R_SETUP_IS 0x08
+#define USBHS_UEP_R_TOG_MASK 0x0C
+#define USBHS_UEP_R_TOG_MDATA 0x0C
+#define USBHS_UEP_R_TOG_DATA2 0x08
+#define USBHS_UEP_R_TOG_DATA1 0x04
+#define USBHS_UEP_R_TOG_DATA0 0x00
+#define USBHS_UEP_R_RES_MASK 0x03
+#define USBHS_UEP_R_RES_ACK 0x02
+#define USBHS_UEP_R_RES_STALL 0x01
+#define USBHS_UEP_R_RES_NAK 0x00
+
+/* R16_UEP_T_ISO */
+#define USBHS_UEP1_T_FIFO_EN 0x0200
+#define USBHS_UEP2_T_FIFO_EN 0x0400
+#define USBHS_UEP3_T_FIFO_EN 0x0800
+#define USBHS_UEP4_T_FIFO_EN 0x1000
+#define USBHS_UEP5_T_FIFO_EN 0x2000
+#define USBHS_UEP6_T_FIFO_EN 0x4000
+#define USBHS_UEP7_T_FIFO_EN 0x8000
+#define USBHS_UEP1_T_ISO_EN 0x0002
+#define USBHS_UEP2_T_ISO_EN 0x0004
+#define USBHS_UEP3_T_ISO_EN 0x0008
+#define USBHS_UEP4_T_ISO_EN 0x0010
+#define USBHS_UEP5_T_ISO_EN 0x0020
+#define USBHS_UEP6_T_ISO_EN 0x0040
+#define USBHS_UEP7_T_ISO_EN 0x0080
+
+/* R16_UEP_R_ISO */
+#define USBHS_UEP1_R_FIFO_EN 0x0200
+#define USBHS_UEP2_R_FIFO_EN 0x0400
+#define USBHS_UEP3_R_FIFO_EN 0x0800
+#define USBHS_UEP4_R_FIFO_EN 0x1000
+#define USBHS_UEP5_R_FIFO_EN 0x2000
+#define USBHS_UEP6_R_FIFO_EN 0x4000
+#define USBHS_UEP7_R_FIFO_EN 0x8000
+#define USBHS_UEP1_R_ISO_EN 0x0002
+#define USBHS_UEP2_R_ISO_EN 0x0004
+#define USBHS_UEP3_R_ISO_EN 0x0008
+#define USBHS_UEP4_R_ISO_EN 0x0010
+#define USBHS_UEP5_R_ISO_EN 0x0020
+#define USBHS_UEP6_R_ISO_EN 0x0040
+#define USBHS_UEP7_R_ISO_EN 0x0080
+
+/* R32_UEPn_RX_FIFO */
+#define USBHS_UEP_RX_FIFO_E 0xFF00
+#define USBHS_UEP_RX_FIFO_S 0x00FF
+
+/* R32_UEPn_TX_FIFO */
+#define USBHS_UEP_TX_FIFO_E 0xFF00
+#define USBHS_UEP_TX_FIFO_S 0x00FF
+
+/* USB high speed host register */
+/* R8_UH_CFG */
+#define USBHS_UH_LPM_EN 0x80
+#define USBHS_UH_FORCE_FS 0x40
+#define USBHS_UH_SOF_EN 0x20
+#define USBHS_UH_DMA_EN 0x10
+#define USBHS_UH_PHY_SUSPENDM 0x08
+#define USBHS_UH_CLR_ALL 0x04
+#define USBHS_RST_SIE 0x02
+#define USBHS_RST_LINK 0x01
+
+/* R8_UH_INT_EN */
+#define USBHS_UHIE_FIFO_OVER 0x80
+#define USBHS_UHIE_TX_HALT 0x40
+#define USBHS_UHIE_SOF_ACT 0x20
+#define USBHS_UHIE_TRANSFER 0x10
+#define USBHS_UHIE_RESUME_ACT 0x08
+#define USBHS_UHIE_WKUP_ACT 0x04
+
+/* R8_UH_DEV_AD */
+#define USBHS_UH_DEV_ADDR 0x7F
+
+/* R32_UH_CONTROL */
+#define USBHS_UH_RX_NO_RES 0x800000
+#define USBHS_UH_TX_NO_RES 0x400000
+#define USBHS_UH_RX_NO_DATA 0x200000
+#define USBHS_UH_TX_NO_DATA 0x100000
+#define USBHS_UH_PRE_PID_EN 0x080000
+#define USBHS_UH_SPLIT_VALID 0x040000
+#define USBHS_UH_LPM_VALID 0x020000
+#define USBHS_UH_HOST_ACTION 0x010000
+#define USBHS_UH_BUF_MODE 0x0400
+#define USBHS_UH_T_TOG_MASK 0x0300
+#define USBHS_UH_T_TOG_MDATA 0x0300
+#define USBHS_UH_T_TOG_DATA2 0x0200
+#define USBHS_UH_T_TOG_DATA1 0x0100
+#define USBHS_UH_T_TOG_DATA0 0x0000
+#define USBHS_UH_T_ENDP_MASK 0xF0
+#define USBHS_UH_T_TOKEN_MASK 0x0F
+
+/* R8_UH_INT_FLAG */
+#define USBHS_UHIF_FIFO_OVER 0x80
+#define USBHS_UHIF_TX_HALT 0x40
+#define USBHS_UHIF_SOF_ACT 0x20
+#define USBHS_UHIF_TRANSFER 0x10
+#define USBHS_UHIF_RESUME_ACT 0x08
+#define USBHS_UHIF_WKUP_ACT 0x04
+
+/* R8_UH_INT_ST */
+#define USBHS_UHIF_PORT_RX_RESUME 0x10
+#define USBHS_UH_R_TOKEN_MASK 0x0F
+
+/* R8_UH_MIS_ST */
+#define USBHS_UHMS_BUS_SE0 0x80
+#define USBHS_UHMS_BUS_J 0x40
+#define USBHS_UHMS_LINESTATE 0x30
+#define USBHS_UHMS_USB_WAKEUP 0x08
+#define USBHS_UHMS_SOF_ACT 0x04
+#define USBHS_UHMS_SOF_PRE 0x02
+#define USBHS_UHMS_SOF_FREE 0x01
+
+/* R32_UH_LPM_DATA */
+#define USBHS_UH_LPM_DATA 0x07FF
+
+/* R32_UH_SPLIT_DATA */
+#define USBHS_UH_SPLIT_DATA 0x07FFFF
+
+/* R32_UH_FRAME */
+#define USBHS_UH_SOF_CNT_CLR 0x02000000
+#define USBHS_UH_SOF_CNT_EN 0x01000000
+#define USBHS_UH_MFRAME_NO 0x070000
+#define USBHS_UH_FRAME_NO 0x07FF
+
+/* R32_UH_TX_LEN */
+#define USBHS_UH_TX_LEN 0x07FF
+
+/* R32_UH_RX_LEN */
+#define USBHS_UH_RX_LEN 0x07FF
+
+/* R32_UH_RX_MAX_LEN */
+#define USBHS_UH_RX_MAX_LEN 0x07FF
+
+/* R32_UH_RX_DMA */
+#define USBHS_R32_UH_RX_DMA 0x01FFFF
+
+/* R32_UH_TX_DMA */
+#define USBHS_R32_UH_TX_DMA 0x01FFFF
+
+/* R32_UH_PORT_CTRL */
+#define USBHS_UH_BUS_RST_LONG 0x010000
+#define USBHS_UH_PORT_SLEEP_BESL 0xF000
+#define USBHS_UH_CLR_PORT_SLEEP 0x0100
+#define USBHS_UH_CLR_PORT_CONNECT 0x20
+#define USBHS_UH_CLR_PORT_EN 0x10
+#define USBHS_UH_SET_PORT_SLEEP 0x08
+#define USBHS_UH_CLR_PORT_SUSP 0x04
+#define USBHS_UH_SET_PORT_SUSP 0x02
+#define USBHS_UH_SET_PORT_RESET 0x01
+
+/* R8_UH_PORT_CFG */
+#define USBHS_UH_PD_EN 0x80
+#define USBHS_UH_HOST_EN 0x01
+
+/* R8_UH_PORT_INT_EN */
+#define USBHS_UHIE_PORT_SLP 0x20
+#define USBHS_UHIE_PORT_RESET 0x10
+#define USBHS_UHIE_PORT_SUSP 0x04
+#define USBHS_UHIE_PORT_EN 0x02
+#define USBHS_UHIE_PORT_CONNECT 0x01
+
+/* R8_UH_PORT_TEST_CT */
+#define USBHS_UH_TEST_SE0_NAK 0x10
+#define USBHS_UH_TEST_PACKET 0x08
+#define USBHS_UH_TEST_FORCE_EN 0x04
+#define USBHS_UH_TEST_K 0x02
+#define USBHS_UH_TEST_J 0x01
+
+/* R16_UH_PORT_ST */
+#define USBHS_UHIS_PORT_TEST 0x0800
+#define USBHS_UHIS_PORT_SPEED_MASK 0x0600
+#define USBHS_UHIS_PORT_HS 0x0400
+#define USBHS_UHIS_PORT_LS 0x0200
+#define USBHS_UHIS_PORT_FS 0x0000
+#define USBHS_UHIS_PORT_SLP 0x20
+#define USBHS_UHIS_PORT_RST 0x10
+#define USBHS_UHIS_PORT_SUSP 0x04
+#define USBHS_UHIS_PORT_EN 0x02
+#define USBHS_UHIS_PORT_CONNECT 0x01
+
+/* R8_UH_PORT_CHG */
+#define USBHS_UHIF_PORT_SLP 0x20
+#define USBHS_UHIF_PORT_RESET 0x10
+#define USBHS_UHIF_PORT_SUSP 0x04
+#define USBHS_UHIF_PORT_EN 0x02
+#define USBHS_UHIF_PORT_CONNECT 0x01
+
+/* R32_UH_BC_CTRL */
+#define UDM_VSRC_ACT 0x0400
+#define UDM_BC_VSRC 0x0200
+#define UDP_BC_VSRC 0x0100
+#define BC_AUTO_MODE 0x40
+#define UDM_BC_CMPE 0x20
+#define UDP_BC_CMPE 0x10
+#define UDM_BC_CMPO 0x02
+#define UDP_BC_CMPO 0x01
+
+/* IO definitions */
+#ifdef __cplusplus
+#define __I volatile
+#else
+#define __I volatile const
+#endif
+
+#define __O volatile
+#define __IO volatile
+
+/* USBHS Device Registers */
+typedef struct
+{
+ __IO uint8_t CONTROL;
+ __IO uint8_t BASE_MODE;
+ __IO uint8_t INT_EN;
+ __IO uint8_t DEV_AD;
+ __IO uint8_t WAKE_CTRL;
+ __IO uint8_t TEST_MODE;
+ __IO uint16_t LPM_DATA;
+
+ __IO uint8_t INT_FG;
+ __IO uint8_t INT_ST;
+ __IO uint8_t MIS_ST;
+ uint8_t RESERVED0;
+
+ __IO uint16_t FRAME_NO;
+ __IO uint16_t BUS;
+
+ __IO uint16_t UEP_TX_EN;
+ __IO uint16_t UEP_RX_EN;
+ __IO uint16_t UEP_TX_TOG_AUTO;
+ __IO uint16_t UEP_RX_TOG_AUTO;
+
+ __IO uint8_t UEP_TX_BURST;
+ __IO uint8_t UEP_TX_BURST_MODE;
+ __IO uint8_t UEP_RX_BURST;
+ __IO uint8_t UEP_RX_RES_MODE;
+
+ __IO uint32_t UEP_AF_MODE;
+ __IO uint32_t UEP0_DMA;
+ __IO uint32_t UEP1_RX_DMA;
+ __IO uint32_t UEP2_RX_DMA;
+ __IO uint32_t UEP3_RX_DMA;
+ __IO uint32_t UEP4_RX_DMA;
+ __IO uint32_t UEP5_RX_DMA;
+ __IO uint32_t UEP6_RX_DMA;
+ __IO uint32_t UEP7_RX_DMA;
+ __IO uint32_t UEP1_TX_DMA;
+ __IO uint32_t UEP2_TX_DMA;
+ __IO uint32_t UEP3_TX_DMA;
+ __IO uint32_t UEP4_TX_DMA;
+ __IO uint32_t UEP5_TX_DMA;
+ __IO uint32_t UEP6_TX_DMA;
+ __IO uint32_t UEP7_TX_DMA;
+ __IO uint32_t UEP0_MAX_LEN;
+ __IO uint32_t UEP1_MAX_LEN;
+ __IO uint32_t UEP2_MAX_LEN;
+ __IO uint32_t UEP3_MAX_LEN;
+ __IO uint32_t UEP4_MAX_LEN;
+ __IO uint32_t UEP5_MAX_LEN;
+ __IO uint32_t UEP6_MAX_LEN;
+ __IO uint32_t UEP7_MAX_LEN;
+
+ __IO uint16_t UEP0_RX_LEN;
+ uint16_t RESERVED1;
+ __IO uint16_t UEP1_RX_LEN;
+ __IO uint16_t UEP1_RX_SIZE;
+ __IO uint16_t UEP2_RX_LEN;
+ __IO uint16_t UEP2_RX_SIZE;
+ __IO uint16_t UEP3_RX_LEN;
+ __IO uint16_t UEP3_RX_SIZE;
+ __IO uint16_t UEP4_RX_LEN;
+ __IO uint16_t UEP4_RX_SIZE;
+ __IO uint16_t UEP5_RX_LEN;
+ __IO uint16_t UEP5_RX_SIZE;
+ __IO uint16_t UEP6_RX_LEN;
+ __IO uint16_t UEP6_RX_SIZE;
+ __IO uint16_t UEP7_RX_LEN;
+ __IO uint16_t UEP7_RX_SIZE;
+ __IO uint16_t UEP0_TX_LEN;
+ __IO uint8_t UEP0_TX_CTRL;
+ __IO uint8_t UEP0_RX_CTRL;
+
+ __IO uint16_t UEP1_TX_LEN;
+ __IO uint8_t UEP1_TX_CTRL;
+ __IO uint8_t UEP1_RX_CTRL;
+ __IO uint16_t UEP2_TX_LEN;
+ __IO uint8_t UEP2_TX_CTRL;
+ __IO uint8_t UEP2_RX_CTRL;
+ __IO uint16_t UEP3_TX_LEN;
+ __IO uint8_t UEP3_TX_CTRL;
+ __IO uint8_t UEP3_RX_CTRL;
+ __IO uint16_t UEP4_TX_LEN;
+ __IO uint8_t UEP4_TX_CTRL;
+ __IO uint8_t UEP4_RX_CTRL;
+ __IO uint16_t UEP5_TX_LEN;
+ __IO uint8_t UEP5_TX_CTRL;
+ __IO uint8_t UEP5_RX_CTRL;
+ __IO uint16_t UEP6_TX_LEN;
+ __IO uint8_t UEP6_TX_CTRL;
+ __IO uint8_t UEP6_RX_CTRL;
+ __IO uint16_t UEP7_TX_LEN;
+ __IO uint8_t UEP7_TX_CTRL;
+ __IO uint8_t UEP7_RX_CTRL;
+
+ __IO uint16_t UEP_TX_ISO;
+ __IO uint16_t UEP_RX_ISO;
+
+ __IO uint32_t UEP1_RX_FIFO;
+ __IO uint32_t UEP2_RX_FIFO;
+ __IO uint32_t UEP3_RX_FIFO;
+ __IO uint32_t UEP4_RX_FIFO;
+ __IO uint32_t UEP5_RX_FIFO;
+ __IO uint32_t UEP6_RX_FIFO;
+ __IO uint32_t UEP7_RX_FIFO;
+ __IO uint32_t UEP1_TX_FIFO;
+ __IO uint32_t UEP2_TX_FIFO;
+ __IO uint32_t UEP3_TX_FIFO;
+ __IO uint32_t UEP4_TX_FIFO;
+ __IO uint32_t UEP5_TX_FIFO;
+ __IO uint32_t UEP6_TX_FIFO;
+ __IO uint32_t UEP7_TX_FIFO;
+} USBHSD_TypeDef;
+
+/* USBHS Host Registers */
+typedef struct
+{
+ __IO uint8_t CFG;
+ uint8_t RESERVED0;
+ __IO uint8_t INT_EN;
+ __IO uint8_t DEV_ADDR;
+ __IO uint32_t CONTROL;
+
+ __IO uint8_t INT_FLAG;
+ __IO uint8_t INT_ST;
+ __IO uint8_t MIS_ST;
+ uint8_t RESERVED1;
+
+ __IO uint32_t LPM;
+ __IO uint32_t SPLIT;
+ __IO uint32_t FRAME;
+ __IO uint32_t TX_LEN;
+ __IO uint32_t RX_LEN;
+ __IO uint32_t RX_MAX_LEN;
+ __IO uint32_t RX_DMA;
+ __IO uint32_t TX_DMA;
+ __IO uint32_t PORT_CTRL;
+ __IO uint8_t PORT_CFG;
+ uint8_t RESERVED2;
+ __IO uint8_t PORT_INT_EN;
+ __IO uint8_t PORT_TEST_CT;
+
+ __IO uint16_t PORT_STATUS;
+ __IO uint8_t PORT_STATUS_CHG;
+ uint8_t RESERVED3[5];
+ __IO uint32_t ROOT_BC_CTRL;
+} USBHSH_TypeDef;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/port/xhci/phytium/README.md b/port/xhci/phytium/README.md
index 4eb67580..f83affd1 100644
--- a/port/xhci/phytium/README.md
+++ b/port/xhci/phytium/README.md
@@ -7,8 +7,8 @@
- FreeRTOS
-- - 1. [XHCI 平台控制器使用鼠标/键盘/U盘功能](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/xhci_platform/README.md)
-- - 2. [XHCI PCIe控制器使用鼠标/键盘/U盘功能](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/xhci_pcie/README.md)
+- - 1. [XHCI 平台控制器使用鼠标/键盘/U盘功能](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_host/README.md)
+- - 2. [XHCI PCIe控制器使用鼠标/键盘/U盘功能](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_host/README.md)
- - 3. [LVGL 中使用 XHCI 平台控制器连接的鼠标/键盘/U盘](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/blob/master/example/peripheral/media/lvgl_indev/README.md)
---------------------------------------------
@@ -42,8 +42,8 @@
- FreeRTOS
- - 1. [XHCI platform controller for mouse/keyboard/USB drive functions](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/xhci_platform/README.md)
- - 2. [XHCI PCIe controller for mouse/keyboard/USB drive functions](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/xhci_pcie/README.md)
+ - 1. [XHCI platform controller for mouse/keyboard/USB drive functions](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_host/README.md)
+ - 2. [XHCI PCIe controller for mouse/keyboard/USB drive functions](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/tree/master/example/peripheral/usb/usb_host/README.md)
- 3. [Using XHCI platform controller-connected mouse/keyboard/USB drive in LVGL](https://gitee.com/phytium_embedded/phytium-free-rtos-sdk/blob/master/example/peripheral/media/lvgl_indev/README.md)
---------------------------------------------
diff --git a/port/xhci/phytium/freertos/usb_config.h b/port/xhci/phytium/freertos/usb_config.h
index 60a9ed18..642c136b 100755..100644
--- a/port/xhci/phytium/freertos/usb_config.h
+++ b/port/xhci/phytium/freertos/usb_config.h
@@ -1,36 +1,32 @@
/*
- * Copyright : (C) 2024 Phytium Information Technology, Inc.
+ * Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
- *
- * Modify History:
- * Ver   Who        Date         Changes
- * ----- ------     --------    --------------------------------------
- * 1.0 zhugengyu 2024/6/26 first commit
*/
-
#ifndef CHERRYUSB_CONFIG_H
#define CHERRYUSB_CONFIG_H
+#include <stdio.h>
+#include <stdlib.h>
#include "sdkconfig.h"
-#include "FreeRTOS.h"
-#include "task.h"
+#include "fparameters.h"
/* ================ USB common Configuration ================ */
#define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__)
-void *xhci_mem_malloc(size_t align, size_t size);
-void xhci_mem_free(void *ptr);
-
-#define XHCI_DCACHE_FLUSH (1 << 0)
-#define XHCI_DCACHE_INVALIDATE (1 << 1)
-void xhci_dcache_sync(void *ptr, size_t len, uint32_t flags);
-
+void *usb_sys_mem_malloc(size_t size);
+void usb_sys_mem_free(void *ptr);
+void *usb_sys_malloc_align(size_t align, size_t size);
unsigned long usb_hc_get_register_base(uint32_t id);
+unsigned long usb_dc_get_register_base(uint32_t id);
+void usb_hc_disable_interrupt(uint32_t id);
+void usb_hc_enable_interrupt(uint32_t id);
-#define usb_malloc(size) xhci_mem_malloc(sizeof(int), size)
-#define usb_free(ptr) xhci_mem_free(ptr)
+#define usb_malloc(size) usb_sys_mem_malloc(size)
+#define usb_calloc(num, size) usb_sys_mem_malloc((num) * (size))
+#define usb_free(ptr) usb_sys_mem_free(ptr)
+#define usb_align(align, size) usb_sys_malloc_align(align, size)
#ifndef CONFIG_USB_DBG_LEVEL
#if defined(CONFIG_LOG_ERROR)
@@ -41,15 +37,21 @@ unsigned long usb_hc_get_register_base(uint32_t id);
#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
#elif defined(CONFIG_LOG_DEBUG) || defined(CONFIG_LOG_VERBOS)
#define CONFIG_USB_DBG_LEVEL USB_DBG_LOG
+#elif defined(CONFIG_LOG_NONE)
+#define CONFIG_USB_DBG_LEVEL USB_DBG_ERROR
+#undef CONFIG_USB_PRINTF
+#define CONFIG_USB_PRINTF(...)
#else
#define CONFIG_USB_DBG_LEVEL USB_DBG_ERROR
#endif
#endif
+#define CONFIG_USBDEV_ADVANCE_DESC
+
/* Enable print with color */
#define CONFIG_USB_PRINTF_COLOR_ENABLE
-/* data align size when use dma */
+/* data align size when use dma or use dcache */
#ifndef CONFIG_USB_ALIGN_SIZE
#define CONFIG_USB_ALIGN_SIZE 4
#endif
@@ -59,74 +61,6 @@ unsigned long usb_hc_get_register_base(uint32_t id);
/* ================= USB Device Stack Configuration ================ */
-/* Ep0 in and out transfer buffer */
-#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
-#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
-#endif
-
-/* Setup packet log for debug */
-// #define CONFIG_USBDEV_SETUP_LOG_PRINT
-
-/* Send ep0 in data from user buffer instead of copying into ep0 reqdata
- * Please note that user buffer must be aligned with CONFIG_USB_ALIGN_SIZE
-*/
-// #define CONFIG_USBDEV_EP0_INDATA_NO_COPY
-
-/* Check if the input descriptor is correct */
-// #define CONFIG_USBDEV_DESC_CHECK
-
-/* Enable test mode */
-// #define CONFIG_USBDEV_TEST_MODE
-
-#ifndef CONFIG_USBDEV_MSC_MAX_LUN
-#define CONFIG_USBDEV_MSC_MAX_LUN 1
-#endif
-
-#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
-#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512
-#endif
-
-#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
-#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
-#endif
-
-#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
-#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
-#endif
-
-#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
-#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
-#endif
-
-// #define CONFIG_USBDEV_MSC_THREAD
-
-#ifndef CONFIG_USBDEV_MSC_PRIO
-#define CONFIG_USBDEV_MSC_PRIO 4
-#endif
-
-#ifndef CONFIG_USBDEV_MSC_STACKSIZE
-#define CONFIG_USBDEV_MSC_STACKSIZE 2048
-#endif
-
-#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
-#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
-#endif
-
-/* rndis transfer buffer size, must be a multiple of (1536 + 44)*/
-#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
-#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
-#endif
-
-#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID
-#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff
-#endif
-
-#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC
-#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB"
-#endif
-
-#define CONFIG_USBDEV_RNDIS_USING_LWIP
-
/* ================ USB HOST Stack Configuration ================== */
#define CONFIG_USBHOST_MAX_RHPORTS 8
@@ -151,9 +85,20 @@ unsigned long usb_hc_get_register_base(uint32_t id);
#define CONFIG_USBHOST_PSC_STACKSIZE 8192
#endif
-//#define CONFIG_USBHOST_GET_STRING_DESC
+/* XHCI deferred interrupt thread priority (0 = highest, CherryUSB
+ * convention; must match hub priority PSC_PRIO) */
+#ifndef CONFIG_USB_XHCI_IRQ_PRIO
+#define CONFIG_USB_XHCI_IRQ_PRIO 0
+#endif
+
+/* GIC interrupt priority: must be >= configMAX_API_CALL_INTERRUPT_PRIORITY
+ * so xSemaphoreGiveFromISR from a hard ISR is well-defined */
+#define USB_XHCI_GIC_IRQ_PRIO 13U
+#ifdef configMAX_API_CALL_INTERRUPT_PRIORITY
+_Static_assert(USB_XHCI_GIC_IRQ_PRIO >= configMAX_API_CALL_INTERRUPT_PRIORITY,
+ "XHCI GIC irq priority must be >= configMAX_API_CALL_INTERRUPT_PRIORITY");
+#endif
-// #define CONFIG_USBHOST_MSOS_ENABLE
#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE
#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
#endif
@@ -175,118 +120,45 @@ unsigned long usb_hc_get_register_base(uint32_t id);
#define CONFIG_INPUT_MOUSE_WHEEL
#endif
-/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
- * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
- */
-#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE
-#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048)
-#endif
-
-/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
-#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE
-#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
-#endif
+/* ================ USB Device Port Configuration ================*/
-/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
- * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
- */
-#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE
-#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE (2048)
-#endif
-/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
-#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE
-#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE (2048)
+/* ================ USB Host Port Configuration ==================*/
+#ifndef CONFIG_USBHOST_MAX_BUS
+#define CONFIG_USBHOST_MAX_BUS 4
#endif
-/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
- * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
- */
-#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE
-#define CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE (2048)
-#endif
-/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
-#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE
-#define CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE (2048)
+#ifndef CONFIG_USBHOST_PIPE_NUM
+#define CONFIG_USBHOST_PIPE_NUM 10
#endif
-/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
- * you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
- */
-#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE
-#define CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE (2048)
-#endif
-/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
-#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE
-#define CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE (2048)
-#endif
+/* ================ USB Dcache Configuration ==================*/
-#define CONFIG_USBHOST_BLUETOOTH_HCI_H4
-// #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG
+/* ================ USB Device Framework Configuration ============*/
-#ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE
-#define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048
+#ifndef USB_HAVE_BUSDMA
+#define USB_HAVE_BUSDMA 1
#endif
-#ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE
-#define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048
+#define USB_HAVE_PER_BUS_PROCESS 1
+#ifndef USB_HAVE_FIXED_IFACE
+#define USB_HAVE_FIXED_IFACE 1
#endif
-
-/* ================ USB Device Port Configuration ================*/
-
-#ifndef CONFIG_USBDEV_MAX_BUS
-#define CONFIG_USBDEV_MAX_BUS 2 // for now, bus num must be 1 except hpm ip
+#ifndef USB_HAVE_FIXED_ENDPOINT
+#define USB_HAVE_FIXED_ENDPOINT 1
#endif
-
-#ifndef CONFIG_USBDEV_EP_NUM
-#define CONFIG_USBDEV_EP_NUM 8
+#ifndef USB_HAVE_MALLOC_WAITOK
+#define USB_HAVE_MALLOC_WAITOK 0
#endif
-
-/* ---------------- FSDEV Configuration ---------------- */
-//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
-
-/* ---------------- DWC2 Configuration ---------------- */
-// #define CONFIG_USB_DWC2_RXALL_FIFO_SIZE (1024 / 4)
-// #define CONFIG_USB_DWC2_TX0_FIFO_SIZE (64 / 4)
-// #define CONFIG_USB_DWC2_TX1_FIFO_SIZE (512 / 4)
-// #define CONFIG_USB_DWC2_TX2_FIFO_SIZE (64 / 4)
-// #define CONFIG_USB_DWC2_TX3_FIFO_SIZE (64 / 4)
-// #define CONFIG_USB_DWC2_TX4_FIFO_SIZE (0 / 4)
-// #define CONFIG_USB_DWC2_TX5_FIFO_SIZE (0 / 4)
-// #define CONFIG_USB_DWC2_TX6_FIFO_SIZE (0 / 4)
-// #define CONFIG_USB_DWC2_TX7_FIFO_SIZE (0 / 4)
-// #define CONFIG_USB_DWC2_TX8_FIFO_SIZE (0 / 4)
-
-/* ---------------- MUSB Configuration ---------------- */
-// #define CONFIG_USB_MUSB_SUNXI
-
-/* ================ USB Host Port Configuration ==================*/
-#ifndef CONFIG_USBHOST_MAX_BUS
-#define CONFIG_USBHOST_MAX_BUS 2
+#ifndef USB_HAVE_UGEN
+#define USB_HAVE_UGEN 0
#endif
-
-#ifndef CONFIG_USBHOST_PIPE_NUM
-#define CONFIG_USBHOST_PIPE_NUM 10
+#ifndef USB_HAVE_PF
+#define USB_HAVE_PF 0
#endif
-
-/* ---------------- EHCI Configuration ---------------- */
-
-#define CONFIG_USB_EHCI_HCCR_OFFSET (0x0)
-#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
-#define CONFIG_USB_EHCI_QH_NUM CONFIG_USBHOST_PIPE_NUM
-#define CONFIG_USB_EHCI_QTD_NUM 3
-#define CONFIG_USB_EHCI_ITD_NUM 20
-// #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
-// #define CONFIG_USB_EHCI_CONFIGFLAG
-// #define CONFIG_USB_EHCI_ISO
-// #define CONFIG_USB_EHCI_WITH_OHCI
-
-/* ---------------- OHCI Configuration ---------------- */
-#define CONFIG_USB_OHCI_HCOR_OFFSET (0x0)
-
-/* ---------------- XHCI Configuration ---------------- */
-#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
-
-#ifndef CONFIG_USB_XHCI_ENABLE_SOFT_ISR
-#define CONFIG_USB_XHCI_ENABLE_SOFT_ISR 0
+#ifndef USB_HAVE_POWERD
+#define USB_HAVE_POWERD 0
+#endif
+#ifndef USB_HAVE_TT_SUPPORT
+#define USB_HAVE_TT_SUPPORT 0
#endif
#endif
diff --git a/port/xhci/phytium/freertos/usb_glue_phytium.c b/port/xhci/phytium/freertos/usb_glue_phytium.c
index e939b468..4a0ab31e 100644
--- a/port/xhci/phytium/freertos/usb_glue_phytium.c
+++ b/port/xhci/phytium/freertos/usb_glue_phytium.c
@@ -12,9 +12,8 @@
#include <stdio.h>
#include <string.h>
-#include "sdkconfig.h"
-
#include "fassert.h"
+#include "fparameters.h"
#include "finterrupt.h"
#include "fcpu_info.h"
#include "fdebug.h"
@@ -23,66 +22,64 @@
#include "usbh_core.h"
+/* OSAL glue (FreeRTOS backend) */
+#include "usb_glue_phytium_common.h"
+#include <FreeRTOS.h>
+#include "semphr.h"
+#include "timers.h"
+
/************************** Constant Definitions *****************************/
-#define FUSB_MEMP_TOTAL_SIZE SZ_1M
+#define USB_MEMP_TOTAL_SIZE SZ_1M
/**************************** Type Definitions *******************************/
-#if defined(CONFIG_CHERRY_USB_PORT_XHCI_PLATFROM)
+#if defined(CONFIG_CHERRY_USB_PORT_XHCI_PLATFROM) || defined(CONFIG_CHERRY_USB_PORT_XHCI_PCIE)
void usb_hc_setup_xhci_interrupt(u32 id);
+void usb_hc_port_poll_stop(u32 id);
#endif
#if defined(CONFIG_CHERRY_USB_PORT_XHCI_PCIE)
unsigned long usb_hc_setup_xhci_pcie(struct usbh_bus *bus);
#endif
/************************** Variable Definitions *****************************/
static FMemp memp;
-static u8 memp_buf[FUSB_MEMP_TOTAL_SIZE] __attribute__((aligned(8))) = {0};
+static u8 memp_buf[USB_MEMP_TOTAL_SIZE] __attribute__((aligned(8))) = { 0 };
static u32 memp_ref_cnt = 0;
-static void xhci_mem_init(void)
+void usb_sys_mem_init(void)
{
- if (FT_COMPONENT_IS_READY != memp.is_ready)
- {
- USB_ASSERT(FT_SUCCESS == FMempInit(&memp, &memp_buf[0], &memp_buf[0] + FUSB_MEMP_TOTAL_SIZE));
+ if (FT_COMPONENT_IS_READY != memp.is_ready) {
+ FASSERT(FT_SUCCESS == FMempInit(&memp, &memp_buf[0], &memp_buf[0] + USB_MEMP_TOTAL_SIZE));
}
}
-static void xhci_mem_deinit(void)
+void usb_sys_mem_deinit(void)
{
- if (FT_COMPONENT_IS_READY == memp.is_ready)
- {
+ if (FT_COMPONENT_IS_READY == memp.is_ready) {
FMempDeinit(&memp);
}
}
-void *xhci_mem_malloc(size_t align, size_t size)
+void *usb_sys_malloc_align(size_t align, size_t size)
{
void *result = FMempMallocAlign(&memp, size, align);
- if (result)
- {
+ if (result) {
memset(result, 0U, size);
+ } else {
+ USB_LOG_ERR("malloc_align: fail size=%u align=%u\n", (unsigned)size, (unsigned)align);
}
return result;
}
-void xhci_mem_free(void *ptr)
+void *usb_sys_mem_malloc(size_t size)
{
- if (NULL != ptr)
- {
- FMempFree(&memp, ptr);
- }
+ return usb_sys_malloc_align(sizeof(void *), size);
}
-void xhci_dcache_sync(void *ptr, size_t len, uint32_t flags)
+void usb_sys_mem_free(void *ptr)
{
- if (flags & XHCI_DCACHE_FLUSH)
- {
- FCacheDCacheFlushRange((uintptr_t)ptr, len);
- }
- else if (flags & XHCI_DCACHE_INVALIDATE)
- {
- FCacheDCacheInvalidateRange((uintptr_t)ptr, len);
+ if (NULL != ptr) {
+ FMempFree(&memp, ptr);
}
}
@@ -100,7 +97,8 @@ int xPortIsInsideInterrupt(void)
void usb_hc_low_level_init(struct usbh_bus *bus)
{
if (memp_ref_cnt == 0) {
- xhci_mem_init(); /* create memory pool before first bus init */
+ usb_sys_mem_init(); /* create memory pool before first bus init */
+ cusb_callout_drain_resource_init(); /* init global drain lock/semaphore */
}
memp_ref_cnt++; /* one more bus is using the memory pool */
@@ -118,6 +116,7 @@ void usb_hc_low_level_init(struct usbh_bus *bus)
/* pcie XHCI controller */
bus->hcd.reg_base = usb_hc_setup_xhci_pcie(bus);
bus->busid = 0U; /* only support one pcie lane */
+ usb_hc_setup_xhci_interrupt(bus->busid);
#else
USB_LOG_ERR("Invalid register base !!!\n");
USB_ASSERT(0);
@@ -127,9 +126,26 @@ void usb_hc_low_level_init(struct usbh_bus *bus)
void usb_hc_low_level_deinit(struct usbh_bus *bus)
{
+#if defined(CONFIG_CHERRY_USB_PORT_XHCI_PLATFROM) || defined(CONFIG_CHERRY_USB_PORT_XHCI_PCIE)
+ /* stop the port poll timer before releasing resources */
+ usb_hc_port_poll_stop(bus->busid);
+#endif
+
memp_ref_cnt--; /* one more bus is leaving */
if (memp_ref_cnt == 0) {
- xhci_mem_deinit(); /* release memory pool after the last bus left */
+ usb_sys_mem_deinit(); /* release memory pool after the last bus left */
}
-} \ No newline at end of file
+}
+
+/* dcache overrides (override library weak defaults, required by both
+ * platform and PCIe XHCI) */
+void xhci_dcache_flush(void *addr, size_t size)
+{
+ FCacheDCacheFlushRange((uintptr_t)addr, size);
+}
+
+void xhci_dcache_invalidate(void *addr, size_t size)
+{
+ FCacheDCacheInvalidateRange((uintptr_t)addr, size);
+}
diff --git a/port/xhci/phytium/freertos/usb_glue_phytium_common.c b/port/xhci/phytium/freertos/usb_glue_phytium_common.c
new file mode 100644
index 00000000..97e2d5f6
--- /dev/null
+++ b/port/xhci/phytium/freertos/usb_glue_phytium_common.c
@@ -0,0 +1,181 @@
+/*
+ * usb_glue_phytium_common.c -- FreeRTOS OSAL bridge implementation
+ *
+ * Provides callout timers, recursive mutex and hub queue query,
+ * shared by the XHCI and PUSB3 ports.
+ */
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "timers.h"
+#include "semphr.h"
+
+#include "usbh_core.h"
+#include "usb_glue_phytium_common.h"
+
+/* ================================================================ */
+/* OSAL: callout timer (FreeRTOS backend) */
+/* ================================================================ */
+
+static void cusb_callout_timer_cb(TimerHandle_t handle)
+{
+ cusb_callout_t *c = (cusb_callout_t *)pvTimerGetTimerID(handle);
+
+ USB_MTX_LOCK(c->mtx);
+ c->fn(c->arg);
+ USB_MTX_UNLOCK(c->mtx);
+}
+
+void cusb_callout_init_mtx(cusb_callout_t *c, void *mtx)
+{
+ c->mtx = mtx;
+ c->timer = (void *)xTimerCreate("cb_to",
+ pdMS_TO_TICKS(1), pdFALSE,
+ c, (TimerCallbackFunction_t)cusb_callout_timer_cb);
+}
+
+/* Global drain sync: a lock + semaphore serializing drain operations,
+ * created once in usb_hc_low_level_init. */
+static void *s_callout_drain_mtx;
+static usb_osal_sem_t s_callout_drain_sem;
+
+void cusb_callout_drain_resource_init(void)
+{
+ if (!s_callout_drain_mtx) {
+ s_callout_drain_mtx = cusb_recursive_mutex_create();
+ s_callout_drain_sem = usb_osal_sem_create_counting(1);
+ }
+}
+
+void cusb_callout_reset(cusb_callout_t *c, uint32_t ticks,
+ void (*fn)(void *), void *arg)
+{
+ TimerHandle_t t = (TimerHandle_t)c->timer;
+
+ c->fn = fn;
+ c->arg = arg;
+ if (xPortIsInsideInterrupt()) {
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+ if (xTimerChangePeriodFromISR(t, pdMS_TO_TICKS(ticks * 1000 / hz), &xHigherPriorityTaskWoken) != pdPASS)
+ USB_LOG_ERR("callout_reset: change period from ISR fail\n");
+ portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+ } else {
+ /* xTimerChangePeriod (re)starts the timer by itself; no extra xTimerStart needed */
+ if (xTimerChangePeriod(t, pdMS_TO_TICKS(ticks * 1000 / hz), portMAX_DELAY) != pdPASS)
+ USB_LOG_ERR("callout_reset: change period fail\n");
+ }
+}
+
+void cusb_callout_stop(cusb_callout_t *c)
+{
+ if (xPortIsInsideInterrupt()) {
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+ xTimerStopFromISR((TimerHandle_t)c->timer, &xHigherPriorityTaskWoken);
+ portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+ } else {
+ if (xTimerStop((TimerHandle_t)c->timer, portMAX_DELAY) != pdPASS)
+ USB_LOG_ERR("callout_stop: stop fail\n");
+ }
+}
+
+static void cusb_callout_drain_sync(void *arg, uint32_t param)
+{
+ (void)arg;
+ (void)param;
+ usb_osal_sem_give(s_callout_drain_sem);
+}
+
+/* Stop the timer and wait for in-flight callbacks to finish;
+ * caller must not hold the callout's lock. */
+void cusb_callout_drain(cusb_callout_t *c)
+{
+ if (xPortIsInsideInterrupt()) {
+ /* Cannot wait in ISR context; degrade to stop (draining from ISR is also forbidden by the framework) */
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+ xTimerStopFromISR((TimerHandle_t)c->timer, &xHigherPriorityTaskWoken);
+ portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+ return;
+ }
+ if (!s_callout_drain_mtx)
+ return;
+ cusb_recursive_mutex_take(s_callout_drain_mtx);
+ xTimerStop((TimerHandle_t)c->timer, portMAX_DELAY);
+ usb_osal_sem_take(s_callout_drain_sem, 0); /* clear stale token */
+ if (xTimerPendFunctionCall(cusb_callout_drain_sync, NULL, 0, portMAX_DELAY) != pdPASS) {
+ USB_LOG_ERR("callout_drain: pend fail\n");
+ } else {
+ usb_osal_sem_take(s_callout_drain_sem, USB_OSAL_WAITING_FOREVER);
+ }
+ cusb_recursive_mutex_give(s_callout_drain_mtx);
+}
+
+/* ---- recursive mutex ---- */
+
+struct cusb_rmtx {
+ SemaphoreHandle_t sem;
+ void *owner; /* TaskHandle_t of current holder, NULL if unlocked */
+ int count; /* recursion depth */
+};
+
+void *cusb_recursive_mutex_create(void)
+{
+ struct cusb_rmtx *m = usb_osal_malloc(sizeof(*m));
+ if (!m)
+ return NULL;
+ m->sem = xSemaphoreCreateRecursiveMutex();
+ if (!m->sem) {
+ usb_osal_free(m);
+ return NULL;
+ }
+ m->owner = NULL;
+ m->count = 0;
+ return m;
+}
+
+void cusb_recursive_mutex_delete(void *m)
+{
+ struct cusb_rmtx *r = (struct cusb_rmtx *)m;
+ if (!r)
+ return;
+ vSemaphoreDelete(r->sem);
+ usb_osal_free(r);
+}
+
+void cusb_recursive_mutex_take(void *m)
+{
+ struct cusb_rmtx *r = (struct cusb_rmtx *)m;
+ if (!r) {
+ USB_LOG_ERR("rmtx_take NULL\n");
+ return;
+ }
+ xSemaphoreTakeRecursive(r->sem, portMAX_DELAY);
+ if (r->count++ == 0)
+ r->owner = (void *)xTaskGetCurrentTaskHandle();
+}
+
+void cusb_recursive_mutex_give(void *m)
+{
+ struct cusb_rmtx *r = (struct cusb_rmtx *)m;
+ if (!r) {
+ USB_LOG_ERR("rmtx_give NULL\n");
+ return;
+ }
+ if (--r->count == 0)
+ r->owner = NULL;
+ xSemaphoreGiveRecursive(r->sem);
+}
+
+int cusb_recursive_mutex_is_owned(void *m)
+{
+ struct cusb_rmtx *r = (struct cusb_rmtx *)m;
+ if (!r)
+ return 0;
+ return (r->owner == (void *)xTaskGetCurrentTaskHandle()) ? 1 : 0;
+}
+
+/* ---- hub message queue space query ---- */
+
+int cusb_glue_mq_has_space(void *mq)
+{
+ return mq && (uxQueueSpacesAvailable((QueueHandle_t)mq) > 0);
+}
diff --git a/port/xhci/phytium/freertos/usb_glue_phytium_common.h b/port/xhci/phytium/freertos/usb_glue_phytium_common.h
new file mode 100644
index 00000000..567036a8
--- /dev/null
+++ b/port/xhci/phytium/freertos/usb_glue_phytium_common.h
@@ -0,0 +1,64 @@
+/*
+ * usb_glue_phytium_common.h -- FreeRTOS OSAL glue declarations
+ *
+ * Shared by the XHCI and PUSB3 ports; compiled in both SOURCE_CODE and
+ * STATIC_LIB modes.
+ */
+
+#ifndef _CUSB_GLUE_PHYTIUM_COMMON_H_
+#define _CUSB_GLUE_PHYTIUM_COMMON_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "usb_osal.h"
+
+/* ---- struct mtx (storage for the recursive-mutex handle) ---- */
+
+struct mtx {
+ void *handle;
+};
+
+/* ---- Callout timer (implementation in usb_glue_phytium_common.c) ---- */
+
+#define hz 1000
+
+typedef struct {
+ void *mtx;
+ void *timer;
+ void (*fn)(void *);
+ void *arg;
+} cusb_callout_t;
+
+void cusb_callout_init_mtx(cusb_callout_t *c, void *mtx);
+void cusb_callout_reset(cusb_callout_t *c, uint32_t ticks,
+ void (*fn)(void *), void *arg);
+void cusb_callout_stop(cusb_callout_t *c);
+void cusb_callout_drain(cusb_callout_t *c);
+void cusb_callout_drain_resource_init(void);
+
+/* ---- Recursive mutex (implementation in usb_glue_phytium_common.c) ---- */
+
+void *cusb_recursive_mutex_create(void);
+void cusb_recursive_mutex_delete(void *m);
+void cusb_recursive_mutex_take(void *m);
+void cusb_recursive_mutex_give(void *m);
+int cusb_recursive_mutex_is_owned(void *m);
+
+#define USB_MTX_LOCK(_m) \
+ do { \
+ struct mtx *_pm = (struct mtx *)(uintptr_t)(_m); \
+ cusb_recursive_mutex_take(_pm->handle); \
+ } while (0)
+
+#define USB_MTX_UNLOCK(_m) \
+ do { \
+ struct mtx *_pm = (struct mtx *)(uintptr_t)(_m); \
+ cusb_recursive_mutex_give(_pm->handle); \
+ } while (0)
+
+/* ---- hub message queue space query ---- */
+
+int cusb_glue_mq_has_space(void *mq);
+
+#endif /* _CUSB_GLUE_PHYTIUM_COMMON_H_ */
diff --git a/port/xhci/phytium/freertos/usb_glue_phytium_pcie.c b/port/xhci/phytium/freertos/usb_glue_phytium_pcie.c
index 4b981089..65432ee1 100644
--- a/port/xhci/phytium/freertos/usb_glue_phytium_pcie.c
+++ b/port/xhci/phytium/freertos/usb_glue_phytium_pcie.c
@@ -14,6 +14,8 @@
#include "FreeRTOS.h"
#include "task.h"
+#include "semphr.h"
+#include "timers.h"
#include "sdkconfig.h"
@@ -28,23 +30,66 @@
#include "fpcie_ecam_common.h"
/************************** Constant Definitions *****************************/
+#define USB_XHCI_IRQ_TASK_STACK 8192U
+#define FUSB3_PCIE_NUM 1 /* PCIe single controller */
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
static FPcieEcam pcie_device;
+static SemaphoreHandle_t s_xhci_irq_sem[FUSB3_PCIE_NUM] = { NULL };
+static TimerHandle_t s_port_poll_timer[FUSB3_PCIE_NUM] = { NULL };
-static void usb_hc_xhci_pcie_interrupt_handler(void *param)
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** Function Prototypes ******************************/
+
+/* Port poll timer callback: runs in the timer daemon task context */
+static void cusb_port_poll_timer_cb(TimerHandle_t handle)
+{
+ extern void cusb_xhci_port_poll(uint8_t busid);
+
+ cusb_xhci_port_poll((uint8_t)(uintptr_t)pvTimerGetTimerID(handle));
+}
+
+/******************************* Functions ***********************************/
+
+static void usb_hc_xhci_irq_task(void *arg)
{
+ uint32_t id = (uint32_t)(uintptr_t)arg;
extern void USBH_IRQHandler(uint8_t busid);
- USBH_IRQHandler((uint8_t)(uintptr_t)0);
+
+ for (;;) {
+ if (s_xhci_irq_sem[id] == NULL) {
+ USB_LOG_ERR("xhci_irq sem NULL id=%lu\n", (unsigned long)id);
+ while (1)
+ ;
+ }
+ xSemaphoreTake(s_xhci_irq_sem[id], portMAX_DELAY);
+ USBH_IRQHandler((uint8_t)id);
+ }
+}
+
+static void usb_hc_xhci_pcie_interrupt_handler(void *param)
+{
+ BaseType_t higher_prio_woken = pdFALSE;
+ extern void cusb_xhci_irq_ack(uint8_t busid);
+ uint32_t id = (uint32_t)(uintptr_t)0;
+
+ (void)param;
+ cusb_xhci_irq_ack((uint8_t)id);
+
+ if (s_xhci_irq_sem[id] != NULL) {
+ xSemaphoreGiveFromISR(s_xhci_irq_sem[id], &higher_prio_woken);
+ portYIELD_FROM_ISR(higher_prio_woken);
+ }
}
static void usb_hc_pcie_intx_init(FPcieEcam *instance_p)
{
u32 cpu_id;
u32 irq_num = FPCIE_ECAM_INTA_IRQ_NUM;
- u32 irq_priority = 13U;
+ u32 irq_priority = USB_XHCI_GIC_IRQ_PRIO;
(void)GetCpuId(&cpu_id);
USB_LOG_DBG("interrupt num: %d", irq_num);
@@ -57,9 +102,6 @@ static void usb_hc_pcie_intx_init(FPcieEcam *instance_p)
FPcieEcamIntxIrqHandler,
&pcie_device,
NULL);
-
- /* enable irq */
- InterruptUmask(irq_num);
}
static FError usb_hc_pcie_init(FPcieEcam *pcie_device)
@@ -67,21 +109,19 @@ static FError usb_hc_pcie_init(FPcieEcam *pcie_device)
FError ret = FT_SUCCESS;
ret = FPcieEcamCfgInitialize(pcie_device, FPcieEcamLookupConfig(FPCIE_ECAM_INSTANCE0), NULL);
- if (FT_SUCCESS != ret)
- {
+ if (FT_SUCCESS != ret) {
return ret;
}
-
+
USB_LOG_DBG("\n");
USB_LOG_DBG(" PCI:\n");
USB_LOG_DBG(" B:D:F VID:PID parent_BDF class_code\n");
ret = FPcieEcamEnumerateBus(pcie_device, 0);
- if (FT_SUCCESS != ret)
- {
+ if (FT_SUCCESS != ret) {
return ret;
}
- usb_hc_pcie_intx_init(pcie_device); /* register pcie_device intx handler */
+ usb_hc_pcie_intx_init(pcie_device); /* register pcie_device intx handler */
return FT_SUCCESS;
}
@@ -93,12 +133,11 @@ static FError usb_hc_pcie_install_irq(FPcieEcam *pcie_device, struct usbh_bus *u
intx_fun.IntxCallBack = usb_hc_xhci_pcie_interrupt_handler;
intx_fun.args = usb;
intx_fun.bus = bus;
- intx_fun.device = device;
- intx_fun.function = function;
+ intx_fun.device = device;
+ intx_fun.function = function;
ret = FPcieEcamIntxRegister(pcie_device, bus, device, function, &intx_fun);
- if (FT_SUCCESS != ret)
- {
+ if (FT_SUCCESS != ret) {
USB_LOG_ERR("FPcieIntxRegiterIrqHandler failed.\n");
return ret;
}
@@ -106,6 +145,56 @@ static FError usb_hc_pcie_install_irq(FPcieEcam *pcie_device, struct usbh_bus *u
return ret;
}
+void usb_hc_disable_interrupt(u32 id)
+{
+ u32 irq_num = FPCIE_ECAM_INTA_IRQ_NUM;
+
+ InterruptMask(irq_num);
+}
+
+void usb_hc_enable_interrupt(u32 id)
+{
+ u32 irq_num = FPCIE_ECAM_INTA_IRQ_NUM;
+
+ InterruptUmask(irq_num);
+}
+
+void usb_hc_setup_xhci_interrupt(u32 id)
+{
+ char task_name[configMAX_TASK_NAME_LEN];
+
+ if (s_xhci_irq_sem[id] == NULL) {
+ s_xhci_irq_sem[id] = xSemaphoreCreateBinary();
+ FASSERT(s_xhci_irq_sem[id] != NULL);
+ snprintf(task_name, sizeof(task_name), "xhci_irq%lu", (unsigned long)id);
+ FASSERT(usb_osal_thread_create(task_name, USB_XHCI_IRQ_TASK_STACK,
+ CONFIG_USB_XHCI_IRQ_PRIO, usb_hc_xhci_irq_task,
+ (void *)(uintptr_t)id) != NULL);
+ }
+
+ /* Port poll timer: deterministic fallback scanning PORTSC every
+ * 100 ms; deinit stops it but never deletes it. */
+ if (s_port_poll_timer[id] == NULL) {
+ s_port_poll_timer[id] = xTimerCreate("usb_poll",
+ pdMS_TO_TICKS(100), pdTRUE,
+ (void *)(uintptr_t)id, cusb_port_poll_timer_cb);
+ FASSERT(s_port_poll_timer[id] != NULL);
+ }
+ xTimerStart(s_port_poll_timer[id], portMAX_DELAY);
+}
+
+void usb_hc_port_poll_stop(u32 id)
+{
+ if (s_port_poll_timer[id] != NULL) {
+ xTimerStop(s_port_poll_timer[id], portMAX_DELAY);
+ }
+}
+
+unsigned long usb_hc_get_register_base(uint32_t id)
+{
+ return 0U;
+}
+
unsigned long usb_hc_setup_xhci_pcie(struct usbh_bus *usb)
{
FError ret = FT_SUCCESS;
@@ -113,7 +202,7 @@ unsigned long usb_hc_setup_xhci_pcie(struct usbh_bus *usb)
u32 bdf;
u32 class;
u16 pci_command;
- u8 bus,device,function;
+ u8 bus, device, function;
u16 vid, did;
uintptr bar0_addr = 0;
uintptr bar1_addr = 0;
@@ -122,43 +211,39 @@ unsigned long usb_hc_setup_xhci_pcie(struct usbh_bus *usb)
u32 config_data;
ret = usb_hc_pcie_init(&pcie_device);
- if (FT_SUCCESS != ret)
- {
+ if (FT_SUCCESS != ret) {
USB_LOG_ERR("FPcieInit failed.\n");
return usb_base;
}
/* find xhci host from pcie_device instance */
- for (host = 0; host < pcie_device.scans_bdf_count; host++)
- {
- bus = pcie_device.scans_bdf[host].bus;
- device = pcie_device.scans_bdf[host].device;
- function= pcie_device.scans_bdf[host].function;
+ for (host = 0; host < pcie_device.scans_bdf_count; host++) {
+ bus = pcie_device.scans_bdf[host].bus;
+ device = pcie_device.scans_bdf[host].device;
+ function = pcie_device.scans_bdf[host].function;
- FPcieEcamReadConfigSpace(&pcie_device,bus,device,function,FPCIE_CCR_REV_CLASSID_REGS,&config_data);
- class = config_data >> 8;
+ FPcieEcamReadConfigSpace(&pcie_device, bus, device, function, FPCIE_CCR_REV_CLASSID_REGS, &config_data);
+ class = config_data >> 8;
- if (class == class_code)
- {
- (void)FPcieEcamReadConfigSpace(&pcie_device,bus,device,function,FPCIE_CCR_ID_REG,&config_data);
- vid = FPCIE_CCR_VENDOR_ID_MASK(config_data);
- did = FPCIE_CCR_DEVICE_ID_MASK(config_data);
+ if (class == class_code) {
+ (void)FPcieEcamReadConfigSpace(&pcie_device, bus, device, function, FPCIE_CCR_ID_REG, &config_data);
+ vid = FPCIE_CCR_VENDOR_ID_MASK(config_data);
+ did = FPCIE_CCR_DEVICE_ID_MASK(config_data);
USB_LOG_DBG("xHCI-PCI HOST found !!!, b.d.f = %x.%x.%x\n", bus, device, function);
- FPcieEcamReadConfigSpace(&pcie_device,bus,device,function,FPCIE_CCR_BAR_ADDR0_REGS,(u32 *)&bar0_addr);
+ FPcieEcamReadConfigSpace(&pcie_device, bus, device, function, FPCIE_CCR_BAR_ADDR0_REGS, (u32 *)&bar0_addr);
bar0_addr &= ~0xfff;
#if defined(FAARCH64_USE)
- FPcieEcamReadConfigSpace(&pcie_device,bus,device,function,FPCIE_CCR_BAR_ADDR1_REGS,(u32 *)&bar1_addr);
+ FPcieEcamReadConfigSpace(&pcie_device, bus, device, function, FPCIE_CCR_BAR_ADDR1_REGS, (u32 *)&bar1_addr);
#endif
- USB_LOG_DBG("FSataPcieIntrInstall BarAddress %p:%p", bar1_addr, bar0_addr);
+ USB_LOG_DBG("XHCI-PCI BarAddress %p:%p", bar1_addr, bar0_addr);
- if ((0x0 == bar0_addr) && (0x0 == bar1_addr))
- {
+ if ((0x0 == bar0_addr) && (0x0 == bar1_addr)) {
USB_LOG_ERR("Invalid Bar address");
return usb_base;
- }
+ }
usb_hc_pcie_install_irq(&pcie_device, usb, bus, device, function);
#if defined(FAARCH64_USE)
@@ -167,7 +252,7 @@ unsigned long usb_hc_setup_xhci_pcie(struct usbh_bus *usb)
usb_base = bar0_addr;
#endif
USB_LOG_INFO("xHCI base address: 0x%lx", usb_base);
- }
+ }
}
return usb_base;
diff --git a/port/xhci/phytium/freertos/usb_glue_phytium_plat.c b/port/xhci/phytium/freertos/usb_glue_phytium_plat.c
index 8671e0e1..17166673 100755..100644
--- a/port/xhci/phytium/freertos/usb_glue_phytium_plat.c
+++ b/port/xhci/phytium/freertos/usb_glue_phytium_plat.c
@@ -14,6 +14,10 @@
#include "sdkconfig.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
#include "fassert.h"
#include "finterrupt.h"
#include "fcpu_info.h"
@@ -24,21 +28,103 @@
#include "usbh_core.h"
/************************** Constant Definitions *****************************/
+#define USB_XHCI_IRQ_TASK_STACK 8192U /* in bytes, same as usbproc */
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
-static void usb_hc_xhci_interrupt_handler(s32 vector, void *param)
+static SemaphoreHandle_t s_xhci_irq_sem[FUSB3_NUM] = { NULL };
+static TimerHandle_t s_port_poll_timer[FUSB3_NUM] = { NULL };
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+/************************** Function Prototypes ******************************/
+static uint32_t usb_hc_get_xhci_irq_num(u32 id);
+
+/* Port poll timer callback: runs in the timer daemon task context, forwards pending port change bits */
+static void cusb_port_poll_timer_cb(TimerHandle_t handle)
+{
+ extern void cusb_xhci_port_poll(uint8_t busid);
+
+ cusb_xhci_port_poll((uint8_t)(uintptr_t)pvTimerGetTimerID(handle));
+}
+
+/******************************* Functions ***********************************/
+
+/* Deferred interrupt thread: hard ISR wakes this thread; interrupt
+ * processing runs here in thread context where lock macros work. */
+static void usb_hc_xhci_irq_task(void *arg)
{
+ uint32_t id = (uint32_t)(uintptr_t)arg;
extern void USBH_IRQHandler(uint8_t busid);
- USBH_IRQHandler((uint8_t)(uintptr_t)param);
+
+ for (;;) {
+ if (s_xhci_irq_sem[id] == NULL) {
+ USB_LOG_ERR("xhci_irq sem NULL id=%lu\n", (unsigned long)id);
+ while (1)
+ ;
+ }
+ xSemaphoreTake(s_xhci_irq_sem[id], portMAX_DELAY);
+ USBH_IRQHandler((uint8_t)id);
+ }
+}
+
+static void usb_hc_xhci_interrupt_handler(s32 vector, void *param)
+{
+ uint32_t id = (uint32_t)(uintptr_t)param;
+ BaseType_t higher_prio_woken = pdFALSE;
+ extern void cusb_xhci_irq_ack(uint8_t busid);
+
+ (void)vector;
+
+ /* Ack at controller level only (IMAN.IP); port changes arrive as
+ * PSC TRBs on the event ring and are handled in the IRQ thread. */
+ cusb_xhci_irq_ack((uint8_t)id);
+
+ if (s_xhci_irq_sem[id] != NULL) {
+ xSemaphoreGiveFromISR(s_xhci_irq_sem[id], &higher_prio_woken);
+ portYIELD_FROM_ISR(higher_prio_woken);
+ }
+}
+
+static uint32_t usb_hc_get_xhci_irq_num(u32 id)
+{
+#if defined(CONFIG_TARGET_PE2204) || defined(CONFIG_TARGET_PE2202)
+ uint32_t irq_num[FUSB3_NUM] = {
+ FUSB3_0_IRQ_NUM,
+ FUSB3_1_IRQ_NUM
+ };
+ FASSERT(id < FUSB3_NUM);
+#endif
+
+ return irq_num[id];
}
void usb_hc_setup_xhci_interrupt(u32 id)
{
u32 cpu_id;
- u32 irq_num = (id == FUSB3_ID_0) ? FUSB3_0_IRQ_NUM : FUSB3_1_IRQ_NUM;
- u32 irq_priority = 13U;
+ u32 irq_priority = USB_XHCI_GIC_IRQ_PRIO;
+ u32 irq_num = usb_hc_get_xhci_irq_num(id);
+ char task_name[configMAX_TASK_NAME_LEN];
+
+ if (s_xhci_irq_sem[id] == NULL) {
+ s_xhci_irq_sem[id] = xSemaphoreCreateBinary();
+ FASSERT(s_xhci_irq_sem[id] != NULL);
+ snprintf(task_name, sizeof(task_name), "xhci_irq%lu", (unsigned long)id);
+ FASSERT(usb_osal_thread_create(task_name, USB_XHCI_IRQ_TASK_STACK,
+ CONFIG_USB_XHCI_IRQ_PRIO, usb_hc_xhci_irq_task,
+ (void *)(uintptr_t)id) != NULL);
+ }
+
+ /* Port poll timer: deterministic fallback scanning PORTSC every
+ * 100 ms; deinit stops it but never deletes it. */
+ if (s_port_poll_timer[id] == NULL) {
+ s_port_poll_timer[id] = xTimerCreate("usb_poll",
+ pdMS_TO_TICKS(100), pdTRUE,
+ (void *)(uintptr_t)id, cusb_port_poll_timer_cb);
+ FASSERT(s_port_poll_timer[id] != NULL);
+ }
+ xTimerStart(s_port_poll_timer[id], portMAX_DELAY);
GetCpuId(&cpu_id);
InterruptSetTargetCpus(irq_num, cpu_id);
@@ -50,15 +136,39 @@ void usb_hc_setup_xhci_interrupt(u32 id)
usb_hc_xhci_interrupt_handler,
(void *)(uintptr_t)id,
NULL);
+}
+
+void usb_hc_port_poll_stop(u32 id)
+{
+ /* stop polling so it cannot wake the hub after detach */
+ if (s_port_poll_timer[id] != NULL) {
+ xTimerStop(s_port_poll_timer[id], portMAX_DELAY);
+ }
+}
+
+void usb_hc_disable_interrupt(u32 id)
+{
+ u32 irq_num = usb_hc_get_xhci_irq_num(id);
+
+ InterruptMask(irq_num);
+}
+
+void usb_hc_enable_interrupt(u32 id)
+{
+ u32 irq_num = usb_hc_get_xhci_irq_num(id);
- /* enable irq */
InterruptUmask(irq_num);
}
unsigned long usb_hc_get_register_base(uint32_t id)
{
- if (FUSB3_ID_0 == id)
- return FUSB3_0_BASE_ADDR + FUSB3_XHCI_OFFSET;
- else
- return FUSB3_1_BASE_ADDR + FUSB3_XHCI_OFFSET;
-} \ No newline at end of file
+#if defined(CONFIG_TARGET_PE2204) || defined(CONFIG_TARGET_PE2202)
+ unsigned long base_reg[FUSB3_NUM] = {
+ FUSB3_0_BASE_ADDR + FUSB3_XHCI_OFFSET,
+ FUSB3_1_BASE_ADDR + FUSB3_XHCI_OFFSET
+ };
+ FASSERT(id < FUSB3_NUM);
+#endif
+
+ return base_reg[id];
+}
diff --git a/port/xhci/phytium/libxhci_a32_hardfp.a b/port/xhci/phytium/libxhci_a32_hardfp.a
index 7b1c5bc2..40c0bfaa 100644
--- a/port/xhci/phytium/libxhci_a32_hardfp.a
+++ b/port/xhci/phytium/libxhci_a32_hardfp.a
Binary files differ
diff --git a/port/xhci/phytium/libxhci_a32_softfp_crypto-neon-fp-armv8.a b/port/xhci/phytium/libxhci_a32_softfp_crypto-neon-fp-armv8.a
new file mode 100644
index 00000000..c2f0b67d
--- /dev/null
+++ b/port/xhci/phytium/libxhci_a32_softfp_crypto-neon-fp-armv8.a
Binary files differ
diff --git a/port/xhci/phytium/libxhci_a32_softfp_crypto_neon.a b/port/xhci/phytium/libxhci_a32_softfp_crypto_neon.a
deleted file mode 100644
index c5c624e4..00000000
--- a/port/xhci/phytium/libxhci_a32_softfp_crypto_neon.a
+++ /dev/null
Binary files differ
diff --git a/port/xhci/phytium/libxhci_a32_softfp_neon.a b/port/xhci/phytium/libxhci_a32_softfp_neon.a
deleted file mode 100644
index 5a8a3688..00000000
--- a/port/xhci/phytium/libxhci_a32_softfp_neon.a
+++ /dev/null
Binary files differ
diff --git a/port/xhci/phytium/libxhci_a64.a b/port/xhci/phytium/libxhci_a64.a
index 39062c1e..891be375 100644
--- a/port/xhci/phytium/libxhci_a64.a
+++ b/port/xhci/phytium/libxhci_a64.a
Binary files differ
diff --git a/port/xhci/phytium/rt-thread/usb_config.h b/port/xhci/phytium/rt-thread/usb_config.h
index 460d1241..c33f6965 100644
--- a/port/xhci/phytium/rt-thread/usb_config.h
+++ b/port/xhci/phytium/rt-thread/usb_config.h
@@ -283,7 +283,7 @@ unsigned long usb_hc_get_register_base(uint32_t id);
#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
#ifndef CONFIG_USB_XHCI_ENABLE_SOFT_ISR
-#define CONFIG_USB_XHCI_ENABLE_SOFT_ISR 0
+#define CONFIG_USB_XHCI_ENABLE_SOFT_ISR 0
#endif
#endif
diff --git a/port/xhci/phytium/rt-thread/usb_glue_phytium.c b/port/xhci/phytium/rt-thread/usb_glue_phytium.c
index 1f72f313..5fe334ed 100644
--- a/port/xhci/phytium/rt-thread/usb_glue_phytium.c
+++ b/port/xhci/phytium/rt-thread/usb_glue_phytium.c
@@ -20,8 +20,7 @@ void *xhci_mem_malloc(size_t align, size_t size)
{
void *result = rt_malloc_align(size, align);
- if (result)
- {
+ if (result) {
memset(result, 0U, size);
}
@@ -30,20 +29,16 @@ void *xhci_mem_malloc(size_t align, size_t size)
void xhci_mem_free(void *ptr)
{
- if (NULL != ptr)
- {
+ if (NULL != ptr) {
rt_free(ptr);
}
}
void xhci_dcache_sync(void *ptr, size_t len, uint32_t flags)
{
- if (flags & XHCI_DCACHE_FLUSH)
- {
+ if (flags & XHCI_DCACHE_FLUSH) {
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, ptr, len);
- }
- else if (flags & XHCI_DCACHE_INVALIDATE)
- {
+ } else if (flags & XHCI_DCACHE_INVALIDATE) {
rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, ptr, len);
}
}
diff --git a/port/xhci/phytium/rt-thread/usb_glue_phytium_plat.c b/port/xhci/phytium/rt-thread/usb_glue_phytium_plat.c
index 5847eefc..754dad79 100644
--- a/port/xhci/phytium/rt-thread/usb_glue_phytium_plat.c
+++ b/port/xhci/phytium/rt-thread/usb_glue_phytium_plat.c
@@ -28,7 +28,7 @@ void usb_hc_setup_xhci_interrupt(uint32_t id)
{
uint32_t irq_num = (id == FUSB3_ID_0) ? FUSB3_0_IRQ_NUM : FUSB3_1_IRQ_NUM;
rt_hw_interrupt_set_priority(irq_num, 0xd0);
- rt_hw_interrupt_install(irq_num, usb_hc_xhci_interrupt_handler,
+ rt_hw_interrupt_install(irq_num, usb_hc_xhci_interrupt_handler,
NULL, "xhci");
rt_hw_interrupt_umask(irq_num);
}
diff --git a/tests/hpmicro/CMakeLists.txt b/tests/hpmicro/CMakeLists.txt
index c9158767..a74735b5 100644
--- a/tests/hpmicro/CMakeLists.txt
+++ b/tests/hpmicro/CMakeLists.txt
@@ -10,6 +10,12 @@ set(CONFIG_CHERRYSH 1)
set(CONFIG_CHERRYSH_INTERFACE "uart")
set(CONFIG_USB_DEVICE 1)
+set(CONFIG_SDMMC 1)
+set(CONFIG_FATFS 1)
+
+set(CONFIG_CHERRYUSB_DEVICE_ADB_SYNC 1)
+set(CONFIG_CHERRYUSB_DEVICE_ADB_SYNC_FATFS 1)
+
set(CONFIG_FREERTOS 1)
set(CONFIG_LWIP 1)
set(CONFIG_LWIP_IPERF 1)
@@ -34,6 +40,8 @@ sdk_compile_definitions(-DCONFIG_USBHOST_PLATFORM_CDC_RNDIS)
sdk_compile_definitions(-DCONFIG_USBHOST_PLATFORM_ASIX)
sdk_compile_definitions(-DCONFIG_USBHOST_PLATFORM_RTL8152)
+sdk_compile_definitions(-DSD_FATFS_ENABLE=1)
+sdk_compile_definitions(-DFF_CODE_PAGE=437)
# sdk_compile_definitions(-DCONFIG_USB_OTG_ENABLE)
sdk_compile_options("-O2")
diff --git a/third_party/libscpi/inc/scpi/cc.h b/third_party/libscpi/inc/scpi/cc.h
new file mode 100644
index 00000000..3487ed1a
--- /dev/null
+++ b/third_party/libscpi/inc/scpi/cc.h
@@ -0,0 +1,211 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file cc.h
+ *
+ * @brief compiler detection
+ *
+ *
+ */
+
+#ifndef __SCPI_CC_H_
+#define __SCPI_CC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__STDC__)
+# define C89 1
+# if defined(__STDC_VERSION__)
+# define C90 1
+# if (__STDC_VERSION__ >= 199409L)
+# define C94 1
+# endif
+# if (__STDC_VERSION__ >= 199901L)
+# define C99 1
+# endif
+# endif
+#endif
+
+#if defined(__cplusplus)
+# if (__cplusplus >= 199711)
+# define CXX98 1
+# endif
+#endif
+
+#if (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200809L) || \
+ (defined _XOPEN_SOURCE && _XOPEN_SOURCE >= 700)
+ #define HAVE_STRNDUP 1
+ #define HAVE_STRNLEN 1
+#endif
+
+#if (defined _BSD_SOURCE && _BSD_SOURCE) || \
+ (defined _XOPEN_SOURCE && _XOPEN_SOURCE >= 500) || \
+ (defined _ISOC99_SOURCE && _ISOC99_SOURCE) || \
+ (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L) || \
+ C99
+ #define HAVE_SNPRINTF 1
+#endif
+
+#if (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L)
+ #define HAVE_STRNCASECMP 1
+#endif
+
+#if (defined _BSD_SOURCE && _BSD_SOURCE) || \
+ (defined _SVID_SOURCE && _SVID_SOURCE) || \
+ (defined _XOPEN_SOURCE && _XOPEN_SOURCE) || \
+ (defined _ISOC99_SOURCE && _ISOC99_SOURCE) || \
+ (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L) ||\
+ C99
+ #define HAVE_ISNAN 1
+#endif
+
+#if (defined _XOPEN_SOURCE && _XOPEN_SOURCE >= 600)|| \
+ (defined _ISOC99_SOURCE && _ISOC99_SOURCE) || \
+ (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L) || \
+ C99
+ #define HAVE_ISFINITE 1
+ #define HAVE_SIGNBIT 1
+#endif
+
+#if (defined _XOPEN_SOURCE && XOPEN_SOURCE >= 600) || \
+ (defined _BSD_SOURCE && _BSD_SOURCE) || \
+ (defined _SVID_SOURCE && _SVID_SOURCE) || \
+ (defined _ISOC99_SOURCE && _ISOC99_SOURCE) || \
+ (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L)
+ #define HAVE_STRTOLL 1
+#endif
+
+#if (defined _XOPEN_SOURCE && _XOPEN_SOURCE >= 600) || \
+ (defined _ISOC99_SOURCE && _ISOC99_SOURCE) || \
+ (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L) || \
+ C99
+ #define HAVE_STRTOF 1
+#endif
+
+#if (defined _ISOC99_SOURCE && _ISOC99_SOURCE) || C99 || CXX98
+ #define HAVE_STDBOOL 1
+#endif
+
+/* Compiler specific */
+/* RealView/Keil ARM Compiler, e.g. Cortex-M CPUs */
+#if defined(__CC_ARM)
+#define HAVE_STRNCASECMP 1
+#endif
+
+/* National Instruments (R) CVI x86/x64 PC platform */
+#if defined(_CVI_)
+#define HAVE_STRNICMP 1
+#endif
+
+/* 8bit PIC - PIC16, etc */
+#if defined(_MPC_)
+#define HAVE_STRNICMP 1
+#endif
+
+/* PIC24 */
+#if defined(__C30__)
+#endif
+
+/* PIC32mx */
+#if defined(__C32__)
+#define HAVE_FINITE 1
+#endif
+
+/* AVR libc */
+#if defined(__AVR__)
+#include <stdlib.h>
+#define HAVE_DTOSTRE 1
+#undef HAVE_STRTOF
+#define HAVE_STRTOF 0
+#endif
+
+/* default values */
+#ifndef HAVE_STRNLEN
+#define HAVE_STRNLEN 0
+#endif
+
+#ifndef HAVE_STRDUP
+#define HAVE_STRDUP 0
+#endif
+
+#ifndef HAVE_STRNDUP
+#define HAVE_STRNDUP 0
+#endif
+
+#ifndef HAVE_STRNICMP
+#define HAVE_STRNICMP 0
+#endif
+
+#ifndef HAVE_STDBOOL
+#define HAVE_STDBOOL 0
+#endif
+
+#ifndef HAVE_SNPRINTF
+#define HAVE_SNPRINTF 0
+#endif
+
+#ifndef HAVE_STRNCASECMP
+#define HAVE_STRNCASECMP 0
+#endif
+
+#ifndef HAVE_ISNAN
+#define HAVE_ISNAN 0
+#endif
+
+#ifndef HAVE_ISFINITE
+#define HAVE_ISFINITE 0
+#endif
+
+#ifndef HAVE_FINITE
+#define HAVE_FINITE 0
+#endif
+
+#ifndef HAVE_SIGNBIT
+#define HAVE_SIGNBIT 0
+#endif
+
+#ifndef HAVE_STRTOLL
+#define HAVE_STRTOLL 0
+#endif
+
+#ifndef HAVE_STRTOF
+#define HAVE_STRTOF 0
+#endif
+
+#ifndef HAVE_DTOSTRE
+#define HAVE_DTOSTRE 0
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SCPI_CC_H_ */
diff --git a/third_party/libscpi/inc/scpi/config.h b/third_party/libscpi/inc/scpi/config.h
new file mode 100644
index 00000000..2d3652e6
--- /dev/null
+++ b/third_party/libscpi/inc/scpi/config.h
@@ -0,0 +1,291 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file config.h
+ * @date Wed Mar 20 12:21:26 UTC 2013
+ *
+ * @brief SCPI Configuration
+ *
+ *
+ */
+
+#ifndef __SCPI_CONFIG_H_
+#define __SCPI_CONFIG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "cc.h"
+
+#ifdef SCPI_USER_CONFIG
+#include "scpi_user_config.h"
+#endif
+
+/* set the termination character(s) */
+#define LINE_ENDING_CR "\r" /* use a <CR> carriage return as termination charcter */
+#define LINE_ENDING_LF "\n" /* use a <LF> line feed as termination charcter */
+#define LINE_ENDING_CRLF "\r\n" /* use <CR><LF> carriage return + line feed as termination charcters */
+
+#ifndef SCPI_LINE_ENDING
+#define SCPI_LINE_ENDING LINE_ENDING_CRLF
+#endif
+
+#ifndef USE_CUSTOM_REGISTERS
+#define USE_CUSTOM_REGISTERS 0
+#endif
+
+/**
+ * Detect, if it has limited resources or it is running on a full blown operating system.
+ * All values can be overiden by scpi_user_config.h
+ */
+#define SYSTEM_BARE_METAL 0
+#define SYSTEM_FULL_BLOWN 1
+
+/* This should cover all windows compilers (msvc, mingw, cvi) and all Linux/OSX/BSD and other UNIX compatible systems (gcc, clang) */
+#if defined(_WIN32) || defined(_WIN64) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
+#define SYSTEM_TYPE SYSTEM_FULL_BLOWN
+#else
+#define SYSTEM_TYPE SYSTEM_BARE_METAL
+#endif
+
+/**
+ * Enable full error list
+ * 0 = Minimal set of errors
+ * 1 = Full set of errors
+ *
+ * For small systems, full set of errors will occupy large ammount of data
+ * It is enabled by default on full blown systems and disabled on limited bare metal systems
+ */
+#ifndef USE_FULL_ERROR_LIST
+#define USE_FULL_ERROR_LIST SYSTEM_TYPE
+#endif
+
+/**
+ * Enable also LIST_OF_USER_ERRORS to be included
+ * 0 = Use only library defined errors
+ * 1 = Use also LIST_OF_USER_ERRORS
+ */
+#ifndef USE_USER_ERROR_LIST
+#define USE_USER_ERROR_LIST 0
+#endif
+
+#ifndef USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+#define USE_DEVICE_DEPENDENT_ERROR_INFORMATION SYSTEM_TYPE
+#endif
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+#ifndef USE_MEMORY_ALLOCATION_FREE
+#define USE_MEMORY_ALLOCATION_FREE 1
+#endif
+#else
+#ifndef USE_MEMORY_ALLOCATION_FREE
+#define USE_MEMORY_ALLOCATION_FREE 0
+#endif
+#endif
+
+#ifndef USE_COMMAND_TAGS
+#define USE_COMMAND_TAGS 1
+#endif
+
+#ifndef USE_DEPRECATED_FUNCTIONS
+#define USE_DEPRECATED_FUNCTIONS 1
+#endif
+
+#ifndef USE_CUSTOM_DTOSTRE
+#define USE_CUSTOM_DTOSTRE 0
+#endif
+
+#ifndef USE_UNITS_IMPERIAL
+#define USE_UNITS_IMPERIAL 0
+#endif
+
+#ifndef USE_UNITS_ANGLE
+#define USE_UNITS_ANGLE SYSTEM_TYPE
+#endif
+
+#ifndef USE_UNITS_PARTICLES
+#define USE_UNITS_PARTICLES SYSTEM_TYPE
+#endif
+
+#ifndef USE_UNITS_DISTANCE
+#define USE_UNITS_DISTANCE SYSTEM_TYPE
+#endif
+
+#ifndef USE_UNITS_MAGNETIC
+#define USE_UNITS_MAGNETIC SYSTEM_TYPE
+#endif
+
+#ifndef USE_UNITS_LIGHT
+#define USE_UNITS_LIGHT SYSTEM_TYPE
+#endif
+
+#ifndef USE_UNITS_ENERGY_FORCE_MASS
+#define USE_UNITS_ENERGY_FORCE_MASS SYSTEM_TYPE
+#endif
+
+#ifndef USE_UNITS_TIME
+#define USE_UNITS_TIME SYSTEM_TYPE
+#endif
+
+#ifndef USE_UNITS_TEMPERATURE
+#define USE_UNITS_TEMPERATURE SYSTEM_TYPE
+#endif
+
+#ifndef USE_UNITS_RATIO
+#define USE_UNITS_RATIO SYSTEM_TYPE
+#endif
+
+#ifndef USE_UNITS_POWER
+#define USE_UNITS_POWER 1
+#endif
+
+#ifndef USE_UNITS_FREQUENCY
+#define USE_UNITS_FREQUENCY 1
+#endif
+
+#ifndef USE_UNITS_ELECTRIC
+#define USE_UNITS_ELECTRIC 1
+#endif
+
+#ifndef USE_UNITS_ELECTRIC_CHARGE_CONDUCTANCE
+#define USE_UNITS_ELECTRIC_CHARGE_CONDUCTANCE SYSTEM_TYPE
+#endif
+
+/* define local macros depending on existance of strnlen */
+#if HAVE_STRNLEN
+#define SCPIDEFINE_strnlen(s, l) strnlen((s), (l))
+#else
+#define SCPIDEFINE_strnlen(s, l) BSD_strnlen((s), (l))
+#endif
+
+/* define local macros depending on existance of strncasecmp and strnicmp */
+#if HAVE_STRNCASECMP
+#define SCPIDEFINE_strncasecmp(s1, s2, l) strncasecmp((s1), (s2), (l))
+#elif HAVE_STRNICMP
+#define SCPIDEFINE_strncasecmp(s1, s2, l) strnicmp((s1), (s2), (l))
+#else
+#define SCPIDEFINE_strncasecmp(s1, s2, l) OUR_strncasecmp((s1), (s2), (l))
+#endif
+
+#if HAVE_DTOSTRE
+#define SCPIDEFINE_floatToStr(v, s, l) dtostre((double)(v), (s), 6, DTOSTR_PLUS_SIGN | DTOSTR_ALWAYS_SIGN | DTOSTR_UPPERCASE)
+#elif USE_CUSTOM_DTOSTRE
+#define SCPIDEFINE_floatToStr(v, s, l) SCPI_dtostre((v), (s), (l), 6, 0)
+#elif HAVE_SNPRINTF
+#define SCPIDEFINE_floatToStr(v, s, l) snprintf((s), (l), "%g", (v))
+#else
+#define SCPIDEFINE_floatToStr(v, s, l) SCPI_dtostre((v), (s), (l), 6, 0)
+#endif
+
+#if HAVE_DTOSTRE
+#define SCPIDEFINE_doubleToStr(v, s, l) dtostre((v), (s), 15, DTOSTR_PLUS_SIGN | DTOSTR_ALWAYS_SIGN | DTOSTR_UPPERCASE)
+#elif USE_CUSTOM_DTOSTRE
+#define SCPIDEFINE_doubleToStr(v, s, l) SCPI_dtostre((v), (s), (l), 15, 0)
+#elif HAVE_SNPRINTF
+#define SCPIDEFINE_doubleToStr(v, s, l) snprintf((s), (l), "%.15lg", (v))
+#else
+#define SCPIDEFINE_doubleToStr(v, s, l) SCPI_dtostre((v), (s), (l), 15, 0)
+#endif
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+
+ #if USE_MEMORY_ALLOCATION_FREE
+ #include <stdlib.h>
+ #include <string.h>
+ #define SCPIDEFINE_DESCRIPTION_MAX_PARTS 2
+ #if HAVE_STRNDUP
+ #define SCPIDEFINE_strndup(h, s, l) strndup((s), (l))
+ #else
+ #define SCPIDEFINE_strndup(h, s, l) OUR_strndup((s), (l))
+ #endif
+ #define SCPIDEFINE_free(h, s, r) free((s))
+ #else
+ #define SCPIDEFINE_DESCRIPTION_MAX_PARTS 3
+ #define SCPIDEFINE_strndup(h, s, l) scpiheap_strndup((h), (s), (l))
+ #define SCPIDEFINE_free(h, s, r) scpiheap_free((h), (s), (r))
+ #define SCPIDEFINE_get_parts(h, s, l1, s2, l2) scpiheap_get_parts((h), (s), (l1), (s2), (l2))
+ #endif
+#else
+ #define SCPIDEFINE_DESCRIPTION_MAX_PARTS 1
+ #define SCPIDEFINE_strndup(h, s, l) NULL
+ #define SCPIDEFINE_free(h, s, r)
+#endif
+
+#if HAVE_SIGNBIT
+ #define SCPIDEFINE_signbit(n) signbit(n)
+#else
+ #define SCPIDEFINE_signbit(n) ((n)<0)
+#endif
+
+#if HAVE_FINITE
+ #define SCPIDEFINE_isfinite(n) finite(n)
+#elif HAVE_ISFINITE
+ #define SCPIDEFINE_isfinite(n) isfinite(n)
+#else
+ #define SCPIDEFINE_isfinite(n) (!SCPIDEFINE_isnan((n)) && ((n) < INFINITY) && ((n) > -INFINITY))
+#endif
+
+#if HAVE_STRTOF
+ #define SCPIDEFINE_strtof(n, p) strtof((n), (p))
+#else
+ #define SCPIDEFINE_strtof(n, p) strtod((n), (p))
+#endif
+
+#if HAVE_STRTOLL
+ #define SCPIDEFINE_strtoll(n, p, b) strtoll((n), (p), (b))
+ #define SCPIDEFINE_strtoull(n, p, b) strtoull((n), (p), (b))
+#else
+ #define SCPIDEFINE_strtoll(n, p, b) strtoll((n), (p), (b))
+ #define SCPIDEFINE_strtoull(n, p, b) strtoull((n), (p), (b))
+ extern long long int strtoll(const char *nptr, char **endptr, int base);
+ extern unsigned long long int strtoull(const char *nptr, char **endptr, int base);
+ /* TODO: implement OUR_strtoll and OUR_strtoull */
+ /* #warning "64bit string to int conversion not implemented" */
+#endif
+
+#if HAVE_ISNAN
+ #define SCPIDEFINE_isnan(n) isnan((n))
+#else
+ #define SCPIDEFINE_isnan(n) ((n) != (n))
+#endif
+
+#ifndef NAN
+ #define NAN (0.0 / 0.0)
+#endif
+
+#ifndef INFINITY
+ #define INFINITY (1.0 / 0.0)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/libscpi/inc/scpi/constants.h b/third_party/libscpi/inc/scpi/constants.h
new file mode 100644
index 00000000..14b58b43
--- /dev/null
+++ b/third_party/libscpi/inc/scpi/constants.h
@@ -0,0 +1,62 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_constants.h
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief SCPI Device constants
+ *
+ *
+ */
+
+#ifndef SCPI_CONSTANTS_H
+#define SCPI_CONSTANTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* 21.21 :VERSion?
+ * YYYY.V
+ * YYYY = SCPI year
+ * V = SCPI revision
+ */
+#define SCPI_STD_VERSION_REVISION "1999.0"
+
+/* 21.8 :ERRor Subsystem
+ * The maximum string length of <Error/event_description> plus <Device-dependent_info> is 255 characters.
+ */
+#define SCPI_STD_ERROR_DESC_MAX_STRING_LENGTH 255
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_CONSTANTS_H */
+
diff --git a/third_party/libscpi/inc/scpi/error.h b/third_party/libscpi/inc/scpi/error.h
new file mode 100644
index 00000000..d931e4f8
--- /dev/null
+++ b/third_party/libscpi/inc/scpi/error.h
@@ -0,0 +1,208 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_error.h
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief Error handling and storing routines
+ *
+ *
+ */
+
+#ifndef SCPI_ERROR_H
+#define SCPI_ERROR_H
+
+#include "scpi/config.h"
+#include "scpi/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void SCPI_ErrorInit(scpi_t * context, scpi_error_t * data, int16_t size);
+ void SCPI_ErrorClear(scpi_t * context);
+ scpi_bool_t SCPI_ErrorPop(scpi_t * context, scpi_error_t * error);
+ void SCPI_ErrorPushEx(scpi_t * context, int16_t err, char * info, size_t info_len);
+ void SCPI_ErrorPush(scpi_t * context, int16_t err);
+ int32_t SCPI_ErrorCount(scpi_t * context);
+ const char * SCPI_ErrorTranslate(int16_t err);
+
+
+ /* Using X-Macro technique to define everything once
+ * http://en.wikipedia.org/wiki/X_Macro
+ *
+ * X macro is for minimal set of errors for library itself
+ * XE macro is for full set of SCPI errors available to user application
+ */
+#define LIST_OF_ERRORS \
+ X(SCPI_ERROR_NO_ERROR, 0, "No error") \
+ XE(SCPI_ERROR_COMMAND, -100, "Command error") \
+ X(SCPI_ERROR_INVALID_CHARACTER, -101, "Invalid character") \
+ XE(SCPI_ERROR_SYNTAX, -102, "Syntax error") \
+ X(SCPI_ERROR_INVALID_SEPARATOR, -103, "Invalid separator") \
+ X(SCPI_ERROR_DATA_TYPE_ERROR, -104, "Data type error") \
+ XE(SCPI_ERROR_GET_NOT_ALLOWED, -105, "GET not allowed") \
+ X(SCPI_ERROR_PARAMETER_NOT_ALLOWED, -108, "Parameter not allowed") \
+ X(SCPI_ERROR_MISSING_PARAMETER, -109, "Missing parameter") \
+ XE(SCPI_ERROR_COMMAND_HEADER, -110, "Command header error") \
+ XE(SCPI_ERROR_HEADER_SEPARATOR, -111, "Header separator error") \
+ XE(SCPI_ERROR_PRG_MNEMONIC_TOO_LONG, -112, "Program mnemonic too long") \
+ X(SCPI_ERROR_UNDEFINED_HEADER, -113, "Undefined header") \
+ XE(SCPI_ERROR_HEADER_SUFFIX_OUTOFRANGE, -114, "Header suffix out of range") \
+ XE(SCPI_ERROR_UNEXP_NUM_OF_PARAMETER, -115, "Unexpected number of parameters") \
+ XE(SCPI_ERROR_NUMERIC_DATA_ERROR, -120, "Numeric data error") \
+ XE(SCPI_ERROR_INVAL_CHAR_IN_NUMBER, -121, "Invalid character in number") \
+ XE(SCPI_ERROR_EXPONENT_TOO_LONG, -123, "Exponent too large") \
+ XE(SCPI_ERROR_TOO_MANY_DIGITS, -124, "Too many digits") \
+ XE(SCPI_ERROR_NUMERIC_DATA_NOT_ALLOWED, -128, "Numeric data not allowed") \
+ XE(SCPI_ERROR_SUFFIX_ERROR, -130, "Suffix error") \
+ X(SCPI_ERROR_INVALID_SUFFIX, -131, "Invalid suffix") \
+ XE(SCPI_ERROR_SUFFIX_TOO_LONG, -134, "Suffix too long") \
+ X(SCPI_ERROR_SUFFIX_NOT_ALLOWED, -138, "Suffix not allowed") \
+ XE(SCPI_ERROR_CHARACTER_DATA_ERROR, -140, "Character data error") \
+ XE(SCPI_ERROR_INVAL_CHARACTER_DATA, -141, "Invalid character data") \
+ XE(SCPI_ERROR_CHARACTER_DATA_TOO_LONG, -144, "Character data too long") \
+ XE(SCPI_ERROR_CHARACTER_DATA_NOT_ALLOWED, -148, "Character data not allowed") \
+ XE(SCPI_ERROR_STRING_DATA_ERROR, -150, "String data error") \
+ X(SCPI_ERROR_INVALID_STRING_DATA, -151, "Invalid string data") \
+ XE(SCPI_ERROR_STRING_DATA_NOT_ALLOWED, -158, "String data not allowed") \
+ XE(SCPI_ERROR_BLOCK_DATA_ERROR, -160, "Block data error") \
+ XE(SCPI_ERROR_INVALID_BLOCK_DATA, -161, "Invalid block data") \
+ XE(SCPI_ERROR_BLOCK_DATA_NOT_ALLOWED, -168, "Block data not allowed") \
+ X(SCPI_ERROR_EXPRESSION_PARSING_ERROR, -170, "Expression error") \
+ XE(SCPI_ERROR_INVAL_EXPRESSION, -171, "Invalid expression") \
+ XE(SCPI_ERROR_EXPRESSION_DATA_NOT_ALLOWED, -178, "Expression data not allowed") \
+ XE(SCPI_ERROR_MACRO_DEFINITION_ERROR, -180, "Macro error") \
+ XE(SCPI_ERROR_INVAL_OUTSIDE_MACRO_DEF, -181, "Invalid outside macro definition") \
+ XE(SCPI_ERROR_INVAL_INSIDE_MACRO_DEF, -183, "Invalid inside macro definition") \
+ XE(SCPI_ERROR_MACRO_PARAMETER_ERROR, -184, "Macro parameter error") \
+ X(SCPI_ERROR_EXECUTION_ERROR, -200, "Execution error") \
+ XE(SCPI_ERROR_INVAL_WHILE_IN_LOCAL, -201, "Invalid while in local") \
+ XE(SCPI_ERROR_SETTINGS_LOST_DUE_TO_RTL, -202, "Settings lost due to rtl") \
+ XE(SCPI_ERROR_COMMAND_PROTECTED, -203, "Command protected") \
+ XE(SCPI_ERROR_TRIGGER_ERROR, -210, "Trigger error") \
+ XE(SCPI_ERROR_TRIGGER_IGNORED, -211, "Trigger ignored") \
+ XE(SCPI_ERROR_ARM_IGNORED, -212, "Arm ignored") \
+ XE(SCPI_ERROR_INIT_IGNORED, -213, "Init ignored") \
+ XE(SCPI_ERROR_TRIGGER_DEADLOCK, -214, "Trigger deadlock") \
+ XE(SCPI_ERROR_ARM_DEADLOCK, -215, "Arm deadlock") \
+ XE(SCPI_ERROR_PARAMETER_ERROR, -220, "Parameter error") \
+ XE(SCPI_ERROR_SETTINGS_CONFLICT, -221, "Settings conflict") \
+ XE(SCPI_ERROR_DATA_OUT_OF_RANGE, -222, "Data out of range") \
+ XE(SCPI_ERROR_TOO_MUCH_DATA, -223, "Too much data") \
+ X(SCPI_ERROR_ILLEGAL_PARAMETER_VALUE, -224, "Illegal parameter value") \
+ XE(SCPI_ERROR_OUT_OF_MEMORY_FOR_REQ_OP, -225, "Out of memory") \
+ XE(SCPI_ERROR_LISTS_NOT_SAME_LENGTH, -226, "Lists not same length") \
+ XE(SCPI_ERROR_DATA_CORRUPT, -230, "Data corrupt or stale") \
+ XE(SCPI_ERROR_DATA_QUESTIONABLE, -231, "Data questionable") \
+ XE(SCPI_ERROR_INVAL_VERSION, -233, "Invalid version") \
+ XE(SCPI_ERROR_HARDWARE_ERROR, -240, "Hardware error") \
+ XE(SCPI_ERROR_HARDWARE_MISSING, -241, "Hardware missing") \
+ XE(SCPI_ERROR_MASS_STORAGE_ERROR, -250, "Mass storage error") \
+ XE(SCPI_ERROR_MISSING_MASS_STORAGE, -251, "Missing mass storage") \
+ XE(SCPI_ERROR_MISSING_MASS_MEDIA, -252, "Missing media") \
+ XE(SCPI_ERROR_CORRUPT_MEDIA, -253, "Corrupt media") \
+ XE(SCPI_ERROR_MEDIA_FULL, -254, "Media full") \
+ XE(SCPI_ERROR_DIRECTORY_FULL, -255, "Directory full") \
+ XE(SCPI_ERROR_FILE_NAME_NOT_FOUND, -256, "File name not found") \
+ XE(SCPI_ERROR_FILE_NAME_ERROR, -257, "File name error") \
+ XE(SCPI_ERROR_MEDIA_PROTECTED, -258, "Media protected") \
+ XE(SCPI_ERROR_EXPRESSION_EXECUTING_ERROR, -260, "Expression error") \
+ XE(SCPI_ERROR_MATH_ERROR_IN_EXPRESSION, -261, "Math error in expression") \
+ XE(SCPI_ERROR_MACRO_UNDEF_EXEC_ERROR, -270, "Macro error") \
+ XE(SCPI_ERROR_MACRO_SYNTAX_ERROR, -271, "Macro syntax error") \
+ XE(SCPI_ERROR_MACRO_EXECUTION_ERROR, -272, "Macro execution error") \
+ XE(SCPI_ERROR_ILLEGAL_MACRO_LABEL, -273, "Illegal macro label") \
+ XE(SCPI_ERROR_IMPROPER_USED_MACRO_PARAM, -274, "Macro parameter error") \
+ XE(SCPI_ERROR_MACRO_DEFINITION_TOO_LONG, -275, "Macro definition too long") \
+ XE(SCPI_ERROR_MACRO_RECURSION_ERROR, -276, "Macro recursion error") \
+ XE(SCPI_ERROR_MACRO_REDEF_NOT_ALLOWED, -277, "Macro redefinition not allowed") \
+ XE(SCPI_ERROR_MACRO_HEADER_NOT_FOUND, -278, "Macro header not found") \
+ XE(SCPI_ERROR_PROGRAM_ERROR, -280, "Program error") \
+ XE(SCPI_ERROR_CANNOT_CREATE_PROGRAM, -281, "Cannot create program") \
+ XE(SCPI_ERROR_ILLEGAL_PROGRAM_NAME, -282, "Illegal program name") \
+ XE(SCPI_ERROR_ILLEGAL_VARIABLE_NAME, -283, "Illegal variable name") \
+ XE(SCPI_ERROR_PROGRAM_CURRENTLY_RUNNING, -284, "Program currently running") \
+ XE(SCPI_ERROR_PROGRAM_SYNTAX_ERROR, -285, "Program syntax error") \
+ XE(SCPI_ERROR_PROGRAM_RUNTIME_ERROR, -286, "Program runtime error") \
+ XE(SCPI_ERROR_MEMORY_USE_ERROR, -290, "Memory use error") \
+ XE(SCPI_ERROR_OUT_OF_MEMORY, -291, "Out of memory") \
+ XE(SCPI_ERROR_REF_NAME_DOES_NOT_EXIST, -292, "Referenced name does not exist") \
+ XE(SCPI_ERROR_REF_NAME_ALREADY_EXISTS, -293, "Referenced name already exists") \
+ XE(SCPI_ERROR_INCOMPATIBLE_TYPE, -294, "Incompatible type") \
+ XE(SCPI_ERROR_DEVICE_ERROR, -300, "Device specific error") \
+ X(SCPI_ERROR_SYSTEM_ERROR, -310, "System error") \
+ XE(SCPI_ERROR_MEMORY_ERROR, -311, "Memory error") \
+ XE(SCPI_ERROR_PUD_MEMORY_LOST, -312, "PUD memory lost") \
+ XE(SCPI_ERROR_CALIBRATION_MEMORY_LOST, -313, "Calibration memory lost") \
+ XE(SCPI_ERROR_SAVE_RECALL_MEMORY_LOST, -314, "Save/recall memory lost") \
+ XE(SCPI_ERROR_CONFIGURATION_MEMORY_LOST, -315, "Configuration memory lost") \
+ XE(SCPI_ERROR_STORAGE_FAULT, -320, "Storage fault") \
+ XE(SCPI_ERROR_OUT_OF_DEVICE_MEMORY, -321, "Out of memory") \
+ XE(SCPI_ERROR_SELF_TEST_FAILED, -330, "Self-test failed") \
+ XE(SCPI_ERROR_CALIBRATION_FAILED, -340, "Calibration failed") \
+ X(SCPI_ERROR_QUEUE_OVERFLOW, -350, "Queue overflow") \
+ XE(SCPI_ERROR_COMMUNICATION_ERROR, -360, "Communication error") \
+ XE(SCPI_ERROR_PARITY_ERROR_IN_CMD_MSG, -361, "Parity error in program message") \
+ XE(SCPI_ERROR_FRAMING_ERROR_IN_CMD_MSG, -362, "Framing error in program message") \
+ X(SCPI_ERROR_INPUT_BUFFER_OVERRUN, -363, "Input buffer overrun") \
+ XE(SCPI_ERROR_TIME_OUT, -365, "Time out error") \
+ XE(SCPI_ERROR_QUERY_ERROR, -400, "Query error") \
+ XE(SCPI_ERROR_QUERY_INTERRUPTED, -410, "Query INTERRUPTED") \
+ XE(SCPI_ERROR_QUERY_UNTERMINATED, -420, "Query UNTERMINATED") \
+ XE(SCPI_ERROR_QUERY_DEADLOCKED, -430, "Query DEADLOCKED") \
+ XE(SCPI_ERROR_QUERY_UNTERM_INDEF_RESP, -440, "Query UNTERMINATED after indefinite response") \
+ XE(SCPI_ERROR_POWER_ON, -500, "Power on") \
+ XE(SCPI_ERROR_USER_REQUEST, -600, "User request") \
+ XE(SCPI_ERROR_REQUEST_CONTROL, -700, "Request control") \
+ XE(SCPI_ERROR_OPERATION_COMPLETE, -800, "Operation complete") \
+
+
+ enum {
+#define X(def, val, str) def = val,
+#if USE_FULL_ERROR_LIST
+#define XE X
+#else
+#define XE(def, val, str)
+#endif
+ LIST_OF_ERRORS
+
+#if USE_USER_ERROR_LIST
+ LIST_OF_USER_ERRORS
+#endif
+#undef X
+#undef XE
+ };
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_ERROR_H */
+
diff --git a/third_party/libscpi/inc/scpi/expression.h b/third_party/libscpi/inc/scpi/expression.h
new file mode 100644
index 00000000..897eb14d
--- /dev/null
+++ b/third_party/libscpi/inc/scpi/expression.h
@@ -0,0 +1,62 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file expression.h
+ *
+ * @brief Expressions handling
+ *
+ *
+ */
+#ifndef SCPI_EXPRESSION_H
+#define SCPI_EXPRESSION_H
+
+#include "scpi/config.h"
+#include "scpi/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ enum _scpi_expr_result_t {
+ SCPI_EXPR_OK = 0,
+ SCPI_EXPR_ERROR,
+ SCPI_EXPR_NO_MORE,
+ };
+ typedef enum _scpi_expr_result_t scpi_expr_result_t;
+
+ scpi_expr_result_t SCPI_ExprNumericListEntry(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, scpi_parameter_t * valueFrom, scpi_parameter_t * valueTo);
+ scpi_expr_result_t SCPI_ExprNumericListEntryInt(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, int32_t * valueFrom, int32_t * valueTo);
+ scpi_expr_result_t SCPI_ExprNumericListEntryDouble(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, double * valueFrom, double * valueTo);
+ scpi_expr_result_t SCPI_ExprChannelListEntry(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, int32_t * valuesFrom, int32_t * valuesTo, size_t length, size_t * dimensions);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_EXPRESSION_H */
diff --git a/third_party/libscpi/inc/scpi/ieee488.h b/third_party/libscpi/inc/scpi/ieee488.h
new file mode 100644
index 00000000..15fb527d
--- /dev/null
+++ b/third_party/libscpi/inc/scpi/ieee488.h
@@ -0,0 +1,94 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_ieee488.h
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief Implementation of IEEE488.2 commands and state model
+ *
+ *
+ */
+
+#ifndef SCPI_IEEE488_H
+#define SCPI_IEEE488_H
+
+#include "scpi/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ scpi_result_t SCPI_CoreCls(scpi_t * context);
+ scpi_result_t SCPI_CoreEse(scpi_t * context);
+ scpi_result_t SCPI_CoreEseQ(scpi_t * context);
+ scpi_result_t SCPI_CoreEsrQ(scpi_t * context);
+ scpi_result_t SCPI_CoreIdnQ(scpi_t * context);
+ scpi_result_t SCPI_CoreOpc(scpi_t * context);
+ scpi_result_t SCPI_CoreOpcQ(scpi_t * context);
+ scpi_result_t SCPI_CoreRst(scpi_t * context);
+ scpi_result_t SCPI_CoreSre(scpi_t * context);
+ scpi_result_t SCPI_CoreSreQ(scpi_t * context);
+ scpi_result_t SCPI_CoreStbQ(scpi_t * context);
+ scpi_result_t SCPI_CoreTstQ(scpi_t * context);
+ scpi_result_t SCPI_CoreWai(scpi_t * context);
+
+
+#define STB_R01 0x01 /* Not used */
+#define STB_PRO 0x02 /* Protection Event Flag */
+#define STB_QMA 0x04 /* Error/Event queue message available */
+#define STB_QES 0x08 /* Questionable status */
+#define STB_MAV 0x10 /* Message Available */
+#define STB_ESR 0x20 /* Standard Event Status Register */
+#define STB_SRQ 0x40 /* Service Request */
+#define STB_OPS 0x80 /* Operation Status Flag */
+
+
+#define ESR_OPC 0x01 /* Operation complete */
+#define ESR_REQ 0x02 /* Request Control */
+#define ESR_QER 0x04 /* Query Error */
+#define ESR_DER 0x08 /* Device Dependent Error */
+#define ESR_EER 0x10 /* Execution Error (e.g. range error) */
+#define ESR_CER 0x20 /* Command error (e.g. syntax error) */
+#define ESR_URQ 0x40 /* User Request */
+#define ESR_PON 0x80 /* Power On */
+
+
+ scpi_reg_val_t SCPI_RegGet(scpi_t * context, scpi_reg_name_t name);
+ void SCPI_RegSet(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t val);
+ void SCPI_RegSetBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits);
+ void SCPI_RegClearBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits);
+
+ void SCPI_EventClear(scpi_t * context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_IEEE488_H */
+
diff --git a/third_party/libscpi/inc/scpi/minimal.h b/third_party/libscpi/inc/scpi/minimal.h
new file mode 100644
index 00000000..e14f1ed6
--- /dev/null
+++ b/third_party/libscpi/inc/scpi/minimal.h
@@ -0,0 +1,69 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_minimal.h
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief SCPI minimal implementation
+ *
+ *
+ */
+
+#ifndef SCPI_MINIMAL_H
+#define SCPI_MINIMAL_H
+
+#include "scpi/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ scpi_result_t SCPI_Stub(scpi_t * context);
+ scpi_result_t SCPI_StubQ(scpi_t * context);
+
+ scpi_result_t SCPI_SystemVersionQ(scpi_t * context);
+ scpi_result_t SCPI_SystemErrorNextQ(scpi_t * context);
+ scpi_result_t SCPI_SystemErrorCountQ(scpi_t * context);
+ scpi_result_t SCPI_StatusQuestionableEventQ(scpi_t * context);
+ scpi_result_t SCPI_StatusQuestionableConditionQ(scpi_t * context);
+ scpi_result_t SCPI_StatusQuestionableEnableQ(scpi_t * context);
+ scpi_result_t SCPI_StatusQuestionableEnable(scpi_t * context);
+ scpi_result_t SCPI_StatusOperationConditionQ(scpi_t * context);
+ scpi_result_t SCPI_StatusOperationEventQ(scpi_t * context);
+ scpi_result_t SCPI_StatusOperationEnableQ(scpi_t * context);
+ scpi_result_t SCPI_StatusOperationEnable(scpi_t * context);
+ scpi_result_t SCPI_StatusPreset(scpi_t * context);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_MINIMAL_H */
+
diff --git a/third_party/libscpi/inc/scpi/parser.h b/third_party/libscpi/inc/scpi/parser.h
new file mode 100644
index 00000000..643cec61
--- /dev/null
+++ b/third_party/libscpi/inc/scpi/parser.h
@@ -0,0 +1,151 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_parser.h
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief SCPI parser implementation
+ *
+ *
+ */
+
+#ifndef SCPI_PARSER_H
+#define SCPI_PARSER_H
+
+#include <string.h>
+#include "scpi/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void SCPI_Init(scpi_t * context,
+ const scpi_command_t * commands,
+ scpi_interface_t * interface,
+ const scpi_unit_def_t * units,
+ const char * idn1, const char * idn2, const char * idn3, const char * idn4,
+ char * input_buffer, size_t input_buffer_length,
+ scpi_error_t * error_queue_data, int16_t error_queue_size);
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+ void SCPI_InitHeap(scpi_t * context, char * error_info_heap, size_t error_info_heap_length);
+#endif
+
+ scpi_bool_t SCPI_Input(scpi_t * context, const char * data, int len);
+ scpi_bool_t SCPI_Parse(scpi_t * context, char * data, int len);
+
+ size_t SCPI_ResultCharacters(scpi_t * context, const char * data, size_t len);
+#define SCPI_ResultMnemonic(context, data) SCPI_ResultCharacters((context), (data), strlen(data))
+#define SCPI_ResultUInt8Base(c, v, b) SCPI_ResultUInt32Base((c), (v), (uint8_t)(b))
+#define SCPI_ResultUInt8(c, v) SCPI_ResultUInt32Base((c), (uint8_t)(v), 10)
+#define SCPI_ResultInt8(c, v) SCPI_ResultInt32((c), (int8_t)(v))
+#define SCPI_ResultUInt16Base(c, v, b) SCPI_ResultUInt32Base((c), (uint16_t)(v), (b))
+#define SCPI_ResultUInt16(c, v) SCPI_ResultUInt32Base((c), (uint16_t)(v), 10)
+#define SCPI_ResultInt16(c, v) SCPI_ResultInt32((c), (int16_t)(v))
+ size_t SCPI_ResultUInt32Base(scpi_t * context, uint32_t val, int8_t base);
+#define SCPI_ResultUInt32(c, v) SCPI_ResultUInt32Base((c), (v), 10)
+ size_t SCPI_ResultInt32(scpi_t * context, int32_t val);
+ size_t SCPI_ResultUInt64Base(scpi_t * context, uint64_t val, int8_t base);
+#define SCPI_ResultUInt64(c, v) SCPI_ResultUInt64Base((c), (v), 10)
+ size_t SCPI_ResultInt64(scpi_t * context, int64_t val);
+ size_t SCPI_ResultFloat(scpi_t * context, float val);
+ size_t SCPI_ResultDouble(scpi_t * context, double val);
+ size_t SCPI_ResultText(scpi_t * context, const char * data);
+ size_t SCPI_ResultError(scpi_t * context, scpi_error_t * error);
+ size_t SCPI_ResultArbitraryBlock(scpi_t * context, const void * data, size_t len);
+ size_t SCPI_ResultArbitraryBlockHeader(scpi_t * context, size_t len);
+ size_t SCPI_ResultArbitraryBlockData(scpi_t * context, const void * data, size_t len);
+ size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val);
+
+ size_t SCPI_ResultArrayInt8(scpi_t * context, const int8_t * array, size_t count, scpi_array_format_t format);
+ size_t SCPI_ResultArrayUInt8(scpi_t * context, const uint8_t * array, size_t count, scpi_array_format_t format);
+ size_t SCPI_ResultArrayInt16(scpi_t * context, const int16_t * array, size_t count, scpi_array_format_t format);
+ size_t SCPI_ResultArrayUInt16(scpi_t * context, const uint16_t * array, size_t count, scpi_array_format_t format);
+ size_t SCPI_ResultArrayInt32(scpi_t * context, const int32_t * array, size_t count, scpi_array_format_t format);
+ size_t SCPI_ResultArrayUInt32(scpi_t * context, const uint32_t * array, size_t count, scpi_array_format_t format);
+ size_t SCPI_ResultArrayInt64(scpi_t * context, const int64_t * array, size_t count, scpi_array_format_t format);
+ size_t SCPI_ResultArrayUInt64(scpi_t * context, const uint64_t * array, size_t count, scpi_array_format_t format);
+ size_t SCPI_ResultArrayFloat(scpi_t * context, const float * array, size_t count, scpi_array_format_t format);
+ size_t SCPI_ResultArrayDouble(scpi_t * context, const double * array, size_t count, scpi_array_format_t format);
+
+ scpi_bool_t SCPI_Parameter(scpi_t * context, scpi_parameter_t * parameter, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamIsValid(scpi_parameter_t * parameter);
+ scpi_bool_t SCPI_ParamErrorOccurred(scpi_t * context);
+ scpi_bool_t SCPI_ParamIsNumber(scpi_parameter_t * parameter, scpi_bool_t suffixAllowed);
+ scpi_bool_t SCPI_ParamToInt32(scpi_t * context, scpi_parameter_t * parameter, int32_t * value);
+ scpi_bool_t SCPI_ParamToUInt32(scpi_t * context, scpi_parameter_t * parameter, uint32_t * value);
+ scpi_bool_t SCPI_ParamToInt64(scpi_t * context, scpi_parameter_t * parameter, int64_t * value);
+ scpi_bool_t SCPI_ParamToUInt64(scpi_t * context, scpi_parameter_t * parameter, uint64_t * value);
+ scpi_bool_t SCPI_ParamToFloat(scpi_t * context, scpi_parameter_t * parameter, float * value);
+ scpi_bool_t SCPI_ParamToDouble(scpi_t * context, scpi_parameter_t * parameter, double * value);
+ scpi_bool_t SCPI_ParamToChoice(scpi_t * context, scpi_parameter_t * parameter, const scpi_choice_def_t * options, int32_t * value);
+ scpi_bool_t SCPI_ChoiceToName(const scpi_choice_def_t * options, int32_t tag, const char ** text);
+
+ scpi_bool_t SCPI_ParamInt32(scpi_t * context, int32_t * value, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamUInt32(scpi_t * context, uint32_t * value, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamInt64(scpi_t * context, int64_t * value, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamUInt64(scpi_t * context, uint64_t * value, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamFloat(scpi_t * context, float * value, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamCharacters(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamArbitraryBlock(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamCopyText(scpi_t * context, char * buffer, size_t buffer_len, size_t * copy_len, scpi_bool_t mandatory);
+
+ extern const scpi_choice_def_t scpi_bool_def[];
+ scpi_bool_t SCPI_ParamBool(scpi_t * context, scpi_bool_t * value, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamChoice(scpi_t * context, const scpi_choice_def_t * options, int32_t * value, scpi_bool_t mandatory);
+
+ scpi_bool_t SCPI_ParamArrayInt32(scpi_t * context, int32_t *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamArrayUInt32(scpi_t * context, uint32_t *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamArrayInt64(scpi_t * context, int64_t *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamArrayUInt64(scpi_t * context, uint64_t *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamArrayFloat(scpi_t * context, float *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory);
+ scpi_bool_t SCPI_ParamArrayDouble(scpi_t * context, double *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory);
+
+ scpi_bool_t SCPI_IsCmd(scpi_t * context, const char * cmd);
+#if USE_COMMAND_TAGS
+ int32_t SCPI_CmdTag(scpi_t * context);
+#endif /* USE_COMMAND_TAGS */
+ scpi_bool_t SCPI_Match(const char * pattern, const char * value, size_t len);
+ scpi_bool_t SCPI_CommandNumbers(scpi_t * context, int32_t * numbers, size_t len, int32_t default_value);
+
+#if USE_DEPRECATED_FUNCTIONS
+ /* deprecated finction, should be removed later */
+#define SCPI_ResultIntBase(context, val, base) SCPI_ResultInt32Base ((context), (val), (base), TRUE)
+#define SCPI_ResultInt(context, val) SCPI_ResultInt32 ((context), (val))
+#define SCPI_ParamToInt(context, parameter, value) SCPI_ParamToInt32((context), (parameter), (value))
+#define SCPI_ParamToUnsignedInt(context, parameter, value) SCPI_ParamToUInt32((context), (parameter), (value))
+#define SCPI_ParamInt(context, value, mandatory) SCPI_ParamInt32((context), (value), (mandatory))
+#define SCPI_ParamUnsignedInt(context, value, mandatory) SCPI_ParamUInt32((context), (value), (mandatory))
+#endif /* USE_DEPRECATED_FUNCTIONS */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_PARSER_H */
+
diff --git a/third_party/libscpi/inc/scpi/scpi.h b/third_party/libscpi/inc/scpi/scpi.h
new file mode 100644
index 00000000..ea28dd44
--- /dev/null
+++ b/third_party/libscpi/inc/scpi/scpi.h
@@ -0,0 +1,51 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi.h
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief SCPI library include file
+ *
+ *
+ */
+
+#ifndef SCPI_H
+#define SCPI_H
+
+#include "scpi/parser.h"
+#include "scpi/ieee488.h"
+#include "scpi/error.h"
+#include "scpi/constants.h"
+#include "scpi/minimal.h"
+#include "scpi/units.h"
+#include "scpi/utils.h"
+#include "scpi/expression.h"
+
+#endif /* SCPI_H */
+
diff --git a/third_party/libscpi/inc/scpi/types.h b/third_party/libscpi/inc/scpi/types.h
new file mode 100644
index 00000000..eb9b2153
--- /dev/null
+++ b/third_party/libscpi/inc/scpi/types.h
@@ -0,0 +1,459 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer, Richard.hmm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_types.h
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief SCPI data types
+ *
+ *
+ */
+
+#ifndef SCPI_TYPES_H
+#define SCPI_TYPES_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include "scpi/config.h"
+
+#if HAVE_STDBOOL
+#include <stdbool.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !HAVE_STDBOOL
+ typedef unsigned char bool;
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+ /* basic data types */
+ typedef bool scpi_bool_t;
+ /* typedef enum { FALSE = 0, TRUE } scpi_bool_t; */
+
+ /* IEEE 488.2 registers */
+ enum _scpi_reg_name_t {
+ SCPI_REG_STB = 0, /* Status Byte */
+ SCPI_REG_SRE, /* Service Request Enable Register */
+ SCPI_REG_ESR, /* Standard Event Status Register (ESR, SESR) */
+ SCPI_REG_ESE, /* Event Status Enable Register */
+ SCPI_REG_OPER, /* OPERation Status Register */
+ SCPI_REG_OPERE, /* OPERation Status Enable Register */
+ SCPI_REG_OPERC, /* OPERation Status Condition Register */
+ SCPI_REG_QUES, /* QUEStionable status register */
+ SCPI_REG_QUESE, /* QUEStionable status Enable Register */
+ SCPI_REG_QUESC, /* QUEStionable status Condition Register */
+
+#if USE_CUSTOM_REGISTERS
+#ifndef USER_REGISTERS
+#error "No user registers defined"
+#else
+ USER_REGISTERS
+#endif
+#endif
+
+ /* number of registers */
+ SCPI_REG_COUNT,
+ /* last definition - a value for no register */
+ SCPI_REG_NONE
+ };
+ typedef enum _scpi_reg_name_t scpi_reg_name_t;
+
+ enum _scpi_ctrl_name_t {
+ SCPI_CTRL_SRQ = 1, /* service request */
+ SCPI_CTRL_GTL, /* Go to local */
+ SCPI_CTRL_SDC, /* Selected device clear */
+ SCPI_CTRL_PPC, /* Parallel poll configure */
+ SCPI_CTRL_GET, /* Group execute trigger */
+ SCPI_CTRL_TCT, /* Take control */
+ SCPI_CTRL_LLO, /* Device clear */
+ SCPI_CTRL_DCL, /* Local lockout */
+ SCPI_CTRL_PPU, /* Parallel poll unconfigure */
+ SCPI_CTRL_SPE, /* Serial poll enable */
+ SCPI_CTRL_SPD, /* Serial poll disable */
+ SCPI_CTRL_MLA, /* My local address */
+ SCPI_CTRL_UNL, /* Unlisten */
+ SCPI_CTRL_MTA, /* My talk address */
+ SCPI_CTRL_UNT, /* Untalk */
+ SCPI_CTRL_MSA /* My secondary address */
+ };
+ typedef enum _scpi_ctrl_name_t scpi_ctrl_name_t;
+
+ typedef uint16_t scpi_reg_val_t;
+
+ enum _scpi_reg_class_t {
+ SCPI_REG_CLASS_STB = 0,
+ SCPI_REG_CLASS_SRE,
+ SCPI_REG_CLASS_EVEN,
+ SCPI_REG_CLASS_ENAB,
+ SCPI_REG_CLASS_COND,
+ SCPI_REG_CLASS_NTR,
+ SCPI_REG_CLASS_PTR,
+ };
+ typedef enum _scpi_reg_class_t scpi_reg_class_t;
+
+ enum _scpi_reg_group_t {
+ SCPI_REG_GROUP_STB = 0,
+ SCPI_REG_GROUP_ESR,
+ SCPI_REG_GROUP_OPER,
+ SCPI_REG_GROUP_QUES,
+
+#if USE_CUSTOM_REGISTERS
+#ifndef USER_REGISTER_GROUPS
+#error "No user register groups defined"
+#else
+ USER_REGISTER_GROUPS
+#endif
+#endif
+
+ /* last definition - number of register groups */
+ SCPI_REG_GROUP_COUNT
+ };
+ typedef enum _scpi_reg_group_t scpi_reg_group_t;
+
+ struct _scpi_reg_info_t {
+ scpi_reg_class_t type;
+ scpi_reg_group_t group;
+ };
+ typedef struct _scpi_reg_info_t scpi_reg_info_t;
+
+ struct _scpi_reg_group_info_t {
+ scpi_reg_name_t event;
+ scpi_reg_name_t enable;
+ scpi_reg_name_t condition;
+ scpi_reg_name_t ptfilt;
+ scpi_reg_name_t ntfilt;
+ scpi_reg_name_t parent_reg;
+ scpi_reg_val_t parent_bit;
+ };
+ typedef struct _scpi_reg_group_info_t scpi_reg_group_info_t;
+
+ /* scpi commands */
+ enum _scpi_result_t {
+ SCPI_RES_OK = 1,
+ SCPI_RES_ERR = -1
+ };
+ typedef enum _scpi_result_t scpi_result_t;
+
+ typedef struct _scpi_command_t scpi_command_t;
+
+#if USE_COMMAND_TAGS
+ #define SCPI_CMD_LIST_END {NULL, NULL, 0}
+#else
+ #define SCPI_CMD_LIST_END {NULL, NULL}
+#endif
+
+
+ /* scpi interface */
+ typedef struct _scpi_t scpi_t;
+ typedef struct _scpi_interface_t scpi_interface_t;
+
+ struct _scpi_buffer_t {
+ size_t length;
+ size_t position;
+ char * data;
+ };
+ typedef struct _scpi_buffer_t scpi_buffer_t;
+
+ struct _scpi_const_buffer_t {
+ size_t length;
+ size_t position;
+ const char * data;
+ };
+ typedef struct _scpi_const_buffer_t scpi_const_buffer_t;
+
+ typedef size_t(*scpi_write_t)(scpi_t * context, const char * data, size_t len);
+ typedef scpi_result_t(*scpi_write_control_t)(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val);
+ typedef int (*scpi_error_callback_t)(scpi_t * context, int_fast16_t error);
+
+ /* scpi lexer */
+ enum _scpi_token_type_t {
+ SCPI_TOKEN_COMMA,
+ SCPI_TOKEN_SEMICOLON,
+ SCPI_TOKEN_COLON,
+ SCPI_TOKEN_SPECIFIC_CHARACTER,
+ SCPI_TOKEN_QUESTION,
+ SCPI_TOKEN_NL,
+ SCPI_TOKEN_HEXNUM,
+ SCPI_TOKEN_OCTNUM,
+ SCPI_TOKEN_BINNUM,
+ SCPI_TOKEN_PROGRAM_MNEMONIC,
+ SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA,
+ SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX,
+ SCPI_TOKEN_SUFFIX_PROGRAM_DATA,
+ SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA,
+ SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA,
+ SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA,
+ SCPI_TOKEN_PROGRAM_EXPRESSION,
+ SCPI_TOKEN_COMPOUND_PROGRAM_HEADER,
+ SCPI_TOKEN_INCOMPLETE_COMPOUND_PROGRAM_HEADER,
+ SCPI_TOKEN_COMMON_PROGRAM_HEADER,
+ SCPI_TOKEN_INCOMPLETE_COMMON_PROGRAM_HEADER,
+ SCPI_TOKEN_COMPOUND_QUERY_PROGRAM_HEADER,
+ SCPI_TOKEN_COMMON_QUERY_PROGRAM_HEADER,
+ SCPI_TOKEN_WS,
+ SCPI_TOKEN_ALL_PROGRAM_DATA,
+ SCPI_TOKEN_INVALID,
+ SCPI_TOKEN_UNKNOWN,
+ };
+ typedef enum _scpi_token_type_t scpi_token_type_t;
+
+ struct _scpi_token_t {
+ scpi_token_type_t type;
+ char * ptr;
+ int len;
+ };
+ typedef struct _scpi_token_t scpi_token_t;
+
+ struct _lex_state_t {
+ char * buffer;
+ char * pos;
+ int len;
+ };
+ typedef struct _lex_state_t lex_state_t;
+
+ /* scpi parser */
+ enum _message_termination_t {
+ SCPI_MESSAGE_TERMINATION_NONE,
+ SCPI_MESSAGE_TERMINATION_NL,
+ SCPI_MESSAGE_TERMINATION_SEMICOLON,
+ };
+ typedef enum _message_termination_t message_termination_t;
+
+ struct _scpi_parser_state_t {
+ scpi_token_t programHeader;
+ scpi_token_t programData;
+ int numberOfParameters;
+ message_termination_t termination;
+ };
+ typedef struct _scpi_parser_state_t scpi_parser_state_t;
+
+ typedef scpi_result_t(*scpi_command_callback_t)(scpi_t *);
+
+ struct _scpi_error_info_heap_t {
+ size_t wr;
+ /* size_t rd; */
+ size_t count;
+ size_t size;
+ char * data;
+ };
+ typedef struct _scpi_error_info_heap_t scpi_error_info_heap_t;
+
+ struct _scpi_error_t {
+ int16_t error_code;
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+ char * device_dependent_info;
+#endif
+ };
+ typedef struct _scpi_error_t scpi_error_t;
+
+ struct _scpi_fifo_t {
+ int16_t wr;
+ int16_t rd;
+ int16_t count;
+ int16_t size;
+ scpi_error_t * data;
+ };
+ typedef struct _scpi_fifo_t scpi_fifo_t;
+
+ /* scpi units */
+ enum _scpi_unit_t {
+ SCPI_UNIT_NONE,
+ SCPI_UNIT_VOLT,
+ SCPI_UNIT_AMPER,
+ SCPI_UNIT_OHM,
+ SCPI_UNIT_HERTZ,
+ SCPI_UNIT_CELSIUS,
+ SCPI_UNIT_SECOND,
+ SCPI_UNIT_METER,
+ SCPI_UNIT_GRAY,
+ SCPI_UNIT_BECQUEREL,
+ SCPI_UNIT_MOLE,
+ SCPI_UNIT_DEGREE,
+ SCPI_UNIT_GRADE,
+ SCPI_UNIT_RADIAN,
+ SCPI_UNIT_REVOLUTION,
+ SCPI_UNIT_STERADIAN,
+ SCPI_UNIT_SIEVERT,
+ SCPI_UNIT_FARAD,
+ SCPI_UNIT_COULOMB,
+ SCPI_UNIT_SIEMENS,
+ SCPI_UNIT_ELECTRONVOLT,
+ SCPI_UNIT_JOULE,
+ SCPI_UNIT_NEWTON,
+ SCPI_UNIT_LUX,
+ SCPI_UNIT_HENRY,
+ SCPI_UNIT_ASTRONOMIC_UNIT,
+ SCPI_UNIT_INCH,
+ SCPI_UNIT_FOOT,
+ SCPI_UNIT_PARSEC,
+ SCPI_UNIT_MILE,
+ SCPI_UNIT_NAUTICAL_MILE,
+ SCPI_UNIT_LUMEN,
+ SCPI_UNIT_CANDELA,
+ SCPI_UNIT_WEBER,
+ SCPI_UNIT_TESLA,
+ SCPI_UNIT_ATOMIC_MASS,
+ SCPI_UNIT_KILOGRAM,
+ SCPI_UNIT_WATT,
+ SCPI_UNIT_DBM,
+ SCPI_UNIT_ATMOSPHERE,
+ SCPI_UNIT_INCH_OF_MERCURY,
+ SCPI_UNIT_MM_OF_MERCURY,
+ SCPI_UNIT_PASCAL,
+ SCPI_UNIT_TORT,
+ SCPI_UNIT_BAR,
+ SCPI_UNIT_DECIBEL,
+ SCPI_UNIT_UNITLESS,
+ SCPI_UNIT_FAHRENHEIT,
+ SCPI_UNIT_KELVIN,
+ SCPI_UNIT_DAY,
+ SCPI_UNIT_YEAR,
+ SCPI_UNIT_STROKES,
+ SCPI_UNIT_POISE,
+ SCPI_UNIT_LITER
+ };
+ typedef enum _scpi_unit_t scpi_unit_t;
+
+ struct _scpi_unit_def_t {
+ const char * name;
+ scpi_unit_t unit;
+ double mult;
+ };
+#define SCPI_UNITS_LIST_END {NULL, SCPI_UNIT_NONE, 0}
+ typedef struct _scpi_unit_def_t scpi_unit_def_t;
+
+ enum _scpi_special_number_t {
+ SCPI_NUM_NUMBER,
+ SCPI_NUM_MIN,
+ SCPI_NUM_MAX,
+ SCPI_NUM_DEF,
+ SCPI_NUM_UP,
+ SCPI_NUM_DOWN,
+ SCPI_NUM_NAN,
+ SCPI_NUM_INF,
+ SCPI_NUM_NINF,
+ SCPI_NUM_AUTO
+ };
+ typedef enum _scpi_special_number_t scpi_special_number_t;
+
+ struct _scpi_choice_def_t {
+ const char * name;
+ int32_t tag;
+ };
+#define SCPI_CHOICE_LIST_END {NULL, -1}
+ typedef struct _scpi_choice_def_t scpi_choice_def_t;
+
+ struct _scpi_param_list_t {
+ const scpi_command_t * cmd;
+ lex_state_t lex_state;
+ scpi_const_buffer_t cmd_raw;
+ };
+ typedef struct _scpi_param_list_t scpi_param_list_t;
+
+ struct _scpi_number_parameter_t {
+ scpi_bool_t special;
+
+ union {
+ double value;
+ int32_t tag;
+ } content;
+ scpi_unit_t unit;
+ int8_t base;
+ };
+ typedef struct _scpi_number_parameter_t scpi_number_t;
+
+ struct _scpi_data_parameter_t {
+ const char * ptr;
+ int32_t len;
+ };
+ typedef struct _scpi_data_parameter_t scpi_data_parameter_t;
+
+ typedef scpi_token_t scpi_parameter_t;
+
+ struct _scpi_command_t {
+ const char * pattern;
+ scpi_command_callback_t callback;
+#if USE_COMMAND_TAGS
+ int32_t tag;
+#endif /* USE_COMMAND_TAGS */
+ };
+
+ struct _scpi_interface_t {
+ scpi_error_callback_t error;
+ scpi_write_t write;
+ scpi_write_control_t control;
+ scpi_command_callback_t flush;
+ scpi_command_callback_t reset;
+ };
+
+ struct _scpi_t {
+ const scpi_command_t * cmdlist;
+ scpi_buffer_t buffer;
+ scpi_param_list_t param_list;
+ scpi_interface_t * interface;
+ int_fast16_t output_count;
+ int_fast16_t input_count;
+ scpi_bool_t first_output;
+ scpi_bool_t cmd_error;
+ scpi_fifo_t error_queue;
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+ scpi_error_info_heap_t error_info_heap;
+#endif
+ scpi_reg_val_t registers[SCPI_REG_COUNT];
+ const scpi_unit_def_t * units;
+ void * user_context;
+ scpi_parser_state_t parser_state;
+ const char * idn[4];
+ size_t arbitrary_remaining;
+ };
+
+ enum _scpi_array_format_t {
+ SCPI_FORMAT_ASCII = 0,
+ SCPI_FORMAT_NORMAL = 1,
+ SCPI_FORMAT_SWAPPED = 2,
+ SCPI_FORMAT_BIGENDIAN = SCPI_FORMAT_NORMAL,
+ SCPI_FORMAT_LITTLEENDIAN = SCPI_FORMAT_SWAPPED,
+ };
+ typedef enum _scpi_array_format_t scpi_array_format_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_TYPES_H */
+
diff --git a/third_party/libscpi/inc/scpi/units.h b/third_party/libscpi/inc/scpi/units.h
new file mode 100644
index 00000000..345e9fa4
--- /dev/null
+++ b/third_party/libscpi/inc/scpi/units.h
@@ -0,0 +1,60 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_units.h
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief SCPI Units
+ *
+ *
+ */
+
+#ifndef SCPI_UNITS_H
+#define SCPI_UNITS_H
+
+#include "scpi/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern const scpi_unit_def_t scpi_units_def[];
+ extern const scpi_choice_def_t scpi_special_numbers_def[];
+
+ scpi_bool_t SCPI_ParamNumber(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, scpi_bool_t mandatory);
+
+ scpi_bool_t SCPI_ParamTranslateNumberVal(scpi_t * context, scpi_parameter_t * parameter);
+ size_t SCPI_NumberToStr(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, char * str, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_UNITS_H */
+
diff --git a/third_party/libscpi/inc/scpi/utils.h b/third_party/libscpi/inc/scpi/utils.h
new file mode 100644
index 00000000..055e4683
--- /dev/null
+++ b/third_party/libscpi/inc/scpi/utils.h
@@ -0,0 +1,62 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file utils.h
+ *
+ * @brief Conversion routines and string manipulation routines
+ *
+ *
+ */
+
+#ifndef SCPI_UTILS_H
+#define SCPI_UTILS_H
+
+#include <stdint.h>
+#include "scpi/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ size_t SCPI_UInt32ToStrBase(uint32_t val, char * str, size_t len, int8_t base);
+ size_t SCPI_Int32ToStr(int32_t val, char * str, size_t len);
+ size_t SCPI_UInt64ToStrBase(uint64_t val, char * str, size_t len, int8_t base);
+ size_t SCPI_Int64ToStr(int64_t val, char * str, size_t len);
+ size_t SCPI_FloatToStr(float val, char * str, size_t len);
+ size_t SCPI_DoubleToStr(double val, char * str, size_t len);
+
+ /* deprecated finction, should be removed later */
+#define SCPI_LongToStr(val, str, len, base) SCPI_Int32ToStr((val), (str), (len), (base), TRUE)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_UTILS_H */
+
diff --git a/third_party/libscpi/src/error.c b/third_party/libscpi/src/error.c
new file mode 100644
index 00000000..88071406
--- /dev/null
+++ b/third_party/libscpi/src/error.c
@@ -0,0 +1,237 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @file scpi_error.c
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief Error handling and storing routines
+ *
+ *
+ */
+
+#include <stdint.h>
+
+#include "scpi/parser.h"
+#include "scpi/ieee488.h"
+#include "scpi/error.h"
+#include "fifo_private.h"
+#include "scpi/constants.h"
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+#define SCPI_ERROR_SETVAL(e, c, i) do { (e)->error_code = (c); (e)->device_dependent_info = (i); } while(0)
+#else
+#define SCPI_ERROR_SETVAL(e, c, i) do { (e)->error_code = (c); (void)(i);} while(0)
+#endif
+
+/**
+ * Initialize error queue
+ * @param context - scpi context
+ */
+void SCPI_ErrorInit(scpi_t * context, scpi_error_t * data, int16_t size) {
+ fifo_init(&context->error_queue, data, size);
+}
+
+/**
+ * Emit no error
+ * @param context scpi context
+ */
+static void SCPI_ErrorEmitEmpty(scpi_t * context) {
+ if ((SCPI_ErrorCount(context) == 0) && (SCPI_RegGet(context, SCPI_REG_STB) & STB_QMA)) {
+ SCPI_RegClearBits(context, SCPI_REG_STB, STB_QMA);
+
+ if (context->interface && context->interface->error) {
+ context->interface->error(context, 0);
+ }
+ }
+}
+
+/**
+ * Emit error
+ * @param context scpi context
+ * @param err Error to emit
+ */
+static void SCPI_ErrorEmit(scpi_t * context, int16_t err) {
+ SCPI_RegSetBits(context, SCPI_REG_STB, STB_QMA);
+
+ if (context->interface && context->interface->error) {
+ context->interface->error(context, err);
+ }
+}
+
+/**
+ * Clear error queue
+ * @param context - scpi context
+ */
+void SCPI_ErrorClear(scpi_t * context) {
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+ scpi_error_t error;
+ while (fifo_remove(&context->error_queue, &error)) {
+ SCPIDEFINE_free(&context->error_info_heap, error.device_dependent_info, false);
+ }
+#endif
+ fifo_clear(&context->error_queue);
+
+ SCPI_ErrorEmitEmpty(context);
+}
+
+/**
+ * Pop error from queue
+ * @param context - scpi context
+ * @param error
+ * @return
+ */
+scpi_bool_t SCPI_ErrorPop(scpi_t * context, scpi_error_t * error) {
+ if (!error || !context) return FALSE;
+ SCPI_ERROR_SETVAL(error, 0, NULL);
+ fifo_remove(&context->error_queue, error);
+
+ SCPI_ErrorEmitEmpty(context);
+
+ return TRUE;
+}
+
+/**
+ * Return number of errors/events in the queue
+ * @param context
+ * @return
+ */
+int32_t SCPI_ErrorCount(scpi_t * context) {
+ int16_t result = 0;
+
+ fifo_count(&context->error_queue, &result);
+
+ return result;
+}
+
+static scpi_bool_t SCPI_ErrorAddInternal(scpi_t * context, int16_t err, char * info, size_t info_len) {
+ scpi_error_t error_value;
+ /* SCPIDEFINE_strndup is sometimes a dumy that does not reference it's arguments.
+ Since info_len is not referenced elsewhere caoing to void prevents unusd argument warnings */
+ (void) info_len;
+ char * info_ptr = NULL;
+ if (info) {
+ info_ptr = SCPIDEFINE_strndup(&context->error_info_heap, info, info_len);
+ }
+ SCPI_ERROR_SETVAL(&error_value, err, info_ptr);
+ if (!fifo_add(&context->error_queue, &error_value)) {
+ SCPIDEFINE_free(&context->error_info_heap, error_value.device_dependent_info, true);
+ fifo_remove_last(&context->error_queue, &error_value);
+ SCPIDEFINE_free(&context->error_info_heap, error_value.device_dependent_info, true);
+ SCPI_ERROR_SETVAL(&error_value, SCPI_ERROR_QUEUE_OVERFLOW, NULL);
+ fifo_add(&context->error_queue, &error_value);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+struct error_reg {
+ int16_t from;
+ int16_t to;
+ scpi_reg_val_t esrBit;
+};
+
+#define ERROR_DEFS_N 9
+
+static const struct error_reg errs[ERROR_DEFS_N] = {
+ {-100, -199, ESR_CER}, /* Command error (e.g. syntax error) ch 21.8.9 */
+ {-200, -299, ESR_EER}, /* Execution Error (e.g. range error) ch 21.8.10 */
+ {-300, -399, ESR_DER}, /* Device specific error -300, -399 ch 21.8.11 */
+ { 1, 32767, ESR_DER}, /* Device designer provided specific error 1, 32767 ch 21.8.11 */
+ {-400, -499, ESR_QER}, /* Query error -400, -499 ch 21.8.12 */
+ {-500, -599, ESR_PON}, /* Power on event -500, -599 ch 21.8.13 */
+ {-600, -699, ESR_URQ}, /* User Request Event -600, -699 ch 21.8.14 */
+ {-700, -799, ESR_REQ}, /* Request Control Event -700, -799 ch 21.8.15 */
+ {-800, -899, ESR_OPC}, /* Operation Complete Event -800, -899 ch 21.8.16 */
+};
+
+/**
+ * Push error to queue
+ * @param context
+ * @param err - error number
+ * @param info - additional text information or NULL for no text
+ * @param info_len - length of text or 0 for automatic length
+ */
+void SCPI_ErrorPushEx(scpi_t * context, int16_t err, char * info, size_t info_len) {
+ int i;
+ /* automatic calculation of length */
+ if (info && info_len == 0) {
+ info_len = SCPIDEFINE_strnlen(info, SCPI_STD_ERROR_DESC_MAX_STRING_LENGTH);
+ }
+ scpi_bool_t queue_overflow = !SCPI_ErrorAddInternal(context, err, info, info_len);
+
+ for (i = 0; i < ERROR_DEFS_N; i++) {
+ if ((err <= errs[i].from) && (err >= errs[i].to)) {
+ SCPI_RegSetBits(context, SCPI_REG_ESR, errs[i].esrBit);
+ }
+ }
+
+ SCPI_ErrorEmit(context, err);
+ if (queue_overflow) {
+ SCPI_ErrorEmit(context, SCPI_ERROR_QUEUE_OVERFLOW);
+ }
+
+ if (context) {
+ context->cmd_error = TRUE;
+ }
+}
+
+/**
+ * Push error to queue
+ * @param context - scpi context
+ * @param err - error number
+ */
+void SCPI_ErrorPush(scpi_t * context, int16_t err) {
+ SCPI_ErrorPushEx(context, err, NULL, 0);
+ return;
+}
+
+/**
+ * Translate error number to string
+ * @param err - error number
+ * @return Error string representation
+ */
+const char * SCPI_ErrorTranslate(int16_t err) {
+ switch (err) {
+#define X(def, val, str) case def: return str;
+#if USE_FULL_ERROR_LIST
+#define XE X
+#else
+#define XE(def, val, str)
+#endif
+ LIST_OF_ERRORS
+
+#if USE_USER_ERROR_LIST
+ LIST_OF_USER_ERRORS
+#endif
+#undef X
+#undef XE
+ default: return "Unknown error";
+ }
+}
+
+
diff --git a/third_party/libscpi/src/expression.c b/third_party/libscpi/src/expression.c
new file mode 100644
index 00000000..27a38dd5
--- /dev/null
+++ b/third_party/libscpi/src/expression.c
@@ -0,0 +1,316 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file expression.c
+ *
+ * @brief Expressions handling
+ *
+ *
+ */
+
+#include "scpi/expression.h"
+#include "scpi/error.h"
+#include "scpi/parser.h"
+
+#include "lexer_private.h"
+
+/**
+ * Parse one range or single value
+ * @param state lexer state
+ * @param isRange return true if parsed expression is range
+ * @param valueFrom return parsed value from
+ * @param valueTo return parsed value to
+ * @return SCPI_EXPR_OK - parsing was succesful
+ * SCPI_EXPR_ERROR - parser error
+ * SCPI_EXPR_NO_MORE - no more data
+ */
+static scpi_expr_result_t numericRange(lex_state_t * state, scpi_bool_t * isRange, scpi_token_t * valueFrom, scpi_token_t * valueTo) {
+ if (scpiLex_DecimalNumericProgramData(state, valueFrom)) {
+ if (scpiLex_Colon(state, valueTo)) {
+ *isRange = TRUE;
+ if (scpiLex_DecimalNumericProgramData(state, valueTo)) {
+ return SCPI_EXPR_OK;
+ } else {
+ return SCPI_EXPR_ERROR;
+ }
+ } else {
+ *isRange = FALSE;
+ return SCPI_EXPR_OK;
+ }
+ }
+
+ return SCPI_EXPR_NO_MORE;
+}
+
+/**
+ * Parse entry on specified position
+ * @param context scpi context
+ * @param param input parameter
+ * @param index index of position (start from 0)
+ * @param isRange return true if expression at index was range
+ * @param valueFrom return value from
+ * @param valueTo return value to
+ * @return SCPI_EXPR_OK - parsing was succesful
+ * SCPI_EXPR_ERROR - parser error
+ * SCPI_EXPR_NO_MORE - no more data
+ * @see SCPI_ExprNumericListEntryInt, SCPI_ExprNumericListEntryDouble
+ */
+scpi_expr_result_t SCPI_ExprNumericListEntry(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, scpi_parameter_t * valueFrom, scpi_parameter_t * valueTo) {
+ lex_state_t lex;
+ int i;
+ scpi_expr_result_t res = SCPI_EXPR_OK;
+
+ if (!isRange || !valueFrom || !valueTo || !param) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return SCPI_EXPR_ERROR;
+ }
+
+ if (param->type != SCPI_TOKEN_PROGRAM_EXPRESSION) {
+ SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+ return SCPI_EXPR_ERROR;
+ }
+
+ lex.buffer = param->ptr + 1;
+ lex.pos = lex.buffer;
+ lex.len = param->len - 2;
+
+ for (i = 0; i <= index; i++) {
+ res = numericRange(&lex, isRange, valueFrom, valueTo);
+ if (res != SCPI_EXPR_OK) {
+ break;
+ }
+ if (i != index) {
+ if (!scpiLex_Comma(&lex, valueFrom)) {
+ res = scpiLex_IsEos(&lex) ? SCPI_EXPR_NO_MORE : SCPI_EXPR_ERROR;
+ break;
+ }
+ }
+ }
+
+ if (res == SCPI_EXPR_ERROR) {
+ SCPI_ErrorPush(context, SCPI_ERROR_EXPRESSION_PARSING_ERROR);
+ }
+ return res;
+}
+
+/**
+ * Parse entry on specified position and convert result to int32_t
+ * @param context scpi context
+ * @param param input parameter
+ * @param index index of position (start from 0)
+ * @param isRange return true if expression at index was range
+ * @param valueFrom return value from
+ * @param valueTo return value to
+ * @return SCPI_EXPR_OK - parsing was succesful
+ * SCPI_EXPR_ERROR - parser error
+ * SCPI_EXPR_NO_MORE - no more data
+ * @see SCPI_ExprNumericListEntry, SCPI_ExprNumericListEntryDouble
+ */
+scpi_expr_result_t SCPI_ExprNumericListEntryInt(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, int32_t * valueFrom, int32_t * valueTo) {
+ scpi_expr_result_t res;
+ scpi_bool_t range = FALSE;
+ scpi_parameter_t paramFrom;
+ scpi_parameter_t paramTo;
+
+ res = SCPI_ExprNumericListEntry(context, param, index, &range, &paramFrom, &paramTo);
+ if (res == SCPI_EXPR_OK) {
+ *isRange = range;
+ SCPI_ParamToInt32(context, &paramFrom, valueFrom);
+ if (range) {
+ SCPI_ParamToInt32(context, &paramTo, valueTo);
+ }
+ }
+
+ return res;
+}
+
+/**
+ * Parse entry on specified position and convert result to double
+ * @param context scpi context
+ * @param param input parameter
+ * @param index index of position (start from 0)
+ * @param isRange return true if expression at index was range
+ * @param valueFrom return value from
+ * @param valueTo return value to
+ * @return SCPI_EXPR_OK - parsing was succesful
+ * SCPI_EXPR_ERROR - parser error
+ * SCPI_EXPR_NO_MORE - no more data
+ * @see SCPI_ExprNumericListEntry, SCPI_ExprNumericListEntryInt
+ */
+scpi_expr_result_t SCPI_ExprNumericListEntryDouble(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, double * valueFrom, double * valueTo) {
+ scpi_expr_result_t res;
+ scpi_bool_t range = FALSE;
+ scpi_parameter_t paramFrom;
+ scpi_parameter_t paramTo;
+
+ res = SCPI_ExprNumericListEntry(context, param, index, &range, &paramFrom, &paramTo);
+ if (res == SCPI_EXPR_OK) {
+ *isRange = range;
+ SCPI_ParamToDouble(context, &paramFrom, valueFrom);
+ if (range) {
+ SCPI_ParamToDouble(context, &paramTo, valueTo);
+ }
+ }
+
+ return res;
+}
+
+/**
+ * Parse one channel_spec e.g. "1!5!8"
+ * @param context
+ * @param state lexer state
+ * @param values range values
+ * @param length length of values array
+ * @param dimensions real number of dimensions
+ */
+static scpi_expr_result_t channelSpec(scpi_t * context, lex_state_t * state, int32_t * values, size_t length, size_t * dimensions) {
+ scpi_parameter_t param;
+ size_t i = 0;
+ while (scpiLex_DecimalNumericProgramData(state, &param)) {
+ if (i < length) {
+ SCPI_ParamToInt32(context, &param, &values[i]);
+ }
+
+ if (scpiLex_SpecificCharacter(state, &param, '!')) {
+ i++;
+ } else {
+ *dimensions = i + 1;
+ return SCPI_EXPR_OK;
+ }
+ }
+
+ if (i == 0) {
+ return SCPI_EXPR_NO_MORE;
+ } else {
+ /* there was at least one number followed by !, but after ! was not another number */
+ return SCPI_EXPR_ERROR;
+ }
+}
+
+/**
+ * Parse channel_range e.g. "1!2:5!6"
+ * @param context
+ * @param state lexer state
+ * @param isRange return true if it is range
+ * @param valuesFrom return array of values from
+ * @param valuesTo return array of values to
+ * @param length length of values arrays
+ * @param dimensions real number of dimensions
+ */
+static scpi_expr_result_t channelRange(scpi_t * context, lex_state_t * state, scpi_bool_t * isRange, int32_t * valuesFrom, int32_t * valuesTo, size_t length, size_t * dimensions) {
+ scpi_token_t token;
+ scpi_expr_result_t err;
+ size_t fromDimensions;
+ size_t toDimensions;
+
+ err = channelSpec(context, state, valuesFrom, length, &fromDimensions);
+ if (err == SCPI_EXPR_OK) {
+ if (scpiLex_Colon(state, &token)) {
+ *isRange = TRUE;
+ err = channelSpec(context, state, valuesTo, length, &toDimensions);
+ if (err != SCPI_EXPR_OK) {
+ return SCPI_EXPR_ERROR;
+ }
+ if (fromDimensions != toDimensions) {
+ return SCPI_EXPR_ERROR;
+ }
+ *dimensions = fromDimensions;
+ } else {
+ *isRange = FALSE;
+ *dimensions = fromDimensions;
+ return SCPI_EXPR_OK;
+ }
+ } else if (err == SCPI_EXPR_NO_MORE) {
+ err = SCPI_EXPR_ERROR;
+ }
+
+ return err;
+}
+
+/**
+ * Parse one list entry at specific position e.g. "1!2:5!6"
+ * @param context
+ * @param param
+ * @param index
+ * @param isRange return true if it is range
+ * @param valuesFrom return array of values from
+ * @param valuesTo return array of values to
+ * @param length length of values arrays
+ * @param dimensions real number of dimensions
+ */
+scpi_expr_result_t SCPI_ExprChannelListEntry(scpi_t * context, scpi_parameter_t * param, int index, scpi_bool_t * isRange, int32_t * valuesFrom, int32_t * valuesTo, size_t length, size_t * dimensions) {
+ lex_state_t lex;
+ int i;
+ scpi_expr_result_t res = SCPI_EXPR_OK;
+ scpi_token_t token;
+
+ if (!isRange || !param || !dimensions || (length && (!valuesFrom || !valuesTo))) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return SCPI_EXPR_ERROR;
+ }
+
+ if (param->type != SCPI_TOKEN_PROGRAM_EXPRESSION) {
+ SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+ return SCPI_EXPR_ERROR;
+ }
+
+ lex.buffer = param->ptr + 1;
+ lex.pos = lex.buffer;
+ lex.len = param->len - 2;
+
+ /* detect channel list expression */
+ if (!scpiLex_SpecificCharacter(&lex, &token, '@')) {
+ SCPI_ErrorPush(context, SCPI_ERROR_EXPRESSION_PARSING_ERROR);
+ return SCPI_EXPR_ERROR;
+ }
+
+ for (i = 0; i <= index; i++) {
+ res = channelRange(context, &lex, isRange, valuesFrom, valuesTo, (i == index) ? length : 0, dimensions);
+ if (res != SCPI_EXPR_OK) {
+ break;
+ }
+ if (i != index) {
+ if (!scpiLex_Comma(&lex, &token)) {
+ res = scpiLex_IsEos(&lex) ? SCPI_EXPR_NO_MORE : SCPI_EXPR_ERROR;
+ break;
+ }
+ }
+ }
+
+ if (res == SCPI_EXPR_ERROR) {
+ SCPI_ErrorPush(context, SCPI_ERROR_EXPRESSION_PARSING_ERROR);
+ }
+ if (res == SCPI_EXPR_NO_MORE) {
+ if (!scpiLex_IsEos(&lex)) {
+ res = SCPI_EXPR_ERROR;
+ SCPI_ErrorPush(context, SCPI_ERROR_EXPRESSION_PARSING_ERROR);
+ }
+ }
+ return res;
+}
diff --git a/third_party/libscpi/src/fifo.c b/third_party/libscpi/src/fifo.c
new file mode 100644
index 00000000..8cecc4e2
--- /dev/null
+++ b/third_party/libscpi/src/fifo.c
@@ -0,0 +1,146 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fifo_private.h"
+
+/**
+ * Initialize fifo
+ * @param fifo
+ */
+void fifo_init(scpi_fifo_t * fifo, scpi_error_t * data, int16_t size) {
+ fifo->wr = 0;
+ fifo->rd = 0;
+ fifo->count = 0;
+ fifo->data = data;
+ fifo->size = size;
+}
+
+/**
+ * Empty fifo
+ * @param fifo
+ */
+void fifo_clear(scpi_fifo_t * fifo) {
+ fifo->wr = 0;
+ fifo->rd = 0;
+ fifo->count = 0;
+}
+
+/**
+ * Test if fifo is empty
+ * @param fifo
+ * @return
+ */
+scpi_bool_t fifo_is_empty(scpi_fifo_t * fifo) {
+ return fifo->count == 0;
+}
+
+/**
+ * Test if fifo is full
+ * @param fifo
+ * @return
+ */
+scpi_bool_t fifo_is_full(scpi_fifo_t * fifo) {
+ return fifo->count == fifo->size;
+}
+
+/**
+ * Add element to fifo. If fifo is full, return FALSE.
+ * @param fifo
+ * @param err
+ * @param info
+ * @return
+ */
+scpi_bool_t fifo_add(scpi_fifo_t * fifo, const scpi_error_t * value) {
+ /* FIFO full? */
+ if (fifo_is_full(fifo)) {
+ return FALSE;
+ }
+ if (!value) {
+ return FALSE;
+ }
+
+ fifo->data[fifo->wr] = *value;
+ fifo->wr = (fifo->wr + 1) % (fifo->size);
+ fifo->count += 1;
+ return TRUE;
+}
+
+/**
+ * Remove element form fifo
+ * @param fifo
+ * @param value
+ * @return FALSE - fifo is empty
+ */
+scpi_bool_t fifo_remove(scpi_fifo_t * fifo, scpi_error_t * value) {
+ /* FIFO empty? */
+ if (fifo_is_empty(fifo)) {
+ return FALSE;
+ }
+
+ if (value) {
+ *value = fifo->data[fifo->rd];
+ }
+
+ fifo->rd = (fifo->rd + 1) % (fifo->size);
+ fifo->count -= 1;
+
+ return TRUE;
+}
+
+/**
+ * Remove last element from fifo
+ * @param fifo
+ * @param value
+ * @return FALSE - fifo is empty
+ */
+scpi_bool_t fifo_remove_last(scpi_fifo_t * fifo, scpi_error_t * value) {
+ /* FIFO empty? */
+ if (fifo_is_empty(fifo)) {
+ return FALSE;
+ }
+
+ fifo->wr = (fifo->wr + fifo->size - 1) % (fifo->size);
+
+ if (value) {
+ *value = fifo->data[fifo->wr];
+ }
+ fifo->count -= 1;
+
+ return TRUE;
+}
+
+/**
+ * Retrive number of elements in fifo
+ * @param fifo
+ * @param value
+ * @return
+ */
+scpi_bool_t fifo_count(scpi_fifo_t * fifo, int16_t * value) {
+ *value = fifo->count;
+ return TRUE;
+}
diff --git a/third_party/libscpi/src/fifo_private.h b/third_party/libscpi/src/fifo_private.h
new file mode 100644
index 00000000..8678763c
--- /dev/null
+++ b/third_party/libscpi/src/fifo_private.h
@@ -0,0 +1,61 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_fifo.h
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief basic FIFO implementation
+ *
+ *
+ */
+
+#ifndef SCPI_FIFO_H
+#define SCPI_FIFO_H
+
+#include "scpi/types.h"
+#include "utils_private.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void fifo_init(scpi_fifo_t * fifo, scpi_error_t * data, int16_t size) LOCAL;
+ void fifo_clear(scpi_fifo_t * fifo) LOCAL;
+ scpi_bool_t fifo_is_empty(scpi_fifo_t * fifo) LOCAL;
+ scpi_bool_t fifo_is_full(scpi_fifo_t * fifo) LOCAL;
+ scpi_bool_t fifo_add(scpi_fifo_t * fifo, const scpi_error_t * value) LOCAL;
+ scpi_bool_t fifo_remove(scpi_fifo_t * fifo, scpi_error_t * value) LOCAL;
+ scpi_bool_t fifo_remove_last(scpi_fifo_t * fifo, scpi_error_t * value) LOCAL;
+ scpi_bool_t fifo_count(scpi_fifo_t * fifo, int16_t * value) LOCAL;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_FIFO_H */
diff --git a/third_party/libscpi/src/ieee488.c b/third_party/libscpi/src/ieee488.c
new file mode 100644
index 00000000..c5f26653
--- /dev/null
+++ b/third_party/libscpi/src/ieee488.c
@@ -0,0 +1,424 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_ieee488.c
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief Implementation of IEEE488.2 commands and state model
+ *
+ *
+ */
+
+#include "scpi/parser.h"
+#include "scpi/ieee488.h"
+#include "scpi/error.h"
+#include "scpi/constants.h"
+
+#include <stdio.h>
+
+static const scpi_reg_info_t scpi_reg_details[SCPI_REG_COUNT] = {
+ { SCPI_REG_CLASS_STB, SCPI_REG_GROUP_STB },
+ { SCPI_REG_CLASS_SRE, SCPI_REG_GROUP_STB },
+ { SCPI_REG_CLASS_EVEN, SCPI_REG_GROUP_ESR },
+ { SCPI_REG_CLASS_ENAB, SCPI_REG_GROUP_ESR },
+ { SCPI_REG_CLASS_EVEN, SCPI_REG_GROUP_OPER },
+ { SCPI_REG_CLASS_ENAB, SCPI_REG_GROUP_OPER },
+ { SCPI_REG_CLASS_COND, SCPI_REG_GROUP_OPER },
+ { SCPI_REG_CLASS_EVEN, SCPI_REG_GROUP_QUES },
+ { SCPI_REG_CLASS_ENAB, SCPI_REG_GROUP_QUES },
+ { SCPI_REG_CLASS_COND, SCPI_REG_GROUP_QUES },
+
+#if USE_CUSTOM_REGISTERS
+#ifndef USER_REGISTER_DETAILS
+#error "No user register details defined"
+#else
+ USER_REGISTER_DETAILS
+#endif
+#endif
+
+};
+
+static const scpi_reg_group_info_t scpi_reg_group_details[SCPI_REG_GROUP_COUNT] = {
+ {
+ SCPI_REG_STB,
+ SCPI_REG_SRE,
+ SCPI_REG_NONE,
+ SCPI_REG_NONE,
+ SCPI_REG_NONE,
+ SCPI_REG_NONE,
+ 0
+ }, /* SCPI_REG_GROUP_STB */
+ {
+ SCPI_REG_ESR,
+ SCPI_REG_ESE,
+ SCPI_REG_NONE,
+ SCPI_REG_NONE,
+ SCPI_REG_NONE,
+ SCPI_REG_STB,
+ STB_ESR
+ }, /* SCPI_REG_GROUP_ESR */
+ {
+ SCPI_REG_OPER,
+ SCPI_REG_OPERE,
+ SCPI_REG_OPERC,
+ SCPI_REG_NONE,
+ SCPI_REG_NONE,
+ SCPI_REG_STB,
+ STB_OPS
+ }, /* SCPI_REG_GROUP_OPER */
+ {
+ SCPI_REG_QUES,
+ SCPI_REG_QUESE,
+ SCPI_REG_QUESC,
+ SCPI_REG_NONE,
+ SCPI_REG_NONE,
+ SCPI_REG_STB,
+ STB_QES
+ }, /* SCPI_REG_GROUP_QUES */
+
+#if USE_CUSTOM_REGISTERS
+#ifndef USER_REGISTER_GROUP_DETAILS
+#error "No user register group details defined"
+#else
+ USER_REGISTER_GROUP_DETAILS
+#endif
+#endif
+
+};
+
+/**
+ * Get register value
+ * @param name - register name
+ * @return register value
+ */
+scpi_reg_val_t SCPI_RegGet(scpi_t * context, scpi_reg_name_t name) {
+ if ((name < SCPI_REG_COUNT) && context) {
+ return context->registers[name];
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Wrapper function to control interface from context
+ * @param context
+ * @param ctrl number of controll message
+ * @param value value of related register
+ */
+static size_t writeControl(scpi_t * context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val) {
+ if (context && context->interface && context->interface->control) {
+ return context->interface->control(context, ctrl, val);
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Set register value
+ * @param name - register name
+ * @param val - new value
+ */
+void SCPI_RegSet(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t val) {
+ if ((name >= SCPI_REG_COUNT) || (context == NULL)) {
+ return;
+ }
+
+ scpi_reg_group_info_t register_group;
+
+ do {
+ scpi_reg_class_t register_type = scpi_reg_details[name].type;
+ register_group = scpi_reg_group_details[scpi_reg_details[name].group];
+
+ scpi_reg_val_t ptrans;
+
+ /* store old register value */
+ scpi_reg_val_t old_val = context->registers[name];
+
+ if (old_val == val) {
+ return;
+ } else {
+ context->registers[name] = val;
+ }
+
+ switch (register_type) {
+ case SCPI_REG_CLASS_STB:
+ case SCPI_REG_CLASS_SRE:
+ {
+ scpi_reg_val_t stb = context->registers[SCPI_REG_STB] & ~STB_SRQ;
+ scpi_reg_val_t sre = context->registers[SCPI_REG_SRE] & ~STB_SRQ;
+
+ if (stb & sre) {
+ ptrans = ((old_val ^ val) & val);
+ context->registers[SCPI_REG_STB] |= STB_SRQ;
+ if (ptrans & val) {
+ writeControl(context, SCPI_CTRL_SRQ, context->registers[SCPI_REG_STB]);
+ }
+ } else {
+ context->registers[SCPI_REG_STB] &= ~STB_SRQ;
+ }
+ break;
+ }
+ case SCPI_REG_CLASS_EVEN:
+ {
+ scpi_reg_val_t enable;
+ if(register_group.enable != SCPI_REG_NONE) {
+ enable = SCPI_RegGet(context, register_group.enable);
+ } else {
+ enable = 0xFFFF;
+ }
+
+ scpi_bool_t summary = val & enable;
+
+ name = register_group.parent_reg;
+ val = SCPI_RegGet(context, register_group.parent_reg);
+ if (summary) {
+ val |= register_group.parent_bit;
+ } else {
+ val &= ~(register_group.parent_bit);
+ }
+ break;
+ }
+ case SCPI_REG_CLASS_COND:
+ {
+ name = register_group.event;
+
+ if(register_group.ptfilt == SCPI_REG_NONE && register_group.ntfilt == SCPI_REG_NONE) {
+ val = ((old_val ^ val) & val) | SCPI_RegGet(context, register_group.event);
+ } else {
+ scpi_reg_val_t ptfilt = 0, ntfilt = 0;
+ scpi_reg_val_t transitions;
+ scpi_reg_val_t ntrans;
+
+ if(register_group.ptfilt != SCPI_REG_NONE) {
+ ptfilt = SCPI_RegGet(context, register_group.ptfilt);
+ }
+
+ if(register_group.ntfilt != SCPI_REG_NONE) {
+ ntfilt = SCPI_RegGet(context, register_group.ntfilt);
+ }
+
+ transitions = old_val ^ val;
+ ptrans = transitions & val;
+ ntrans = transitions & ~ptrans;
+
+ val = ((ptrans & ptfilt) | (ntrans & ntfilt)) | SCPI_RegGet(context, register_group.event);
+ }
+ break;
+ }
+ case SCPI_REG_CLASS_ENAB:
+ case SCPI_REG_CLASS_NTR:
+ case SCPI_REG_CLASS_PTR:
+ return;
+ }
+ } while(register_group.parent_reg != SCPI_REG_NONE);
+}
+
+/**
+ * Set register bits
+ * @param name - register name
+ * @param bits bit mask
+ */
+void SCPI_RegSetBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits) {
+ SCPI_RegSet(context, name, SCPI_RegGet(context, name) | bits);
+}
+
+/**
+ * Clear register bits
+ * @param name - register name
+ * @param bits bit mask
+ */
+void SCPI_RegClearBits(scpi_t * context, scpi_reg_name_t name, scpi_reg_val_t bits) {
+ SCPI_RegSet(context, name, SCPI_RegGet(context, name) & ~bits);
+}
+
+/**
+ * *CLS - This command clears all status data structures in a device.
+ * For a device which minimally complies with SCPI. (SCPI std 4.1.3.2)
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreCls(scpi_t * context) {
+ SCPI_ErrorClear(context);
+ int i;
+ for (i = 0; i < SCPI_REG_GROUP_COUNT; ++i) {
+ scpi_reg_name_t event_reg = scpi_reg_group_details[i].event;
+ if (event_reg != SCPI_REG_STB) {
+ SCPI_RegSet(context, event_reg, 0);
+ }
+ }
+ return SCPI_RES_OK;
+}
+
+/**
+ * *ESE
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreEse(scpi_t * context) {
+ int32_t new_ESE;
+ if (SCPI_ParamInt32(context, &new_ESE, TRUE)) {
+ SCPI_RegSet(context, SCPI_REG_ESE, (scpi_reg_val_t) new_ESE);
+ return SCPI_RES_OK;
+ }
+ return SCPI_RES_ERR;
+}
+
+/**
+ * *ESE?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreEseQ(scpi_t * context) {
+ SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_ESE));
+ return SCPI_RES_OK;
+}
+
+/**
+ * *ESR?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreEsrQ(scpi_t * context) {
+ SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_ESR));
+ SCPI_RegSet(context, SCPI_REG_ESR, 0);
+ return SCPI_RES_OK;
+}
+
+/**
+ * *IDN?
+ *
+ * field1: MANUFACTURE
+ * field2: MODEL
+ * field4: SUBSYSTEMS REVISIONS
+ *
+ * example: MANUFACTURE,MODEL,0,01-02-01
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreIdnQ(scpi_t * context) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ if (context->idn[i]) {
+ SCPI_ResultMnemonic(context, context->idn[i]);
+ } else {
+ SCPI_ResultMnemonic(context, "0");
+ }
+ }
+ return SCPI_RES_OK;
+}
+
+/**
+ * *OPC
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreOpc(scpi_t * context) {
+ SCPI_RegSetBits(context, SCPI_REG_ESR, ESR_OPC);
+ return SCPI_RES_OK;
+}
+
+/**
+ * *OPC?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreOpcQ(scpi_t * context) {
+ /* Operation is always completed */
+ SCPI_ResultInt32(context, 1);
+ return SCPI_RES_OK;
+}
+
+/**
+ * *RST
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreRst(scpi_t * context) {
+ if (context && context->interface && context->interface->reset) {
+ return context->interface->reset(context);
+ }
+ return SCPI_RES_OK;
+}
+
+/**
+ * *SRE
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreSre(scpi_t * context) {
+ int32_t new_SRE;
+ if (SCPI_ParamInt32(context, &new_SRE, TRUE)) {
+ SCPI_RegSet(context, SCPI_REG_SRE, (scpi_reg_val_t) new_SRE);
+ return SCPI_RES_OK;
+ }
+ return SCPI_RES_ERR;
+}
+
+/**
+ * *SRE?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreSreQ(scpi_t * context) {
+ SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_SRE));
+ return SCPI_RES_OK;
+}
+
+/**
+ * *STB?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreStbQ(scpi_t * context) {
+ SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_STB));
+ return SCPI_RES_OK;
+}
+
+/**
+ * *TST?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreTstQ(scpi_t * context) {
+ (void) context;
+ SCPI_ResultInt32(context, 0);
+ return SCPI_RES_OK;
+}
+
+/**
+ * *WAI
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_CoreWai(scpi_t * context) {
+ (void) context;
+ /* NOP */
+ return SCPI_RES_OK;
+}
+
diff --git a/third_party/libscpi/src/lexer.c b/third_party/libscpi/src/lexer.c
new file mode 100644
index 00000000..dad45a09
--- /dev/null
+++ b/third_party/libscpi/src/lexer.c
@@ -0,0 +1,935 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file lexer.c
+ * @date Wed Mar 20 19:35:19 UTC 2013
+ *
+ * @brief SCPI Lexer
+ *
+ *
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "lexer_private.h"
+#include "scpi/error.h"
+
+/**
+ * Is white space
+ * @param c
+ * @return
+ */
+static int isws(int c) {
+ if ((c == ' ') || (c == '\t')) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Is binary digit
+ * @param c
+ * @return
+ */
+static int isbdigit(int c) {
+ if ((c == '0') || (c == '1')) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Is hexadecimal digit
+ * @param c
+ * @return
+ */
+static int isqdigit(int c) {
+ if ((c == '0') || (c == '1') || (c == '2') || (c == '3') || (c == '4') || (c == '5') || (c == '6') || (c == '7')) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Is end of string
+ * @param state
+ * @return
+ */
+static int iseos(lex_state_t * state) {
+ if ((state->buffer + state->len) <= (state->pos)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Private export of iseos
+ * @param state
+ * @return
+ */
+int scpiLex_IsEos(lex_state_t * state) {
+ return iseos(state);
+}
+
+/**
+ * Test current character
+ * @param state
+ * @param chr
+ * @return
+ */
+static int ischr(lex_state_t * state, char chr) {
+ return (state->pos[0] == chr);
+}
+
+/**
+ * Is plus or minus
+ * @param c
+ * @return
+ */
+static int isplusmn(int c) {
+ return c == '+' || c == '-';
+}
+
+/**
+ * Is letter H
+ * @param c
+ * @return
+ */
+static int isH(int c) {
+ return c == 'h' || c == 'H';
+}
+
+/**
+ * Is letter B
+ * @param c
+ * @return
+ */
+static int isB(int c) {
+ return c == 'b' || c == 'B';
+}
+
+/**
+ * Is letter Q
+ * @param c
+ * @return
+ */
+static int isQ(int c) {
+ return c == 'q' || c == 'Q';
+}
+
+/**
+ * Is letter E
+ * @param c
+ * @return
+ */
+static int isE(int c) {
+ return c == 'e' || c == 'E';
+}
+
+#define SKIP_NONE 0
+#define SKIP_OK 1
+#define SKIP_INCOMPLETE -1
+
+/* skip characters */
+/* 7.4.1 <PROGRAM MESSAGE UNIT SEPARATOR>*/
+/* TODO: static int skipProgramMessageUnitSeparator(lex_state_t * state) */
+
+/**
+ * Skip all whitespaces
+ * @param state
+ * @return
+ */
+static int skipWs(lex_state_t * state) {
+ int someSpace = 0;
+ while (!iseos(state) && isws(state->pos[0])) {
+ state->pos++;
+ someSpace++;
+ }
+
+ return someSpace;
+}
+
+/* 7.4.2 <PROGRAM DATA SEPARATOR> */
+/* static int skipProgramDataSeparator(lex_state_t * state) */
+
+/* 7.5.2 <PROGRAM MESSAGE TERMINATOR> */
+/* static int skipProgramMessageTerminator(lex_state_t * state) */
+
+/**
+ * Skip decimal digit
+ * @param state
+ * @return
+ */
+static int skipDigit(lex_state_t * state) {
+ if (!iseos(state) && isdigit((uint8_t)(state->pos[0]))) {
+ state->pos++;
+ return SKIP_OK;
+ } else {
+ return SKIP_NONE;
+ }
+}
+
+/**
+ * Skip multiple decimal digits
+ * @param state
+ * @return
+ */
+static int skipNumbers(lex_state_t * state) {
+ int someNumbers = 0;
+ while (!iseos(state) && isdigit((uint8_t)(state->pos[0]))) {
+ state->pos++;
+ someNumbers++;
+ }
+ return someNumbers;
+}
+
+/**
+ * Skip plus or minus
+ * @param state
+ * @return
+ */
+static int skipPlusmn(lex_state_t * state) {
+ if (!iseos(state) && isplusmn(state->pos[0])) {
+ state->pos++;
+ return SKIP_OK;
+ } else {
+ return SKIP_NONE;
+ }
+}
+
+/**
+ * Skip any character from 'a'-'Z'
+ * @param state
+ * @return
+ */
+static int skipAlpha(lex_state_t * state) {
+ int someLetters = 0;
+ while (!iseos(state) && isalpha((uint8_t)(state->pos[0]))) {
+ state->pos++;
+ someLetters++;
+ }
+ return someLetters;
+}
+
+/**
+ * Skip exact character chr or nothing
+ * @param state
+ * @param chr
+ * @return
+ */
+static int skipChr(lex_state_t * state, char chr) {
+ if (!iseos(state) && ischr(state, chr)) {
+ state->pos++;
+ return SKIP_OK;
+ } else {
+ return SKIP_NONE;
+ }
+}
+
+/**
+ * Skip slash or dot
+ * @param state
+ * @return
+ */
+static int skipSlashDot(lex_state_t * state) {
+ if (!iseos(state) && (ischr(state, '/') | ischr(state, '.'))) {
+ state->pos++;
+ return SKIP_OK;
+ } else {
+ return SKIP_NONE;
+ }
+}
+
+/**
+ * Skip star
+ * @param state
+ * @return
+ */
+static int skipStar(lex_state_t * state) {
+ if (!iseos(state) && ischr(state, '*')) {
+ state->pos++;
+ return SKIP_OK;
+ } else {
+ return SKIP_NONE;
+ }
+}
+
+/**
+ * Skip colon
+ * @param state
+ * @return
+ */
+static int skipColon(lex_state_t * state) {
+ if (!iseos(state) && ischr(state, ':')) {
+ state->pos++;
+ return SKIP_OK;
+ } else {
+ return SKIP_NONE;
+ }
+}
+
+/* 7.6.1.2 <COMMAND PROGRAM HEADER> */
+
+/**
+ * Skip program mnemonic [a-z][a-z0-9_]*
+ * @param state
+ * @return
+ */
+static int skipProgramMnemonic(lex_state_t * state) {
+ const char * startPos = state->pos;
+ if (!iseos(state) && isalpha((uint8_t)(state->pos[0]))) {
+ state->pos++;
+ while (!iseos(state) && (isalnum((uint8_t)(state->pos[0])) || ischr(state, '_'))) {
+ state->pos++;
+ }
+ }
+
+ if (iseos(state)) {
+ return (state->pos - startPos) * SKIP_INCOMPLETE;
+ } else {
+ return (state->pos - startPos) * SKIP_OK;
+ }
+}
+
+/* tokens */
+
+/**
+ * Detect token white space
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_WhiteSpace(lex_state_t * state, scpi_token_t * token) {
+ token->ptr = state->pos;
+
+ skipWs(state);
+
+ token->len = state->pos - token->ptr;
+
+ if (token->len > 0) {
+ token->type = SCPI_TOKEN_WS;
+ } else {
+ token->type = SCPI_TOKEN_UNKNOWN;
+ }
+
+ return token->len;
+}
+
+/* 7.6.1 <COMMAND PROGRAM HEADER> */
+
+/**
+ * Skip command program header \*<PROGRAM MNEMONIC>
+ * @param state
+ * @return
+ */
+static int skipCommonProgramHeader(lex_state_t * state) {
+ int res;
+ if (skipStar(state)) {
+ res = skipProgramMnemonic(state);
+ if (res == SKIP_NONE && iseos(state)) {
+ return SKIP_INCOMPLETE;
+ } else if (res <= SKIP_INCOMPLETE) {
+ return SKIP_OK;
+ } else if (res >= SKIP_OK) {
+ return SKIP_OK;
+ } else {
+ return SKIP_INCOMPLETE;
+ }
+ }
+ return SKIP_NONE;
+}
+
+/**
+ * Skip compound program header :<PROGRAM MNEMONIC>:<PROGRAM MNEMONIC>...
+ * @param state
+ * @return
+ */
+static int skipCompoundProgramHeader(lex_state_t * state) {
+ int res;
+ int firstColon = skipColon(state);
+
+ res = skipProgramMnemonic(state);
+ if (res >= SKIP_OK) {
+ while (skipColon(state)) {
+ res = skipProgramMnemonic(state);
+ if (res <= SKIP_INCOMPLETE) {
+ return SKIP_OK;
+ } else if (res == SKIP_NONE) {
+ return SKIP_INCOMPLETE;
+ }
+ }
+ return SKIP_OK;
+ } else if (res <= SKIP_INCOMPLETE) {
+ return SKIP_OK;
+ } else if (firstColon) {
+ return SKIP_INCOMPLETE;
+ } else {
+ return SKIP_NONE;
+ }
+}
+
+/**
+ * Detect token command or compound program header
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_ProgramHeader(lex_state_t * state, scpi_token_t * token) {
+ int res;
+ token->ptr = state->pos;
+ token->type = SCPI_TOKEN_UNKNOWN;
+
+ res = skipCommonProgramHeader(state);
+ if (res >= SKIP_OK) {
+ if (skipChr(state, '?') >= SKIP_OK) {
+ token->type = SCPI_TOKEN_COMMON_QUERY_PROGRAM_HEADER;
+ } else {
+ token->type = SCPI_TOKEN_COMMON_PROGRAM_HEADER;
+ }
+ } else if (res <= SKIP_INCOMPLETE) {
+ token->type = SCPI_TOKEN_INCOMPLETE_COMMON_PROGRAM_HEADER;
+ } else if (res == SKIP_NONE) {
+ res = skipCompoundProgramHeader(state);
+
+ if (res >= SKIP_OK) {
+ if (skipChr(state, '?') >= SKIP_OK) {
+ token->type = SCPI_TOKEN_COMPOUND_QUERY_PROGRAM_HEADER;
+ } else {
+ token->type = SCPI_TOKEN_COMPOUND_PROGRAM_HEADER;
+ }
+ } else if (res <= SKIP_INCOMPLETE) {
+ token->type = SCPI_TOKEN_INCOMPLETE_COMPOUND_PROGRAM_HEADER;
+ }
+ }
+
+ if (token->type != SCPI_TOKEN_UNKNOWN) {
+ token->len = state->pos - token->ptr;
+ } else {
+ token->len = 0;
+ state->pos = token->ptr;
+ }
+
+ return token->len;
+}
+
+/* 7.7.1 <CHARACTER PROGRAM DATA> */
+
+/**
+ * Detect token "Character program data"
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_CharacterProgramData(lex_state_t * state, scpi_token_t * token) {
+ token->ptr = state->pos;
+
+ if (!iseos(state) && isalpha((uint8_t)(state->pos[0]))) {
+ state->pos++;
+ while (!iseos(state) && (isalnum((uint8_t)(state->pos[0])) || ischr(state, '_'))) {
+ state->pos++;
+ }
+ }
+
+ token->len = state->pos - token->ptr;
+ if (token->len > 0) {
+ token->type = SCPI_TOKEN_PROGRAM_MNEMONIC;
+ } else {
+ token->type = SCPI_TOKEN_UNKNOWN;
+ }
+
+ return token->len;
+}
+
+/* 7.7.2 <DECIMAL NUMERIC PROGRAM DATA> */
+static int skipMantisa(lex_state_t * state) {
+ int someNumbers = 0;
+
+ skipPlusmn(state);
+
+ someNumbers += skipNumbers(state);
+
+ if (skipChr(state, '.')) {
+ someNumbers += skipNumbers(state);
+ }
+
+ return someNumbers;
+}
+
+static int skipExponent(lex_state_t * state) {
+ int someNumbers = 0;
+
+ if (!iseos(state) && isE(state->pos[0])) {
+ state->pos++;
+
+ skipWs(state);
+
+ skipPlusmn(state);
+
+ someNumbers = skipNumbers(state);
+ }
+
+ return someNumbers;
+}
+
+/**
+ * Detect token Decimal number
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_DecimalNumericProgramData(lex_state_t * state, scpi_token_t * token) {
+ char * rollback;
+ token->ptr = state->pos;
+
+ if (skipMantisa(state)) {
+ rollback = state->pos;
+ skipWs(state);
+ if (!skipExponent(state)) {
+ state->pos = rollback;
+ }
+ } else {
+ state->pos = token->ptr;
+ }
+
+ token->len = state->pos - token->ptr;
+ if (token->len > 0) {
+ token->type = SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA;
+ } else {
+ token->type = SCPI_TOKEN_UNKNOWN;
+ }
+
+ return token->len;
+}
+
+/* 7.7.3 <SUFFIX PROGRAM DATA> */
+int scpiLex_SuffixProgramData(lex_state_t * state, scpi_token_t * token) {
+ token->ptr = state->pos;
+
+ skipChr(state, '/');
+
+ /* TODO: strict parsing : SLASH? (ALPHA+ (MINUS? DIGIT)?) ((SLASH | DOT) (ALPHA+ (MINUS? DIGIT)?))* */
+ if (skipAlpha(state)) {
+ skipChr(state, '-');
+ skipDigit(state);
+
+ while (skipSlashDot(state)) {
+ skipAlpha(state);
+ skipChr(state, '-');
+ skipDigit(state);
+ }
+ }
+
+ token->len = state->pos - token->ptr;
+ if ((token->len > 0)) {
+ token->type = SCPI_TOKEN_SUFFIX_PROGRAM_DATA;
+ } else {
+ token->type = SCPI_TOKEN_UNKNOWN;
+ state->pos = token->ptr;
+ token->len = 0;
+ }
+
+ return token->len;
+}
+
+/* 7.7.4 <NONDECIMAL NUMERIC PROGRAM DATA> */
+static int skipHexNum(lex_state_t * state) {
+ int someNumbers = 0;
+ while (!iseos(state) && isxdigit((uint8_t)(state->pos[0]))) {
+ state->pos++;
+ someNumbers++;
+ }
+ return someNumbers;
+}
+
+static int skipOctNum(lex_state_t * state) {
+ int someNumbers = 0;
+ while (!iseos(state) && isqdigit(state->pos[0])) {
+ state->pos++;
+ someNumbers++;
+ }
+ return someNumbers;
+}
+
+static int skipBinNum(lex_state_t * state) {
+ int someNumbers = 0;
+ while (!iseos(state) && isbdigit(state->pos[0])) {
+ state->pos++;
+ someNumbers++;
+ }
+ return someNumbers;
+}
+
+/**
+ * Detect token nondecimal number
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_NondecimalNumericData(lex_state_t * state, scpi_token_t * token) {
+ int someNumbers = 0;
+ token->ptr = state->pos;
+ if (skipChr(state, '#')) {
+ if (!iseos(state)) {
+ if (isH(state->pos[0])) {
+ state->pos++;
+ someNumbers = skipHexNum(state);
+ token->type = SCPI_TOKEN_HEXNUM;
+ } else if (isQ(state->pos[0])) {
+ state->pos++;
+ someNumbers = skipOctNum(state);
+ token->type = SCPI_TOKEN_OCTNUM;
+ } else if (isB(state->pos[0])) {
+ state->pos++;
+ someNumbers = skipBinNum(state);
+ token->type = SCPI_TOKEN_BINNUM;
+ }
+ }
+ }
+
+ if (someNumbers) {
+ token->ptr += 2; /* ignore number prefix */
+ token->len = state->pos - token->ptr;
+ } else {
+ token->type = SCPI_TOKEN_UNKNOWN;
+ state->pos = token->ptr;
+ token->len = 0;
+ }
+ return token->len > 0 ? token->len + 2 : 0;
+}
+
+/* 7.7.5 <STRING PROGRAM DATA> */
+static int isascii7bit(int c) {
+ return (c >= 0) && (c <= 0x7f);
+}
+
+static void skipQuoteProgramData(lex_state_t * state, char quote) {
+ while (!iseos(state)) {
+ if (isascii7bit(state->pos[0]) && !ischr(state, quote)) {
+ state->pos++;
+ } else if (ischr(state, quote)) {
+ state->pos++;
+ if (!iseos(state) && ischr(state, quote)) {
+ state->pos++;
+ } else {
+ state->pos--;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+}
+
+static void skipDoubleQuoteProgramData(lex_state_t * state) {
+ skipQuoteProgramData(state, '"');
+}
+
+static void skipSingleQuoteProgramData(lex_state_t * state) {
+ skipQuoteProgramData(state, '\'');
+}
+
+/**
+ * Detect token String data
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_StringProgramData(lex_state_t * state, scpi_token_t * token) {
+ token->ptr = state->pos;
+
+ if (!iseos(state)) {
+ if (ischr(state, '"')) {
+ state->pos++;
+ token->type = SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA;
+ skipDoubleQuoteProgramData(state);
+ if (!iseos(state) && ischr(state, '"')) {
+ state->pos++;
+ token->len = state->pos - token->ptr;
+ } else {
+ state->pos = token->ptr;
+ }
+ } else if (ischr(state, '\'')) {
+ state->pos++;
+ token->type = SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA;
+ skipSingleQuoteProgramData(state);
+ if (!iseos(state) && ischr(state, '\'')) {
+ state->pos++;
+ token->len = state->pos - token->ptr;
+ } else {
+ state->pos = token->ptr;
+ }
+ }
+ }
+
+ token->len = state->pos - token->ptr;
+
+ if ((token->len > 0)) {
+ /* token->ptr++;
+ * token->len -= 2; */
+ } else {
+ token->type = SCPI_TOKEN_UNKNOWN;
+ state->pos = token->ptr;
+ token->len = 0;
+ }
+
+ return token->len > 0 ? token->len : 0;
+}
+
+/* 7.7.6 <ARBITRARY BLOCK PROGRAM DATA> */
+static int isNonzeroDigit(int c) {
+ return isdigit(c) && (c != '0');
+}
+
+/**
+ * Detect token Block Data
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_ArbitraryBlockProgramData(lex_state_t * state, scpi_token_t * token) {
+ int i;
+ int arbitraryBlockLength = 0;
+ const char * ptr = state->pos;
+ int validData = -1;
+ token->ptr = state->pos;
+
+ if (skipChr(state, '#')) {
+ if (!iseos(state) && isNonzeroDigit(state->pos[0])) {
+ /* Get number of digits */
+ i = state->pos[0] - '0';
+ state->pos++;
+
+ for (; i > 0; i--) {
+ if (!iseos(state) && isdigit((uint8_t)(state->pos[0]))) {
+ arbitraryBlockLength *= 10;
+ arbitraryBlockLength += (state->pos[0] - '0');
+ state->pos++;
+ } else {
+ break;
+ }
+ }
+
+ if (i == 0) {
+ state->pos += arbitraryBlockLength;
+ if ((state->buffer + state->len) >= (state->pos)) {
+ token->ptr = state->pos - arbitraryBlockLength;
+ token->len = arbitraryBlockLength;
+ validData = 1;
+ } else {
+ validData = 0;
+ }
+ } else if (iseos(state)) {
+ validData = 0;
+ }
+ } else if (iseos(state)) {
+ validData = 0;
+ }
+ }
+
+ if (validData == 1) {
+ /* valid */
+ token->type = SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA;
+ } else if (validData == 0) {
+ /* incomplete */
+ token->type = SCPI_TOKEN_UNKNOWN;
+ token->len = 0;
+ state->pos = state->buffer + state->len;
+ } else {
+ /* invalid */
+ token->type = SCPI_TOKEN_UNKNOWN;
+ state->pos = token->ptr;
+ token->len = 0;
+ }
+
+ return token->len + (token->ptr - ptr);
+}
+
+/* 7.7.7 <EXPRESSION PROGRAM DATA> */
+static int isProgramExpression(int c) {
+ if ((c >= 0x20) && (c <= 0x7e)) {
+ if ((c != '"')
+ && (c != '#')
+ && (c != '\'')
+ && (c != '(')
+ && (c != ')')
+ && (c != ';')) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void skipProgramExpression(lex_state_t * state) {
+ while (!iseos(state) && isProgramExpression(state->pos[0])) {
+ state->pos++;
+ }
+}
+
+/* TODO: 7.7.7.2-2 recursive - any program data */
+
+/**
+ * Detect token Expression
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_ProgramExpression(lex_state_t * state, scpi_token_t * token) {
+ token->ptr = state->pos;
+
+ if (!iseos(state) && ischr(state, '(')) {
+ state->pos++;
+ skipProgramExpression(state);
+
+ if (!iseos(state) && ischr(state, ')')) {
+ state->pos++;
+ token->len = state->pos - token->ptr;
+ } else {
+ token->len = 0;
+ }
+ }
+
+ if ((token->len > 0)) {
+ token->type = SCPI_TOKEN_PROGRAM_EXPRESSION;
+ } else {
+ token->type = SCPI_TOKEN_UNKNOWN;
+ state->pos = token->ptr;
+ token->len = 0;
+ }
+
+ return token->len;
+}
+
+/**
+ * Detect token comma
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_Comma(lex_state_t * state, scpi_token_t * token) {
+ token->ptr = state->pos;
+
+ if (skipChr(state, ',')) {
+ token->len = 1;
+ token->type = SCPI_TOKEN_COMMA;
+ } else {
+ token->len = 0;
+ token->type = SCPI_TOKEN_UNKNOWN;
+ }
+
+ return token->len;
+}
+
+/**
+ * Detect token semicolon
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_Semicolon(lex_state_t * state, scpi_token_t * token) {
+ token->ptr = state->pos;
+
+ if (skipChr(state, ';')) {
+ token->len = 1;
+ token->type = SCPI_TOKEN_SEMICOLON;
+ } else {
+ token->len = 0;
+ token->type = SCPI_TOKEN_UNKNOWN;
+ }
+
+ return token->len;
+}
+
+/**
+ * Detect token colon
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_Colon(lex_state_t * state, scpi_token_t * token) {
+ token->ptr = state->pos;
+
+ if (skipChr(state, ':')) {
+ token->len = 1;
+ token->type = SCPI_TOKEN_COLON;
+ } else {
+ token->len = 0;
+ token->type = SCPI_TOKEN_UNKNOWN;
+ }
+
+ return token->len;
+}
+
+/**
+ * Detect specified character
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_SpecificCharacter(lex_state_t * state, scpi_token_t * token, char chr) {
+ token->ptr = state->pos;
+
+ if (skipChr(state, chr)) {
+ token->len = 1;
+ token->type = SCPI_TOKEN_SPECIFIC_CHARACTER;
+ } else {
+ token->len = 0;
+ token->type = SCPI_TOKEN_UNKNOWN;
+ }
+
+ return token->len;
+}
+
+/**
+ * Detect token New line
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiLex_NewLine(lex_state_t * state, scpi_token_t * token) {
+ token->ptr = state->pos;
+
+ skipChr(state, '\r');
+ skipChr(state, '\n');
+
+ token->len = state->pos - token->ptr;
+
+ if ((token->len > 0)) {
+ token->type = SCPI_TOKEN_NL;
+ } else {
+ token->type = SCPI_TOKEN_UNKNOWN;
+ state->pos = token->ptr;
+ token->len = 0;
+ }
+
+ return token->len;
+}
diff --git a/third_party/libscpi/src/lexer_private.h b/third_party/libscpi/src/lexer_private.h
new file mode 100644
index 00000000..914ee157
--- /dev/null
+++ b/third_party/libscpi/src/lexer_private.h
@@ -0,0 +1,69 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file lexer.h
+ * @date Thu Mar 21 15:00:58 UTC 2013
+ *
+ * @brief SCPI Lexer
+ *
+ *
+ */
+
+#ifndef SCPI_LEXER_H
+#define SCPI_LEXER_H
+
+#include "scpi/types.h"
+#include "utils_private.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int scpiLex_IsEos(lex_state_t * state) LOCAL;
+ int scpiLex_WhiteSpace(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_ProgramHeader(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_CharacterProgramData(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_DecimalNumericProgramData(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_SuffixProgramData(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_NondecimalNumericData(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_StringProgramData(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_ArbitraryBlockProgramData(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_ProgramExpression(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_Comma(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_Semicolon(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_Colon(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_NewLine(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiLex_SpecificCharacter(lex_state_t * state, scpi_token_t * token, char chr) LOCAL;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_LEXER_H */
+
diff --git a/third_party/libscpi/src/minimal.c b/third_party/libscpi/src/minimal.c
new file mode 100644
index 00000000..29dff824
--- /dev/null
+++ b/third_party/libscpi/src/minimal.c
@@ -0,0 +1,215 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_minimal.c
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief SCPI minimal implementation
+ *
+ *
+ */
+
+
+#include "scpi/parser.h"
+#include "scpi/minimal.h"
+#include "scpi/constants.h"
+#include "scpi/error.h"
+#include "scpi/ieee488.h"
+#include "utils_private.h"
+
+/**
+ * Command stub function
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_Stub(scpi_t * context) {
+ (void) context;
+ return SCPI_RES_OK;
+}
+
+/**
+ * Query command stub function
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_StubQ(scpi_t * context) {
+ SCPI_ResultInt32(context, 0);
+ return SCPI_RES_OK;
+}
+
+/**
+ * SYSTem:VERSion?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_SystemVersionQ(scpi_t * context) {
+ SCPI_ResultMnemonic(context, SCPI_STD_VERSION_REVISION);
+ return SCPI_RES_OK;
+}
+
+/**
+ * SYSTem:ERRor[:NEXT]?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_SystemErrorNextQ(scpi_t * context) {
+ scpi_error_t error;
+ SCPI_ErrorPop(context, &error);
+ SCPI_ResultError(context, &error);
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+ SCPIDEFINE_free(&context->error_info_heap, error.device_dependent_info, false);
+#endif
+ return SCPI_RES_OK;
+}
+
+/**
+ * SYSTem:ERRor:COUNt?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_SystemErrorCountQ(scpi_t * context) {
+ SCPI_ResultInt32(context, SCPI_ErrorCount(context));
+
+ return SCPI_RES_OK;
+}
+
+/**
+ * STATus:QUEStionable:CONDition?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_StatusQuestionableConditionQ(scpi_t * context) {
+ /* return value */
+ SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_QUESC));
+
+ return SCPI_RES_OK;
+}
+
+/**
+ * STATus:QUEStionable[:EVENt]?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_StatusQuestionableEventQ(scpi_t * context) {
+ /* return value */
+ SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_QUES));
+
+ /* clear register */
+ SCPI_RegSet(context, SCPI_REG_QUES, 0);
+
+ return SCPI_RES_OK;
+}
+
+/**
+ * STATus:QUEStionable:ENABle?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_StatusQuestionableEnableQ(scpi_t * context) {
+ /* return value */
+ SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_QUESE));
+
+ return SCPI_RES_OK;
+}
+
+/**
+ * STATus:QUEStionable:ENABle
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_StatusQuestionableEnable(scpi_t * context) {
+ int32_t new_QUESE;
+ if (SCPI_ParamInt32(context, &new_QUESE, TRUE)) {
+ SCPI_RegSet(context, SCPI_REG_QUESE, (scpi_reg_val_t) new_QUESE);
+ }
+ return SCPI_RES_OK;
+}
+
+/**
+ * STATus:OPERation:CONDition?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_StatusOperationConditionQ(scpi_t * context) {
+ /* return value */
+ SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_OPERC));
+
+ return SCPI_RES_OK;
+}
+
+/**
+ * STATus:OPERation[:EVENt]?
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_StatusOperationEventQ(scpi_t * context) {
+ /* return value */
+ SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_OPER));
+
+ /* clear register */
+ SCPI_RegSet(context, SCPI_REG_OPER, 0);
+
+ return SCPI_RES_OK;
+}
+
+/**
+ * STATus:OPERation:ENABle?
+ * @param context
+ * @return
+ */
+ scpi_result_t SCPI_StatusOperationEnableQ(scpi_t * context) {
+ /* return value */
+ SCPI_ResultInt32(context, SCPI_RegGet(context, SCPI_REG_OPERE));
+
+ return SCPI_RES_OK;
+}
+
+/**
+ * STATus:OPERation:ENABle
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_StatusOperationEnable(scpi_t * context) {
+ int32_t new_OPERE;
+ if (SCPI_ParamInt32(context, &new_OPERE, TRUE)) {
+ SCPI_RegSet(context, SCPI_REG_OPERE, (scpi_reg_val_t) new_OPERE);
+ }
+ return SCPI_RES_OK;
+}
+
+/**
+ * STATus:PRESet
+ * @param context
+ * @return
+ */
+scpi_result_t SCPI_StatusPreset(scpi_t * context) {
+ /* clear STATUS:... */
+ SCPI_RegSet(context, SCPI_REG_QUES, 0);
+ return SCPI_RES_OK;
+}
diff --git a/third_party/libscpi/src/parser.c b/third_party/libscpi/src/parser.c
new file mode 100644
index 00000000..de14418d
--- /dev/null
+++ b/third_party/libscpi/src/parser.c
@@ -0,0 +1,1834 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_parser.c
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief SCPI parser implementation
+ *
+ *
+ */
+
+#include <ctype.h>
+#include <string.h>
+
+#include "scpi/config.h"
+#include "scpi/parser.h"
+#include "parser_private.h"
+#include "lexer_private.h"
+#include "scpi/error.h"
+#include "scpi/constants.h"
+#include "scpi/utils.h"
+
+/**
+ * Write data to SCPI output
+ * @param context
+ * @param data
+ * @param len - length of data to be written
+ * @return number of bytes written
+ */
+static size_t writeData(scpi_t * context, const char * data, size_t len) {
+ if ((len > 0) && (data != NULL)) {
+ return context->interface->write(context, data, len);
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Flush data to SCPI output
+ * @param context
+ * @return
+ */
+static int flushData(scpi_t * context) {
+ if (context && context->interface && context->interface->flush) {
+ return context->interface->flush(context);
+ } else {
+ return SCPI_RES_OK;
+ }
+}
+
+/**
+ * Write result delimiter to output
+ * @param context
+ * @return number of bytes written
+ */
+static size_t writeDelimiter(scpi_t * context) {
+ if (context->output_count > 0) {
+ return writeData(context, ",", 1);
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Conditionaly write "New Line"
+ * @param context
+ * @return number of characters written
+ */
+static size_t writeNewLine(scpi_t * context) {
+ if (!context->first_output) {
+ size_t len;
+#ifndef SCPI_LINE_ENDING
+#error no termination character defined
+#endif
+ len = writeData(context, SCPI_LINE_ENDING, strlen(SCPI_LINE_ENDING));
+ flushData(context);
+ return len;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Conditionaly write ";"
+ * @param context
+ * @return number of characters written
+ */
+static size_t writeSemicolon(scpi_t * context) {
+ if (context->output_count > 0) {
+ return writeData(context, ";", 1);
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Process command
+ * @param context
+ */
+static scpi_bool_t processCommand(scpi_t * context) {
+ const scpi_command_t * cmd = context->param_list.cmd;
+ lex_state_t * state = &context->param_list.lex_state;
+ scpi_bool_t result = TRUE;
+ scpi_bool_t is_query = context->param_list.cmd_raw.data[context->param_list.cmd_raw.length - 1] == '?';
+
+ /* conditionally write ; */
+ if(!context->first_output && is_query) {
+ writeData(context, ";", 1);
+ }
+
+ context->cmd_error = FALSE;
+ context->output_count = 0;
+ context->input_count = 0;
+ context->arbitrary_remaining = 0;
+
+ /* if callback exists - call command callback */
+ if (cmd->callback != NULL) {
+ if ((cmd->callback(context) != SCPI_RES_OK)) {
+ if (!context->cmd_error) {
+ SCPI_ErrorPush(context, SCPI_ERROR_EXECUTION_ERROR);
+ }
+ result = FALSE;
+ } else {
+ if (context->cmd_error) {
+ result = FALSE;
+ } else {
+ if(context->first_output && is_query) {
+ context->first_output = FALSE;
+ }
+ }
+ }
+ }
+
+ /* set error if command callback did not read all parameters */
+ if (state->pos < (state->buffer + state->len) && !context->cmd_error) {
+ SCPI_ErrorPush(context, SCPI_ERROR_PARAMETER_NOT_ALLOWED);
+ result = FALSE;
+ }
+
+ return result;
+}
+
+/**
+ * Cycle all patterns and search matching pattern. Execute command callback.
+ * @param context
+ * @result TRUE if context->paramlist is filled with correct values
+ */
+static scpi_bool_t findCommandHeader(scpi_t * context, const char * header, int len) {
+ int32_t i;
+ const scpi_command_t * cmd;
+
+ for (i = 0; context->cmdlist[i].pattern != NULL; i++) {
+ cmd = &context->cmdlist[i];
+ if (matchCommand(cmd->pattern, header, len, NULL, 0, 0)) {
+ context->param_list.cmd = cmd;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * Parse one command line
+ * @param context
+ * @param data - complete command line
+ * @param len - command line length
+ * @return FALSE if there was some error during evaluation of commands
+ */
+scpi_bool_t SCPI_Parse(scpi_t * context, char * data, int len) {
+ scpi_bool_t result = TRUE;
+ scpi_parser_state_t * state;
+ int r;
+ scpi_token_t cmd_prev = {SCPI_TOKEN_UNKNOWN, NULL, 0};
+
+ if (context == NULL) {
+ return FALSE;
+ }
+
+ state = &context->parser_state;
+ context->output_count = 0;
+ context->first_output = TRUE;
+
+ while (1) {
+ r = scpiParser_detectProgramMessageUnit(state, data, len);
+
+ if (state->programHeader.type == SCPI_TOKEN_INVALID) {
+ SCPI_ErrorPush(context, SCPI_ERROR_INVALID_CHARACTER);
+ result = FALSE;
+ } else if (state->programHeader.len > 0) {
+
+ composeCompoundCommand(&cmd_prev, &state->programHeader);
+
+ if (findCommandHeader(context, state->programHeader.ptr, state->programHeader.len)) {
+
+ context->param_list.lex_state.buffer = state->programData.ptr;
+ context->param_list.lex_state.pos = context->param_list.lex_state.buffer;
+ context->param_list.lex_state.len = state->programData.len;
+ context->param_list.cmd_raw.data = state->programHeader.ptr;
+ context->param_list.cmd_raw.position = 0;
+ context->param_list.cmd_raw.length = state->programHeader.len;
+
+ result &= processCommand(context);
+ cmd_prev = state->programHeader;
+ } else {
+ /* place undefined header with error */
+ /* calculate length of errorenous header and trim \r\n */
+ size_t r2 = r;
+ while (r2 > 0 && (data[r2 - 1] == '\r' || data[r2 - 1] == '\n')) r2--;
+ SCPI_ErrorPushEx(context, SCPI_ERROR_UNDEFINED_HEADER, data, r2);
+ result = FALSE;
+ }
+ }
+
+ if (r < len) {
+ data += r;
+ len -= r;
+ } else {
+ break;
+ }
+
+ }
+
+ /* conditionally write new line */
+ writeNewLine(context);
+
+ return result;
+}
+
+/**
+ * Initialize SCPI context structure
+ * @param context
+ * @param commands
+ * @param interface
+ * @param units
+ * @param idn1
+ * @param idn2
+ * @param idn3
+ * @param idn4
+ * @param input_buffer
+ * @param input_buffer_length
+ * @param error_queue_data
+ * @param error_queue_size
+ */
+void SCPI_Init(scpi_t * context,
+ const scpi_command_t * commands,
+ scpi_interface_t * interface,
+ const scpi_unit_def_t * units,
+ const char * idn1, const char * idn2, const char * idn3, const char * idn4,
+ char * input_buffer, size_t input_buffer_length,
+ scpi_error_t * error_queue_data, int16_t error_queue_size) {
+ memset(context, 0, sizeof (*context));
+ context->cmdlist = commands;
+ context->interface = interface;
+ context->units = units;
+ context->idn[0] = idn1;
+ context->idn[1] = idn2;
+ context->idn[2] = idn3;
+ context->idn[3] = idn4;
+ context->buffer.data = input_buffer;
+ context->buffer.length = input_buffer_length;
+ context->buffer.position = 0;
+ SCPI_ErrorInit(context, error_queue_data, error_queue_size);
+}
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+
+/**
+ * Initialize context's
+ * @param context
+ * @param data
+ * @param len
+ * @return
+ */
+void SCPI_InitHeap(scpi_t * context,
+ char * error_info_heap, size_t error_info_heap_length) {
+ scpiheap_init(&context->error_info_heap, error_info_heap, error_info_heap_length);
+}
+#endif
+
+/**
+ * Interface to the application. Adds data to system buffer and try to search
+ * command line termination. If the termination is found or if len=0, command
+ * parser is called.
+ *
+ * @param context
+ * @param data - data to process
+ * @param len - length of data
+ * @return
+ */
+scpi_bool_t SCPI_Input(scpi_t * context, const char * data, int len) {
+ scpi_bool_t result = TRUE;
+ size_t totcmdlen = 0;
+ int cmdlen = 0;
+
+ if (len == 0) {
+ context->buffer.data[context->buffer.position] = 0;
+ result = SCPI_Parse(context, context->buffer.data, context->buffer.position);
+ context->buffer.position = 0;
+ } else {
+ int buffer_free;
+
+ buffer_free = context->buffer.length - context->buffer.position;
+ if (len > (buffer_free - 1)) {
+ /* Input buffer overrun - invalidate buffer */
+ context->buffer.position = 0;
+ context->buffer.data[context->buffer.position] = 0;
+ SCPI_ErrorPush(context, SCPI_ERROR_INPUT_BUFFER_OVERRUN);
+ return FALSE;
+ }
+ memcpy(&context->buffer.data[context->buffer.position], data, len);
+ context->buffer.position += len;
+ context->buffer.data[context->buffer.position] = 0;
+
+
+ while (1) {
+ cmdlen = scpiParser_detectProgramMessageUnit(&context->parser_state, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen);
+ totcmdlen += cmdlen;
+
+ if (context->parser_state.termination == SCPI_MESSAGE_TERMINATION_NL) {
+ result = SCPI_Parse(context, context->buffer.data, totcmdlen);
+ memmove(context->buffer.data, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen);
+ context->buffer.position -= totcmdlen;
+ totcmdlen = 0;
+ } else {
+ if (context->parser_state.programHeader.type == SCPI_TOKEN_UNKNOWN
+ && context->parser_state.termination == SCPI_MESSAGE_TERMINATION_NONE) break;
+ if (totcmdlen >= context->buffer.position) break;
+ }
+ }
+ }
+
+ return result;
+}
+
+/* writing results */
+
+/**
+ * Write raw string result to the output
+ * @param context
+ * @param data
+ * @return
+ */
+size_t SCPI_ResultCharacters(scpi_t * context, const char * data, size_t len) {
+ size_t result = 0;
+ result += writeDelimiter(context);
+ result += writeData(context, data, len);
+ context->output_count++;
+ return result;
+}
+
+/**
+ * Return prefix of nondecimal base
+ * @param base
+ * @return
+ */
+static const char * getBasePrefix(int8_t base) {
+ switch (base) {
+ case 2: return "#B";
+ case 8: return "#Q";
+ case 16: return "#H";
+ default: return NULL;
+ }
+}
+
+/**
+ * Write signed/unsigned 32 bit integer value in specific base to the result
+ * @param context
+ * @param val
+ * @param base
+ * @param sign
+ * @return
+ */
+static size_t resultUInt32BaseSign(scpi_t * context, uint32_t val, int8_t base, scpi_bool_t sign) {
+ char buffer[32 + 1];
+ const char * basePrefix;
+ size_t result = 0;
+ size_t len;
+
+ len = UInt32ToStrBaseSign(val, buffer, sizeof (buffer), base, sign);
+ basePrefix = getBasePrefix(base);
+
+ result += writeDelimiter(context);
+ if (basePrefix != NULL) {
+ result += writeData(context, basePrefix, 2);
+ }
+ result += writeData(context, buffer, len);
+ context->output_count++;
+ return result;
+}
+
+/**
+ * Write signed/unsigned 64 bit integer value in specific base to the result
+ * @param context
+ * @param val
+ * @param base
+ * @param sign
+ * @return
+ */
+static size_t resultUInt64BaseSign(scpi_t * context, uint64_t val, int8_t base, scpi_bool_t sign) {
+ char buffer[64 + 1];
+ const char * basePrefix;
+ size_t result = 0;
+ size_t len;
+
+ len = UInt64ToStrBaseSign(val, buffer, sizeof (buffer), base, sign);
+ basePrefix = getBasePrefix(base);
+
+ result += writeDelimiter(context);
+ if (basePrefix != NULL) {
+ result += writeData(context, basePrefix, 2);
+ }
+ result += writeData(context, buffer, len);
+ context->output_count++;
+ return result;
+}
+
+/**
+ * Write signed 32 bit integer value to the result
+ * @param context
+ * @param val
+ * @return
+ */
+size_t SCPI_ResultInt32(scpi_t * context, int32_t val) {
+ return resultUInt32BaseSign(context, val, 10, TRUE);
+}
+
+/**
+ * Write unsigned 32 bit integer value in specific base to the result
+ * Write signed/unsigned 32 bit integer value in specific base to the result
+ * @param context
+ * @param val
+ * @return
+ */
+size_t SCPI_ResultUInt32Base(scpi_t * context, uint32_t val, int8_t base) {
+ return resultUInt32BaseSign(context, val, base, FALSE);
+}
+
+/**
+ * Write signed 64 bit integer value to the result
+ * @param context
+ * @param val
+ * @return
+ */
+size_t SCPI_ResultInt64(scpi_t * context, int64_t val) {
+ return resultUInt64BaseSign(context, val, 10, TRUE);
+}
+
+/**
+ * Write unsigned 64 bit integer value in specific base to the result
+ * @param context
+ * @param val
+ * @return
+ */
+size_t SCPI_ResultUInt64Base(scpi_t * context, uint64_t val, int8_t base) {
+ return resultUInt64BaseSign(context, val, base, FALSE);
+}
+
+/**
+ * Write float (32 bit) value to the result
+ * @param context
+ * @param val
+ * @return
+ */
+size_t SCPI_ResultFloat(scpi_t * context, float val) {
+ char buffer[32];
+ size_t result = 0;
+ size_t len = SCPI_FloatToStr(val, buffer, sizeof (buffer));
+ result += writeDelimiter(context);
+ result += writeData(context, buffer, len);
+ context->output_count++;
+ return result;
+}
+
+/**
+ * Write double (64bit) value to the result
+ * @param context
+ * @param val
+ * @return
+ */
+size_t SCPI_ResultDouble(scpi_t * context, double val) {
+ char buffer[32];
+ size_t result = 0;
+ size_t len = SCPI_DoubleToStr(val, buffer, sizeof (buffer));
+ result += writeDelimiter(context);
+ result += writeData(context, buffer, len);
+ context->output_count++;
+ return result;
+}
+
+/**
+ * Write string within "" to the result
+ * @param context
+ * @param data
+ * @return
+ */
+size_t SCPI_ResultText(scpi_t * context, const char * data) {
+ size_t result = 0;
+ size_t len = strlen(data);
+ const char * quote;
+ result += writeDelimiter(context);
+ result += writeData(context, "\"", 1);
+ while ((quote = strnpbrk(data, len, "\""))) {
+ result += writeData(context, data, quote - data + 1);
+ result += writeData(context, "\"", 1);
+ len -= quote - data + 1;
+ data = quote + 1;
+ }
+ result += writeData(context, data, len);
+ result += writeData(context, "\"", 1);
+ context->output_count++;
+ return result;
+}
+
+/**
+ * SCPI-99:21.8 Device-dependent error information.
+ * Write error information with the following syntax:
+ * <Error/event_number>,"<Error/event_description>[;<Device-dependent_info>]"
+ * The maximum string length of <Error/event_description> plus <Device-dependent_info>
+ * is SCPI_STD_ERROR_DESC_MAX_STRING_LENGTH (255) characters.
+ *
+ * @param context
+ * @param error
+ * @return
+ */
+size_t SCPI_ResultError(scpi_t * context, scpi_error_t * error) {
+ size_t result = 0;
+ size_t outputlimit = SCPI_STD_ERROR_DESC_MAX_STRING_LENGTH;
+ size_t step = 0;
+ const char * quote;
+
+ const char * data[SCPIDEFINE_DESCRIPTION_MAX_PARTS];
+ size_t len[SCPIDEFINE_DESCRIPTION_MAX_PARTS];
+ size_t i;
+
+ data[0] = SCPI_ErrorTranslate(error->error_code);
+ len[0] = strlen(data[0]);
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+ data[1] = error->device_dependent_info;
+#if USE_MEMORY_ALLOCATION_FREE
+ len[1] = error->device_dependent_info ? strlen(data[1]) : 0;
+#else
+ SCPIDEFINE_get_parts(&context->error_info_heap, data[1], &len[1], &data[2], &len[2]);
+#endif
+#endif
+
+ result += SCPI_ResultInt32(context, error->error_code);
+ result += writeDelimiter(context);
+ result += writeData(context, "\"", 1);
+
+ for (i = 0; (i < SCPIDEFINE_DESCRIPTION_MAX_PARTS) && data[i] && outputlimit; i++) {
+ if (i == 1) {
+ result += writeSemicolon(context);
+ outputlimit -= 1;
+ }
+ if (len[i] > outputlimit) {
+ len[i] = outputlimit;
+ }
+
+ while ((quote = strnpbrk(data[i], len[i], "\""))) {
+ if ((step = quote - data[i] + 1) >= outputlimit) {
+ len[i] -= 1;
+ outputlimit -= 1;
+ break;
+ }
+ result += writeData(context, data[i], step);
+ result += writeData(context, "\"", 1);
+ len[i] -= step;
+ outputlimit -= step + 1;
+ data[i] = quote + 1;
+ if (len[i] > outputlimit) {
+ len[i] = outputlimit;
+ }
+ }
+
+ result += writeData(context, data[i], len[i]);
+ outputlimit -= len[i];
+ }
+ result += writeData(context, "\"", 1);
+
+ return result;
+}
+
+/**
+ * Write arbitrary block header with length
+ * @param context
+ * @param len
+ * @return
+ */
+size_t SCPI_ResultArbitraryBlockHeader(scpi_t * context, size_t len) {
+ size_t result = 0;
+ char block_header[12];
+ size_t header_len;
+ block_header[0] = '#';
+ SCPI_UInt32ToStrBase((uint32_t) len, block_header + 2, 10, 10);
+
+ header_len = strlen(block_header + 2);
+ block_header[1] = (char) (header_len + '0');
+
+ context->arbitrary_remaining = len;
+ result = writeDelimiter(context);
+ result += writeData(context, block_header, header_len + 2);
+ return result;
+}
+
+/**
+ * Add data to arbitrary block
+ * @param context
+ * @param data
+ * @param len
+ * @return
+ */
+size_t SCPI_ResultArbitraryBlockData(scpi_t * context, const void * data, size_t len) {
+
+ if (context->arbitrary_remaining < len) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return 0;
+ }
+
+ context->arbitrary_remaining -= len;
+
+ if (context->arbitrary_remaining == 0) {
+ context->output_count++;
+ }
+
+ return writeData(context, (const char *) data, len);
+}
+
+/**
+ * Write arbitrary block program data to the result
+ * @param context
+ * @param data
+ * @param len
+ * @return
+ */
+size_t SCPI_ResultArbitraryBlock(scpi_t * context, const void * data, size_t len) {
+ size_t result = 0;
+ result += SCPI_ResultArbitraryBlockHeader(context, len);
+ result += SCPI_ResultArbitraryBlockData(context, data, len);
+ return result;
+}
+
+/**
+ * Write boolean value to the result
+ * @param context
+ * @param val
+ * @return
+ */
+size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val) {
+ return resultUInt32BaseSign(context, val ? 1 : 0, 10, FALSE);
+}
+
+/* parsing parameters */
+
+/**
+ * Invalidate token
+ * @param token
+ * @param ptr
+ */
+static void invalidateToken(scpi_token_t * token, char * ptr) {
+ token->len = 0;
+ token->ptr = ptr;
+ token->type = SCPI_TOKEN_UNKNOWN;
+}
+
+/**
+ * Get one parameter from command line
+ * @param context
+ * @param parameter
+ * @param mandatory
+ * @return
+ */
+scpi_bool_t SCPI_Parameter(scpi_t * context, scpi_parameter_t * parameter, scpi_bool_t mandatory) {
+ lex_state_t * state;
+
+ if (!parameter) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ invalidateToken(parameter, NULL);
+
+ state = &context->param_list.lex_state;
+
+ if (state->pos >= (state->buffer + state->len)) {
+ if (mandatory) {
+ SCPI_ErrorPush(context, SCPI_ERROR_MISSING_PARAMETER);
+ } else {
+ parameter->type = SCPI_TOKEN_PROGRAM_MNEMONIC; /* TODO: select something different */
+ }
+ return FALSE;
+ }
+ if (context->input_count != 0) {
+ scpiLex_Comma(state, parameter);
+ if (parameter->type != SCPI_TOKEN_COMMA) {
+ invalidateToken(parameter, NULL);
+ SCPI_ErrorPush(context, SCPI_ERROR_INVALID_SEPARATOR);
+ return FALSE;
+ }
+ }
+
+ context->input_count++;
+
+ scpiParser_parseProgramData(&context->param_list.lex_state, parameter);
+
+ switch (parameter->type) {
+ case SCPI_TOKEN_HEXNUM:
+ case SCPI_TOKEN_OCTNUM:
+ case SCPI_TOKEN_BINNUM:
+ case SCPI_TOKEN_PROGRAM_MNEMONIC:
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+ case SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA:
+ case SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA:
+ case SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA:
+ case SCPI_TOKEN_PROGRAM_EXPRESSION:
+ return TRUE;
+ default:
+ invalidateToken(parameter, NULL);
+ SCPI_ErrorPush(context, SCPI_ERROR_INVALID_STRING_DATA);
+ return FALSE;
+ }
+}
+
+/**
+ * Detect if parameter is number
+ * @param parameter
+ * @param suffixAllowed
+ * @return
+ */
+scpi_bool_t SCPI_ParamIsNumber(scpi_parameter_t * parameter, scpi_bool_t suffixAllowed) {
+ switch (parameter->type) {
+ case SCPI_TOKEN_HEXNUM:
+ case SCPI_TOKEN_OCTNUM:
+ case SCPI_TOKEN_BINNUM:
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+ return TRUE;
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+ return suffixAllowed;
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ * Convert parameter to signed/unsigned 32 bit integer
+ * @param context
+ * @param parameter
+ * @param value result
+ * @param sign
+ * @return TRUE if succesful
+ */
+static scpi_bool_t ParamSignToUInt32(scpi_t * context, scpi_parameter_t * parameter, uint32_t * value, scpi_bool_t sign) {
+
+ if (!value) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ switch (parameter->type) {
+ case SCPI_TOKEN_HEXNUM:
+ return strBaseToUInt32(parameter->ptr, value, 16) > 0 ? TRUE : FALSE;
+ case SCPI_TOKEN_OCTNUM:
+ return strBaseToUInt32(parameter->ptr, value, 8) > 0 ? TRUE : FALSE;
+ case SCPI_TOKEN_BINNUM:
+ return strBaseToUInt32(parameter->ptr, value, 2) > 0 ? TRUE : FALSE;
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+ if (sign) {
+ return strBaseToInt32(parameter->ptr, (int32_t *) value, 10) > 0 ? TRUE : FALSE;
+ } else {
+ return strBaseToUInt32(parameter->ptr, value, 10) > 0 ? TRUE : FALSE;
+ }
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ * Convert parameter to signed/unsigned 64 bit integer
+ * @param context
+ * @param parameter
+ * @param value result
+ * @param sign
+ * @return TRUE if succesful
+ */
+static scpi_bool_t ParamSignToUInt64(scpi_t * context, scpi_parameter_t * parameter, uint64_t * value, scpi_bool_t sign) {
+
+ if (!value) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ switch (parameter->type) {
+ case SCPI_TOKEN_HEXNUM:
+ return strBaseToUInt64(parameter->ptr, value, 16) > 0 ? TRUE : FALSE;
+ case SCPI_TOKEN_OCTNUM:
+ return strBaseToUInt64(parameter->ptr, value, 8) > 0 ? TRUE : FALSE;
+ case SCPI_TOKEN_BINNUM:
+ return strBaseToUInt64(parameter->ptr, value, 2) > 0 ? TRUE : FALSE;
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+ if (sign) {
+ return strBaseToInt64(parameter->ptr, (int64_t *) value, 10) > 0 ? TRUE : FALSE;
+ } else {
+ return strBaseToUInt64(parameter->ptr, value, 10) > 0 ? TRUE : FALSE;
+ }
+ default:
+ return FALSE;
+ }
+}
+
+/**
+ * Convert parameter to signed 32 bit integer
+ * @param context
+ * @param parameter
+ * @param value result
+ * @return TRUE if succesful
+ */
+scpi_bool_t SCPI_ParamToInt32(scpi_t * context, scpi_parameter_t * parameter, int32_t * value) {
+ return ParamSignToUInt32(context, parameter, (uint32_t *) value, TRUE);
+}
+
+/**
+ * Convert parameter to unsigned 32 bit integer
+ * @param context
+ * @param parameter
+ * @param value result
+ * @return TRUE if succesful
+ */
+scpi_bool_t SCPI_ParamToUInt32(scpi_t * context, scpi_parameter_t * parameter, uint32_t * value) {
+ return ParamSignToUInt32(context, parameter, value, FALSE);
+}
+
+/**
+ * Convert parameter to signed 64 bit integer
+ * @param context
+ * @param parameter
+ * @param value result
+ * @return TRUE if succesful
+ */
+scpi_bool_t SCPI_ParamToInt64(scpi_t * context, scpi_parameter_t * parameter, int64_t * value) {
+ return ParamSignToUInt64(context, parameter, (uint64_t *) value, TRUE);
+}
+
+/**
+ * Convert parameter to unsigned 32 bit integer
+ * @param context
+ * @param parameter
+ * @param value result
+ * @return TRUE if succesful
+ */
+scpi_bool_t SCPI_ParamToUInt64(scpi_t * context, scpi_parameter_t * parameter, uint64_t * value) {
+ return ParamSignToUInt64(context, parameter, value, FALSE);
+}
+
+/**
+ * Convert parameter to float (32 bit)
+ * @param context
+ * @param parameter
+ * @param value result
+ * @return TRUE if succesful
+ */
+scpi_bool_t SCPI_ParamToFloat(scpi_t * context, scpi_parameter_t * parameter, float * value) {
+ scpi_bool_t result;
+ uint32_t valint;
+
+ if (!value) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ switch (parameter->type) {
+ case SCPI_TOKEN_HEXNUM:
+ case SCPI_TOKEN_OCTNUM:
+ case SCPI_TOKEN_BINNUM:
+ result = SCPI_ParamToUInt32(context, parameter, &valint);
+ *value = valint;
+ break;
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+ result = strToFloat(parameter->ptr, value) > 0 ? TRUE : FALSE;
+ break;
+ default:
+ result = FALSE;
+ }
+ return result;
+}
+
+/**
+ * Convert parameter to double (64 bit)
+ * @param context
+ * @param parameter
+ * @param value result
+ * @return TRUE if succesful
+ */
+scpi_bool_t SCPI_ParamToDouble(scpi_t * context, scpi_parameter_t * parameter, double * value) {
+ scpi_bool_t result;
+ uint64_t valint;
+
+ if (!value) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ switch (parameter->type) {
+ case SCPI_TOKEN_HEXNUM:
+ case SCPI_TOKEN_OCTNUM:
+ case SCPI_TOKEN_BINNUM:
+ result = SCPI_ParamToUInt64(context, parameter, &valint);
+ *value = valint;
+ break;
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+ result = strToDouble(parameter->ptr, value) > 0 ? TRUE : FALSE;
+ break;
+ default:
+ result = FALSE;
+ }
+ return result;
+}
+
+/**
+ * Read floating point float (32 bit) parameter
+ * @param context
+ * @param value
+ * @param mandatory
+ * @return
+ */
+scpi_bool_t SCPI_ParamFloat(scpi_t * context, float * value, scpi_bool_t mandatory) {
+ scpi_bool_t result;
+ scpi_parameter_t param;
+
+ if (!value) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ result = SCPI_Parameter(context, &param, mandatory);
+ if (result) {
+ if (SCPI_ParamIsNumber(&param, FALSE)) {
+ SCPI_ParamToFloat(context, &param, value);
+ } else if (SCPI_ParamIsNumber(&param, TRUE)) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
+ result = FALSE;
+ } else {
+ SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+ result = FALSE;
+ }
+ }
+ return result;
+}
+
+/**
+ * Read floating point double (64 bit) parameter
+ * @param context
+ * @param value
+ * @param mandatory
+ * @return
+ */
+scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory) {
+ scpi_bool_t result;
+ scpi_parameter_t param;
+
+ if (!value) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ result = SCPI_Parameter(context, &param, mandatory);
+ if (result) {
+ if (SCPI_ParamIsNumber(&param, FALSE)) {
+ SCPI_ParamToDouble(context, &param, value);
+ } else if (SCPI_ParamIsNumber(&param, TRUE)) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
+ result = FALSE;
+ } else {
+ SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+ result = FALSE;
+ }
+ }
+ return result;
+}
+
+/**
+ * Read signed/unsigned 32 bit integer parameter
+ * @param context
+ * @param value
+ * @param mandatory
+ * @param sign
+ * @return
+ */
+static scpi_bool_t ParamSignUInt32(scpi_t * context, uint32_t * value, scpi_bool_t mandatory, scpi_bool_t sign) {
+ scpi_bool_t result;
+ scpi_parameter_t param;
+
+ if (!value) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ result = SCPI_Parameter(context, &param, mandatory);
+ if (result) {
+ if (SCPI_ParamIsNumber(&param, FALSE)) {
+ result = ParamSignToUInt32(context, &param, value, sign);
+ } else if (SCPI_ParamIsNumber(&param, TRUE)) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
+ result = FALSE;
+ } else {
+ SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+ result = FALSE;
+ }
+ }
+ return result;
+}
+
+/**
+ * Read signed/unsigned 64 bit integer parameter
+ * @param context
+ * @param value
+ * @param mandatory
+ * @param sign
+ * @return
+ */
+static scpi_bool_t ParamSignUInt64(scpi_t * context, uint64_t * value, scpi_bool_t mandatory, scpi_bool_t sign) {
+ scpi_bool_t result;
+ scpi_parameter_t param;
+
+ if (!value) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ result = SCPI_Parameter(context, &param, mandatory);
+ if (result) {
+ if (SCPI_ParamIsNumber(&param, FALSE)) {
+ result = ParamSignToUInt64(context, &param, value, sign);
+ } else if (SCPI_ParamIsNumber(&param, TRUE)) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED);
+ result = FALSE;
+ } else {
+ SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+ result = FALSE;
+ }
+ }
+ return result;
+}
+
+/**
+ * Read signed 32 bit integer parameter
+ * @param context
+ * @param value
+ * @param mandatory
+ * @return
+ */
+scpi_bool_t SCPI_ParamInt32(scpi_t * context, int32_t * value, scpi_bool_t mandatory) {
+ return ParamSignUInt32(context, (uint32_t *) value, mandatory, TRUE);
+}
+
+/**
+ * Read unsigned 32 bit integer parameter
+ * @param context
+ * @param value
+ * @param mandatory
+ * @return
+ */
+scpi_bool_t SCPI_ParamUInt32(scpi_t * context, uint32_t * value, scpi_bool_t mandatory) {
+ return ParamSignUInt32(context, value, mandatory, FALSE);
+}
+
+/**
+ * Read signed 64 bit integer parameter
+ * @param context
+ * @param value
+ * @param mandatory
+ * @return
+ */
+scpi_bool_t SCPI_ParamInt64(scpi_t * context, int64_t * value, scpi_bool_t mandatory) {
+ return ParamSignUInt64(context, (uint64_t *) value, mandatory, TRUE);
+}
+
+/**
+ * Read unsigned 64 bit integer parameter
+ * @param context
+ * @param value
+ * @param mandatory
+ * @return
+ */
+scpi_bool_t SCPI_ParamUInt64(scpi_t * context, uint64_t * value, scpi_bool_t mandatory) {
+ return ParamSignUInt64(context, value, mandatory, FALSE);
+}
+
+/**
+ * Read character parameter
+ * @param context
+ * @param value
+ * @param len
+ * @param mandatory
+ * @return
+ */
+scpi_bool_t SCPI_ParamCharacters(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) {
+ scpi_bool_t result;
+ scpi_parameter_t param;
+
+ if (!value || !len) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ result = SCPI_Parameter(context, &param, mandatory);
+ if (result) {
+ switch (param.type) {
+ case SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA:
+ case SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA:
+ *value = param.ptr + 1;
+ *len = param.len - 2;
+ break;
+ default:
+ *value = param.ptr;
+ *len = param.len;
+ break;
+ }
+
+ /* TODO: return also parameter type (ProgramMnemonic, ArbitraryBlockProgramData, SingleQuoteProgramData, DoubleQuoteProgramData */
+ }
+
+ return result;
+}
+
+/**
+ * Get arbitrary block program data and returns pointer to data
+ * @param context
+ * @param value result pointer to data
+ * @param len result length of data
+ * @param mandatory
+ * @return
+ */
+scpi_bool_t SCPI_ParamArbitraryBlock(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) {
+ scpi_bool_t result;
+ scpi_parameter_t param;
+
+ if (!value || !len) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ result = SCPI_Parameter(context, &param, mandatory);
+ if (result) {
+ if (param.type == SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA) {
+ *value = param.ptr;
+ *len = param.len;
+ } else {
+ SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+ result = FALSE;
+ }
+ }
+
+ return result;
+}
+
+scpi_bool_t SCPI_ParamCopyText(scpi_t * context, char * buffer, size_t buffer_len, size_t * copy_len, scpi_bool_t mandatory) {
+ scpi_bool_t result;
+ scpi_parameter_t param;
+ size_t i_from;
+ size_t i_to;
+ char quote;
+
+ if (!buffer || !copy_len) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ result = SCPI_Parameter(context, &param, mandatory);
+ if (result) {
+
+ switch (param.type) {
+ case SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA:
+ case SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA:
+ quote = param.type == SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA ? '\'' : '"';
+ for (i_from = 1, i_to = 0; i_from < (size_t) (param.len - 1); i_from++) {
+ if (i_from >= buffer_len) {
+ break;
+ }
+ buffer[i_to] = param.ptr[i_from];
+ i_to++;
+ if (param.ptr[i_from] == quote) {
+ i_from++;
+ }
+ }
+ *copy_len = i_to;
+ if (i_to < buffer_len) {
+ buffer[i_to] = 0;
+ }
+ break;
+ default:
+ SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+ result = FALSE;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Convert parameter to choice
+ * @param context
+ * @param parameter - should be PROGRAM_MNEMONIC
+ * @param options - NULL terminated list of choices
+ * @param value - index to options
+ * @return
+ */
+scpi_bool_t SCPI_ParamToChoice(scpi_t * context, scpi_parameter_t * parameter, const scpi_choice_def_t * options, int32_t * value) {
+ size_t res;
+ scpi_bool_t result = FALSE;
+
+ if (!options || !value) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ if (parameter->type == SCPI_TOKEN_PROGRAM_MNEMONIC) {
+ for (res = 0; options[res].name; ++res) {
+ if (matchPattern(options[res].name, strlen(options[res].name), parameter->ptr, parameter->len, NULL)) {
+ *value = options[res].tag;
+ result = TRUE;
+ break;
+ }
+ }
+
+ if (!result) {
+ SCPI_ErrorPush(context, SCPI_ERROR_ILLEGAL_PARAMETER_VALUE);
+ }
+ } else {
+ SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR);
+ }
+
+ return result;
+}
+
+/**
+ * Find tag in choices and returns its first textual representation
+ * @param options specifications of choices numbers (patterns)
+ * @param tag numerical representatio of choice
+ * @param text result text
+ * @return TRUE if succesfule, else FALSE
+ */
+scpi_bool_t SCPI_ChoiceToName(const scpi_choice_def_t * options, int32_t tag, const char ** text) {
+ int i;
+
+ for (i = 0; options[i].name != NULL; i++) {
+ if (options[i].tag == tag) {
+ *text = options[i].name;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*
+ * Definition of BOOL choice list
+ */
+const scpi_choice_def_t scpi_bool_def[] = {
+ {"OFF", 0},
+ {"ON", 1},
+ SCPI_CHOICE_LIST_END /* termination of option list */
+};
+
+/**
+ * Read BOOL parameter (0,1,ON,OFF)
+ * @param context
+ * @param value
+ * @param mandatory
+ * @return
+ */
+scpi_bool_t SCPI_ParamBool(scpi_t * context, scpi_bool_t * value, scpi_bool_t mandatory) {
+ scpi_bool_t result;
+ scpi_parameter_t param;
+ int32_t intval;
+
+ if (!value) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ result = SCPI_Parameter(context, &param, mandatory);
+
+ if (result) {
+ if (param.type == SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA) {
+ SCPI_ParamToInt32(context, &param, &intval);
+ *value = intval ? TRUE : FALSE;
+ } else {
+ result = SCPI_ParamToChoice(context, &param, scpi_bool_def, &intval);
+ if (result) {
+ *value = intval ? TRUE : FALSE;
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Read value from list of options
+ * @param context
+ * @param options
+ * @param value
+ * @param mandatory
+ * @return
+ */
+scpi_bool_t SCPI_ParamChoice(scpi_t * context, const scpi_choice_def_t * options, int32_t * value, scpi_bool_t mandatory) {
+ scpi_bool_t result;
+ scpi_parameter_t param;
+
+ if (!options || !value) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ result = SCPI_Parameter(context, &param, mandatory);
+ if (result) {
+ result = SCPI_ParamToChoice(context, &param, options, value);
+ }
+
+ return result;
+}
+
+/**
+ * Parse one parameter and detect type
+ * @param state
+ * @param token
+ * @return
+ */
+int scpiParser_parseProgramData(lex_state_t * state, scpi_token_t * token) {
+ scpi_token_t tmp;
+ int result = 0;
+ int wsLen;
+ int suffixLen;
+ int realLen = 0;
+ realLen += scpiLex_WhiteSpace(state, &tmp);
+
+ if (result == 0) result = scpiLex_NondecimalNumericData(state, token);
+ if (result == 0) result = scpiLex_CharacterProgramData(state, token);
+ if (result == 0) {
+ result = scpiLex_DecimalNumericProgramData(state, token);
+ if (result != 0) {
+ wsLen = scpiLex_WhiteSpace(state, &tmp);
+ suffixLen = scpiLex_SuffixProgramData(state, &tmp);
+ if (suffixLen > 0) {
+ token->len += wsLen + suffixLen;
+ token->type = SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX;
+ result = token->len;
+ }
+ }
+ }
+
+ if (result == 0) result = scpiLex_StringProgramData(state, token);
+ if (result == 0) result = scpiLex_ArbitraryBlockProgramData(state, token);
+ if (result == 0) result = scpiLex_ProgramExpression(state, token);
+
+ realLen += scpiLex_WhiteSpace(state, &tmp);
+
+ return result + realLen;
+}
+
+/**
+ * Skip all parameters to correctly detect end of command line.
+ * @param state
+ * @param token
+ * @param numberOfParameters
+ * @return
+ */
+int scpiParser_parseAllProgramData(lex_state_t * state, scpi_token_t * token, int * numberOfParameters) {
+
+ int result;
+ scpi_token_t tmp;
+ int paramCount = 0;
+
+ token->len = -1;
+ token->type = SCPI_TOKEN_ALL_PROGRAM_DATA;
+ token->ptr = state->pos;
+
+
+ for (result = 1; result != 0; result = scpiLex_Comma(state, &tmp)) {
+ token->len += result;
+
+ result = scpiParser_parseProgramData(state, &tmp);
+ if (tmp.type != SCPI_TOKEN_UNKNOWN) {
+ token->len += result;
+ } else {
+ token->type = SCPI_TOKEN_UNKNOWN;
+ token->len = 0;
+ paramCount = -1;
+ break;
+ }
+ paramCount++;
+ }
+
+ if (numberOfParameters != NULL) {
+ *numberOfParameters = paramCount;
+ }
+ return token->len;
+}
+
+/**
+ * Skip complete command line - program header and parameters
+ * @param state
+ * @param buffer
+ * @param len
+ * @return
+ */
+int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, char * buffer, int len) {
+ lex_state_t lex_state;
+ scpi_token_t tmp;
+ int result = 0;
+
+ lex_state.buffer = lex_state.pos = buffer;
+ lex_state.len = len;
+ state->numberOfParameters = 0;
+
+ /* ignore whitespace at the begginig */
+ scpiLex_WhiteSpace(&lex_state, &tmp);
+
+ if (scpiLex_ProgramHeader(&lex_state, &state->programHeader) >= 0) {
+ if (scpiLex_WhiteSpace(&lex_state, &tmp) > 0) {
+ scpiParser_parseAllProgramData(&lex_state, &state->programData, &state->numberOfParameters);
+ } else {
+ invalidateToken(&state->programData, lex_state.pos);
+ }
+ } else {
+ invalidateToken(&state->programHeader, lex_state.buffer);
+ invalidateToken(&state->programData, lex_state.buffer);
+ }
+
+ if (result == 0) result = scpiLex_NewLine(&lex_state, &tmp);
+ if (result == 0) result = scpiLex_Semicolon(&lex_state, &tmp);
+
+ if (!scpiLex_IsEos(&lex_state) && (result == 0)) {
+ lex_state.pos++;
+
+ state->programHeader.len = 1;
+ state->programHeader.type = SCPI_TOKEN_INVALID;
+
+ invalidateToken(&state->programData, lex_state.buffer);
+ }
+
+ if (SCPI_TOKEN_SEMICOLON == tmp.type) {
+ state->termination = SCPI_MESSAGE_TERMINATION_SEMICOLON;
+ } else if (SCPI_TOKEN_NL == tmp.type) {
+ state->termination = SCPI_MESSAGE_TERMINATION_NL;
+ } else {
+ state->termination = SCPI_MESSAGE_TERMINATION_NONE;
+ }
+
+ return lex_state.pos - lex_state.buffer;
+}
+
+/**
+ * Check current command
+ * - suitable for one handle to multiple commands
+ * @param context
+ * @param cmd
+ * @return
+ */
+scpi_bool_t SCPI_IsCmd(scpi_t * context, const char * cmd) {
+ const char * pattern;
+
+ if (!context->param_list.cmd) {
+ return FALSE;
+ }
+
+ pattern = context->param_list.cmd->pattern;
+ return matchCommand(pattern, cmd, strlen(cmd), NULL, 0, 0);
+}
+
+#if USE_COMMAND_TAGS
+
+/**
+ * Return the .tag field of the matching scpi_command_t
+ * @param context
+ * @return
+ */
+int32_t SCPI_CmdTag(scpi_t * context) {
+ if (context->param_list.cmd) {
+ return context->param_list.cmd->tag;
+ } else {
+ return 0;
+ }
+}
+#endif /* USE_COMMAND_TAGS */
+
+scpi_bool_t SCPI_Match(const char * pattern, const char * value, size_t len) {
+ return matchCommand(pattern, value, len, NULL, 0, 0);
+}
+
+scpi_bool_t SCPI_CommandNumbers(scpi_t * context, int32_t * numbers, size_t len, int32_t default_value) {
+ return matchCommand(context->param_list.cmd->pattern, context->param_list.cmd_raw.data, context->param_list.cmd_raw.length, numbers, len, default_value);
+}
+
+/**
+ * If SCPI_Parameter() returns FALSE, this function can detect, if the parameter
+ * is just missing (TRUE) or if there was an error during processing of the command (FALSE)
+ * @param parameter
+ * @return
+ */
+scpi_bool_t SCPI_ParamIsValid(scpi_parameter_t * parameter) {
+ return parameter->type == SCPI_TOKEN_UNKNOWN ? FALSE : TRUE;
+}
+
+/**
+ * Returns TRUE if there was an error during parameter handling
+ * @param context
+ * @return
+ */
+scpi_bool_t SCPI_ParamErrorOccurred(scpi_t * context) {
+ return context->cmd_error;
+}
+
+/**
+ * Result binary array and swap bytes if needed (native endiannes != required endiannes)
+ * @param context
+ * @param array
+ * @param count
+ * @param item_size
+ * @param format
+ * @return
+ */
+static size_t produceResultArrayBinary(scpi_t * context, const void * array, size_t count, size_t item_size, scpi_array_format_t format) {
+
+ if (SCPI_GetNativeFormat() == format) {
+ switch (item_size) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ return SCPI_ResultArbitraryBlock(context, array, count * item_size);
+ default:
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return 0;
+ }
+ } else {
+ size_t result = 0;
+ size_t i;
+ switch (item_size) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ result += SCPI_ResultArbitraryBlockHeader(context, count * item_size);
+ break;
+ default:
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return 0;
+ }
+
+ switch (item_size) {
+ case 1:
+ result += SCPI_ResultArbitraryBlockData(context, array, count);
+ break;
+ case 2:
+ for (i = 0; i < count; i++) {
+ uint16_t val = SCPI_Swap16(((uint16_t*) array)[i]);
+ result += SCPI_ResultArbitraryBlockData(context, &val, item_size);
+ }
+ break;
+ case 4:
+ for (i = 0; i < count; i++) {
+ uint32_t val = SCPI_Swap32(((uint32_t*) array)[i]);
+ result += SCPI_ResultArbitraryBlockData(context, &val, item_size);
+ }
+ break;
+ case 8:
+ for (i = 0; i < count; i++) {
+ uint64_t val = SCPI_Swap64(((uint64_t*) array)[i]);
+ result += SCPI_ResultArbitraryBlockData(context, &val, item_size);
+ }
+ break;
+ }
+
+ return result;
+ }
+}
+
+
+#define RESULT_ARRAY(func) do {\
+ size_t result = 0;\
+ if (format == SCPI_FORMAT_ASCII) {\
+ size_t i;\
+ for (i = 0; i < count; i++) {\
+ result += func(context, array[i]);\
+ }\
+ } else {\
+ result = produceResultArrayBinary(context, array, count, sizeof(*array), format);\
+ }\
+ return result;\
+} while(0)
+
+/**
+ * Result array of signed 8bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return
+ */
+size_t SCPI_ResultArrayInt8(scpi_t * context, const int8_t * array, size_t count, scpi_array_format_t format) {
+ RESULT_ARRAY(SCPI_ResultInt8);
+}
+
+/**
+ * Result array of unsigned 8bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return
+ */
+size_t SCPI_ResultArrayUInt8(scpi_t * context, const uint8_t * array, size_t count, scpi_array_format_t format) {
+ RESULT_ARRAY(SCPI_ResultUInt8);
+}
+
+/**
+ * Result array of signed 16bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return
+ */
+size_t SCPI_ResultArrayInt16(scpi_t * context, const int16_t * array, size_t count, scpi_array_format_t format) {
+ RESULT_ARRAY(SCPI_ResultInt16);
+}
+
+/**
+ * Result array of unsigned 16bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return
+ */
+size_t SCPI_ResultArrayUInt16(scpi_t * context, const uint16_t * array, size_t count, scpi_array_format_t format) {
+ RESULT_ARRAY(SCPI_ResultUInt16);
+}
+
+/**
+ * Result array of signed 32bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return
+ */
+size_t SCPI_ResultArrayInt32(scpi_t * context, const int32_t * array, size_t count, scpi_array_format_t format) {
+ RESULT_ARRAY(SCPI_ResultInt32);
+}
+
+/**
+ * Result array of unsigned 32bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return
+ */
+size_t SCPI_ResultArrayUInt32(scpi_t * context, const uint32_t * array, size_t count, scpi_array_format_t format) {
+ RESULT_ARRAY(SCPI_ResultUInt32);
+}
+
+/**
+ * Result array of signed 64bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return
+ */
+size_t SCPI_ResultArrayInt64(scpi_t * context, const int64_t * array, size_t count, scpi_array_format_t format) {
+ RESULT_ARRAY(SCPI_ResultInt64);
+}
+
+/**
+ * Result array of unsigned 64bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return
+ */
+size_t SCPI_ResultArrayUInt64(scpi_t * context, const uint64_t * array, size_t count, scpi_array_format_t format) {
+ RESULT_ARRAY(SCPI_ResultUInt64);
+}
+
+/**
+ * Result array of floats
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return
+ */
+size_t SCPI_ResultArrayFloat(scpi_t * context, const float * array, size_t count, scpi_array_format_t format) {
+ RESULT_ARRAY(SCPI_ResultFloat);
+}
+
+/**
+ * Result array of doubles
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return
+ */
+size_t SCPI_ResultArrayDouble(scpi_t * context, const double * array, size_t count, scpi_array_format_t format) {
+ RESULT_ARRAY(SCPI_ResultDouble);
+}
+
+/*
+ * Template macro to generate all SCPI_ParamArrayXYZ function
+ */
+#define PARAM_ARRAY_TEMPLATE(func) do{\
+ if (format != SCPI_FORMAT_ASCII) return FALSE;\
+ for (*o_count = 0; *o_count < i_count; (*o_count)++) {\
+ if (!func(context, &data[*o_count], mandatory)) {\
+ break;\
+ }\
+ mandatory = FALSE;\
+ }\
+ return mandatory ? FALSE : TRUE;\
+}while(0)
+
+/**
+ * Read list of values up to i_count
+ * @param context
+ * @param data - array to fill
+ * @param i_count - number of elements of data
+ * @param o_count - real number of filled elements
+ * @param mandatory
+ * @return TRUE on success
+ */
+scpi_bool_t SCPI_ParamArrayInt32(scpi_t * context, int32_t *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory) {
+ PARAM_ARRAY_TEMPLATE(SCPI_ParamInt32);
+}
+
+/**
+ * Read list of values up to i_count
+ * @param context
+ * @param data - array to fill
+ * @param i_count - number of elements of data
+ * @param o_count - real number of filled elements
+ * @param mandatory
+ * @return TRUE on success
+ */
+scpi_bool_t SCPI_ParamArrayUInt32(scpi_t * context, uint32_t *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory) {
+ PARAM_ARRAY_TEMPLATE(SCPI_ParamUInt32);
+}
+
+/**
+ * Read list of values up to i_count
+ * @param context
+ * @param data - array to fill
+ * @param i_count - number of elements of data
+ * @param o_count - real number of filled elements
+ * @param mandatory
+ * @return TRUE on success
+ */
+scpi_bool_t SCPI_ParamArrayInt64(scpi_t * context, int64_t *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory) {
+ PARAM_ARRAY_TEMPLATE(SCPI_ParamInt64);
+}
+
+/**
+ * Read list of values up to i_count
+ * @param context
+ * @param data - array to fill
+ * @param i_count - number of elements of data
+ * @param o_count - real number of filled elements
+ * @param mandatory
+ * @return TRUE on success
+ */
+scpi_bool_t SCPI_ParamArrayUInt64(scpi_t * context, uint64_t *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory) {
+ PARAM_ARRAY_TEMPLATE(SCPI_ParamUInt64);
+}
+
+/**
+ * Read list of values up to i_count
+ * @param context
+ * @param data - array to fill
+ * @param i_count - number of elements of data
+ * @param o_count - real number of filled elements
+ * @param mandatory
+ * @return TRUE on success
+ */
+scpi_bool_t SCPI_ParamArrayFloat(scpi_t * context, float *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory) {
+ PARAM_ARRAY_TEMPLATE(SCPI_ParamFloat);
+}
+
+/**
+ * Read list of values up to i_count
+ * @param context
+ * @param data - array to fill
+ * @param i_count - number of elements of data
+ * @param o_count - real number of filled elements
+ * @param mandatory
+ * @return TRUE on success
+ */
+scpi_bool_t SCPI_ParamArrayDouble(scpi_t * context, double *data, size_t i_count, size_t *o_count, scpi_array_format_t format, scpi_bool_t mandatory) {
+ PARAM_ARRAY_TEMPLATE(SCPI_ParamDouble);
+}
diff --git a/third_party/libscpi/src/parser_private.h b/third_party/libscpi/src/parser_private.h
new file mode 100644
index 00000000..bb8642fa
--- /dev/null
+++ b/third_party/libscpi/src/parser_private.h
@@ -0,0 +1,56 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file parser_private.h
+ *
+ * @brief SCPI Parser private definitions
+ *
+ *
+ */
+
+#ifndef SCPI_PARSER_PRIVATE_H
+#define SCPI_PARSER_PRIVATE_H
+
+#include "scpi/types.h"
+#include "utils_private.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int scpiParser_parseProgramData(lex_state_t * state, scpi_token_t * token) LOCAL;
+ int scpiParser_parseAllProgramData(lex_state_t * state, scpi_token_t * token, int * numberOfParameters) LOCAL;
+ int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, char * buffer, int len) LOCAL;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_PARSER_PRIVATE_H */
+
diff --git a/third_party/libscpi/src/scpi.g b/third_party/libscpi/src/scpi.g
new file mode 100644
index 00000000..a3993ffd
--- /dev/null
+++ b/third_party/libscpi/src/scpi.g
@@ -0,0 +1,141 @@
+grammar scpi;
+
+terminatedProgramMessage
+ : programMessage NL? EOF
+ ;
+
+programMessage
+ : programMessageUnit (SEMICOLON programMessageUnit)*
+ ;
+
+
+programMessageUnit
+ : WS* programHeader (WS programData (COMMA programData)*)?
+ ;
+
+programHeader
+ : compoundProgramHeader
+ | commonProgramHeader
+ ;
+
+compoundProgramHeader
+ : COLON? PROGRAM_MNEMONIC (COLON PROGRAM_MNEMONIC)* QUESTION?
+ ;
+
+commonProgramHeader
+ : STAR PROGRAM_MNEMONIC QUESTION?
+ ;
+
+programDataSeparator
+ : WS*
+ ;
+
+programData
+ : WS* programDataType WS*
+ ;
+
+programDataType
+ : nondecimalNumericProgramData
+ | characterProgramData
+ | decimalNumericProgramData
+ | stringProgramData
+ | arbitraryBlockProgramData
+ | expressionProgramData
+// | suffixProgramData
+ ;
+
+nondecimalNumericProgramData
+ : HEXNUM
+ | OCTNUM
+ | BINNUM
+ ;
+
+characterProgramData
+ : PROGRAM_MNEMONIC
+ ;
+
+decimalNumericProgramData
+ : DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX
+ ;
+
+//suffixProgramData
+// : PROGRAM_MNEMONIC//SUFFIX_PROGRAM_DATA
+// ;
+
+stringProgramData
+ : SINGLE_QUOTE_PROGRAM_DATA
+ | DOUBLE_QUOTE_PROGRAM_DATA
+ ;
+
+expressionProgramData
+ : PROGRAM_EXPRESSION
+ ;
+
+// support only nonzero prefix
+arbitraryBlockProgramData
+ : SHARP NONZERO_DIGIT NUMBER .*
+ ;
+
+PROGRAM_MNEMONIC : ALPHA (ALPHA | DIGIT | UNDERSCORE)*;
+HEXNUM : SHARP H HEXDIGIT*;
+BINNUM : SHARP Q OCTDIGIT*;
+OCTNUM : SHARP B BINDIGIT*;
+UNDERSCORE : '_';
+SEMICOLON : ';';
+QUESTION : '?';
+COLON : ':';
+COMMA : ',';
+STAR : '*';
+NL : '\r'? '\n' ;
+WS : (SPACE | TAB);
+
+DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX : DECIMAL_NUMERIC_PROGRAM_DATA WS* (SUFFIX_PROGRAM_DATA)?;
+fragment DECIMAL_NUMERIC_PROGRAM_DATA : MANTISA WS* (EXPONENT)?;
+SINGLE_QUOTE_PROGRAM_DATA : SINGLE_QUOTE ( (NON_SINGLE_QUOTE) | (SINGLE_QUOTE SINGLE_QUOTE))* SINGLE_QUOTE;
+DOUBLE_QUOTE_PROGRAM_DATA : DOUBLE_QUOTE ( (NON_DOUBLE_QUOTE) | (DOUBLE_QUOTE DOUBLE_QUOTE))* DOUBLE_QUOTE;
+//SUFFIX_PROGRAM_DATA : SLASH? (ALPHA+ (MINUS? DIGIT)?) ((SLASH | DOT) (ALPHA+ (MINUS? DIGIT)?))*;
+fragment SUFFIX_PROGRAM_DATA : SLASH? ALPHA+ ((SLASH | DOT) ALPHA+)*;
+//fragment SUFFIX_PROGRAM_DATA : ALPHA+;
+
+fragment PROGRAM_EXPRESSION_CHARACTER : (SPACE | '!' | '$'..'&' | '*'..':' | '<' ..'~');
+PROGRAM_EXPRESSION : LBRACKET PROGRAM_EXPRESSION_CHARACTER RBRACKET;
+
+fragment PLUSMN : (PLUS | MINUS);
+fragment MANTISA : PLUSMN? ( (NUMBER) | (NUMBER DOT NUMBER?) | (DOT NUMBER));
+
+//fragment EXPONENT : WS* E WS* PLUSMN? NUMBER;
+fragment EXPONENT : E WS* PLUSMN? NUMBER;
+
+fragment NUMBER : DIGIT+;
+
+fragment LBRACKET : '(';
+fragment RBRACKET : ')';
+
+fragment ALPHA : ('a'..'z'|'A'..'Z');
+fragment DIGIT : ('0'..'9');
+fragment NONZERO_DIGIT : ('1'..'9');
+
+fragment HEXDIGIT : (DIGIT | 'a'..'f' | 'A'..'F');
+fragment OCTDIGIT : ('0'..'7');
+fragment BINDIGIT : ('0' | '1');
+
+fragment SHARP : '#';
+
+fragment E : ('E'|'e');
+fragment H : ('H'|'h');
+fragment Q : ('Q'|'q');
+fragment B : ('B'|'b');
+
+fragment SPACE : ' ';
+fragment TAB : '\t';
+
+fragment PLUS : '+';
+fragment MINUS : '-';
+fragment DOT : '.';
+fragment SLASH : '/';
+fragment SINGLE_QUOTE : '\'';
+fragment DOUBLE_QUOTE : '"';
+fragment NON_SINGLE_QUOTE : ~SINGLE_QUOTE;
+fragment NON_DOUBLE_QUOTE : ~DOUBLE_QUOTE;
+
+
diff --git a/third_party/libscpi/src/units.c b/third_party/libscpi/src/units.c
new file mode 100644
index 00000000..e68af418
--- /dev/null
+++ b/third_party/libscpi/src/units.c
@@ -0,0 +1,512 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_units.c
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief SCPI units
+ *
+ *
+ */
+
+#include <string.h>
+#include "scpi/parser.h"
+#include "scpi/units.h"
+#include "utils_private.h"
+#include "scpi/utils.h"
+#include "scpi/error.h"
+#include "lexer_private.h"
+
+
+/*
+ * multipliers IEEE 488.2-1992 tab 7-2
+ * 1E18 EX
+ * 1E15 PE
+ * 1E12 T
+ * 1E9 G
+ * 1E6 MA (use M for OHM and HZ)
+ * 1E3 K
+ * 1E-3 M (disaalowed for OHM and HZ)
+ * 1E-6 U
+ * 1E-9 N
+ * 1E-12 P
+ * 1E-15 F
+ * 1E-18 A
+ */
+
+/*
+ * units definition IEEE 488.2-1992 tab 7-1
+ */
+const scpi_unit_def_t scpi_units_def[] = {
+#if USE_UNITS_PARTICLES
+ /* Absorbet dose */
+ {/* name */ "GY", /* unit */ SCPI_UNIT_GRAY, /* mult */ 1},
+
+ /* Activity of radionuclide */
+ {/* name */ "BQ", /* unit */ SCPI_UNIT_BECQUEREL, /* mult */ 1},
+
+ /* Amount of substance */
+ {/* name */ "MOL", /* unit */ SCPI_UNIT_MOLE, /* mult */ 1},
+
+ /* Dose equivalent */
+ {/* name */ "NSV", /* unit */ SCPI_UNIT_SIEVERT, /* mult */ 1e-9},
+ {/* name */ "USV", /* unit */ SCPI_UNIT_SIEVERT, /* mult */ 1e-6},
+ {/* name */ "MSV", /* unit */ SCPI_UNIT_SIEVERT, /* mult */ 1e-3},
+ {/* name */ "SV", /* unit */ SCPI_UNIT_SIEVERT, /* mult */ 1},
+ {/* name */ "KSV", /* unit */ SCPI_UNIT_SIEVERT, /* mult */ 1e3},
+ {/* name */ "MASV", /* unit */ SCPI_UNIT_SIEVERT, /* mult */ 1e6},
+
+ /* Energy */
+ {/* name */ "EV", /* unit */ SCPI_UNIT_ELECTRONVOLT, /* mult */ 1},
+ {/* name */ "KEV", /* unit */ SCPI_UNIT_ELECTRONVOLT, /* mult */ 1e3},
+ {/* name */ "MAEV", /* unit */ SCPI_UNIT_ELECTRONVOLT, /* mult */ 1e6},
+ {/* name */ "GEV", /* unit */ SCPI_UNIT_ELECTRONVOLT, /* mult */ 1e9},
+ {/* name */ "TEV", /* unit */ SCPI_UNIT_ELECTRONVOLT, /* mult */ 1e12},
+
+ /* Mass */
+ {/* name */ "U", /* unit */ SCPI_UNIT_ATOMIC_MASS, /* mult */ 1},
+#endif /* USE_UNITS_PARTICLES */
+
+#if USE_UNITS_ANGLE
+ /* Angle */
+ {/* name */ "DEG", /* unit */ SCPI_UNIT_DEGREE, /* mult */ 1},
+ {/* name */ "GON", /* unit */ SCPI_UNIT_GRADE, /* mult */ 1},
+ {/* name */ "MNT", /* unit */ SCPI_UNIT_DEGREE, /* mult */ 1. / 60.},
+ {/* name */ "RAD", /* unit */ SCPI_UNIT_RADIAN, /* mult */ 1},
+ {/* name */ "SEC", /* unit */ SCPI_UNIT_DEGREE, /* mult */ 1. / 3600.},
+ {/* name */ "REV", /* unit */ SCPI_UNIT_REVOLUTION, /* mult */ 1},
+ {/* name */ "RS", /* unit */ SCPI_UNIT_STERADIAN, /* mult */ 1},
+#endif /* USE_UNITS_ANGLE */
+
+#if USE_UNITS_ELECTRIC
+ /* Electric - capacitance */
+ {/* name */ "PF", /* unit */ SCPI_UNIT_FARAD, /* mult */ 1e-12},
+ {/* name */ "NF", /* unit */ SCPI_UNIT_FARAD, /* mult */ 1e-9},
+ {/* name */ "UF", /* unit */ SCPI_UNIT_FARAD, /* mult */ 1e-6},
+ {/* name */ "MF", /* unit */ SCPI_UNIT_FARAD, /* mult */ 1e-3},
+ {/* name */ "F", /* unit */ SCPI_UNIT_FARAD, /* mult */ 1},
+
+ /* Electric - current */
+ {/* name */ "UA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-6},
+ {/* name */ "MA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e-3},
+ {/* name */ "A", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1},
+ {/* name */ "KA", /* unit */ SCPI_UNIT_AMPER, /* mult */ 1e3},
+
+ /* Electric - potential */
+ {/* name */ "UV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-6},
+ {/* name */ "MV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e-3},
+ {/* name */ "V", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1},
+ {/* name */ "KV", /* unit */ SCPI_UNIT_VOLT, /* mult */ 1e3},
+
+ /* Electric - resistance */
+ {/* name */ "OHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1},
+ {/* name */ "KOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e3},
+ {/* name */ "MOHM", /* unit */ SCPI_UNIT_OHM, /* mult */ 1e6},
+
+ /* Inductance */
+ {/* name */ "UH", /* unit */ SCPI_UNIT_HENRY, /* mult */ 1e-6},
+ {/* name */ "MH", /* unit */ SCPI_UNIT_HENRY, /* mult */ 1e-3},
+ {/* name */ "H", /* unit */ SCPI_UNIT_HENRY, /* mult */ 1},
+#endif /* USE_UNITS_ELECTRIC */
+
+#if USE_UNITS_ELECTRIC_CHARGE_CONDUCTANCE
+ /* Electric - charge */
+ {/* name */ "C", /* unit */ SCPI_UNIT_COULOMB, /* mult */ 1},
+
+ /* Electric - conductance */
+ {/* name */ "USIE", /* unit */ SCPI_UNIT_SIEMENS, /* mult */ 1e-6},
+ {/* name */ "MSIE", /* unit */ SCPI_UNIT_SIEMENS, /* mult */ 1e-3},
+ {/* name */ "SIE", /* unit */ SCPI_UNIT_SIEMENS, /* mult */ 1},
+#endif /* USE_UNITS_ELECTRIC_CHARGE_CONDUCTANCE */
+
+#if USE_UNITS_ENERGY_FORCE_MASS
+ /* Energy */
+ {/* name */ "J", /* unit */ SCPI_UNIT_JOULE, /* mult */ 1},
+ {/* name */ "KJ", /* unit */ SCPI_UNIT_JOULE, /* mult */ 1e3},
+ {/* name */ "MAJ", /* unit */ SCPI_UNIT_JOULE, /* mult */ 1e6},
+
+ /* Force */
+ {/* name */ "N", /* unit */ SCPI_UNIT_NEWTON, /* mult */ 1},
+ {/* name */ "KN", /* unit */ SCPI_UNIT_NEWTON, /* mult */ 1e3},
+
+ /* Pressure */
+ {/* name */ "ATM", /* unit */ SCPI_UNIT_ATMOSPHERE, /* mult */ 1},
+ {/* name */ "INHG", /* unit */ SCPI_UNIT_INCH_OF_MERCURY, /* mult */ 1},
+ {/* name */ "MMHG", /* unit */ SCPI_UNIT_MM_OF_MERCURY, /* mult */ 1},
+
+ {/* name */ "TORR", /* unit */ SCPI_UNIT_TORT, /* mult */ 1},
+ {/* name */ "BAR", /* unit */ SCPI_UNIT_BAR, /* mult */ 1},
+
+ {/* name */ "PAL", /* unit */ SCPI_UNIT_PASCAL, /* mult */ 1},
+ {/* name */ "KPAL", /* unit */ SCPI_UNIT_PASCAL, /* mult */ 1e3},
+ {/* name */ "MAPAL", /* unit */ SCPI_UNIT_PASCAL, /* mult */ 1e6},
+
+ /* Viscosity kinematic */
+ {/* name */ "ST", /* unit */ SCPI_UNIT_STROKES, /* mult */ 1},
+
+ /* Viscosity dynamic */
+ {/* name */ "P", /* unit */ SCPI_UNIT_POISE, /* mult */ 1},
+
+ /* Viscosity dynamic */
+ {/* name */ "L", /* unit */ SCPI_UNIT_LITER, /* mult */ 1},
+
+ /* Mass */
+ {/* name */ "MG", /* unit */ SCPI_UNIT_KILOGRAM, /* mult */ 1e-6},
+ {/* name */ "G", /* unit */ SCPI_UNIT_KILOGRAM, /* mult */ 1e-3},
+ {/* name */ "KG", /* unit */ SCPI_UNIT_KILOGRAM, /* mult */ 1},
+ {/* name */ "TNE", /* unit */ SCPI_UNIT_KILOGRAM, /* mult */ 1000},
+#endif /* USE_UNITS_ENERGY_FORCE_MASS */
+
+#if USE_UNITS_FREQUENCY
+ /* Frequency */
+ {/* name */ "HZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1},
+ {/* name */ "KHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e3},
+ {/* name */ "MHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e6},
+ {/* name */ "GHZ", /* unit */ SCPI_UNIT_HERTZ, /* mult */ 1e9},
+#endif /* USE_UNITS_FREQUENCY */
+
+#if USE_UNITS_DISTANCE
+ /* Length */
+ {/* name */ "ASU", /* unit */ SCPI_UNIT_ASTRONOMIC_UNIT, /* mult */ 1},
+ {/* name */ "PRS", /* unit */ SCPI_UNIT_PARSEC, /* mult */ 1},
+#if USE_UNITS_IMPERIAL
+ {/* name */ "IN", /* unit */ SCPI_UNIT_INCH, /* mult */ 1},
+ {/* name */ "FT", /* unit */ SCPI_UNIT_FOOT, /* mult */ 1},
+ {/* name */ "MI", /* unit */ SCPI_UNIT_MILE, /* mult */ 1},
+ {/* name */ "NAMI", /* unit */ SCPI_UNIT_NAUTICAL_MILE, /* mult */ 1},
+#endif /* USE_UNITS_IMPERIAL */
+
+ {/* name */ "NM", /* unit */ SCPI_UNIT_METER, /* mult */ 1e-9},
+ {/* name */ "UM", /* unit */ SCPI_UNIT_METER, /* mult */ 1e-6},
+ {/* name */ "MM", /* unit */ SCPI_UNIT_METER, /* mult */ 1e-3},
+ {/* name */ "M", /* unit */ SCPI_UNIT_METER, /* mult */ 1},
+ {/* name */ "KM", /* unit */ SCPI_UNIT_METER, /* mult */ 1e3},
+#endif /* USE_UNITS_DISTANCE */
+
+#if USE_UNITS_LIGHT
+ /* Illuminance */
+ {/* name */ "LX", /* unit */ SCPI_UNIT_LUX, /* mult */ 1},
+
+ /* Luminous flux */
+ {/* name */ "LM", /* unit */ SCPI_UNIT_LUMEN, /* mult */ 1},
+
+ /* Luminous intensity */
+ {/* name */ "CD", /* unit */ SCPI_UNIT_CANDELA, /* mult */ 1},
+#endif /* USE_UNITS_LIGHT */
+
+#if USE_UNITS_MAGNETIC
+ /* Magnetic flux */
+ {/* name */ "WB", /* unit */ SCPI_UNIT_WEBER, /* mult */ 1},
+
+ /* Magnetic induction */
+ {/* name */ "NT", /* unit */ SCPI_UNIT_TESLA, /* mult */ 1e-9},
+ {/* name */ "UT", /* unit */ SCPI_UNIT_TESLA, /* mult */ 1e-6},
+ {/* name */ "MT", /* unit */ SCPI_UNIT_TESLA, /* mult */ 1e-3},
+ {/* name */ "T", /* unit */ SCPI_UNIT_TESLA, /* mult */ 1},
+#endif /* USE_UNITS_MAGNETIC */
+
+#if USE_UNITS_POWER
+ /* Power */
+ {/* name */ "W", /* unit */ SCPI_UNIT_WATT, /* mult */ 1},
+ {/* name */ "DBM", /* unit */ SCPI_UNIT_DBM, /* mult */ 1},
+ {/* name */ "DBMW", /* unit */ SCPI_UNIT_DBM, /* mult */ 1},
+#endif /* USE_UNITS_POWER */
+
+#if USE_UNITS_RATIO
+ /* Ratio */
+ {/* name */ "DB", /* unit */ SCPI_UNIT_DECIBEL, /* mult */ 1},
+ {/* name */ "PCT", /* unit */ SCPI_UNIT_UNITLESS, /* mult */ 1e-2},
+ {/* name */ "PPM", /* unit */ SCPI_UNIT_UNITLESS, /* mult */ 1e-6},
+#endif /* USE_UNITS_RATIO */
+
+#if USE_UNITS_TEMPERATURE
+ /* Temperature */
+ {/* name */ "CEL", /* unit */ SCPI_UNIT_CELSIUS, /* mult */ 1},
+#if USE_UNITS_IMPERIAL
+ {/* name */ "FAR", /* unit */ SCPI_UNIT_FAHRENHEIT, /* mult */ 1},
+#endif /* USE_UNITS_IMPERIAL */
+ {/* name */ "K", /* unit */ SCPI_UNIT_KELVIN, /* mult */ 1},
+#endif /* USE_UNITS_TEMPERATURE */
+
+#if USE_UNITS_TIME
+ /* Time */
+ {/* name */ "PS", /* unit */ SCPI_UNIT_SECOND, /* mult */ 1e-12},
+ {/* name */ "NS", /* unit */ SCPI_UNIT_SECOND, /* mult */ 1e-9},
+ {/* name */ "US", /* unit */ SCPI_UNIT_SECOND, /* mult */ 1e-6},
+ {/* name */ "MS", /* unit */ SCPI_UNIT_SECOND, /* mult */ 1e-3},
+ {/* name */ "S", /* unit */ SCPI_UNIT_SECOND, /* mult */ 1},
+ {/* name */ "MIN", /* unit */ SCPI_UNIT_SECOND, /* mult */ 60},
+ {/* name */ "HR", /* unit */ SCPI_UNIT_SECOND, /* mult */ 3600},
+ {/* name */ "D", /* unit */ SCPI_UNIT_DAY, /* mult */ 1},
+ {/* name */ "ANN", /* unit */ SCPI_UNIT_YEAR, /* mult */ 1},
+#endif /* USE_UNITS_TIME */
+
+ SCPI_UNITS_LIST_END,
+};
+
+/*
+ * Special number values definition
+ */
+const scpi_choice_def_t scpi_special_numbers_def[] = {
+ {/* name */ "MINimum", /* type */ SCPI_NUM_MIN},
+ {/* name */ "MAXimum", /* type */ SCPI_NUM_MAX},
+ {/* name */ "DEFault", /* type */ SCPI_NUM_DEF},
+ {/* name */ "UP", /* type */ SCPI_NUM_UP},
+ {/* name */ "DOWN", /* type */ SCPI_NUM_DOWN},
+ {/* name */ "NAN", /* type */ SCPI_NUM_NAN},
+ {/* name */ "INFinity", /* type */ SCPI_NUM_INF},
+ {/* name */ "NINF", /* type */ SCPI_NUM_NINF},
+ {/* name */ "AUTO", /* type */ SCPI_NUM_AUTO},
+ SCPI_CHOICE_LIST_END,
+};
+
+/**
+ * Convert string describing unit to its representation
+ * @param units units patterns
+ * @param unit text representation of unknown unit
+ * @param len length of text representation
+ * @return pointer of related unit definition or NULL
+ */
+static const scpi_unit_def_t * translateUnit(const scpi_unit_def_t * units, const char * unit, size_t len) {
+ int i;
+
+ if (units == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; units[i].name != NULL; i++) {
+ if (compareStr(unit, len, units[i].name, strlen(units[i].name))) {
+ return &units[i];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Convert unit definition to string
+ * @param units units definitions (patterns)
+ * @param unit type of unit
+ * @return string representation of unit
+ */
+static const char * translateUnitInverse(const scpi_unit_def_t * units, const scpi_unit_t unit) {
+ int i;
+
+ if (units == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; units[i].name != NULL; i++) {
+ if ((units[i].unit == unit) && (units[i].mult == 1)) {
+ return units[i].name;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Transform number to base units
+ * @param context
+ * @param unit text representation of unit
+ * @param len length of text representation
+ * @param value preparsed numeric value
+ * @return TRUE if value parameter was converted to base units
+ */
+static scpi_bool_t transformNumber(scpi_t * context, const char * unit, size_t len, scpi_number_t * value) {
+ size_t s;
+ const scpi_unit_def_t * unitDef;
+ s = skipWhitespace(unit, len);
+
+ if (s == len) {
+ value->unit = SCPI_UNIT_NONE;
+ return TRUE;
+ }
+
+ unitDef = translateUnit(context->units, unit + s, len - s);
+
+ if (unitDef == NULL) {
+ SCPI_ErrorPush(context, SCPI_ERROR_INVALID_SUFFIX);
+ return FALSE;
+ }
+
+ value->content.value *= unitDef->mult;
+ value->unit = unitDef->unit;
+
+ return TRUE;
+}
+
+/**
+ * Parse parameter as number, number with unit or special value (min, max, default, ...)
+ * @param context
+ * @param value return value
+ * @param mandatory if the parameter is mandatory
+ * @return
+ */
+scpi_bool_t SCPI_ParamNumber(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, scpi_bool_t mandatory) {
+ scpi_token_t token;
+ lex_state_t state;
+ scpi_parameter_t param;
+ scpi_bool_t result;
+ int32_t tag;
+
+ if (!value) {
+ SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+ return FALSE;
+ }
+
+ result = SCPI_Parameter(context, &param, mandatory);
+
+ if (!result) {
+ return result;
+ }
+
+ state.buffer = param.ptr;
+ state.pos = state.buffer;
+ state.len = param.len;
+
+ switch (param.type) {
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+ case SCPI_TOKEN_HEXNUM:
+ case SCPI_TOKEN_OCTNUM:
+ case SCPI_TOKEN_BINNUM:
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+ case SCPI_TOKEN_PROGRAM_MNEMONIC:
+ value->unit = SCPI_UNIT_NONE;
+ value->special = FALSE;
+ result = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ switch (param.type) {
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+ case SCPI_TOKEN_PROGRAM_MNEMONIC:
+ value->base = 10;
+ break;
+ case SCPI_TOKEN_BINNUM:
+ value->base = 2;
+ break;
+ case SCPI_TOKEN_HEXNUM:
+ value->base = 16;
+ break;
+ case SCPI_TOKEN_OCTNUM:
+ value->base = 8;
+ break;
+ default:
+ break;
+ }
+
+ switch (param.type) {
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA:
+ SCPI_ParamToDouble(context, &param, &(value->content.value));
+ break;
+ case SCPI_TOKEN_HEXNUM:
+ SCPI_ParamToDouble(context, &param, &(value->content.value));
+ break;
+ case SCPI_TOKEN_OCTNUM:
+ SCPI_ParamToDouble(context, &param, &(value->content.value));
+ break;
+ case SCPI_TOKEN_BINNUM:
+ SCPI_ParamToDouble(context, &param, &(value->content.value));
+ break;
+ case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX:
+ scpiLex_DecimalNumericProgramData(&state, &token);
+ scpiLex_WhiteSpace(&state, &token);
+ scpiLex_SuffixProgramData(&state, &token);
+
+ SCPI_ParamToDouble(context, &param, &(value->content.value));
+
+ result = transformNumber(context, token.ptr, token.len, value);
+ break;
+ case SCPI_TOKEN_PROGRAM_MNEMONIC:
+ scpiLex_WhiteSpace(&state, &token);
+ scpiLex_CharacterProgramData(&state, &token);
+
+ /* convert string to special number type */
+ result = SCPI_ParamToChoice(context, &token, special, &tag);
+
+ value->special = TRUE;
+ value->content.tag = tag;
+
+ break;
+ default:
+ result = FALSE;
+ }
+
+ return result;
+}
+
+/**
+ * Convert scpi_number_t to string
+ * @param context
+ * @param value number value
+ * @param str target string
+ * @param len max length of string including null-character termination
+ * @return number of chars written to string
+ */
+size_t SCPI_NumberToStr(scpi_t * context, const scpi_choice_def_t * special, scpi_number_t * value, char * str, size_t len) {
+ const char * type;
+ const char * unit;
+ size_t result;
+
+ if (!value || !str || len==0) {
+ return 0;
+ }
+
+ if (value->special) {
+ if (SCPI_ChoiceToName(special, value->content.tag, &type)) {
+ strncpy(str, type, len);
+ result = SCPIDEFINE_strnlen(str, len - 1);
+ str[result] = '\0';
+ return result;
+ } else {
+ str[0] = '\0';
+ return 0;
+ }
+ }
+
+ result = SCPI_DoubleToStr(value->content.value, str, len);
+
+ if (result + 1 < len) {
+ unit = translateUnitInverse(context->units, value->unit);
+
+ if (unit) {
+ strncat(str, " ", len - result);
+ if (result + 2 < len) {
+ strncat(str, unit, len - result - 1);
+ }
+ result = strlen(str);
+ }
+ }
+
+ return result;
+}
diff --git a/third_party/libscpi/src/utils.c b/third_party/libscpi/src/utils.c
new file mode 100644
index 00000000..328f8be7
--- /dev/null
+++ b/third_party/libscpi/src/utils.c
@@ -0,0 +1,1142 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer, Richard.hmm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_utils.c
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief Conversion routines and string manipulation routines
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#include "utils_private.h"
+#include "scpi/utils.h"
+
+static size_t patternSeparatorShortPos(const char * pattern, size_t len);
+static size_t patternSeparatorPos(const char * pattern, size_t len);
+static size_t cmdSeparatorPos(const char * cmd, size_t len);
+
+/**
+ * Find the first occurrence in str of a character in set.
+ * @param str
+ * @param size
+ * @param set
+ * @return
+ */
+char * strnpbrk(const char *str, size_t size, const char *set) {
+ const char *scanp;
+ long c, sc;
+ const char * strend = str + size;
+
+ while ((strend != str) && ((c = *str++) != 0)) {
+ for (scanp = set; (sc = *scanp++) != '\0';)
+ if (sc == c)
+ return ((char *) (str - 1));
+ }
+ return (NULL);
+}
+
+/**
+ * Converts signed/unsigned 32 bit integer value to string in specific base
+ * @param val integer value
+ * @param str converted textual representation
+ * @param len string buffer length
+ * @param base output base
+ * @param sign
+ * @return number of bytes written to str (without '\0')
+ */
+size_t UInt32ToStrBaseSign(uint32_t val, char * str, size_t len, int8_t base, scpi_bool_t sign) {
+ const char digits[] = "0123456789ABCDEF";
+
+#define ADD_CHAR(c) if (pos < len) str[pos++] = (c)
+ uint32_t x = 0;
+ int_fast8_t digit;
+ size_t pos = 0;
+ uint32_t uval = val;
+
+ if (uval == 0) {
+ ADD_CHAR('0');
+ } else {
+
+ switch (base) {
+ case 2:
+ x = 0x80000000L;
+ break;
+ case 8:
+ x = 0x40000000L;
+ break;
+ default:
+ case 10:
+ base = 10;
+ x = 1000000000L;
+ break;
+ case 16:
+ x = 0x10000000L;
+ break;
+ }
+
+ /* add sign for numbers in base 10 */
+ if (sign && ((int32_t) val < 0) && (base == 10)) {
+ uval = -val;
+ ADD_CHAR('-');
+ }
+
+ /* remove leading zeros */
+ while ((uval / x) == 0) {
+ x /= base;
+ }
+
+ do {
+ digit = (uint8_t) (uval / x);
+ ADD_CHAR(digits[digit]);
+ uval -= digit * x;
+ x /= base;
+ } while (x && (pos < len));
+ }
+
+ if (pos < len) str[pos] = 0;
+ return pos;
+#undef ADD_CHAR
+}
+
+/**
+ * Converts signed 32 bit integer value to string
+ * @param val integer value
+ * @param str converted textual representation
+ * @param len string buffer length
+ * @return number of bytes written to str (without '\0')
+ */
+size_t SCPI_Int32ToStr(int32_t val, char * str, size_t len) {
+ return UInt32ToStrBaseSign((uint32_t) val, str, len, 10, TRUE);
+}
+
+/**
+ * Converts unsigned 32 bit integer value to string in specific base
+ * @param val integer value
+ * @param str converted textual representation
+ * @param len string buffer length
+ * @param base output base
+ * @return number of bytes written to str (without '\0')
+ */
+size_t SCPI_UInt32ToStrBase(uint32_t val, char * str, size_t len, int8_t base) {
+ return UInt32ToStrBaseSign(val, str, len, base, FALSE);
+}
+
+/**
+ * Converts signed/unsigned 64 bit integer value to string in specific base
+ * @param val integer value
+ * @param str converted textual representation
+ * @param len string buffer length
+ * @param base output base
+ * @param sign
+ * @return number of bytes written to str (without '\0')
+ */
+size_t UInt64ToStrBaseSign(uint64_t val, char * str, size_t len, int8_t base, scpi_bool_t sign) {
+ const char digits[] = "0123456789ABCDEF";
+
+#define ADD_CHAR(c) if (pos < len) str[pos++] = (c)
+ uint64_t x = 0;
+ int_fast8_t digit;
+ size_t pos = 0;
+ uint64_t uval = val;
+
+ if (uval == 0) {
+ ADD_CHAR('0');
+ } else {
+
+ switch (base) {
+ case 2:
+ x = 0x8000000000000000ULL;
+ break;
+ case 8:
+ x = 0x8000000000000000ULL;
+ break;
+ default:
+ case 10:
+ x = 10000000000000000000ULL;
+ base = 10;
+ break;
+ case 16:
+ x = 0x1000000000000000ULL;
+ break;
+ }
+
+ /* add sign for numbers in base 10 */
+ if (sign && ((int64_t) val < 0) && (base == 10)) {
+ uval = -val;
+ ADD_CHAR('-');
+ }
+
+ /* remove leading zeros */
+ while ((uval / x) == 0) {
+ x /= base;
+ }
+
+ do {
+ digit = (uint8_t) (uval / x);
+ ADD_CHAR(digits[digit]);
+ uval -= digit * x;
+ x /= base;
+ } while (x && (pos < len));
+ }
+
+ if (pos < len) str[pos] = 0;
+ return pos;
+#undef ADD_CHAR
+}
+
+/**
+ * Converts signed 64 bit integer value to string
+ * @param val integer value
+ * @param str converted textual representation
+ * @param len string buffer length
+ * @return number of bytes written to str (without '\0')
+ */
+size_t SCPI_Int64ToStr(int64_t val, char * str, size_t len) {
+ return UInt64ToStrBaseSign((uint64_t) val, str, len, 10, TRUE);
+}
+
+/**
+ * Converts signed/unsigned 64 bit integer value to string in specific base
+ * @param val integer value
+ * @param str converted textual representation
+ * @param len string buffer length
+ * @param base output base
+ * @return number of bytes written to str (without '\0')
+ */
+size_t SCPI_UInt64ToStrBase(uint64_t val, char * str, size_t len, int8_t base) {
+ return UInt64ToStrBaseSign(val, str, len, base, FALSE);
+}
+
+/**
+ * Converts float (32 bit) value to string
+ * @param val long value
+ * @param str converted textual representation
+ * @param len string buffer length
+ * @return number of bytes written to str (without '\0')
+ */
+size_t SCPI_FloatToStr(float val, char * str, size_t len) {
+ SCPIDEFINE_floatToStr(val, str, len);
+ return strlen(str);
+}
+
+/**
+ * Converts double (64 bit) value to string
+ * @param val double value
+ * @param str converted textual representation
+ * @param len string buffer length
+ * @return number of bytes written to str (without '\0')
+ */
+size_t SCPI_DoubleToStr(double val, char * str, size_t len) {
+ SCPIDEFINE_doubleToStr(val, str, len);
+ return strlen(str);
+}
+
+/**
+ * Converts string to signed 32bit integer representation
+ * @param str string value
+ * @param val 32bit integer result
+ * @return number of bytes used in string
+ */
+size_t strBaseToInt32(const char * str, int32_t * val, int8_t base) {
+ char * endptr;
+ *val = strtol(str, &endptr, base);
+ return endptr - str;
+}
+
+/**
+ * Converts string to unsigned 32bit integer representation
+ * @param str string value
+ * @param val 32bit integer result
+ * @return number of bytes used in string
+ */
+size_t strBaseToUInt32(const char * str, uint32_t * val, int8_t base) {
+ char * endptr;
+ *val = strtoul(str, &endptr, base);
+ return endptr - str;
+}
+
+/**
+ * Converts string to signed 64bit integer representation
+ * @param str string value
+ * @param val 64bit integer result
+ * @return number of bytes used in string
+ */
+size_t strBaseToInt64(const char * str, int64_t * val, int8_t base) {
+ char * endptr;
+ *val = SCPIDEFINE_strtoll(str, &endptr, base);
+ return endptr - str;
+}
+
+/**
+ * Converts string to unsigned 64bit integer representation
+ * @param str string value
+ * @param val 64bit integer result
+ * @return number of bytes used in string
+ */
+size_t strBaseToUInt64(const char * str, uint64_t * val, int8_t base) {
+ char * endptr;
+ *val = SCPIDEFINE_strtoull(str, &endptr, base);
+ return endptr - str;
+}
+
+/**
+ * Converts string to float (32 bit) representation
+ * @param str string value
+ * @param val float result
+ * @return number of bytes used in string
+ */
+size_t strToFloat(const char * str, float * val) {
+ char * endptr;
+ *val = SCPIDEFINE_strtof(str, &endptr);
+ return endptr - str;
+}
+
+/**
+ * Converts string to double (64 bit) representation
+ * @param str string value
+ * @param val double result
+ * @return number of bytes used in string
+ */
+size_t strToDouble(const char * str, double * val) {
+ char * endptr;
+ *val = strtod(str, &endptr);
+ return endptr - str;
+}
+
+/**
+ * Compare two strings with exact length
+ * @param str1
+ * @param len1
+ * @param str2
+ * @param len2
+ * @return TRUE if len1==len2 and "len" characters of both strings are equal
+ */
+scpi_bool_t compareStr(const char * str1, size_t len1, const char * str2, size_t len2) {
+ if (len1 != len2) {
+ return FALSE;
+ }
+
+ if (SCPIDEFINE_strncasecmp(str1, str2, len2) == 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Compare two strings, one be longer but may contains only numbers in that section
+ * @param str1
+ * @param len1
+ * @param str2
+ * @param len2
+ * @return TRUE if strings match
+ */
+scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2, int32_t * num) {
+ scpi_bool_t result = FALSE;
+ size_t i;
+
+ if (len2 < len1) {
+ return FALSE;
+ }
+
+ if (SCPIDEFINE_strncasecmp(str1, str2, len1) == 0) {
+ result = TRUE;
+
+ if (num) {
+ if (len1 == len2) {
+ /* *num = 1; */
+ } else {
+ int32_t tmpNum;
+ i = len1 + strBaseToInt32(str2 + len1, &tmpNum, 10);
+ if (i != len2) {
+ result = FALSE;
+ } else {
+ *num = tmpNum;
+ }
+ }
+ } else {
+ for (i = len1; i < len2; i++) {
+ if (!isdigit((int) str2[i])) {
+ result = FALSE;
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Count white spaces from the beggining
+ * @param cmd - command
+ * @param len - max search length
+ * @return number of white spaces
+ */
+size_t skipWhitespace(const char * cmd, size_t len) {
+ size_t i;
+ for (i = 0; i < len; i++) {
+ if (!isspace((unsigned char) cmd[i])) {
+ return i;
+ }
+ }
+ return len;
+}
+
+/**
+ * Pattern is composed from upper case an lower case letters. This function
+ * search the first lowercase letter
+ * @param pattern
+ * @param len - max search length
+ * @return position of separator or len
+ */
+static size_t patternSeparatorShortPos(const char * pattern, size_t len) {
+ size_t i;
+ for (i = 0; (i < len) && pattern[i]; i++) {
+ if (islower((unsigned char) pattern[i])) {
+ return i;
+ }
+ }
+ return i;
+}
+
+/**
+ * Find pattern separator position
+ * @param pattern
+ * @param len - max search length
+ * @return position of separator or len
+ */
+static size_t patternSeparatorPos(const char * pattern, size_t len) {
+
+ char * separator = strnpbrk(pattern, len, "?:[]");
+ if (separator == NULL) {
+ return len;
+ } else {
+ return separator - pattern;
+ }
+}
+
+/**
+ * Find command separator position
+ * @param cmd - input command
+ * @param len - max search length
+ * @return position of separator or len
+ */
+static size_t cmdSeparatorPos(const char * cmd, size_t len) {
+ char * separator = strnpbrk(cmd, len, ":?");
+ size_t result;
+ if (separator == NULL) {
+ result = len;
+ } else {
+ result = separator - cmd;
+ }
+
+ return result;
+}
+
+/**
+ * Match pattern and str. Pattern is in format UPPERCASElowercase
+ * @param pattern
+ * @param pattern_len
+ * @param str
+ * @param str_len
+ * @return
+ */
+scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len, int32_t * num) {
+ int pattern_sep_pos_short;
+
+ if ((pattern_len > 0) && pattern[pattern_len - 1] == '#') {
+ size_t new_pattern_len = pattern_len - 1;
+
+ pattern_sep_pos_short = patternSeparatorShortPos(pattern, new_pattern_len);
+
+ return compareStrAndNum(pattern, new_pattern_len, str, str_len, num) ||
+ compareStrAndNum(pattern, pattern_sep_pos_short, str, str_len, num);
+ } else {
+
+ pattern_sep_pos_short = patternSeparatorShortPos(pattern, pattern_len);
+
+ return compareStr(pattern, pattern_len, str, str_len) ||
+ compareStr(pattern, pattern_sep_pos_short, str, str_len);
+ }
+}
+
+/**
+ * Compare pattern and command
+ * @param pattern eg. [:MEASure]:VOLTage:DC?
+ * @param cmd - command
+ * @param len - max search length
+ * @return TRUE if pattern matches, FALSE otherwise
+ */
+scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len, int32_t *numbers, size_t numbers_len, int32_t default_value) {
+#define SKIP_PATTERN(n) do {pattern_ptr += (n); pattern_len -= (n);} while(0)
+#define SKIP_CMD(n) do {cmd_ptr += (n); cmd_len -= (n);} while(0)
+
+ scpi_bool_t result = FALSE;
+ int brackets = 0;
+ int cmd_sep_pos = 0;
+
+ size_t numbers_idx = 0;
+ int32_t *number_ptr = NULL;
+
+ const char * pattern_ptr = pattern;
+ int pattern_len = strlen(pattern);
+
+ const char * cmd_ptr = cmd;
+ size_t cmd_len = SCPIDEFINE_strnlen(cmd, len);
+
+ /* both commands are query commands? */
+ if (pattern_ptr[pattern_len - 1] == '?') {
+ if (cmd_ptr[cmd_len - 1] == '?') {
+ cmd_len -= 1;
+ pattern_len -= 1;
+ } else {
+ return FALSE;
+ }
+ }
+
+ /* now support optional keywords in pattern style, e.g. [:MEASure]:VOLTage:DC? */
+ if (pattern_ptr[0] == '[') { /* skip first '[' */
+ SKIP_PATTERN(1);
+ brackets++;
+ }
+ if (pattern_ptr[0] == ':') { /* skip first ':' */
+ SKIP_PATTERN(1);
+ }
+
+ if (cmd_ptr[0] == ':') {
+ /* handle errornouse ":*IDN?" */
+ if (cmd_len >= 2) {
+ if (cmd_ptr[1] != '*') {
+ SKIP_CMD(1);
+ } else {
+ return FALSE;
+ }
+ }
+ }
+
+ while (1) {
+ int pattern_sep_pos = patternSeparatorPos(pattern_ptr, pattern_len);
+
+ cmd_sep_pos = cmdSeparatorPos(cmd_ptr, cmd_len);
+
+ if ((pattern_sep_pos > 0) && pattern_ptr[pattern_sep_pos - 1] == '#') {
+ if (numbers && (numbers_idx < numbers_len)) {
+ number_ptr = numbers + numbers_idx;
+ *number_ptr = default_value; /* default value */
+ } else {
+ number_ptr = NULL;
+ }
+ numbers_idx++;
+ } else {
+ number_ptr = NULL;
+ }
+
+ if (matchPattern(pattern_ptr, pattern_sep_pos, cmd_ptr, cmd_sep_pos, number_ptr)) {
+ SKIP_PATTERN(pattern_sep_pos);
+ SKIP_CMD(cmd_sep_pos);
+ result = TRUE;
+
+ /* command is complete */
+ if ((pattern_len == 0) && (cmd_len == 0)) {
+ break;
+ }
+
+ /* pattern complete, but command not */
+ if ((pattern_len == 0) && (cmd_len > 0)) {
+ result = FALSE;
+ break;
+ }
+
+ /* command complete, but pattern not */
+ if (cmd_len == 0) {
+ /* verify all subsequent pattern parts are also optional */
+ while (pattern_len) {
+ pattern_sep_pos = patternSeparatorPos(pattern_ptr, pattern_len);
+ switch (pattern_ptr[pattern_sep_pos]) {
+ case '[':
+ brackets++;
+ break;
+ case ']':
+ brackets--;
+ break;
+ default:
+ break;
+ }
+ SKIP_PATTERN(pattern_sep_pos + 1);
+ if (brackets == 0) {
+ if ((pattern_len > 0) && (pattern_ptr[0] == '[')) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+ if (pattern_len != 0) {
+ result = FALSE;
+ }
+ break; /* exist optional keyword, command is complete */
+ }
+
+ /* both command and patter contains command separator at this position */
+ if ((pattern_len > 0)
+ && ((pattern_ptr[0] == cmd_ptr[0])
+ && (pattern_ptr[0] == ':'))) {
+ SKIP_PATTERN(1);
+ SKIP_CMD(1);
+ } else if ((pattern_len > 1)
+ && (pattern_ptr[1] == cmd_ptr[0])
+ && (pattern_ptr[0] == '[')
+ && (pattern_ptr[1] == ':')) {
+ SKIP_PATTERN(2); /* for skip '[' in "[:" */
+ SKIP_CMD(1);
+ brackets++;
+ } else if ((pattern_len > 1)
+ && (pattern_ptr[1] == cmd_ptr[0])
+ && (pattern_ptr[0] == ']')
+ && (pattern_ptr[1] == ':')) {
+ SKIP_PATTERN(2); /* for skip ']' in "]:" */
+ SKIP_CMD(1);
+ brackets--;
+ } else if ((pattern_len > 2)
+ && (pattern_ptr[2] == cmd_ptr[0])
+ && (pattern_ptr[0] == ']')
+ && (pattern_ptr[1] == '[')
+ && (pattern_ptr[2] == ':')) {
+ SKIP_PATTERN(3); /* for skip '][' in "][:" */
+ SKIP_CMD(1);
+ /* brackets++; */
+ /* brackets--; */
+ } else {
+ result = FALSE;
+ break;
+ }
+ } else {
+ SKIP_PATTERN(pattern_sep_pos);
+ if ((pattern_ptr[0] == ']') && (pattern_ptr[1] == ':')) {
+ SKIP_PATTERN(2); /* for skip ']' in "]:" , pattern_ptr continue, while cmd_ptr remain unchanged */
+ brackets--;
+ } else if ((pattern_len > 2) && (pattern_ptr[0] == ']')
+ && (pattern_ptr[1] == '[')
+ && (pattern_ptr[2] == ':')) {
+ SKIP_PATTERN(3); /* for skip ']' in "][:" , pattern_ptr continue, while cmd_ptr remain unchanged */
+ /* brackets++; */
+ /* brackets--; */
+ } else {
+ result = FALSE;
+ break;
+ }
+ }
+ }
+
+ return result;
+#undef SKIP_PATTERN
+#undef SKIP_CMD
+}
+
+/**
+ * Compose command from previous command anc current command
+ *
+ * @param prev pointer to previous command
+ * @param current pointer of current command
+ *
+ * prev and current should be in the same memory buffer
+ */
+scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) {
+ size_t i;
+
+ /* Invalid input */
+ if (current == NULL || current->ptr == NULL || current->len == 0)
+ return FALSE;
+
+ /* no previous command - nothing to do*/
+ if (prev->ptr == NULL || prev->len == 0)
+ return TRUE;
+
+ /* Common command or command root - nothing to do */
+ if (current->ptr[0] == '*' || current->ptr[0] == ':')
+ return TRUE;
+
+ /* Previsou command was common command - nothing to do */
+ if (prev->ptr[0] == '*')
+ return TRUE;
+
+ /* Find last occurence of ':' */
+ for (i = prev->len; i > 0; i--) {
+ if (prev->ptr[i - 1] == ':') {
+ break;
+ }
+ }
+
+ /* Previous command was simple command - nothing to do*/
+ if (i == 0)
+ return TRUE;
+
+ current->ptr -= i;
+ current->len += i;
+ memmove(current->ptr, prev->ptr, i);
+ return TRUE;
+}
+
+
+
+#if !HAVE_STRNLEN
+/* use FreeBSD strnlen */
+
+/*-
+ * Copyright (c) 2009 David Schultz <[email protected]>
+ * All rights reserved.
+ */
+size_t
+BSD_strnlen(const char *s, size_t maxlen) {
+ size_t len;
+
+ for (len = 0; len < maxlen; len++, s++) {
+ if (!*s)
+ break;
+ }
+ return (len);
+}
+#endif
+
+#if !HAVE_STRNCASECMP && !HAVE_STRNICMP
+
+int OUR_strncasecmp(const char *s1, const char *s2, size_t n) {
+ unsigned char c1, c2;
+
+ for (; n != 0; n--) {
+ c1 = tolower((unsigned char) *s1++);
+ c2 = tolower((unsigned char) *s2++);
+ if (c1 != c2) {
+ return c1 - c2;
+ }
+ if (c1 == '\0') {
+ return 0;
+ }
+ }
+ return 0;
+}
+#endif
+
+#if USE_MEMORY_ALLOCATION_FREE && !HAVE_STRNDUP
+char *OUR_strndup(const char *s, size_t n) {
+ size_t len = SCPIDEFINE_strnlen(s, n);
+ char * result = malloc(len + 1);
+ if (!result) {
+ return NULL;
+ }
+ memcpy(result, s, len);
+ result[len] = '\0';
+ return result;
+}
+#endif
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+
+/**
+ * Initialize heap structure
+ * @param heap - pointer to manual allocated heap buffer
+ * @param error_info_heap - buffer for the heap
+ * @param error_info_heap_length - length of the heap
+ */
+void scpiheap_init(scpi_error_info_heap_t * heap, char * error_info_heap, size_t error_info_heap_length)
+{
+ heap->data = error_info_heap;
+ heap->wr = 0;
+ heap->size = error_info_heap_length;
+ heap->count = heap->size;
+ memset(heap->data, 0, heap->size);
+}
+
+/**
+ * Duplicate string if "strdup" ("malloc/free") not supported on system.
+ * Allocate space in heap if it possible
+ *
+ * @param heap - pointer to manual allocated heap buffer
+ * @param s - current pointer of duplication string
+ * @return - pointer of duplicated string or NULL, if duplicate is not possible.
+ */
+char * scpiheap_strndup(scpi_error_info_heap_t * heap, const char *s, size_t n) {
+ if (!s || !heap || !heap->size) {
+ return NULL;
+ }
+
+ if (heap->data[heap->wr] != '\0') {
+ return NULL;
+ }
+
+ if (*s == '\0') {
+ return NULL;
+ }
+
+ size_t len = SCPIDEFINE_strnlen(s, n) + 1; /* additional '\0' at end */
+ if (len > heap->count) {
+ return NULL;
+ }
+ const char * ptrs = s;
+ char * head = &heap->data[heap->wr];
+ size_t rem = heap->size - (&heap->data[heap->wr] - heap->data);
+
+ if (len >= rem) {
+ memcpy(&heap->data[heap->wr], s, rem);
+ len = len - rem;
+ ptrs += rem;
+ heap->wr = 0;
+ heap->count -= rem;
+ }
+
+ memcpy(&heap->data[heap->wr], ptrs, len);
+ heap->wr += len;
+ heap->count -= len;
+
+ /* ensure '\0' a the end */
+ if (heap->wr > 0) {
+ heap->data[heap->wr - 1] = '\0';
+ } else {
+ heap->data[heap->size - 1] = '\0';
+ }
+ return head;
+}
+
+/**
+ * Return pointers and lengths two parts of string in the circular buffer from heap
+ *
+ * @param heap - pointer to manual allocated heap buffer
+ * @param s - pointer of duplicate string.
+ * @return len1 - lenght of first part of string.
+ * @return s2 - pointer of second part of string, if string splited .
+ * @return len2 - lenght of second part of string.
+ */
+scpi_bool_t scpiheap_get_parts(scpi_error_info_heap_t * heap, const char * s, size_t * len1, const char ** s2, size_t * len2) {
+ if (!heap || !s || !len1 || !s2 || !len2) {
+ return FALSE;
+ }
+
+ if (*s == '\0') {
+ return FALSE;
+ }
+
+ *len1 = 0;
+ size_t rem = heap->size - (s - heap->data);
+ *len1 = strnlen(s, rem);
+
+ if (&s[*len1 - 1] == &heap->data[heap->size - 1]) {
+ *s2 = heap->data;
+ *len2 = strnlen(*s2, heap->size);
+ } else {
+ *s2 = NULL;
+ *len2 = 0;
+ }
+ return TRUE;
+}
+
+/**
+ * Frees space in heap, if "malloc/free" not supported on system, or nothing.
+ *
+ * @param heap - pointer to manual allocated heap buffer
+ * @param s - pointer of duplicate string
+ * @param rollback - backward write pointer in heap
+ */
+void scpiheap_free(scpi_error_info_heap_t * heap, char * s, scpi_bool_t rollback) {
+
+ if (!s) return;
+
+ char * data_add;
+ size_t len[2];
+
+ if (!scpiheap_get_parts(heap, s, &len[0], (const char **)&data_add, &len[1])) return;
+
+ if (data_add) {
+ len[1]++;
+ memset(data_add, 0, len[1]);
+ heap->count += len[1];
+ } else {
+ len[0]++;
+ }
+ memset(s, 0, len[0]);
+ heap->count += len[0];
+ if (heap->count == heap->size) {
+ heap->wr = 0;
+ return;
+ }
+ if (rollback) {
+ size_t rb = len[0] + len[1];
+ if (rb > heap->wr) {
+ heap->wr += heap->size;
+ }
+ heap->wr -= rb;
+ }
+}
+
+#endif
+
+/*
+ * Floating point to string conversion routines
+ *
+ * Copyright (C) 2002 Michael Ringgaard. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static char *scpi_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf, size_t bufsize) {
+ int r1, r2;
+ double fi, fj;
+ int w1, w2;
+
+ if (ndigits < 0) ndigits = 0;
+ if (ndigits >= (int) (bufsize - 1)) ndigits = bufsize - 2;
+
+ r2 = 0;
+ *sign = 0;
+ w1 = 0;
+ if (arg < 0) {
+ *sign = 1;
+ arg = -arg;
+ }
+ frexp(arg, &r1);
+ arg = modf(arg, &fi);
+
+ if (fi != 0) {
+ r1 = r1 * 308 / 1024 - ndigits;
+ w2 = bufsize;
+ while (r1 > 0) {
+ fj = modf(fi / 10, &fi);
+ r2++;
+ r1--;
+ }
+ while (fi != 0) {
+ fj = modf(fi / 10, &fi);
+ buf[--w2] = (int) ((fj + .03) * 10) + '0';
+ r2++;
+ }
+ while (w2 < (int) bufsize) buf[w1++] = buf[w2++];
+ } else if (arg > 0) {
+ while ((fj = arg * 10) < 1) {
+ arg = fj;
+ r2--;
+ }
+ }
+ w2 = ndigits;
+ *decpt = r2;
+ if (w2 < 0) {
+ buf[0] = '\0';
+ return buf;
+ }
+ while (w1 <= w2 && w1 < (int) bufsize) {
+ arg *= 10;
+ arg = modf(arg, &fj);
+ buf[w1++] = (int) fj + '0';
+ }
+ if (w2 >= (int) bufsize) {
+ buf[bufsize - 1] = '\0';
+ return buf;
+ }
+ w1 = w2;
+ buf[w2] += 5;
+ while (buf[w2] > '9') {
+ buf[w2] = '0';
+ if (w2 > 0) {
+ ++buf[--w2];
+ } else {
+ buf[w2] = '1';
+ (*decpt)++;
+ }
+ }
+ buf[w1] = '\0';
+ return buf;
+}
+
+#define SCPI_DTOSTRE_BUFFER_SIZE 32
+
+char * SCPI_dtostre(double __val, char * __s, size_t __ssize, unsigned char __prec, unsigned char __flags) {
+ char buffer[SCPI_DTOSTRE_BUFFER_SIZE];
+
+ int sign = SCPIDEFINE_signbit(__val);
+ char * s = buffer;
+ int decpt;
+ if (sign) {
+ __val = -__val;
+ s[0] = '-';
+ s++;
+ } else if (!SCPIDEFINE_isnan(__val)) {
+ if (SCPI_DTOSTRE_PLUS_SIGN & __flags) {
+ s[0] = '+';
+ s++;
+ } else if (SCPI_DTOSTRE_ALWAYS_SIGN & __flags) {
+ s[0] = ' ';
+ s++;
+ }
+ }
+
+ if (!SCPIDEFINE_isfinite(__val)) {
+ if (SCPIDEFINE_isnan(__val)) {
+ strcpy(s, (__flags & SCPI_DTOSTRE_UPPERCASE) ? "NAN" : "nan");
+ } else {
+ strcpy(s, (__flags & SCPI_DTOSTRE_UPPERCASE) ? "INF" : "inf");
+ }
+ strncpy(__s, buffer, __ssize);
+ __s[__ssize - 1] = '\0';
+ return __s;
+ }
+
+ scpi_ecvt(__val, __prec, &decpt, &sign, s, SCPI_DTOSTRE_BUFFER_SIZE - 1);
+ if (decpt > 1 && decpt <= __prec) {
+ memmove(s + decpt + 1, s + decpt, __prec + 1 - decpt);
+ s[decpt] = '.';
+ decpt = 0;
+ } else if (decpt > -4 && decpt <= 0) {
+ decpt = -decpt + 1;
+ memmove(s + decpt + 1, s, __prec + 1);
+ memset(s, '0', decpt + 1);
+ s[1] = '.';
+ decpt = 0;
+ } else {
+ memmove(s + 2, s + 1, __prec + 1);
+ s[1] = '.';
+ decpt--;
+ }
+
+ s = &s[__prec];
+ while (s[0] == '0') {
+ s[0] = 0;
+ s--;
+ }
+ if (s[0] == '.') {
+ s[0] = 0;
+ s--;
+ }
+
+ if (decpt != 0) {
+ s++;
+ s[0] = 'e';
+ s++;
+ if (decpt != 0) {
+ if (decpt > 0) {
+ s[0] = '+';
+ }
+ if (decpt < 0) {
+ s[0] = '-';
+ decpt = -decpt;
+ }
+ s++;
+ }
+ UInt32ToStrBaseSign(decpt, s, 5, 10, 0);
+ if (s[1] == 0) {
+ s[2] = s[1];
+ s[1] = s[0];
+ s[0] = '0';
+ }
+ }
+
+ strncpy(__s, buffer, __ssize);
+ __s[__ssize - 1] = '\0';
+ return __s;
+}
+
+/**
+ * Get native CPU endiannes
+ * @return
+ */
+scpi_array_format_t SCPI_GetNativeFormat(void) {
+
+ union {
+ uint32_t i;
+ char c[4];
+ } bint = {0x01020304};
+
+ return bint.c[0] == 1 ? SCPI_FORMAT_BIGENDIAN : SCPI_FORMAT_LITTLEENDIAN;
+}
+
+/**
+ * Swap 16bit number
+ * @param val
+ * @return
+ */
+uint16_t SCPI_Swap16(uint16_t val) {
+ return ((val & 0x00FF) << 8) |
+ ((val & 0xFF00) >> 8);
+}
+
+/**
+ * Swap 32bit number
+ * @param val
+ * @return
+ */
+uint32_t SCPI_Swap32(uint32_t val) {
+ return ((val & 0x000000FFul) << 24) |
+ ((val & 0x0000FF00ul) << 8) |
+ ((val & 0x00FF0000ul) >> 8) |
+ ((val & 0xFF000000ul) >> 24);
+}
+
+/**
+ * Swap 64bit number
+ * @param val
+ * @return
+ */
+uint64_t SCPI_Swap64(uint64_t val) {
+ return ((val & 0x00000000000000FFull) << 56) |
+ ((val & 0x000000000000FF00ull) << 40) |
+ ((val & 0x0000000000FF0000ull) << 24) |
+ ((val & 0x00000000FF000000ull) << 8) |
+ ((val & 0x000000FF00000000ull) >> 8) |
+ ((val & 0x0000FF0000000000ull) >> 24) |
+ ((val & 0x00FF000000000000ull) >> 40) |
+ ((val & 0xFF00000000000000ull) >> 56);
+}
diff --git a/third_party/libscpi/src/utils_private.h b/third_party/libscpi/src/utils_private.h
new file mode 100644
index 00000000..6ae1616a
--- /dev/null
+++ b/third_party/libscpi/src/utils_private.h
@@ -0,0 +1,128 @@
+/*-
+ * BSD 2-Clause License
+ *
+ * Copyright (c) 2012-2018, Jan Breuer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file scpi_utils.h
+ * @date Thu Nov 15 10:58:45 UTC 2012
+ *
+ * @brief Conversion routines and string manipulation routines
+ *
+ *
+ */
+
+#ifndef SCPI_UTILS_PRIVATE_H
+#define SCPI_UTILS_PRIVATE_H
+
+#include <stdint.h>
+#include "scpi/config.h"
+#include "scpi/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+#define LOCAL __attribute__((visibility ("hidden")))
+#else
+#define LOCAL
+#endif
+
+ char * strnpbrk(const char *str, size_t size, const char *set) LOCAL;
+ scpi_bool_t compareStr(const char * str1, size_t len1, const char * str2, size_t len2) LOCAL;
+ scpi_bool_t compareStrAndNum(const char * str1, size_t len1, const char * str2, size_t len2, int32_t * num) LOCAL;
+ size_t UInt32ToStrBaseSign(uint32_t val, char * str, size_t len, int8_t base, scpi_bool_t sign) LOCAL;
+ size_t UInt64ToStrBaseSign(uint64_t val, char * str, size_t len, int8_t base, scpi_bool_t sign) LOCAL;
+ size_t strBaseToInt32(const char * str, int32_t * val, int8_t base) LOCAL;
+ size_t strBaseToUInt32(const char * str, uint32_t * val, int8_t base) LOCAL;
+ size_t strBaseToInt64(const char * str, int64_t * val, int8_t base) LOCAL;
+ size_t strBaseToUInt64(const char * str, uint64_t * val, int8_t base) LOCAL;
+ size_t strToFloat(const char * str, float * val) LOCAL;
+ size_t strToDouble(const char * str, double * val) LOCAL;
+ scpi_bool_t locateText(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL;
+ scpi_bool_t locateStr(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL;
+ size_t skipWhitespace(const char * cmd, size_t len) LOCAL;
+ scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len, int32_t * num) LOCAL;
+ scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len, int32_t *numbers, size_t numbers_len, int32_t default_value) LOCAL;
+ scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) LOCAL;
+
+#define SCPI_DTOSTRE_UPPERCASE 1
+#define SCPI_DTOSTRE_ALWAYS_SIGN 2
+#define SCPI_DTOSTRE_PLUS_SIGN 4
+ char * SCPI_dtostre(double __val, char * __s, size_t __ssize, unsigned char __prec, unsigned char __flags);
+
+ scpi_array_format_t SCPI_GetNativeFormat(void);
+ uint16_t SCPI_Swap16(uint16_t val);
+ uint32_t SCPI_Swap32(uint32_t val);
+ uint64_t SCPI_Swap64(uint64_t val);
+
+#if !HAVE_STRNLEN
+ size_t BSD_strnlen(const char *s, size_t maxlen) LOCAL;
+#endif
+
+#if !HAVE_STRNCASECMP && !HAVE_STRNICMP
+ int OUR_strncasecmp(const char *s1, const char *s2, size_t n) LOCAL;
+#endif
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+ void scpiheap_init(scpi_error_info_heap_t * heap, char * error_info_heap, size_t error_info_heap_length);
+ char * scpiheap_strndup(scpi_error_info_heap_t * heap, const char *s, size_t n) LOCAL;
+ void scpiheap_free(scpi_error_info_heap_t * heap, char *s, scpi_bool_t rollback) LOCAL;
+ scpi_bool_t scpiheap_get_parts(scpi_error_info_heap_t * heap, const char *s1, size_t * len1, const char ** s2, size_t * len2) LOCAL;
+#endif
+
+#if !HAVE_STRNDUP
+ char *OUR_strndup(const char *s, size_t n);
+#endif
+
+#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#if 0
+#define max(a,b) \
+ ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a > _b ? _a : _b; })
+
+#define min(a,b) \
+ ({ __typeof__ (a) _a = (a); \
+ __typeof__ (b) _b = (b); \
+ _a < _b ? _a : _b; })
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SCPI_UTILS_PRIVATE_H */
+