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
diff -r 000000000000 -r 1a3aa2e25db9 WinUSBDevice.cpp
--- /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