From 582cbe3c5a0761e8bce72fa21f5d9db840540d0d Mon Sep 17 00:00:00 2001 From: Kevin Mehall Date: Sat, 9 Apr 2016 09:22:44 -0700 Subject: [PATCH 1/2] Make Windows auto-install WinUSB driver. Apply the Windows Compatible ID descriptor to the CDC interfaces as well as the vendor-class interface. It seems that Windows will only automatically install the driver if *all* interface of the device have the WCID descriptor set to WINUSB. This will prevent the CDC serial console interface from working on Windows. Bumps the bcdDevice so Windows machines that have cached the descriptors will re-load them. --- firmware/usb.c | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index b5b06b0..c715a87 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -16,7 +16,7 @@ __attribute__((__aligned__(4))) const USB_DeviceDescriptor device_descriptor = { .bMaxPacketSize0 = 64, .idVendor = 0x1209, .idProduct = 0x7551, - .bcdDevice = 0x0110, + .bcdDevice = 0x0111, .iManufacturer = 0x01, .iProduct = 0x02, @@ -212,20 +212,35 @@ __attribute__((__aligned__(4))) const USB_StringDescriptor msft_os = { .bString = u"MSFT100\xee" }; -__attribute__((__aligned__(4))) const USB_MicrosoftCompatibleDescriptor msft_compatible = { - .dwLength = sizeof(USB_MicrosoftCompatibleDescriptor) + sizeof(USB_MicrosoftCompatibleDescriptor_Interface), +// TODO: this doesn't need to be in RAM if it is copied into usb_ep0_out one packet at a time +__attribute__((__aligned__(4), __section__(".data"))) const USB_MicrosoftCompatibleDescriptor msft_compatible = { + .dwLength = sizeof(USB_MicrosoftCompatibleDescriptor) + 3 * sizeof(USB_MicrosoftCompatibleDescriptor_Interface), .bcdVersion = 0x0100, .wIndex = 0x0004, - .bCount = 1, + .bCount = 3, .reserved = {0, 0, 0, 0, 0, 0, 0}, .interfaces = { { .bFirstInterfaceNumber = 0, - .reserved1 = 0, + .reserved1 = 0x01, .compatibleID = "WINUSB\0\0", .subCompatibleID = {0, 0, 0, 0, 0, 0, 0, 0}, .reserved2 = {0, 0, 0, 0, 0, 0}, - } + }, + { + .bFirstInterfaceNumber = 1, + .reserved1 = 0x01, + .compatibleID = "WINUSB\0\0", + .subCompatibleID = {0, 0, 0, 0, 0, 0, 0, 0}, + .reserved2 = {0, 0, 0, 0, 0, 0}, + }, + { + .bFirstInterfaceNumber = 2, + .reserved1 = 0x01, + .compatibleID = "WINUSB\0\0", + .subCompatibleID = {0, 0, 0, 0, 0, 0, 0, 0}, + .reserved2 = {0, 0, 0, 0, 0, 0}, + }, } }; @@ -366,11 +381,25 @@ void req_boot_status() { return usb_ep0_in(len); } +// TODO: Use the version in the USB library after making it handle descriptors larger than 64 bytes +static void handle_msft_compatible(const USB_MicrosoftCompatibleDescriptor* msft_compatible) { + if (usb_setup.wIndex == 0x0004) { + uint16_t len = usb_setup.wLength; + if (len > msft_compatible->dwLength) { + len = msft_compatible->dwLength; + } + usb_ep_start_in(0x80, (uint8_t*) msft_compatible, len, true); + usb_ep0_out(); + } else { + return usb_ep0_stall(); + } +} + void usb_cb_control_setup(void) { uint8_t recipient = usb_setup.bmRequestType & USB_REQTYPE_RECIPIENT_MASK; if (recipient == USB_RECIPIENT_DEVICE) { switch(usb_setup.bRequest) { - case 0xee: return usb_handle_msft_compatible(&msft_compatible); + case 0xee: return handle_msft_compatible(&msft_compatible); case REQ_PWR: return req_gpio(usb_setup.wIndex, usb_setup.wValue); case REQ_INFO: return req_info(usb_setup.wIndex); case REQ_BOOT: return req_boot(); From de4f613382cc3291bfea91d5c2b847c4b381936e Mon Sep 17 00:00:00 2001 From: Tim Cameron Ryan Date: Sun, 24 Apr 2016 05:30:15 -0700 Subject: [PATCH 2/2] Adds extended WinUSB descriptor. --- firmware/usb.c | 66 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index c715a87..8c9a15d 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -206,15 +206,20 @@ __attribute__((__aligned__(4))) const USB_StringDescriptor language_string = { .bString = {USB_LANGUAGE_EN_US}, }; +#define MSFT_ID 0xEE +#define MSFT_ID_STR u"\xEE" + __attribute__((__aligned__(4))) const USB_StringDescriptor msft_os = { .bLength = 18, .bDescriptorType = USB_DTYPE_String, - .bString = u"MSFT100\xee" + .bString = u"MSFT100" MSFT_ID_STR }; +__attribute__((__aligned__(4))) uint8_t ep0_buffer[146]; + // TODO: this doesn't need to be in RAM if it is copied into usb_ep0_out one packet at a time -__attribute__((__aligned__(4), __section__(".data"))) const USB_MicrosoftCompatibleDescriptor msft_compatible = { - .dwLength = sizeof(USB_MicrosoftCompatibleDescriptor) + 3 * sizeof(USB_MicrosoftCompatibleDescriptor_Interface), +const USB_MicrosoftCompatibleDescriptor msft_compatible = { + .dwLength = sizeof(USB_MicrosoftCompatibleDescriptor) + (3 * sizeof(USB_MicrosoftCompatibleDescriptor_Interface)), .bcdVersion = 0x0100, .wIndex = 0x0004, .bCount = 3, @@ -244,6 +249,33 @@ __attribute__((__aligned__(4), __section__(".data"))) const USB_MicrosoftCompati } }; +typedef struct { + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint16_t wCount; + uint32_t dwPropLength; + uint32_t dwType; + uint16_t wNameLength; + uint16_t name[21]; + uint32_t dwDataLength; + uint16_t data[40]; + uint8_t _padding[2]; +} __attribute__((packed)) USB_MicrosoftExtendedPropertiesDescriptor; + +const USB_MicrosoftExtendedPropertiesDescriptor msft_extended = { + .dwLength = 146, + .bcdVersion = 0x0100, + .wIndex = 0x05, + .wCount = 0x01, + .dwPropLength = 136, + .dwType = 7, + .wNameLength = 42, + .name = u"DeviceInterfaceGUIDs\0", + .dwDataLength = 80, + .data = u"{3c33bbfd-71f9-4815-8b8f-7cd1ef928b3d}\0\0", +}; + uint16_t usb_cb_get_descriptor(uint8_t type, uint8_t index, const uint8_t** ptr) { const void* address = NULL; uint16_t size = 0; @@ -382,30 +414,38 @@ void req_boot_status() { } // TODO: Use the version in the USB library after making it handle descriptors larger than 64 bytes -static void handle_msft_compatible(const USB_MicrosoftCompatibleDescriptor* msft_compatible) { - if (usb_setup.wIndex == 0x0004) { - uint16_t len = usb_setup.wLength; - if (len > msft_compatible->dwLength) { - len = msft_compatible->dwLength; - } - usb_ep_start_in(0x80, (uint8_t*) msft_compatible, len, true); - usb_ep0_out(); +static inline void handle_msft_compatible(const USB_MicrosoftCompatibleDescriptor* msft_compatible, const USB_MicrosoftExtendedPropertiesDescriptor* msft_extended) { + uint16_t len; + if (usb_setup.wIndex == 0x0005) { + len = msft_extended->dwLength; + memcpy(ep0_buffer, msft_extended, len); + } else if (usb_setup.wIndex == 0x0004) { + len = msft_compatible->dwLength; + memcpy(ep0_buffer, msft_compatible, len); } else { return usb_ep0_stall(); } + if (len > usb_setup.wLength) { + len = usb_setup.wLength; + } + usb_ep_start_in(0x80, ep0_buffer, len, true); + usb_ep0_out(); } void usb_cb_control_setup(void) { uint8_t recipient = usb_setup.bmRequestType & USB_REQTYPE_RECIPIENT_MASK; if (recipient == USB_RECIPIENT_DEVICE) { switch(usb_setup.bRequest) { - case 0xee: return handle_msft_compatible(&msft_compatible); + case MSFT_ID: return handle_msft_compatible(&msft_compatible, &msft_extended); case REQ_PWR: return req_gpio(usb_setup.wIndex, usb_setup.wValue); case REQ_INFO: return req_info(usb_setup.wIndex); case REQ_BOOT: return req_boot(); case REQ_OPENWRT_BOOT_STATUS: return req_boot_status(); } } else if (recipient == USB_RECIPIENT_INTERFACE) { + switch(usb_setup.bRequest) { + case MSFT_ID: return handle_msft_compatible(&msft_compatible, &msft_extended); + } } return usb_ep0_stall(); } @@ -480,4 +520,4 @@ bool usb_cb_set_interface(uint16_t interface, uint16_t new_altsetting) { return true; } return false; -} +} \ No newline at end of file