3. 端点概念详解
在USB协议体系中,端点(Endpoint)是主机与设备之间数据传输的逻辑通道,也是USB通信的最小可寻址单元。每个USB设备可以拥有最多16个IN端点和16个OUT端点(端点号0-15)。对于QNX BSP开发者而言,正确理解端点类型、方向与描述符结构,是配置USB控制器、编写批量传输驱动的核心前提。
3.1 端点0:控制端点
端点0(Endpoint 0)是每个USB设备在枚举阶段必须实现的默认端点,属于控制传输类型。它在设备连接后立即生效,用于主机获取设备描述符、配置设备地址、设置配置值等标准请求。
- 双向性:端点0在逻辑上同时支持IN和OUT方向,但物理上使用同一端点号(0x00)。
- 传输类型:固定为控制传输(Control Transfer),包含Setup、Data(可选)、Status三个阶段。
- 最大包长:由设备描述符的bMaxPacketSize0字段定义,常见值为8、16、32、64字节。
- QNX驱动角色:在QNX USB stack中,端点0由USB协议栈(如usbdi)自动管理,BSP开发者通常不需要手动配置,但必须确保控制器硬件支持端点0的Setup事务处理。
3.2 IN端点与OUT端点
除端点0外,所有端点都必须明确指定方向。方向字段编码在端点描述符的bEndpointAddress字节中。IN端点和OUT端点在硬件FIFO管理、DMA通道分配、中断处理逻辑上存在显著差异。
| 特性 | IN端点 | OUT端点 |
|---|---|---|
| 数据流向 | 设备 → 主机 | 主机 → 设备 |
| bEndpointAddress[7] | 1 | 0 |
| 典型用途 | 批量数据上传、中断状态报告 | 批量数据下发、控制命令发送 |
| QNX FIFO配置 | 需配置为设备→主机方向FIFO | 需配置为主机→设备方向FIFO |
| DMA传输方向 | 外设→内存 | 内存→外设 |
| 中断触发条件 | 设备发送数据完成 | 主机发送数据完成 |
3.3 端点描述符结构
端点描述符(Endpoint Descriptor)是USB设备固件中用于描述端点属性的标准数据结构。主机在枚举阶段通过GET_DESCRIPTOR请求获取该描述符,QNX USB stack据此配置控制器硬件。标准端点描述符长度为7字节,结构如下:
| 偏移 | 字段 | 长度 | 说明 |
|---|---|---|---|
| 0 | bLength | 1字节 | 描述符长度,固定为0x07 |
| 1 | bDescriptorType | 1字节 | 描述符类型,端点描述符为0x05 |
| 2 | bEndpointAddress | 1字节 | 端点地址(含方向) |
| 3 | bmAttributes | 1字节 | 端点属性(传输类型) |
| 4 | wMaxPacketSize | 2字节 | 最大包长(低10位有效) |
| 6 | bInterval | 1字节 | 轮询间隔(中断/同步端点) |
3.3.1 bEndpointAddress 详解
bEndpointAddress是端点描述符中最重要的字段之一,它编码了端点号、方向以及保留位。其位结构如下:
- Bit[3:0]:端点号(0-15),端点0固定为0x00。
- Bit[6:4]:保留位,必须为0。
- Bit[7]:方向位。0=OUT(主机→设备),1=IN(设备→主机)。
常见取值示例:
0x81:端点1 IN(端点号=1,方向=IN)0x02:端点2 OUT(端点号=2,方向=OUT)0x00:端点0(控制端点,双向)
3.3.2 bmAttributes 详解
bmAttributes字段定义端点的传输类型,占用低2位,高6位保留或用于同步类型(仅同步传输)。
| bmAttributes[1:0] | 传输类型 | 典型应用场景 |
|---|---|---|
| 00 | 控制传输(Control) | 枚举、标准请求(仅端点0) |
| 01 | 等时传输(Isochronous) | 音频、视频流(无重传) |
| 10 | 批量传输(Bulk) | U盘、数据采集(可靠传输) |
| 11 | 中断传输(Interrupt) | 鼠标、键盘、HID设备 |
3.3.3 wMaxPacketSize 详解
wMaxPacketSize是2字节字段,但只有低10位(Bit[9:0])用于表示最大包长,高6位保留或用于附加信息(如同步端点的额外事务数)。对于批量端点,该值通常为8、16、32、64或512字节。
wMaxPacketSize直接决定FIFO深度和DMA传输粒度。配置批量端点时,必须确保控制器FIFO大小 ≥ wMaxPacketSize,否则批量传输将因FIFO溢出而失败。例如,若wMaxPacketSize=512字节,则对应FIFO至少需要512字节深度。
3.4 QNX BSP中的端点配置实践
在QNX BSP开发中,端点配置通常发生在USB控制器初始化阶段。以下是一个典型的批量端点配置代码片段,展示了如何根据端点描述符设置硬件寄存器:
/* QNX USB BSP 批量端点配置示例 */
void usb_bsp_configure_endpoint(struct usb_device *dev,
struct usb_endpoint_descriptor *ep_desc)
{
uint8_t ep_addr = ep_desc->bEndpointAddress;
uint8_t ep_num = ep_addr & 0x0F;
uint8_t ep_dir = (ep_addr & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
uint8_t ep_type = ep_desc->bmAttributes & 0x03;
uint16_t max_pkt = ep_desc->wMaxPacketSize & 0x03FF;
/* 检查端点类型是否为批量传输 */
if (ep_type != USB_ENDPOINT_XFER_BULK) {
return; /* 非批量端点,跳过 */
}
/* 配置FIFO大小:必须 ≥ wMaxPacketSize */
if (max_pkt > BSP_USB_FIFO_SIZE) {
/* 错误处理:FIFO容量不足 */
log_error("Endpoint %d: wMaxPacketSize %d exceeds FIFO size %d",
ep_num, max_pkt, BSP_USB_FIFO_SIZE);
return;
}
/* 设置端点寄存器:地址、方向、类型、最大包长 */
hw_write_endpoint_reg(ep_num, EP_REG_ADDR, ep_addr);
hw_write_endpoint_reg(ep_num, EP_REG_ATTR, ep_type);
hw_write_endpoint_reg(ep_num, EP_REG_MAXPKT, max_pkt);
/* 配置FIFO方向(IN/OUT) */
if (ep_dir == USB_DIR_IN) {
hw_set_fifo_direction(ep_num, FIFO_DIR_DEVICE_TO_HOST);
} else {
hw_set_fifo_direction(ep_num, FIFO_DIR_HOST_TO_DEVICE);
}
log_info("Bulk endpoint %d configured: dir=%s, max_pkt=%d",
ep_num, (ep_dir == USB_DIR_IN) ? "IN" : "OUT", max_pkt);
}
1. 确认bEndpointAddress的方向位与FIFO方向一致。
2. 确认wMaxPacketSize ≤ 控制器FIFO深度。
3. 确认bmAttributes的低2位为0x02(批量传输)。
4. 确认端点号未与其他端点冲突(同一端点号不能同时用于IN和OUT,端点0除外)。
3.5 端点描述符与QNX USB Stack的交互
在QNX系统中,USB协议栈(usbdi)在枚举阶段解析端点描述符,并通过usb_device_attach()回调将配置信息传递给BSP驱动。BSP开发者需要实现以下接口来响应端点配置:
- usb_bsp_configure_endpoint():配置单个端点的硬件寄存器。
- usb_bsp_deconfigure_endpoint():在设备断开或配置变更时释放端点资源。
- usb_bsp_start_endpoint():启用端点数据传输。
- usb_bsp_stop_endpoint():停止端点数据传输。