2. 端点(Endpoint)基础:概念、方向、类型与描述符

端点(Endpoint)是USB通信中最基本的逻辑单元,也是主机与设备之间数据传输的终点。理解端点的概念、方向、类型以及描述符结构,是进行高速设备驱动开发和性能调优的前提。本节将系统性地拆解端点的核心属性,并通过结构图与表格帮助建立清晰的认知模型。

2.1 端点的核心概念

在USB协议中,每个USB设备可以包含多个端点,每个端点都是一个单向或双向的数据传输通道。主机通过端点号(Endpoint Number)和方向(Direction)唯一标识一个端点。端点0是所有设备必须实现的默认控制端点,用于设备枚举和基本控制操作。

关键理解:端点不是物理引脚,而是设备固件中实现的一组缓冲区与状态机。主机通过USB总线向端点发送或接收数据,设备固件则通过中断或轮询方式处理端点缓冲区。
USB端点概念结构图 USB 主机 主机控制器 (HCD) 端点管道 端点管道 端点管道 USB 总线 USB 设备 设备固件 端点 0 (控制) 端点 1 (批量IN) 端点 2 (中断OUT) 每个端点由 端点号 + 方向 唯一标识,主机通过端点管道与设备端点进行数据交换

2.2 端点方向:IN 与 OUT

端点的方向是相对于主机而言的:

  • IN 端点:数据从设备传输到主机。设备向主机发送数据时使用 IN 端点。
  • OUT 端点:数据从主机传输到设备。主机向设备发送数据时使用 OUT 端点。

端点0是双向的,同时支持IN和OUT方向,但其他端点通常是单向的。在描述符中,方向信息编码在端点地址(bEndpointAddress)的最高位(bit 7)中:0表示OUT,1表示IN。

方向 bit 7 值 数据流向 典型用途
OUT 0 主机 → 设备 发送命令、配置数据、批量写入
IN 1 设备 → 主机 读取状态、批量读取、中断事件上报
驱动开发提示:在Linux内核中,端点方向通过 usb_endpoint_dir_in(epd) 和 usb_endpoint_dir_out(epd) 宏判断。不要混淆方向与数据传输的物理方向——IN总是从设备到主机。

2.3 端点类型:四种传输方式

USB规范定义了四种端点类型,每种类型对应不同的传输特性,适用于不同的应用场景。高速设备(USB 2.0及以上)对这四种类型都有明确的带宽和延迟要求。

四种USB端点类型对比 控制传输 端点0 双向 可靠,有握手 最大包: 64/512B 批量传输 非0端点 单向 可靠,带宽尽力 最大包: 64/512B 中断传输 非0端点 单向 可靠,保证延迟 轮询间隔: 1~255ms 等时传输 非0端点 单向 不可靠,无重传 保证带宽 端点类型选择原则 • 控制传输:设备枚举、标准请求、类特定命令 • 批量传输:大块数据,如U盘读写、打印机数据 • 中断传输:周期性小数据,如鼠标、键盘、HID设备 • 等时传输:实时音视频流,如USB摄像头、音频设备

2.4 端点描述符结构

端点描述符是USB描述符体系中的关键组成部分,它向主机报告端点的属性。每个非0端点都必须有一个对应的端点描述符。端点描述符的结构在USB规范中定义如下:

偏移 字段 大小 说明
0 bLength 1字节 描述符长度,固定为7
1 bDescriptorType 1字节 描述符类型,端点描述符为0x05
2 bEndpointAddress 1字节 端点地址:bit 3-0 端点号,bit 7 方向(0=OUT,1=IN)
3 bmAttributes 1字节 bit 1-0 传输类型:00控制,01等时,10批量,11中断
4 wMaxPacketSize 2字节 最大包大小(字节),高速设备可达512/1024字节
6 bInterval 1字节 轮询间隔(帧/微帧),中断/等时端点使用
常见错误:在编写设备固件或驱动时,bEndpointAddress 和 bmAttributes 的位域定义容易混淆。例如,将方向位错误地设置在 bmAttributes 中会导致枚举失败。务必使用USB规范提供的宏或位操作函数。

2.5 端点号与地址编码

端点号(Endpoint Number)是一个4位值(0~15),但端点0是保留的控制端点。实际可用的非0端点号范围是1~15。端点地址(bEndpointAddress)将端点号和方向编码在一个字节中:

  • bit 3-0:端点号(0~15)
  • bit 6-4:保留,必须为0
  • bit 7:方向(0=OUT,1=IN)

