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 架构 |
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% 以上。
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 读到不一致的描述符,引发总线错误或数据损坏。
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 防止硬件访问
- 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 地址。