2. USB体系结构:主机控制器、集线器、设备与拓扑
USB的体系结构,说白了就是一套“谁管谁、谁连谁”的规则。主机控制器是大脑,集线器是分线器,设备是干活的手。我刚开始接触USB时,总觉得这东西就是插上就能用,后来调试一次枚举失败才发现——不理解体系结构,连问题出在哪都找不到。
2.1 主机控制器:总线的“大脑”
主机控制器(Host Controller)是USB通信的发起者。所有事务都是由它发起的,设备只能被动响应。你想想看,没有主机控制器的调度,总线上那么多设备同时发数据,不乱套才怪。
主机控制器有几种主流类型,我用表格帮你区分一下:
| 类型 | 协议版本 | 速度支持 | 特点 |
|---|---|---|---|
| OHCI | USB 1.x | 全速/低速 | 软件复杂度高,硬件简单,早期非Intel平台常见 |
| UHCI | USB 1.x | 全速/低速 | 硬件复杂度高,软件简单,Intel主导 |
| EHCI | USB 2.0 | 高速/全速/低速 | 兼容OHCI/UHCI,通过配套控制器实现 |
| xHCI | USB 3.x | 超高速/高速/全速/低速 | 统一架构,支持所有速度和协议 |
我个人习惯,排查枚举问题时先看一眼主机控制器类型。比如xHCI支持动态端口切换,但有些老BIOS没配好,设备就是枚举不了。我记得有一次,一个USB 2.0设备插在xHCI端口上就是不认,后来发现是BIOS把端口设成了“仅USB 3.0”模式……改回自动就好了。
lsusb -t(Linux)或设备管理器(Windows)看主机控制器驱动是否正常。如果驱动都没加载,后面全是白费功夫。
2.2 USB集线器:总线的“分线器”
集线器(Hub)负责扩展端口,但更重要的是——它要处理速度转换。你想想,一个高速主机控制器要跟低速鼠标通信,中间必须有个“翻译”。这个翻译就是事务转换器(Transaction Translator,简称TT)。
我曾经在一个项目里遇到过USB触摸屏断断续续的问题,折腾了两天才发现是经过了一个不支持多TT的Hub,多个全速设备共享一个TT导致带宽不足。换了支持多TT的Hub,问题立刻消失。
- 单TT:所有端口共享一个事务转换器,设备多了容易拥堵。
- 多TT:每个端口有自己的事务转换器,带宽独立,适合多个全速/低速设备。
集线器还有“自供电”和“总线供电”之分。自供电的Hub能给下游设备提供500mA甚至更多电流,总线供电的Hub(尤其是无外接电源的)往往力不从心。我建议你在做多设备系统时,尽量选自供电Hub,否则枚举失败大概率是供电不足。
2.3 设备角色:不仅仅是“从设备”
USB设备按功能可分成几类:
- 功能设备:单一功能,比如一个USB鼠标、一个U盘。
- 复合设备:一个物理设备包含多个功能,比如带USB HUB的键盘(键盘+Hub),内部是多个功能描述符。
- 组合设备:接口关联描述符将多个接口组合成一个功能,比如USB耳机既当音频又当音量控制。
很多调试者分不清复合设备和组合设备。嗯,这里要注意:复合设备在设备描述符里会声明bDeviceClass = 0x00,然后每个接口(Interface)自己做主;组合设备则通过接口关联描述符把多个接口绑在一起。我曾经因为没仔细看接口关联描述符,以为某个复合设备只是普通HID,结果枚举描述符解析一直报错。
2.4 拓扑结构:一棵有根的树
USB拓扑是典型的树形结构。根在最顶上(主机控制器的根集线器),往下是一层一层的Hub,叶节点是设备。规范规定最多7层(包括根集线器在内),最多127个设备(包括Hub本身)。
你想想看,为什么是7层?因为USB信号延迟和Hub转发的时间预算就那么多。超过7层,信号质量就会变差,甚至枚举失败。我在一个工控项目中遇到过:客户把Hub串成了8层,结果最末尾的设备时好时坏。我们建议他们把长链路换成有源USB延长器,问题才解决。
另外,根集线器本身也算一层。所以从主机到设备,中间最多经过5个Hub(根集线器算第1层,设备在第7层)。
2.5 根集线器与端口:起点和终点
根集线器(Root Hub)集成在主机控制器内部,它不是独立芯片,而是主机控制器内部的一个逻辑组件。所有的USB端口,最终都连接到根集线器上。每根端口都有自己的状态机——从断开、上电、复位、枚举到正常工作。
我调试枚举问题时,最喜欢看的寄存器就是端口状态寄存器。你可以在Linux下用lsusb -v看到端口状态,或者用evtest看设备热插拔。有一次,一个USB设备插上后没任何反应,我查端口状态寄存器发现端口一直处于“复位”状态,根本不解锁——后来发现是主板漏电导致复位信号异常。
根集线器端口还有一个关键点:每个端口都可以单独控制供电。如果软件层面没有把端口电源打开,设备根本不会有反应。很多嵌入式开发者忘了在初始化代码里调用hub_port_power_on(),结果枚举失败。嗯,这个坑我踩过不止一次。
2.6 本章知识体系一览
这张图把整个USB体系结构串起来了。你从最上面的主机控制器看起,往下到根集线器,再到端口,再到下一级Hub,最后到设备。每一层都有各自的职责和限制。记住,最多7层、127个设备——这是硬杠杠。
好了,USB体系结构的核心概念就这些。理解清楚主机控制器、Hub、设备角色、拓扑层级和根集线器端口,你就能明白USB枚举到底走过了哪些关卡。下一关,才是真正的描述符之战。