1. OHCI 协议概述

1.1 OHCI 标准背景

OHCI(Open Host Controller Interface)是由 Microsoft、Compaq 和 National Semiconductor 等公司联合制定的 USB 主机控制器开放标准,于 1996 年随 USB 1.0/1.1 规范一同发布。其核心设计目标是通过硬件接管 USB 事务处理的底层调度,降低对 CPU 的干预频率,从而在嵌入式系统和 PC 平台上实现统一的 USB 主机接口。

关键设计理念: OHCI 将 USB 帧调度、事务拆分、重试与错误恢复等逻辑固化在硬件状态机中,驱动只需维护描述符链表(ED/TD),由主机控制器 DMA 引擎自动遍历执行。

OHCI 标准定义了主机控制器与软件驱动之间的寄存器接口、内存数据结构(端点描述符 ED、传输描述符 TD)以及帧周期调度规则。它要求主机控制器具备 DMA 能力,能够直接从系统内存读取 ED/TD 链表,无需 CPU 逐条搬运。

标准属性 OHCI 定义
发布组织 Compaq / Microsoft / National Semiconductor
对应 USB 版本 USB 1.0 / 1.1(全速 12 Mbps / 低速 1.5 Mbps)
调度方式 硬件帧调度 + 链表遍历(ED/TD 队列)
DMA 要求 必须支持,主机控制器自动读取内存描述符
典型应用 嵌入式 SoC、早期 PC 主板、PowerPC 架构
OHCI 主机控制器架构概览 系统内存 HCCA(中断列表) ED 链表(端点描述符) TD 队列(传输描述符) DMA 读取 OHCI 主机控制器 帧调度器(1ms 帧) ED 遍历引擎 TD 执行 / 重试逻辑 USB 总线 USB 设备 批量端点 中断端点 OHCI 通过 DMA 直接遍历内存中的 ED/TD 链表,CPU 仅需维护链表结构

1.2 批量传输在 USB 协议中的位置

USB 协议定义了四种传输类型,批量传输(Bulk Transfer)专为数据量大、实时性要求不高但必须保证可靠交付的场景设计。在 USB 1.1 全速模式下,批量传输的最大包长度为 8/16/32/64 字节;在 USB 2.0 高速模式下可达 512 字节。

传输类型 典型用途 带宽保证 错误重试 最大包长(全速)
控制传输 设备枚举、配置 10% 保留 是 8/16/32/64 字节
批量传输 U 盘、打印机、数据采集 无保证(空闲时全占) 是(硬件重试) 8/16/32/64 字节
中断传输 鼠标、键盘、HID ≤90% 每帧 是 1~64 字节
等时传输 音频、视频流 预定带宽 否 1~1023 字节
批量传输在 OHCI 中的调度位置: OHCI 将批量端点挂载在每帧的“批量列表”中,仅在完成所有中断传输和帧起始(SOF)后,利用剩余时间发送批量数据。因此批量传输的实时延迟不可预测,但吞吐量可以接近总线带宽的 90% 以上。
USB 帧内传输类型调度顺序(OHCI) 1 ms 帧(全速模式) SOF 中断传输 批量传输(占用剩余时间) EOF 空闲 批量传输调度特点 • 批量传输在每帧中优先级最低,仅在中断传输和 SOF 之后执行 • 如果帧内剩余时间不足一个批量事务,则延迟到下一帧 • 批量传输支持硬件自动重试(NAK/STALL 处理)

1.3 OHCI 与 UHCI / EHCI 的对比

USB 主机控制器标准主要分为 OHCI、UHCI 和 EHCI 三大体系。OHCI 和 UHCI 均面向 USB 1.1,但设计哲学截然不同;EHCI 则面向 USB 2.0 高速模式。理解三者的差异对驱动开发和 DMA 调试至关重要。

