2. Linux USB子系统基础:USB体系结构、主机侧与设备侧驱动、USB Gadget框架简介
在深入ACM Gadget串口设备驱动开发之前,必须理解Linux USB子系统的整体架构。USB子系统分为主机侧(Host Side)和设备侧(Device Side)两大阵营,而USB Gadget框架正是设备侧驱动的核心实现。本章将系统梳理USB体系结构、主机侧与设备侧的驱动差异,并重点介绍Gadget框架的设计理念与核心组件。
2.1 USB体系结构概述
USB(Universal Serial Bus)采用主从式拓扑结构,一个USB系统中只有一个主机(Host),最多可连接127个设备(Device)。主机负责调度所有数据传输,设备只能被动响应主机的请求。
2.2 主机侧驱动(Host Side)
主机侧驱动负责管理USB主机控制器与连接的USB设备之间的通信。Linux内核中,主机侧驱动栈分为三个层次:
| 层次 | 组件 | 职责 | 典型实现 |
|---|---|---|---|
| 硬件层 | USB主机控制器 | 物理层信号处理、总线事务调度 | EHCI(USB 2.0)、xHCI(USB 3.0) |
| 驱动层 | HCD(Host Controller Driver) | 抽象主机控制器硬件差异,向上提供统一接口 | ehci-hcd、xhci-hcd |
| 核心层 | USB Core | 设备枚举、配置管理、urb(USB Request Block)调度 | drivers/usb/core/ |
| 设备驱动层 | USB设备驱动 | 实现具体设备功能(存储、串口、HID等) | usb-storage、usb-serial |
开发提示:在主机侧开发中,最常打交道的是
struct usb_device、struct usb_interface 和 struct urb。USB Core 负责将设备驱动与具体的USB设备绑定,驱动开发者只需实现 probe() 和 disconnect() 回调。
2.3 设备侧驱动(Device Side)与USB Gadget框架
设备侧驱动使嵌入式Linux设备能够作为USB外设(如串口、网卡、大容量存储)连接到主机。Linux内核通过USB Gadget框架实现这一能力。Gadget框架的核心思想是:将嵌入式设备的USB控制器(UDC)抽象为可编程的USB设备,通过软件配置其描述符和端点行为,从而模拟任意USB外设。
2.3.1 Gadget框架核心组件
2.3.2 Gadget框架关键数据结构
Gadget框架的核心数据结构定义在 include/linux/usb/gadget.h 中,开发者必须熟悉以下结构体:
| 数据结构 | 作用 | 关键字段 |
|---|---|---|
struct usb_gadget |
代表一个USB设备控制器(UDC) | ops(操作函数集)、ep0(端点0)、speed(当前速率) |
struct usb_ep |
代表一个USB端点 | ops(端点操作)、maxpacket(最大包长) |
struct usb_request |
代表一个USB请求(类似主机侧的URB) | buf(数据缓冲区)、length(长度)、complete(完成回调) |
struct usb_composite_dev |
复合设备上下文,管理多个功能(Function) | gadget、config、driver |
struct usb_function |
代表一个USB功能(如ACM串口、ECM网卡) | bind()、unbind()、setup()、disable() |
2.3.3 Gadget驱动开发流程
- 注册UDC驱动:实现
struct usb_gadget_driver,调用usb_gadget_probe_driver()注册。 - 实现功能驱动(Function Driver):填充
struct usb_function,实现bind()、setup()等回调。 - 配置描述符:定义设备描述符、配置描述符、接口描述符、端点描述符。
- 端点分配与数据传输:通过
usb_ep_alloc_request()分配请求,调用usb_ep_queue()提交数据。 - 复合设备绑定:使用
usb_composite_probe()将多个功能组合成一个复合设备。
ACM Gadget串口开发要点:在后续章节中,我们将基于
usb_f_acm 模块实现ACM串口功能。该模块实现了USB CDC ACM(Abstract Control Model)协议,使嵌入式设备在主机侧呈现为标准串口设备(如Linux的 /dev/ttyACM0)。核心工作包括:配置接口描述符、实现控制传输(SetLineCoding、SetControlLineState)和数据传输(Bulk IN/OUT端点)。
2.4 主机侧与设备侧驱动对比
| 对比维度 | 主机侧驱动 | 设备侧驱动(Gadget) |
|---|---|---|
| 角色 | 主机(Host),主动发起传输 | 设备(Device),被动响应传输 |
| 核心API | struct urb、usb_submit_urb() |
struct usb_request、usb_ep_queue() |
| 驱动注册 | usb_register() |
usb_gadget_probe_driver() |
| 典型应用 | USB存储驱动、USB串口驱动 | USB Gadget串口、Gadget网卡、Gadget存储 |
| 硬件依赖 | USB主机控制器(EHCI/xHCI) | USB设备控制器(UDC,如DWC2、ChipIdea) |
| 开发复杂度 | 中等,需处理URB生命周期 | 较高,需管理描述符、端点、复合设备 |
常见误区:初学者容易混淆主机侧和设备侧的API。例如,主机侧使用
usb_control_msg() 发送控制传输,而设备侧则需要通过 usb_ep_queue() 将请求提交到端点0,并在 setup() 回调中处理控制请求。两者方向完全相反,务必区分。
2.5 本章小结
- USB体系结构采用主从式拓扑,主机侧和设备侧驱动栈层次分明。
- 主机侧驱动通过HCD、USB Core和设备驱动三层架构管理USB设备。
- 设备侧驱动通过USB Gadget框架实现,核心组件包括UDC驱动、功能驱动和复合设备层。
- Gadget框架的关键数据结构包括
usb_gadget、usb_ep、usb_request和usb_function。 - ACM Gadget串口开发基于
usb_f_acm模块,实现CDC ACM协议,使嵌入式设备模拟为标准串口设备。