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)。主机负责调度所有数据传输,设备只能被动响应主机的请求。

USB体系结构分层示意图 USB主机(Host) USB主机控制器 主机控制器驱动(HCD) USB核心(USB Core) USB设备驱动(如usb-storage、usb-serial) USB物理总线 USB设备(Device) USB设备控制器(UDC) Gadget驱动 USB功能驱动(如g_serial、g_ether) 用户态应用(如ACM Gadget串口应用) 关键概念 • 主机侧:USB主机控制器 → HCD → USB Core → 设备驱动 • 设备侧:UDC → Gadget驱动 → 功能驱动 → 用户态应用 • USB Gadget框架使嵌入式设备可以模拟成任意USB外设(串口、网卡、存储等)

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框架核心组件

USB Gadget框架软件架构 用户空间(User Space) 用户态应用(如getty、pppd) 配置文件(configfs) 内核空间(Kernel Space) 功能驱动(Function) 配置层(Config) UDC驱动 Gadget API 硬件层(Hardware) USB设备控制器(UDC)

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驱动开发流程

  1. 注册UDC驱动:实现 struct usb_gadget_driver,调用 usb_gadget_probe_driver() 注册。
  2. 实现功能驱动(Function Driver):填充 struct usb_function,实现 bind()、setup() 等回调。
  3. 配置描述符:定义设备描述符、配置描述符、接口描述符、端点描述符。
  4. 端点分配与数据传输:通过 usb_ep_alloc_request() 分配请求,调用 usb_ep_queue() 提交数据。
  5. 复合设备绑定:使用 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协议,使嵌入式设备模拟为标准串口设备。