3. 端点概念详解:端点0(控制端点)、IN/OUT端点、端点描述符结构

在USB协议体系中,端点(Endpoint)是主机与设备之间数据传输的逻辑通道,也是USB通信的最小可寻址单元。每个USB设备可以拥有最多16个IN端点和16个OUT端点(端点号0-15)。对于QNX BSP开发者而言,正确理解端点类型、方向与描述符结构,是配置USB控制器、编写批量传输驱动的核心前提。

💡 核心概念:端点方向始终以主机视角定义。IN端点表示设备→主机,OUT端点表示主机→设备。端点0是唯一双向的默认控制端点,所有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事务处理。
📌 端点0故障排查要点:如果设备无法完成枚举,首先检查端点0的最大包长是否与控制器预期一致。QNX usbdi库在初始化时会读取bMaxPacketSize0,若该值超出控制器FIFO容量,将导致控制传输失败。
端点0 控制传输三阶段流程 阶段1: Setup 主机发送8字节请求 阶段2: Data 数据包传输(可选) 阶段3: Status 握手确认/错误报告 端点0是唯一不需要配置描述符即可使用的端点,由USB协议栈自动管理 QNX BSP开发者需确保控制器硬件支持Setup令牌包和Data PID序列

3.2 IN端点与OUT端点

除端点0外,所有端点都必须明确指定方向。方向字段编码在端点描述符的bEndpointAddress字节中。IN端点和OUT端点在硬件FIFO管理、DMA通道分配、中断处理逻辑上存在显著差异。

特性 IN端点 OUT端点
数据流向 设备 → 主机 主机 → 设备
bEndpointAddress[7] 1 0
典型用途 批量数据上传、中断状态报告 批量数据下发、控制命令发送
QNX FIFO配置 需配置为设备→主机方向FIFO 需配置为主机→设备方向FIFO
DMA传输方向 外设→内存 内存→外设
中断触发条件 设备发送数据完成 主机发送数据完成
⚠️ 常见配置错误:在QNX BSP中配置批量端点时,如果IN/OUT方向与FIFO方向不匹配,会导致数据传输超时或数据错位。例如,将IN端点映射到OUT方向的FIFO,控制器将无法正确发送数据。

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字节。

🔧 QNX BSP配置要点:在QNX USB控制器驱动中,wMaxPacketSize直接决定FIFO深度和DMA传输粒度。配置批量端点时,必须确保控制器FIFO大小 ≥ wMaxPacketSize,否则批量传输将因FIFO溢出而失败。例如,若wMaxPacketSize=512字节,则对应FIFO至少需要512字节深度。
端点描述符结构位图(7字节) bLength 0x07 bDescriptorType 0x05 bEndpointAddress 端点号+方向 bmAttributes 传输类型 wMaxPacketSize 最大包长(低10位) bInterval 轮询间隔 bEndpointAddress 位展开(1字节) Bit7 Bit6:4 Bit3:0 方向 保留(0) 端点号 批量端点典型配置:bEndpointAddress=0x81(端点1 IN),bmAttributes=0x02(批量), wMaxPacketSize=0x0200(512字节),bInterval=0x00(批量端点忽略)

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():停止端点数据传输。