嵌入式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 配置空间则负责系统级资源分配与中断路由。
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 —— 挂起控制。
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): 用于中断传输的队列管理,同样位于内存中。
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 传输后数据缓冲区的内容一致性。