学习指南

本次实习项目共有三个阶段,前两个阶段各包含五个实验内容(实验开始前,请先阅读每阶段的相关知识),第三阶段为驱动开发环节

  • 第一阶段主要了解树莓派以及如何在树莓派上运行ArceOS

    • 实验一为编译环境,消耗时间较久,大概需要一个小时左右

    • 实验二、三为在模拟环境运行ArceOS,每个实验大概需要一刻钟左右

    • 实验四、五为在树莓派主板上运行ArceOS,每个实验大概需要一刻钟左右(没有树莓派主板可以继续在qemu上运行)

  • 第二阶段主要用Rust写树莓派串口驱动,共包含五个实验内容

    • 实验一为驱动 UART0 串口,大概需要一个小时左右(没有树莓派可以在qemu上运行)

    • 实验二为用串口驱动小车,大概需要一个小时左右(没有小车,可以通过查看输出结果验证代码是否可以跑通)

    • 实验三为驱动另一串口,大概需要一个小时左右(没有树莓派可以在qemu上运行)

    • 实验四与实验三类似

    • 实验五为通过初始串口发出指令,由另一串口驱动小车,大概需要一个小时(选做)

  • 第三阶段为用Rust写树莓派USB转串口驱动,可以分为以下几步

    • PCIe总线初始化,可以读取USB设备ID

    • 为USB设备分配内存空间

    • xhci主机控制器的初始化

    • 枚举检测设备,为设备分配地址

    • 解析设备配置,加载相应的驱动程序

    • USB转串口的驱动实现

    • 完成技术需求,撰写技术总结文档

第一阶段:认识树莓派及ArceOS编译

本阶段主要以认识树莓派为主,学会如何编译支持树莓派4b的 Qemu 模拟器、如何在树莓派4b上运行 ArceOS。

ArceOS:

ArceOS实验环境配置

克隆这个仓库:

https://github.com/chenlongos/arceos

生成ArceOS代码仓库。

前置了解:树莓派相关知识

树莓派新手入门手册

树莓派4B(Raspberry Pi 4 Model B)是一款功能强大的单板计算机,由Raspberry Pi基金会推出。它提供了丰富的特性和扩展性,适用于各种项目和应用。以下是与树莓派4B相关的一些知识:

  1. 规格和硬件:树莓派4B采用了Broadcom BCM2711 SoC处理器,具有四个ARM Cortex-A72 CPU核心、VideoCore VI GPU和1GB、2GB或4GB LPDDR4内存选项。它还配备了多个USB 3.0和USB 2.0接口、Gigabit以太网端口、HDMI输出、MicroSD卡槽等。
  2. 操作系统支持:树莓派4B可以运行各种操作系统,包括Raspberry Pi官方的Raspberry Pi OS(以前称为Raspbian),以及其他基于Linux的发行版如Ubuntu、Fedora等。还可以安装其它的操作系统。
  3. GPIO引脚:树莓派4B具有40个GPIO(通用输入/输出)引脚,可以用于连接和控制各种外部设备,如传感器、LED、电机等。这些引脚还可以通过编程语言进行访问和控制。
  4. 外设接口:除了GPIO引脚,树莓派4B还提供了丰富的外设接口。它具有多个USB端口(包括USB 3.0和USB 2.0)、以太网端口、HDMI接口(支持4K分辨率输出)、音频/视频接口、摄像头接口、显示器接口等。
  5. 储存和扩展:树莓派4B使用MicroSD卡作为主要的存储介质,可以通过插入不同容量的MicroSD卡来扩展存储空间。此外,它还具有两个Micro HDMI端口和一个CSI摄像头接口,可用于连接外部显示器和摄像头模块。

树莓派主板如下图所示:

小车如下图所示(最上方是一块树莓派主板):

树莓派跑ArceOS通过串口控制小车运动:

实验一:支持树莓派4b的 Qemu 环境搭建

  1. 克隆这个仓库来生成新的 qemu 用来支持树莓派4b

    git clone https://github.com/0xMirasio/qemu-patch-raspberry4.git
    
    root@uBuntu:~/Github/Chenlong# git clone https://github.com/0xMirasio/qemu-patch-raspberry4
    Cloning into 'qemu-patch-raspberry4'...
    remote: Enumerating objects: 605399, done.
    remote: Counting objects: 100% (1/1), done.
    remote: Total 605399 (delta 0), reused 0 (delta 0), pack-reused 605398
    Receiving objects: 100% (605399/605399), 360.98 MiB | 11.84 MiB/s, done.
    Resolving deltas: 100% (489320/489320), done.
    root@uBuntu:~/Github/Chenlong# cd qemu-patch-raspberry4/
    root@uBuntu:~/Github/Chenlong/qemu-patch-raspberry4# ls
    accel           common-user    dtc                   io             memory_ldst.c.inc  page-vary-common.c    qemu-keymap.c    scripts         trace
    audio           configs        dump                  iothread.c     meson              pc-bios               qemu-nbd.c       scsi            trace-events
    authz           configure      ebpf                  job.c          meson.build        plugins               qemu.nsi         semihosting     ui
    backends        contrib        fpu                   job-qmp.c      meson_options.txt  po                    qemu-options.hx  slirp           util
    block           COPYING        fsdev                 Kconfig        migration          python                qemu.sasl        softmmu         VERSION
    block.c         COPYING.LIB    gdbstub.c             Kconfig.host   module-common.c    qapi                  qga              storage-daemon  version.rc
    blockdev.c      cpu.c          gdb-xml               libdecnumber   monitor            qemu-bridge-helper.c  qobject          stubs
    blockdev-nbd.c  cpus-common.c  gitdm.config          LICENSE        nbd                qemu-edid.c           qom              subprojects
    blockjob.c      crypto         hmp-commands.hx       linux-headers  net                qemu-img.c            README.rst       target
    bsd-user        disas          hmp-commands-info.hx  linux-user     os-posix.c         qemu-img-cmds.hx      replay           tcg
    capstone        disas.c        hw                    MAINTAINERS    os-win32.c         qemu-io.c             replication.c    tests
    chardev         docs           include               Makefile       page-vary.c        qemu-io-cmds.c        roms             tools
    
  2. 然后,执行以下操作进行编译:

    mkdir build
    cd build/
    ../configure
    make
    
    root@uBuntu:~/Github/Chenlong/qemu-patch-raspberry4# mkdir build
    root@uBuntu:~/Github/Chenlong/qemu-patch-raspberry4# cd build/
    root@uBuntu:~/Github/Chenlong/qemu-patch-raspberry4/build# ../configure
    root@uBuntu:~/Github/Chenlong/qemu-patch-raspberry4/build# make
    
  3. 编译时间较长,完成后生成的可执行文件就在当前 qemu 项目的 build 目录下,版本号为 QEMU emulator version 6.2.50 :

    root@uBuntu:~/Github/Chenlong/qemu-patch-raspberry4/build# ls qemu-system-*
    qemu-system-aarch64  qemu-system-cris  qemu-system-microblaze    qemu-system-mips64el  qemu-system-ppc      qemu-system-rx     qemu-system-sparc    qemu-system-xtensa
    qemu-system-alpha    qemu-system-hppa  qemu-system-microblazeel  qemu-system-mipsel    qemu-system-ppc64    qemu-system-s390x  qemu-system-sparc64  qemu-system-xtensaeb
    qemu-system-arm      qemu-system-i386  qemu-system-mips          qemu-system-nios2     qemu-system-riscv32  qemu-system-sh4    qemu-system-tricore
    qemu-system-avr      qemu-system-m68k  qemu-system-mips64        qemu-system-or1k      qemu-system-riscv64  qemu-system-sh4eb  qemu-system-x86_64
    
    root@uBuntu:~/Github/Chenlong/qemu-patch-raspberry4/build# ./qemu-system-aarch64 --version
    QEMU emulator version 6.2.50 (v6.2.0-1433-g6213f46ca3)
    Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers
    
  4. 最后,执行

    qemu-system-aarch64 -M help | grep ras
    

    可以看到 qemu 已经支持 树莓派4b 了

    root@iZ2ze7ajbjlxlzqf7yrk1zZ:~/Github/Chenlong/qemu-patch-raspberry4/build# ./qemu-system-aarch64 -M help | grep ras
    raspi0               Raspberry Pi Zero (revision 1.2)
    raspi1ap             Raspberry Pi A+ (revision 1.1)
    raspi2b              Raspberry Pi 2B (revision 1.1)
    raspi3ap             Raspberry Pi 3A+ (revision 1.0)
    raspi3b              Raspberry Pi 3B (revision 1.2)
    raspi4b1g            Raspberry Pi 4B (revision 1.1)
    raspi4b2g            Raspberry Pi 4B (revision 1.2)
    

至此,实验一结束,最终提交实验过程记录(包含出现的各类问题及解决办法)以及执行qemu-system-aarch64 -M help | grep ras命令后生成的结果,要求可以看到已经支持树莓派4b了。

实验二:Qemu 模拟器启动 ArceOS,打印Hello,world

  1. 在ArceOS目录下,输入:

    make A=apps/helloworld ARCH=aarch64 PLATFORM=aarch64-raspi4 SMP=4 
    

    (如果4核运行不了,可以改为单核)

    编译出ArceOS在raspi4 上的一个镜像。

  2. 在qemu模拟器上运行该镜像:

    ./qemu-system-aarch64 -m 2G -smp 4 -cpu cortex-a72 -machine raspi4b2g -nographic -kernel {yourpath}/helloworld_aarch64-raspi4.bin
    
  3. 最后,看到ArceOS在qemu模拟器中成功运行:

    root@DESKTOP-KO8A4KB:~/qemu-patch-raspberry4/build/arceos# make A=apps/helloworld ARCH=aarch64 PLATFORM=aarch64-raspi4 SMP=4
        Building App: helloworld, Arch: aarch64, Platform: aarch64-raspi4, App type: rust
    cargo build --target aarch64-unknown-none-softfloat --target-dir /root/qemu-patch-raspberry4/build/arceos/target --release  --manifest-path 
    apps/helloworld/Cargo.toml --features "axstd/log-level-warn axstd/smp"
        Finished release [optimized] target(s) in 0.09s
    rust-objcopy --binary-architecture=aarch64 apps/helloworld/helloworld_aarch64-raspi4.elf --strip-all -O binary apps/helloworld/helloworld_aarch64-raspi4.bin
    root@DESKTOP-KO8A4KB:~/qemu-patch-raspberry4/build/arceos# cd ..
    root@DESKTOP-KO8A4KB:~/qemu-patch-raspberry4/build# ./qemu-system-aarch64 -m 2G -smp 4 -cpu cortex-a72 -machine raspi4b2g -nographic -kernel 
    arceos/apps/helloworld/helloworld_aarch64-raspi4.bin
    
           d8888                            .d88888b.   .d8888b.
          d88888                           d88P" "Y88b d88P  Y88b
         d88P888                           888     888 Y88b.
        d88P 888 888d888  .d8888b  .d88b.  888     888  "Y888b.
       d88P  888 888P"   d88P"    d8P  Y8b 888     888     "Y88b.
      d88P   888 888     888      88888888 888     888       "888
     d8888888888 888     Y88b.    Y8b.     Y88b. .d88P Y88b  d88P
    d88P     888 888      "Y8888P  "Y8888   "Y88888P"   "Y8888P"
    
    arch = aarch64
    platform = aarch64-raspi4
    target = aarch64-unknown-none-softfloat
    smp = 4
    build_mode = release
    log_level = warn
    
    Hello, world!
    

至此,实验二结束,最终提交实验过程记录(包含出现的各类问题及解决办法)以及ArceOS成功运行,打印Hello,world的结果。

实验三:Qemu 模拟器启动 ArceOS,执行shell命令

  1. 在ArceOS目录下,输入:

    make A=apps/fs/shell ARCH=aarch64 PLATFORM=aarch64-raspi4 SMP=4 BLK=y FEATURES=driver-ramdisk
    

    编译出ArceOS在raspi4 上的镜像。

  2. 在qemu模拟器上运行该镜像:

    ./qemu-system-aarch64 -m 2G -smp 4 -cpu cortex-a72 -machine raspi4b2g  -nographic -kernel arceos/apps/fs/shell/shell_aarch64-raspi4.bin
    
  3. 看到ArceOS在qemu模拟器中成功运行:

    
           d8888                            .d88888b.   .d8888b.
          d88888                           d88P" "Y88b d88P  Y88b
         d88P888                           888     888 Y88b.
        d88P 888 888d888  .d8888b  .d88b.  888     888  "Y888b.
       d88P  888 888P"   d88P"    d8P  Y8b 888     888     "Y88b.
      d88P   888 888     888      88888888 888     888       "888
     d8888888888 888     Y88b.    Y8b.     Y88b. .d88P Y88b  d88P
    d88P     888 888      "Y8888P  "Y8888   "Y88888P"   "Y8888P"
    
    arch = aarch64
    platform = aarch64-raspi4
    target = aarch64-unknown-none-softfloat
    smp = 4
    build_mode = release
    log_level = warn
    
    [  0.032734 fatfs::boot_sector:615] Invalid FAT type
    [  0.055230 fatfs::dir:140] Is a directory
    [  0.059208 fatfs::dir:140] Is a directory
    [  0.064018 fatfs::dir:140] Is a directory
    [  0.066387 fatfs::dir:140] Is a directory
    Available commands:
      cat
      cd
      echo
      exit
      help
      ls
      mkdir
      pwd
      rm
      uname
      ldr
      str
    arceos:/$
    
  4. 尝试运行ldr和str命令:

    • ldr命令是用来读取地址所存储的值,例如输入ldr ffff0000fe201000,就会读出在地址为ffff0000fe201000中存储的值。
    arceos# ldr ffff0000fe201000
    ldr
    Value at address 0xffff0000fe201000: 0x66
    
    • str命令是用来往地址中写入值的,例如输入str ffff0000400fe000 123,就会往地址为ffff0000400fe000中写入123,输入234,就会写入234。
    arceos# str ffff0000400fe000 123
    arceos# ldr ffff0000400fe000
    ldr
    Value at address 0xffff0000400fe000: 0x123
    arceos# str ffff0000400fe000 234
    arceos# ldr ffff0000400fe000
    ldr
    Value at address 0xffff0000400fe000: 0x234
    
  5. 尝试输出字母A:

    尝试向ffff0000fe201000中写入41,使其输出字母A:

    arceos:/$ str ffff0000fe201000 41
    AWrite value at address ffff0000fe201000: 0x41
    

    可以在最后一行的开头看到输出了一个字母A。

至此,实验三结束,最终提交实验过程记录(包含出现的各类问题及解决办法)以及关于ArceOS成功运行,并且尝试执行ldr、str命令,最后再成功输出字母A的结果。(相关代码位置:arceos/apps/cli/src/)

实验四:树莓派启动 ArceOS,打印Hello,world

前置知识

SD卡的配置:

  • 创建一个名为bootFAT32分区
  • 在SD卡上生成一个名为config.txt的文件,并将以下内容写入其中:
```
arm_64bit=1
init_uart_clock=48000000
```
  • Raspberry Pi firmware repo中将以下文件复制到SD卡上:

  • 将通过编译生成的kernel8.img复制到SD卡上 kernel8.img的生成

    • 首先,克隆这个仓库:
    git clone https://github.com/chenlongos/rust-raspberrypi-OS-tutorials.git
    
    • 然后,在06_uart_chainloader目录下,执行:
    BSP=rpi4 make
    

    便可以看到生成了一个kernel8.img文件。

树莓派上电启动启动流程:

  • 硬件初始化: 树莓派4上电后,硬件会被初始化,包括CPU、内存、外设等。
  • GPU加载启动代码(bootcode.bin): GPU(图形处理单元)是树莓派启动的主要控制器。在启动时,GPU会从SD卡的boot分区加载一个文件,通常是 bootcode.bin。这个文件包含了GPU的启动代码,负责初始化系统硬件,设置内存分配和加载下一阶段的启动代码。
  • 加载启动配置文件(config.txt): GPU加载 config.txt 文件,该文件包含了系统的配置信息,比如时钟频率、内存分配等。
  • 加载启动文件(start4.elf): GPU加载 start4.elf 文件,它是一个二进制文件,包含了树莓派系统的启动代码,它负责初始化硬件和启动ARM处理器。
  • 加载设备树文件(bcm2711-rpi-4-b.dtb):start4.elf文件应该也会去读取设备树文件,然后设置一些基本的参数。
  • 加载操作系统内核(kernel8.img): start4.elf 文件会加载操作系统内核,是一个名为 kernel8.img 的文件。这个内核文件是一个裸机可执行文件,包含了操作系统的核心功能。
  • 初始化和启动操作系统: 内核文件被加载到内存后,GPU将控制权交给ARM处理器,操作系统开始初始化并启动,完成系统的启动过程。

树莓派通过串口与主机连接

将三根串口连接线分别了解到编号为6,8,10的三个引脚处。(6号对应的是地线GND,8号对应的是TXD,10号对应的是RXD)

再将一根USB串口转换线与连接到树莓派的线相连,其中TXD对应RXD,RXD对应TXD,GND对应GND。(默认情况下,USB串口转换线中黑色代表GND,白色代表RXD,绿色代表TXD,红色不连接)

连接软件的使用

以putty为例:

连接类型选择Serial,再将Serial line改为COM3(具体需要自己查看),Speed(波特率)设为115200,最后点击Open即可。

实验内容

  1. 在ArceOS目录下,输入:

    make A=apps/helloworld ARCH=aarch64 PLATFORM=aarch64-raspi4  LOG=debug 
    

    编译出ArceOS在raspi4 上的一个镜像。

  2. 编译生成一个kernel8.img文件:

    BSP=rpi4 make
    
  3. 把 kernel8.img 和 helloworld_aarch64-raspi4.bin 通过 cat 命令拼接到一个 bin 文件中,仍然取名为 kernel8.img

    cat ../rust-raspberrypi-OS-tutorials/06_uart_chainloader/kernel8.img apps/helloworld/helloworld_aarch64-raspi4.bin > kernel8.img
    

若已有树莓派开发板则进行以下操作

  1. 把新生成的 kernel8.img 拷贝到 sd 卡上。

  2. 将树莓派与PC相连,打开连接软件。

  3. 启动树莓派板子,可以看到上电后输出 miniload 并进入到 arceos helloworld 里

    
           d8888                            .d88888b.   .d8888b.
          d88888                           d88P" "Y88b d88P  Y88b
         d88P888                           888     888 Y88b.
        d88P 888 888d888  .d8888b  .d88b.  888     888  "Y888b.
       d88P  888 888P"   d88P"    d8P  Y8b 888     888     "Y88b.
      d88P   888 888     888      88888888 888     888       "888
     d8888888888 888     Y88b.    Y8b.     Y88b. .d88P Y88b  d88P
    d88P     888 888      "Y8888P  "Y8888   "Y88888P"   "Y8888P"
    
    arch = aarch64
    platform = aarch64-raspi4
    target = aarch64-unknown-none-softfloat
    smp = 1
    build_mode = release
    log_level = debug
    
    [  0.108847 0 axruntime:126] Logging is enabled.
    [  0.114576 0 axruntime:127] Primary CPU 0 started, dtb = 0x0.
    [  0.121522 0 axruntime:129] Found physcial memory regions:
    [  0.128209 0 axruntime:131]   [PA:0x80000, PA:0x86000) .text (READ | EXECUTE | RESERVED)
    [  0.137498 0 axruntime:131]   [PA:0x86000, PA:0x88000) .rodata (READ | RESERVED)
    [  0.146093 0 axruntime:131]   [PA:0x88000, PA:0x8c000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED)
    [  0.157033 0 axruntime:131]   [PA:0x8c000, PA:0xcc000) boot stack (READ | WRITE | RESERVED)
    [  0.166583 0 axruntime:131]   [PA:0xcc000, PA:0xcd000) .bss (READ | WRITE | RESERVED)
    [  0.175613 0 axruntime:131]   [PA:0x0, PA:0x1000) spintable (READ | WRITE | RESERVED)
    [  0.184642 0 axruntime:131]   [PA:0xcd000, PA:0xfc000000) free memory (READ | WRITE | FREE)
    [  0.194193 0 axruntime:131]   [PA:0xfe201000, PA:0xfe202000) mmio (READ | WRITE | DEVICE | RESERVED)
    [  0.204525 0 axruntime:131]   [PA:0xff841000, PA:0xff849000) mmio (READ | WRITE | DEVICE | RESERVED)
    [  0.214857 0 axruntime:149] Initialize platform devices...
    [  0.221542 0 axruntime:185] Primary CPU 0 init OK.
    Hello, world! 
    [  9.556116 0 axruntime:198] main task exited: exit_code=0
    [  9.560792 0 axhal::platform::aarch64_raspi::misc:21] Shutting down...
    

若没有开发板则在qemu模拟器中进行

  1. 在qemu中运行kernel8.img:

    ./qemu-system-aarch64 -m 2G -smp 4 -cpu cortex-a72 -machine raspi4b2g -nographic -kernel arceos/kernel8.img
    
  2. 可以看到输出:

    
           d8888                            .d88888b.   .d8888b.
          d88888                           d88P" "Y88b d88P  Y88b
         d88P888                           888     888 Y88b.
        d88P 888 888d888  .d8888b  .d88b.  888     888  "Y888b.
       d88P  888 888P"   d88P"    d8P  Y8b 888     888     "Y88b.
      d88P   888 888     888      88888888 888     888       "888
     d8888888888 888     Y88b.    Y8b.     Y88b. .d88P Y88b  d88P
    d88P     888 888      "Y8888P  "Y8888   "Y88888P"   "Y8888P"
    
    arch = aarch64
    platform = aarch64-raspi4
    target = aarch64-unknown-none-softfloat
    smp = 1
    build_mode = release
    log_level = debug 
    
    [  0.018980 0 axruntime:126] Logging is enabled.
    [  0.021262 0 axruntime:127] Primary CPU 0 started, dtb = 0x0.
    [  0.022619 0 axruntime:129] Found physcial memory regions:
    [  0.023704 0 axruntime:131]   [PA:0x80000, PA:0x86000) .text (READ | EXECUTE | RESERVED)
    [  0.025339 0 axruntime:131]   [PA:0x86000, PA:0x88000) .rodata (READ | RESERVED)
    [  0.026509 0 axruntime:131]   [PA:0x88000, PA:0x8c000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED)
    [  0.028264 0 axruntime:131]   [PA:0x8c000, PA:0xcc000) boot stack (READ | WRITE | RESERVED)
    [  0.029420 0 axruntime:131]   [PA:0xcc000, PA:0xcd000) .bss (READ | WRITE | RESERVED)
    [  0.030306 0 axruntime:131]   [PA:0x0, PA:0x1000) spintable (READ | WRITE | RESERVED)
    [  0.032056 0 axruntime:131]   [PA:0xcd000, PA:0xfc000000) free memory (READ | WRITE | FREE)
    [  0.032680 0 axruntime:131]   [PA:0xfe201000, PA:0xfe202000) mmio (READ | WRITE | DEVICE | RESERVED)
    [  0.033333 0 axruntime:131]   [PA:0xff841000, PA:0xff849000) mmio (READ | WRITE | DEVICE | RESERVED)
    [  0.034284 0 axruntime:149] Initialize platform devices...
    [  0.035041 0 axruntime:185] Primary CPU 0 init OK.
    Hello, world!
    [  0.036391 0 axruntime:198] main task exited: exit_code=0
    [  0.037152 0 axhal::platform::aarch64_raspi::misc:21] Shutting down...
    

    (ArceOS上面的内容miniload是原先的kernel8.img里的)

至此,实验四结束,最终提交实验过程记录(包含出现的各类问题及解决办法)以及ArceOS成功运行,打印Hello,world的结果。

实验五:树莓派启动 ArceOS,执行shell命令

  1. 在ArceOS目录下,输入:

    make A=apps/cli ARCH=aarch64 PLATFORM=aarch64-raspi4 LOG=debug
    

    编译出ArceOS在raspi4 上的镜像。

  2. 生成kernel8.img文件

    BSP=rpi4 make
    
  3. 把 kernel8.img 和 cli_aarch64-raspi4.bin 通过 cat 命令拼接到一个 bin 文件中,仍然取名为 kernel8.img:

    cat ../rust-raspberrypi-OS-tutorials/06_uart_chainloader/kernel8.img apps/cli/cli_aarch64-raspi4.bin > kernel8.img
    

若已有树莓派开发板则进行以下操作

  1. 把新生成的 kernel8.img 拷贝到 sd 卡上。

  2. 将树莓派与PC相连,打开连接软件。

  3. 启动树莓派板子,可以看到上电后输出 miniload 并进入到 shell 命令里:

           d8888                            .d88888b.   .d8888b.
          d88888                           d88P" "Y88b d88P  Y88b
         d88P888                           888     888 Y88b.
        d88P 888 888d888  .d8888b  .d88b.  888     888  "Y888b.
       d88P  888 888P"   d88P"    d8P  Y8b 888     888     "Y88b.
      d88P   888 888     888      88888888 888     888       "888
     d8888888888 888     Y88b.    Y8b.     Y88b. .d88P Y88b  d88P
    d88P     888 888      "Y8888P  "Y8888   "Y88888P"   "Y8888P"
    
    arch = aarch64
    platform = aarch64-raspi4
    target = aarch64-unknown-none-softfloat
    smp = 1
    build_mode = release
    log_level = debug
    
    [  0.108866 0 axruntime:126] Logging is enabled.
    [  0.114596 0 axruntime:127] Primary CPU 0 started, dtb = 0x0.
    [  0.121542 0 axruntime:129] Found physcial memory regions:
    [  0.128229 0 axruntime:131]   [PA:0x80000, PA:0x8a000) .text (READ | EXECUTE | RESERVED)
    [  0.137517 0 axruntime:131]   [PA:0x8a000, PA:0x8d000) .rodata (READ | RESERVED)
    [  0.146113 0 axruntime:131]   [PA:0x8d000, PA:0x91000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED)
    [  0.157053 0 axruntime:131]   [PA:0x91000, PA:0xd1000) boot stack (READ | WRITE | RESERVED)
    [  0.166603 0 axruntime:131]   [PA:0xd1000, PA:0xd2000) .bss (READ | WRITE | RESERVED)
    [  0.175633 0 axruntime:131]   [PA:0x0, PA:0x1000) spintable (READ | WRITE | RESERVED)
    [  0.184662 0 axruntime:131]   [PA:0xd2000, PA:0xfc000000) free memory (READ | WRITE | FREE)
    [  0.194213 0 axruntime:131]   [PA:0xfe201000, PA:0xfe202000) mmio (READ | WRITE | DEVICE | RESERVED)
    [  0.204545 0 axruntime:131]   [PA:0xff841000, PA:0xff849000) mmio (READ | WRITE | DEVICE | RESERVED)
    [  0.214877 0 axruntime:149] Initialize platform devices...
    [  0.221562 0 axruntime:185] Primary CPU 0 init OK.
    Available commands:
      exit
      help
      uname
      ldr
      str
    arceos#
    
  4. 尝试修改ldr命令相关代码(位置arceos/apps/cli/src/cmd.rs):

    • 目前的ldr只能以8个字节为间隔来读取地址的值,要求改为以4个字节为间隔来读取地址的值(地址都是以16进制表示的),例如:

      arceos# ldr ffff0000fe201000
      ldr
      Value at address 0xffff0000fe201000: 0x31
      
      arceos# ldr ffff0000fe201004   //修改前如果输入ldr ffff0000fe201004 会直接崩溃
      ldr
      Value at address 0xffff0000fe201000: 0x0
      
    • 目前的ldr只能将完整的地址输入进去才能输出,要求改为输入一个地址加一个数字,可以直接输出一排相邻地址的值(起始的值为输入的地址的值,输出的值的个数取决于输入的数字,不输入默认为1),例如:

      arceos# ldr ffff0000fe201000 5 //修改前只能输入ldr ffff0000fe201000 ffff0000fe201008
      ldr
      Value at address 0xffff0000fe201000: 0x31
      Value at address 0xffff0000fe201004: 0x0
      Value at address 0xffff0000fe201008: 0x0
      Value at address 0xffff0000fe20100c: 0x0
      Value at address 0xffff0000fe201010: 0x0
      
  5. 尝试修改str命令相关代码

    目前的str只能以8个字节为间隔来写入地址的值,要求改为以4个字节为间隔来写入地址的值(地址都是以16进制表示的),例如:

    arceos# str ffff0000fe201000 123
    
    arceos# str ffff0000fe201004 123  //修改前如果输入ldr ffff0000fe201004 会直接崩溃
    
    
  6. 尝试输出字母A:

    尝试向ffff0000fe201000中写入41,使其输出字母A:

    arceos# str ffff0000fe201000 41
    Aarceos# 
    

    可以看到输出了一个字母A。(如果没有输出A,可能原因是提供的str代码执行后会打印出很多东西,导致A的结果被顶掉了,所以可以把一些打印语句删除再进行尝试)

若没有开发板则在qemu模拟器中运行

  1. 在qemu中运行kernel8.img:

    ./qemu-system-aarch64 -m 2G -smp 4 -cpu cortex-a72 -machine raspi4b2g -nographic -kernel arceos/kernel8.img
    
  2. 可以看到输出:

           d8888                            .d88888b.   .d8888b.
          d88888                           d88P" "Y88b d88P  Y88b
         d88P888                           888     888 Y88b.
        d88P 888 888d888  .d8888b  .d88b.  888     888  "Y888b.
       d88P  888 888P"   d88P"    d8P  Y8b 888     888     "Y88b.
      d88P   888 888     888      88888888 888     888       "888
     d8888888888 888     Y88b.    Y8b.     Y88b. .d88P Y88b  d88P
    d88P     888 888      "Y8888P  "Y8888   "Y88888P"   "Y8888P"
    
    arch = aarch64
    platform = aarch64-raspi4
    target = aarch64-unknown-none-softfloat
    smp = 1
    build_mode = release
    log_level = debug
    
    [  0.108866 0 axruntime:126] Logging is enabled.
    [  0.114596 0 axruntime:127] Primary CPU 0 started, dtb = 0x0.
    [  0.121542 0 axruntime:129] Found physcial memory regions:
    [  0.128229 0 axruntime:131]   [PA:0x80000, PA:0x8a000) .text (READ | EXECUTE | RESERVED)
    [  0.137517 0 axruntime:131]   [PA:0x8a000, PA:0x8d000) .rodata (READ | RESERVED)
    [  0.146113 0 axruntime:131]   [PA:0x8d000, PA:0x91000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED)
    [  0.157053 0 axruntime:131]   [PA:0x91000, PA:0xd1000) boot stack (READ | WRITE | RESERVED)
    [  0.166603 0 axruntime:131]   [PA:0xd1000, PA:0xd2000) .bss (READ | WRITE | RESERVED)
    [  0.175633 0 axruntime:131]   [PA:0x0, PA:0x1000) spintable (READ | WRITE | RESERVED)
    [  0.184662 0 axruntime:131]   [PA:0xd2000, PA:0xfc000000) free memory (READ | WRITE | FREE)
    [  0.194213 0 axruntime:131]   [PA:0xfe201000, PA:0xfe202000) mmio (READ | WRITE | DEVICE | RESERVED)
    [  0.204545 0 axruntime:131]   [PA:0xff841000, PA:0xff849000) mmio (READ | WRITE | DEVICE | RESERVED)
    [  0.214877 0 axruntime:149] Initialize platform devices...
    [  0.221562 0 axruntime:185] Primary CPU 0 init OK.
    Available commands:
      exit
      help
      uname
      ldr
      str
    arceos#
    
  3. 同上面的第7步

  4. 同上面的第8步

  5. 同上面的第9步

