2. UHCI 初始化流程总览

UHCI 主机控制器的初始化是 USB 子系统正常工作的前提。该过程涉及软件(驱动程序)与硬件(UHCI 控制器)之间的严格握手协议,核心目标是为后续的帧传输建立可用的 DMA 描述符链表。本章将系统梳理初始化步骤、关键寄存器以及软硬件交互的时序。

2.1 主机控制器初始化步骤

UHCI 的初始化遵循一个固定的线性流程,任何步骤的缺失或顺序错误都会导致控制器无法进入工作状态。完整的初始化步骤分为以下 6 个阶段:

  1. 端口复位与全局复位:通过 USBCMD 寄存器中的 HCRESET 位触发主机控制器复位,复位后所有寄存器恢复默认值。
  2. 主机控制器停止确认:复位后控制器处于停止状态,软件需轮询 USBSTS 寄存器的 HCHalted 位,确认停止完成。
  3. 帧列表基地址设置:在内存中分配 4KB 对齐的帧列表(Frame List),并将物理地址写入 FLBASEADD 寄存器。
  4. 帧计数器与中断配置:设置帧号(FRNUM)、帧长度(SOF 调整)以及中断使能(USBINTR)。
  5. DMA 描述符链表构建:在帧列表的每个指针项中填入传输描述符(TD)或队列头(QH)的物理地址,形成完整的调度环。
  6. 运行位设置:将 USBCMD 寄存器的 RS 位置 1,控制器开始根据帧列表调度传输。
关键约束: 步骤 5 必须在步骤 6 之前完成。若在 RS 位为 1 时修改帧列表指针,可能导致 DMA 取指错误,引发不可预测的系统行为。
UHCI 初始化步骤流程图 1. 端口/全局复位 2. 停止确认 3. 帧列表基地址 4. 帧/中断配置 5. DMA 描述符链表 6. 设置 RS 位运行 注意:步骤 5 必须在步骤 6 之前完成,否则 DMA 取指可能出错。

2.2 软件与硬件的握手协议

UHCI 的软硬件握手通过一组特定的寄存器位域实现。软件通过写入命令寄存器发起操作,硬件通过状态寄存器反馈执行结果。以下是关键的握手序列:

阶段 软件操作 硬件响应 超时处理
复位握手 写 USBCMD.HCRESET = 1 复位内部状态机,HCHalted 置 1 轮询 1ms 未完成则报错
停止确认 读 USBSTS.HCHalted 返回 1 表示已停止 轮询 100μs 未就绪则复位
基地址写入 写 FLBASEADD = 帧列表物理地址 锁存地址,用于 DMA 取指 无超时,但地址必须 4KB 对齐
运行启动 写 USBCMD.RS = 1 开始帧周期,HCHalted 清 0 轮询 10μs 未清除则硬件故障
实战建议: 在每次写命令寄存器后,建议插入一个 Memory Barrier(如 x86 的 mfence 或 out 指令),确保写操作被 PCI 总线刷新到 UHCI 控制器,避免因写缓冲导致的握手失败。
软硬件握手时序图 软件 (驱动程序) 硬件 (UHCI 控制器) 写 HCRESET = 1 HCHalted = 1 写 FLBASEADD 写 RS = 1 HCHalted = 0 每次写操作后建议插入 Memory Barrier 确保 PCI 写刷新

2.3 关键寄存器列表

UHCI 初始化阶段涉及的寄存器数量有限,但每个寄存器的位域定义直接影响 DMA 描述符管理。以下是必须掌握的寄存器清单:

寄存器名称 偏移地址 位宽 初始化阶段用途
USBCMD 0x00 16-bit 复位控制器 (HCRESET)、启动/停止 (RS)、中断阈值控制
USBSTS 0x02 16-bit 查询 HCHalted 状态、检测主机控制器错误 (HSE)
USBINTR 0x04 16-bit 使能传输完成/错误/短包中断
FRNUM 0x06 16-bit 设置当前帧号,用于帧列表索引计算
FLBASEADD 0x08 32-bit 写入帧列表基地址(必须 4KB 对齐)
SOFMOD 0x0C 8-bit 调整 SOF 帧长度,用于时钟补偿
常见错误: FLBASEADD 寄存器只保存物理地址的低 32 位。在 64 位系统上,如果帧列表位于 4GB 以上地址空间,必须通过 PCIe 的 DMA 重映射 或 IOMMU 将地址映射到 32 位可访问区域,否则 DMA 将访问错误地址。
关键寄存器与 DMA 描述符关系图 UHCI 寄存器组 USBCMD USBSTS FLBASEADD FRNUM SOFMOD 帧列表 (Frame List) [0] → QH/TD 地址 [1] → QH/TD 地址 ... [1023] → QH/TD 地址 DMA 描述符链 QH (队列头) TD (传输描述符) TD (传输描述符) ... 链表结构 FLBASEADD 指针索引 FLBASEADD 指向帧列表基地址,帧列表项指向 QH/TD,形成完整的 DMA 调度链

2.4 初始化流程中的关键检查点

在实际的嵌入式系统开发中,初始化流程的每个步骤都应设置检查点,以确保软硬件状态一致。以下是推荐的检查点清单:

  • 复位后检查:读取 USBSTS 寄存器,确认 HCHalted 位为 1,且所有其他状态位为 0。
  • 基地址写入后检查:回读 FLBASEADD 寄存器,确认写入值与预期一致(PCI 写合并可能导致回读不一致,需注意)。
  • 描述符链表构建后检查:通过软件遍历帧列表,验证每个指针项指向的 QH/TD 结构体签名(Signature)是否正确。
  • 运行后检查:设置 RS 位后,轮询 USBSTS 的 HCHalted 位,确认在 10μs 内清零,否则触发硬件错误处理。
性能优化提示: 在初始化阶段,帧列表的填充可以采用 rep stosd 指令批量写入,减少循环开销。对于 1024 项的帧列表,单次 rep stosd 即可完成所有指针的初始化,比逐项写入快约 10 倍。
初始化检查点流程图 复位后检查 基地址回读 链表遍历验证 运行状态确认 每个检查点失败都应触发错误恢复流程,避免带病运行导致 DMA 数据损坏 建议在调试阶段使用 GPIO 或串口输出检查点状态,便于定位问题