-
Notifications
You must be signed in to change notification settings - Fork 179
WCID Device
WCID是(Windows Compatible ID)的简称,具备WCID的USB设备在插入Windows电脑上时,Windows会自动为其安装驱动程序。就像键盘、鼠标、U盘这类的设备一样,插上之后就能使用,不需要手动安装驱动程序。CDC串口类设备在Windows上有通用的usbser驱动程序,但是这类设备还需要一个inf文件将设备的VID和PID和驱动对应起来。而具备WCID的设备,不需要编写inf文件就能够在Windows上正确安装并使用。
TeenyDT是一个基于lua开发的USB描述符生成工具,如果设备接口包含WCID相关的内容,能够自动生成相关描述符,TeenyDT源代码。
TeenyDT提供在线试用功能,国外镜像, 国内镜像。在"sample desc"中选择WinUSB或WinUSB20即可生成MS OS 1.0或MS OS 2.0风格的WCID相关描述符。
下文中出现的描述符内容均由TeenyDT自动生成的。
- 在Windows上使用自定义的USB设备,需要开发驱动程序,驱动程序的开发需要专用的工具和环境。驱动的环境配置以及开发的难度,让很多开发者望而却步。一个典型的驱动包含后缀为sys的文件,一个inf文件将硬件设备ID与驱动程序关联起来,还有一些配置需要的动态库和其他文件。
- 对于USB设备,核心操作就是标准的设备请求和对端点进行读写,如果能够写一个通用的驱动将这些通用操作封装起来,并提供应用层的接口,就不需要再写内核驱动了。基于这样的想法,诞生了libusb和WinUSB这样的通用驱动。libusb由社区维护,适用于Windows、Linux多种平台,并提供统一的接口。WinUSB由微软官方提供,预装在操作系统中。这样只需要针对不同的USB设备,只需要开发相应的应用层程序就能使用了。设备和驱动由inf文件进行关联。例如CDC串口类设备,支持WinUSB的STLink调试器,这类设备只需要一个inf文件,就能正确安装并使用了。
- 更进一步,有没有可能连inf也不需要呢。就像HID设备那样,真正的即插即用。微软的WCID提供了这样的解决方案:为一类设备提供通用的驱动,这类设备不再以VID,PID进行匹配,而是以MS_COMP_xxxx进行匹配,凡是能识别为MS_COMP_xxxx的设备就能自动进行驱动安装,不需要inf文件,真正的即插即用。
支持WCID的设备ID以MS_COMP_xxxx进行驱动匹配,而不是通常的VID和PID,如果驱动程序inf文件中的设备ID项包含有对应的MS_COMP_xxxx,则为这样的设备安装对应的驱动。
以WinUSB设备为例而言,其inf文件中包含了名为MS_COMP_WINUSB的设备ID,插入的USB设备如果也被识别为MS_COMP_WINUSB则会为其安装WinUSB驱动。
[Generic.Section.NTamd64]
%USB\MS_COMP_WINUSB.DeviceDesc%=WINUSB,USB\MS_COMP_WINUSB
- 设备端为了支持WCID,需要将设备描述为支持USB2.0,即将设备描述符中的bcdUSBVersion字段设置为0x200,设备描述符完整内容:
__ALIGN(2) const uint8_t TINYUSB_DeviceDescriptor [18] = {
0x12, /* bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
0x00, 0x02, /* bcdUSB */
0x00, /* bDeviceClass */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x08, /* bMaxPacketSize */
LOBYTE(TINYUSB_VID), HIBYTE(TINYUSB_VID), /* idVendor */
LOBYTE(TINYUSB_PID), HIBYTE(TINYUSB_PID), /* idProduct */
0x00, 0x01, /* bcdDevice */
0x01, /* iManufacture */
0x02, /* iProduct */
0x03, /* iSerial */
0x01, /* bNumConfigurations */
};
- 设备端响应序号为0xee的字符描述符请求,字符内容为“MSFT100\x17”,其中\x17可以为其他值,稍后会用到,都以0x17为例。设备响应此请求通知系统这是一个支持WCID的设备,后续可以用0x17来获取更多信息。设备字符描述符完整内容为:
const uint8_t WCID_StringDescriptor_MSOS [18]= {
0x12, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
'M', 0x00, /* wcChar0 */
'S', 0x00, /* wcChar1 */
'F', 0x00, /* wcChar2 */
'T', 0x00, /* wcChar3 */
'1', 0x00, /* wcChar4 */
'0', 0x00, /* wcChar5 */
'0', 0x00, /* wcChar6 */
0x17, /* bVendorCode */
0x00, /* bReserved */
};
- 设备端响应request号为0x17,序号为4的厂商请求,请求内容:
Format | bmRequestType | bRequest | wValue | wIndex | wLength | data |
---|---|---|---|---|---|---|
Binary | 11000000b | 00010111b | 0b | 0100b | length | descriptor data |
Hex | 0xc0 | 0x17 | 0x00 | 0x04 | length | descriptor data |
如果设备只有一个WCID接口,响应内容如下:
const uint8_t TINYUSB_WCIDDescriptor [40] = {
0x28, 0x00, 0x00, 0x00, /* dwLength */
0x00, 0x01, /* bcdVersion */
0x04, 0x00, /* wIndex */
0x01, /* bCount */
0,0,0,0,0,0,0, /* Reserved */
/* WCID Function */
0x00, /* bFirstInterfaceNumber */
0x01, /* bReserved */
/* CID */
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
/* sub CID */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0,0,0,0,0,0, /* Reserved */
};
如果设备有两个WCID接口,响应内容如下:
const uint8_t TINYUSB_WCIDDescriptor [64] = {
0x40, 0x00, 0x00, 0x00, /* dwLength */
0x00, 0x01, /* bcdVersion */
0x04, 0x00, /* wIndex */
0x02, /* bCount */
0,0,0,0,0,0,0, /* Reserved */
/* WCID Function */
0x00, /* bFirstInterfaceNumber */
0x01, /* bReserved */
/* CID */
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
/* sub CID */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0,0,0,0,0,0, /* Reserved */
/* WCID Function */
0x01, /* bFirstInterfaceNumber */
0x01, /* bReserved */
/* CID */
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
/* sub CID */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0,0,0,0,0,0, /* Reserved */
};
- 设备端响应request号为0x17,序号为5的厂商请求,请求内容:
Format | bmRequestType | bRequest | wValue | wIndex | wLength | data |
---|---|---|---|---|---|---|
Binary | 11000000b | 00010111b | 0b | 0101b | length | descriptor data |
Hex | 0xc0 | 0x17 | 0x00 | 0x05 | length | descriptor data |
如果设备只有一个WCID接口,响应内容如下:
const uint8_t TINYUSB_WCIDProperties [142] = {
0x8e, 0x00, 0x00, 0x00, /* dwLength */
0x00, 0x01, /* bcdVersion */
0x05, 0x00, /* wIndex */
0x01, 0x00, /* wCount */
/*WCID property field */
/* DeviceInterfaceGUID =
{1d2e834c-faea-0d8e-830a-4cba5a1ab804} */
0x84, 0x00, 0x00, 0x00, /* dwSize */
0x01, 0x00, 0x00, 0x00, /* dwPropertyDataType */
0x28, 0x00, /* wPropertyNameLength */
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00,
'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00,
't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00,
'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00,
'U', 0x00, 'I', 0x00, 'D', 0x00, 0x00, 0x00,
0x4e, 0x00, 0x00, 0x00, /* dwPropertyDataLength */
'{', 0x00, '1', 0x00, 'd', 0x00, '2', 0x00,
'e', 0x00, '8', 0x00, '3', 0x00, '4', 0x00,
'c', 0x00, '-', 0x00, 'f', 0x00, 'a', 0x00,
'e', 0x00, 'a', 0x00, '-', 0x00, '0', 0x00,
'd', 0x00, '8', 0x00, 'e', 0x00, '-', 0x00,
'8', 0x00, '3', 0x00, '0', 0x00, 'a', 0x00,
'-', 0x00, '4', 0x00, 'c', 0x00, 'b', 0x00,
'a', 0x00, '5', 0x00, 'a', 0x00, '1', 0x00,
'a', 0x00, 'b', 0x00, '8', 0x00, '0', 0x00,
'4', 0x00, '}', 0x00, 0x00, 0x00,
};
如果设备有两个个WCID接口,通过Setup包中的wValue值来区分是哪一个接口,返回相应的内容。
在Win8.1之后,微软使用了新的协议来支持WinUSB这类的设备。将设备描述符中的bcdUSB设置为0x210,这个时候windows会通过15号请求来获取Binary Object Store描述符。在这个描述符中返回一些信息,告诉操作系统我们的设备支持MS OS 2.0描述符。然后再通过序列号7的厂商请求来获取MS OS 2.0 descriptor set,在这个描述符中将设备的兼容信息以及接口参数统一上报给系统。目前TeenyUSB已经增加了对MS OS 2.0 WinUSB设备的支持,只需将bcdUSB设置为0x210就能启用MS OS 2.0描述符,同时原来的1.0版本的描述符将会屏蔽掉以减少代码量。
const uint8_t BULK_WCIDBOS [33] __ALIGN_END = {
0x05, /* bLength */
USB_DESC_TYPE_BOS, /* bDescriptorType */
0x21, 0x00, /* wTotalLength */
0x01, /* bNumDeviceCaps */
/* WCID DEVICE_CAPABILITY descriptor */
0x1c, /* bLength */
0x10, /* bDescriptorType */
0x05, /* bDevCapabilityType */
0x00, /* bReserved */
/* WCID WinUSB CAPABILITY descriptor */
0xdf, 0x60, 0xdd, 0xd8, 0x89, 0x45, 0xc7, 0x4c, /* PlatformCapabilityUUID */
0x9c, 0xd2, 0x65, 0x9d, 0x9e, 0x64, 0x8a, 0x9f, /* PlatformCapabilityUUID */
0x00, 0x00, 0x03, 0x06, /* dwWindowsVersion */
LOBYTE(BULK_WCID_DESC_SET_SIZE), HIBYTE(BULK_WCID_DESC_SET_SIZE),/* wDescriptorSetTotalLength */
WCID_VENDOR_CODE, /* bVendorCode */
0x00, /* bAltEnumCode */
};
const uint8_t BULK_WCIDDescriptorSet [162] __ALIGN_END = {
0x0a, 0x00, /* wLength */
0x00, 0x00, /* wDescriptorType */
0x00, 0x00, 0x03, 0x06, /* dwWindowsVersion */
0xa2, 0x00, /* wDescriptorSetTotalLength */
/* WCID WinUSB compatible ID */
0x14, 0x00, /* wLength */
0x03, 0x00, /* wDescriptorType */
/* CID */
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
/* sub CID */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* WCID WinUSB registry value */
/* DeviceInterfaceGUIDs = {88bae032-5a81-49f0-bc3d-a4ff138216d6} */
0x84, 0x00, /* wLength */
0x04, 0x00, /* wDescriptorType */
0x07, 0x00, /* wPropertyDataType */
0x2a, 0x00, /* wPropertyNameLength */
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00,
'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00,
't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00,
'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00,
'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00,
0x00, 0x00,
0x50, 0x00, /* wPropertyDataLength */
'{', 0x00, '8', 0x00, '8', 0x00, 'b', 0x00,
'a', 0x00, 'e', 0x00, '0', 0x00, '3', 0x00,
'2', 0x00, '-', 0x00, '5', 0x00, 'a', 0x00,
'8', 0x00, '1', 0x00, '-', 0x00, '4', 0x00,
'9', 0x00, 'f', 0x00, '0', 0x00, '-', 0x00,
'b', 0x00, 'c', 0x00, '3', 0x00, 'd', 0x00,
'-', 0x00, 'a', 0x00, '4', 0x00, 'f', 0x00,
'f', 0x00, '1', 0x00, '3', 0x00, '8', 0x00,
'2', 0x00, '1', 0x00, '6', 0x00, 'd', 0x00,
'6', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00,
};
const uint8_t BULK_WCIDDescriptorSet [490] __ALIGN_END = {
0x0a, 0x00, /* wLength */
0x00, 0x00, /* wDescriptorType */
0x00, 0x00, 0x03, 0x06, /* dwWindowsVersion */
0xea, 0x01, /* wDescriptorSetTotalLength */
/* Microsoft OS 2.0 function subset header */
0x08, 0x00, /* wLength */
0x02, 0x00, /* wDescriptorType */
0x00, /* bFirstInterface */
0x00, /* bReserved */
0xa0, 0x00, /* wSubsetLength */
/* WCID WinUSB compatible ID */
0x14, 0x00, /* wLength */
0x03, 0x00, /* wDescriptorType */
/* CID */
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
/* sub CID */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* WCID WinUSB registry value */
/* DeviceInterfaceGUIDs = {88bae032-5a81-49f0-bc3d-a4ff138216d6} */
0x84, 0x00, /* wLength */
0x04, 0x00, /* wDescriptorType */
0x07, 0x00, /* wPropertyDataType */
0x2a, 0x00, /* wPropertyNameLength */
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00,
'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00,
't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00,
'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00,
'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00,
0x00, 0x00,
0x50, 0x00, /* wPropertyDataLength */
'{', 0x00, '8', 0x00, '8', 0x00, 'b', 0x00,
'a', 0x00, 'e', 0x00, '0', 0x00, '3', 0x00,
'2', 0x00, '-', 0x00, '5', 0x00, 'a', 0x00,
'8', 0x00, '1', 0x00, '-', 0x00, '4', 0x00,
'9', 0x00, 'f', 0x00, '0', 0x00, '-', 0x00,
'b', 0x00, 'c', 0x00, '3', 0x00, 'd', 0x00,
'-', 0x00, 'a', 0x00, '4', 0x00, 'f', 0x00,
'f', 0x00, '1', 0x00, '3', 0x00, '8', 0x00,
'2', 0x00, '1', 0x00, '6', 0x00, 'd', 0x00,
'6', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00,
/* Microsoft OS 2.0 function subset header */
0x08, 0x00, /* wLength */
0x02, 0x00, /* wDescriptorType */
0x01, /* bFirstInterface */
0x00, /* bReserved */
0xa0, 0x00, /* wSubsetLength */
/* WCID WinUSB compatible ID */
0x14, 0x00, /* wLength */
0x03, 0x00, /* wDescriptorType */
/* CID */
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
/* sub CID */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* WCID WinUSB registry value */
/* DeviceInterfaceGUIDs = {88bae032-5a81-49f0-bc3d-a4ff138216d6} */
0x84, 0x00, /* wLength */
0x04, 0x00, /* wDescriptorType */
0x07, 0x00, /* wPropertyDataType */
0x2a, 0x00, /* wPropertyNameLength */
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00,
'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00,
't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00,
'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00,
'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00,
0x00, 0x00,
0x50, 0x00, /* wPropertyDataLength */
'{', 0x00, '8', 0x00, '8', 0x00, 'b', 0x00,
'a', 0x00, 'e', 0x00, '0', 0x00, '3', 0x00,
'2', 0x00, '-', 0x00, '5', 0x00, 'a', 0x00,
'8', 0x00, '1', 0x00, '-', 0x00, '4', 0x00,
'9', 0x00, 'f', 0x00, '0', 0x00, '-', 0x00,
'b', 0x00, 'c', 0x00, '3', 0x00, 'd', 0x00,
'-', 0x00, 'a', 0x00, '4', 0x00, 'f', 0x00,
'f', 0x00, '1', 0x00, '3', 0x00, '8', 0x00,
'2', 0x00, '1', 0x00, '6', 0x00, 'd', 0x00,
'6', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00,
/* Microsoft OS 2.0 function subset header */
0x08, 0x00, /* wLength */
0x02, 0x00, /* wDescriptorType */
0x02, /* bFirstInterface */
0x00, /* bReserved */
0xa0, 0x00, /* wSubsetLength */
/* WCID WinUSB compatible ID */
0x14, 0x00, /* wLength */
0x03, 0x00, /* wDescriptorType */
/* CID */
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
/* sub CID */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* WCID WinUSB registry value */
/* DeviceInterfaceGUIDs = {88bae032-5a81-49f0-bc3d-a4ff138216d6} */
0x84, 0x00, /* wLength */
0x04, 0x00, /* wDescriptorType */
0x07, 0x00, /* wPropertyDataType */
0x2a, 0x00, /* wPropertyNameLength */
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00,
'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00,
't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00,
'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00,
'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00,
0x00, 0x00,
0x50, 0x00, /* wPropertyDataLength */
'{', 0x00, '8', 0x00, '8', 0x00, 'b', 0x00,
'a', 0x00, 'e', 0x00, '0', 0x00, '3', 0x00,
'2', 0x00, '-', 0x00, '5', 0x00, 'a', 0x00,
'8', 0x00, '1', 0x00, '-', 0x00, '4', 0x00,
'9', 0x00, 'f', 0x00, '0', 0x00, '-', 0x00,
'b', 0x00, 'c', 0x00, '3', 0x00, 'd', 0x00,
'-', 0x00, 'a', 0x00, '4', 0x00, 'f', 0x00,
'f', 0x00, '1', 0x00, '3', 0x00, '8', 0x00,
'2', 0x00, '1', 0x00, '6', 0x00, 'd', 0x00,
'6', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00,
};