1. OHCI 协议概述:标准历史、核心设计思想与对比

OHCI(Open Host Controller Interface)是 USB 主机控制器接口标准之一,由 Compaq、Microsoft 和 National Semiconductor 联合制定,于 1996 年发布 1.0 规范。它定义了 USB 主机控制器硬件与软件驱动之间的标准接口,旨在降低驱动开发复杂度,提升跨平台兼容性。

1.1 OHCI 标准的历史演进

USB 1.x 时代,主机控制器接口存在两大阵营:Intel 主导的 UHCI(Universal Host Controller Interface)和开放联盟主导的 OHCI。OHCI 的设计目标是将更多控制逻辑交给硬件,减少软件干预,从而简化驱动开发。

时间 事件 影响
1995 USB 1.0 规范发布 定义物理层和协议层,但未统一主机控制器接口
1996 OHCI 1.0 规范发布 Compaq/Microsoft/National Semiconductor 联合推出
1998 UHCI 规范发布 Intel 推出,硬件更简单,软件负担更重
2000 USB 2.0 / EHCI 规范发布 EHCI 兼容 OHCI/UHCI,通过 Companion Controller 实现
2008 USB 3.0 / xHCI 规范发布 统一所有速度等级,逐步取代 OHCI/UHCI/EHCI
驱动开发提示: OHCI 在嵌入式领域(如 ARM SoC、早期 PowerPC 平台)仍有广泛应用。理解 OHCI 的硬件自动调度机制,对调试中断延迟和控制传输超时问题至关重要。

1.2 核心设计思想

OHCI 的核心设计哲学是 “硬件辅助,软件轻量”。与 UHCI 将大部分调度工作交给软件不同,OHCI 在硬件层面实现了以下关键机制:

  • 周期性列表(Periodic List): 硬件自动遍历中断传输(Interrupt Transfer)和等时传输(Isochronous Transfer)的 ED(Endpoint Descriptor)链表,无需软件逐帧干预。
  • 非周期性列表(Non-periodic List): 硬件在周期性列表空闲时,自动切换到控制传输(Control)和批量传输(Bulk)的 ED 链表,实现带宽复用。
  • HCCA(Host Controller Communication Area): 一块共享内存区域,硬件将帧完成状态、中断状态等信息写入 HCCA,驱动通过轮询或中断读取。
  • 帧周期固定为 1ms: 硬件以 1ms 为帧周期,每帧开始发送 SOF(Start of Frame)包,驱动基于帧号(Frame Number)进行时间管理。
关键概念: OHCI 的 ED(Endpoint Descriptor)和 TD(Transfer Descriptor)是驱动与硬件交互的核心数据结构。ED 描述端点属性(方向、速度、格式),TD 描述具体传输请求(数据缓冲区、传输长度、完成状态)。硬件自动遍历 ED 链表,从对应 TD 队列中取出待处理传输。
OHCI 主机控制器核心架构 OHCI 主机控制器核心架构 OHCI 主机控制器 硬件自动调度引擎 HCCA 帧状态 / 中断状态 系统内存 ED / TD 链表 周期性列表 中断 / 等时传输 ED 非周期性列表 控制 / 批量传输 ED 带宽调度器 空闲时切换至非周期性 说明: 硬件每帧(1ms)自动遍历周期性列表,处理中断/等时传输; 周期性列表空闲时,硬件自动切换到非周期性列表,处理控制/批量传输。 USB 总线(Root Hub + 设备)

1.3 OHCI 与 UHCI / EHCI 的对比

三种主机控制器接口在设计理念、硬件复杂度、软件负担和适用场景上存在显著差异。下表从驱动开发角度进行对比:

