在嵌入式与物联网设备开发中,USB 不只是一个接口,而是一整套复杂的通信体系。
本文在基础 USB 认知(Host / Device / OTG / 接口类型)之上,进一步补充:
🧠 USB 协议分层结构(协议栈)
🐧 Linux USB 驱动架构
⚙️ 工程落地理解方式
🧠 一、USB 的核心角色回顾
Host(主机):控制通信、供电、发起请求
Device(设备):被动响应请求
OTG:支持角色切换(Host / Device)
👉 本质:USB 是主从架构,不是对等通信
🧩 二、USB 协议分层结构(协议栈模型)
USB 并不是“一根线直接通信”,而是一个完整的分层协议体系。
📡 1️⃣ USB 协议栈总体结构
┌────────────────────────────┐ │ Application │ 应用层(如 U盘 / 摄像头 / 串口) ├────────────────────────────┤ │ Class Driver │ 类驱动(HID / Mass Storage / CDC) ├────────────────────────────┤ │ USB Core │ USB核心层(Linux usbcore) ├────────────────────────────┤ │ Host Controller │ HCD(xHCI / EHCI / OHCI) ├────────────────────────────┤ │ USB Bus │ USB总线层 ├────────────────────────────┤ │ PHY Layer │ 物理层(D+/D- / Type-C CC) └────────────────────────────┘📌 每一层的作用
🧠 ① 应用层(Application)
用户直接看到的功能:
U盘挂载
USB摄像头
USB转串口
🧩 ② Class Driver(类驱动)
USB 最大特点之一:“按类别驱动”
常见类:
| Class | 作用 |
|---|---|
| HID | 键盘 / 鼠标 |
| MSC | U盘 / 存储设备 |
| CDC | USB转串口 |
| UVC | 摄像头 |
👉 关键点:
USB 不是按厂商驱动,而是按“类别驱动”
🧠 ③ USB Core(核心层)
Linux 内核中的usbcore:
设备枚举
设备管理
接口匹配
驱动绑定
⚙️ ④ Host Controller Driver(HCD)
控制 USB 控制器硬件:
| 控制器 | 说明 |
|---|---|
| EHCI | USB2.0 高速 |
| OHCI/UHCI | USB1.1 |
| xHCI | USB3.x / USB-C |
👉 这一层直接操作硬件寄存器
🔌 ⑤ PHY Layer(物理层)
真实信号层:
D+ / D- 差分信号
USB 5V 电源
Type-C CC 引脚(角色识别)
🐧 三、Linux USB 驱动架构(重点工程部分)
USB 在 Linux 中是一个典型分层驱动模型。
🧠 1️⃣ Linux USB 架构图
User Space ↑ /dev/ttyUSB0 ↑ ┌───────────────────┐ │ USB Class Driver │ ← cdc_acm / usb-storage / usbhid └───────────────────┘ ↑ ┌───────────────────┐ │ usbcore │ ← USB核心层 └───────────────────┘ ↑ ┌───────────────────┐ │ Host Controller │ ← xHCI driver └───────────────────┘ ↑ USB PHY ↑ USB Device⚙️ 2️⃣ USB 驱动匹配机制(关键)
Linux USB 驱动不是“插上就随便跑”,而是:
📌 通过 VID / PID 匹配
USB_DEVICE(0x12D1, 0x1001)VID = 厂商 ID
PID = 产品 ID
📌 通过 Class 匹配
例如:
CDC(串口)
HID(键鼠)
MSC(U盘)
👉 这也是“免驱设备”的来源
🧩 3️⃣ /dev/ttyUSB0 是怎么来的?
以 USB 转串口为例:
USB设备 ↓ usbcore识别 ↓ cdc_acm / usbserial driver ↓ tty layer ↓ /dev/ttyUSB0⚠️ 常见问题解释
❗ 为什么 ttyUSB0 会变?
因为:
USB 枚举顺序变化
多设备插拔顺序变化
udev 没有固定规则
🔧 解决方案:
✔ 使用 udev rule 固定设备
SUBSYSTEM=="tty", ATTRS{idVendor}=="xxxx", SYMLINK+="usb_serial"✔ 或使用:
/dev/serial/by-id/🔁 四、OTG 与 Linux 的关系
OTG 实际上就是:
“同一个 USB 控制器,切换 Host / Device 模式”
Linux 中体现为:
| 模式 | 内核角色 |
|---|---|
| Host | xHCI/EHCI driver |
| Device | gadget driver |
📌 Device 模式(Gadget)
Linux 可以模拟 USB 设备:
USB 网卡
USB 串口
USB 存储
👉 使用gadget framework
📷 OTG + Linux结构图建议
建议画一张综合图:
Linux Device ┌───────────────┐ │ Host Mode │ │ Gadget Mode │ └──────┬────────┘ OTG │ USB PHY Controller │ USB Port⚡ 五、工程总结
USB 可以抽象成三句话:
🧠 1️⃣ 架构本质
USB = Host 控制 + Device 响应
🧠 2️⃣ 软件本质
USB = Class Driver + Core + HCD
🧠 3️⃣ Linux本质
USB = 可热插拔 + 自动匹配驱动 + 分层架构
六、“免驱”≠一定能用:USB设备为什么插上还是没驱动?
在实际开发和现场运维中,经常会遇到一个典型误区:
❌ “官方说免驱,但插上设备就是没有驱动/没有节点”
这里的关键是:免驱指的是系统自带 Class Driver,而不是保证一定可用。
🧠 1️⃣ “免驱”的真实含义
USB所谓“免驱”,本质是:
操作系统已经内置了对应Class Driver(类驱动)
例如:
- HID(键盘/鼠标)
- MSC(U盘)
- CDC(串口)
- UVC(摄像头)
👉 只要设备符合标准 Class,就能自动绑定驱动。
❗ 2️⃣ 为什么“免驱设备”仍然可能不工作?
可以归为三类问题:
🔌 (1)硬件层:USB都没真正识别
现象:
lsusb 无设备变化原因:
- 线材只有充电无数据
- OTG未开启 / 未供电
- USB Host模式未生效
👉 本质:设备根本没进入枚举阶段
🧩 (2)枚举成功,但Class不匹配
现象:
lsusb 能看到设备,但没有 /dev/xxx原因:
- 设备使用 Vendor Specific Class(0xFF)
- VID/PID 不在驱动匹配表
- Descriptor 不符合标准 CDC/HID/MSC
👉 本质:系统不知道用哪个驱动
⚙️ (3)驱动存在,但未加载/未绑定
现象:
- lsusb 有设备
- 但没有 ttyUSB / video / block 节点
原因:
modprobe cdc_acm modprobe usbserial或:
- 内核未编译相关模块
- 驱动未自动 probe
👉 本质:驱动在,但没“认出你”
如果在映翰通的设备上,明明是免驱的设备却仍旧无法正常工作,可以提供 pid+vid + 驱动文件预置到系统内解决问题。