嵌入式UHCI多类型传输与DMA协同测试 - 第2节

2.1 UHCI 控制器硬件架构概览

UHCI(Universal Host Controller Interface)是 Intel 定义的 USB 1.1 全速/低速主机控制器标准。其硬件架构围绕 寄存器文件、PCI 配置空间 和 帧列表(Frame List) 三大核心模块构建。理解这些模块的布局与映射关系,是进行控制传输与 DMA 测试验证的基础。

关键概念: UHCI 通过 I/O 映射的寄存器组控制 USB 总线状态,通过内存映射的帧列表与传输描述符(TD)实现 DMA 传输。PCI 配置空间则负责系统级资源分配与中断路由。
UHCI 控制器硬件架构顶层框图 UHCI 主控制器核心 (状态机 / 帧定时 / 列表遍历) I/O 映射寄存器文件 USBCMD / USBSTS / USBINTR FRNUM / FLBASEADD / SOF / PORTSC PCI 配置空间 VID / DID / 基地址寄存器 中断线 / 中断引脚 帧列表 (Frame List) 内存映射 · 1024 项 · 4KB 对齐 说明:UHCI 通过 PCI 配置空间获取 I/O 基地址,通过 FLBASEADD 寄存器定位内存中的帧列表,帧列表项指向传输描述符(TD)链表。

2.2 UHCI 寄存器布局详解

UHCI 寄存器全部通过 I/O 空间 访问,基地址由 PCI 配置空间的 BAR0(基地址寄存器 0)提供。每个寄存器为 8 位、16 位或 32 位宽度,偏移地址相对于 I/O 基地址计算。

2.2.1 核心寄存器一览

偏移地址 寄存器名称 宽度 功能描述
0x00 USBCMD 16 位 主机控制器命令寄存器:启动/停止调度、全局复位、帧列表大小选择
0x02 USBSTS 16 位 主机控制器状态寄存器:HCHalted、HCPE、FatalError、USB Error Interrupt 等
0x04 USBINTR 16 位 中断使能寄存器:控制哪些状态位能产生中断
0x06 FRNUM 16 位 帧号寄存器:当前帧号(0~1023),软件可写用于同步
0x08 FLBASEADD 32 位 帧列表基地址寄存器:指向 4KB 对齐的帧列表物理地址
0x0C SOF 8 位 帧起始调节寄存器:微调 SOF 信号时序
0x10~0x1F PORTSC[1:2] 16 位/端口 端口状态与控制寄存器:连接检测、使能、复位、挂起、过流等
测试要点: 在嵌入式平台验证时,应首先读取 USBSTS 的 HCHalted 位(bit 5)确认控制器处于停止状态,再通过 USBCMD 的 Run/Stop 位(bit 0)启动调度。FLBASEADD 必须指向 4KB 对齐的物理内存区域,否则 DMA 将产生致命错误。

2.2.2 关键寄存器位域详解

以下列出测试验证中需要重点关注的寄存器位域:

  • USBCMD (0x00):
    • Bit 0 (RS):Run/Stop —— 1 启动帧列表遍历,0 停止。
    • Bit 1 (HCRESET):Host Controller Reset —— 写 1 复位控制器,复位后自动清零。
    • Bit 2 (GRESET):Global Reset —— 写 1 触发 USB 总线复位。
    • Bit 4 (FGR):Force Global Resume —— 用于远程唤醒。
    • Bit 7 (SWDBG):Software Debug —— 使能后控制器进入单步模式。
  • USBSTS (0x02):
    • Bit 0 (INT):USB Interrupt —— 传输完成或错误时置位。
    • Bit 1 (ERR):USB Error Interrupt —— 发生 USB 协议错误。
    • Bit 2 (RD):Resume Detect —— 检测到唤醒信号。
    • Bit 3 (HSE):Host System Error —— PCI 总线错误。
    • Bit 5 (HCHalted):Host Controller Halted —— 控制器处于停止状态。
  • PORTSC (0x10 / 0x12):
    • Bit 0 (CCS):Current Connect Status —— 0 未连接,1 已连接。
    • Bit 1 (CSC):Connect Status Change —— 连接状态变化标志。
    • Bit 2 (PE):Port Enable —— 端口使能位。
    • Bit 3 (PEC):Port Enable Change —— 使能状态变化标志。
    • Bit 4 (LS):Line Status —— 用于检测低速/全速设备。
    • Bit 8 (SUSP):Suspend —— 挂起控制。
USBCMD 寄存器位域布局 (16-bit) USBCMD (I/O 偏移 0x00) 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 保留 (Reserved) 保留 FGR GR HC RS 说明:RS=1 启动帧列表遍历;HCRESET 写 1 复位控制器;GRESET 触发 USB 总线复位;FGR 用于远程唤醒。