至此,实验五结束,最终提交实验过程记录(包含出现的各类问题及解决办法)以及关于ArceOS成功运行,并且执行ldr一次输出20个值的结果(以ffff0000fe201000为起始地址),最后再成功输出字母A的结果。

第二阶段:Rust编写树莓派串口驱动

此阶段主要关于树莓派如何启用串口。

前置知识一:树莓派 GPIO 功能

引脚介绍

  • 下图为树莓派40个引脚的介绍。

  • 根据官方文档,可知各种 UART 信号如何(包括迷你 UART)映射到通用 I/O (GPIO) 上。
PullALT0ALT1ALT2ALT3ALT4ALT5
GPIO0HighTXD2
GPIO1HighRXD2
GPIO2HighCTS2
GPIO3HighRTS2
GPIO4HighTXD3
GPIO5HighRXD3
GPIO6HighCTS3
GPIO7HighRTS3
GPIO8HighTXD4
GPIO9HighRXD4
GPIO10HighCTS4
GPIO11HighRTS4
GPIO12HighTXD5
GPIO13HighRXD5
GPIO14LowTXD0CTS5
GPIO15LowRXD0RTS5
GPIO16LowCTS0
GPIO17LowRTS0

相关寄存器

GPIO 寄存器基地址:0xfe200000

寄存器简介

  • 根据官方文档,以下表格是部分寄存器的介绍。
OffsetNameDescription
0x00GPFSEL0GPIO Function Select 0
0x04GPFSEL1GPIO Function Select 1
0x08GPFSEL2GPIO Function Select 2
0x0cGPFSEL3GPIO Function Select 3
0x10GPFSEL4GPIO Function Select 4
0x14GPFSEL5GPIO Function Select 5
0xe4GPIO_PUP_PDN_CNTRL_REG0GPIO Pull-up / Pull-down Register 0
0xe8GPIO_PUP_PDN_CNTRL_REG1GPIO Pull-up / Pull-down Register 1
0xecGPIO_PUP_PDN_CNTRL_REG2GPIO Pull-up / Pull-down Register 2
0xf0GPIO_PUP_PDN_CNTRL_REG3GPIO Pull-up / Pull-down Register 3
  • GPFSEL寄存器,主要是控制GPIOxx--GPIOxx的功能选择。

    GPFSEL0控制GPIO0--GPIO9的功能选择;

    GPFSEL1控制GPIO10--GPIO19的功能选择;

    GPFSEL2控制GPIO20--GPIO29的功能选择;

    GPFSEL3控制GPIO30--GPIO39的功能选择;

    GPFSEL4控制GPIO40--GPIO49的功能选择;

    GPFSEL5控制GPIO50--GPIO57的功能选择。

    该寄存器存储32位的二进制数,每3位代表了一个GPIO引脚选择的功能,最后两位保留,其中,每个值的对应关系为

    000 = GPIO Pin ~ is an input
    001 = GPIO Pin ~ is an output
    100 = GPIO Pin ~ takes alternate function 0
    101 = GPIO Pin ~ takes alternate function 1
    110 = GPIO Pin ~ takes alternate function 2
    111 = GPIO Pin ~ takes alternate function 3
    011 = GPIO Pin ~ takes alternate function 4
    010 = GPIO Pin ~ takes alternate function 5
    
  • GPIO_PUP_PDN_CNTRL_REG寄存器,主要用于对GPIOxx--GPIOxx配置GPIO引脚的上拉(Pull-Up)和下拉(Pull-Down)电阻(上拉电阻会将引脚连接到正电源,从而将引脚拉高到高电平;下拉电阻会将引脚连接到地(GND),从而将引脚拉低到低电平)。

    GPIO_PUP_PDN_CNTRL_REG0用于对GPIO0--GPIO15配置GPIO引脚的上拉(Pull-Up)和下拉(Pull-Down)电阻;

    GPIO_PUP_PDN_CNTRL_REG1用于对GPIO16--GPIO31配置GPIO引脚的上拉(Pull-Up)和下拉(Pull-Down)电阻;

    GPIO_PUP_PDN_CNTRL_REG2用于对GPIO32--GPIO47配置GPIO引脚的上拉(Pull-Up)和下拉(Pull-Down)电阻;

    GPIO_PUP_PDN_CNTRL_REG3用于对GPIO48--GPIO57配置GPIO引脚的上拉(Pull-Up)和下拉(Pull-Down)电阻。

    该寄存器存储32位的二进制数,每2位代表了一个GPIO引脚上拉/下拉电阻选择的可能配置,其中,每个值的对应关系为:

    00 = No resistor is selected
    01 = Pull up resistor is selected
    10 = Pull down resistor is selected
    11 = Reserved
    

关于寄存器的代码介绍

位置:rust-raspberrypi-OS-tutorials/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs

#![allow(unused)]
fn main() {
register_bitfields! {
    u32,

    /// GPIO Function Select 1
    GPFSEL1 [
        /// Pin 15
        FSEL15 OFFSET(15) NUMBITS(3) [
            Input = 0b000,
            Output = 0b001,
            AltFunc0 = 0b100  // PL011 UART RX
        ],
        /// Pin 14
        FSEL14 OFFSET(12) NUMBITS(3) [
            Input = 0b000,
            Output = 0b001,
            AltFunc0 = 0b100  // PL011 UART TX
        ],
    ],
    /// GPIO Pull-up/down Register
    /// BCM2837 only.
    GPPUD [
        /// Controls the actuation of the internal pull-up/down control line to ALL the GPIO pins.
        PUD OFFSET(0) NUMBITS(2) [
            Off = 0b00,
            PullDown = 0b01,
            PullUp = 0b10
        ]
    ],
    /// GPIO Pull-up/down Clock Register 0
    /// BCM2837 only.
    GPPUDCLK0 [
        /// Pin 15
        PUDCLK15 OFFSET(15) NUMBITS(1) [
            NoEffect = 0,
            AssertClock = 1
        ],
        /// Pin 14
        PUDCLK14 OFFSET(14) NUMBITS(1) [
            NoEffect = 0,
            AssertClock = 1
        ],
    ],

    /// GPIO Pull-up / Pull-down Register 0
    /// BCM2711 only.
    GPIO_PUP_PDN_CNTRL_REG0 [
        /// Pin 15
        GPIO_PUP_PDN_CNTRL15 OFFSET(30) NUMBITS(2) [
            NoResistor = 0b00,
            PullUp = 0b01
        ],
        /// Pin 14
        GPIO_PUP_PDN_CNTRL14 OFFSET(28) NUMBITS(2) [
            NoResistor = 0b00,
            PullUp = 0b01
        ],
    ]
}

register_structs! {
    #[allow(non_snake_case)]
    RegisterBlock {
        (0x00 => _reserved1),
        (0x04 => GPFSEL1: ReadWrite<u32, GPFSEL1::Register>),
        (0x08 => _reserved2),
        (0x94 => GPPUD: ReadWrite<u32, GPPUD::Register>),
        (0x98 => GPPUDCLK0: ReadWrite<u32, GPPUDCLK0::Register>),
        (0x9C => _reserved3),
        (0xE4 => GPIO_PUP_PDN_CNTRL_REG0: ReadWrite<u32, GPIO_PUP_PDN_CNTRL_REG0::Register>),
        (0xE8 => @END),
    }
}
}

根据上述内容,可以知道GPIO14、15要实现串口通信,需要启用ALT0功能。而这对应着关于GPIO的GPFSEL1寄存器,

所以,在代码中,在第12-14位和第15-17位设置为0b100:

#![allow(unused)]
fn main() {
 GPFSEL1 [
        /// Pin 15
        FSEL15 OFFSET(15) NUMBITS(3) [
            Input = 0b000,
            Output = 0b001,
            AltFunc0 = 0b100  // PL011 UART RX
        ],

        /// Pin 14
        FSEL14 OFFSET(12) NUMBITS(3) [
            Input = 0b000,
            Output = 0b001,
            AltFunc0 = 0b100  // PL011 UART TX
        ],
 ]

}

还要设置上拉/下拉电阻,在第28、29位和第30、31位设置为0b01:

#![allow(unused)]
fn main() {
 GPIO_PUP_PDN_CNTRL_REG0 [
        /// Pin 15
        GPIO_PUP_PDN_CNTRL15 OFFSET(30) NUMBITS(2) [
            NoResistor = 0b00,
            PullUp = 0b01
        ],

        /// Pin 14
        GPIO_PUP_PDN_CNTRL14 OFFSET(28) NUMBITS(2) [
            NoResistor = 0b00,
            PullUp = 0b01
        ]
  ]
}

前置知识二:UART 通信

UART 是一种通用的串行、异步通信总线,该总线有两条数据线,TXD 用于发送数据,RXD用于接收数据,在嵌入式系统中常用于主机与辅助设备之间的通信。

UART连接方式如图:

基本特性和工作原理:

  1. 异步性: UART是异步通信协议,发送和接收设备之间不需要共享时钟信号。相反,它使用起始位(Start Bit)和停止位(Stop Bit)来标识每个数据字节的开始和结束,以及一个或多个数据位组成的数据字节。

  2. 数据帧: UART通信的数据传输以数据帧为单位。每个数据帧通常包括一个起始位、8位数据(通常是8位,但也可以是其他位数)、一个可选的奇偶校验位和一个或多个停止位。起始位和停止位提供了数据的边界,确保接收端能够准确地识别每个字节。

  3. 波特率: 波特率是UART通信中的数据传输速度,通常以每秒位数(bps,bits per second)为单位。发送和接收设备必须使用相同的波特率进行通信,以确保数据的正确传输。 波特率计算公式:波特率=时钟频率/16*(IBRD+(FBRD)/64)

  4. 起始位和停止位: 起始位指示数据传输的开始,停止位标志着数据传输的结束。当接收端检测到起始位时,它开始接收数据位,然后是奇偶校验位(如果启用),最后是停止位。接收端通过检测停止位来确定整个数据帧的结束。

  5. 奇偶校验: UART通信可以使用奇偶校验位来验证数据的准确性。奇偶校验可以选择奇数或偶数校验。发送端计算数据位中1的数量,如果选择奇校验,发送端会确保总位数(包括校验位)为奇数;如果选择偶校验,发送端会确保总位数为偶数。

相关寄存器

寄存器简介

根据官方文档,以下是关于部分寄存器的介绍。

OffsetNameDescription
0x00DRData Register
0x04RSRECR
0x18FRFlag register
0x24IBRDInteger Baud rate divisor
0x28FBRDFractional Baud rate divisor
0x2cLCRHLine Control register
0x30CRControl register
0x44ICRInterrupt Clear Register
0x48DMACRDMA Control Register
  • DR寄存器,数据寄存器,用于存储将要发送的数据或接收到的数据。

  • FR寄存器,标志寄存器。

  • IBRD寄存器,整数波特率除数寄存器。

  • FBRD寄存器,分数波特率除数寄存器。

IBRD和FBRD寄存器决定了波特率的数值。

  • LCR_H寄存器,线控制寄存器,用于配置 UART 的数据格式,包括数据位数、停止位数、奇偶校验设置等。

  • CR寄存器,控制寄存器,控制UART的启用,控制发送和接收数据的启用。

  • ICR寄存器,中断清除寄存器,用于清除 UART 中断标志,以便在处理中断后复位相应的中断状态。具体来说,当某个中断发生时,相应的标志位会被设置。通过写入 ICR 寄存器,可以清除这些标志位。

关于寄存器的代码部分

位置:rust-raspberrypi-OS-tutorials/06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_pl011_uart.rs

#![allow(unused)]
fn main() {
register_bitfields! {
    u32,

    /// Flag Register.
    FR [
        /// Transmit FIFO empty. The meaning of this bit depends on the state of the FEN bit in the
        /// Line Control Register, LCR_H.
        ///
        /// - If the FIFO is disabled, this bit is set when the transmit holding register is empty.
        /// - If the FIFO is enabled, the TXFE bit is set when the transmit FIFO is empty.
        /// - This bit does not indicate if there is data in the transmit shift register.
        TXFE OFFSET(7) NUMBITS(1) [],

        /// Transmit FIFO full. The meaning of this bit depends on the state of the FEN bit in the
        /// LCR_H Register.
        ///
        /// - If the FIFO is disabled, this bit is set when the transmit holding register is full.
        /// - If the FIFO is enabled, the TXFF bit is set when the transmit FIFO is full.
        TXFF OFFSET(5) NUMBITS(1) [],

        /// Receive FIFO empty. The meaning of this bit depends on the state of the FEN bit in the
        /// LCR_H Register.
        ///
        /// - If the FIFO is disabled, this bit is set when the receive holding register is empty.
        /// - If the FIFO is enabled, the RXFE bit is set when the receive FIFO is empty.
        RXFE OFFSET(4) NUMBITS(1) [],

        /// UART busy. If this bit is set to 1, the UART is busy transmitting data. This bit remains
        /// set until the complete byte, including all the stop bits, has been sent from the shift
        /// register.
        ///
        /// This bit is set as soon as the transmit FIFO becomes non-empty, regardless of whether
        /// the UART is enabled or not.
        BUSY OFFSET(3) NUMBITS(1) []
    ],

    /// Integer Baud Rate Divisor.
    IBRD [
        /// The integer baud rate divisor.
        BAUD_DIVINT OFFSET(0) NUMBITS(16) []
    ],

    /// Fractional Baud Rate Divisor.
    FBRD [
        ///  The fractional baud rate divisor.
        BAUD_DIVFRAC OFFSET(0) NUMBITS(6) []
    ],

    /// Line Control Register.
    LCR_H [
        /// Word length. These bits indicate the number of data bits transmitted or received in a
        /// frame.
        #[allow(clippy::enum_variant_names)]
        WLEN OFFSET(5) NUMBITS(2) [
            FiveBit = 0b00,
            SixBit = 0b01,
            SevenBit = 0b10,
            EightBit = 0b11
        ],

        /// Enable FIFOs:
        ///
        /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become 1-byte-deep holding
        /// registers.
        ///
        /// 1 = Transmit and receive FIFO buffers are enabled (FIFO mode).
        FEN  OFFSET(4) NUMBITS(1) [
            FifosDisabled = 0,
            FifosEnabled = 1
        ]
    ],

    /// Control Register.
    CR [
        /// Receive enable. If this bit is set to 1, the receive section of the UART is enabled.
        /// Data reception occurs for either UART signals or SIR signals depending on the setting of
        /// the SIREN bit. When the UART is disabled in the middle of reception, it completes the
        /// current character before stopping.
        RXE OFFSET(9) NUMBITS(1) [
            Disabled = 0,
            Enabled = 1
        ],

        /// Transmit enable. If this bit is set to 1, the transmit section of the UART is enabled.
        /// Data transmission occurs for either UART signals, or SIR signals depending on the
        /// setting of the SIREN bit. When the UART is disabled in the middle of transmission, it
        /// completes the current character before stopping.
        TXE OFFSET(8) NUMBITS(1) [
            Disabled = 0,
            Enabled = 1
        ],

        /// UART enable:
        ///
        /// 0 = UART is disabled. If the UART is disabled in the middle of transmission or
        /// reception, it completes the current character before stopping.
        ///
        /// 1 = The UART is enabled. Data transmission and reception occurs for either UART signals
        /// or SIR signals depending on the setting of the SIREN bit
        UARTEN OFFSET(0) NUMBITS(1) [
            /// If the UART is disabled in the middle of transmission or reception, it completes the
            /// current character before stopping.
            Disabled = 0,
            Enabled = 1
        ]
    ],

    /// Interrupt Clear Register.
    ICR [
        /// Meta field for all pending interrupts.
        ALL OFFSET(0) NUMBITS(11) []
    ]
}

register_structs! {
    #[allow(non_snake_case)]
    pub RegisterBlock {
        (0x00 => DR: ReadWrite<u32>),
        (0x04 => _reserved1),
        (0x18 => FR: ReadOnly<u32, FR::Register>),
        (0x1c => _reserved2),
        (0x24 => IBRD: WriteOnly<u32, IBRD::Register>),
        (0x28 => FBRD: WriteOnly<u32, FBRD::Register>),
        (0x2c => LCR_H: WriteOnly<u32, LCR_H::Register>),
        (0x30 => CR: WriteOnly<u32, CR::Register>),
        (0x34 => _reserved3),
        (0x44 => ICR: WriteOnly<u32, ICR::Register>),
        (0x48 => @END),
    }
}

impl PL011UartInner {
    
    ... ...

    pub fn init(&mut self) {
        
        self.flush();

        // Turn the UART off temporarily.
        self.registers.CR.set(0);

        // Clear all pending interrupts.
        self.registers.ICR.write(ICR::ALL::CLEAR);

        // Set new baud rate = 115200
        // (48_000_000 / 16) / 115200 = 26.0416667
        // INTEGER((0.0416667 * 64) + 0.5) = 3.16666688
        self.registers.IBRD.write(IBRD::BAUD_DIVINT.val(26));
        self.registers.FBRD.write(FBRD::BAUD_DIVFRAC.val(3));

        self.registers
            .LCR_H
            .write(LCR_H::WLEN::EightBit + LCR_H::FEN::FifosEnabled);

        // Turn the UART on.
        self.registers
            .CR
            .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);
    }

    ... ...
}
}

要将波特率设置为115200,所以,在代码中:

self.registers.IBRD.write(IBRD::BAUD_DIVINT.val(26));
self.registers.FBRD.write(FBRD::BAUD_DIVFRAC.val(3));

要启用FIFO,并且将发送或接收的数据位数设置为8位,所以:

self.registers
            .LCR_H
            .write(LCR_H::WLEN::EightBit + LCR_H::FEN::FifosEnabled);

还要启用表示UART启用,同时启用发送和接收数据,所以:

self.registers
    .CR
    .write(CR::UARTEN::Enabled + CR::TXE::Enabled + CR::RXE::Enabled);

实验一:UART0 的启用

  1. 在rust-raspberrypi-OS-tutorials/05_drivers_gpio_uart中输入:

    BSP=rpi4 make
    

    编译生成一个kernel8.img文件。

  2. 把新生成的 kernel8.img 拷贝到 sd 卡上,并将SD卡插入RPi。

  3. 运行miniterm target,在主机上打开UART设备:

    make miniterm
    
  4. 将USB串口连接到主机PC,然后打开树莓派电源开关。

  5. 会得到以下输出:

    Miniterm 1.0
    
    [MT] ⏳ Waiting for /dev/ttyUSB0
    [MT] ✅ Serial connected
    [0] mingo version 0.5.0
    [1] Booting on: Raspberry Pi 4
    [2] Drivers loaded:
         1. BCM PL011 UART
         2. BCM GPIO
    [3] Chars written: 117
    [4] Echoing input now
    

如果没有树莓派主板,可以在qemu上运行生成的kernel8.img。

./qemu-system-aarch64 -m 2G -smp 4 -cpu cortex-a72 -machine raspi4b2g -nographic -kernel rust-raspberrypi-OS-tutorials/05_drivers_gpio_uart/kernel8.img

至此,实验一结束,最终提交实验过程记录(包含出现的各类问题及解决办法)以及正确的输出结果。

实验二:通过 UART0 驱动小车

补充知识:树莓派如何与小车(STM32)相连

参考:https://github.com/orgs/chenlongos/discussions/14

实验内容

驱动小车的代码位置:arceos/apps/boards/raspi4/src/main.rs

  1. 在ArceOS目录下,输入:

    make A=apps/boards/raspi4 ARCH=aarch64 PLATFORM=aarch64-raspi4 LOG=debug SMP=4
    

    编译出ArceOS在raspi4 上的一个镜像raspi4_aarch64-raspi4.bin。

  2. 在rust-raspberrypi-OS-tutorials/06_uart_chainloader中输入:

    BSP=rpi4 make
    

    编译生成一个kernel8.img文件。

  3. 把 kernel8.img 和 raspi4_aarch64-raspi4.bin 通过 cat 命令拼接到一个 bin 文件中,仍然取名为 kernel8.img:

    cat ../rust-raspberrypi-OS-tutorials/06_uart_chainloader/kernel8.img apps/boards/raspi4/raspi4_aarch64-raspi4.bin > kernel8.img
    
  4. 把新生成的 kernel8.img 拷贝到 sd 卡上,并且将树莓派串口连线与小车相连。

  5. 打开树莓派电源,可以看到小车会走出一个方形的轨迹。

  6. 修改代码,改变小车的运动轨迹。(尝试使小车跑出不同的轨迹形状,如三角形等)

    可以参考以下资料:

    https://github.com/orgs/chenlongos/discussions/13#discussion-5604815

若没有小车,可以在qemu模拟器上运行,

./qemu-system-aarch64 -m 2G -smp 4 -cpu cortex-a72 -machine raspi4b2g -nographic -kernel arceos/kernel8.img

尝试看到代码的逻辑是可以跑通的。

至此,实验二结束,最终提交实验过程记录(包含出现的各类问题及解决办法)以及相关代码。

实验三:通过 UART0 启用 UART5

若已有树莓派开发板则进行以下操作:

  1. GPIO改为ALT4功能启用UART5

    根据前置知识,已经知道GPIO12和GPIO13的ALT4功能可以用来进行串口通信,为UART5。其中,GPIO12对应着TXD/发送、GPIO13对应着RXD/接收。

    • 在原先启用GPIO14、15的ALT0的基础上,需要在偏移地址为0x04的GPFSEL1寄存器的第6-8位和第9-11位将值设置为0b011,也就是将值变为0b0010 0100 0110 1100 0000即0x246c0。

      let str_addr1 = "ffff0000fe200004 246c0";
      do_str(str_addr1);
      
    • 在偏移地址为0xe4的GPIO_PUP_PDN_CNTRL_REG0寄存器中将值变为0b0101_0101_0000_0000_0000_0000_0000_0000即0x5500_0000。

      let str_addr2 = "ffff0000fe2000e4 55000000";
      do_str(str_addr2);
      

    这样GPIO12、13的功能就变为了ALT4。

  2. 配置UART相关寄存器

    通过bcm2711的数据手册,可以知道UART5的起始地址为0xfe201a00

    • 波特率设置为115200,将偏移地址为0x24的IBRD寄存器的值变为26,将偏移地址为0x28的FBRD寄存器的值变为3。

      let str_addr3 = "ffff0000fe201a24 1A";
      let str_addr4 = "ffff0000fe201a28 3";
      do_str(str_addr3);
      do_str(str_addr4);
      
    • 启用FIFO缓冲区,设置数据位数为8位,即将偏移地址为0x2c的寄存器的值变为70。

      let str_addr5 = "ffff0000fe201a2c 70";
      do_str(str_addr5);
      
    • 启用UART,启用发送接收,即将偏移地址为0x30的寄存器的值变为301。

      let str_addr6 = "ffff0000fe201a30 301";
      do_str(str_addr6);
      

      所以,在shell命令的源代码中,添加一个命令 UART ,使得输入 UART 5 便可以启用 UART 5:

      #![allow(unused)]
      fn main() {
      fn do_UART(args: &str) {
          match args {
          "5" =>{
              let str_addr0 = "ffff0000fe200000 1B";
              let str_addr1 = "ffff0000fe200004 246c0";
              let str_addr2 = "ffff0000fe2000e4 55000000";
              let str_addr3 = "ffff0000fe201a24 1A";
              let str_addr4 = "ffff0000fe201a28 3";
              let str_addr5 = "ffff0000fe201a2c 70";
              let str_addr6 = "ffff0000fe201a30 301";
              //调用str写入函数
              do_str(str_addr0);
              do_str(str_addr1);
              do_str(str_addr2);
              do_str(str_addr3);
              do_str(str_addr4);
              do_str(str_addr5);
              do_str(str_addr6);
              }
          _ => {}
          } 
      }
      }
      
  3. 将以下测试函数添加到shell命令中:

    #![allow(unused)]
    fn main() {
    fn do_test(args: &str) {
            fn delay(seconds: u64) {
             for i in 1..seconds + 1 {
                 fn fibonacci_recursive(n: u64) -> u64 {
                     if n == 0 {
                         return 0;
                     }
                     if n == 1 {
                         return 1;
                     }
                     return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2);
                 }
                 fibonacci_recursive(36 + (i % 2));
             }
         }
     if args == "run" {
         loop {
             let arges = "ffff0000fe201a00 41";
             do_str(arges);
             delay(4);
         }
     }
    }
    }
    

    再启用UART 5后,运行此命令 test run ,然后将UART 5的TXD、RXD和GND与PC相连,观察输出。

    如果屏幕中会不断地输出字母A,则表示UART5被成功启用,可以通过UART5来进行数据通信。

若没有开发板则进行以下操作:

  1. 查看rust-raspberrypi-OS-tutorials/06_uart_chainloader关于gpio和uart的代码

    位置:rust-raspberrypi-OS-tutorials/06_uart_chainloader/src/bsp/device_driver/bcm/

    修改bcm2xxx_gpio.rs中的:

    #![allow(unused)]
    fn main() {
    GPFSEL1 [
         /// Pin 15
         FSEL15 OFFSET(15) NUMBITS(3) [
             Input = 0b000,
             Output = 0b001,
             AltFunc0 = 0b100  // PL011 UART RX
    
         ],
    
         /// Pin 14
         FSEL14 OFFSET(12) NUMBITS(3) [
             Input = 0b000,
             Output = 0b001,
             AltFunc0 = 0b100  // PL011 UART TX
         ]
     ],
    }
    

    将FSEL14、15改为12、13,将OFFSET偏移位改为6、9, 由于需要启用的UART5的ALT功能为4,所以需要将AltFunc0 = 0b100变为AltFunc4 = 0b010

    #![allow(unused)]
    fn main() {
    GPIO_PUP_PDN_CNTRL_REG0 [
         /// Pin 15
         GPIO_PUP_PDN_CNTRL15 OFFSET(30) NUMBITS(2) [
             NoResistor = 0b00,
             PullUp = 0b01
         ],
    
         /// Pin 14
         GPIO_PUP_PDN_CNTRL14 OFFSET(28) NUMBITS(2) [
             NoResistor = 0b00,
             PullUp = 0b01
         ],
     ]
    }
    

    将OFFSET偏移位改为24、26

  2. 用UART5的基地址替换掉UART0的基地址:

    位置:rust-raspberrypi-OS-tutorials/06_uart_chainloader/src/bsp/raspberrypi/memory.rs

    #![allow(unused)]
    fn main() {
    pub const UART_OFFSET:         usize = 0x0020_1000;
    ···
    pub const START:            usize =         0xFE00_0000;
    pub const PL011_UART_START: usize = START + UART_OFFSET;
    }
    

    将UART0的基地址fe201000变为UART5的基地址fe201a00

  3. 生成kernel8.img文件,尝试在qemu模拟器中运行kernel8.img

上述步骤是将原先可用的串口UART0变为了串口UART5,所以还是只启用了一个串口,因此

  1. 在rust-raspberrypi-OS-tutorials/06_uart_chainloader中修改并添加代码,使得串口UART0和UART5都被直接启用

至此,实验三结束,最终提交实验过程记录(包含出现的各类问题及解决办法)以及屏幕不断打印字母A的截图。

实验四:通过 UART0 启用 UART2/3/4

根据实验三启用UART5,尝试再启用一个新的串口UART2/3/4。

同实验三,如果没有树莓派,可以查看rust-raspberrypi-OS-tutorials/06_uart_chainloader关于gpio和uart的代码,修改相关代码来启用uart2/3/4。

最终提交实验过程记录(包含出现的各类问题及解决办法)以及修改的代码部分,并且可以成功通过test测试。

实验五:通过 UART0 发送指令,由 UART2/3/4/5 驱动小车

由实验二和实验三,考虑将树莓派通过 UART0 与主机相连,通过 UART5 与小车相连,然后可以在主机端驱动小车运动

因此,本实验要求为:在第一阶段实验五和第二阶段实验二、三、四的基础上,在shell命令相关代码中添加一个 move 命令,使得可以通过主机下达命令从而驱使小车运动

类似步骤为:

  1. 在shell命令中添加move函数,实现驱动小车的功能。

  2. 将新生成的关于shell的镜像与kernel8.img合并,复制到SD卡上。

  3. 树莓派通过 UART0 (引脚6(GND)、8(TXD)、10(RXD))与主机相连,通过 UART5 (引脚34(GND)、32(TXD)、33(RXD))与小车相连。

  4. 打开连接软件,启动树莓派电源。

  5. 在shell命令中输入move相关命令,观察发现小车开始运动(注意:在实验时应该将小车四轮悬空)。

至此,实验五结束,最终提交实验过程记录(包含出现的各类问题及解决办法)以及move部分的代码以及通过主机端控制小车运动的视频。

第三阶段:Rust编写树莓派USB驱动

经过第二阶段的了解、学习,可以发现目前如果想要用树莓派驱动小车需要对STM32板子进行飞线处理,而这需要进行焊接,非常的不方便,而且树莓派本身含有许多的USB接口,因此,考虑编写USB转串口驱动,使得树莓派可以通过USB接口控制小车运动,就像这样:

通过串口控制

背景资料:https://github.com/orgs/chenlongos/discussions/14

参考资料:

  1. https://blog.csdn.net/fudan_abc
  2. VL805相关手册
  3. xhci协议

