diff --git a/firmware/usb.c b/firmware/usb.c index b5b06b0..8c9a15d 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, @@ -206,29 +206,76 @@ __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))) const USB_MicrosoftCompatibleDescriptor msft_compatible = { - .dwLength = sizeof(USB_MicrosoftCompatibleDescriptor) + sizeof(USB_MicrosoftCompatibleDescriptor_Interface), +__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 +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}, + }, } }; +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; @@ -366,17 +413,39 @@ 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 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 usb_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(); } @@ -451,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