2. 端点(Endpoint)基础:概念、方向、类型与描述符
端点(Endpoint)是USB通信中最基本的逻辑单元,也是主机与设备之间数据传输的终点。理解端点的概念、方向、类型以及描述符结构,是进行高速设备驱动开发和性能调优的前提。本节将系统性地拆解端点的核心属性,并通过结构图与表格帮助建立清晰的认知模型。
2.1 端点的核心概念
在USB协议中,每个USB设备可以包含多个端点,每个端点都是一个单向或双向的数据传输通道。主机通过端点号(Endpoint Number)和方向(Direction)唯一标识一个端点。端点0是所有设备必须实现的默认控制端点,用于设备枚举和基本控制操作。
2.2 端点方向:IN 与 OUT
端点的方向是相对于主机而言的:
- IN 端点:数据从设备传输到主机。设备向主机发送数据时使用 IN 端点。
- OUT 端点:数据从主机传输到设备。主机向设备发送数据时使用 OUT 端点。
端点0是双向的,同时支持IN和OUT方向,但其他端点通常是单向的。在描述符中,方向信息编码在端点地址(bEndpointAddress)的最高位(bit 7)中:0表示OUT,1表示IN。
| 方向 | bit 7 值 | 数据流向 | 典型用途 |
|---|---|---|---|
| OUT | 0 | 主机 → 设备 | 发送命令、配置数据、批量写入 |
| IN | 1 | 设备 → 主机 | 读取状态、批量读取、中断事件上报 |
usb_endpoint_dir_in(epd) 和 usb_endpoint_dir_out(epd) 宏判断。不要混淆方向与数据传输的物理方向——IN总是从设备到主机。
2.3 端点类型:四种传输方式
USB规范定义了四种端点类型,每种类型对应不同的传输特性,适用于不同的应用场景。高速设备(USB 2.0及以上)对这四种类型都有明确的带宽和延迟要求。
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。
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微帧) | 高速等时间隔同样以微帧为单位 |
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)调度和性能优化的基础。