USB/XHCI驱动 前情提要&背景知识

  • 什么是xhci?
  • 答: xhci是USB的控制器, USB1.0的控制器是UHCI/OHCI, 2.0是EHCI, EHCI不向下兼容1.0, 直到USB3.0的XHCI出现,统一了操作标准
  • 具体的来说,有没有参考资料?
  • 答:有,之后整理好群里打包发
  • XHCI可以做什么?
  • 答:分为两部分,首先XHCI控制器负责整个USB系统的数据与其他内存空间的交互,其次,XHCI控制器负责控制USB设备
    • 追问:控制和传输,有区别吗?
    • 答:有,传输不改变设备的状态,具体来说,不管是USB HUB还是USB FUNCTION,其实都是状态机
    • 追问2: HUB/FUNCTION又是什么?
    • 答:这么描述吧:
      • 首先HUB/FUNCTION都是USB设备
      • HUB是可以管理设备的设备(比如扩展坞,值得一提的是其实整个USB设备树的根-称为ROOTHUB,其实也只不过是一个特殊的扩展坞而已)
      • FUNCTION是实际上有功能的设备(例:起存储功能的U盘,起网卡功能的USB网卡...)
    • 追问3:再说说状态机的事?
    • 答:在Intel的XHCI文档中搜索state machine来了解各部分的状态
  • 好吧:那么USB系统是如何构成的?
  • 答:宏观上是树状结构,逻辑上USB设备都是事件驱动的事件机器:
    • 对于HUB,其内部有两种事件发送端,但是事件的接收端是统一的:
      • 事件接收端:EventRing-其实是个消息队列,当EventRing接收到事件后会想办法通知操作系统-用中断,或者操作系统主动轮询这个队列以检查新到的事件
      • 内部事件发送端:CommandRing-负责发送改变HUB状态的/调用HUB硬件实现的功能的请求事件的地方
      • 设备事件发送端:TransferRing-负责发送与设备的EndPoint交互(控制/传输都通过这个ring进行)的事件的地方
        • 追问:Endpoint是什么?
        • 答:是在物理上传输数据的部分,一个设备可以有很多个EndPoint,具体数量随USB协议版本而变化,EndPoint一般是单向的,Hub与设备的EndPoint建立通信后,这个逻辑概念上的数据传输路线就被叫做数据管道
        • 但是Endpoint0是特殊的,他必然存在,且是唯一同时可以双向通信的EndPoint,负责与HUB交换设备的"控制"事件,人们喜欢把Endpoint0的传输操作叫做"控制传输"
        • 为什么要这么设计?因为更多的管道就是更多的带宽!
      • 事件传输单元:TRB(Transfer Request Block)-每个TRB都由4位u32组成,且容纳这些数据的内存必须16位对齐,其中第四个u32的10-15位内保存的是TRB类型(即事件类型)的唯一标识符
      • 事实上,这三个Ring在数据结构上拥有相同的实现方式: 其中RING_LENGTH随不同设备而改变,属于配置选项,同时,ring的最后一个单元总是要放一个LinkTrb以标明这里是ring的结尾,需要从头开始循环。
        #![allow(unused)]
        fn main() {
        let ring = [[u32;4];RING_LENGTH];
        let enqueue_pointer:*const [u32;4];
        let dequeue_pointer:*const [u32;4];
        let cycle_bit:bool;
        }
        
        • 追问:循环?
        • 答:是的,ring表示这玩意是个用数组实现的循环队列,当然,也有队头(dequeue)和队尾(enqueue),这两个指针中间的TRB就是正在处理的事件,同时,为了硬件纠错,还引入了cycle_bit,正在处理的事件的cycle_bit必须与环的cycle_bit一致才被视为有效事件,否则当成很久之前就已经处理过了,会直接跳过/报错。
        • TRB大体可分为三类:Control/Transfer/Event TRB,名字就已经表明了他们分别在什么地方出现
    • 对于设备,我们其实并不关心,这部分是制造厂商要负责的事情,我们只在乎数据/控制的传输,把它当成一个塞进去命令就会给反馈的黑盒即可
      • 具体说说!
      • 答:好吧,与设备的通信如同TCP协议一样,有着"三次握手"的格式
      • 首先,发送Setup TRB---这表示一次事件的开始,以及表明了接下来要传输什么数据,setup TRB的类型是有限的,已经在xhci文档/usb文档里列了出来,请自行查阅
      • 然后,发送Data TRB---这部分是可选的,有些TRB并不需要发送数据,比如GetDescriptor TRB,这个Setup TRB中就已经包含了完整的请求信息(请求的数据条目的编号)
      • 最后:发送Status TRB--标准着这次事件的结束,其中包含了一些额外的控制信息,与中断系统/连续传输有关
      • 最后的最后:敲响门铃寄存器来通知设备接受事件,并在EventRing/本设备的doorbell中断上等待设备回报回来的事件。
        • doorbell是什么?
        • 硬件上的实现,这玩意是一个数组,主要用处就是通知被分配在特定slot上的设备有事件被发起,请接收并处理
        • 其中doorbell 0比较特殊,它被称为"默认地址"-实际上是控制器自己,当一个设备刚插上HUB时,它会被分配到默认地址上,(因为这时设备还没有被分配地址),这也就意味着xhci一次性只能处理一个设备插进来的情况,如果在极短的时间插进来了多个设备,那么其他设备就得排队等待
        • 同时这也意味着,每个doorbell 都对应 一个分配出去的slot id,具体的请看xhci 文档
        • 那么什么是Slot?
        • 有这么两个概念:
          • port-HUB物理上有多少个usb口,每个port都有一个寄存器,这些寄存器是连续分配的,可以当初一个数组。
          • slot-hub一共能管理多少设备(包括下游设备,比如hub接hub),每个设备都有一个slot id,这样就抽象掉了port号的概念。
      • 我还是不明白,控制器怎么知道如何管理这些设备,具体来说,如何进行控制?
      • 答:通过dcbaa/, Device Context Base Address Array
        • Device Context,指的是我们为设备分配的内存区域,是用于控制设备的Endpoint+Slot的区域。
        • dcbaa,是我们分配的一个数组,其上包含了各个Device Context的地址(指针)
        • dcbaap,是xhci的一个寄存器,其值由我们配置为指向dcbaa的地址,xhci正是通过这个寄存器来知道/控制设备的配置状态的。
  • 好吧,能将整个流程完整的描述一遍吗?我是指程序上?
  • 答:从这里的try_init函数入手,这是整个驱动的入口,同时辅以xhci文档的第四章来确定你当前看的是哪一步。同时也可以参考飞腾派的官方嵌入式sdk
    • 经过与官方沟通的最新进展,sdk中的xhci并不稳定且正确,详细的请参考沟通记录,因此,请转而参考他们的freertos仓库。
  • 行!那么目前还需要干什么?
  • 参考问题文件夹,其中是与飞腾官方所沟通的一些问题,也是我们驱动目前需要解决的问题,如果有新问题,也请加进去。

任务一:PCIe主桥初始化

何为PCIe

PCIe(Peripheral Component Interconnect Express),是一种高速串行计算机扩展总线标准,用于连接计算机内部的硬件设备。PCIe是PCI的后继者,旨在提供更高的带宽和性能。

关键特点:

  1. 高速串行连接: 与传统的PCI总线使用并行连接不同,PCIe采用高速串行连接。这使得数据能够以更高的速率进行传输,提供更大的带宽。

  2. 多通道架构: PCIe采用多通道(lanes)的结构,每个通道都能独立传输数据。每个通道的带宽是独立分配的,通常以“x1”、“x4”、“x8”和“x16”等倍数来表示。例如,PCIe x16插槽提供比PCIe x1插槽更大的带宽。

  3. 点对点连接: 每个PCIe设备都与主板上的PCIe插槽之间建立一个点对点的连接。这种连接方式与传统PCI总线的共享连接方式相比,更有效地支持高带宽需求。

  4. 热插拔支持: PCIe支持热插拔,允许用户在计算机运行时插入或拔出PCIe设备,而无需重新启动计算机。

  5. 兼容性: PCIe是一种通用的总线标准,广泛应用于各种设备,包括显卡、网卡、固态硬盘、扩展卡等。

初始化实现

参考代码:https://github.com/Axsl666/arceos

运行结果:

       d8888                            .d88888b.   .d8888b.
      d88888                           d88P" "Y88b d88P  Y88b
     d88P888                           888     888 Y88b.
    d88P 888 888d888  .d8888b  .d88b.  888     888  "Y888b.
   d88P  888 888P"   d88P"    d8P  Y8b 888     888     "Y88b.
  d88P   888 888     888      88888888 888     888       "888
 d8888888888 888     Y88b.    Y8b.     Y88b. .d88P Y88b  d88P
d88P     888 888      "Y8888P  "Y8888   "Y88888P"   "Y8888P"

arch = aarch64
platform = aarch64-raspi4
target = aarch64-unknown-none-softfloat
smp = 1
build_mode = release
log_level = debug

[  0.108847 0 axruntime:126] Logging is enabled.
[  0.114577 0 axruntime:127] Primary CPU 0 started, dtb = 0x0.
[  0.121522 0 axruntime:129] Found physcial memory regions:
[  0.128209 0 axruntime:131]   [PA:0x80000, PA:0x89000) .text (READ | EXECUTE | RESERVED)
[  0.137498 0 axruntime:131]   [PA:0x89000, PA:0x8c000) .rodata (READ | RESERVED)
[  0.146093 0 axruntime:131]   [PA:0x8c000, PA:0x90000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED)
[  0.157033 0 axruntime:131]   [PA:0x90000, PA:0xd0000) boot stack (READ | WRITE | RESERVED)
[  0.166584 0 axruntime:131]   [PA:0xd0000, PA:0xd1000) .bss (READ | WRITE | RESERVED)
[  0.175613 0 axruntime:131]   [PA:0x0, PA:0x1000) spintable (READ | WRITE | RESERVED)
[  0.184643 0 axruntime:131]   [PA:0xd1000, PA:0xfc000000) free memory (READ | WRITE | FREE)
[  0.194193 0 axruntime:131]   [PA:0xfe201000, PA:0xfe202000) mmio (READ | WRITE | DEVICE | RESERVED)
[  0.204525 0 axruntime:131]   [PA:0xff841000, PA:0xff849000) mmio (READ | WRITE | DEVICE | RESERVED)
[  0.214857 0 axruntime:131]   [PA:0xfd500000, PA:0xfd509310) mmio (READ | WRITE | DEVICE | RESERVED)
[  0.225189 0 axruntime:149] Initialize platform devices...
[  0.231874 0 axruntime:185] Primary CPU 0 init OK.
Available commands:
  exit
  help
  uname
  ldr
  str
  uart
  test
arceos# [  0.245158 0 brcm_pcie::bcm2711:309] assert bridge reset
[  0.251670 0 brcm_pcie::bcm2711:313] assert fundamental reset
[  0.258618 0 brcm_pcie::bcm2711:319] deassert bridge reset
[  0.265304 0 brcm_pcie::bcm2711:326] enable serdes
[  0.271294 0 brcm_pcie::bcm2711:333] hw_rev772
[  0.276935 0 brcm_pcie::bcm2711:339] disable and clear any pending interrupts
[  0.340273 0 brcm_pcie::bcm2711:406] PCIe link is ready

arceos# ldr ffff0000fd508000
Value at address ffff0000fd508000: 0x34831106

代码分析

#![allow(unused)]
fn main() {
//相关寄存器地址及配置
register_bitfields![
    u32,

    //  Broadcom STB PCIe Register Offsets
    // 0x0188
    RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 [
        LITTLE_ENDIAN OFFSET(0) NUMBITS(1) [],
        ENDIAN_MODE_BAR2 OFFSET(0xC) NUMBITS(1) [],
    ],

    // 0x043c
    RC_CFG_PRIV1_ID_VAL3 [
        CLASS_ID  OFFSET(0) NUMBITS(24) [
            pcie_pcie_bridge = 0x060400
        ],
    ],

    ...
    
    RGR1_SW_INIT_1 [
        PCIE_RGR1_SW_INTI_1_PERST OFFSET(0) NUMBITS(1) [],
        RGR1_SW_INTI_1_GENERIC OFFSET(1) NUMBITS(1) [],
    ],

];

...

impl BCM2711PCIeHostBridgeRegs {
    // 设置桥接器软初始化标志
    fn bridge_sw_init_set(&self, bit: u32) {
        // 如果 bit 为 1,将 RGR1_SW_INTI_1_GENERIC 置位
        if bit == 1 {
            self.rgr1_sw_init
                .modify(RGR1_SW_INIT_1::RGR1_SW_INTI_1_GENERIC::SET);
        }
        // 如果 bit 为 0,清除 RGR1_SW_INTI_1_GENERIC 位
        if bit == 0 {
            self.rgr1_sw_init
                .modify(RGR1_SW_INIT_1::RGR1_SW_INTI_1_GENERIC::CLEAR);
        }
    }

    // 设置 PERST(复位)标志
    fn perst_set(&self, bit: u32) {
        // 如果 bit 为 1,将 PCIE_RGR1_SW_INTI_1_PERST 置位
        if bit == 1 {
            self.rgr1_sw_init
                .modify(RGR1_SW_INIT_1::PCIE_RGR1_SW_INTI_1_PERST::SET);
        }
        // 如果 bit 为 0,清除 PCIE_RGR1_SW_INTI_1_PERST 位
        if bit == 0 {
            self.rgr1_sw_init
                .modify(RGR1_SW_INIT_1::PCIE_RGR1_SW_INTI_1_PERST::CLEAR);
        }
    }
}

 pub fn setup(&self) {
    let regs = self.regs();

    // 断言桥复位
    // 确保 PCIe 控制器处于已知状态,实际上是将 PCIe 控制器的状态置于一个初始值
    regs.bridge_sw_init_set(1);
    log::debug!("assert bridge reset");

    // 断言基本复位
    // 将整个 PCIe 控制器或者相关模块复位到初始状态,以确保系统在初始化开始时处于一种可控制和已知状态
    regs.perst_set(1);
    log::debug!("assert fundamental reset");

    H::sleep(core::time::Duration::from_micros(2));

    // 解除桥复位
    //标志 PCIe 控制器已经完成了一系列的初始化步骤,并且认为 PCIe 控制器已经准备好正常工作
    regs.bridge_sw_init_set(0);
    log::debug!("deassert bridge reset");

    H::sleep(core::time::Duration::from_micros(2));

    // 启用 SerDes,确保 PCIe 控制器能够正常进行数据传输
    regs.misc_hard_pcie_hard_debug
        .modify(MISC_HARD_PCIE_HARD_DEBUG::SERDES_IDDQ::CLEAR);
    log::debug!("enable serdes");

    H::sleep(core::time::Duration::from_micros(2));

    // 获取硬件版本
    let hw_rev = regs.misc_revision.read(MISC_REVISION::MISC_REVISION) & 0xFFFF;
    log::debug!("hw_rev: {}", hw_rev);

    // 禁用和清除任何挂起的中断,保在 PCIe 控制器初始化的过程中,系统处于一个可控的状态
    regs.msi_intr2_clr.write(MSI_INTR2_CLR::INTR_CLR::SET);
    regs.msi_intr2_mask_set
        .write(MSI_INTR2_MASK_SET::INTR_MASK_SET::SET);
    log::debug!("disable and clear any pending interrupts");

    // 初始化设置 SCB_MAX_BURST_SIZE 0x0, CFG_READ_UR_MODE, SCB_ACCESS_EN
    regs.misc_misc_ctrl
        .modify(MISC_MISC_CTRL::SCB_ACCESS_EN::SET);
    regs.misc_misc_ctrl
        .modify(MISC_MISC_CTRL::CFG_READ_UR_MODE::SET);
    regs.misc_misc_ctrl
        .modify(MISC_MISC_CTRL::MAX_BURST_SIZE::CLEAR);

    // 设置入站内存视图
    regs.misc_rc_bar2_config_lo
        .write(MISC_RC_BAR2_CONFIG_LO::VALUE_LO::init_val);
    regs.misc_rc_bar2_config_hi
        .write(MISC_RC_BAR2_CONFIG_HI::VALUE_HI::init_val);
    regs.misc_misc_ctrl
        .modify(MISC_MISC_CTRL::SCB0_SIZE::init_val);

    // 禁用 PCIe->GISB 内存窗口和 PCIe->SCB 内存窗口
    regs.misc_rc_bar1_config_lo
        .modify(MISC_RC_BAR1_CONFIG_LO::MEM_WIN::CLEAR);
    regs.misc_rc_bar3_config_lo
        .modify(MISC_RC_BAR3_CONFIG_LO::MEM_WIN::CLEAR);

    // 设置 MSIs,清除中断,屏蔽中断
    // CPU::MMIOWrite32(pcieBase + MSI_BAR_CONFIG_LO, (MSI_TARGET_ADDR & 0xFFFFFFFFu) | 1);
    // CPU::MMIOWrite32(pcieBase + MSI_BAR_CONFIG_HI, MSI_TARGET_ADDR >> 32);
    // CPU::MMIOWrite32(pcieBase + MSI_DATA_CONFIG, hwRev >= HW_REV_33 ? 0xffe06540 : 0xFFF86540);
    // TODO: 在此注册 MSI 处理程序

  

    // 解除基本复位
    // 在确认初始化步骤完成后,将 PCIe 控制器从基本复位状态恢复到正常工作状态
    regs.perst_set(0);

    // 等待 [0xfd504068] 的位 4 和 5 被设置,每隔 5000 微秒检查一次
    for _ in 0..20 {
        let val = regs.misc_pcie_status.read(MISC_PCIE_STATUS::CHECK_BITS);
        log::trace!("val: {}", val);
        if val == 0x3 {
            break;
        }
        H::sleep(core::time::Duration::from_micros(5000));
    }

    // 检查链路是否正常
    {
        let val = regs.misc_pcie_status.read(MISC_PCIE_STATUS::CHECK_BITS);
        if val != 0x3 {
            panic!("PCIe link is down");
        }
    }

    // 检查控制器是否运行在根复杂模式。如果位 7 未设置,则发生错误
    {
        let val = regs.misc_pcie_status.read(MISC_PCIE_STATUS::RC_MODE);
        if val != 0x1 {
            panic!("PCIe controller is not running in root complex mode");
        }
    }

    log::debug!("PCIe link is ready");

    // 配置出站内存
    // 定义 PCIe 设备可以访问的一块内存区域,使 PCIe 设备可以读取或写入这个内存区域中的数据
    regs.misc_cpu_2_pcie_mem_win0_lo
        .write(MISC_CPU_2_PCIE_MEM_WIN0_LO::MEM_WIN0_LO::init_val);
    regs.misc_cpu_2_pcie_mem_win0_hi
        .write(MISC_CPU_2_PCIE_MEM_WIN0_HI::MEM_WIN0_HI::init_val);
    regs.misc_cpu_2_pcie_mem_win0_base_limit
        .write(MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT::MEM_WIN0_BASE_LIMIT::init_val);
    regs.misc_cpu_2_pcie_mem_win0_base_hi
        .write(MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI::MEM_WIN0_BASE_HI::init_val);
    regs.misc_cpu_2_pcie_mem_win0_limit_hi
        .write(MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI::MEM_WIN0_LIMIT_HI::init_val);

    // 设置正确的 Class ID
    regs.rc_cfg_priv1_id_val3
        .modify(RC_CFG_PRIV1_ID_VAL3::CLASS_ID::pcie_pcie_bridge);

}
}

任务二:PCIe主机桥为PCIe设备分配内存空间

流程:

  1. 枚举PCIe设备:使用操作系统提供的PCIe总线驱动程序,首先枚举(或探测)连接到主机系统上的PCIe设备。这将识别和注册每个设备,并为其分配一个唯一的设备标识符。

  2. 识别设备和配置空间:对于每个已枚举的PCIe设备,读取其配置空间来获取设备的相关信息,例如设备ID、制造商ID、设备类、中断号等。配置空间是设备的一部分,包含用于描述设备和其资源分配的寄存器。

  3. 分配内存空间:根据设备的需求,向设备分配内存空间。可以通过操作系统的内存管理机制进行。

  4. 映射内存空间:将分配的内存空间映射到设备的地址空间中,以便设备可以访问该内存。

参考代码仓库:https://github.com/dbydd/arceos_experiment/tree/task3_usb

运行结果:


       d8888                            .d88888b.   .d8888b.
      d88888                           d88P" "Y88b d88P  Y88b
     d88P888                           888     888 Y88b.
    d88P 888 888d888  .d8888b  .d88b.  888     888  "Y888b.
   d88P  888 888P"   d88P"    d8P  Y8b 888     888     "Y88b.
  d88P   888 888     888      88888888 888     888       "888
 d8888888888 888     Y88b.    Y8b.     Y88b. .d88P Y88b  d88P
d88P     888 888      "Y8888P  "Y8888   "Y88888P"   "Y8888P"

arch = aarch64
platform = aarch64-raspi4
target = aarch64-unknown-none-softfloat
smp = 1
build_mode = release
log_level = debug

[  0.111216 0 axruntime:126] Logging is enabled.
[  0.116945 0 axruntime:127] Primary CPU 0 started, dtb = 0x0.
[  0.123891 0 axruntime:129] Found physcial memory regions:
[  0.130578 0 axruntime:131]   [PA:0x80000, PA:0x91000) .text (READ | EXECUTE | RESERVED)
[  0.139866 0 axruntime:131]   [PA:0x91000, PA:0x96000) .rodata (READ | RESERVED)
[  0.148462 0 axruntime:131]   [PA:0x96000, PA:0x9a000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED)
[  0.159402 0 axruntime:131]   [PA:0x9a000, PA:0xda000) boot stack (READ | WRITE | RESERVED)
[  0.168952 0 axruntime:131]   [PA:0xda000, PA:0xff000) .bss (READ | WRITE | RESERVED)
[  0.177982 0 axruntime:131]   [PA:0x0, PA:0x1000) spintable (READ | WRITE | RESERVED)
[  0.187012 0 axruntime:131]   [PA:0xff000, PA:0xfc000000) free memory (READ | WRITE | FREE)
[  0.196562 0 axruntime:131]   [PA:0xfe201000, PA:0xfe202000) mmio (READ | WRITE | DEVICE | RESERVED)
[  0.206894 0 axruntime:131]   [PA:0xff841000, PA:0xff849000) mmio (READ | WRITE | DEVICE | RESERVED)
[  0.217226 0 axruntime:131]   [PA:0xfd500000, PA:0xfd509310) mmio (READ | WRITE | DEVICE | RESERVED)
[  0.227558 0 axruntime:131]   [PA:0xf8000000, PA:0xfc000000) mmio (READ | WRITE | DEVICE | RESERVED)
[  0.237890 0 axruntime:149] Initialize platform devices...
[  0.244575 0 axruntime:185] Primary CPU 0 init OK.
[  0.250567 0 brcm_pcie::bcm2711:309] assert bridge reset
[  0.257078 0 brcm_pcie::bcm2711:313] assert fundamental reset
[  0.264026 0 brcm_pcie::bcm2711:319] deassert bridge reset
[  0.270711 0 brcm_pcie::bcm2711:326] enable serdes
[  0.276702 0 brcm_pcie::bcm2711:333] hw_rev772
[  0.282343 0 brcm_pcie::bcm2711:339] disable and clear any pending interrupts
[  1.290781 0 brcm_pcie::bcm2711:408] PCIe link is ready
Available commands:
  exit
  help
  uname
  ldr
  str
  uart
  test
  move
  tud
arceos# tud
[  3.236644 0 brcm_pcie::bcm2711:309] assert bridge reset
[  3.240455 0 brcm_pcie::bcm2711:313] assert fundamental reset
[  3.247403 0 brcm_pcie::bcm2711:319] deassert bridge reset
[  3.254088 0 brcm_pcie::bcm2711:326] enable serdes
[  3.260079 0 brcm_pcie::bcm2711:333] hw_rev772
[  3.265720 0 brcm_pcie::bcm2711:339] disable and clear any pending interrupts
[  4.274160 0 brcm_pcie::bcm2711:408] PCIe link is ready
[  4.277714 0 axdriver:158] Initialize device drivers...
[  4.284137 0 axdriver:159]   device model: static
[  4.290041 0 axdriver::bus::pci:144] base_vaddr:ffff0000fd500000
[  4.297248 0 axdriver::bus::pci:155] iter 0
[  4.302666 0 axdriver::bus::pci:160] PCI 00:01.0: 1106:3483 (class 0c.03, rev 01) Standard
[  4.312094 0 axdriver::bus::pci:162] in!
[  4.317250 0 axdriver::bus::pci:37] type 64
[  4.322632 0 axdriver::bus::pci:61]   BAR 0: MEM [0x600000000, 0x600001000) 64bit
[  4.331282 0 axdriver::bus::pci:79] two ents
[  4.336805 0 axdriver::drivers:168] vl805 found! at DeviceFunction { bus: 0, device: 1, function: 0 }
[  4.347203 0 axdriver::drivers:171] Memory space at 0x600000000, size 4096, type Width64, prefetchable false
[  4.358227 0 axdriver::drivers:181] status:10
[  4.363754 0 axdriver::drivers:182] command:7
[  4.369311 0 axdriver::bus::pci:177] registered a new XHCI device at 00:01.0: "xhci-controller"
[  4.379209 0 axdriver:166] number of NICs: 0
[  4.384679 0 axdriver:190] number of xhci devices: 1
[  4.390843 0 axdriver:193]   xhci device 0: "xhci-controller"
arceos#

任务三:xhci 主机控制器初始化

任务四:xhci 检测设备,分配地址空间

任务五:解析设备配置,加载对应驱动

任务六:USB转串口的设备驱动实现

参考资料:

  1. https://blog.csdn.net/mao_hui_fei/article/details/107592985
  2. https://github.com/orgs/chenlongos/discussions
  3. https://github.com/MrRobertYuan/report/blob/main/docs/2023/20230601_How-to-run-ArceOS-on-raspi4.md
  4. https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf
  5. https://elinux.org/RPi_BCM2711_GPIOs#GPIO0
  6. https://juejin.cn/post/6977611730784354334
  7. https://github.com/chenlongos/rust-raspberrypi-OS-tutorials/tree/master/06_uart_chainloader
  8. https://pinout.xyz

飞腾派学习指南

本次实习项目共有两个阶段,第一阶段分为两个方向,可以任选一方向进行开发,分别是 USB 驱动开发和 I2C 驱动,第二阶段为实现颜色追踪这一目标

  • 第一阶段-- USB 驱动:

    • 实验一:xhci控制器初始化,接管控制器

    • 实验二:读取 USB 设备,与设备通信,编写设备驱动

  • 第一阶段-- I2C 驱动

    • 实验一:I2C 驱动实现

    • 实验二:通过 I2C 驱动 PCA9685 模块驱动小车

  • 第二阶段为用Rust编写飞腾派各类驱动,具体包括:

    • 摄像头驱动,实现读取物体颜色后,可以跟随颜色

    • 颜色识别算法,实现物体的颜色识别

    • Python库的支持,实现支持颜色识别需要用到的python库

时间安排

image

7b27af0c141c9aade85d765db19e38b

相关数据手册:

  1. https://pan.baidu.com/s/1pStiyqohrB3SxHAFFk8R6Q?pwd=dzdv 提取码:dzdv
  2. 飞腾派数据手册&编程手册:https://ese9a2b5c9d46i.prissl.qiqiuyun.net/1708999963/65dd451b88681301680027?attname=%E9%A3%9E%E8%85%BE%E6%B4%BE%E6%95%B0%E6%8D%AE%E6%89%8B%E5%86%8C%26%E7%BC%96%E7%A8%8B%E6%89%8B%E5%86%8C.zip&e=1712544877&token=ExRD5wolmUnwwITVeSEXDQXizfxTRp7vnaMKJbO-:_Yz27ZregW6Z0Ac0FBYHNCAzoB0=

飞腾派参数

image-20240427150628174

名称描述
CPU飞腾四核处理器,ARMV8架构,2 × FTC664@1.8GHz+2 × FTC310@1.5GHz
内存64位DDR4,分2G版本和4G版本
硬盘支持microSD和EMMC启动,二选一
网络2 × 千兆以太网(RJ45)
USB1 × USB3.0 host,3 × USB2.0 host(键鼠)
PCIe1 × Mini—PCIe、支持AI加速、4G/5G通信、MSATA固态硬盘等模块
蓝牙蓝牙BT4.2/BLE4.2
WIFI2.4G + 5G双频WIFI
显示1 × HDMI,支持分辨率1920*1080
音频3.5mm耳机口输出
UART1 ×调试串口 + 2 × MIO(可配置多功能IO口为UART模式)
I2C2 + 2 × MIO(可配置多功能IO口为I2C模式)
I2S1路
SPI2路
CAN1路CANFD
GPIO最多29个

前置实验:飞腾派运行ArceOS

  1. 硬件准备:

  2. 飞腾派上电启动,把有ArceOS启动镜像的读卡器或者U盘插到飞腾派上,用串口把飞腾派与电脑相连接,启动电脑上的远程连接软件,如Putty,波特率设置为115200

    串口接法:接8、10、12号引脚位置,如图所示(8号代表TX,接RX;10号代表RX,接TX;12号接地线)

  3. 在uboot倒计时结束前按任意键进入手动引导

    • 输入usb start ,启用USB驱动来识别插入的USB设备(读卡器/U盘)

    • 输入fatload usb 0 0x90100000 cli_aarch64-phytium-pi.bin,从插入的USB设备上下载ArceOS镜像

    • 输入go 0x90100000加载ArceOS镜像

      (这里是没有开debug)

    • 便可以看到ArceOS启动成功,进入到了shell界面

在飞腾派上运行Dora-rs

参考:https://dora-rs.ai/zh-CN/

安装Dora-rs

  1. 下载 Ubuntu 系统镜像并烧录到飞腾派上

    用户名和密码均为:root

  2. 飞腾派启用网络

    • 串口连接

      配置网络:

      输入sudo nmcli dev wifi,扫描附近热点

      输入sudo nmcli dev wifi connect "SSID" password "PASSWORD" ifname wlan0,连接到指定热点,SSID和 PASSWORD 替换成实际的 WiFi名称和密码。

    • 连接显示屏

  3. 下载安装Dora-rs

    export DORA_VERSION=v0.3.2 # Check for the latest release
    export ARCHITECTURE=$(uname -m)
    wget https://github.com/dora-rs/dora/releases/download/${DORA_VERSION}/dora-${DORA_VERSION}-${ARCHITECTURE}-Linux.zip
    unzip dora-${DORA_VERSION}-${ARCHITECTURE}-Linux.zip
    pip install dora-rs==${DORA_VERSION}
    PATH=$PATH:$(pwd)
    dora --help
    

尝试使用Dora-rs

Python Conversation

