USB WCID设备中特殊字符描述符
WCID全称”Windows Compatible ID,中文名为“Windows兼容ID”。 WCID设备是一种向Windows系统提供额外信息的USB设备,以便于自动安装驱动程序,并在某些情况下允许立即访问。
USB设备驱动的匹配安装一般是以VID/PID进行驱动匹配的,但WCID设备却是根据Compatible ID来进行匹配的。
使用Compatible ID匹配的设备,只要是 WCID 相同的设备,即使是不同厂家生产的,也可以使用相同的驱动,这样也规避了不同厂家相同功能设备的PID问题。
为了支持WCID,设备需要响应一个特殊的字符串描述符请求,并返回一个特殊的字符描串述符。 Windows 系统会根据这个字符描述符中的参数,发起厂商自定义请求来获取设备的 WCID。获取到 WCID 后,根据 WCID进行驱动匹配与安装。
其实Windows中的大部分兼容驱动设备,都是使用的兼容ID(Compatible ID)来进行匹配的。如标准的UVC设备,UAC设备和HID设备。当然系统在进行驱动匹配时会优先匹配硬件ID相同的驱动。
Windows系统中预装的WinUSB驱动支持 WCID 设备,它的兼容ID是“WINUSB”,只要我们设备的 WCID 能被识别为“ WINUSB”就能自动安装上WinUSB驱动,不需要编写INF文件。
WCID的获取条件
- 只有 USB 2.0 或更高版本的设备才能被识别为 WCID。如果 USB 设备描述符的 bcdUSB 字段等于0x0100或0x0110,集线器驱动程序将跳过对 MS OS 描述符的查询并进入“序列号字符串描述符查询”状态
WCID的获取步骤
第一步:获取字符串描述符
USB设备接入USB端口号,Microsoft USB 端口驱动程序 ( usbport.sys) 除了读取标准 USB 描述符,其中包括标准设备、配置、接口和字符串描述符。它还将尝试读取index=0xEE 附加字符串描述符。
该字符串描描述符的结构如下:
值 | 类型 | 描述 |
---|---|---|
0x12 | 字节 | 描述符长度(18 字节) |
0x03 | 字节 | 描述符类型(3 = 字符串) |
0x4D, 0x00, 0x53, 0x00,<br>0x46, 0x00, 0x54, 0x00,<br>0x31, 0x00, 0x30, 0x00,<br>0x30, 0x00 | 7字Unicode 字符串 (LE) | 签名: “MSFT100” |
0x## | 字节 | 供应商代码 |
0x00 | 字节 | 填充 |
当系统正确并获取到此字符串前,在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\[VID+PID+BCD_RELEASE_NUMBER]
的位置创建一个键值为osvc字节的REG_BINARY的2字节密钥。
- 如果0xEE描述符不存在,或者它与 Microsoft 签名 ( “MSFT100”)不匹配,则osvc设置为0x0000,表示该设备不是 WCID设备。
- 如果0xEE描述符存在并且与 Microsoft 操作系统字符串描述符的预期组织相匹配,则oscv设置为0x01##,其中01表示设备满足 MS 操作系统供应商扩展,其中##是供应商代码字节值
以下是 Windows 7 为 WCID 设备(LibusbDotNet 的标准设备,其中VID为0x04D8、 PID为0xFA2E和BCD版本号0x0001)创建的密钥示例:
在上面的示例中,供应商代码为0x20。因此,可以通过检查注册获取设备是否是WCID设备。
第二步:获取设备的兼容ID
WCID不同的兼容ID支持的应用类型不同,所以对应的上层也是不相同的。通过获取兼容ID可以根据该兼容ID类型适配相应的应用。
Windows的兼容ID类型有以下:
- “WINUSB\0\0”
- “LIBUSB0\0”
- “LIBUSBK\0”
由于在第一步中,系统判断oscv字段有效,这时系统会下发一个厂商自定义的USB标准请求用于获取 Compatible ID Feature Descriptor.
1字节 | 1字节 | 2字节 | 2字节 | 2字节 |
---|---|---|---|---|
bmRequestType(1) | bRequest(1) | wValue(2) | wIndex(2) | wLength(2) |
0xC0 | 供应商代码0x## | 0x0000 | 0x0004 | 0x0028 |
返回的兼容ID特性描述符内容如下:
值 | 类型 | 描述 |
---|---|---|
0x28, 0x00, 0x00, 0x00 | DWORD (LE) | Descriptor length (40 bytes) |
0x00, 0x01 | BCD WORD (LE) | Version (‘1.0’) |
0x04, 0x00 | WORD (LE) | Compatibility ID Descriptor index (0x0004) |
0x01 | BYTE | Number of sections (1) |
0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00 | 7 BYTES | Reserved |
0x00 | BYTE | Interface Number (Interface #0) |
0x01 | BYTE | Reserved |
0x57, 0x49, 0x4E, 0x55, 0x53, 0x42, 0x00, 0x00 | 8 BYTES | (NUL-terminated)ASCII String Compatible ID (“WINUSB\0\0”) |
0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00 | 8 BYTES | (NUL-terminated?)ASCII String Sub-Compatible ID(unused) |
0x00, 0x00, 0x00, 0x00,0x00, 0x00 | 6 BYTES | Reserved |
这时,系统会在注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB
的位置存储该设备的兼容ID.如VID_04D8&PID_FA2E
目录下:
兼容ID的格式为USB\MS_COMP_XXXXXXXX
,如这里为USB\MS_COMP_WINUSB
自定义接口GUID
上面Index=4用于获取设备的兼容ID,在windows领域内使用index=5用于获取固件自己定义的设备interface guid.
如果设备只有一个接口,DeviceInterfaceGUID的GUID以NULL为结束
如果有多个接口GUID,则以双NULL为结束。
感谢USB中文网文先的让反馈 https://github.com/pbatard/libwdi/issues/252
如果定义了接口GUID,在注册表中可以显示如下:
如图所述,GUID {F70242C7-FB25-443B-9E7E-A4260F373982}写入了注册表中,我们可以Setup api函数使用该GUID来枚举设备。
WCID描述符符和特性描述符示例
这里使用从http://libusb.info 下载最新的xusb通过可执行文件运行显示信息:
D:\libusb\Win32\Debug\examples>xusb -i 04d8:fa2f
Using libusb v1.0.21.11121
Opening device 04D8:FA2F...
Device properties:
bus number: 2
port path: 3 (from root hub)
speed: 12 Mbit/s (USB FullSpeed)
Reading device descriptor:
length: 18
device class: 0
S/N: 3
VID:PID: 04D8:FA2F
bcdDevice: 0001
iMan:iProd:iSer: 1:2:3
nb confs: 1
Reading BOS descriptor: no descriptor
Reading first configuration descriptor:
nb interfaces: 1
interface[0]: id = 5
interface[0].altsetting[0]: num endpoints = 2
Class.SubClass.Protocol: 00.00.00
endpoint[0].address: 01
max packet size: 0020
polling interval: 00
endpoint[1].address: 81
max packet size: 0020
polling interval: 00
Claiming interface 0...
Reading string descriptors:
String (0x01): "Travis Robinson"
String (0x02): "Benchmark Device"
String (0x03): "LUSBW1"
String (0xEE): "MSFT100 "
Reading Extended Compat ID OS Feature Descriptor (wIndex = 0x0004):
00000000 28 00 00 00 00 01 04 00 01 00 00 00 00 00 00 00 (...............
00000010 00 01 57 49 4e 55 53 42 00 00 00 00 00 00 00 00 ..WINUSB........
00000020 00 00 00 00 00 00 00 00 ........
Reading Extended Properties OS Feature Descriptor (wIndex = 0x0005):
00000000 8e 00 00 00 00 01 05 00 01 00 84 00 00 00 01 00 ................
00000010 00 00 28 00 44 00 65 00 76 00 69 00 63 00 65 00 ..(.D.e.v.i.c.e.
00000020 49 00 6e 00 74 00 65 00 72 00 66 00 61 00 63 00 I.n.t.e.r.f.a.c.
00000030 65 00 47 00 55 00 49 00 44 00 00 00 4e 00 00 00 e.G.U.I.D...N...
00000040 7b 00 46 00 37 00 30 00 32 00 34 00 32 00 43 00 {.F.7.0.2.4.2.C.
00000050 37 00 2d 00 46 00 42 00 32 00 35 00 2d 00 34 00 7.-.F.B.2.5.-.4.
00000060 34 00 33 00 42 00 2d 00 39 00 45 00 37 00 45 00 4.3.B.-.9.E.7.E.
00000070 2d 00 41 00 34 00 32 00 36 00 30 00 46 00 33 00 -.A.4.2.6.0.F.3.
00000080 37 00 33 00 39 00 38 00 32 00 7d 00 00 00 7.3.9.8.2.}...
Releasing interface 0...
Closing device...
参考资料:
- WCID Devices
- WinUSB Device (MSDN)
- Microsoft-Defined USB Descriptors (MSDN)
- Microsoft OS 2.0 Descriptors Specification (MSDN)
- Microsoft OS Descriptors Overview (MSDN)
- How does USB stack enumerate a device? (MSDN)