2. USB数据传输模型:端点、管道、传输类型

USB数据传输模型是理解USB Gadget驱动的基础。与I²C、SPI等传统总线不同,USB采用主机主导的轮询式通信模型,所有数据传输均由主机发起。本章将深入剖析USB数据传输的核心概念:端点、管道以及四种传输类型。

2.1 核心概念:端点与管道

2.1.1 端点(Endpoint)

端点是USB设备中唯一可寻址的物理或逻辑实体,是主机与设备之间数据通信的终点。每个USB设备都有一个唯一的设备地址,而每个端点则在设备内部通过端点号进行区分。

  • 方向性:端点分为IN端点(设备→主机)和OUT端点(主机→设备)。
  • 端点0:每个USB设备必须包含端点0,它是一个双向的控制端点,用于设备枚举和配置。
  • 端点描述符:描述端点的属性,包括端点地址、传输类型、最大包大小、轮询间隔等。
嵌入式要点:在Linux Gadget驱动中,端点通过 struct usb_ep 结构体表示。驱动开发者需要为每个功能(如串口、网卡)分配并配置相应的端点。

2.1.2 管道(Pipe)

管道是主机软件(USB驱动程序)与设备端点之间的逻辑连接。一个管道对应一个端点,并定义了数据传输的类型、方向和流控属性。管道是主机视角的概念,而端点是设备视角的概念。

概念 视角 描述
端点 设备 设备内部的数据收发实体,有唯一的端点号
管道 主机 主机驱动与设备端点之间的软件抽象连接
端点与管道关系示意图 主机 (Host) USB主机控制器 ┌─────────────┐ │ 管道0 (控制) │ │ 管道1 (批量) │ └─────────────┘ 设备 (Device) USB Gadget控制器 ┌─────────────┐ │ 端点0 (控制) │ │ 端点1 (批量) │ └─────────────┘ USB总线 USB总线 管道是主机侧的逻辑抽象,端点才是设备侧真正的物理/逻辑收发实体

2.2 四种传输类型

USB规范定义了四种传输类型,以满足不同设备对带宽、延迟和可靠性的需求。每种传输类型都有其特定的应用场景和特性。

传输类型 应用场景 特点 典型设备
控制传输 设备枚举、配置命令 双向、可靠、带宽小、保证送达 所有USB设备(端点0)
批量传输 大数据块传输 单向或双向、可靠、带宽大、延迟不保证 U盘、USB网卡
中断传输 小数据量、周期性查询 单向、可靠、保证延迟、带宽小 USB鼠标、键盘
同步传输 实时数据流 单向、带宽大、无重传、无保证 USB摄像头、音频设备

2.2.1 控制传输(Control Transfer)

控制传输是USB中最基础、最重要的传输类型。它使用端点0,是设备枚举和配置的必经之路。控制传输由主机发起,包含一个或多个阶段:Setup阶段、Data阶段(可选)和Status阶段。

  • Setup阶段:主机发送8字节的Setup包,包含请求类型、请求码、参数等信息。
  • Data阶段:根据Setup包的方向,传输数据。
  • Status阶段:用于确认传输完成,报告状态。
Gadget驱动关键点:在Linux Gadget中,控制传输的处理函数通过 ep0 的回调实现。驱动必须正确处理标准请求(如 GET_DESCRIPTOR、SET_CONFIGURATION)和类特定请求。
控制传输事务流程 主机 设备 Setup (8字节请求) Data (数据/描述符) Status (握手/确认) 控制传输是唯一必须实现双向传输的类型,用于设备枚举和配置管理

2.2.2 批量传输(Bulk Transfer)

批量传输用于传输大量数据,具有可靠但非实时的特点。USB协议通过错误检测和重传机制保证数据完整性。当USB总线空闲时,批量传输可以占用尽可能多的带宽;当总线繁忙时,它会被其他传输类型抢占带宽。

  • 最大包大小:USB 2.0全速为64字节,高速为512字节。
  • 典型应用:U盘(BOT协议)、USB网卡(ECM/RNDIS协议)。
  • Gadget实现:在Linux中,批量端点通过 usb_ep_queue() 提交URB请求。

2.2.3 中断传输(Interrupt Transfer)