2.3 PCI 配置空间

UHCI 作为 PCI 功能设备,其配置空间遵循 PCI 本地总线规范 2.2。系统软件通过配置空间发现设备、分配资源并初始化中断。

2.3.1 配置空间关键字段

配置偏移 字段名称 宽度 典型值 / 说明
0x00 Vendor ID (VID) 16 位 0x8086 (Intel)
0x02 Device ID (DID) 16 位 例如 0x7020 (ICH 系列 UHCI)
0x08 Revision ID / Class Code 32 位 Class Code = 0x0C0300 (USB Host Controller)
0x10 BAR0 32 位 I/O 基地址寄存器,bit 0 = 1 表示 I/O 空间
0x3C Interrupt Line 8 位 系统分配的中断向量号
0x3D Interrupt Pin 8 位 通常为 0x01 (INTA#)
嵌入式平台注意事项: 部分 SoC 将 UHCI 挂载在内部总线上而非标准 PCI 总线,此时配置空间可能通过内存映射寄存器模拟。测试前必须确认 BAR0 返回的是 I/O 地址还是内存地址,并相应调整访问方式。

2.4 I/O 映射与内存映射

UHCI 采用 混合映射 策略:控制寄存器通过 I/O 空间访问,而帧列表和传输描述符(TD)通过内存空间访问。这种设计将频繁访问的寄存器与大数据量的描述符分离,优化了总线利用率。

2.4.1 I/O 映射

  • 访问方式: 使用 x86 的 IN/OUT 指令,或 ARM 平台的 readl()/writel() 配合 I/O 内存映射。
  • 地址范围: 由 BAR0 指定,通常占用 32 字节 I/O 空间。
  • 寄存器对齐: 16 位寄存器必须按 16 位对齐访问,32 位寄存器按 32 位对齐。

2.4.2 内存映射

  • 帧列表: 由 FLBASEADD 寄存器指向,必须位于 4KB 对齐的物理内存中。帧列表包含 1024 个 32 位项,共 4KB。
  • 传输描述符(TD): 每个 TD 为 32 字节,由帧列表项或前一个 TD 的 Link Pointer 指向。TD 必须位于 16 字节对齐的物理内存中。
  • 队列头(QH): 用于中断传输的队列管理,同样位于内存中。
UHCI I/O 映射与内存映射关系 I/O 空间 BAR0 基地址 +0x00 USBCMD +0x02 USBSTS +0x10 PORTSC ... 内存空间 FLBASEADD 指向 帧列表 (4KB) TD 描述符 (32B) QH 队列头 数据缓冲区 PCI 总线 帧列表 (Frame List) Frame 0: 指向 TD 链表 Frame 1: 指向 TD 链表 ... Frame 1023: 指向 TD 链表 FLBASEADD 指向

2.5 寄存器访问示例代码

以下代码演示在嵌入式 Linux 环境下,通过 ioport_map 和 ioread16/iowrite16 访问 UHCI 寄存器:

#include <linux/io.h>
#include <linux/pci.h>

/* 假设已通过 pci_resource_start() 获取 I/O 基地址 */
unsigned long uhci_io_base;
void __iomem *uhci_regs;

/* 映射 I/O 端口到虚拟地址 */
uhci_regs = ioport_map(uhci_io_base, 32);
if (!uhci_regs) {
    pr_err("Failed to map UHCI I/O space\n");
    return -ENOMEM;
}

/* 读取 USBSTS 寄存器,检查 HCHalted 位 */
u16 usbsts = ioread16(uhci_regs + 0x02);
if (usbsts & (1 << 5)) {
    pr_info("UHCI controller is halted\n");
}

/* 设置 FLBASEADD 寄存器,指向 4KB 对齐的帧列表 */
dma_addr_t fl_phys = dma_alloc_coherent(dev, 4096, &fl_dma, GFP_KERNEL);
iowrite32(fl_phys, uhci_regs + 0x08);

/* 启动控制器:写 USBCMD 的 RS 位 */
u16 cmd = ioread16(uhci_regs + 0x00);
cmd |= (1 << 0);  /* 设置 Run/Stop 位 */
iowrite16(cmd, uhci_regs + 0x00);

/* 取消映射 */
ioport_unmap(uhci_regs);
验证建议: 在嵌入式平台测试时,建议先通过 PCI 配置空间读取 BAR0 确认 I/O 基地址,然后使用示波器或逻辑分析仪捕获 I/O 读写周期,验证寄存器访问时序是否符合 UHCI 规范。对于内存映射的帧列表,应检查其物理地址是否确实 4KB 对齐,并验证 DMA 传输后数据缓冲区的内容一致性。