From e9d9fcde04411001ba8dff07b512fdc46ce13e47 Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Sun, 22 Apr 2018 16:08:12 +1000 Subject: Add MS OS Compatibility descriptors to RNDIS demos for driverless install on Windows. --- .../Device/ClassDriver/RNDISEthernet/Descriptors.c | 51 +++++++++++++++++++++- .../Device/ClassDriver/RNDISEthernet/Descriptors.h | 22 ++++++++++ .../ClassDriver/RNDISEthernet/RNDISEthernet.c | 3 ++ Demos/Device/LowLevel/RNDISEthernet/Descriptors.c | 51 +++++++++++++++++++++- Demos/Device/LowLevel/RNDISEthernet/Descriptors.h | 22 ++++++++++ .../Device/LowLevel/RNDISEthernet/RNDISEthernet.c | 3 ++ 6 files changed, 148 insertions(+), 4 deletions(-) (limited to 'Demos') diff --git a/Demos/Device/ClassDriver/RNDISEthernet/Descriptors.c b/Demos/Device/ClassDriver/RNDISEthernet/Descriptors.c index 494150349..8e709cee9 100644 --- a/Demos/Device/ClassDriver/RNDISEthernet/Descriptors.c +++ b/Demos/Device/ClassDriver/RNDISEthernet/Descriptors.c @@ -46,7 +46,7 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = { .Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device}, - .USBSpecification = VERSION_BCD(1,1,0), + .USBSpecification = VERSION_BCD(2,0,0), .Class = CDC_CSCP_CDCClass, .SubClass = CDC_CSCP_NoSpecificSubclass, .Protocol = CDC_CSCP_NoSpecificProtocol, @@ -55,7 +55,7 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = .VendorID = 0x03EB, .ProductID = 0x204C, - .ReleaseNumber = VERSION_BCD(0,0,1), + .ReleaseNumber = VERSION_BCD(0,0,2), .ManufacturerStrIndex = STRING_ID_Manufacturer, .ProductStrIndex = STRING_ID_Product, @@ -192,6 +192,32 @@ const USB_Descriptor_String_t PROGMEM ManufacturerString = USB_STRING_DESCRIPTOR */ const USB_Descriptor_String_t PROGMEM ProductString = USB_STRING_DESCRIPTOR(L"LUFA RNDIS CDC Demo"); +/** Microsoft OS Compatibility string descriptor. This is a special string descriptor that Microsoft based OS hosts + * will query at string descriptor ID 0xEE on initial enumeration, to test if the device supports the Microsoft OS + * Compatibility descriptor extensions (used to give the host additional information on the device's general class + * compatibility for driver-less installation). + */ +const USB_Descriptor_String_t PROGMEM MSConpatibilityString = USB_STRING_DESCRIPTOR_ARRAY('M','S','F','T','1','0','0', VENDOR_REQUEST_ID_MS_COMPAT); + +/** Microsoft OS Compatibility 1.0 descriptor. This is a special descriptor returned by the device on vendor request + * from the host, giving the OS additional compatibility information. This allows the host to automatically install + * the appropriate driver for various devices which share a common USB class (in this case RNDIS, which uses the + * CDC-ACM class usually used by virtual to serial adapters). + */ +const USB_Descriptor_MSCompatibility_t PROGMEM MSCompatibilityDescriptor = + { + .dwLength = sizeof(USB_Descriptor_MSCompatibility_t), + .bcdVersion = VERSION_BCD(1,0,0), + .wIndex = 4, + .bCount = 1, + .bReserved = { 0 }, + .bFirstInterfaceNumber = INTERFACE_ID_CDC_CCI, + .bReserved2 = 1, // Must always be 1 according to spec + .compatibleID = "RNDIS", + .subCompatibleID = "5162001", + .bReserved3 = { 0 }, + }; + /** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" * documentation) by the application code so that the address and size of a requested descriptor can be given * to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function @@ -233,6 +259,10 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, Address = &ProductString; Size = pgm_read_byte(&ProductString.Header.Size); break; + case STRING_ID_MS_Compat: + Address = &MSConpatibilityString; + Size = pgm_read_byte(&MSConpatibilityString.Header.Size); + break; } break; @@ -242,3 +272,20 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, return Size; } +/** Sends the special Microsoft OS Compatibility Descriptor to the host PC, if + * the host is requesting it. + */ +void CheckIfMSCompatibilityDescriptorRequest(void) +{ + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_VENDOR | REQREC_DEVICE)) + { + if (USB_ControlRequest.bRequest == VENDOR_REQUEST_ID_MS_COMPAT) + { + Endpoint_ClearSETUP(); + + /* Write the OS compatibility descriptor to the control endpoint */ + Endpoint_Write_Control_PStream_LE(&MSCompatibilityDescriptor, sizeof(MSCompatibilityDescriptor)); + Endpoint_ClearOUT(); + } + } +} diff --git a/Demos/Device/ClassDriver/RNDISEthernet/Descriptors.h b/Demos/Device/ClassDriver/RNDISEthernet/Descriptors.h index 082f44afc..56a3acd23 100644 --- a/Demos/Device/ClassDriver/RNDISEthernet/Descriptors.h +++ b/Demos/Device/ClassDriver/RNDISEthernet/Descriptors.h @@ -59,6 +59,10 @@ /** Size in bytes of the CDC data IN and OUT endpoints. */ #define CDC_TXRX_EPSIZE 64 + /** Vendor request (0-255) the host should issue to retrieve the + * Microsoft OS Compatibility Descriptors. */ + #define VENDOR_REQUEST_ID_MS_COMPAT 0x01 + /* Type Defines: */ /** Type define for the device configuration descriptor structure. This must be defined in the * application code, as the configuration descriptor contains several sub-descriptors which @@ -81,6 +85,21 @@ USB_Descriptor_Endpoint_t RNDIS_DataInEndpoint; } USB_Descriptor_Configuration_t; + /** Type define for a Microsoft OS Compatibility 1.0 descriptor. */ + typedef struct + { + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint8_t bCount; + uint8_t bReserved[7]; + uint8_t bFirstInterfaceNumber; + uint8_t bReserved2; + char compatibleID[8]; + char subCompatibleID[8]; + uint8_t bReserved3[6]; + } USB_Descriptor_MSCompatibility_t; + /** Enum for the device interface descriptor IDs within the device. Each interface descriptor * should have a unique ID index associated with it, which can be used to refer to the * interface from other descriptors. @@ -100,6 +119,7 @@ STRING_ID_Language = 0, /**< Supported Languages string descriptor ID (must be zero) */ STRING_ID_Manufacturer = 1, /**< Manufacturer string ID */ STRING_ID_Product = 2, /**< Product string ID */ + STRING_ID_MS_Compat = 0xEE, /**< MS OS Compatibility string descriptor ID (magic value set by Microsoft) */ }; /* Function Prototypes: */ @@ -108,5 +128,7 @@ const void** const DescriptorAddress) ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); + void CheckIfMSCompatibilityDescriptorRequest(void); + #endif diff --git a/Demos/Device/ClassDriver/RNDISEthernet/RNDISEthernet.c b/Demos/Device/ClassDriver/RNDISEthernet/RNDISEthernet.c index f963d48e1..cfe90ccd7 100644 --- a/Demos/Device/ClassDriver/RNDISEthernet/RNDISEthernet.c +++ b/Demos/Device/ClassDriver/RNDISEthernet/RNDISEthernet.c @@ -174,6 +174,9 @@ void EVENT_USB_Device_ConfigurationChanged(void) /** Event handler for the library USB Control Request reception event. */ void EVENT_USB_Device_ControlRequest(void) { + /* Send MS OS Compatibility descriptor if requested by the host. */ + CheckIfMSCompatibilityDescriptorRequest(); + RNDIS_Device_ProcessControlRequest(&Ethernet_RNDIS_Interface); } diff --git a/Demos/Device/LowLevel/RNDISEthernet/Descriptors.c b/Demos/Device/LowLevel/RNDISEthernet/Descriptors.c index 494150349..8e709cee9 100644 --- a/Demos/Device/LowLevel/RNDISEthernet/Descriptors.c +++ b/Demos/Device/LowLevel/RNDISEthernet/Descriptors.c @@ -46,7 +46,7 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = { .Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device}, - .USBSpecification = VERSION_BCD(1,1,0), + .USBSpecification = VERSION_BCD(2,0,0), .Class = CDC_CSCP_CDCClass, .SubClass = CDC_CSCP_NoSpecificSubclass, .Protocol = CDC_CSCP_NoSpecificProtocol, @@ -55,7 +55,7 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = .VendorID = 0x03EB, .ProductID = 0x204C, - .ReleaseNumber = VERSION_BCD(0,0,1), + .ReleaseNumber = VERSION_BCD(0,0,2), .ManufacturerStrIndex = STRING_ID_Manufacturer, .ProductStrIndex = STRING_ID_Product, @@ -192,6 +192,32 @@ const USB_Descriptor_String_t PROGMEM ManufacturerString = USB_STRING_DESCRIPTOR */ const USB_Descriptor_String_t PROGMEM ProductString = USB_STRING_DESCRIPTOR(L"LUFA RNDIS CDC Demo"); +/** Microsoft OS Compatibility string descriptor. This is a special string descriptor that Microsoft based OS hosts + * will query at string descriptor ID 0xEE on initial enumeration, to test if the device supports the Microsoft OS + * Compatibility descriptor extensions (used to give the host additional information on the device's general class + * compatibility for driver-less installation). + */ +const USB_Descriptor_String_t PROGMEM MSConpatibilityString = USB_STRING_DESCRIPTOR_ARRAY('M','S','F','T','1','0','0', VENDOR_REQUEST_ID_MS_COMPAT); + +/** Microsoft OS Compatibility 1.0 descriptor. This is a special descriptor returned by the device on vendor request + * from the host, giving the OS additional compatibility information. This allows the host to automatically install + * the appropriate driver for various devices which share a common USB class (in this case RNDIS, which uses the + * CDC-ACM class usually used by virtual to serial adapters). + */ +const USB_Descriptor_MSCompatibility_t PROGMEM MSCompatibilityDescriptor = + { + .dwLength = sizeof(USB_Descriptor_MSCompatibility_t), + .bcdVersion = VERSION_BCD(1,0,0), + .wIndex = 4, + .bCount = 1, + .bReserved = { 0 }, + .bFirstInterfaceNumber = INTERFACE_ID_CDC_CCI, + .bReserved2 = 1, // Must always be 1 according to spec + .compatibleID = "RNDIS", + .subCompatibleID = "5162001", + .bReserved3 = { 0 }, + }; + /** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" * documentation) by the application code so that the address and size of a requested descriptor can be given * to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function @@ -233,6 +259,10 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, Address = &ProductString; Size = pgm_read_byte(&ProductString.Header.Size); break; + case STRING_ID_MS_Compat: + Address = &MSConpatibilityString; + Size = pgm_read_byte(&MSConpatibilityString.Header.Size); + break; } break; @@ -242,3 +272,20 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, return Size; } +/** Sends the special Microsoft OS Compatibility Descriptor to the host PC, if + * the host is requesting it. + */ +void CheckIfMSCompatibilityDescriptorRequest(void) +{ + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_VENDOR | REQREC_DEVICE)) + { + if (USB_ControlRequest.bRequest == VENDOR_REQUEST_ID_MS_COMPAT) + { + Endpoint_ClearSETUP(); + + /* Write the OS compatibility descriptor to the control endpoint */ + Endpoint_Write_Control_PStream_LE(&MSCompatibilityDescriptor, sizeof(MSCompatibilityDescriptor)); + Endpoint_ClearOUT(); + } + } +} diff --git a/Demos/Device/LowLevel/RNDISEthernet/Descriptors.h b/Demos/Device/LowLevel/RNDISEthernet/Descriptors.h index 31c56a00b..8f407fc14 100644 --- a/Demos/Device/LowLevel/RNDISEthernet/Descriptors.h +++ b/Demos/Device/LowLevel/RNDISEthernet/Descriptors.h @@ -59,6 +59,10 @@ /** Size in bytes of the CDC device-to-host notification IN endpoint. */ #define CDC_NOTIFICATION_EPSIZE 8 + /** Vendor request (0-255) the host should issue to retrieve the + * Microsoft OS Compatibility Descriptors. */ + #define VENDOR_REQUEST_ID_MS_COMPAT 0x01 + /* Type Defines: */ /** Type define for the device configuration descriptor structure. This must be defined in the * application code, as the configuration descriptor contains several sub-descriptors which @@ -81,6 +85,21 @@ USB_Descriptor_Endpoint_t RNDIS_DataInEndpoint; } USB_Descriptor_Configuration_t; + /** Type define for a Microsoft OS Compatibility 1.0 descriptor. */ + typedef struct + { + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint8_t bCount; + uint8_t bReserved[7]; + uint8_t bFirstInterfaceNumber; + uint8_t bReserved2; + char compatibleID[8]; + char subCompatibleID[8]; + uint8_t bReserved3[6]; + } USB_Descriptor_MSCompatibility_t; + /** Enum for the device interface descriptor IDs within the device. Each interface descriptor * should have a unique ID index associated with it, which can be used to refer to the * interface from other descriptors. @@ -100,6 +119,7 @@ STRING_ID_Language = 0, /**< Supported Languages string descriptor ID (must be zero) */ STRING_ID_Manufacturer = 1, /**< Manufacturer string ID */ STRING_ID_Product = 2, /**< Product string ID */ + STRING_ID_MS_Compat = 0xEE, /**< MS OS Compatibility string descriptor ID (magic value set by Microsoft) */ }; /* Function Prototypes: */ @@ -108,5 +128,7 @@ const void** const DescriptorAddress) ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); + void CheckIfMSCompatibilityDescriptorRequest(void); + #endif diff --git a/Demos/Device/LowLevel/RNDISEthernet/RNDISEthernet.c b/Demos/Device/LowLevel/RNDISEthernet/RNDISEthernet.c index 80cde672c..247458f39 100644 --- a/Demos/Device/LowLevel/RNDISEthernet/RNDISEthernet.c +++ b/Demos/Device/LowLevel/RNDISEthernet/RNDISEthernet.c @@ -130,6 +130,9 @@ void EVENT_USB_Device_ConfigurationChanged(void) */ void EVENT_USB_Device_ControlRequest(void) { + /* Send MS OS Compatibility descriptor if requested by the host. */ + CheckIfMSCompatibilityDescriptorRequest(); + /* Process RNDIS class commands */ switch (USB_ControlRequest.bRequest) { -- cgit v1.2.3