Skip to content

WCID Device

XToolBox edited this page Nov 14, 2019 · 8 revisions

目录 Table Of Contents

什么是WCID免驱动设备?

WCID是(Windows Compatible ID)的简称,具备WCID的USB设备在插入Windows电脑上时,Windows会自动为其安装驱动程序。就像键盘、鼠标、U盘这类的设备一样,插上之后就能使用,不需要手动安装驱动程序。CDC串口类设备在Windows上有通用的usbser驱动程序,但是这类设备还需要一个inf文件将设备的VID和PID和驱动对应起来。而具备WCID的设备,不需要编写inf文件就能够在Windows上正确安装并使用。

如何生成WCID描述符?

TeenyDT是一个基于lua开发的USB描述符生成工具,如果设备接口包含WCID相关的内容,能够自动生成相关描述符,TeenyDT源代码

TeenyDT提供在线试用功能,国外镜像, 国内镜像。在"sample desc"中选择WinUSB或WinUSB20即可生成MS OS 1.0或MS OS 2.0风格的WCID相关描述符。

下文中出现的描述符内容均由TeenyDT自动生成的。

由繁至简的驱动开发

  1. 在Windows上使用自定义的USB设备,需要开发驱动程序,驱动程序的开发需要专用的工具和环境。驱动的环境配置以及开发的难度,让很多开发者望而却步。一个典型的驱动包含后缀为sys的文件,一个inf文件将硬件设备ID与驱动程序关联起来,还有一些配置需要的动态库和其他文件。
  2. 对于USB设备,核心操作就是标准的设备请求和对端点进行读写,如果能够写一个通用的驱动将这些通用操作封装起来,并提供应用层的接口,就不需要再写内核驱动了。基于这样的想法,诞生了libusb和WinUSB这样的通用驱动。libusb由社区维护,适用于Windows、Linux多种平台,并提供统一的接口。WinUSB由微软官方提供,预装在操作系统中。这样只需要针对不同的USB设备,只需要开发相应的应用层程序就能使用了。设备和驱动由inf文件进行关联。例如CDC串口类设备,支持WinUSB的STLink调试器,这类设备只需要一个inf文件,就能正确安装并使用了。
  3. 更进一步,有没有可能连inf也不需要呢。就像HID设备那样,真正的即插即用。微软的WCID提供了这样的解决方案:为一类设备提供通用的驱动,这类设备不再以VID,PID进行匹配,而是以MS_COMP_xxxx进行匹配,凡是能识别为MS_COMP_xxxx的设备就能自动进行驱动安装,不需要inf文件,真正的即插即用。

WCID设备驱动识别与安装

支持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

设备端

  1. 设备端为了支持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 */
};
  1. 设备端响应序号为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 */
};
  1. 设备端响应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 */
};
  1. 设备端响应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值来区分是哪一个接口,返回相应的内容。

支持MS OS 2.0的WCID设备

在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版本的描述符将会屏蔽掉以减少代码量。

BOS描述符示例

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 */
};

MS OS 2.0 descriptor set示例,普通设备

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, 
};

MS OS 2.0 descriptor set示例,复合设备

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, 
};

参考文档