对比维度 OHCI UHCI EHCI
制定者 Compaq / Microsoft / National Semi Intel Intel 主导的 USB-IF
USB 版本 USB 1.1 USB 1.1 USB 2.0
速度 Full/Low Speed Full/Low Speed High Speed (480 Mbps)
硬件复杂度 高(硬件自动调度) 低(硬件简单) 高(高速传输引擎)
软件负担 低(驱动较简单) 高(驱动需手动调度) 中(需处理高速协议)
帧周期 1ms 固定 1ms 固定 125μs(微帧)
调度方式 硬件遍历 ED/TD 链表 软件构建帧列表(Frame List) 硬件异步列表 + 周期性列表
中断处理 HCCA 记录中断状态,驱动读取 中断寄存器直接映射 中断寄存器 + 异步中断消息
控制传输 硬件自动重试,软件设置 TD 软件需手动管理控制阶段 硬件支持高速控制传输
典型平台 嵌入式 ARM / PowerPC / 早期 PC Intel 芯片组 PC USB 2.0 PC / 嵌入式
调试陷阱: OHCI 的硬件自动重试机制在控制传输阶段可能导致“死循环”现象——当设备无响应时,硬件会无限重试 SETUP 阶段,直到软件干预。驱动开发时必须设置 TD 的“重试计数”或“超时控制”位,否则调试时会出现总线挂起。

1.4 OHCI 在驱动开发中的关键数据结构

驱动开发者必须理解以下三个核心数据结构,它们直接映射到硬件寄存器或共享内存:

  • HcControl(控制寄存器): 控制主机控制器的运行状态(运行/停止/复位)、周期性列表使能、非周期性列表使能等。
  • HcInterruptStatus(中断状态寄存器): 反映写回完成、帧号溢出、根集线器状态变化、传输完成等中断事件。
  • Hcca(Host Controller Communication Area): 256 字节对齐的共享内存区域,包含帧号、完成状态字、中断状态字等。
/* OHCI HCCA 结构定义(简化) */
struct ohci_hcca {
    uint32_t frame_number;      /* 当前帧号,每帧递增 */
    uint32_t done_head;         /* 已完成 TD 链表头指针 */
    uint8_t  reserved[116];     /* 保留 */
    uint32_t interrupt_status;  /* 中断状态位图 */
    uint8_t  pad[120];          /* 填充至 256 字节 */
} __attribute__((aligned(256)));
驱动开发要点: OHCI 驱动初始化时,必须将 HCCA 分配在 256 字节对齐的内存地址上,并将物理地址写入 HcHCCA 寄存器。中断处理函数中,驱动通过读取 HCCA 的 done_head 字段获取已完成 TD 链表,而非直接遍历硬件链表——这是 OHCI 与 UHCI 在中断处理上的核心差异。
OHCI 中断处理流程 OHCI 中断处理流程(驱动视角) 硬件完成 TD 写回 HCCA.done_head 触发中断 HcInterruptStatus 置位 驱动中断服务 读取 HCCA.done_head 遍历完成链表 处理每个 TD 状态 回调上层 URB 完成 / 错误处理 清除中断位 写 HcInterruptStatus 关键调试点: 1. 中断服务中必须读取 HCCA.done_head 并清空,否则硬件不会产生下一次中断。 2. 完成链表中的 TD 可能包含错误状态(如超时、NAK、STALL),驱动需逐一检查。

1.5 控制传输在 OHCI 中的实现特点

控制传输是 USB 设备枚举和配置的基础,在 OHCI 中具有以下特点:

  • 三个阶段: SETUP(建立)、DATA(数据,可选)、STATUS(状态)。每个阶段对应一个或多个 TD。
  • 硬件自动重试: 当设备返回 NAK 时,OHCI 硬件会自动重试当前 TD,无需软件干预。但重试次数过多会导致帧时间超限。
  • 控制 ED 位于非周期性列表: 控制传输的 ED 被挂接到非周期性列表,硬件在周期性列表空闲时处理。
  • TD 完成中断: 每个 TD 完成后,硬件将其加入 HCCA.done_head 链表,并触发中断(如果使能)。
调试建议: 在控制传输调试中,建议在驱动中记录每个 TD 的完成状态和帧号。如果发现 SETUP 阶段反复重试但无 STATUS 阶段,通常是设备未正确解析 SETUP 包,或硬件重试计数未设置导致无限循环。