中断传输并非硬件中断,而是主机以固定的轮询间隔查询设备是否有数据需要传输。它保证了最大延迟,适合小数据量的周期性通信。

  • 轮询间隔:在端点描述符中定义,范围从1ms到255ms。
  • 最大包大小:全速最大64字节,高速最大1024字节。
  • 典型应用:HID设备(鼠标、键盘)、USB游戏手柄。
常见误区:中断传输不是由设备主动发起的!设备只能被动等待主机轮询。在Gadget驱动中,中断传输的“中断”含义是“保证延迟”,而非“异步通知”。

2.2.4 同步传输(Isochronous Transfer)

同步传输用于对时间敏感的实时数据流,如音频、视频。它不保证数据完整性(无重传机制),但保证带宽和固定延迟。

  • 带宽预留:在USB帧(1ms)或微帧(125μs)中预留固定带宽。
  • 无握手阶段:同步传输没有Status阶段,不进行ACK/NAK握手。
  • 典型应用:USB摄像头(UVC协议)、USB音频设备(UAC协议)。

2.3 传输类型对比总结

特性 控制 批量 中断 同步
可靠性 高(有重传) 高(有重传) 高(有重传) 低(无重传)
带宽保证 无 无(尽力而为) 有(固定延迟) 有(固定带宽)
延迟 不保证 不保证 保证(轮询间隔) 保证(固定)
数据方向 双向 单向 单向 单向
典型包大小 (HS) 64字节 512字节 1024字节 1024字节
四种传输类型特性对比 控制传输 可靠性:★★★★★ 带宽:★★☆☆☆ 延迟:★★★☆☆ 双向:是 用途:枚举/配置 批量传输 可靠性:★★★★★ 带宽:★★★★★ 延迟:★☆☆☆☆ 单向:是 用途:U盘/网卡 中断传输 可靠性:★★★★★ 带宽:★★☆☆☆ 延迟:★★★★★ 单向:是 用途:HID设备 同步传输 可靠性:★☆☆☆☆ 带宽:★★★★★ 延迟:★★★★★ 单向:是 用途:音视频

2.4 Linux Gadget中的端点配置示例

在Linux Gadget驱动中,端点配置通常在功能驱动(如 f_serial.c、f_ecm.c)的绑定函数中完成。以下是一个典型的批量端点配置代码片段:

/* 在功能驱动的 bind() 回调中 */
static int my_function_bind(struct usb_configuration *c, struct usb_function *f)
{
    struct f_my_opts *opts = container_of(f, struct f_my_opts, func);
    struct usb_composite_dev *cdev = c->cdev;
    struct usb_ep *ep;
    int ret;

    /* 分配并配置批量IN端点 */
    ep = usb_ep_autoconfig(cdev->gadget, &fs_bulk_in_desc);
    if (!ep)
        goto fail;
    opts->bulk_in = ep;
    ep->driver_data = opts; /* 关联私有数据 */

    /* 分配并配置批量OUT端点 */
    ep = usb_ep_autoconfig(cdev->gadget, &fs_bulk_out_desc);
    if (!ep)
        goto fail;
    opts->bulk_out = ep;
    ep->driver_data = opts;

    /* 启用端点 */
    ret = usb_ep_enable(opts->bulk_in);
    if (ret)
        goto fail;

    ret = usb_ep_enable(opts->bulk_out);
    if (ret)
        goto fail;

    return 0;

fail:
    pr_err("my_function: endpoint allocation failed\n");
    return -ENODEV;
}
驱动开发提示:usb_ep_autoconfig() 是Gadget框架提供的便捷函数,它会根据端点描述符自动匹配可用的物理端点资源。开发者无需手动指定端点号,提高了驱动在不同硬件平台上的可移植性。

2.5 本章小结

  • 端点是USB设备内部的数据收发实体,管道是主机侧的逻辑抽象。
  • 四种传输类型各有侧重:控制用于配置,批量用于大数据,中断用于低延迟小数据,同步用于实时流。
  • 在Linux Gadget驱动中,端点通过 struct usb_ep 管理,使用 usb_ep_queue() 提交数据传输请求。
  • 理解传输类型的选择直接影响Gadget功能的性能和可靠性,是驱动设计的关键决策点。