先说结论:
1、只要能枚举成功为bulk设备,那么就能在设备管理器里面,手动更新驱动程序,强制选择为WINUSB设备即可!不一定要识别为Winusb设备,Win10通用。
2、要识别为Win USB设备,需要枚举时增加一些描述符,windows才能自动安装驱动,而无需强制选择。有2个版本增加描述符方法,这里讲1.0版本,下面重点讲讲单片机MCU如何自动识别为WinUSB
A,定义描述符,具体看这里:使用微软系统描述符1.0制作免驱动自定义USB设备
/* 下面是WINUSB所需的描述符 https://blog.csdn.net/weixin_46753805/article/details/116200729 * * 会索引0xEE处的OS字符串描述符,确认设备是否支持WCID,若回复内容为MSFT100则说明该设备支持WCID,后续才会继续获取兼容ID特征描述等; 获取兼容ID特征描述符,回复兼容信息为WinUSB设备; 获取兼容ID后,系统会根据兼容ID的情况请求属性描述符,对于WinUSB设备需要注册设备接口GUID; * * * */ // 当系统正确并获取到此字符串前,在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\[VID+PID+BCD_RELEASE_NUMBER]的位置创建一个键值为osvc字节的REG_BINARY的2字节密钥。 // "MSFT100" : index : 0xEE : langId : 0x0000 const uint8_t OS_StringDescritpor[ ] = { 0x12, 0x03, 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0, BMS_VENDORCODE, 0 }; // 会在注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB的位置存储该设备的兼容ID.如VID_04D8&PID_FA2E // "WINUSB\0\0" : wIndex : 0x0004 const uint8_t WINUSB_ExtendedCompatId_Descritpor[ ] = { // WCID descriptor = 16byte 0x28, 0x00, 0x00, 0x00, // dwLength 0x00, 0x01, // bcdVersion 0x04, 0x00, // wIndex=4用于获取设备的兼容ID,在windows领域内使用index=5用于获取固件自己定义的设备interface guid 0x01, // bCount 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved[7] // WCID function descriptor 0x00, // bFirstInterfaceNumber 0x01, // RESERVED ( 0x01 ) 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // compactiableID[8] 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subCompactiableID[8] 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Reserved[6] }; // 在 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\Vidxxx&&Pidxxx\LUSBW1\Device Parameters // L"DeviceInterfaceGUID" : wIndex = 0x0005 // L"{12345678-1234-1234-1234-123456789ABC}"(可以换自己的GUID) const uint8_t WINUSB_ExtendedProperty_InterfaceGUID_Descritpor[ ] = { // WCID property descriptor = 10 byte 0x8E, 0x00, 0x00, 0x00, // dwTotalSize = Header + All sections 0x00, 0x01, // bcdVersion 0x05, 0x00, // wIndex=5用于获取固件自己定义的设备interface guid. 0x01, 0x00, // wCount 0x84, 0x00, 0x00, 0x00, // dwSize -- this section 0x01, 0x00, 0x00, 0x00, // dwPropertyDataType 0x28, 0x00, // wPropertyNameLength 'D', 0x00, 'e', 0x00, // bProperytName : WCHAR : L"DeviceInterfaceGUID" 'v', 0x00, 'i', 0x00, // bProperytName : WCHAR 'c', 0x00, 'e', 0x00, // bProperytName : WCHAR 'I', 0x00, 'n', 0x00, // bProperytName : WCHAR 't', 0x00, 'e', 0x00, // bProperytName : WCHAR 'r', 0x00, 'f', 0x00, // bProperytName : WCHAR 'a', 0x00, 'c', 0x00, // bProperytName : WCHAR 'e', 0x00, 'G', 0x00, // bProperytName : WCHAR 'U', 0x00, 'I', 0x00, // bProperytName : WCHAR 'D', 0x00, 0x00, 0x00, // bProperytName : WCHAR 0x4E, 0x00, 0x00, 0x00, // dwPropertyDataLength : 78 Bytes = 0x0000004E '{', 0x00, '1', 0x00, // bPropertyData : WCHAR : L"{12345678-1234-1234-1234-123456789ABC}" '2', 0x00, '3', 0x00, // bPropertyData '4', 0x00, '5', 0x00, // bPropertyData '6', 0x00, '7', 0x00, // bPropertyData '8', 0x00, '-', 0x00, // bPropertyData '1', 0x00, '2', 0x00, // bPropertyData '3', 0x00, '4', 0x00, // bPropertyData '-', 0x00, '1', 0x00, // bPropertyData '3', 0x00, '4', 0x00, // bPropertyData '4', 0x00, '-', 0x00, // bPropertyData '1', 0x00, '2', 0x00, // bPropertyData '3', 0x00, '4', 0x00, // bPropertyData '-', 0x00, '1', 0x00, // bPropertyData '2', 0x00, '3', 0x00, // bPropertyData '4', 0x00, '5', 0x00, // bPropertyData '6', 0x00, '7', 0x00, // bPropertyData '8', 0x00, '9', 0x00, // bPropertyData 'A', 0x00, 'B', 0x00, // bPropertyData 'C', 0x00, '}', 0x00, // bPropertyData 0x00, 0x00 // bPropertyData };
现在的问题就是怎么在单片机端,把这些描述符给他上报上去。
B、在获取字符串那里增加index = 0xee分支,把OS_StringDescritpor上报上去
C、在非标准setup那里把0xC0+VENDORCODE,以及0xC1+VENDORCODE 分别上报WINUSB_ExtendedCompatId_Descritpor以及
WINUSB_ExtendedProperty_InterfaceGUID_Descritpor
Windows在每个流程会最少请求2次,第一次先请求前面0x10个字节,然后知道要传0x28和0x8E,第二次才请求实际长的数据
D、如果包长大于端点0的64字节,那么第二个包要到token_in分支进行传输!否则主机获取不到0x8E个字节就会报xact error错误!
完整的传输截图如下:
难点在ep0分包传输,以及在正确的位置上报描述符!
E、要Windows每次发出0xC1请求,需要把这个Device Parameters节点删除,否则会认为有数据而不会发0xC1请求!0xC0会每次发,只要0xEE上报有数据的话。