https://dora-rs.ai/zh-CN/docs/guides/getting-started/conversation_py

  1. 创建一个新的数据流

    dora new conversation_py --lang python
    cd conversation_py
    
  2. 添加一个新的节点

     dora new --kind custom-node talker
    
  3. 在创建的新节点里创建并编辑talker.py

    加入以下内容:

    from dora import Node
    import pyarrow as pa
    
    node = Node()
    
    event = node.next()
    if event["type"] == "INPUT":
        print(
            f"""Node received:
        id: {event["id"]},
        value: {event["value"]},
        metadata: {event["metadata"]}"""
        )
    node.send_output("speech", pa.array(["Hello World"])) # add this line
    
  4. 调整监听节点

    将node_1的名称更改为listener, 将node_1.py的名称更改为listener.py

    内容变为:

    from dora import Node
    import pyarrow as pa
    
    node = Node()
    
    event = node.next()
    if event["type"] == "INPUT":
        message = event["value"][0].as_py()
        print(
            f"""I heard {message}"""
        )
    
  5. 修改dataflow.yml文件

    变为:

    nodes:
      - id: talker
        custom:
          source: talker/talker.py
          inputs:
            tick: dora/timer/secs/1
          outputs:
            - speech
    
      - id: listener
        custom:
          source: listener/listener.py
          inputs:
            speech: talker/speech
    

之后在终端运行:

dora up
dora start dataflow.yml --name conversation
dora logs conversation listener

结果:

root@Phytium-Pi:/home/user/conversation_py# dora logs conversation listener
I heard Hello World

方向一:飞腾派 USB 驱动

目的:

飞腾小车摄像头是通过 USB 连接在飞腾派上的,而颜色追踪需要用到摄像头读取颜色并识别,所以需要开发 USB 驱动

具体实施:

具体进行以下三方面内容:

  1. PCIe 驱动
  2. USB 驱动
  3. 摄像头设备驱动

注:由于飞腾派 xhci 控制器是连接在 PCIe 接口上的,所以我们需要开发 PCIe 驱动,确保可以识别到 USB 控制器。但是目前我们发现Uboot会帮助初始化USB控制器,所以目前可以先跳过 PCIe 部分,直接开发 USB 部分。

PCIe介绍

总线

总线是连接各个部件的信息传输线,是各个部件共享的传输介质。总线充当了计算机内各个硬件组件之间的通信媒介,使得中央处理器(CPU)、内存、输入输出设备等能够协同工作。

总线分类:

  • 片内总线: 片内总线是指在芯片内部连接各个元件的总线。这些元件可以包括内部的寄存器、缓存、算术单元等。片内总线用于在芯片内部传递数据和控制信号,以协调不同部件的工作。

  • 系统总线: 系统总线是连接计算机主要部件的总线。连接了中央处理器、内存、输入输出控制器等主要组件。系统总线用于在这些主要组件之间传递地址、数据和控制信号,协调它们之间的工作。

  • 通信总线: 通信总线,外部总线,是计算机系统之间或计算机系统与其他系统之间的通信通道。它包括串行传输和并行传输。

PCIe总线

PCIe(Peripheral Component Interconnect Express)是一种计算机总线标准,用于连接内部硬件设备,例如图形卡、存储设备、网卡等。PCIe 是 PCI 标准的一种现代化、高速、并行的演进版本,提供更高的数据传输速率和更强大的性能。

PCIe 具有以下特点:

  • 点对点连接: PCIe 采用点对点(point-to-point)连接架构,每个 PCIe 设备直接连接到主板上的 PCIe 控制器,而不是共享总线。这种点对点连接架构消除了传统总线结构中的冲突和瓶颈,提高了系统性能。

  • 高速串行传输: PCIe 使用高速的差分串行通信,相较于传统的并行总线,提供更高的数据传输速率。这使得 PCIe 能够支持更大的带宽需求,适应了现代高性能计算和通信的要求。

  • 可伸缩性: PCIe 提供了可伸缩性,支持不同数量和配置的通道,例如 PCIe x1、PCIe x4、PCIe x8 和 PCIe x16。这使得 PCIe 能够适应各种设备和应用的需求,从网络适配器到高性能图形卡。

  • 热插拔支持: PCIe 支持热插拔功能,允许用户在系统运行时插入或拔出 PCIe 设备,而无需关闭系统。这增加了系统的灵活性和可维护性。

背景知识

ISA(Industry Standard Architecture)总线是一种计算机总线标准,它的前身可以追溯到1981年IBM推出的个人电脑(PC)。当时,IBM为了连接主板上的微处理器和外部设备(如显卡、声卡等),设计了一个内部通信接口。这个早期的总线被称作PC总线。随着时间的发展,IBM在其1984年推出的IBM PC/AT(Advanced Technology)中引入了一个新版本的总线,这就是ISA总线的前身。它最初是16位的,并且比之前的8位PC总线提供了更高的数据传输速率。ISA总线不仅能兼容新的16位卡,而且还向后兼容之前的8位扩展卡。尽管ISA总线曾经非常流行,但它基于并行通信原理,导致传输速度相对较慢且存在长度限制,这使得它难以满足日益增长的数据传输需求。

英特尔在1992年首次提出了 PCI(Peripheral Component Interconnect) 总线的概念,旨在解决 ISA 总线的瓶颈问题。PCI 是一种并行总线标准,最初被设计为用于连接外部设备,如网卡、显卡、磁盘控制器等。之后,PCI 很快成为一种开放标准,得到了多家硬件制造商的支持。这使得各种设备能够在不同厂商的计算机系统中互通性更好。

随着计算机技术的发展,PCI总线标准逐渐显露出一些限制,如带宽瓶颈和对未来高性能设备的支持不足。因此,产业界开始寻找一种更先进的替代方案。英特尔在2003年首次提出了 PCI Express (Peripheral Component Interconnect Express)的概念,作为对传统 PCI 标准的更新和改进。PCIe 最初被设计为一种高性能、灵活性更强的串行总线标准,以适应未来计算机的需求。

发展历程

  1. PCIe 1.0: PCIe 1.0 标准于2003年发布。它引入了高速串行连接,每个通道的数据速率为2.5 GT/s(gigatransfers per second)。PCIe 1.0 提供了比传统的并行总线更高的性能和可扩展性。
  2. PCIe 2.0: PCIe 2.0 标准于2007年发布。它在每个通道上将数据速率提高到5 GT/s,从而提供了更大的总线带宽。PCIe 2.0 向下兼容 PCIe 1.0,并为图形卡和其他高性能设备提供了更多的带宽。
  3. PCIe 3.0: PCIe 3.0 标准于2010年发布。它将每个通道的数据速率进一步提高到8 GT/s,进一步增加了总线带宽。PCIe 3.0 的发布支持更高分辨率的图形、更快速的存储设备和更多高带宽应用。
  4. PCIe 4.0: PCIe 4.0 标准于2017年发布。它将每个通道的数据速率提高到16 GT/s,实现了比 PCIe 3.0 更高的带宽。PCIe 4.0 的推出对于数据中心、高性能计算和其他需要更高带宽的应用具有重要意义。
  5. PCIe 5.0: PCIe 5.0 标准于2019年发布。它将每个通道的数据速率提高到32 GT/s,再次增加了总线带宽。PCIe 5.0 的推出进一步满足了对更高性能和更大带宽的需求。
  6. PCIe 6.0: PCIe 6.0 标准于2022年发布。它将每个通道的数据速率提高到64 GT/s,为未来计算机系统提供更大的带宽和性能。PCIe 6.0 的推出标志着 PCIe 标准的不断创新和发展。
PCIe Specification(版本) Specification ratification year(发布时间) Encoding(有效数据) Data Rate per lane(传输速率) Throughput(吞吐量)
x1 x2 x4 x8 x16
1.0 2003 8b/10b 2.5GT/s 250MB/s 0.500GB/s 1.000GB/s 2.000GB/s 4.000GB/s
2.0 2007 8b/10b 5.0GT/s 500MB/s 1.000GB/s 2.000GB/s 4.000GB/s 8.000GB/s
3.0 2010 128b/130b 8.0GT/s 985MB/s 1.969GB/s 3.938GB/s 7.877GB/s 15.754GB/s
4.0 2017 128b/130b 16.0GT/s 1.969GB/s 3.938GB/s 7.877GB/s 15.754GB/s 31.508GB/s
5.0 2019 128b/130b 32.0GT/s 3.938GB/s 7.877GB/s 15.754GB/s 31.508GB/s 63.015GB/s
6.0 2022 1b/1b 64.0GT/s 7.563GB/s 15.125GB/s 30.250GB/s 60.500GB/s 121.000GB/s

PCIe链路

PCIe Link表示两个组件之间的全双工通信信道,是PCIe总线中两个设备之间的通信连接,采用点对点的通信架构,一条链路可以包含多个通道(lane),可增加通道个数来满足更高的带宽要求。

image-20231226120533938

Lane,是指一组差分信号的组合,包括发送和接收。一个发送方向的差分信号包括TX+和TX-两条线,接收亦然。所以一条lane有四条物理连线。

image-20231226143119817

PCIe拓扑结构

image-20231226120936484

  1. 点对点连接: PCIe总线采用点对点的通信方式,每个设备都直接连接到根复杂器(Root Complex)或其他中继设备。这种结构消除了共享总线的瓶颈,提供了更高的性能。
  2. 树状结构: PCIe的拓扑结构通常呈现为树状结构。根复杂器是总线的起点,连接到根复杂器的设备称为端点(Endpoint)。可以通过 Switch 进一步连接到其他设备,形成一个树状的拓扑结构。
  3. 根复杂器 Root Complex(RC): RC是PCIe总线的起点,负责初始化和管理总线。RC可以连接到CPU、北桥芯片组或其他I/O控制器。
  4. PCIe Bridge To PCI/PCI-X: 桥接设备,可以连接不同的PCIe域,例如连接其他的PCI总线、PCI-X、PCIe总线。
  5. Switch: PCIe的转接器设备(PCIe扩展端口),为挂载设备提供路由以及转发服务;Switch的内部结构可以看作由PCI桥组成,在Switch中,每个端口对应的PCIe设备号是确定的,Switch设备会记录下游PCIe端口连接设备分配到的PCIe地址,在接收到TLP包时,通过比较目的地址和下游设备的地址,来判断是否转发以及转发到哪个PCIe端口。
  6. 端点设备 PCIe Endponit(EP): 端点是直接连接到PCIe总线的终端设备,如显卡、网卡等。每个设备都有自己的设备标识和唯一的设备ID。
  7. 链路: 链路是连接PCIe设备的通信通道,可以根据需要进行配置。链路的宽度(Link Width)和速度(Link Speed)是PCIe连接的关键参数,决定了数据传输的带宽和速率。
  8. 多域拓扑: PCIe支持多域拓扑,允许将PCIe总线划分为不同的域,每个域内有独立的根复杂器和设备。

PCIe架构

PCIe架构包括四个主要层次:物理层(Physical Layer)、数据链路层(Data Link Layer)、传输层(Transaction Layer)、应用层(Application Layer)。

1. 物理层(Physical Layer):

  • 电气特性: 定义了PCIe信号的电气特性,包括电压水平、时钟频率等。PCIe使用差分信号传输,以提高抗干扰性和传输速率。
  • 连接器和插槽: 规定了物理连接的标准,包括插槽的形状和尺寸,以及连接器的设计。常见的物理连接形式包括x1、x4、x8、x16等。
  • 数据传输: 负责将数据以数据包的形式传输到数据链路层。物理层还管理时序、流控和数据逐字节的传输。
  • 数据包组装: 将数据划分为适当大小的数据包,并在每个数据包上添加控制信息,包括起始和终止标志、错误检测和纠错码等。
  • 流量控制: 确保数据在物理层上的稳定传输,避免因接收方处理能力不足而导致数据丢失。
  • 错误检测和纠错: 负责检测并在可能的情况下纠正传输中的错误,以确保数据的可靠性。

3. 传输层(Transaction Layer):

  • 传输事务: 负责将数据包分解为传输层事务,并在设备之间传递这些事务。每个事务包含有关数据的信息、目标设备的地址等。
  • 路由: 确定数据包的路径,使其能够正确地传递到目标设备。传输层支持多通道和多队列,以提高并行性和性能。
  • 可靠性: 确保数据传输的可靠性,包括重传机制、流控等。

4. 应用层(Application Layer):

  • 与操作系统和应用程序的接口: 提供PCIe设备与主机系统之间的通信接口。在这一层,操作系统通过相应的驱动程序与PCIe设备进行交互。
  • 配置和管理: 应用层处理PCIe设备的配置信息,包括设备ID、中断分配等。此外,它还负责设备的启动和关闭。

实验一:PCIe 初始化,接管 PCIe 控制器

PCIe控制器由Uboot初始化。

飞腾派Linux中关于 PCIe 部分

在飞腾派Linux系统中,输入cat /proc/iomem,得到如下输出:

user@Phytium-Pi:~$ sudo cat /proc/iomem
28000000-28000fff : 28000000.mmc mmc@28000000
28001000-28001fff : 28001000.mmc mmc@28001000
28005000-28005fff : 28009000.i2s i2s@28009000
28009000-28009fff : 28009000.i2s i2s@28009000
2800a000-2800afff : 2800a000.can can@2800a000
2800b000-2800bfff : 2800b000.can can@2800b000
2800c000-2800cfff : uart@2800c000
  2800c000-2800cfff : 2800c000.uart uart@2800c000
2800d000-2800dfff : uart@2800d000
  2800d000-2800dfff : 2800d000.uart uart@2800d000
2800e000-2800efff : uart@2800e000
  2800e000-2800efff : 2800e000.uart uart@2800e000
2800f000-2800ffff : uart@2800f000
  2800f000-2800ffff : 2800f000.uart uart@2800f000
28016000-28016fff : 28016000.i2c i2c@28016000
28024000-28024fff : 28024000.i2c i2c@28024000
28026000-28026fff : 28026000.i2c i2c@28026000
28030000-28030fff : 28030000.i2c i2c@28030000
28034000-28034fff : 28034000.gpio gpio@28034000
28035000-28035fff : 28035000.gpio gpio@28035000
28036000-28036fff : 28036000.gpio gpio@28036000
28037000-28037fff : 28037000.gpio gpio@28037000
28038000-28038fff : 28038000.gpio gpio@28038000
28039000-28039fff : 28039000.gpio gpio@28039000
2803a000-2803afff : 2803a000.spi spi@2803a000
28040000-28040fff : 28041000.watchdog watchdog@28040000
28041000-28041fff : 28041000.watchdog watchdog@28040000
28042000-28042fff : 28043000.watchdog watchdog@28042000
28043000-28043fff : 28043000.watchdog watchdog@28042000
2804a000-2804afff : 2804a000.pwm pwm@2804a000
2804b000-2804bfff : 2804b000.pwm pwm@2804b000
30000000-30000dff : 30000000.iommu
30010000-30010dff : 30000000.iommu
31a08000-31a1ffff : 31a08000.usb3 usb3@31a08000
31a28000-31a3ffff : 31a28000.usb3 usb3@31a28000
32000000-32007fff : 32000000.dc dc@32000000
32008000-32008fff : 32009000.i2s_dp0 i2s_dp0@32009000
32009000-32009fff : 32009000.i2s_dp0 i2s_dp0@32009000
3200c000-3200dfff : 3200c000.ethernet ethernet@3200c000
3200e000-3200ffff : 3200e000.ethernet ethernet@3200e000
32a00000-32a00fff : 32a00000.mailbox mailbox@32a00000
32a10000-32a11fff : 32a10000.sram sram@32a10000
32a36000-32a36fff : 32a36000.rng rng@32a36000
40000000-4fffffff : PCI ECAM
58000000-7fffffff : pcie@40000000
  58000000-581fffff : PCI Bus 0000:01
80000000-fbffffff : System RAM
  80000000-8000ffff : reserved
  90200000-913bffff : Kernel code
  913c0000-9160ffff : reserved
  91610000-917bffff : Kernel data
  e5c00000-f9bfffff : reserved
  f9c32000-f9c38fff : reserved
1000000000-1fffffffff : pcie@40000000
  1000000000-10000fffff : 0000:00:01.0
  1000100000-10002fffff : PCI Bus 0000:01
2000000000-207fffffff : System RAM
  207b000000-207effffff : reserved
  207f138000-207f197fff : reserved
  207f198000-207f798fff : reserved
  207f799000-207f7f4fff : reserved
  207f7f7000-207f7f9fff : reserved
  207f7fa000-207f7fafff : reserved
  207f7fb000-207f7fefff : reserved
  207f7ff000-207f81cfff : reserved
  207f81d000-207fffffff : reserved
  • 1000000000-1fffffffff : pcie@40000000表示 PCIe 设备在系统地址空间中的分配。40000000 是 PCIe 设备的基址

  • 1000000000-10000fffff 是一个PCI设备的地址范围。0000:00:01.0 是PCIe设备的标识符,具体来说,0000:00:01.0 表示PCIe设备的域号、总线号、设备号和功能号。

    1000100000-10002fffff是另一个PCI设备的地址范围,PCI Bus 表示这是一个PCI总线设备,0000:01 表示PCI设备所在的总线号

接管控制权

  1. 加载ArceOS:通过SD卡等引导设备实现

  2. ArceOS初始化:内核开始初始化硬件和各种子系统。在初始化过程中,会尝试检测和配置已经初始化的PCIe控制器。

  3. PCIe子系统初始化:当识别到PCIe控制器后,PCIe子系统会被初始化。其中包括

    • 设备检测
    • 资源分配
    • 设备驱动程序加载

实验二:PCIe 读取 xhci 控制器

PCIe 主桥枚举连接到总线上的设备,发现 USB 3.0 主机控制器设备

  • 执行 PCIe 总线扫描以检测连接到总线上的所有设备。通常通过读取配置空间中的特定寄存器来实现。
  • 对于检测到的设备,需要解析其配置空间以获取设备的厂商 ID、设备 ID、类别码等重要信息。
  • USB 3.0 主机控制器设备的类别码通常是 0x0C(Serial bus controller)。

枚举并记录已连接设备

  1. 初始化根端口:PCIe桥首先会初始化其自身作为根端口,将其配置为根端口的相关寄存器。

  2. 遍历子端口:PCIe桥会依次访问其下方的子端口。这些子端口可以是其他PCIe桥或直接连接的PCI设备。

  3. 检测链接状态:对于每个子端口,PCIe桥会检测其链路状态,以确定是否有设备连接到该端口上。

  4. 链接重播(Link Retraining):如果有设备连接到子端口上,并且链路状态正常,则PCIe桥可能会执行链接重播操作,以确保链路稳定和可靠。

  5. 记录已连接设备:当PCIe桥确定子端口连接了一个PCI设备时,它会记录该设备的信息,如设备ID、厂商ID等。

  6. 递归遍历:如果子端口连接的是另一个PCIe桥,那么PCIe桥会递归地遍历该子桥的子端口,以继续检测更深层次的PCI设备。

USB 介绍

USB(Universal Serial Bus,通用串行总线)是一种用于在计算机系统和外部设备之间传输数据的标准化通信协议和连接接口。USB最初设计用于简化计算机和外部设备之间的连接,并提高设备的可用性。

  • 通用性: USB是一种通用的连接标准,适用于各种设备,包括打印机、键盘、鼠标、摄像头、移动设备等。
  • 插拔性: USB支持热插拔,可以在计算机运行时连接或断开USB设备而无需重启计算机。
  • 高带宽和速度: USB提供不同版本,包括USB 1.0、USB 2.0、USB 3.0、USB 3.1和USB4.0等,每个版本具有不同的数据传输速度和带宽。USB 3.0及更高版本支持更快的数据传输速度。
  • 电力供应: USB接口不仅传输数据,还可以为连接的设备提供电力。这使得许多小型设备无需额外的电源适配器即可正常工作。
  • 连接类型: USB连接器有多种形状和尺寸,Type-A、Type-B、Micro-USB、USB-C等, USB-C是一种可逆连接器,可以在任何方向上插入。
  • 传输类型: USB支持不同类型的数据传输,包括控制传输、批量传输、等时传输和中断传输。

拓扑结构

image

USB host

任何 USB 系统中只有一个主机。主机系统的 USB 接口被称为主机控制器。主机控制器可以以硬件,固件或软件的组合来实现。根集线器集成在主机系统内以提供一个或多个连接点。USB Host 通过 Host Controller 与 USB device 交互。

Host 主要负责:检测 USB 设备拔插管理 Host 和 Device 之间的控制流、数据流收集 USB 总线状态和活动数据信息为连入 USB 总线的设备供电。

USB Host的工作原理是通过发送和接收USB数据包来与USB设备进行通信。

USB Host Controller

Host Controller(主机控制器)是指在计算机系统中负责管理和控制USB总线的硬件或芯片。USB主机控制器的作用是与连接到计算机的USB设备进行通信,协调数据传输,并提供电源管理等功能。

  • 设备管理: 主机控制器负责检测和管理连接到计算机的USB设备。当用户连接USB设备时,主机控制器负责识别设备并与其建立通信。
  • 数据传输: 主机控制器协调数据在USB总线上的传输。它处理USB设备之间的数据传输请求,确保数据以正确的速率和顺序进行传输。
  • 电源管理: USB主机控制器负责为连接的USB设备提供电力。它可以根据需要为设备提供适当的电流,并在设备不再需要电力时进行断电。
  • 错误处理: 主机控制器能够处理USB总线上发生的错误,以确保稳定的数据传输。
  • 协议支持: USB主机控制器需要支持USB规范中定义的各种协议,以确保与不同类型的USB设备的兼容性。

USB device

USB device 可以分为 USB hub 和 USB function。

  • USB Hub Hub 提供了一种低成本、低复杂度的 USB 接口扩展方法。HUB 的上行 Port 面向Host,下行 Port 面向设备(Hub 或功能设备)。在下行 Port 上,Hub 提供了设备连接检测和设备移除检测的能力,并给各下行 Port 供电。Hub 可以单独使能各下行 Port。

  • USB function 能够通过总线传输或接收数据或控制信息的设备

USB/XHCI驱动 前情提要&背景知识

  • 什么是xhci?
  • 答: xhci是USB的控制器, USB1.0的控制器是UHCI/OHCI, 2.0是EHCI, EHCI不向下兼容1.0, 直到USB3.0的XHCI出现,统一了操作标准
  • 具体的来说,有没有参考资料?
  • 答:参考资料
  • XHCI可以做什么?
  • 答:分为两部分,首先XHCI控制器负责整个USB系统的数据与其他内存空间的交互,其次,XHCI控制器负责控制USB设备
    • 追问:控制和传输,有区别吗?
    • 答:有,传输不改变设备的状态,具体来说,不管是USB HUB还是USB FUNCTION,其实都是状态机
    • 追问2: HUB/FUNCTION又是什么?
    • 答:这么描述吧:
      • 首先HUB/FUNCTION都是USB设备
      • HUB是可以管理设备的设备(比如扩展坞,值得一提的是其实整个USB设备树的根-称为ROOTHUB,其实也只不过是一个特殊的扩展坞而已)
      • FUNCTION是实际上有功能的设备(例:起存储功能的U盘,起网卡功能的USB网卡...)
    • 追问3:再说说状态机的事?
    • 答:在Intel的XHCI文档中搜索state machine来了解各部分的状态
  • 好吧:那么USB系统是如何构成的?
  • 答:宏观上是树状结构,逻辑上USB设备都是事件驱动的事件机器:
    • 对于HUB,其内部有两种事件发送端,但是事件的接收端是统一的:
      • 事件接收端:EventRing-其实是个消息队列,当EventRing接收到事件后会想办法通知操作系统-用中断,或者操作系统主动轮询这个队列以检查新到的事件
      • 内部事件发送端:CommandRing-负责发送改变HUB状态的/调用HUB硬件实现的功能的请求事件的地方
      • 设备事件发送端:TransferRing-负责发送与设备的EndPoint交互(控制/传输都通过这个ring进行)的事件的地方
        • 追问:Endpoint是什么?
        • 答:是在物理上传输数据的部分,一个设备可以有很多个EndPoint,具体数量随USB协议版本而变化,EndPoint一般是单向的,Hub与设备的EndPoint建立通信后,这个逻辑概念上的数据传输路线就被叫做数据管道
        • 但是Endpoint0是特殊的,他必然存在,且是唯一同时可以双向通信的EndPoint,负责与HUB交换设备的"控制"事件,人们喜欢把Endpoint0的传输操作叫做"控制传输"
        • 为什么要这么设计?因为更多的管道就是更多的带宽!
      • 事件传输单元:TRB(Transfer Request Block)-每个TRB都由4位u32组成,且容纳这些数据的内存必须16位对齐,其中第四个u32的10-15位内保存的是TRB类型(即事件类型)的唯一标识符
      • 事实上,这三个Ring在数据结构上拥有相同的实现方式: 其中RING_LENGTH随不同设备而改变,属于配置选项,同时,ring的最后一个单元总是要放一个LinkTrb以标明这里是ring的结尾,需要从头开始循环。
        #![allow(unused)]
        fn main() {
        let ring = [[u32;4];RING_LENGTH];
        let enqueue_pointer:*const [u32;4];
        let dequeue_pointer:*const [u32;4];
        let cycle_bit:bool;
        }
        
        • 追问:循环?
        • 答:是的,ring表示这玩意是个用数组实现的循环队列,当然,也有队头(dequeue)和队尾(enqueue),这两个指针中间的TRB就是正在处理的事件,同时,为了硬件纠错,还引入了cycle_bit,正在处理的事件的cycle_bit必须与环的cycle_bit一致才被视为有效事件,否则当成很久之前就已经处理过了,会直接跳过/报错。
        • TRB大体可分为三类:Control/Transfer/Event TRB,名字就已经表明了他们分别在什么地方出现
    • 对于设备,我们其实并不关心,这部分是制造厂商要负责的事情,我们只在乎数据/控制的传输,把它当成一个塞进去命令就会给反馈的黑盒即可
      • 具体说说!
      • 答:好吧,与设备的通信如同TCP协议一样,有着"三次握手"的格式
      • 首先,发送Setup TRB---这表示一次事件的开始,以及表明了接下来要传输什么数据,setup TRB的类型是有限的,已经在xhci文档/usb文档里列了出来,请自行查阅
      • 然后,发送Data TRB---这部分是可选的,有些TRB并不需要发送数据,比如GetDescriptor TRB,这个Setup TRB中就已经包含了完整的请求信息(请求的数据条目的编号)
      • 最后:发送Status TRB--标准着这次事件的结束,其中包含了一些额外的控制信息,与中断系统/连续传输有关
      • 最后的最后:敲响门铃寄存器来通知设备接受事件,并在EventRing/本设备的doorbell中断上等待设备回报回来的事件。
        • doorbell是什么?
        • 硬件上的实现,这玩意是一个数组,主要用处就是通知被分配在特定slot上的设备有事件被发起,请接收并处理
        • 其中doorbell 0比较特殊,它被称为"默认地址"-实际上是控制器自己,当一个设备刚插上HUB时,它会被分配到默认地址上,(因为这时设备还没有被分配地址),这也就意味着xhci一次性只能处理一个设备插进来的情况,如果在极短的时间插进来了多个设备,那么其他设备就得排队等待
        • 同时这也意味着,每个doorbell 都对应 一个分配出去的slot id,具体的请看xhci 文档
        • 那么什么是Slot?
        • 有这么两个概念:
          • port-HUB物理上有多少个usb口,每个port都有一个寄存器,这些寄存器是连续分配的,可以当初一个数组。
          • slot-hub一共能管理多少设备(包括下游设备,比如hub接hub),每个设备都有一个slot id,这样就抽象掉了port号的概念。
      • 我还是不明白,控制器怎么知道如何管理这些设备,具体来说,如何进行控制?
      • 答:通过dcbaa/, Device Context Base Address Array
        • Device Context,指的是我们为设备分配的内存区域,是用于控制设备的Endpoint+Slot的区域。
        • dcbaa,是我们分配的一个数组,其上包含了各个Device Context的地址(指针)
        • dcbaap,是xhci的一个寄存器,其值由我们配置为指向dcbaa的地址,xhci正是通过这个寄存器来知道/控制设备的配置状态的。
  • 好吧,能将整个流程完整的描述一遍吗?我是指程序上?
  • 答:从这里的try_init函数入手,这是整个驱动的入口,同时辅以xhci文档的第四章来确定你当前看的是哪一步。同时也可以参考飞腾派的官方嵌入式sdk
    • 经过与官方沟通的最新进展,sdk中的xhci并不稳定且正确,详细的请参考沟通记录,因此,请转而参考他们的freertos仓库。
  • 行!那么目前还需要干什么?
  • 参考问题文件夹,其中是与飞腾官方所沟通的一些问题,也是我们驱动目前需要解决的问题,如果有新问题,也请加进去。

代码结构导读

在使用rust编程时,我们并不总是遵循OOP(面向对象)的编程思想,转而我们更注重数据的流向,也就是说:我们更关注数据是怎么来的,怎么被处理的,在处理完成后,是怎么被传递到下一步的?

我们从入口开始:

入口

首先,目前在开发阶段,我们暂时选择不让系统在开机时自动进行驱动的初始化,转而由我们手动触发,因此,我们首先修改命令行界面

首先,修改cli crate的Cargo.toml

#...
[dependencies]
# axfs_vfs = { path = "../../../crates/axfs_vfs", optional = true }
# axfs_ramfs = { path = "../../../crates/axfs_ramfs", optional = true }
# crate_interface = { path = "../../../crates/crate_interface", optional = true }
# axstd = { path = "../../../ulib/axstd", features = ["alloc", "fs"], optional = true }
axstd = { path = "../../ulib/axstd", optional = true }
axfeat = { path = "../../api/axfeat", features = [
  "phytium-pi", # +
  "usb-host", # +
  "multitask", # +
] }
driver_usb = { path = "../../crates/driver_usb", features = ["phytium-xhci"] } # +
xhci = "0.9" # +
#...

在添加了driver_usb这个crate后,我们就可以在代码中直接调用驱动中的函数

#![allow(unused)]
fn main() {
//...
const CMD_TABLE: &[(&str, CmdHandler)] = &[
    ("exit", do_exit),
    ("help", do_help),
    ("uname", do_uname),
    ("ldr", do_ldr),
    ("str", do_str),
    ("test_xhci", test_xhci), // +
    ("enum_device", enum_device),// +
];

fn test_xhci(_args: &str) { // +
    driver_usb::try_init()  // +
}                           // +

//...
fn do_ldr(args: &str) { //顺便优化一下do_ldr,来让我们读内存更方便一些
    println!("ldr");
    if args.is_empty() {
        println!("try: ldr ffff0000400fe000 4");
    }

    fn ldr_one(addr: &str, offset: &str) -> io::Result<()> {
        // println!("addr = {}", addr);

        if let (Ok(parsed_addr), Ok(parsed_offset)) = (
            u64::from_str_radix(addr, 16),
            u64::from_str_radix(offset, 10),
        ) {
            for i in 0..parsed_offset {
                let address: *const u64 = (parsed_addr + i * 8) as *const u64; // 强制转换为合适的指针类型
                if address.is_aligned() {
                    let value: u64;
                    // println!("Parsed address: {:p}", address); // 打印地址时使用 %p 格式化符号

                    unsafe {
                        value = *address;
                    }

                    let le_bytes = value.to_le_bytes();

                    // println!("Value at address {}: 0x{:X}", addr, value); // 使用输入的地址打印值
                    // println!("value at address{} = 0x{:X}: ", addr, value);
                    for (j, chunk) in le_bytes.chunks(4).enumerate() {
                        let mut chunk_value: u32 = 0;
                        for (i, byte) in chunk.iter().enumerate() {
                            chunk_value |= (*byte as u32) << (i * 8);
                        }
                        println!(
                            "offset: 0x{:02x}: {:032b}",
                            i as usize * 8 + j * 4,
                            chunk_value
                        );
                    }
                } else {
                    println!("addr not aligned!");
                }
            }
        } else {
            println!("Failed to parse address.");
        }
        return Ok(());
    }

    // for addr in args.split_whitespace() {
    //     if let Err(e) = ldr_one(addr) {
    //         println!("ldr {} {}", addr, e);
    //     }
    // }
    let mut split_ascii_whitespace = args.split_ascii_whitespace();
    let base_addr = split_ascii_whitespace.next();
    let byte_counts = split_ascii_whitespace.next().unwrap_or("1");
    ldr_one(base_addr.unwrap(), byte_counts);
}
//...
}