例如,bEndpointAddress = 0x81 表示端点号1、方向IN;bEndpointAddress = 0x02 表示端点号2、方向OUT。

bEndpointAddress 位域结构 bEndpointAddress (1字节) bit 7 bit 6-4 bit 3 bit 2 bit 1 bit 0 方向 + 端点号 方向 (0=OUT, 1=IN) 端点号 (0~15) 保留 (必须为0)

2.6 高速设备端点特性

在高速模式(USB 2.0,480 Mbps)下,端点的参数与全速/低速模式有显著差异,直接影响驱动性能调优:

参数 全速 (12 Mbps) 高速 (480 Mbps) 说明
wMaxPacketSize (批量) 8/16/32/64 字节 512 字节 高速批量端点固定为512字节
wMaxPacketSize (中断) ≤64 字节 ≤1024 字节 高速中断端点最大包更大
bInterval (中断) 1~255 ms 1~16 (单位: 125μs微帧) 高速中断间隔以微帧为单位
wMaxPacketSize (等时) ≤1023 字节 ≤1024 字节 高速等时支持更高带宽
bInterval (等时) 1~255 ms 1~16 (单位: 125μs微帧) 高速等时间隔同样以微帧为单位
性能调优要点:高速设备驱动开发时,应充分利用512字节的批量端点最大包大小,减少事务开销。对于中断端点,bInterval值越小,轮询频率越高,但会占用更多总线带宽。等时端点需要精确计算带宽预留,避免溢出。

2.7 端点描述符解析示例

以下是一个典型的USB设备配置描述符中端点描述符的原始字节序列及其解析:

/* 原始端点描述符数据 (16进制) */
07 05 81 02 00 02 0A

/* 字段解析 */
bLength         = 0x07        // 描述符长度 = 7
bDescriptorType = 0x05        // 端点描述符类型
bEndpointAddress = 0x81       // 端点号=1, 方向=IN (bit7=1)
bmAttributes    = 0x02        // 传输类型=批量 (bit1-0=10)
wMaxPacketSize  = 0x0200      // 最大包大小 = 512字节 (小端序)
bInterval       = 0x0A        // 轮询间隔 = 10 (高速: 10*125μs = 1.25ms)

在Linux内核驱动中,解析端点描述符通常使用以下辅助函数:

/* Linux内核端点描述符解析示例 */
struct usb_endpoint_descriptor *epd = &iface_desc->endpoint[0].desc;

/* 获取端点号 */
unsigned int ep_num = usb_endpoint_num(epd);

/* 判断方向 */
bool is_in = usb_endpoint_dir_in(epd);

/* 获取传输类型 */
unsigned int ep_type = usb_endpoint_type(epd);  // 0:控制,1:等时,2:批量,3:中断

/* 获取最大包大小 */
unsigned int max_pkt = usb_endpoint_maxp(epd);

/* 获取轮询间隔 */
unsigned int interval = epd->bInterval;
驱动编写建议:不要直接手动解析端点描述符的原始字节,始终使用内核提供的 usb_endpoint_* 系列宏。这些宏已经处理了字节序和位域偏移,能避免跨平台兼容性问题。

2.8 端点与管道(Pipe)的关系

在USB软件栈中,端点描述符定义了设备的硬件能力,而管道(Pipe)是主机侧软件对端点的抽象表示。每个管道对应一个特定的端点,并维护传输状态、缓冲区管理和调度信息。

  • 端点:设备侧的硬件实体,由描述符定义属性。
  • 管道:主机侧软件抽象,由USB核心在枚举时创建,驱动通过管道与端点通信。

在Linux内核中,struct usb_host_endpoint 结构体将端点描述符与管道状态结合在一起:

struct usb_host_endpoint {
    struct usb_endpoint_descriptor  desc;       // 端点描述符
    struct usb_ss_ep_comp_descriptor ss_ep_comp; // 超高速扩展描述符
    struct list_head                urb_list;   // 挂起的URB链表
    void                            *hcpriv;    // 主机控制器私有数据
    unsigned int                    extra;      // 额外信息
    unsigned char                   enabled;    // 端点使能标志
};

理解端点与管道的映射关系,是后续进行URB(USB Request Block)调度和性能优化的基础。

端点与管道映射关系图 主机软件栈 管道 0 (控制) 管道 1 (批量IN) 管道 2 (中断OUT) USB 总线 设备硬件 端点 0 (控制) 端点 1 (批量IN) 端点 2 (中断OUT) 管道是主机侧对端点的软件抽象,驱动通过管道提交URB实现数据传输

2.9 本章小结