hello 今天继续整理 USB 设备描述符信息,简单了解,什么是设备描述符,以及为什么要有描述符

1. USB 设备逻辑组织

USB 设备逻辑组织如下。一个设备可能有若干配置,一个配置下有若干接口,一个接口下又有若干端点。

  • 设备:是指整个USB设备,有唯一的PID/VID信息。
  • 配置:

  • 设备功能组合,但同时还定义了设备的电气特性。一个设备可以有多个配置,但同时只能有一个配置生效,在设备枚举后由主机进行选择。
  • 配置由接口组成,一个配置可以有多个接口
  • 绝大数USB设备有且只有一个配置。

  • 接口:

  • 每一个接口代表一个具体的功能/USB子类,是设备驱动控制的对象。
  • 接口包括端点,0端点所有接口共用。端点:
  • USB 数据传输的起点/终点,USB 数据必须在端点流动
  • 定义了数据传输方式,包括USB数据包最大字节数、传输模式等。

对应的也有设备描述符、配置描述符、接口描述符、端点描述符。

USB:设备描述符和枚举过程_描述符

2. USB 描述符信息

USB 描述符大致可以分为标准描述符和类描述符,标准描述符是所有类设备通用的和USB逻辑组织对应。类描述符和USB子类对应,描述特定的子类协议。

USB:设备描述符和枚举过程_字符串_02

标准描述符:


  • 设备描述符:描述USB设备,一个USB设备有且仅有一个设备描述符
  • 配置描述符:描述配置信息。要点是从属接口和电气特性
  • 接口描述符:描述接口信息。要点是从属端点和子类协议
  • 端点描述符:描述端点信息,要点是传输方式。
  • 字符串描述符:作为其他描述符的补充,定义字符串。

描述符,描述的是usb 设备信息,以及支持的各类功能协议,主要给主机使用,正确的配置了设备信息,usb 主机才能成功枚举,并建立通信。

设备描述符

struct usb_device_descriptor {
__u8 bLength; /* 设备描述符大小,固定为0x12,即18字节*/
__u8 bDescriptorType /* 描述符类型编号,固定为0x01*/;

__le16 bcdUSB; /* USB 版本号:1.1 - 0110,2.0 - 0200 */
__u8 bDeviceClass; /* USB 官方分配的设备类代码, 0x01~0xfe为标准类设备,0xff 为厂商自定义类型,0x00 不在设备描述符中定义 */
__u8 bDeviceSubClass /* USB 官方分配的子类代码 */;
__u8 bDeviceProtocol; /* USB 官方分配的设备协议代码 */
__u8 bMaxPacketSize0;/* 端点0最大数据长度 */
__le16 idVendor; /* 厂商编号 */
__le16 idProduct; /* 产品编号 */
__le16 bcdDevice; /* 设备出厂编号 */
__u8 iManufacturer; /* 描述厂商字符串索引 */
__u8 iProduct; /* 描述产品序列号字符串索引 */
__u8 iSerialNumber; /* 描述设备序列号字符串索引*/
__u8 bNumConfigurations; /* 可能的配置数量 */
} __attribute__ ((packed));

2.1 配置描述符

struct usb_config_descriptor
{
__u8 bLength; //配置描述符长度,固定0x9
__u8 bDescriptorType; //描述符类型编号,固定0x02

__le16 wTotalLength; //要返回的数据总长,指此配置描述符以及其下的接口描述符,端点描述符以及其他类描述符(如果有)的总长度
__u8 bNumInterface; //此配置所包含的接口数量
__u8 bConfigurationVale; //Set_Configuration命令需要的参数值
__u8 iConfiguration; //描述该配置的字符串的索引值

__u8 bmAttribute; //供电模式的选择
__u8 MaxPower; //设备从总线提取的最大电流
}

2.2 接口描述符

struct usb_interface_descriptor
{
__u8 bLength; //接口描述符长度,固定0x09
__u8 bDescriptorType; //描述符类型编号,固定0x04

__u8 bInterfaceNumber; //接口的编号
__u8 bAlternateSetting; //备用接口编号
__u8 bNumEndpoints; //该接口使用端点数,不包括端点0

__u8 bInterfaceClass; //接口类型
__u8 bInterfaceSubClass; //接口子类型
__u8 bInterfaceProtocol; //接口所遵循的协议
__u8 iInterface; //描述该接口的字符串索引值
}

2.3 端点描述符

struct usb_endpoint_descriptor
{
__u8 bLength; //端点描述符长度,固定0x7
__u8 bDescriptorType; //描述符类型编号,固定0x05

__u8 bEndpointAddress; //端点地址(0~3bit),输入输出属性(7bit, 0-OUT, 1-IN)
__u8 bmAttribute; //端点的传输类型属性,0~1bit:4种传输类型,2~3bit:同步类型-信号,4~5bit:端点用途,数据/反馈等
__le16 wMaxPacketSize; //端点收、发的最大数据长度
__u8 bInterval; //主机查询端点的时间间隔
}

3. 枚举过程

枚举目的:


  • 设置USB设备的唯一地址
  • 获取USB设备的全部描述符信息

枚举过程:


  • 识别热插拔
  • 分配设备地址
  • 获取描述符信息 -(可选)选择配置

(1)识别热插拔:


  • 设备插入,主机接口D+/D-电平变化
  • 主机控制器产生中断
  • 主机确认热插拔动作,并通过硬件特性确认设备基础信息(接口标准等)

(2)分配设备地址:

  • 主机控制设备复位,复位后设备默认地址0
  • 主机获取8字节的设备描述符,从中得到端点0最大数据包长度
  • (可选)主机控制设备复位,复位后设备默认地址0
  • 这里再次复位设备的目的在于消除任何不确定性,保证流程可控安全
  • 主机发送请求,设置设备地址,得到ACK应答后,之后启用新地址通讯

(3)获取描述符信息:


  • 主机获取完整的设备描述符
    • 不在第一次就获取完整描述符的原因:设备端点0支持最大包长未知,只能按照最小字节传输(8),效率低
  • 主机获取18字节的配置描述符,得到包含配置描述符在内的描述符总长度
  • 主机获取配置描述符及其下所属的全部描述符
  • 主机获取字符串描述符


USB:设备描述符和枚举过程_子类_03