2. 批量传输端点特性

批量传输(Bulk Transfer)在 USB 协议中用于传输非实时、大块数据,典型应用包括 U 盘读写、打印机数据下发、网络适配器数据收发。批量端点没有固定的带宽保留,总线空闲时才能传输,因此其管道属性、最大包长度、数据 Toggle 同步机制以及 Nak/重试策略直接决定了驱动层 DMA 与 OHCI 主控制器协同工作的可靠性。

2.1 批量端点的管道属性

每个批量端点对应一个单向管道(Pipe),方向分为 IN(设备到主机)和 OUT(主机到设备)。在 OHCI 中,批量管道通过端点描述符(Endpoint Descriptor, ED)和传输描述符(Transfer Descriptor, TD)链表进行管理。

属性 说明 OHCI 寄存器/字段
方向 IN 或 OUT,由端点描述符的 D 位控制 ED.Control.Direction
传输类型 批量传输,ED 中 Format 字段为 00 ED.Control.Format
设备地址 目标 USB 设备的功能地址 ED.Control.FunctionAddress
端点号 批量端点编号(1~15) ED.Control.EndpointNumber
最大包长度 单次传输的最大字节数 ED.Control.MaxPacketSize
Toggle 初始值 数据同步位,初始为 0 ED.Control.Toggle
驱动开发提示: 批量端点的 ED 必须挂接到 OHCI 主控制器的批量列表(Bulk List)中,HcBulkHeadED 寄存器指向链表头部。驱动初始化时需确保 ED 的 Skip 位为 0,否则主控制器会跳过该端点。

2.2 最大包长度

批量端点的最大包长度(MaxPacketSize)由 USB 设备在枚举阶段通过标准设备请求(Get Descriptor)报告。对于全速(Full Speed)批量端点,最大包长度可以是 8、16、32 或 64 字节;对于高速(High Speed)批量端点,固定为 512 字节。OHCI 仅支持全速和低速,因此批量端点最大包长度通常为 64 字节。

驱动在配置 ED 时必须将 MaxPacketSize 字段设置为设备报告的值。如果设置错误,主控制器可能无法正确分割数据包,导致传输错误或数据丢失。

关键约束: 批量传输的数据负载必须按最大包长度分割,最后一包允许小于最大包长度。驱动中的 DMA 缓冲区分配应按照 MaxPacketSize 对齐,避免跨页边界导致的 OHCI 访问异常。

2.3 数据 Toggle 同步机制

USB 批量传输使用数据 Toggle 位(Data0/Data1)实现发送端与接收端的同步。每个批量端点维护一个独立的 Toggle 位,初始值为 0(Data0)。每成功传输一个数据包,Toggle 位翻转一次。接收端通过比较接收到的 PID(Data0/Data1)与本地期望的 Toggle 值来判断数据包是否有效。

批量传输 Toggle 同步流程 主机 (Host) 设备 (Device) Toggle=0 (Data0) Toggle=0 (期望 Data0) 发送 Data0 包 ACK (Toggle 翻转) Toggle=1 (Data1) Toggle=1 (期望 Data1) 发送 Data1 包 Toggle 位由 OHCI 主控制器硬件自动维护,驱动只需在 ED 中设置初始值 数据重传时不翻转 Toggle,接收端通过 Toggle 检测重复包

Toggle 同步机制在驱动开发中的关键点:

  • 初始同步: 批量端点配置后,主机和设备端的 Toggle 初始值必须一致(均为 0)。驱动在 ED 的 Toggle 位写入 0。
  • 硬件自动维护: OHCI 主控制器在每次成功传输后自动翻转 ED 中的 Toggle 位,驱动无需软件干预。
  • 错误恢复: 如果传输失败(如 CRC 错误、超时),Toggle 位不翻转,主机重发相同 Toggle 的数据包。
  • 复位同步: 当驱动通过 CLEAR_FEATURE(ENDPOINT_HALT) 恢复端点时,必须将 Toggle 重置为 0。
常见陷阱: 驱动在 DMA 传输完成后直接复用 TD 时,如果未正确重置 Toggle 位,会导致主机与设备 Toggle 失步,表现为连续的数据包被设备丢弃(返回 Nak 或 STALL)。调试时可通过 USB 分析仪抓取 PID 序列快速定位。

2.4 Nak 与重试策略

当设备无法处理批量数据时(如内部缓冲区满或数据未准备好),会返回 Nak(Negative Acknowledge)握手包。OHCI 主控制器对 Nak 的处理策略直接影响批量传输的效率和延迟。

场景 设备返回 OHCI 行为 驱动影响
设备忙(IN 端点无数据) Nak 暂停当前 TD,继续轮询批量列表中的下一个 ED 驱动需等待 Nak 计数超时或中断
设备忙(OUT 端点缓冲区满) Nak 同上,TD 保留在 ED 队列中 驱动应避免频繁重试导致总线占用
设备错误 STALL 设置 ED 的 Halted 位,停止处理该端点 驱动需发送 CLEAR_FEATURE 恢复
传输成功 ACK 更新 TD 的完成状态,移除 TD 驱动处理完成回调
OHCI 批量传输 Nak 重试流程 主机发送批量包 设备响应? ACK → 传输完成 Nak → 设备忙 重试策略 立即重试 (轮询) 延迟重试 (中断) OHCI 默认采用立即重试(轮询),驱动可通过设置 ED 的 Skip 位实现延迟重试

驱动开发中 Nak 与重试策略的工程实践:

  • OHCI 默认行为: 主控制器在收到 Nak 后立即重试同一 TD,直到成功或超时。这种轮询方式会占用大量总线带宽。
  • 驱动优化: 对于频繁 Nak 的设备(如 U 盘写操作时),驱动应设置 ED 的 Skip 位,将端点暂时移出轮询列表,等待设备中断或定时器触发后再恢复。
  • Nak 计数: OHCI 不提供硬件 Nak 计数器,驱动需通过软件记录连续 Nak 次数,超过阈值时切换为延迟重试策略。
  • DMA 协同: 在 DMA 传输模式下,Nak 导致 TD 滞留,驱动应确保 DMA 缓冲区在 TD 完成前不被释放或复用。
调试建议: 使用 OHCI 的 HcInterruptStatus 寄存器中的 WritebackDoneHead 中断判断批量传输是否完成。如果频繁出现 Nak 导致的中断延迟,考虑在驱动中实现自适应重试间隔:初始间隔 1ms,连续 Nak 后指数退避至 10ms。

2.5 批量端点特性总结

特性 驱动关注点 OHCI 硬件支持 DMA 协同要求
管道属性 ED 配置正确,挂接到批量列表 硬件遍历 ED 链表 DMA 地址与 ED 缓冲区指针一致
最大包长度 与设备描述符一致,缓冲区对齐 硬件自动分割/合并 DMA 传输长度按 MaxPacketSize 对齐
Toggle 同步 初始值设置,复位后重置 硬件自动翻转 TD 重用前检查 Toggle 状态
Nak 与重试 实现自适应重试策略 立即重试(可跳过) DMA 缓冲区生命周期管理