接下来,让我们直接转到driver_usb crate,看看驱动到底是怎么运作的。

[4.0K]  ./
├── [4.0K]  guide/
│   ├── [6.1K]  code_structure1.md
│   └── [7.0K]  quickstart_usb.md
├── [4.0K]  question/
│   ├── [ 39K]  minicom_output.log
│   ├── [ 23K]  question_5_29.md
│   └── [352K]  scan_from_31000000.png
├── [4.0K]  src/
│   ├── [4.0K]  host/
│   │   ├── [4.0K]  structures/
│   │   │   ├── [4.0K]  todos/
│   │   │   │   ├── [ 834]  TODO.md
│   │   │   │   └── [ 13M]  xhci_root_port_init_graph.svg
│   │   │   ├── [4.0K]  usb/
│   │   │   │   ├── [3.7K]  mod.rs
│   │   │   │   ├── [ 10K]  usb_audio.rs
│   │   │   │   ├── [ 854]  usb_device.rs
│   │   │   │   └── [   0]  usb_request.rs
│   │   │   ├── [3.1K]  command_ring.rs
│   │   │   ├── [2.3K]  context.rs
│   │   │   ├── [4.0K]  descriptor.rs
│   │   │   ├── [2.4K]  event_ring.rs
│   │   │   ├── [1.3K]  extended_capabilities.rs
│   │   │   ├── [4.2K]  mod.rs
│   │   │   ├── [1.1K]  registers.rs
│   │   │   ├── [2.3K]  root_port.rs
│   │   │   ├── [2.4K]  scratchpad.rs
│   │   │   ├── [4.2K]  transfer_ring.rs
│   │   │   ├── [9.4K]  xhci_command_manager.rs
│   │   │   ├── [6.2K]  xhci_event_manager.rs
│   │   │   ├── [4.5K]  xhci_roothub.rs
│   │   │   ├── [3.1K]  xhci_slot_manager.rs
│   │   │   └── [ 18K]  xhci_usb_device.rs
│   │   ├── [4.0K]  xhci/
│   │   │   ├── [4.0K]  vl805/
│   │   │   │   ├── [5.8K]  mailbox.rs
│   │   │   │   └── [3.0K]  mod.rs
│   │   │   └── [5.0K]  mod.rs
│   │   └── [ 304]  mod.rs
│   ├── [ 10K]  .build.rs
│   ├── [2.7K]  device_types.rs
│   ├── [2.0K]  dma.rs
│   └── [ 992]  lib.rs
├── [ 24K]  Cargo.lock
└── [1.7K]  Cargo.toml

首先可以关注lib.rs,在这里,我们参考飞腾派官方提供的信息,选择第一个XHCI控制器,其地址为0x31a0_8000,在这里我们加上了虚拟地址的前缀:0xffff_0000,但是由于arceos在映射mmio区域时,采取的是1:1映射,因此这个地址仍然指向0x31a0_8000,同时事实上我们也可以直接访问0x31a0_8000来访问控制器。

#![allow(unused)]
fn main() {
//...
pub fn try_init() {
    init(0xffff_0000_31a0_8000 as usize) //just hard code it! refer phytium pi embedded sdk
}
//...
}
  • 什么是mmio?
  • 答:操作系统课上老师会告诉你虚拟内存的概念,现代的计算机系统,为了上层应用的方便,都会将硬件/数据/指令,统一编址进同一片内存空间中,而开发人员能见到的就是这片空间,在这片内存空间中,映射至硬件的内存区域,就被称为MMIO区域(Memory IO),通过MMIO区域,我们可以直接访问硬件的寄存器。

深入

接下来,让我们往里细看,看看这个函数中具体做了什么,追根溯源,最终可以追踪到xhci这个module

#![allow(unused)]
fn main() {
pub(crate) fn init(mmio_base: usize) {
    unsafe {
        registers::init(mmio_base); //在这里,我们首先读取了xhci的寄存器,并将它们抽象为方便我们操作的数据结构
        extended_capabilities::init(mmio_base);//extended_capabilities寄存器比较特殊,他记载了xhci控制器所支持的额外可选特性
    };

    debug!("resetting xhci controller");
    debug!(
        "before reset:{:?},pagesize: {}",
        registers::handle(|r| r.operational.usbsts.read_volatile()),
        registers::handle(|r| r.operational.pagesize.read_volatile().get())
    );
    reset_xhci_controller(); //在这里,我们遵循xhci规范4.2,进行控制器的重置与暂停运行
    debug!(
        "pagesize: {}",
        registers::handle(|r| r.operational.pagesize.read_volatile().get())
    );

// -----------------0 重置完成后,我们继续遵循4.2,进行各部分有关数据结构的初始化
    xhci_slot_manager::new(); //初始化槽位管理器,xhci_slot_manager这个module中包含了dcbaa的数据结构,并且在new的时候会将其注册进xhci控制器的对应寄存器中
    scratchpad::new(); //初始化scratchpad-这部分是交给xhci控制器进行其内部用途的空间,对于我们来说是个黑盒,只需要知道我们根据规范,得分配出特定大小的连续内存空间即可
    xhci_command_manager::new(); //command_manager-其内部持有CommandRing,同时包含了一些封装好的工具函数,用于发送事件
    xhci_event_manager::new(); //event_manager-其内部持有EventRing,同时包含了各个事件处理函数的入口,换句话来说,这里是处理控制器接收到的事件的地方
    xhci_roothub::new(); //root_hub-在前面的quickstart中,我们有提到,root_hub是整个usb系统的设备树的根节点,事实上root_hub是集成在控制器中的,我们在这里对其进行初始化
//------------------0

    // axhal::irq::register_handler(ARM_IRQ_PCIE_HOST_INTA, interrupt_handler); //中断系统损坏,待修复
    // axhal::irq::register_handler(ARM_IRQ_PCIE_HOST_INTA + 1, interrupt_handler);//就目前来说,我们不使用中断,而是使用轮询eventring来检查有没有新事件

    debug!(
        "before start:{:?}",
        registers::handle(|r| r.operational.usbsts.read_volatile())
    );
    registers::handle(|r| {
        r.operational.usbcmd.update_volatile(|r| {
            r.set_run_stop();  //至此,控制器的数据结构部分分配完毕,我们在这里设置控制器运行
        });

        while r.operational.usbsts.read_volatile().hc_halted() {} //并且等待控制器开机完成,一般等待100ms,在这里我们直接用while循环等待其标志位置0
    });

//-------------------------1仅仅是一些调试信息的输出
    debug!(
        "init completed!, coltroller state:{:?}",
        registers::handle(|r| r.operational.usbsts.read_volatile())
    );

    let number_of_ports =
        registers::handle(|r| r.capability.hcsparams1.read_volatile().number_of_ports() as usize);

    for i in 0..number_of_ports {
        debug!(
            "port{i} : {}",
            registers::handle(|r| r
                .port_register_set
                .read_volatile_at(i)
                .portsc
                .current_connect_status())
        )
    }
//------------------------1

    debug!("initializing roothub");
    ROOT_HUB.get().unwrap().lock().initialize(); //这里就是设备枚举的地方
}
}

那么,设备枚举之前的代码没有什么可以细说的地方,大家自行查看即可,需要注意的是,各个数据结构的分配需要遵循xhci规范的第六章-Table 6.1中所描述的关于内存对齐的要求,这部分我们还没做细致的检查(参考当前所面临的问题的描述/猜想),请同学们进行一一核对,以确定代码的正确性

达成成就-我们需要再深入点

接下来让我们直接看看设备枚举的过程

#![allow(unused)]
fn main() {
// 定义静态变量ROOT_HUB,用于存储根集线器的实例--我们之后要把所有的此类单例模式改写,因为有些计算机系统中有多个xhci控制器,目前重构进度位于phytium_pi_dev分支,任务处于暂停状态,目前不用关心
pub(crate) static ROOT_HUB: OnceCell<Spinlock<Roothub>> = OnceCell::uninit();

pub struct Roothub {
    ports: usize,
    root_ports: PageBox<[Arc<MaybeUninit<Spinlock<RootPort>>>]>, //pagebox分配 无 cache的空间
}

impl Roothub {
    pub fn initialize(&mut self) {
        //todo delay?
        debug!("initializing root ports");
        self.root_ports
            .iter_mut()
            .map(|a| unsafe { a.clone().assume_init() })
            .for_each(|arc| {
                debug!("initializing port {}", arc.lock().root_port_id);
                arc.lock().initialize(); //在这里,我们对每个port进行初始化
            });

        // debug!("configuring root ports"); //configure-目前无需关心,这是个空方法
        // self.root_ports
        //     .iter_mut()
        //     .map(|a| unsafe { a.clone().assume_init() })
        //     .for_each(|arc| {
        //         arc.lock().configure();
        //     });
    }
}
}

于是,我们转而去查看RootPort::initialize方法

#![allow(unused)]
fn main() {
//...
    pub fn initialize(&mut self) { //从这里开始,我们就要转而查看规范文档4.3章所描写的关于设备初始化的部分了
        if !self.connected() { //首先检查这个port上有没有插usb设备
            error!("port {} not connected", self.root_port_id);
            return;
        }
        debug!("port {} connected, continue", self.root_port_id);

        //由于uboot已经探测过设备,因此设备的device context可能已被更改,因此我们需要进行port复位-其实哪怕是在使用其他软件引导的情况下,我们也得这么做,因为你不知道系统启动前发生了什么
        reset_port(self.root_port_id);
        dump_port_status(self.root_port_id);

        let get_speed = self.get_speed(); //从port的寄存器上获取设备速度-这里的速度是硬件通过检查端点上的电压来确定的,是不可靠的。仅仅只是在初期启动时作过渡作用
        if get_speed == USBSpeed::USBSpeedUnknown {
            error!("unknown speed, index:{}", self.root_port_id);
        }
        debug!("port speed: {:?}", get_speed);

        debug!("initializing device: {:?}", get_speed);

        if let Ok(mut device) = XHCIUSBDevice::new(self.root_port_id as u8) { //在这一切之后,创建设备---但是真的应该在这里才开始创建嘛?我们是不是应该从一开始就分配好所有端口上设备的内存区域呢?
            debug!("writing ...");
            self.device_inited = true;
            unsafe { self.device.write(device) };
            debug!("writing complete");
        }

        unsafe { self.device.assume_init_mut().initialize() }; //开始设备的初始化
        debug!("initialize complete");
    }
//...
}

达成成就-结束了?

让我们看看这个设备的initialize方法是个怎么回事?

#![allow(unused)]
fn main() {
//... 从这里开始,就是正在施工的部分了
//我是指,我们正在折腾的部分,你已经跟上了项目最新的进度
    pub fn initialize(&mut self) {
        debug!("initialize/enum this device! port={}", self.port_id);

        // self.address_device(true);
        self.enable_slot(); //向设备申请slot
        self.slot_ctx_init();       ///配置设备的Input Context
        self.config_endpoint_0();   ///
        // self.check_input();
        self.assign_device();//配置设备的Output Context,并将其分配到dcbaa
        self.address_device(false); //address_device-问题就出现在这里,EventRing始终在返回ParamaterError,查阅规范得知,这说明控制器(或usb设备)收到了他不认识的TRB,当然也有可能是其他相关原因,让我们开始排查!接下来在讨论组里讨论吧!
        self.dump_ep0();
        dump_port_status(self.port_id as usize);
        // only available after address device
        // let get_descriptor = self.get_descriptor(); //damn, just assume speed is same lowest!
        // debug!("get desc: {:?}", get_descriptor);
        // dump_port_status(self.port_id as usize);
        // // self.check_endpoint();
        // // sleep(Duration::from_millis(2));

        // self.set_endpoint_speed(get_descriptor.max_packet_size()); //just let it be lowest speed!
        // self.evaluate_context_enable_ep0();
    }
//...
}

更新版:

前情提要

在之前的代码结构导读中,我们介绍了位于分支"phytium_pi_port"上的代码。目前,随着 xhci 部分的结束,我们已经将代码重构并迁移到了"phytium_pi_dev"分支,最新的驱动架构能够应对更多复杂情况,但结构也发生了大的变化,因此,我们重新做一遍代码导读。

文件结构

.
├── Cargo.lock
├── Cargo.toml
├── guide
│   ├── code_file_structure.log
│   ├── code_structure.md
│   └── quickstart_usb.md
└── src
    ├── addr.rs
    ├── ax
    │   └── mod.rs
    ├── device_types.rs
    ├── dma.rs
    ├── err.rs
    ├── host
    │   ├── device.rs
    │   ├── mod.rs
    │   └── xhci
    │       ├── context.rs
    │       ├── event.rs
    │       ├── mod.rs
    │       ├── registers.rs
    │       └── ring.rs
    └── lib.rs
6 directories, 18 files

入口

目前,我们暂时抛弃了原来的 cli 手动启动,而是将 usb 模块的引导做成了一个app


#[derive(Clone)]
struct OsDepImp;

impl OsDep for OsDepImp { //我们优化了驱动的架构,将其重构为系统无关的库,因此我们需要引入对各个操作系统进行适配的抽象层,也就是说,我们将驱动需要操作系统做的事情抽象了出来,形成了这个trait:"OsDep"
    type DMA = GlobalNoCacheAllocator;

    const PAGE_SIZE: usize = axalloc::PAGE_SIZE;
    fn dma_alloc(&self) -> Self::DMA { //就目前来说,我们仅仅只需要操作系统负责分配出No Cache的内存区域(DMA)即可。
        axalloc::global_no_cache_allocator()
    }
}

#[cfg_attr(feature = "axstd", no_mangle)]
fn main() {
    let phytium_cfg_id_0 = (0xffff_0000_31a0_8000, 48, 0);

    let config = USBHostConfig::new(
        phytium_cfg_id_0.0,
        phytium_cfg_id_0.1,
        phytium_cfg_id_0.2,
        OsDepImp {},
    );

    let usb = USBHost::new::<Xhci<_>>(config).unwrap();

    usb.poll();
}

让我们看看USBHostConfig里有什么:

#![allow(unused)]
fn main() {
#[derive(Clone)]
pub struct USBHostConfig<O>
where O: OsDep
{
    pub(crate) base_addr: VirtAddr,
    pub(crate) irq_num: u32,      //中断系统相关:中断号。
    pub(crate) irq_priority: u32, //中断系统相关:中断优先级。注:目前中断系统尚未适配
    pub(crate) os: O //集成了操作系统相关操作的trait对象
}
}

接下来,是与我们曾经的代码逻辑相似的 USBHost(XHCI)初始化流程,也就是USBHost::new方法,这部分所做事情与移植之前相差不大,请读者自行比对理解。

深入

让我们来看看最新的进展,在 USBHost 创建之后,就会被调用 poll 方法,这个方法的作用是进行设备的枚举:

#![allow(unused)]
fn main() {
    fn probe(&self) -> Result {
        let mut port_id_list = Vec::new();
        {
            let mut g = self.regs.lock();
            let regs = &mut g.regs;
            let port_len = regs.port_register_set.len();
            for i in 0..port_len {
                let portsc = &regs.port_register_set.read_volatile_at(i).portsc;
                info!(
                    "{TAG} Port {}: Enabled: {}, Connected: {}, Speed {}, Power {}",
                    i,
                    portsc.port_enabled_disabled(),
                    portsc.current_connect_status(),
                    portsc.port_speed(),
                    portsc.port_power()
                );

                if !portsc.port_enabled_disabled() {
                    continue;
                }

                port_id_list.push(i); //寻找所有连接上了设备的port
            }
        }
        for port_id in port_id_list {
            let slot = self.device_slot_assignment(port_id); //首先,是为设备分配slot
            self.address_device(slot, port_id);              //在这里,我们配置对应slot的上下文(context),并请求xhci为设备设置地址
            self.set_ep0_packet_size(slot);                  //通过控制传输,获取准确的endpoint 0传输数据包大小
            self.setup_fetch_all_dev_desc(slot);             //在以上的配置完成后,获取设备的全部描述符。
        }

        self.dev_ctx
            .lock()
            .attached_set
            .iter_mut()
            .for_each(|dev| {}); //TODO: 为设备选择制定的配置,而后开始传输。目前我们先做一个HID设备(鼠标/键盘)
        Ok(())
    }
}

任务分解 1-设备描述符

设备描述符是设备所包含的描述信息,在这里,我们一次性获取所有的描述符信息,并在需要的时候获取对应条目的描述符

设备描述符有许多种类,不同的种类描述了不同的信息,比如 device 就可能会包含设备的厂家/设备的类型等信息,参考:

#![allow(unused)]
fn main() {
#[derive(FromPrimitive, ToPrimitive, Copy, Clone, Debug)]
#[allow(non_camel_case_types)]
pub(crate) enum Type {
    //USB 1.1: 9.4 Standard Device Requests, Table 9-5. Descriptor Types
    Device = 1,
    Configuration = 2,
    String = 3,
    Interface = 4,
    Endpoint = 5,
    // USB 2.0: 9.4 Standard Device Requests, Table 9-5. Descriptor Types
    DeviceQualifier = 6,
    OtherSpeedConfiguration = 7,
    InterfacePower1 = 8,
    Hid = 0x21,
    HIDReport = 0x22,
    HIDPhysical = 0x23,
    // USB 3.0+: 9.4 Standard Device Requests, Table 9-5. Descriptor Types
    OTG = 0x09,
    Debug = 0x0a,
    InterfaceAssociation = 0x0b,
    Bos = 0x0f,
    DeviceCapability = 0x10,
    SuperSpeedEndpointCompanion = 0x30,
    SuperSpeedPlusIsochEndpointCompanion = 0x31,
}
}

这些类型,每一个都对应了不同的 Descriptor,每个 Descriptor 又有不同的数据结构,好在我们目前暂时不用全部实现,只实现需要的部分即可。我们所需要关心的代码位于这里,

#![allow(unused)]
fn main() {
impl Descriptor {
    pub(crate) fn from_slice(raw: &[u8]) -> Result<Self, Error> {
        assert_eq!(raw.len(), raw[0].into());
        match FromPrimitive::from_u8(raw[1]) {
            Some(t) => {
                let raw: *const [u8] = raw;
                match t {
                    // SAFETY: This operation is safe because the length of `raw` is equivalent to the
                    // one of the descriptor.
                    //todo 任务1:我们所需要的就是在这里补充描述符的创建,在setup_fetch_all_dev_desc方法中,这个方法会被调用多次以反序列化设备传输过来的描述符
                    Type::Device => Ok(Self::Device(unsafe { ptr::read(raw.cast()) })),
                    Type::Configuration => {
                        Ok(Self::Configuration(unsafe { ptr::read(raw.cast()) }))
                    }
                    Type::String => Ok(Self::Str),
                    Type::Interface => Ok(Self::Interface(unsafe { ptr::read(raw.cast()) })),
                    Type::Endpoint => Ok(Self::Endpoint(unsafe { ptr::read(raw.cast()) })),
                    Type::Hid => Ok(Self::Hid),
                    other => unimplemented!("please implement descriptor type:{:?}", other),
                }
            }
            None => Err(Error::UnrecognizedType(raw[1])),
        }
    }
}
}

额外的参考资料:

任务分解 2:设备配置选择

在获取到了描述符后,我们要从设备提供的几种配置中选择一种来设置端点(endpoint),参考:redox 的代码

这部分在我们的代码中应当位于根据设备描述符查找驱动

任务分解 3-HID 驱动编写-键盘

先写一个键盘驱动,参考 redox 代码

USB最新进展

可以读取到描述符:

arceos# test_xhci
[ 47.250961 0:2 driver_usb::host::xhci:49] resetting xhci controller
[ 47.255722 0:2 driver_usb::host::xhci:50] before reset:UsbStatusRegister { hc_halted: false, host_system_error: false, event_interrupt: false, port_change_detect: true, save_state_status: false, restore_state_status: false, save_restore_error: false, controller_not_ready: false, host_controller_error: false },pagesize: 1
[ 47.285321 0:2 driver_usb::host::xhci:136] stop
[ 47.291050 0:2 driver_usb::host::xhci:141] wait until halt
[ 47.297733 0:2 driver_usb::host::xhci:143] halted
[ 47.303635 0:2 driver_usb::host::xhci:145] HCRST!
[ 47.309539 0:2 driver_usb::host::xhci:154] get bios ownership
[ 47.316483 0:2 driver_usb::host::xhci:168] taked xhci ownershop
[ 47.323600 0:2 driver_usb::host::xhci:56] pagesize: 1
[ 47.329850 0:2 driver_usb::host::structures::xhci_roothub:86] number of ports:2
[ 47.338355 0:2 driver_usb::host::structures::xhci_roothub:91] allocating port 0
[ 47.346864 0:2 driver_usb::host::structures:100] ----dumped port state: PortStatusAndControlRegister { current_connect_status: false, port_enabled_disabled: false, over_current_active: false, port_reset: false, port_link_state: 5, port_power: true, port_speed: 0, port_indicator_control: Off, port_link_state_write_strobe: false, connect_status_change: false, port_enabled_disabled_change: false, warm_port_reset_change: false, over_current_change: false, port_reset_change: false, port_link_state_change: false, port_config_error_change: false, cold_attach_status: false, wake_on_connect_enable: false, wake_on_disconnect_enable: false, wake_on_over_current_enable: false, device_removable: false, warm_port_reset: false }
[ 47.411268 0:2 driver_usb::host::structures::xhci_roothub:98] assert:0 == 0
[ 47.419426 0:2 driver_usb::host::structures::xhci_roothub:91] allocating port 1
[ 47.427934 0:2 driver_usb::host::structures:100] ----dumped port state: PortStatusAndControlRegister { current_connect_status: true, port_enabled_disabled: true, over_current_active: false, port_reset: false, port_link_state: 0, port_power: true, port_speed: 4, port_indicator_control: Off, port_link_state_write_strobe: false, connect_status_change: false, port_enabled_disabled_change: false, warm_port_reset_change: false, over_current_change: false, port_reset_change: true, port_link_state_change: false, port_config_error_change: false, cold_attach_status: false, wake_on_connect_enable: false, wake_on_disconnect_enable: false, wake_on_over_current_enable: false, device_removable: false, warm_port_reset: false }
[ 47.492078 0:2 driver_usb::host::structures::xhci_roothub:98] assert:1 == 1
[ 47.500237 0:2 driver_usb::host::structures::xhci_roothub:102] ended
[ 47.507790 0:2 driver_usb::host::structures::xhci_roothub:112] initialized!
[ 47.515949 0:2 driver_usb::host::structures::xhci_slot_manager:63] max slot: 16
[ 47.524457 0:2 driver_usb::host::structures::xhci_slot_manager:87] addr of dcbaa: 90196040
[ 47.533917 0:2 driver_usb::host::structures::xhci_slot_manager:96] initialized!
[ 47.542425 0:2 driver_usb::host::structures::xhci_slot_manager:24] assign device: VA:0x90197000 to dcbaa 0
[ 47.553274 0:2 driver_usb::host::structures::scratchpad:79] initialized!
[ 47.561207 0:2 driver_usb::host::structures::xhci_command_manager:271] initialized!
[ 47.570024 0:2 driver_usb::host::structures::xhci_event_manager:43] initilizating!
[ 47.578825 0:2 driver_usb::host::structures::event_ring:33] created! event ring, check alignment of 4k: VA:0x9019a000
[ 47.590597 0:2 driver_usb::host::structures::xhci_event_manager:56] test
[ 47.598500 0:2 driver_usb::host::structures::xhci_event_manager:96] initialized!
[ 47.607088 0:2 driver_usb::host::xhci:70] before start:UsbStatusRegister { hc_halted: true, host_system_error: false, event_interrupt: false, port_change_detect: true, save_state_status: false, restore_state_status: false, save_restore_error: false, controller_not_ready: false, host_controller_error: false }
[ 47.635560 0:2 driver_usb::host::xhci:82] init completed!, coltroller state:UsbStatusRegister { hc_halted: false, host_system_error: false, event_interrupt: false, port_change_detect: true, save_state_status: false, restore_state_status: false, save_restore_error: false, controller_not_ready: false, host_controller_error: false }
[ 47.665941 0:2 driver_usb::host::xhci:91] port0 : false
[ 47.672363 0:2 driver_usb::host::xhci:91] port1 : true
[ 47.678698 0:2 driver_usb::host::xhci:101] initializing roothub
[ 47.685816 0:2 driver_usb::host::structures::xhci_roothub:40] initializing root ports
[ 47.694843 0:2 driver_usb::host::structures::xhci_roothub:45] initializing port 0
[ 47.703525 0:2 driver_usb::host::structures::root_port:26] port 0 not connected
[ 47.712029 0:2 driver_usb::host::structures::xhci_roothub:45] initializing port 1
[ 47.720711 0:2 driver_usb::host::structures::root_port:29] port 1 connected, continue
[ 47.729737 0:2 driver_usb::host::structures:112] reseting port 1
[ 47.736943 0:2 driver_usb::host::structures:114] before reset Port 1, status: PortStatusAndControlRegister { current_connect_status: true, port_enabled_disabled: true, over_current_active: false, port_reset: false, port_link_state: 0, port_power: true, port_speed: 4, port_indicator_control: Off, port_link_state_write_strobe: false, connect_status_change: false, port_enabled_disabled_change: false, warm_port_reset_change: false, over_current_change: false, port_reset_change: true, port_link_state_change: false, port_config_error_change: false, cold_attach_status: false, wake_on_connect_enable: false, wake_on_disconnect_enable: false, wake_on_over_current_enable: false, device_removable: false, warm_port_reset: false }
[ 47.801619 0:2 driver_usb::host::structures:140] Port 1 reset ok, status: PortStatusAndControlRegister { current_connect_status: true, port_enabled_disabled: true, over_current_active: false, port_reset: false, port_link_state: 0, port_power: true, port_speed: 4, port_indicator_control: Off, port_link_state_write_strobe: false, connect_status_change: false, port_enabled_disabled_change: false, warm_port_reset_change: false, over_current_change: false, port_reset_change: true, port_link_state_change: false, port_config_error_change: false, cold_attach_status: false, wake_on_connect_enable: false, wake_on_disconnect_enable: false, wake_on_over_current_enable: false, device_removable: false, warm_port_reset: false }
[ 47.865927 0:2 driver_usb::host::structures:100] ----dumped port state: PortStatusAndControlRegister { current_connect_status: true, port_enabled_disabled: true, over_current_active: false, port_reset: false, port_link_state: 0, port_power: true, port_speed: 4, port_indicator_control: Off, port_link_state_write_strobe: false, connect_status_change: false, port_enabled_disabled_change: false, warm_port_reset_change: false, over_current_change: false, port_reset_change: true, port_link_state_change: false, port_config_error_change: false, cold_attach_status: false, wake_on_connect_enable: false, wake_on_disconnect_enable: false, wake_on_over_current_enable: false, device_removable: false, warm_port_reset: false }
[ 47.930073 0:2 driver_usb::host::structures::root_port:39] port speed: USBSpeedSuper
[ 47.939011 0:2 driver_usb::host::structures::root_port:41] initializing device: USBSpeedSuper
[ 47.948733 0:2 driver_usb::host::structures::xhci_usb_device:63] new device! port:1
[ 47.957656 0:2 driver_usb::host::structures::root_port:44] writing ...
[ 47.965312 0:2 driver_usb::host::structures::root_port:47] writing complete
[ 47.973471 0:2 driver_usb::host::structures::xhci_usb_device:83] initialize/enum this device! port=1
[ 47.983801 0:2 driver_usb::host::structures::xhci_command_manager:147] do command EnableSlot(EnableSlot { slot_type: 0, cycle_bit: true }) !
[ 47.997601 0:2 driver_usb::host::structures::xhci_command_manager:151] enque trb, assert addr 16B aligned! 90198000
[ 48.009234 0:2 driver_usb::host::structures::xhci_command_manager:167] waiting for interrupt handler complete!
[ 48.020432 0:2 driver_usb::host::structures::xhci_event_manager:106] event handler has a trb:PortStatusChange(PortStatusChange { completion_code: Ok(Success), port_id: 2, cycle_bit: true })
[ 48.038484 0:2 driver_usb::host::structures::xhci_event_manager:135] step into port status change.

[ 48.048813 0:2 driver_usb::host::structures::xhci_roothub:65] port 1 changed!
[ 48.057147 0:2 driver_usb::host::structures:100] ----dumped port state: PortStatusAndControlRegister { current_connect_status: true, port_enabled_disabled: true, over_current_active: false, port_reset: false, port_link_state: 0, port_power: true, port_speed: 4, port_indicator_control: Off, port_link_state_write_strobe: false, connect_status_change: false, port_enabled_disabled_change: false, warm_port_reset_change: false, over_current_change: false, port_reset_change: true, port_link_state_change: false, port_config_error_change: false, cold_attach_status: false, wake_on_connect_enable: false, wake_on_disconnect_enable: false, wake_on_over_current_enable: false, device_removable: false, warm_port_reset: false }
[ 48.121293 0:2 driver_usb::host::structures::xhci_event_manager:106] event handler has a trb:PortStatusChange(PortStatusChange { completion_code: Ok(Success), port_id: 2, cycle_bit: true })
[ 48.139345 0:2 driver_usb::host::structures::xhci_event_manager:135] step into port status change.