对比维度 OHCI UHCI EHCI
对应 USB 版本 USB 1.1(全速/低速) USB 1.1(全速/低速) USB 2.0(高速 480 Mbps)
硬件复杂度 高(硬件状态机调度) 低(软件调度为主) 高(硬件队列管理)
CPU 负载 低(DMA 自动遍历) 高(CPU 需逐帧构建列表) 低(异步列表 + 周期列表)
内存数据结构 ED + TD 链表 队列头(QH) + 传输描述符(TD) iTD/siTD + qTD + QH
帧调度方式 硬件遍历 ED 链表 软件生成帧列表(Frame List) 硬件遍历异步/周期列表
批量传输支持 批量 ED 挂载到批量列表 批量 QH 挂载到帧列表 批量 QH 挂载到异步列表
DMA 要求 必须支持 可选(建议支持) 必须支持
典型厂商 NEC、Cypress、TI Intel、VIA Intel、NEC、Renesas
驱动开发注意: OHCI 驱动需要正确初始化 HCCA(Host Controller Communication Area)并维护 ED/TD 链表的一致性。与 UHCI 不同,OHCI 的硬件调度器会主动遍历链表,因此驱动在修改链表时必须遵循“挂起→修改→恢复”的原子操作序列,否则可能导致 DMA 读到不一致的描述符,引发总线错误或数据损坏。
OHCI / UHCI / EHCI 调度架构对比 OHCI HCCA(中断列表) 批量 ED 链表 控制 ED 链表 硬件自动遍历 CPU 负载:低 UHCI 帧列表(1024 项) QH + TD 队列 软件逐帧构建 CPU 频繁干预 CPU 负载:高 EHCI 异步列表(批量/控制) 周期列表(中断/等时) iTD / siTD / qTD 硬件异步列表遍历 CPU 负载:低 OHCI 和 EHCI 依赖硬件 DMA 调度,UHCI 依赖软件调度——这是驱动调试策略差异的根本来源

1.4 批量传输在 OHCI 驱动中的数据结构

OHCI 驱动使用两种核心描述符来管理批量传输:端点描述符(ED) 和 传输描述符(TD)。ED 描述端点的属性(方向、速度、最大包长等),TD 描述一次数据传输的缓冲区信息。多个 TD 可以挂载到同一个 ED 的 Tail 指针上,形成 FIFO 队列。

批量传输 ED 的关键字段:
- FunctionAddress + EndpointNumber:定位 USB 设备端点
- Direction:OUT(0)或 IN(1)
- MaxPacketSize:批量端点最大包长
- TailP / HeadP:TD 队列的头尾指针(硬件通过 HeadP 遍历)
- Skip:挂起位,驱动修改链表时置 1 防止硬件访问
/* OHCI 端点描述符结构(Linux 内核 ohci.h 简化版) */
struct ohci_ed {
    __u32 hwINFO;           /* 端点信息:地址、方向、速度、格式 */
    __u32 hwTailP;          /* TD 队列尾指针(驱动写) */
    __u32 hwHeadP;          /* TD 队列头指针(硬件更新) */
    __u32 hwNextED;         /* 下一个 ED(链表链接) */
    /* 软件辅助字段 */
    struct ohci_ed *next_ed;
    struct ohci_td *td_list;
    dma_addr_t dma;
};
/* OHCI 通用 TD 结构 */
struct ohci_td {
    __u32 hwINFO;           /* TD 类型、状态、完成码 */
    __u32 hwCBP;            /* 当前缓冲区指针(硬件遍历) */
    __u32 hwNextTD;         /* 下一个 TD */
    __u32 hwBE;             /* 缓冲区结束地址 */
    /* 软件辅助 */
    struct ohci_td *next_td;
    dma_addr_t dma;
};
DMA 协同调试要点: 在调试批量传输时,应重点检查 ED 的 HeadP 和 TailP 是否一致(队列空)、TD 的 CBP 是否被硬件正确更新(传输进度)、以及 NextED 链表是否形成闭环。使用 dmseg 或硬件调试器读取 OHCI 的 HcBulkCurrentED 寄存器可以实时观察硬件当前遍历的 ED 地址。