Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: WinUSBDevice.cpp
- Revision:
- 0:1a3aa2e25db9
- Child:
- 1:0c3b6cc480b6
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WinUSBDevice.cpp Fri Nov 04 22:07:07 2016 +0000 @@ -0,0 +1,301 @@ +#pragma once + +#include "WinUSBDevice.h" + +#include <USBDescriptor.h> + +#include <cstring> + +using std::memcpy; + +// Microsoft OS String Descriptor +#define STRING_OFFSET_MSOS (0xEE) + +// Vendor-defined request code to get the compatible IDs. I set it to 33 to aid debugging. The actual value doesn't matter. +#define GET_MS_DESCRIPTORS (33) + + +#define GENRE_INDEX (1) +#define COMPAT_ID_INDEX (4) +#define EXTENDED_PROPERTIES_INDEX (5) + +#define USB_DT_STRING (3) // USB 2.0 spec table 9.5; Linux header ch9.h + +#ifndef nullptr +#define nullptr NULL +#endif + +// Copy a string, *not* including its null terminator to the destination, up to a maximum of maxBytes. +void copyString8(uint8_t* dest, int maxBytes, const char* src) +{ + for (int i = 0; i < maxBytes; ++i) + { + if (src[i] == nullptr) + return; + dest[i] = src[i]; + } +} + +// Copy a string, *not* including its null terminator to the destination, up to a maximum of maxBytes, but in UTF-16. +void copyString16(uint8_t* dest, int maxBytes, const char* src) +{ + for (int i = 0; i < maxBytes; ++i) + { + if (i % 2 == 0) + { + if (src[i/2] == nullptr) + return; + dest[i] = src[i/2]; + } + else + { + dest[i] = 0; + } + } +} + +// Print information about a USB setup transfer. +void debugUsbSetup(const CONTROL_TRANSFER& transfer) +{ + printf("\n"); + + switch (transfer.setup.bmRequestType.Recipient) + { + case DEVICE_RECIPIENT: + printf("Recipient: Device\n"); + break; + case INTERFACE_RECIPIENT: + printf("Recipient: Interface\n"); + break; + case ENDPOINT_RECIPIENT: + printf("Recipient: Endpoint\n"); + break; + case OTHER_RECIPIENT: + printf("Recipient: Other\n"); + break; + default: + printf("Recipient: Unknown\n"); + break; + } + + printf("Length: %d\n", transfer.setup.wLength); + + switch (transfer.setup.bmRequestType.Type) + { + case STANDARD_TYPE: + printf("Request type: Standard\nRequest: "); + switch (transfer.setup.bRequest) + { + case GET_STATUS: + printf("GET_STATUS\n"); + break; + case CLEAR_FEATURE: + printf("CLEAR_FEATURE\n"); + break; + case SET_FEATURE: + printf("SET_FEATURE\n"); + break; + case SET_ADDRESS: + printf("SET_ADDRESS\n"); + break; + case GET_DESCRIPTOR: + printf("GET_DESCRIPTOR\nDescriptor Type: "); + switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) + { + case DEVICE_DESCRIPTOR: + printf("DEVICE_DESCRIPTOR\n"); + break; + case CONFIGURATION_DESCRIPTOR: + printf("CONFIGURATION_DESCRIPTOR\n"); + break; + case STRING_DESCRIPTOR: + printf("STRING_DESCRIPTOR\nDescriptor Index: "); + switch (DESCRIPTOR_INDEX(transfer.setup.wValue)) + { + case STRING_OFFSET_LANGID: + printf("STRING_OFFSET_LANGID\n"); + break; + case STRING_OFFSET_IMANUFACTURER: + printf("STRING_OFFSET_IMANUFACTURER\n"); + break; + case STRING_OFFSET_IPRODUCT: + printf("STRING_OFFSET_IPRODUCT\n"); + break; + case STRING_OFFSET_ISERIAL: + printf("STRING_OFFSET_ISERIAL\n"); + break; + case STRING_OFFSET_ICONFIGURATION: + printf("STRING_OFFSET_ICONFIGURATION\n"); + break; + case STRING_OFFSET_IINTERFACE: + printf("STRING_OFFSET_IINTERFACE\n"); + break; + case STRING_OFFSET_MSOS: + // This is a Microsoft extension. I think it's a reasonable one before you get all anti-MS. + printf("STRING_OFFSET_MSOS\n"); + break; + default: + printf("Index 0x%02hhx\n", DESCRIPTOR_INDEX(transfer.setup.wValue)); + break; + } + break; + case INTERFACE_DESCRIPTOR: + printf("INTERFACE_DESCRIPTOR\n"); + break; + case ENDPOINT_DESCRIPTOR: + printf("ENDPOINT_DESCRIPTOR\n"); + break; + case QUALIFIER_DESCRIPTOR: + printf("QUALIFIER_DESCRIPTOR\n"); + break; + default: + printf("Descriptor 0x%02hhx\n", DESCRIPTOR_TYPE(transfer.setup.wValue)); + break; + } + break; + case SET_DESCRIPTOR: + printf("SET_DESCRIPTOR\n"); + break; + case GET_CONFIGURATION: + printf("GET_CONFIGURATION\n"); + break; + case SET_CONFIGURATION: + printf("SET_CONFIGURATION\n"); + break; + case GET_INTERFACE: + printf("GET_INTERFACE\n"); + break; + case SET_INTERFACE: + printf("SET_INTERFACE\n"); + break; + case 12: //SYNCH_FRAME: + printf("SYNCH_FRAME\n"); + break; + default: + printf("Request 0x%02hhx\n", transfer.setup.bRequest); + } + break; + case CLASS_TYPE: + printf("Request type: Class Request 0x%02hhx\n", transfer.setup.bRequest); + break; + case VENDOR_TYPE: + printf("Request type: Vendor\nRequest: "); + switch (transfer.setup.bRequest) + { + // Note that GET_MS_DESCRIPTORS is an arbitrary value, which is returned in the STRING_OFFSET_MSOS string descriptor. + case GET_MS_DESCRIPTORS: + printf("GET_MS_DESCRIPTORS\nIndex: "); + switch (transfer.setup.wIndex) + { + case COMPAT_ID_INDEX: + printf("COMPAT_ID_INDEX\n"); + break; + case EXTENDED_PROPERTIES_INDEX: + printf("EXTENDED_PROPERTIES_INDEX\n"); + break; + case GENRE_INDEX: + printf("GENRE_INDEX\n"); + break; + default: + printf("0x%02hhx\n", transfer.setup.wIndex); + break; + } + break; + default: + printf("Request 0x%02hhx\n", transfer.setup.bRequest); + break; + } + break; + case RESERVED_TYPE: + printf("Request type: Reserved Request 0x%02hhx\n", transfer.setup.bRequest); + break; + default: + printf("Request type: Unknown Request 0x%02hhx\n", transfer.setup.bRequest); + break; + } +} + + +WinUSBDevice::WinUSBDevice(uint16_t vendor_id, uint16_t product_id, uint16_t product_release, const char* guid) : USBDevice(vendor_id, product_id, product_release) +{ + // Initialise the descriptors we'll return. + memset(&osStringDesc, 0, sizeof(osStringDesc)); + + osStringDesc.bLength = sizeof(osStringDesc); + osStringDesc.bDescriptorType = USB_DT_STRING; + copyString16(osStringDesc.qwSignature, sizeof(osStringDesc.qwSignature), "MSFT100"); + osStringDesc.bMS_VendorCode = GET_MS_DESCRIPTORS; + + memset(&compatIdData, 0, sizeof(compatIdData)); + + compatIdData.header.dwLength = sizeof(compatIdData); // Length of the complete Extended Compat header (and contents?) + compatIdData.header.bcdVersion = 0x0100; + compatIdData.header.wIndex = COMPAT_ID_INDEX; + compatIdData.header.bCount = 1; + + compatIdData.data[0].bFirstInterfaceNumber = 0; + copyString8(compatIdData.data[0].compatibleID, sizeof(compatIdData.data[0].compatibleID), "WINUSB"); + + memset(&extendedPropertyData, 0, sizeof(extendedPropertyData)); + + extendedPropertyData.header.dwLength = sizeof(extendedPropertyData); // Length of the complete Extended Compat header (and contents) + extendedPropertyData.header.bcdVersion = 0x0100; // This is little endian apparently. + extendedPropertyData.header.wIndex = EXTENDED_PROPERTIES_INDEX; + extendedPropertyData.header.wCount = 1; + + extendedPropertyData.data[0].dwSize = sizeof(extendedPropertyData.data[0]); + extendedPropertyData.data[0].dwPropertyDataType = 7; // 1 means NULL terminated unicode string. 7 means a list of strings (for the GUID*s* variant). + extendedPropertyData.data[0].wPropertyNameLength = sizeof(extendedPropertyData.data[0].bPropertyName); + copyString16(extendedPropertyData.data[0].bPropertyName, sizeof(extendedPropertyData.data[0].bPropertyName), "DeviceInterfaceGUIDs"); + extendedPropertyData.data[0].dwPropertyDataLength = sizeof(extendedPropertyData.data[0].bPropertyData); + copyString16(extendedPropertyData.data[0].bPropertyData, sizeof(extendedPropertyData.data[0].bPropertyData), guid); +} + +bool WinUSBDevice::USBCallback_request() +{ + // This can never be null. + CONTROL_TRANSFER& transfer = *getTransferPtr(); + + debugUsbSetup(transfer); + + // EXTENDED_PROPERTIES_INDEX is sent to the interface, not the device so we can't universally reject non-device requests. + // if (transfer.setup.bmRequestType.Recipient != DEVICE_RECIPIENT) + // return false; + + // Intercept the request for string descriptor 0xEE + if (transfer.setup.bmRequestType.Type == STANDARD_TYPE && + transfer.setup.bRequest == GET_DESCRIPTOR && + DESCRIPTOR_TYPE(transfer.setup.wValue) == STRING_DESCRIPTOR && + DESCRIPTOR_INDEX(transfer.setup.wValue) == STRING_OFFSET_MSOS) + { + transfer.ptr = reinterpret_cast<uint8_t*>(&osStringDesc); + transfer.remaining = osStringDesc.bLength; + transfer.direction = DEVICE_TO_HOST; + return true; + } + + // Our custom descriptor. + if (transfer.setup.bmRequestType.Type == VENDOR_TYPE && + transfer.setup.bRequest == GET_MS_DESCRIPTORS) + { + switch (transfer.setup.wIndex) + { + case COMPAT_ID_INDEX: // Extended Compat ID + transfer.ptr = reinterpret_cast<uint8_t*>(&compatIdData); + transfer.remaining = sizeof(compatIdData); + transfer.direction = DEVICE_TO_HOST; + return true; + case EXTENDED_PROPERTIES_INDEX: // Extended Properties. + transfer.ptr = reinterpret_cast<uint8_t*>(&extendedPropertyData); + transfer.remaining = sizeof(extendedPropertyData); + transfer.direction = DEVICE_TO_HOST; + return true; + case GENRE_INDEX: // Genre + default: + return false; + } + } + + + return false; +} \ No newline at end of file