[ 48.149675 0:2 driver_usb::host::structures::xhci_roothub:65] port 1 changed!
[ 48.158009 0:2 driver_usb::host::structures:100] ----dumped port state: PortStatusAndControlRegister { current_connect_status: true, port_enabled_disabled: true, over_current_active: false, port_reset: false, port_link_state: 0, port_power: true, port_speed: 4, port_indicator_control: Off, port_link_state_write_strobe: false, connect_status_change: false, port_enabled_disabled_change: false, warm_port_reset_change: false, over_current_change: false, port_reset_change: true, port_link_state_change: false, port_config_error_change: false, cold_attach_status: false, wake_on_connect_enable: false, wake_on_disconnect_enable: false, wake_on_over_current_enable: false, device_removable: false, warm_port_reset: false }
[ 48.222154 0:2 driver_usb::host::structures::xhci_event_manager:106] event handler has a trb:CommandCompletion(CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417590272, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true })
[ 48.246978 0:2 driver_usb::host::structures::xhci_command_manager:230] handleing command complete:CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417590272, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }
[ 48.270589 0:2 driver_usb::host::structures::xhci_command_manager:182] t o t a l success!
[ 48.279962 0:2 driver_usb::host::structures::xhci_usb_device:145] enable slot success! CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417590272, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }
[ 48.302616 0:2 driver_usb::host::structures::xhci_usb_device:200] init input ctx
[ 48.311210 0:2 driver_usb::host::structures::xhci_usb_device:266] endpoint 0 state: Disabled, slot state: DisabledEnabled
[ 48.323362 0:2 driver_usb::host::structures::xhci_usb_device:208] root port id: 1
[ 48.332043 0:2 driver_usb::host::structures::xhci_usb_device:241] begin config endpoint 0 and assign dev!
[ 48.342807 0:2 driver_usb::host::structures::xhci_usb_device:244] config ep0
[ 48.351051 0:2 driver_usb::host::structures::xhci_usb_device:266] endpoint 0 state: Disabled, slot state: DisabledEnabled
[ 48.363203 0:2 driver_usb::host::structures::xhci_usb_device:252] address of transfer ring: 9019d000
[ 48.373533 0:2 driver_usb::host::structures::xhci_usb_device:275] assigning device into dcbaa, slot number= 1,output addr: VA:0x901a1000
[ 48.386986 0:2 driver_usb::host::structures::xhci_slot_manager:24] assign device: VA:0x901a1000 to dcbaa 1
[ 48.397837 0:2 driver_usb::host::structures::xhci_usb_device:289] addressing device
[ 48.406690 0:2 driver_usb::host::structures::xhci_usb_device:291] address to input VA:0x9019f000, check 64 alignment!
[ 48.418495 0:2 driver_usb::host::structures::xhci_command_manager:105] addressing device!
[ 48.427869 0:2 driver_usb::host::structures::xhci_command_manager:147] do command AddressDevice(AddressDevice { input_context_pointer: 2417618944, block_set_address_request: false, slot_id: 1, cycle_bit: true }) !
[ 48.448006 0:2 driver_usb::host::structures::xhci_command_manager:151] enque trb, assert addr 16B aligned! 90198010
[ 48.459638 0:2 driver_usb::host::structures::xhci_command_manager:167] waiting for interrupt handler complete!
[ 48.470836 0:2 driver_usb::host::structures::xhci_event_manager:106] event handler has a trb:CommandCompletion(CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417590288, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true })
[ 48.495659 0:2 driver_usb::host::structures::xhci_command_manager:230] handleing command complete:CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417590288, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }
[ 48.519270 0:2 driver_usb::host::structures::xhci_command_manager:182] t o t a l success!
[ 48.528644 0:2 driver_usb::host::structures::xhci_usb_device:300] addressed device at slot id 1
[ 48.538539 0:2 driver_usb::host::structures::xhci_usb_device:301] command result CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417590288, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }
[ 48.560673 0:2 driver_usb::host::structures::xhci_usb_device:306] assert ep0 running!
[ 48.569700 0:2 driver_usb::host::structures::xhci_usb_device:266] endpoint 0 state: Disabled, slot state: DisabledEnabled

------------------------------------------------------------------------------------------------------------
[ 48.581852 0:2 driver_usb::host::structures::xhci_usb_device:368] get descriptor! //获取描述符
[ 48.590532 0:2 driver_usb::host::structures::xhci_usb_device:266] endpoint 0 state: Disabled, slot state: DisabledEnabled
[ 48.602685 0:2 driver_usb::host::structures::xhci_usb_device:376] doorbell id: 1
[ 48.611279 0:2 driver_usb::host::structures::transfer_ring:137] enque_index: 1
[ 48.619697 0:2 driver_usb::host::structures::transfer_ring:137] enque_index: 2
[ 48.628117 0:2 driver_usb::host::structures::transfer_ring:137] enque_index: 3
[ 48.636536 0:2 driver_usb::host::structures::xhci_usb_device:350] doorbell ing
[ 48.644957 0:2 driver_usb::host::structures::xhci_usb_device:357] waiting for event
[ 48.653810 0:2 driver_usb::host::structures::xhci_event_manager:106] event handler has a trb:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417610784, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 48.678634 0:2 driver_usb::host::structures::xhci_event_manager:109] event = TransferEvent { completion_code: Ok(Success), trb_pointer: 2417610784, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 48.700768 0:2 driver_usb::host::structures::xhci_event_manager:110] step into transfer event

[ 48.710663 0:2 driver_usb::host::structures::xhci_slot_manager:45] transfer event! param: Success,TransferEvent { completion_code: Ok(Success), trb_pointer: 2417610784, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 48.734620 0:2 driver_usb::host::structures::xhci_slot_manager:48] transfer event succeed!
[ 48.744081 0:2 driver_usb::host::structures::xhci_usb_device:360] interrupt handler complete! result = Ok([2417610784, 0, 16777216, 16875521])
[ 48.758056 0:2 driver_usb::host::structures::xhci_usb_device:404] getted! buffer:Device { len: 18, descriptor_type: 1, cd_usb: 800, class: 0, subclass: 0, protocol: 0, max_packet_size0: 9, vendor: 0, product_id: 0, device: 0, manufacture: 0, product: 0, serial_number: 0, num_configurations: 0 }
[ 48.785311 0:2 driver_usb::host::structures::xhci_usb_device:406] return!
[ 48.793298 0:2 driver_usb::host::structures::xhci_usb_device:91] get max packet size: 512
[ 48.802671 0:2 driver_usb::host::structures::xhci_usb_device:418] eval ctx and enable ep0!
[ 48.812133 0:2 driver_usb::host::structures::xhci_command_manager:147] do command EvaluateContext(EvaluateContext { input_context_pointer: 2417618944, slot_id: 1, cycle_bit: true }) !
[ 48.829666 0:2 driver_usb::host::structures::xhci_command_manager:151] enque trb, assert addr 16B aligned! 90198020
[ 48.841298 0:2 driver_usb::host::structures::xhci_command_manager:167] waiting for interrupt handler complete!
[ 48.852496 0:2 driver_usb::host::structures::xhci_event_manager:106] event handler has a trb:CommandCompletion(CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417590304, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true })
[ 48.877319 0:2 driver_usb::host::structures::xhci_command_manager:230] handleing command complete:CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417590304, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }
[ 48.900930 0:2 driver_usb::host::structures::xhci_command_manager:182] t o t a l success!
[ 48.910303 0:2 driver_usb::host::structures::xhci_usb_device:427] success! complete code: CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417590304, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }
[ 48.933238 0:2 driver_usb::host::structures::transfer_ring:137] enque_index: 4
[ 48.941639 0:2 driver_usb::host::structures::transfer_ring:137] enque_index: 5
[ 48.950058 0:2 driver_usb::host::structures::transfer_ring:137] enque_index: 6
[ 48.958477 0:2 driver_usb::host::structures::xhci_usb_device:350] doorbell ing
[ 48.966897 0:2 driver_usb::host::structures::xhci_usb_device:357] waiting for event
[ 48.975752 0:2 driver_usb::host::structures::xhci_event_manager:106] event handler has a trb:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417610832, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 49.000575 0:2 driver_usb::host::structures::xhci_event_manager:109] event = TransferEvent { completion_code: Ok(Success), trb_pointer: 2417610832, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 49.022709 0:2 driver_usb::host::structures::xhci_event_manager:110] step into transfer event

[ 49.032604 0:2 driver_usb::host::structures::xhci_slot_manager:45] transfer event! param: Success,TransferEvent { completion_code: Ok(Success), trb_pointer: 2417610832, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 49.056561 0:2 driver_usb::host::structures::xhci_slot_manager:48] transfer event succeed!
[ 49.066022 0:2 driver_usb::host::structures::xhci_usb_device:360] interrupt handler complete! result = Ok([2417610832, 0, 16777216, 16875521])
[ 49.079997 0:2 driver_usb::host::structures::xhci_usb_device:159] fetched!

------------------------------------------------------------------------------------------------------------
[ 49.088074 0:2 driver_usb::host::structures::xhci_usb_device:161] dev descriptors: [Device(Device { len: 18, descriptor_type: 1, cd_usb: 800, class: 0, subclass: 0, protocol: 0, max_packet_size0: 9, vendor: 2385, product_id: 5734, device: 1, manufacture: 1, product: 2, serial_number: 3, num_configurations: 1 })] //设备描述符
[ 49.116887 0:2 driver_usb::host::structures::root_port:51] initialize complete
[ 49.125325 0:2 driver_usb::host::structures::transfer_ring:137] enque_index: 7
[ 49.133727 0:2 driver_usb::host::structures::transfer_ring:137] enque_index: 8
[ 49.142147 0:2 driver_usb::host::structures::transfer_ring:137] enque_index: 9
[ 49.150566 0:2 driver_usb::host::structures::xhci_usb_device:350] doorbell ing
[ 49.158986 0:2 driver_usb::host::structures::xhci_usb_device:357] waiting for event
[ 49.167840 0:2 driver_usb::host::structures::xhci_event_manager:106] event handler has a trb:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417610880, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 49.192663 0:2 driver_usb::host::structures::xhci_event_manager:109] event = TransferEvent { completion_code: Ok(Success), trb_pointer: 2417610880, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 49.214797 0:2 driver_usb::host::structures::xhci_event_manager:110] step into transfer event

[ 49.224693 0:2 driver_usb::host::structures::xhci_slot_manager:45] transfer event! param: Success,TransferEvent { completion_code: Ok(Success), trb_pointer: 2417610880, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 49.248649 0:2 driver_usb::host::structures::xhci_slot_manager:48] transfer event succeed!
[ 49.258111 0:2 driver_usb::host::structures::xhci_usb_device:360] interrupt handler complete! result = Ok([2417610880, 0, 16777216, 16875521])
[ 49.272086 0:2 driver_usb::host::structures::xhci_usb_device:172] fetched!
[ 49.280164 0:2 driver_usb::host::structures::descriptor:188] Unrecognized USB descriptor: UnrecognizedType(48)
[ 49.291358 0:2 driver_usb::host::structures::descriptor:188] Unrecognized USB descriptor: UnrecognizedType(48)

------------------------------------------------------------------------------------------------------------
[ 49.302554 0:2 driver_usb::host::structures::xhci_usb_device:174] config descriptors: [Configuration(Configuration { length: 9, ty: 2, total_length: 44, num_interfaces: 1, config_val: 1, config_string: 0, attributes: 128, max_power: 37 }), Interface(Interface { len: 9, descriptor_type: 4, interface_number: 0, alternate_setting: 0, num_endpoints: 2, interface_class: 8, interface_subclass: 6, interface_protocol: 80, interface: 0 }), Endpoint(Endpoint { len: 7, descriptor_type: 5, endpoint_address: 129, attributes: 2, max_packet_size: 1024, interval: 0 }), Endpoint(Endpoint { len: 7, descriptor_type: 5, endpoint_address: 2, attributes: 2, max_packet_size: 1024, interval: 0 })] //配置描述符、接口描述符、端点描述符
[ 49.363478 0:2 driver_usb::host::structures::xhci_command_manager:147] do command ConfigureEndpoint(ConfigureEndpoint { input_context_pointer: 2417618944, deconfigure: false, slot_id: 1, cycle_bit: true }) !
[ 49.383016 0:2 driver_usb::host::structures::xhci_command_manager:151] enque trb, assert addr 16B aligned! 90198030
[ 49.394648 0:2 driver_usb::host::structures::xhci_command_manager:167] waiting for interrupt handler complete!
[ 49.405845 0:2 driver_usb::host::structures::xhci_event_manager:106] event handler has a trb:CommandCompletion(CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417590320, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true })
[ 49.430669 0:2 driver_usb::host::structures::xhci_command_manager:230] handleing command complete:CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417590320, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }
[ 49.454280 0:2 driver_usb::host::structures::xhci_command_manager:182] t o t a l success!
[ 49.463654 0:2 driver_usb::host::structures::xhci_usb_device:114] configure endpoint complete
[ 49.473375 0:2 driver_usb::host::structures::root_port:54] configure complete
arceos# 

设备描述符(Device Descriptor)已经成功获取,字段的解释如下:

  1. len: 18
    • 描述符的长度为18字节
  2. descriptor_type: 1
    • 描述符类型为1,表示这是设备描述符
  3. cd_usb: 800
    • USB协议版本,0x800表示USB 2.0版本
  4. class: 0
    • 设备类代码,0表示设备由其接口描述符指定设备类
  5. subclass: 0
    • 设备子类代码,0表示无特定子类
  6. protocol: 0
    • 设备协议代码,0表示无特定协议
  7. max_packet_size0: 9
    • 端点0的最大包大小为9字节
  8. vendor: 2385
    • 供应商ID,2385
  9. product_id: 5734
    • 产品ID,5734
  10. device: 1
    • 设备版本号
  11. manufacture: 1
    • 制造商字符串描述符的索引
  12. product: 2
    • 产品字符串描述符的索引
  13. serial_number: 3
    • 序列号字符串描述符的索引
  14. num_configurations: 1
    • 设备支持的配置数,表示该设备有1个配置

配置描述符 (Configuration Descriptor)

  1. length: 9

    • 描述符长度为9字节
  2. ty: 2

    • 描述符类型为2,表示这是一个配置描述符
  3. total_length: 44

    • 该配置所包含的所有描述符的总长度为44字节
  4. num_interfaces: 1

    • 该配置包含1个接口
  5. config_val: 1

    • 该配置的值为1,用于设置该配置
  6. config_string: 0

    • 配置字符串描述符的索引,值为0表示没有字符串描述符
  7. attributes: 128

    • 配置的属性,128表示总线供电
  8. max_power: 37

    • 设备所需的最大功率

接口描述符 (Interface Descriptor):

  1. len: 9

    • 描述符长度为9字节
  2. descriptor_type: 4

    • 描述符类型为4,表示这是一个接口描述符
  3. interface_number: 0

    • 接口编号为0
  4. alternate_setting: 0

    • 备用设置编号为0
  5. num_endpoints: 2

    • 该接口有2个端点(不包括端点0)
  6. interface_class: 8

    • 接口类代码为8,表示该接口属于大容量存储类
  7. interface_subclass: 6

    • 接口子类代码为6,表示SCSI传输命令集
  8. interface_protocol: 80

    • 接口协议代码为80,表示Bulk-Only传输
  9. interface: 0

    • 接口字符串描述符的索引,值为0表示没有字符串描述符

端点描述符 (Endpoint Descriptor):

  1. 第一个端点描述符
    • len: 7
      • 描述符长度为7字节
    • descriptor_type: 5
      • 描述符类型为5,表示这是一个端点描述符
    • endpoint_address: 129
      • 端点地址为129(0x81),表示这是一个IN方向的端点,端点号为1
    • attributes: 2
      • 端点属性为2,表示这是一个批量传输端点
    • max_packet_size: 1024
      • 端点的最大包大小为1024字节
    • interval: 0
      • 轮询间隔为0,表示不适用于批量传输端点
  2. 第二个端点描述符
    • len: 7
      • 描述符长度为7字节
    • descriptor_type: 5
      • 描述符类型为5,表示这是一个端点描述符
    • endpoint_address: 2
      • 端点地址为2,表示这是一个OUT方向的端点,端点号为2
    • attributes:
      • 端点属性为2,表示这是一个批量传输端点
    • max_packet_size: 1024
      • 端点的最大包大小为1024字节
    • interval: 0
      • 轮询间隔为0,表示不适用于批量传输端点

根据描述符配置端点,进行通信:

