配置描述符
USB 设备以一系列称为 USB 配置的接口的形式公开其功能。 每个接口由一个或多个备用设置组成,每个备用设置由一组端点组成。
配置描述符中描述了 USB 配置。 配置描述符包含有关配置及其接口、备用设置及其端点的信息。 每个接口描述符或备用设置均在 USB_INTERFACE_DESCRIPTOR 结构中描述。 在配置中,每个接口描述符在内存中后跟接口和备用设置的所有端点描述符。 每个端点描述符都存储在 USB_ENDPOINT_DESCRIPTOR 结构中。
例如,请考虑 USB 设备布局中描述的 USB 网络摄像头设备。 设备支持具有两个接口的配置,第一个接口 (索引 0) 支持两个备用设置。
以下示例显示了 USB 网络摄像头设备的配置描述符:
Configuration Descriptor:
wTotalLength: 0x02CA
bNumInterfaces: 0x02
bConfigurationValue: 0x01
iConfiguration: 0x00
bmAttributes: 0x80 (Bus Powered )
MaxPower: 0xFA (500 mA)
bConfigurationValue 字段指示设备固件中定义的配置编号。 客户端驱动程序使用该数字值来选择活动配置。 有关 USB 设备配置的详细信息,请参阅 如何为 USB 设备选择配置。 USB 配置还指示某些电源特征。 bmAttributes 包含一个位掩码,指示配置是否支持远程唤醒功能,以及设备是总线供电还是自供电。 MaxPower 字段指定当设备采用总线供电时,设备可从主机提取的最大功率(以毫安为单位)。 配置描述符还指示设备支持的 (bNumInterfaces) 接口总数。
接口描述符
以下示例显示了网络摄像头设备的接口 0 的备用设置 0 的接口描述符:
Interface Descriptor:
bInterfaceNumber: 0x00
bAlternateSetting: 0x00
bNumEndpoints: 0x01
bInterfaceClass: 0x0E
bInterfaceSubClass: 0x02
bInterfaceProtocol: 0x00
iInterface: 0x02
0x0409: "Microsoft LifeCam VX-5000"
0x0409: "Microsoft LifeCam VX-5000"
在前面的示例中,请注意 bInterfaceNumber 和 bAlternateSetting 字段值。 这些字段包含客户端驱动程序用于激活接口及其备用设置之一的索引值。 对于激活,驱动程序会向 USB 驱动程序堆栈发送选择接口请求。 然后,驱动程序堆栈 (SET INTERFACE) 生成标准控制请求并将其发送到设备。 请注意 bInterfaceClass 字段。 接口描述符或其任何备用设置的描述符指定类代码、子类和协议。 0x0E 的值指示接口适用于视频设备类。 另请注意 iInterface 字段。 该值指示在接口描述符后面追加了两个字符串描述符。 字符串描述符包含 Unicode 说明,这些说明在设备枚举期间用于标识功能。 有关字符串描述符的详细信息,请参阅 USB 字符串描述符。
接口中的每个端点描述设备的单个输入或输出流。 支持不同类型函数流的设备具有多个接口。 支持与一个函数相关的多个流的设备可以支持单个接口上的多个端点。
端点描述符
除默认端点之外,所有类型的端点必须提供端点描述符,以便主机可以获取有关端点的信息。端点描述符包括其地址、类型、方向和端点可以处理的数据量等信息。 到端点的数据传输基于该信息。
以下示例显示了网络摄像头设备的端点描述符:
Endpoint Descriptor:
bEndpointAddress: 0x82 IN
bmAttributes: 0x01
wMaxPacketSize: 0x0080 (128)
bInterval: 0x01
bEndpointAddress 字段指定包含端点编号 (位 3.0) 的唯一端点地址,以及端点方向 (位 7) 。 通过读取上述示例中的这些值,我们可以确定描述符描述了端点编号为 2 的 IN 端点。 bmAttributes 属性指示端点类型为常时等量。 wMaxPacketSizefield 指示端点在单个事务中可以发送或接收的最大字节数。 位 12..11 指示每个微帧可以发送的事务总数。 bInterval 指示端点发送或接收数据的频率。
字符串描述符
设备、配置和接口描述符可能包含对字符串描述符的引用。 本主题介绍如何从设备获取特定字符串描述符。
字符串描述符由其从 1 开始的索引号引用。 字符串描述符包含一个或多个 Unicode 字符串;每个字符串都是将其他字符串翻译成另一种语言。
客户端驱动程序使用 DescriptorType = USB_STRING_DESCRIPTOR_TYPE 的 UsbBuildGetDescriptorRequest 生成请求以获取字符串描述符。 Index 参数指定索引号,LanguageID 参数指定语言 ID, (与 Microsoft Win32 LANGID 值) 相同的值使用。 驱动程序可以请求特殊索引号 0,以确定设备支持的语言 ID。 对于此特殊值,设备返回语言 ID 数组,而不是 Unicode 字符串。
由于字符串描述符包含可变长度的数据,因此驱动程序必须分两个步骤获取它。 首先,驱动程序必须发出请求,传递足够大的数据缓冲区来保存字符串描述符(USB_STRING_DESCRIPTOR结构)的标头。 USB_STRING_DESCRIPTOR 的 bLength 成员指定整个描述符的大小(以字节为单位)。 然后,驱动程序使用大小 为 bLength 的数据缓冲区发出相同的请求。
以下代码演示如何使用语言 ID langID 请求第 i 个字符串描述符:
USB_STRING_DESCRIPTOR USD, *pFullUSD;
UsbBuildGetDescriptorRequest(
pURB, // points to the URB to be filled in
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_STRING_DESCRIPTOR_TYPE,
i, // index of string descriptor
langID, // language ID of string.
&USD, // points to a USB_STRING_DESCRIPTOR.
NULL,
sizeof(USB_STRING_DESCRIPTOR),
NULL
);
pFullUSD = ExAllocatePool(NonPagedPool, USD.bLength);
UsbBuildGetDescriptorRequest(
pURB, // points to the URB to be filled in
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_STRING_DESCRIPTOR_TYPE,
i, // index of string descriptor
langID, // language ID of string
pFullUSD,
NULL,
USD.bLength,
NULL
);
接口关联描述符
USB 接口关联描述符 (IAD) 允许设备对属于某个函数的接口进行分组。 本文介绍客户端驱动程序如何确定设备是否包含函数的 IAD。
通用串行总线规范(修订版 2.0)不支持在单个函数中对复合设备的多个接口进行分组。 但是,USB 设备工作组 (DWG) 创建了允许具有多个接口的函数的 USB 设备类。 USB 实施者论坛 (ECN) 发布了工程更改通知,该通知定义了接口分组机制。
ECN 指定一个 USB 描述符,称为接口关联描述符 (IAD) ,它允许硬件制造商定义接口分组。 最有可能使用 IAD 的设备类包括:
- USB 视频类规范 (类代码 - 0x0E)
- USB 音频类规范 (类代码 - 0x01)
- USB 蓝牙类规范 (类代码 - 0xE0)
在固件中向 Windows 发出 IAD 警报的复合设备
根据通用串行总线规范的指定,复合设备的制造商通常会将值分配给设备类 (bDeviceClass) 、子类 (bDeviceSubClass) 和协议 (bDeviceProtocol) 字段的值。 制造商可以将每个单独的接口与不同的设备类和协议相关联。
USB-IF 核心团队设计了一个特殊的类和协议代码集,用于通知操作系统设备固件中存在一个或多个 IAD。 设备描述符必须具有下表中显示的值,否则操作系统无法正确检测设备的 IAD 或对设备的接口进行分组。
代码值警告不支持 IAD 的 Windows 版本安装正确枚举设备的特殊用途总线驱动程序。 如果没有设备描述符中的这些代码,系统可能无法枚举设备,或者设备可能无法正常工作。
一个设备可以有多个 IAD。 每个 IAD 必须紧挨在 IAD 描述的接口组中的接口之前。
功能类 (bFunctionClass) 、子类 (bFunctionSubclassClass) ,以及 IAD 的协议 (bFunctionProtocol) 字段必须包含描述函数中接口的 USB 设备类指定的值。
IAD 的类和子类字段不需要与 IAD 描述的接口集合中的接口的类和子类字段相匹配。 Microsoft 建议集合的第一个接口具有与 IAD 的类和子类字段匹配的类和子类字段。 下表指示应匹配的字段。
IAD 的 bFirstInterface 字段指示函数中第一个接口的编号。 IAD 的 bInterfaceCount 字段指示接口集合中的接口数。 IAD 接口集合中的接口必须是连续的的接口编号列表中不能有间隙,因此具有第一个接口号的计数足以指定集合中的所有接口。
访问 IAD 的内容
客户端驱动程序无法直接访问 IAD 描述符。 IAD 工程更改通知 (ECN) 指定设备在收到主机软件对配置描述符 (GetDescriptor 配置) 的请求时返回的配置信息中必须包含 IAD。 主机软件无法使用 GetDescriptor 请求直接检索 IAD。
但是,客户端驱动程序可以查询 USB 设备的父驱动程序以获取设备的硬件标识符ID,并且设备的硬件 ID 包含有关 IAD 字段的嵌入信息。