ccc[ 53.770504 0 axruntime:138] Logging is enabled.
[ 53.776233 0 axruntime:139] Primary CPU 512 started, dtb = 0x1.
[ 53.783350 0 axruntime:141] Found physcial memory regions:
c[ 53.790122 0 axruntime:144]   [PA:0x90100000, PA:0x90126000) .text (READ | EXECUTE | RESERVED)
[ 53.799929 0 axruntime:144]   [PA:0x90126000, PA:0x9012d000) .rodata (READ | RESERVED)
[ 53.809043 0 axruntime:144]   [PA:0x9012d000, PA:0x90131000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED)
[ 53.820500 0 axruntime:144]   [PA:0x90131000, PA:0x90171000) boot stack (READ | WRITE | RESERVED)
[ 53.830569 0 axruntime:144]   [PA:0x90171000, PA:0x90197000) .bss (READ | WRITE | RESERVED)
[ 53.840117 0 axruntime:144]   [PA:0x0, PA:0x1000) spintable (READ | WRITE | RESERVED)
[ 53.849144 0 axruntime:144]   [PA:0x90197000, PA:0x90897000) nocache memory (READ | WRITE | DEVICE)
[ 53.859387 0 axruntime:144]   [PA:0x90897000, PA:0xff900000) free memory (READ | WRITE | FREE)
[ 53.869195 0 axruntime:144]   [PA:0x2800c000, PA:0x2800d000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 53.879524 0 axruntime:144]   [PA:0x2800d000, PA:0x2800e000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 53.889854 0 axruntime:144]   [PA:0x2800e000, PA:0x2800f000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 53.900183 0 axruntime:144]   [PA:0x2800f000, PA:0x28010000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 53.910512 0 axruntime:144]   [PA:0x30000000, PA:0x38000000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 53.920841 0 axruntime:144]   [PA:0x40000000, PA:0x80000000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 53.931170 0 axruntime:144]   [PA:0x1000000000, PA:0x3000000000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 53.941847 0 axruntime:223] Initialize global memory allocator...
[ 53.949138 0 axruntime:224]   use TLSF allocator.
[ 53.955042 0 axalloc:284] initialize global allocator at: free-[0xffff000090897000, 0xffff0000ff900000)
[ 53.965952 0 axruntime:158] Initialize kernel page table...
[ 53.972494 0 axruntime:258] Initialize global no cache memory allocator...
[ 53.980474 0 axalloc:300] initialize global allocator at: nocache-[0x90197000,0x90897000)
[ 53.989850 0 axruntime:165] Initialize platform devices...
[ 53.996531 0 axhal::platform::aarch64_common::gic:51] Initialize GICv2...
[ 54.004518 0 axtask::api:66] Initialize scheduling...
[ 54.010771 0 axtask::task:146] new task: Task(1, "idle")
[ 54.017280 0 axtask::task:146] new task: Task(3, "gc")
[ 54.023617 0 axalloc:126] expand heap memory: [0xffff0000908a9000, 0xffff0000908e9000)
[ 54.032734 0 axalloc:126] expand heap memory: [0xffff0000908e9000, 0xffff000090969000)
[ 54.041844 0 axtask::api:72]   use Round-robin scheduler.
[ 54.048437 0 axdriver:158] Initialize device drivers...
[ 54.054861 0 axdriver:159]   device model: static
[ 54.060763 0 driver_pci::phytium:18] PCIe link start @0xFFFF000040000000...
[ 54.068922 0 driver_pci::phytium:19] theroticly, since uboot had already initialized it, we need't to operate it any more!
[ 54.081161 0 axdriver::bus::pci:14] probing in pci.rs!
[ 54.087498 0 driver_pci::root_complex:96] into next!
[ 54.093661 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.100604 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.107548 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.114492 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.121436 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.128380 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.135324 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.142268 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.149212 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.156156 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.163100 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.170044 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.176988 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.183932 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.190876 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.197820 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.204764 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.211708 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.218652 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.225596 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.232540 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.239484 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.246428 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.253372 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.260316 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.267260 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.274204 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.281148 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.288092 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.295036 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.301980 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.308924 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 54.315868 0 driver_pci::root_complex:116] none!
[ 54.321684 0 axdriver:190] number of usb host controller: 0
[ 54.328454 0 axruntime:191] Initialize interrupt handlers...
[ 54.335312 0 axruntime:201] Primary CPU 512 init OK.
[ 54.341475 0:2 driver_usb::host::xhci:79] [XHCI] Base addr: VA:0xffff000031a08000
[ 54.350157 0:2 driver_usb::host::xhci:90] [XHCI] Max_slots: 16, max_ports: 2, max_irqs: 1, page size: 1
[ 54.361463 0:2 driver_usb::dma:125] allocated data:0x901b8880
[ 54.367723 0:2 driver_usb::dma:125] allocated data:0x901b9900
[ 54.374667 0:2 driver_usb::host::xhci:141] [XHCI] Reset begin
[ 54.381576 0:2 driver_usb::host::xhci:142] [XHCI] Stop
[ 54.387913 0:2 driver_usb::host::xhci:150] [XHCI] Until halt
[ 54.394770 0:2 driver_usb::host::xhci:152] [XHCI] Halted
[ 54.401279 0:2 driver_usb::host::xhci:157] [XHCI] Wait for ready...
[ 54.408744 0:2 driver_usb::host::xhci:159] [XHCI] Ready
[ 54.415169 0:2 driver_usb::host::xhci:167] [XHCI] Reset HC
[ 54.421852 0:2 driver_usb::host::xhci:181] [XHCI] XCHI reset ok
[ 54.428969 0:2 driver_usb::host::xhci:187] [XHCI] Setting enabled slots to 16.
[ 54.437389 0:2 driver_usb::host::xhci:197] [XHCI] Writing DCBAAP: 90198000
[ 54.445461 0:2 driver_usb::host::xhci:208] [XHCI] Writing CRCR: 901B8880
[ 54.453360 0:2 driver_usb::host::xhci:252] [XHCI] Disable interrupts
[ 54.460912 0:2 driver_usb::host::xhci:262] [XHCI] Writing ERSTZ
[ 54.468029 0:2 driver_usb::host::xhci:266] [XHCI] Writing ERDP: 901B9900
[ 54.475928 0:2 driver_usb::host::xhci:273] [XHCI] Writing ERSTBA: 901B98C0
[ 54.484001 0:2 driver_usb::host::xhci:284] [XHCI] Enabling primary interrupter.
[ 54.492507 0:2 driver_usb::host::xhci:500] [XHCI] Scratch buf count: 0
[ 54.500232 0:2 driver_usb::host::xhci:234] [XHCI] Start run
[ 54.507003 0:2 driver_usb::host::xhci:241] [XHCI] Is running
[ 54.513859 0:2 driver_usb::host::xhci:483] [XHCI] Test command ring
[ 54.521325 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 0
[ 54.528702 0:2 driver_usb::host::xhci::ring:59] next index
[ 54.535385 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 0
[ 54.543110 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd Noop(Noop { cycle_bit: true }) @FFFF0000901704C4
[ 54.554048 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 54.560991 0:2 driver_usb::host::xhci::ring:59] next index
[ 54.567677 0:2 driver_usb::host::xhci:337] event: PortStatusChange(PortStatusChange { completion_code: Ok(Success), port_id: 1, cycle_bit: true })
[ 54.581997 0:2 driver_usb::host::xhci::ring:59] next index
[ 54.588681 0:2 driver_usb::host::xhci:329] [XHCI] Cmd @901B8880 got result, cycle true
[ 54.597795 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 1
[ 54.605172 0:2 driver_usb::host::xhci::ring:59] next index
[ 54.611856 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 1
[ 54.619581 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd Noop(Noop { cycle_bit: true }) @FFFF0000901704C4
[ 54.630519 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 54.637462 0:2 driver_usb::host::xhci::ring:59] next index
[ 54.644146 0:2 driver_usb::host::xhci:329] [XHCI] Cmd @901B8890 got result, cycle true
[ 54.653260 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 2
[ 54.660638 0:2 driver_usb::host::xhci::ring:59] next index
[ 54.667321 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 2
[ 54.675046 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd Noop(Noop { cycle_bit: true }) @FFFF0000901704C4
[ 54.685984 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 54.692927 0:2 driver_usb::host::xhci::ring:59] next index
[ 54.699611 0:2 driver_usb::host::xhci:329] [XHCI] Cmd @901B88A0 got result, cycle true
[ 54.708725 0:2 driver_usb::host::xhci:487] [XHCI] Command ring ok
[ 54.716016 0:2 driver_usb::host::xhci:543] [XHCI] Port 0 start reset
[ 54.781410 0:2 driver_usb::host::xhci:556] [XHCI] Port 0 reset ok
[ 54.785829 0:2 driver_usb::host::xhci:543] [XHCI] Port 1 start reset
[ 54.793387 0:2 driver_usb::host::xhci:556] [XHCI] Port 1 reset ok
[ 54.800672 0:2 driver_usb::host::xhci:115] [XHCI] Init success
[ 54.807706 0:2 driver_usb::host::xhci:568] [XHCI] Port 0: Enabled: true, Connected: true, Speed 1, Power true
[ 54.818816 0:2 driver_usb::host::xhci:568] [XHCI] Port 1: Enabled: false, Connected: false, Speed 0, Power true
[ 54.830098 0:2 driver_usb::host::xhci:880] [XHCI] CMD: enable slot
[ 54.837475 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 3
[ 54.844853 0:2 driver_usb::host::xhci::ring:59] next index
[ 54.851537 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 3
[ 54.859262 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd EnableSlot(EnableSlot { slot_type: 0, cycle_bit: true }) @FFFF00009017039C
[ 54.872456 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 54.879400 0:2 driver_usb::host::xhci::ring:59] next index
[ 54.886084 0:2 driver_usb::host::xhci:337] event: PortStatusChange(PortStatusChange { completion_code: Ok(Success), port_id: 1, cycle_bit: true })
[ 54.900405 0:2 driver_usb::host::xhci::ring:59] next index
[ 54.907090 0:2 driver_usb::host::xhci:329] [XHCI] Cmd @901B88B0 got result, cycle true
[ 54.916203 0:2 driver_usb::host::xhci:885] [XHCI] Result: CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417723568, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }, slot id: 1
[ 54.937382 0:2 driver_usb::host::xhci:888] new slot!
[ 54.943546 0:2 driver_usb::dma:125] allocated data:0x901ba940
[ 54.950491 0:2 driver_usb::dma:125] allocated data:0x901baa80
[ 54.957435 0:2 driver_usb::dma:125] allocated data:0x901babc0
[ 54.964379 0:2 driver_usb::dma:125] allocated data:0x901bad00
[ 54.971323 0:2 driver_usb::dma:125] allocated data:0x901bae40
[ 54.978267 0:2 driver_usb::dma:125] allocated data:0x901baf80
[ 54.985211 0:2 driver_usb::dma:125] allocated data:0x901bb0c0
[ 54.992156 0:2 driver_usb::dma:125] allocated data:0x901bb200
[ 54.999099 0:2 driver_usb::dma:125] allocated data:0x901bb340
[ 55.006043 0:2 driver_usb::dma:125] allocated data:0x901bb480
[ 55.012987 0:2 driver_usb::dma:125] allocated data:0x901bb5c0
[ 55.019931 0:2 driver_usb::dma:125] allocated data:0x901bb700
[ 55.026875 0:2 driver_usb::dma:125] allocated data:0x901bb840
[ 55.033819 0:2 driver_usb::dma:125] allocated data:0x901bb980
[ 55.040763 0:2 driver_usb::dma:125] allocated data:0x901bbac0
[ 55.047708 0:2 driver_usb::dma:125] allocated data:0x901bbc00
[ 55.054651 0:2 driver_usb::host::xhci::context:76] new rings!
[ 55.061593 0:2 driver_usb::host::xhci::context:87] new desc container
[ 55.069233 0:2 driver_usb::host::xhci::context:93] insert complete!
[ 55.076697 0:2 driver_usb::host::xhci:586] assign complete!
[ 55.083474 0:2 driver_usb::host::xhci:844] [XHCI] CMD: address device
[ 55.091105 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 4
[ 55.098483 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.105167 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 4
[ 55.112892 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd AddressDevice(AddressDevice { input_context_pointer: 2417606656, block_set_address_request: false, slot_id: 1, cycle_bit: true }) @FFFF00009017032C
[ 55.132422 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 55.139366 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.146050 0:2 driver_usb::host::xhci:329] [XHCI] Cmd @901B88C0 got result, cycle true
[ 55.155164 0:2 driver_usb::host::xhci:853] [XHCI] Result: CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417723584, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }
[ 55.175301 0:2 driver_usb::host::xhci:588] address complete!
[ 55.182160 0:2 driver_usb::host::xhci:746] [XHCI] CMD: get endpoint0 packet size
[ 55.190753 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 0
[ 55.198129 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.204813 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 0
[ 55.212538 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 1
[ 55.219916 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.226600 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 1
[ 55.234325 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 2
[ 55.241703 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.248386 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 2
[ 55.256112 0:2 driver_usb::host::xhci:442] [XHCI] Post control transfer!
[ 55.264011 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 55.270956 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417731936, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 55.292741 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.299426 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @901BA960 got result, cycle true
[ 55.308974 0:2 driver_usb::host::xhci:753] [XHCI] Result: TransferEvent { completion_code: Ok(Success), trb_pointer: 2417731936, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 55.329458 0:2 driver_usb::host::xhci:767] [XHCI] CMD: evaluating context for set endpoint0 packet size
[ 55.340047 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 5
[ 55.347425 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.354109 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 5
[ 55.361834 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd EvaluateContext(EvaluateContext { input_context_pointer: 2417606656, slot_id: 1, cycle_bit: true }) @FFFF00009017032C
[ 55.378761 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 55.385704 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.392388 0:2 driver_usb::host::xhci:329] [XHCI] Cmd @901B88D0 got result, cycle true
[ 55.401502 0:2 driver_usb::host::xhci:773] [XHCI] Result: CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417723600, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }
[ 55.421641 0:2 driver_usb::host::xhci:590] packet size complete!
[ 55.428846 0:2 driver_usb::dma:125] allocated data:0x901bd000
[ 55.436063 0:2 driver_usb::host::xhci:716] [XHCI] Transfer Control: Fetching all configs
[ 55.445077 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 3
[ 55.452453 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.459137 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 3
[ 55.466862 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 4
[ 55.474240 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.480924 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 4
[ 55.488649 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 5
[ 55.496027 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.502710 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 5
[ 55.510436 0:2 driver_usb::host::xhci:442] [XHCI] Post control transfer!
[ 55.518335 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 55.525279 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417731984, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 55.547065 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.553750 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @901BA990 got result, cycle true
[ 55.563297 0:2 driver_usb::host::xhci:725] [XHCI] Result: TransferEvent { completion_code: Ok(Success), trb_pointer: 2417731984, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 55.583787 0:2 driver_usb::dma:125] allocated data:0x901bd000
[ 55.591001 0:2 driver_usb::host::xhci:688] [XHCI] Transfer Control: Fetching all configs
[ 55.600014 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 6
[ 55.607391 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.614075 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 6
[ 55.621800 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 7
[ 55.629178 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.635862 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 7
[ 55.643587 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 8
[ 55.650965 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.657648 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 8
[ 55.665374 0:2 driver_usb::host::xhci:442] [XHCI] Post control transfer!
[ 55.673273 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 55.680217 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417732032, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 55.702003 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.708688 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @901BA9C0 got result, cycle true
[ 55.718235 0:2 driver_usb::host::xhci:697] [XHCI] Result: TransferEvent { completion_code: Ok(Success), trb_pointer: 2417732032, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 55.738735 0:2 driver_usb::host::xhci:669] fetched descriptors:[Device(Device { len: 18, descriptor_type: 1, cd_usb: 272, class: 0, subclass: 0, protocol: 0, max_packet_size0: 8, vendor: 9354, product_id: 33639, device: 256, manufacture: 1, product: 2, serial_number: 0, num_configurations: 1 }), Configuration(Configuration { length: 9, ty: 2, total_length: 59, num_interfaces: 2, config_val: 1, config_string: 0, attributes: 160, max_power: 25 }), Interface(Interface { len: 9, descriptor_type: 4, interface_number: 0, alternate_setting: 0, num_endpoints: 1, interface_class: 3, interface_subclass: 1, interface_protocol: 2, interface: 0 }), Hid(Hid { len: 9, descriptor_type: 33, hid_bcd: 273, country_code: 33, num_descriptions: 1, report_descriptor_type: 34, report_descriptor_len: 142 }), Endpoint(Endpoint { len: 7, descriptor_type: 5, endpoint_address: 130, attributes: 3, max_packet_size: 8, interval: 4, ssc: None }), Interface(Interface { len: 9, descriptor_type: 4, interface_number: 1, alternate_setting: 0, num_endpoints: 1, interface_class: 3, interface_subclass: 1, interface_protocol: 1, interface: 0 }), Hid(Hid { len: 9, descriptor_type: 33, hid_bcd: 273, country_code: 33, num_descriptions: 1, report_descriptor_type: 34, report_descriptor_len: 59 }), Endpoint(Endpoint { len: 7, descriptor_type: 5, endpoint_address: 129, attributes: 3, max_packet_size: 8, interval: 10, ssc: None })]
[ 55.862323 0:2 driver_usb::host::xhci:592] fetch all complete!
[ 55.869355 0:2 driver_usb::host::xhci:598] set cfg!
[ 55.875433 0:2 driver_usb::host::xhci::xhci_device:84] found last entry: 0x82
[ 55.883767 0:2 driver_usb::host::xhci::xhci_device:185] set a interrupt endpoint! addr:5
[ 55.893051 0:2 driver_usb::host::xhci::xhci_device:185] set a interrupt endpoint! addr:3
[ 55.902338 0:2 driver_usb::host::xhci::xhci_device:109] [XHCI DEVICE] CMD: configure endpoint
[ 55.912060 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 6
[ 55.919437 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.926121 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 6
[ 55.933846 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd ConfigureEndpoint(ConfigureEndpoint { input_context_pointer: 2417606656, deconfigure: false, slot_id: 1, cycle_bit: true }) @FFFF0000901704C4
[ 55.952856 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 55.959799 0:2 driver_usb::host::xhci::ring:59] next index
[ 55.966483 0:2 driver_usb::host::xhci:329] [XHCI] Cmd @901B88E0 got result, cycle true
[ 55.975597 0:2 driver_usb::host::xhci::xhci_device:119] [XHCI DEVICE] CMD: result:Ok(CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417723616, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true })
[ 55.998166 0:2 driver_usb::host::xhci::xhci_device:58] try creating!
[ 56.005717 0:2 driver_usb::host::usb::drivers::driver_usb_hid:61] creating!
[ 56.013878 0:2 driver_usb::host::usb::drivers::driver_usb_hid:65] desc_device: [Device { len: 18, descriptor_type: 1, cd_usb: 272, class: 0, subclass: 0, protocol: 0, max_packet_size0: 8, vendor: 9354, product_id: 33639, device: 256, manufacture: 1, product: 2, serial_number: 0, num_configurations: 1 }]
[ 56.041914 0:2 driver_usb::host::usb::drivers::driver_usb_hid:89] interface csp:3,1,2
[ 56.050943 0:2 driver_usb::host::usb::drivers::driver_usb_hid:125] [USB-HID DRIVER]: post idle request to control endpoint
[ 56.063179 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 9
[ 56.070556 0:2 driver_usb::host::xhci::ring:59] next index
[ 56.077240 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 9
[ 56.084965 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 10
[ 56.092430 0:2 driver_usb::host::xhci::ring:59] next index
[ 56.099113 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 10
[ 56.106925 0:2 driver_usb::host::xhci:442] [XHCI] Post control transfer!
[ 56.114824 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 56.121769 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417732064, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 56.143555 0:2 driver_usb::host::xhci::ring:59] next index
[ 56.150240 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @901BA9E0 got result, cycle true
[ 56.159787 0:2 driver_usb::host::usb::drivers::driver_usb_hid:134] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417732064, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 56.683657 0:2 driver_usb::dma:125] allocated data:0x901bc180
[ 56.687738 0:2 driver_usb::host::usb::drivers::driver_usb_hid:156] [USB-HID DRIVER]: post report request
[ 56.698407 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 11
[ 56.705870 0:2 driver_usb::host::xhci::ring:59] next index
[ 56.712554 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 11
[ 56.720366 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 12
[ 56.727831 0:2 driver_usb::host::xhci::ring:59] next index
[ 56.734514 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 12
[ 56.742326 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 13
[ 56.749791 0:2 driver_usb::host::xhci::ring:59] next index
[ 56.756475 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 13
[ 56.764287 0:2 driver_usb::host::xhci:388] [XHCI] Post control transfer!
[ 56.772186 0:2 driver_usb::host::xhci:398] [XHCI] Wait result
[ 56.779129 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 56.786074 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417732112, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 56.807860 0:2 driver_usb::host::xhci::ring:59] next index
[ 56.814544 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @901BAA10 got result, cycle true
[ 56.824093 0:2 driver_usb::host::usb::drivers::driver_usb_hid:167] [USB-HID DRIVER]: result: TransferEvent { completion_code: Ok(Success), trb_pointer: 2417732112, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 56.847620 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 05 01 09 02 
[ 56.856124 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] a1 01 85 01 
[ 56.864630 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 09 01 a1 00 
[ 56.873136 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 05 09 19 01 
[ 56.881643 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 29 05 15 00 
[ 56.890149 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 25 01 95 05 
[ 56.898655 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 75 01 81 02 
[ 56.907162 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 95 01 75 03 
[ 56.915668 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 81 01 05 01 
[ 56.924175 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 09 30 09 31 
[ 56.932681 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 15 81 25 7f 
[ 56.941187 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 75 08 95 02 
[ 56.949694 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 81 06 09 38 
[ 56.958200 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 15 81 25 7f 
[ 56.966707 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 75 08 95 01 
[ 56.975213 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 81 06 c0 c0 
[ 56.983719 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 05 0c 09 01 
[ 56.992226 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] a1 01 85 03 
[ 57.000732 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 75 10 95 02 
[ 57.009239 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 15 01 26 8c 
[ 57.017745 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 02 19 01 2a 
[ 57.026252 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 8c 02 81 00 
[ 57.034758 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] c0 05 01 09 
[ 57.043264 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 80 a1 01 85 
[ 57.051771 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 04 75 02 95 
[ 57.060277 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 01 15 01 25 
[ 57.068783 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 03 09 82 09 
[ 57.077290 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 81 09 83 81 
[ 57.085796 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 60 75 06 81 
[ 57.094303 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 03 c0 05 01 
[ 57.102809 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 09 00 a1 01 
[ 57.111316 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 85 05 06 00 
[ 57.119822 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] ff 09 01 15 
[ 57.128328 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 81 25 7f 75 
[ 57.136835 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 08 95 07 b1 
[ 57.145340 0:2 driver_usb::host::usb::drivers::driver_usb_hid:254] 02 c0 
[ 57.653328 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 57.657400 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 57.669119 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 0
[ 57.676496 0:2 driver_usb::host::xhci::ring:59] next index
[ 57.683180 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 0
[ 57.690906 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 57.701755 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 57.708699 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 57.731093 0:2 driver_usb::host::xhci::ring:59] next index
[ 57.737777 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 57.751718 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 57.773327 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 58.281835 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 58.285907 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 58.297626 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 1
[ 58.305003 0:2 driver_usb::host::xhci::ring:59] next index
[ 58.311686 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 1
[ 58.319412 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 58.330262 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 58.337206 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 58.359600 0:2 driver_usb::host::xhci::ring:59] next index
[ 58.366285 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 58.380224 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 58.401833 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 58.910339 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 58.914411 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 58.926130 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 2
[ 58.933507 0:2 driver_usb::host::xhci::ring:59] next index
[ 58.940191 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 2
[ 58.947916 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 58.958766 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 58.965710 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 58.988104 0:2 driver_usb::host::xhci::ring:59] next index
[ 58.994789 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 59.008728 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 59.030337 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 59.538843 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 59.542915 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 59.554634 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 3
[ 59.562011 0:2 driver_usb::host::xhci::ring:59] next index
[ 59.568695 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 3
[ 59.576420 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 59.587270 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 59.594214 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 59.616608 0:2 driver_usb::host::xhci::ring:59] next index
[ 59.623293 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 59.637233 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 59.658841 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 60.167347 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 60.171419 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 60.183138 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 4
[ 60.190515 0:2 driver_usb::host::xhci::ring:59] next index
[ 60.197199 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 4
[ 60.204924 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 60.215775 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 60.222719 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 60.245113 0:2 driver_usb::host::xhci::ring:59] next index
[ 60.251797 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 60.265737 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 60.287345 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 60.795851 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 60.799924 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 60.811642 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 5
[ 60.819019 0:2 driver_usb::host::xhci::ring:59] next index
[ 60.825703 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 5
[ 60.833428 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 60.844279 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 60.851223 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 60.873617 0:2 driver_usb::host::xhci::ring:59] next index
[ 60.880301 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 60.894241 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 60.915850 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 61.424356 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 61.428428 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 61.440146 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 6
[ 61.447524 0:2 driver_usb::host::xhci::ring:59] next index
[ 61.454207 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 6
[ 61.461932 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 61.472783 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 61.479727 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 61.502121 0:2 driver_usb::host::xhci::ring:59] next index
[ 61.508805 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 61.522745 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 61.544354 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 62.052860 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 62.056932 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 62.068650 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 7
[ 62.076028 0:2 driver_usb::host::xhci::ring:59] next index
[ 62.082711 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 7
[ 62.090437 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 62.101287 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 62.108231 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 62.130625 0:2 driver_usb::host::xhci::ring:59] next index
[ 62.137309 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 62.151249 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 62.172858 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 62.681364 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 62.685436 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 62.697155 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 8
[ 62.704532 0:2 driver_usb::host::xhci::ring:59] next index
[ 62.711216 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 8
[ 62.718941 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 62.729791 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 62.736735 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 62.759129 0:2 driver_usb::host::xhci::ring:59] next index
[ 62.765813 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 62.779753 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 62.801362 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 63.309868 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 63.313940 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 63.325659 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 9
[ 63.333036 0:2 driver_usb::host::xhci::ring:59] next index
[ 63.339720 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 9
[ 63.347445 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 63.358295 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 63.365239 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 63.387633 0:2 driver_usb::host::xhci::ring:59] next index
[ 63.394318 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 63.408258 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 63.429866 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 63.938372 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 63.942444 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 63.954163 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 10
[ 63.961627 0:2 driver_usb::host::xhci::ring:59] next index
[ 63.968311 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 10
[ 63.976123 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 63.986973 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 63.993917 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 64.016311 0:2 driver_usb::host::xhci::ring:59] next index
[ 64.022995 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 64.036935 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 64.058544 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 64.567050 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 64.571122 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 64.582841 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 11
[ 64.590305 0:2 driver_usb::host::xhci::ring:59] next index
[ 64.596988 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 11
[ 64.604800 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 64.615651 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 64.622595 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 64.644989 0:2 driver_usb::host::xhci::ring:59] next index
[ 64.651673 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 64.665613 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 64.687222 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 65.195728 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 65.199800 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 65.211519 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 12
[ 65.218983 0:2 driver_usb::host::xhci::ring:59] next index
[ 65.225666 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 12
[ 65.233478 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 65.244329 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 65.251273 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 65.273667 0:2 driver_usb::host::xhci::ring:59] next index
[ 65.280351 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 65.294291 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 65.315899 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 65.824405 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 65.828477 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 65.840196 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 13
[ 65.847660 0:2 driver_usb::host::xhci::ring:59] next index
[ 65.854344 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 13
[ 65.862156 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 65.873006 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 65.879951 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 65.902344 0:2 driver_usb::host::xhci::ring:59] next index
[ 65.909029 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 65.922969 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 65.944577 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00 
[ 66.453083 0:2 driver_usb::dma:125] allocated data:0x901bc160
[ 66.457155 0:2 driver_usb::host::usb::drivers::driver_usb_hid:185] [USB-HID DRIVER]: post IN Transfer report request
[ 66.468874 0:2 driver_usb::host::xhci::ring:46] enqueue trb into 14
[ 66.476338 0:2 driver_usb::host::xhci::ring:59] next index
[ 66.483022 0:2 driver_usb::host::xhci::ring:49] enqueued,next index: 14
[ 66.490834 0:2 driver_usb::host::usb::drivers::driver_usb_hid:222] [USB-HID DRIVER] Post control transfer!
[ 66.501684 0:2 driver_usb::host::xhci:456] [XHCI] Wait result
[ 66.508628 0:2 driver_usb::host::xhci:462] received temp!:TransferEvent(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 66.531022 0:2 driver_usb::host::xhci::ring:59] next index
[ 66.537706 0:2 driver_usb::host::xhci:467] [XHCI] Transfer @0 got result, cycle true
[ 66.551646 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(EndpointNotEnabledError), trb_pointer: 0, trb_transfer_length: 0, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 66.573255 0:2 driver_usb::host::usb::drivers::driver_usb_hid:249] 00 00 00 00

配置端点返回值已由ParameterError变为Success,但是后续的发送传输请求,设备返回值依然为EndpointNotEnabledError

根据Linux打印的一些信息,发现是端点配置中传入的一些信息问题,现在已修复,端点成功启用:

 

Phytium-Pi#go 0x90100000
## Starting application at 0x90100000 ...
aaaaaaaaaaaacarch = aarch64
platform = aarch64-phytium-pi
target = aarch64-unknown-none-softfloat
smp = 1
build_mode = release
log_level = debug

ccc[ 39.153072 0 axruntime:138] Logging is enabled.
[ 39.158801 0 axruntime:139] Primary CPU 512 started, dtb = 0x1.
[ 39.165918 0 axruntime:141] Found physcial memory regions:
c[ 39.172689 0 axruntime:144]   [PA:0x90100000, PA:0x90126000) .text (READ | EXECUTE | RESERVED)
[ 39.182497 0 axruntime:144]   [PA:0x90126000, PA:0x9012e000) .rodata (READ | RESERVED)
[ 39.191611 0 axruntime:144]   [PA:0x9012e000, PA:0x90132000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED)
[ 39.203068 0 axruntime:144]   [PA:0x90132000, PA:0x90172000) boot stack (READ | WRITE | RESERVED)
[ 39.213137 0 axruntime:144]   [PA:0x90172000, PA:0x90198000) .bss (READ | WRITE | RESERVED)
[ 39.222685 0 axruntime:144]   [PA:0x0, PA:0x1000) spintable (READ | WRITE | RESERVED)
[ 39.231713 0 axruntime:144]   [PA:0x90198000, PA:0x90898000) nocache memory (READ | WRITE | DEVICE)
[ 39.241955 0 axruntime:144]   [PA:0x90898000, PA:0xff900000) free memory (READ | WRITE | FREE)
[ 39.251763 0 axruntime:144]   [PA:0x2800c000, PA:0x2800d000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 39.262093 0 axruntime:144]   [PA:0x2800d000, PA:0x2800e000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 39.272422 0 axruntime:144]   [PA:0x2800e000, PA:0x2800f000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 39.282751 0 axruntime:144]   [PA:0x2800f000, PA:0x28010000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 39.293080 0 axruntime:144]   [PA:0x30000000, PA:0x38000000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 39.303409 0 axruntime:144]   [PA:0x40000000, PA:0x80000000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 39.313739 0 axruntime:144]   [PA:0x1000000000, PA:0x3000000000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 39.324415 0 axruntime:223] Initialize global memory allocator...
[ 39.331706 0 axruntime:224]   use TLSF allocator.
[ 39.337611 0 axalloc:284] initialize global allocator at: free-[0xffff000090898000, 0xffff0000ff900000)
[ 39.348522 0 axruntime:158] Initialize kernel page table...
[ 39.355060 0 axruntime:258] Initialize global no cache memory allocator...
[ 39.363042 0 axalloc:300] initialize global allocator at: nocache-[0x90198000,0x90898000)
[ 39.372418 0 axruntime:165] Initialize platform devices...
[ 39.379099 0 axhal::platform::aarch64_common::gic:51] Initialize GICv2...
[ 39.387085 0 axtask::api:66] Initialize scheduling...
[ 39.393338 0 axtask::task:146] new task: Task(1, "idle")
[ 39.399848 0 axtask::task:146] new task: Task(3, "gc")
[ 39.406185 0 axalloc:126] expand heap memory: [0xffff0000908aa000, 0xffff0000908ea000)
[ 39.415302 0 axalloc:126] expand heap memory: [0xffff0000908ea000, 0xffff00009096a000)
[ 39.424411 0 axtask::api:72]   use Round-robin scheduler.
[ 39.431006 0 axdriver:158] Initialize device drivers...
[ 39.437429 0 axdriver:159]   device model: static
[ 39.443331 0 driver_pci::phytium:18] PCIe link start @0xFFFF000040000000...
[ 39.451490 0 driver_pci::phytium:19] theroticly, since uboot had already initialized it, we need't to operate it any more!
[ 39.463729 0 axdriver::bus::pci:14] probing in pci.rs!
[ 39.470066 0 driver_pci::root_complex:96] into next!
[ 39.476229 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.483173 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.490117 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.497061 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.504005 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.510948 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.517893 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.524837 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.531781 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.538724 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.545669 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.552613 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.559556 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.566500 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.573445 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.580389 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.587332 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.594277 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.601221 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.608165 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.615108 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.622053 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.628997 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.635941 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.642884 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.649828 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.656773 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.663717 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.670660 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.677605 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.684549 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.691493 0 driver_pci::root_complex:139] vid FFFF, did FFFF
[ 39.698436 0 driver_pci::root_complex:116] none!
[ 39.704252 0 axdriver:190] number of usb host controller: 0
[ 39.711022 0 axruntime:191] Initialize interrupt handlers...
[ 39.717880 0 axruntime:201] Primary CPU 512 init OK.
[ 39.724043 0:2 driver_usb::host::xhci:80] [XHCI] Base addr: VA:0xffff000031a08000
[ 39.732725 0:2 driver_usb::host::xhci:91] [XHCI] Max_slots: 16, max_ports: 2, max_irqs: 1, page size: 1
[ 39.744031 0:2 driver_usb::dma:125] allocated data:0x901b9880
[ 39.750291 0:2 driver_usb::dma:125] allocated data:0x901ba900
[ 39.757235 0:2 driver_usb::host::xhci:142] [XHCI] Reset begin
[ 39.764144 0:2 driver_usb::host::xhci:143] [XHCI] Stop
[ 39.770481 0:2 driver_usb::host::xhci:151] [XHCI] Until halt
[ 39.777338 0:2 driver_usb::host::xhci:153] [XHCI] Halted
[ 39.783848 0:2 driver_usb::host::xhci:158] [XHCI] Wait for ready...
[ 39.791313 0:2 driver_usb::host::xhci:160] [XHCI] Ready
[ 39.797737 0:2 driver_usb::host::xhci:168] [XHCI] Reset HC
[ 39.804420 0:2 driver_usb::host::xhci:182] [XHCI] XCHI reset ok
[ 39.811537 0:2 driver_usb::host::xhci:188] [XHCI] Setting enabled slots to 16.
[ 39.819957 0:2 driver_usb::host::xhci:198] [XHCI] Writing DCBAAP: 90199000
[ 39.828030 0:2 driver_usb::host::xhci:209] [XHCI] Writing CRCR: 901B9880
[ 39.835929 0:2 driver_usb::host::xhci:253] [XHCI] Disable interrupts
[ 39.843480 0:2 driver_usb::host::xhci:263] [XHCI] Writing ERSTZ
[ 39.850597 0:2 driver_usb::host::xhci:267] [XHCI] Writing ERDP: 901BA900
[ 39.858496 0:2 driver_usb::host::xhci:274] [XHCI] Writing ERSTBA: 901BA8C0
[ 39.866569 0:2 driver_usb::host::xhci:285] [XHCI] Enabling primary interrupter.
[ 39.875075 0:2 driver_usb::host::xhci:508] [XHCI] Scratch buf count: 0
[ 39.882800 0:2 driver_usb::host::xhci:235] [XHCI] Start run
[ 39.889571 0:2 driver_usb::host::xhci:242] [XHCI] Is running
[ 39.896428 0:2 driver_usb::host::xhci:491] [XHCI] Test command ring
[ 39.903893 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [0, 0, 0, 23553]
[ 39.912225 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd Noop(Noop { cycle_bit: true }) @901B9880
[ 39.922468 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 39.929413 0:2 driver_usb::host::xhci:345] event: PortStatusChange(PortStatusChange { completion_code: Ok(Success), port_id: 1, cycle_bit: true })
[ 39.943734 0:2 driver_usb::host::xhci:335] [XHCI] Cmd @901B9880 got result, cycle true
[ 39.952847 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [0, 0, 0, 23553]
[ 39.961180 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd Noop(Noop { cycle_bit: true }) @901B9890
[ 39.971423 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 39.978367 0:2 driver_usb::host::xhci:335] [XHCI] Cmd @901B9890 got result, cycle true
[ 39.987480 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [0, 0, 0, 23553]
[ 39.995813 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd Noop(Noop { cycle_bit: true }) @901B98A0
[ 40.006056 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 40.013000 0:2 driver_usb::host::xhci:335] [XHCI] Cmd @901B98A0 got result, cycle true
[ 40.022114 0:2 driver_usb::host::xhci:495] [XHCI] Command ring ok
[ 40.029405 0:2 driver_usb::host::xhci:551] [XHCI] Port 0 start reset
[ 40.094799 0:2 driver_usb::host::xhci:564] [XHCI] Port 0 reset ok
[ 40.099219 0:2 driver_usb::host::xhci:551] [XHCI] Port 1 start reset
[ 40.106776 0:2 driver_usb::host::xhci:564] [XHCI] Port 1 reset ok
[ 40.114062 0:2 driver_usb::host::xhci:116] [XHCI] Init success
[ 40.421095 0:2 driver_usb::host::xhci:576] [XHCI] Port 0: Enabled: true, Connected: true, Speed 2, Power true
[ 40.429336 0:2 driver_usb::host::xhci:576] [XHCI] Port 1: Enabled: false, Connected: false, Speed 0, Power true
[ 40.440618 0:2 driver_usb::host::xhci:896] [XHCI] CMD: enable slot
[ 40.447995 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [0, 0, 0, 9217]
[ 40.456241 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd EnableSlot(EnableSlot { slot_type: 0, cycle_bit: true }) @901B98B0
[ 40.468741 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 40.475685 0:2 driver_usb::host::xhci:345] event: PortStatusChange(PortStatusChange { completion_code: Ok(Success), port_id: 1, cycle_bit: true })
[ 40.490007 0:2 driver_usb::host::xhci:335] [XHCI] Cmd @901B98B0 got result, cycle true
[ 40.499121 0:2 driver_usb::host::xhci:901] [XHCI] Result: CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417727664, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }, slot id: 1
[ 40.520300 0:2 driver_usb::host::xhci:904] new slot!
[ 40.526463 0:2 driver_usb::dma:125] allocated data:0x901bb940
[ 40.533411 0:2 driver_usb::dma:125] allocated data:0x901bbb80
[ 40.540355 0:2 driver_usb::dma:125] allocated data:0x901bbdc0
[ 40.547299 0:2 driver_usb::dma:125] allocated data:0x901bc000
[ 40.554243 0:2 driver_usb::dma:125] allocated data:0x901bc240
[ 40.561187 0:2 driver_usb::dma:125] allocated data:0x901bc480
[ 40.568131 0:2 driver_usb::dma:125] allocated data:0x901bc6c0
[ 40.575075 0:2 driver_usb::dma:125] allocated data:0x901bc900
[ 40.582019 0:2 driver_usb::dma:125] allocated data:0x901bcb40
[ 40.588963 0:2 driver_usb::dma:125] allocated data:0x901bcd80
[ 40.595907 0:2 driver_usb::dma:125] allocated data:0x901bcfc0
[ 40.602851 0:2 driver_usb::dma:125] allocated data:0x901bd200
[ 40.609795 0:2 driver_usb::dma:125] allocated data:0x901bd440
[ 40.616739 0:2 driver_usb::dma:125] allocated data:0x901bd680
[ 40.623683 0:2 driver_usb::dma:125] allocated data:0x901bd8c0
[ 40.630627 0:2 driver_usb::dma:125] allocated data:0x901bdb00
[ 40.637571 0:2 driver_usb::host::xhci::context:76] new rings!
[ 40.644511 0:2 driver_usb::host::xhci::context:87] new desc container
[ 40.652150 0:2 driver_usb::host::xhci::context:93] insert complete!
[ 40.659614 0:2 driver_usb::host::xhci:594] assign complete!
[ 40.666391 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [2417602560, 0, 0, 16788481]
[ 40.675759 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd AddressDevice(AddressDevice { input_context_pointer: 2417602560, block_set_address_request: false, slot_id: 1, cycle_bit: true }) @901B98C0
[ 40.694595 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 40.701539 0:2 driver_usb::host::xhci:335] [XHCI] Cmd @901B98C0 got result, cycle true
[ 40.710652 0:2 driver_usb::host::xhci:869] address [1] ok
[ 40.717249 0:2 driver_usb::host::xhci:596] address complete!
[ 40.724109 0:2 driver_usb::host::xhci:764] [XHCI] CMD: get endpoint0 packet size
[ 40.732701 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [16778880, 1179648, 8, 198721]
[ 40.742247 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [2417750016, 0, 18, 68609]
[ 40.751448 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [0, 0, 0, 4129]
[ 40.759695 0:2 driver_usb::host::xhci:450] [XHCI] Post control transfer!
[ 40.767594 0:2 driver_usb::host::xhci:464] [XHCI] Wait result
[ 40.774538 0:2 driver_usb::host::xhci:470] received temp!:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417736032, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 40.796325 0:2 driver_usb::host::xhci:475] [XHCI] Transfer @901BB960 got result, cycle true
[ 40.805873 0:2 driver_usb::host::xhci:771] [XHCI] Result: TransferEvent { completion_code: Ok(Success), trb_pointer: 2417736032, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 40.826357 0:2 driver_usb::host::xhci:785] [XHCI] CMD: evaluating context for set endpoint0 packet size 8
[ 40.837120 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [2417602560, 0, 0, 16790529]
[ 40.846494 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd EvaluateContext(EvaluateContext { input_context_pointer: 2417602560, slot_id: 1, cycle_bit: true }) @901B98D0
[ 40.862726 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 40.869671 0:2 driver_usb::host::xhci:335] [XHCI] Cmd @901B98D0 got result, cycle true
[ 40.878784 0:2 driver_usb::host::xhci:794] [XHCI] Result: CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417727696, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }
[ 40.898923 0:2 driver_usb::host::xhci:598] packet size complete!
[ 40.906128 0:2 driver_usb::dma:125] allocated data:0x901bf000
[ 40.913345 0:2 driver_usb::host::xhci:734] [XHCI] Transfer Control: Fetching device desc
[ 40.922359 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [16778880, 268435456, 8, 198721]
[ 40.932079 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [2417750016, 0, 4096, 68609]
[ 40.941453 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [0, 0, 0, 4129]
[ 40.949700 0:2 driver_usb::host::xhci:450] [XHCI] Post control transfer!
[ 40.957599 0:2 driver_usb::host::xhci:464] [XHCI] Wait result
[ 40.964543 0:2 driver_usb::host::xhci:470] received temp!:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417736080, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 40.986330 0:2 driver_usb::host::xhci:475] [XHCI] Transfer @901BB990 got result, cycle true
[ 40.995878 0:2 driver_usb::host::xhci:743] [XHCI] Result: TransferEvent { completion_code: Ok(Success), trb_pointer: 2417736080, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 41.016367 0:2 driver_usb::dma:125] allocated data:0x901bf000
[ 41.023581 0:2 driver_usb::host::xhci:706] [XHCI] Transfer Control: Fetching config desc
[ 41.032595 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [33556096, 268435456, 8, 198721]
[ 41.042315 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [2417750016, 0, 4096, 68609]
[ 41.051689 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [0, 0, 0, 4129]
[ 41.059936 0:2 driver_usb::host::xhci:450] [XHCI] Post control transfer!
[ 41.067835 0:2 driver_usb::host::xhci:464] [XHCI] Wait result
[ 41.074779 0:2 driver_usb::host::xhci:470] received temp!:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417736128, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 41.096566 0:2 driver_usb::host::xhci:475] [XHCI] Transfer @901BB9C0 got result, cycle true
[ 41.106113 0:2 driver_usb::host::xhci:715] [XHCI] Result: TransferEvent { completion_code: Ok(Success), trb_pointer: 2417736128, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 41.126607 0:2 driver_usb::host::xhci:687] fetched descriptors:[
    Device(
        Device {
            len: 18,
            descriptor_type: 1,
            cd_usb: 272,
            class: 0,
            subclass: 0,
            protocol: 0,
            max_packet_size0: 8,
            vendor: 6127,
            product_id: 24717,
            device: 9304,
            manufacture: 1,
            product: 2,
            serial_number: 0,
            num_configurations: 1,
        },
    ),
    Configuration(
        Configuration {
            length: 9,
            ty: 2,
            total_length: 34,
            num_interfaces: 1,
            config_val: 1,
            config_string: 0,
            attributes: 160,
            max_power: 50,
        },
    ),
    Interface(
        Interface {
            len: 9,
            descriptor_type: 4,
            interface_number: 0,
            alternate_setting: 0,
            num_endpoints: 1,
            interface_class: 3,
            interface_subclass: 1,
            interface_protocol: 2,
            interface: 0,
        },
    ),
    Hid(
        Hid {
            len: 9,
            descriptor_type: 33,
            hid_bcd: 273,
            country_code: 0,
            num_descriptions: 1,
            report_descriptor_type: 34,
            report_descriptor_len: 62,
        },
    ),
    Endpoint(
        Endpoint {
            len: 7,
            descriptor_type: 5,
            endpoint_address: 129,
            attributes: 3,
            max_packet_size: 4,
            interval: 10,
            ssc: None,
        },
    ),
]
[ 41.273724 0:2 driver_usb::host::xhci:600] fetch all complete!
[ 41.280756 0:2 driver_usb::host::xhci:606] set cfg!
[ 41.286833 0:2 driver_usb::host::xhci::xhci_device:88] found last entry: 0x81
[ 41.295167 0:2 driver_usb::host::xhci::xhci_device:238] set a interrupt endpoint! addr:3
[ 41.304452 0:2 driver_usb::host::xhci::xhci_device:118] [XHCI DEVICE] CMD: configure endpoint
[ 41.314173 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [2417602560, 0, 0, 16789505]
[ 41.323547 0:2 driver_usb::host::xhci:308] [XHCI] Post cmd ConfigureEndpoint(ConfigureEndpoint { input_context_pointer: 2417602560, deconfigure: false, slot_id: 1, cycle_bit: true }) @901B98E0
[ 41.341863 0:2 driver_usb::host::xhci:320] [XHCI] Wait result
[ 41.348807 0:2 driver_usb::host::xhci:335] [XHCI] Cmd @901B98E0 got result, cycle true
[ 41.357920 0:2 driver_usb::host::xhci::xhci_device:128] [XHCI DEVICE] CMD: result:CommandCompletion { completion_code: Ok(Success), command_trb_pointer: 2417727712, command_completion_parameter: 0, vf_id: 0, slot_id: 1, cycle_bit: true }
[ 41.380142 0:2 driver_usb::host::xhci::xhci_device:59] try creating!
[ 41.387692 0:2 driver_usb::host::usb::drivers::driver_usb_hid:80] creating!
[ 41.395853 0:2 driver_usb::host::usb::drivers::driver_usb_hid:84] desc_device: [Device { len: 18, descriptor_type: 1, cd_usb: 272, class: 0, subclass: 0, protocol: 0, max_packet_size0: 8, vendor: 6127, product_id: 24717, device: 9304, manufacture: 1, product: 2, serial_number: 0, num_configurations: 1 }]
[ 41.423976 0:2 driver_usb::host::usb::drivers::driver_usb_hid:108] interface csp:3,1,2
[ 41.433090 0:2 driver_usb::host::usb::drivers::driver_usb_hid:134] ###driver usbhid working!###
[ 41.442984 0:2 driver_usb::host::usb::drivers::driver_usb_hid:60] dumped output context at slot 1:
 Device {
    slot: Slot {
        route_string: 0,
        speed: 2,
        multi_tt: false,
        hub: false,
        context_entries: 3,
        max_exit_latency: 0,
        root_hub_port_number: 1,
        number_of_ports: 0,
        parent_hub_slot_id: 0,
        parent_port_number: 0,
        tt_think_time: 0,
        interrupter_target: 0,
        usb_device_address: 1,
        slot_state: Configured,
    },
    endpoints: [
        Endpoint {
            endpoint_state: Running,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 3,
            endpoint_type: Control,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 8,
            dequeue_cycle_state: true,
            tr_dequeue_pointer: 2417736145,
            average_trb_length: 8,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Running,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 3,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 3,
            endpoint_type: InterruptIn,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 4,
            dequeue_cycle_state: true,
            tr_dequeue_pointer: 2417737729,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 4,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
    ],
}
[ 43.147304 0:2 driver_usb::host::usb::drivers::driver_usb_hid:151] [USB-HID DRIVER]: post idle request to control endpoint
[ 43.159542 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [2593, 0, 8, 2113]
[ 43.168047 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [0, 0, 0, 4129]
[ 43.176293 0:2 driver_usb::host::xhci:450] [XHCI] Post control transfer!
[ 43.184193 0:2 driver_usb::host::xhci:464] [XHCI] Wait result
[ 43.191136 0:2 driver_usb::host::xhci:470] received temp!:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417736160, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 43.212923 0:2 driver_usb::host::xhci:475] [XHCI] Transfer @901BB9E0 got result, cycle true
[ 43.222471 0:2 driver_usb::host::usb::drivers::driver_usb_hid:160] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417736160, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 43.246341 0:2 driver_usb::host::usb::drivers::driver_usb_hid:176] [USB-HID DRIVER]: post set protocol request
[ 43.257539 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [68385, 0, 8, 2113]
[ 43.266131 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [0, 0, 0, 4129]
[ 43.274377 0:2 driver_usb::host::xhci:450] [XHCI] Post control transfer!
[ 43.282276 0:2 driver_usb::host::xhci:464] [XHCI] Wait result
[ 43.289220 0:2 driver_usb::host::xhci:470] received temp!:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417736192, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 43.311007 0:2 driver_usb::host::xhci:475] [XHCI] Transfer @901BBA00 got result, cycle true
[ 43.320555 0:2 driver_usb::host::usb::drivers::driver_usb_hid:187] [USB-HID DRIVER]: result: TransferEvent { completion_code: Ok(Success), trb_pointer: 2417736192, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 43.844078 0:2 driver_usb::dma:125] allocated data:0x901be180
[ 43.848154 0:2 driver_usb::host::usb::drivers::driver_usb_hid:210] [USB-HID DRIVER]: post report request
[ 43.858828 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [570427009, 4063232, 8, 198721]
[ 43.868461 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [2417746304, 0, 62, 68609]
[ 43.877662 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [0, 0, 0, 4129]
[ 43.885909 0:2 driver_usb::host::xhci:396] [XHCI] Post control transfer!
[ 43.893807 0:2 driver_usb::host::xhci:406] [XHCI] Wait result
[ 43.900751 0:2 driver_usb::host::xhci:464] [XHCI] Wait result
[ 43.907696 0:2 driver_usb::host::xhci:470] received temp!:TransferEvent(TransferEvent { completion_code: Ok(Success), trb_pointer: 2417736240, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true })
[ 43.929483 0:2 driver_usb::host::xhci:475] [XHCI] Transfer @901BBA30 got result, cycle true
[ 43.939030 0:2 driver_usb::host::usb::drivers::driver_usb_hid:221] [USB-HID DRIVER]: result: TransferEvent { completion_code: Ok(Success), trb_pointer: 2417736240, trb_transfer_length: 0, event_data: false, endpoint_id: 1, slot_id: 1, cycle_bit: true }
[ 43.962558 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 05 01 09 02 
[ 43.971061 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] a1 01 09 01 
[ 43.979568 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] a1 00 05 09 
[ 43.988074 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 19 01 29 03 
[ 43.996580 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 15 00 25 01 
[ 44.005087 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 95 03 75 01 
[ 44.013593 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 81 02 95 05 
[ 44.022100 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 75 01 81 03 
[ 44.030606 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 05 01 09 30 
[ 44.039112 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 09 31 15 81 
[ 44.047619 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 25 7f 75 08 
[ 44.056125 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 95 02 81 06 
[ 44.064632 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 09 38 15 81 
[ 44.073138 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 25 7f 75 08 
[ 44.081644 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 95 01 81 06 
[ 44.090150 0:2 driver_usb::host::usb::drivers::driver_usb_hid:299] c0 c0 
[ 45.098137 0:2 driver_usb::dma:125] allocated data:0x901be160
[ 45.102209 0:2 driver_usb::host::usb::drivers::driver_usb_hid:236] [USB-HID DRIVER]: post IN Transfer report request
[ 45.113928 0:2 driver_usb::host::xhci::ring:48] enqueue trb: [2417746272, 0, 4, 1061]
[ 45.122954 0:2 driver_usb::host::usb::drivers::driver_usb_hid:267] [USB-HID DRIVER] Post control transfer! at slot_id:1,dci:3
[ 45.135454 0:2 driver_usb::host::xhci:464] [XHCI] Wait result
[ 45.142398 0:2 driver_usb::host::xhci:470] received temp!:TransferEvent(TransferEvent { completion_code: Ok(UsbTransactionError), trb_pointer: 2417737728, trb_transfer_length: 4, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 45.165226 0:2 driver_usb::host::xhci:475] [XHCI] Transfer @901BC000 got result, cycle true
[ 45.174774 0:2 driver_usb::host::usb::drivers::driver_usb_hid:281] [USB-HID DRIVER]: result: Ok(TransferEvent { completion_code: Ok(UsbTransactionError), trb_pointer: 2417737728, trb_transfer_length: 4, event_data: false, endpoint_id: 3, slot_id: 1, cycle_bit: true })
[ 45.199688 0:2 driver_usb::host::usb::drivers::driver_usb_hid:294] 00 00 00 00 
[ 45.208249 0:2 axtask::run_queue:86] task exit: Task(2, "main"), exit_code=0
[ 45.216439 0:2 axhal::platform::aarch64_phytium_pi::misc:22] Shutting down...

端点启用后,发送中断传输请求,但是出现了传输错误UsbTransactionError

实验一:飞腾派 Uboot 启动 USB

在飞腾派Uboot界面,输入usb start后可以看到如下输出:

starting USB...
Bus usb3@31a00000: Register 2000110 NbrPorts 2
Starting the controller
USB XHCI 1.10
Bus usb3@31a20000: Register 2000110 NbrPorts 2
Starting the controller
USB XHCI 1.10
scanning bus usb3@31a00000 for devices... 1 USB Device(s) found
scanning bus usb3@31a20000 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found

发现USB控制器初始化成功,端口也完成注册,同时扫描两个USB控制器,发现两个USB设备

输入usb tree也可以看到:

Phytium-Pi#usb tree
USB device tree:
  1  Hub (5 Gb/s, 0mA)
     U-Boot XHCI Host Controller

  1  Hub (5 Gb/s, 0mA)
     U-Boot XHCI Host Controller

尝试插入USB设备如内存卡(注意Uboot只初始化了一个端口(上方的蓝色端口),其余端口无法通信),由于Uboot不支持动态加载,所以我们需要usb reset,重新启动USB,可以看到,可以检测出一个存储设备:

Phytium-Pi#usb reset
resetting USB...
Bus usb3@31a00000: Register 2000110 NbrPorts 2
Starting the controller
USB XHCI 1.10
Bus usb3@31a20000: Register 2000110 NbrPorts 2
Starting the controller
USB XHCI 1.10
scanning bus usb3@31a00000 for devices... 2 USB Device(s) found
scanning bus usb3@31a20000 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 1 Storage Device(s) found

Phytium-Pi#usb tree
USB device tree:
  1  Hub (5 Gb/s, 0mA)
  |  U-Boot XHCI Host Controller
  |
  +-2  Mass Storage (5 Gb/s, 124mA)
       Prolific Technology Inc. USB SD Card Reader      ABCDEF0123456789AB

  1  Hub (5 Gb/s, 0mA)
     U-Boot XHCI Host Controller

再尝试插入其它的USB设备,同样可以检测到:

Phytium-Pi#usb reset
resetting USB...
Bus usb3@31a00000: Register 2000110 NbrPorts 2
Starting the controller
USB XHCI 1.10
Bus usb3@31a20000: Register 2000110 NbrPorts 2
Starting the controller
USB XHCI 1.10
scanning bus usb3@31a00000 for devices... 2 USB Device(s) found
scanning bus usb3@31a20000 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
Phytium-Pi#usb tree
USB device tree:
  1  Hub (5 Gb/s, 0mA)
  |  U-Boot XHCI Host Controller
  |
  +-2  Human Interface (12 Mb/s, 100mA)
       Keychron Keychron C1   //  键盘

  1  Hub (5 Gb/s, 0mA)
     U-Boot XHCI Host Controller
Phytium-Pi#usb reset
resetting USB...
Bus usb3@31a00000: Register 2000110 NbrPorts 2
Starting the controller
USB XHCI 1.10
Bus usb3@31a20000: Register 2000110 NbrPorts 2
Starting the controller
USB XHCI 1.10
scanning bus usb3@31a00000 for devices... 2 USB Device(s) found
scanning bus usb3@31a20000 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
Phytium-Pi#usb tree
USB device tree:
  1  Hub (5 Gb/s, 0mA)
  |  U-Boot XHCI Host Controller
  |
  +-2   (480 Mb/s, 500mA)
       EMEET HD Webcam eMeet C950 SN0001   //  摄像头

  1  Hub (5 Gb/s, 0mA)
     U-Boot XHCI Host Controller

实验二:xhci 控制器初始化,接管控制权

USB 初始化

通过Uboot启动ArceOS时,我们已经发现飞腾派的USB接口已经可以识别出我们插入的USB存储设备,并能从存储设备中读取下载ArceOS启动镜像。这是由于在Uboot引导阶段,关于USB主机控制器已经被初始化成功,并且会加载相应的一些驱动程序:USB 控制器驱动程序、USB 存储设备驱动程序等。所以关于主机控制器的初始化工作,我们可以暂时跳过,直接用Uboot已经初始化的控制器,只需在ArceOS中接管其控制权便可以管理USB了。

接管控制权

  1. 加载ArceOS:通过SD卡等引导设备实现

  2. ArceOS初始化:内核开始初始化硬件和各种子系统。在初始化过程中,会尝试检测和配置已经初始化的 USB 控制器。

    代码地址:https://github.com/arceos-usb/arceos_experiment/tree/phytium_pi_port

    从飞腾派软件编程手册V1.0中5.4.2关于USB寄存器基地址可知,USB基地址为:0x31A0_0000

    但是,注意 XHCI 协议规范定义寄存器基地址为USB3.0寄存器基地址+0x8000,所以最终基地址为0x31A0_8000

    因此,我们在尝试注册 xhci 控制器时,传入的地址为0x31A0_8000,

    #![allow(unused)]
    fn main() {
    fn test_xhci(_args: &str) {
        driver_usb::try_init(0x31a08000 as usize)
    }
    }
    

    运行实例:

    arceos# test_xhci
    [ 31.922557 0:2 driver_usb::host::structures::registers:30] handleing!
    [ 31.927492 0:2 driver_usb::host::xhci:47] resetting xhci controller
    [ 31.934955 0:2 driver_usb::host::structures::registers:30] handleing!
    [ 31.942594 0:2 driver_usb::host::xhci:98] stop
    [ 31.948236 0:2 driver_usb::host::xhci:103] wait until halt
    [ 31.954920 0:2 driver_usb::host::xhci:105] halted
    [ 31.960822 0:2 driver_usb::host::xhci:107] HCRST!
    [ 31.966726 0:2 driver_usb::host::xhci:133] Reset xHCI Controller Globally
    [ 31.974710 0:2 driver_usb::host::structures::registers:30] handleing!
    [ 31.983446 0:2 driver_usb::host::structures::xhci_slot_manager:51] initialized!
    [ 31.990854 0:2 driver_usb::host::structures::xhci_event_manager:40] initilizating!
    [ 31.999621 0:2 driver_usb::host::structures::registers:30] handleing!
    [ 32.007293 0:2 driver_usb::host::structures::event_ring:33] created!
    [ 32.014812 0:2 driver_usb::host::structures::registers:30] handleing!
    [ 32.022450 0:2 driver_usb::host::structures::xhci_event_manager:53] test
    [ 32.030353 0:2 driver_usb::host::structures::xhci_event_manager:98] initialized!
    [ 32.038942 0:2 driver_usb::host::structures::registers:30] handleing!
    [ 32.046614 0:2 driver_usb::host::structures::registers:30] handleing!
    [ 32.054220 0:2 driver_usb::host::structures::xhci_command_manager:59] initialized!
    [ 32.062985 0:2 driver_usb::host::structures::registers:30] handleing!
    [ 32.070632 0:2 driver_usb::host::structures::scratchpad:54] initialized!
    [ 32.078523 0:2 driver_usb::host::structures::scratchpad:60] initialized!
    [ 32.086421 0:2 driver_usb::host::structures::registers:30] handleing!
    [ 32.094063 0:2 driver_usb::host::structures::roothub:84] initialized!
    [ 32.101698 0:2 driver_usb::host::structures::registers:30] handleing!
    [ 32.109337 0:2 driver_usb::host::structures::registers:30] handleing!
    [ 32.116975 0:2 driver_usb::host::xhci:65] init completed!, coltroller state:UsbStatusRegister { hc_halted: false, host_system_error: false, event_interrupt: 
    false, port_change_detect: true, save_state_status: false, restore_state_status: false, save_restore_error: false, controller_not_ready: false, 
    host_controller_error: false }
    

实验三:读取 USB 设备,并完成一个无线鼠标的设备驱动

  1. 端口检测:USB 3.0主机控制器会定期轮询每个端口,检测是否有设备连接。通过检查端口状态寄存器来完成,如果探测到了连接,控制器会进入设备探测阶段。

  2. 设备探测:一旦检测到连接,USB 3.0主机控制器会开始与设备进行通信,以确定其速度和协议。包括向设备发送探测信号,等待设备响应,并解析设备的描述符。

  3. 设备速度确认:在探测到设备后,USB 3.0主机控制器会与设备进行通信,确认其速度和所支持的USB规范版本(例如USB 2.0、USB 3.0等)。

  4. 配置阶段:一旦设备的速度和规范确认,USB 3.0主机控制器会向设备发送配置命令,并分配设备地址。包括配置端点和分配USB地址。

  5. 设备驱动加载:在设备被成功配置后,USB 3.0主机控制器会加载相应的设备驱动程序。

目前进展已经可以读取到插入的 USB 设备的各种描述符,包括设备描述符、配置描述符、接口描述符以及端点描述符,之后要进行的工作就是写四种通信通信协议,包括控制传输、批量传输、同步传输和中断传输。

尝试接入不同的 USB 设备,可以发现会读出不一样的厂商号和设备号,例如:

USB设备vendor(厂商号)product_id(设备号)
U盘(aigo)23164096
鼠标(罗技g502)113349291
鼠标(罗技M650)113350504
键盘(京东京造)1452591
无线手柄121294
摄像头(U20-CAM-1080P)12943115
U盘(爱国者):

[ 27.176312 0:2 driver_usb::host::structures::xhci_usb_device:163] dev descriptors: [Device(Device { len: 18, descriptor_type: 1, cd_usb: 512, class: 0, subclass: 0, protocol: 0, max_packet_size0: 64, vendor: 2316, product_id: 4096, device: 4352, manufacture: 1, product: 2, serial_number: 3, num_configurations: 1 })]

键盘(京东京造):

[ 29.586200 0:2 driver_usb::host::structures::xhci_usb_device:163] dev descriptors: [Device(Device { len: 18, descriptor_type: 1, cd_usb: 512, class: 0, subclass: 0, protocol: 0, max_packet_size0: 64, vendor: 1452, product_id: 591, device: 259, manufacture: 1, product: 2, serial_number: 0, num_configurations: 1 })]

鼠标(罗技G502):

[ 31.996362 0:2 driver_usb::host::structures::xhci_usb_device:163] dev descriptors: [Device(Device { len: 18, descriptor_type: 1, cd_usb: 512, class: 0, subclass: 0, protocol: 0, max_packet_size0: 64, vendor: 1133, product_id: 49291, device: 9987, manufacture: 1, product: 2, serial_number: 3, num_configurations: 1 })]

摄像头(U20-CAM-1080P):

[ 34.983512 0:2 driver_usb::host::structures::xhci_usb_device:163] dev descriptors: [Device(Device { len: 18, descriptor_type: 1, cd_usb: 512, class: 239, subclass: 2, protocol: 1, max_packet_size0: 64, vendor: 12943, product_id: 115, device: 256, manufacture: 2, product: 1, serial_number: 3, num_configurations: 1 })]

无线手柄:

[ 29.809112 0:2 driver_usb::host::structures::xhci_usb_device:163] dev descriptors: [Device(Device { len: 18, descriptor_type: 1, cd_usb: 272, class: 0, subclass: 0, protocol: 0, max_packet_size0: 8, vendor: 121, product_id: 294, device: 4099, manufacture: 0, product: 2, serial_number: 0, num_configurations: 1 })]

无线鼠标(罗技M650):

[ 31.094196 0:2 driver_usb::host::structures::xhci_usb_device:163] dev descriptors: [Device(Device { len: 18, descriptor_type: 1, cd_usb: 512, class: 0, subclass: 0, protocol: 0, max_packet_size0: 64, vendor: 1133, product_id: 50504, device: 1281, manufacture: 1, product: 2, serial_number: 0, num_configurations: 1 })]

现在已经根据鼠标的描述符成功配置鼠标的端点信息。接下来便是进行中断传输命令。

 Device {
    slot: Slot {
        route_string: 0,
        speed: 2,
        multi_tt: false,
        hub: false,
        context_entries: 3,
        max_exit_latency: 0,
        root_hub_port_number: 1,
        number_of_ports: 0,
        parent_hub_slot_id: 0,
        parent_port_number: 0,
        tt_think_time: 0,
        interrupter_target: 0,
        usb_device_address: 1,
        slot_state: Configured,
    },
    endpoints: [
        Endpoint {
            endpoint_state: Running,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 3,
            endpoint_type: Control,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 8,
            dequeue_cycle_state: true,
            tr_dequeue_pointer: 2417736145,
            average_trb_length: 8,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Disabled,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 0,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 0,
            endpoint_type: NotValid,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 0,
            dequeue_cycle_state: false,
            tr_dequeue_pointer: 0,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 0,
        },
        Endpoint {
            endpoint_state: Running,
            mult: 0,
            max_primary_streams: 0,
            linear_stream_array: false,
            interval: 3,
            max_endpoint_service_time_interval_payload_high: 0,
            error_count: 3,
            endpoint_type: InterruptIn,
            host_initiate_disable: false,
            max_burst_size: 0,
            max_packet_size: 4,
            dequeue_cycle_state: true,
            tr_dequeue_pointer: 2417737729,
            average_trb_length: 0,
            max_endpoint_service_time_interval_payload_low: 4,
        },

根据上述信息可以看出端点0类型为:控制传输,已启用,端点3为中断传输(传输方向:设备到主机),已启用。

方向二:飞腾派 I2C 驱动

目的:

飞腾派通过 I2C 驱动PCA9685模块驱动小车前进,因此需要编写 I2C 驱动从而驱动小车运动

具体实施:

具体进行以下三方面内容:

  1. I2C 驱动
  2. 适配PCA9685模块
  3. 驱动小车

I2C 介绍

I2C是一种多主机、两线制、低速串行通信总线,广泛用于微控制器和各种外围设备之间的通信。它使用两条线路:串行数据线(SDA)和串行时钟线(SCL)进行双向传输。

核心特性:

  1. 两线制:I2C 通信只需两条线路:

    • SDA(Serial Data Line):数据线,用于传输数据。
    • SCL(Serial Clock Line):时钟线,由主设备控制,用于同步所有设备上的数据传输。
  2. 多主机和多从机:I2C 总线允许有多个主设备(可以发起通信)和多个从设备(响应主设备的请求)。这使得多个控制器可以管理不同的从设备,增加了系统的灵活性。

  3. 地址分配:每个 I2C 设备都通过一个唯一的地址进行识别。这些地址在设备通信时使用,确保数据包被正确发送到指定的设备。

  4. 简单的连接:由于通信线路数量少,I2C 设备通常易于安装和配置,减少了硬件布局的复杂性。

  5. 同步串行通信:数据传输是同步进行的,意味着数据传输由时钟信号控制,提高了数据传输的可靠性。

数据传输模式:

I2C 支持多种数据传输模式,包括标准模式(100kbps)、快速模式(400kbps)、快速模式加(1Mbps)和高速模式(3.4Mbps)。根据需要选择不同的速率,可以平衡通信速度和系统资源消耗。

应用场景:

I2C 协议在嵌入式系统中非常流行,适用于各种应用,如:

  • 传感器读取:温度、湿度、压力等传感器经常通过 I2C 与微控制器通信。
  • 设备控制:在许多小型设备或计算机系统中,如笔记本电脑,I2C 用于调节音量、亮度、电源管理等。
  • 存储设备:某些类型的 EEPROM 和其他存储设备通过 I2C 接口与主控制器通信。

实验一:ArceOS的 I2C 驱动实现

飞腾派的每个MIO均可单独当做UART/I2C。端口功能的选择,可以通过配置creg_mio_func_sel寄存器来实现,配置为00选择I2C,配置为01选择UART。

MIO寄存器基地址:

NameOffset
MIO00x000_2801_4000
MIO10x000_2801_6000
MIO20x000_2801_8000
MIO30x000_2801_A000
MIO40x000_2801_C000
MIO50x000_2801_E000
MIO60x000_2802_0000
MIO70x000_2802_2000
MIO80x000_2802_4000
MIO90x000_2802_6000
MIO100x000_2802_8000
MIO110x000_2802_A000
MIO120x000_2802_C000
MIO130x000_2802_E000
MIO140x000_2803_0000
MIO150x000_2803_2000

image

I2C 操作说明:

  1. 模式配置:

    配置MIO寄存器creg_mio_func_sel为0x00,选择I2C模式

  2. 配置为master:

    1. 配置寄存器0x6c(IC_ENABLE)为0;

    2. 写寄存器0x00(IC_CON),配置主从、speed、设备地址宽度。

    3. 将设备地址写入寄存器0x04(IC_TAR);

    4. 使能控制器,配置寄存器0x6c(IC_ENABLE)为1。

  3. 发送数据:

    1. 判断发送FIFO不满:读0x70(IC_STATUS)地址,判断bit[1]为1时,即发送 FIFO 不满。

    2. 发送写数据命令:向0x10(IC_DATA_CMD)的bit[7:0]写入数据,向bit[8]写入0。

    3. 支持写入多字节数据,重复1、2步骤即可。

    4. 写入最后一个字节数据时要加上停止信号,即除了向0x10(IC_DATA_CMD)的bit[7:0]写数据,bit[8]写0表示写以外,向bit[9]写1表示停止。

  4. 接收数据:

    1. 发送读数据命令:向0x10(IC_DATA_CMD)bit[8]写1,表示命令为读操作。

    2. 判断接收FIFO不空:读0x70(IC_STATUS)地址,判断bit[3]为1时,即接收 FIFO 不空。

    3. 读取数据:读0x10(IC_DATA_CMD)地址。

    4. 支持读多字节数据,重复前三步即可。

    5. 读最后一个字节数据时要加上停止信号,即除了向0x10(IC_DATA_CMD)的bit[8]仍写1表示读以外,向bit[9]写1表示停止。

  5. I2C 部分寄存器:

NameOffsetDescription
IC_CON0x00I2C控制寄存器
IC_TAR0x04I2C主机地址寄存器
IC_DATA_CMD0x10I2C数据寄存器
IC_ENABLE0x6CI2C使能寄存器
IC_STATUS0x70I2C状态寄存器

tip:可参考本文档的树莓派串口部分。

实验二:ArceOS通过 I2C 驱动 PCA9685 模块

进阶方向:颜色追踪

方向一实现 USB 驱动,为成功驱动摄像头提供了前提;方向二实现 I2C 驱动,成功驱动小车前进。

目的

小车通过 USB 连接摄像头,通过摄像头读取物体的颜色,然后通过摄像头识别出该颜色后通过 I2C 驱动发送数据到小车控制板,控制小车朝着该颜色的物体运动

第一步:摄像头驱动实现

编写驱动代码:

  • 初始化摄像头
  • 配置摄像头参数
  • 开始捕获图像
  • 处理图像数据
  • 停止捕获图像

第二步:颜色识别算法

算法步骤

  1. 图像获取:获取待处理的图像。
  2. 颜色空间转换:将图像从RGB颜色空间转换为HSV(Hue, Saturation, Value)颜色空间。HSV颜色空间更适合颜色识别,因为它将颜色信息与亮度信息分开,更符合人类感知。
    • Hue(色调):表示颜色的种类,取值范围是[0, 360],对应不同的颜色。
    • Saturation(饱和度):表示颜色的纯度,取值范围是[0, 1],0表示灰色,1表示纯色。
    • Value(亮度):表示颜色的亮度,取值范围是[0, 1],0表示黑色,1表示白色。
  3. 颜色区间定义:定义你想要识别的颜色区间范围。对于每种颜色,定义其在HSV空间中的最小值和最大值。
  4. 颜色区域提取:遍历图像中的每个像素,判断其HSV值是否在定义的颜色区间内。
  5. 形态学处理(可选):对提取的颜色区域进行形态学处理,比如膨胀、腐蚀、开运算、闭运算等,以去除噪声或者连接相邻区域。
  6. 区域检测:检测并标记提取的颜色区域,可以使用连通区域算法(Connected Component Labeling)或者轮廓检测等方法。
  7. 显示结果:在原始图像上绘制出检测到的颜色区域,可以用不同的颜色或者标记框来表示。

第三步:python库的支持

飞腾派参考资料

  1. 飞腾产品资料:

    飞腾派开发板产品信息:https://www.phytium.com.cn/homepage/phytium_pie/

    飞腾CPU资料下载:https://www.phytium.com.cn/homepage/download/

  2. 飞腾嵌入式软件开源社区:https://gitee.com/phytium_embedded

  3. 飞腾派开发板资料:

    飞腾派开发板资料:https://pan.baidu.com/s/1pStiyqohrB3SxHAFFk8R6Q?pwd=dzdv 提取码:dzdv

    飞腾派开发板电子发烧友社区:https://bbs.elecfans.com/group_1708

  4. 飞腾派数据手册&编程手册:https://ese9a2b5c9d46i.prissl.qiqiuyun.net/1708999963/65dd451b88681301680027?attname=%E9%A3%9E%E8%85%BE%E6%B4%BE%E6%95%B0%E6%8D%AE%E6%89%8B%E5%86%8C%26%E7%BC%96%E7%A8%8B%E6%89%8B%E5%86%8C.zip&e=1712544877&token=ExRD5wolmUnwwITVeSEXDQXizfxTRp7vnaMKJbO-:_Yz27ZregW6Z0Ac0FBYHNCAzoB0=

  5. USB相关资料下载:https://docs.qq.com/doc/DSUh1Z21tUGR3aWhy

  6. OSDEV 论坛-USB 教程:https://wiki.osdev.org/Universal_Serial_Bus#Control_Transfers

  7. OSDEV 论坛-PCI 协议教程:https://wiki.osdev.org/PCI#Base_Address_Registers

  8. PCIE 简明教程:https://blog.csdn.net/u013253075/article/details/80835831

  9. 飞腾派I2C:https://www.xcc.com/planet/post/3197