diff --git a/Makefile b/Makefile index 32a61bca2..d54c4afc9 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,10 @@ ifneq ($(EMULATOR),1) OBJS += timer.o endif +OBJS += usb21_standard.o +OBJS += webusb.o +OBJS += winusb.o + OBJS += gen/bitmaps.o OBJS += gen/fonts.o diff --git a/bootloader/usb.c b/bootloader/usb.c index d60a622c0..128eefbca 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -18,7 +18,6 @@ */ #include -#include #include #include @@ -37,8 +36,14 @@ #include "secp256k1.h" #include "memzero.h" +#include "usb21_standard.h" +#include "webusb.h" +#include "winusb.h" + #define FIRMWARE_MAGIC "TRZR" +#define USB_INTERFACE_INDEX_MAIN 0 + #define ENDPOINT_ADDRESS_IN (0x81) #define ENDPOINT_ADDRESS_OUT (0x01) @@ -48,60 +53,21 @@ static bool old_was_unsigned; static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0200, + .bcdUSB = 0x0210, .bDeviceClass = 0, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = 0x534c, .idProduct = 0x0001, - .bcdDevice = 0x0100, + .bcdDevice = 0x0300, .iManufacturer = 1, .iProduct = 2, .iSerialNumber = 3, .bNumConfigurations = 1, }; -static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined) - 0x09, 0x01, // USAGE (1) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x20, // USAGE (Input Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x21, // USAGE (Output Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0xc0 // END_COLLECTION -}; - -static const struct { - struct usb_hid_descriptor hid_descriptor; - struct { - uint8_t bReportDescriptorType; - uint16_t wDescriptorLength; - } __attribute__((packed)) hid_report; -} __attribute__((packed)) hid_function = { - .hid_descriptor = { - .bLength = sizeof(hid_function), - .bDescriptorType = USB_DT_HID, - .bcdHID = 0x0111, - .bCountryCode = 0, - .bNumDescriptors = 1, - }, - .hid_report = { - .bReportDescriptorType = USB_DT_REPORT, - .wDescriptorLength = sizeof(hid_report_descriptor), - } -}; - -static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ +static const struct usb_endpoint_descriptor endpoints[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_IN, @@ -117,24 +83,24 @@ static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ .bInterval = 1, }}; -static const struct usb_interface_descriptor hid_iface[] = {{ +static const struct usb_interface_descriptor iface[] = {{ .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, .bAlternateSetting = 0, .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_HID, + .bInterfaceClass = USB_CLASS_VENDOR, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = 0, - .endpoint = hid_endpoints, - .extra = &hid_function, - .extralen = sizeof(hid_function), + .endpoint = endpoints, + .extra = NULL, + .extralen = 0, }}; static const struct usb_interface ifaces[] = {{ .num_altsetting = 1, - .altsetting = hid_iface, + .altsetting = iface, }}; static const struct usb_config_descriptor config = { @@ -155,23 +121,6 @@ static const char *usb_strings[] = { "", // empty serial }; -static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) -{ - (void)complete; - (void)dev; - - if ((req->bmRequestType != 0x81) || - (req->bRequest != USB_REQ_GET_DESCRIPTOR) || - (req->wValue != 0x2200)) - return 0; - - /* Handle the HID report descriptor. */ - *buf = (uint8_t *)hid_report_descriptor; - *len = sizeof(hid_report_descriptor); - - return 1; -} - enum { STATE_READY, STATE_OPEN, @@ -315,7 +264,7 @@ static void restore_metadata(const uint8_t *backup) flash_lock(); } -static void hid_rx_callback(usbd_device *dev, uint8_t ep) +static void rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static uint8_t buf[64] __attribute__((aligned(4))); @@ -665,23 +614,37 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } -static void hid_set_config(usbd_device *dev, uint16_t wValue) +static void set_config(usbd_device *dev, uint16_t wValue) { (void)wValue; - usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); - - usbd_register_control_callback( - dev, - USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - hid_control_request - ); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, rx_callback); } static usbd_device *usbd_dev; -static uint8_t usbd_control_buffer[128]; +static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); + +static const struct usb_device_capability_descriptor* capabilities[] = { + (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, +}; + +static const struct usb_bos_descriptor bos_descriptor = { + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + .bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), + .capabilities = capabilities +}; + +void usbInit(void) +{ + usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings)/sizeof(const char *), usbd_control_buffer, sizeof(usbd_control_buffer)); + usbd_register_set_config_callback(usbd_dev, set_config); + usb21_setup(usbd_dev, &bos_descriptor); + static const char* origin_url = "trezor.io/start"; + webusb_setup(usbd_dev, origin_url); + winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); +} void checkButtons(void) { @@ -715,8 +678,7 @@ void checkButtons(void) void usbLoop(bool firmware_present) { brand_new_firmware = !firmware_present; - usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, hid_set_config); + usbInit(); for (;;) { usbd_poll(usbd_dev); if (brand_new_firmware && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { diff --git a/firmware/usb.c b/firmware/usb.c index 7a59b6fa0..be7cae7b9 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -29,18 +29,27 @@ #include "util.h" #include "timer.h" +#include "usb21_standard.h" +#include "webusb.h" +#include "winusb.h" + + #define USB_INTERFACE_INDEX_MAIN 0 #if DEBUG_LINK #define USB_INTERFACE_INDEX_DEBUG 1 #define USB_INTERFACE_INDEX_U2F 2 +#define USB_INTERFACE_COUNT 3 #else #define USB_INTERFACE_INDEX_U2F 1 +#define USB_INTERFACE_COUNT 2 #endif -#define ENDPOINT_ADDRESS_IN (0x81) -#define ENDPOINT_ADDRESS_OUT (0x01) +#define ENDPOINT_ADDRESS_MAIN_IN (0x81) +#define ENDPOINT_ADDRESS_MAIN_OUT (0x01) +#if DEBUG_LINK #define ENDPOINT_ADDRESS_DEBUG_IN (0x82) #define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) +#endif #define ENDPOINT_ADDRESS_U2F_IN (0x83) #define ENDPOINT_ADDRESS_U2F_OUT (0x03) @@ -50,7 +59,7 @@ X(SERIAL_NUMBER, storage_uuid_str) \ X(INTERFACE_MAIN, "TREZOR Interface") \ X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \ - X(INTERFACE_U2F, "U2F Interface") + X(INTERFACE_U2F, "TREZOR U2F Interface") \ #define X(name, value) USB_STRING_##name, enum { @@ -68,60 +77,20 @@ static const char *usb_strings[] = { static const struct usb_device_descriptor dev_descr = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0200, + .bcdUSB = 0x0210, .bDeviceClass = 0, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = 0x534c, .idProduct = 0x0001, - .bcdDevice = 0x0100, + .bcdDevice = 0x0200, .iManufacturer = USB_STRING_MANUFACTURER, .iProduct = USB_STRING_PRODUCT, .iSerialNumber = USB_STRING_SERIAL_NUMBER, .bNumConfigurations = 1, }; -static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined) - 0x09, 0x01, // USAGE (1) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x20, // USAGE (Input Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x21, // USAGE (Output Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0xc0 // END_COLLECTION -}; - -#if DEBUG_LINK -static const uint8_t hid_report_descriptor_debug[] = { - 0x06, 0x01, 0xff, // USAGE_PAGE (Vendor Defined) - 0x09, 0x01, // USAGE (1) - 0xa1, 0x01, // COLLECTION (Application) - 0x09, 0x20, // USAGE (Input Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x09, 0x21, // USAGE (Output Report Data) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x40, // REPORT_COUNT (64) - 0x91, 0x02, // OUTPUT (Data,Var,Abs) - 0xc0 // END_COLLECTION -}; -#endif - static const uint8_t hid_report_descriptor_u2f[] = { 0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance) 0x09, 0x01, // USAGE (U2F HID Authenticator Device) @@ -141,26 +110,6 @@ static const uint8_t hid_report_descriptor_u2f[] = { 0xc0 // END_COLLECTION }; -static const struct { - struct usb_hid_descriptor hid_descriptor; - struct { - uint8_t bReportDescriptorType; - uint16_t wDescriptorLength; - } __attribute__((packed)) hid_report; -} __attribute__((packed)) hid_function = { - .hid_descriptor = { - .bLength = sizeof(hid_function), - .bDescriptorType = USB_DT_HID, - .bcdHID = 0x0111, - .bCountryCode = 0, - .bNumDescriptors = 1, - }, - .hid_report = { - .bReportDescriptorType = USB_DT_REPORT, - .wDescriptorLength = sizeof(hid_report_descriptor), - } -}; - static const struct { struct usb_hid_descriptor hid_descriptor_u2f; struct { @@ -181,52 +130,20 @@ static const struct { } }; - -static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; - -static const struct usb_interface_descriptor hid_iface[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_HID, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = USB_STRING_INTERFACE_MAIN, - .endpoint = hid_endpoints, - .extra = &hid_function, - .extralen = sizeof(hid_function), -}}; - static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 2, + .bInterval = 1, }, { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .wMaxPacketSize = 64, - .bInterval = 2, + .bInterval = 1, }}; static const struct usb_interface_descriptor hid_iface_u2f[] = {{ @@ -245,7 +162,7 @@ static const struct usb_interface_descriptor hid_iface_u2f[] = {{ }}; #if DEBUG_LINK -static const struct usb_endpoint_descriptor hid_endpoints_debug[2] = {{ +static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = {{ .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN, @@ -261,29 +178,64 @@ static const struct usb_endpoint_descriptor hid_endpoints_debug[2] = {{ .bInterval = 1, }}; -static const struct usb_interface_descriptor hid_iface_debug[] = {{ +static const struct usb_interface_descriptor webusb_iface_debug[] = {{ .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = USB_INTERFACE_INDEX_DEBUG, .bAlternateSetting = 0, .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_HID, + .bInterfaceClass = USB_CLASS_VENDOR, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = USB_STRING_INTERFACE_DEBUG, - .endpoint = hid_endpoints_debug, - .extra = &hid_function, - .extralen = sizeof(hid_function), + .endpoint = webusb_endpoints_debug, + .extra = NULL, + .extralen = 0, }}; + #endif +static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct usb_interface_descriptor webusb_iface_main[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = USB_STRING_INTERFACE_MAIN, + .endpoint = webusb_endpoints_main, + .extra = NULL, + .extralen = 0, +}}; + + +// Windows are strict about interfaces appearing +// in correct order static const struct usb_interface ifaces[] = {{ .num_altsetting = 1, - .altsetting = hid_iface, + .altsetting = webusb_iface_main, #if DEBUG_LINK }, { .num_altsetting = 1, - .altsetting = hid_iface_debug, + .altsetting = webusb_iface_debug, #endif }, { .num_altsetting = 1, @@ -294,11 +246,7 @@ static const struct usb_config_descriptor config = { .bLength = USB_DT_CONFIGURATION_SIZE, .bDescriptorType = USB_DT_CONFIGURATION, .wTotalLength = 0, -#if DEBUG_LINK - .bNumInterfaces = 3, -#else - .bNumInterfaces = 2, -#endif + .bNumInterfaces = USB_INTERFACE_COUNT, .bConfigurationValue = 1, .iConfiguration = 0, .bmAttributes = 0x80, @@ -312,40 +260,24 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin (void)dev; if ((req->bmRequestType != 0x81) || - (req->bRequest != USB_REQ_GET_DESCRIPTOR) || - (req->wValue != 0x2200)) + (req->bRequest != USB_REQ_GET_DESCRIPTOR) || + (req->wValue != 0x2200)) return 0; - if (req->wIndex == USB_INTERFACE_INDEX_U2F) { - debugLog(0, "", "hid_control_request u2f"); - *buf = (uint8_t *)hid_report_descriptor_u2f; - *len = sizeof(hid_report_descriptor_u2f); - return 1; - } - -#if DEBUG_LINK - if (req->wIndex == USB_INTERFACE_INDEX_DEBUG) { - debugLog(0, "", "hid_control_request debug"); - *buf = (uint8_t *)hid_report_descriptor_debug; - *len = sizeof(hid_report_descriptor_debug); - return 1; - } -#endif - - debugLog(0, "", "hid_control_request main"); - *buf = (uint8_t *)hid_report_descriptor; - *len = sizeof(hid_report_descriptor); + debugLog(0, "", "hid_control_request u2f"); + *buf = (uint8_t *)hid_report_descriptor_u2f; + *len = MIN(*len, sizeof(hid_report_descriptor_u2f)); return 1; } static volatile char tiny = 0; -static void hid_rx_callback(usbd_device *dev, uint8_t ep) +static void main_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); - if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; - debugLog(0, "", "hid_rx_callback"); + if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_MAIN_OUT, buf, 64) != 64) return; + debugLog(0, "", "main_rx_callback"); if (!tiny) { msg_read(buf, 64); } else { @@ -353,23 +285,23 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep) } } -static void hid_u2f_rx_callback(usbd_device *dev, uint8_t ep) +static void u2f_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); - debugLog(0, "", "hid_u2f_rx_callback"); + debugLog(0, "", "u2f_rx_callback"); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; u2fhid_read(tiny, (const U2FHID_FRAME *) (void*) buf); } #if DEBUG_LINK -static void hid_debug_rx_callback(usbd_device *dev, uint8_t ep) +static void debug_rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) return; - debugLog(0, "", "hid_debug_rx_callback"); + debugLog(0, "", "debug_rx_callback"); if (!tiny) { msg_debug_read(buf, 64); } else { @@ -378,17 +310,17 @@ static void hid_debug_rx_callback(usbd_device *dev, uint8_t ep) } #endif -static void hid_set_config(usbd_device *dev, uint16_t wValue) +static void set_config(usbd_device *dev, uint16_t wValue) { (void)wValue; - usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, main_rx_callback); usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_u2f_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, u2f_rx_callback); #if DEBUG_LINK usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); - usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_debug_rx_callback); + usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, debug_rx_callback); #endif usbd_register_control_callback( @@ -399,12 +331,29 @@ static void hid_set_config(usbd_device *dev, uint16_t wValue) } static usbd_device *usbd_dev; -static uint8_t usbd_control_buffer[128]; +static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); + +static const struct usb_device_capability_descriptor* capabilities[] = { + (const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, +}; + +static const struct usb_bos_descriptor bos_descriptor = { + .bLength = USB_DT_BOS_SIZE, + .bDescriptorType = USB_DT_BOS, + .bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), + .capabilities = capabilities +}; void usbInit(void) { usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings) / sizeof(*usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer)); - usbd_register_set_config_callback(usbd_dev, hid_set_config); + usbd_register_set_config_callback(usbd_dev, set_config); + usb21_setup(usbd_dev, &bos_descriptor); + static const char* origin_url = "trezor.io/start"; + webusb_setup(usbd_dev, origin_url); + // Debug link interface does not have WinUSB set; + // if you really need debug link on windows, edit the descriptor in winusb.c + winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); } void usbPoll(void) @@ -415,7 +364,7 @@ void usbPoll(void) // write pending data data = msg_out_data(); if (data) { - while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_IN, data, 64) != 64 ) {} + while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_MAIN_IN, data, 64) != 64 ) {} } data = u2f_out_data(); if (data) { diff --git a/usb21_standard.h b/usb21_standard.h index e7578a533..e5358bcd5 100644 --- a/usb21_standard.h +++ b/usb21_standard.h @@ -22,10 +22,8 @@ #include /* USB 3.1 Descriptor Types - Table 9-6 */ -#define USB_DT_BOS 15 +#define USB_DT_BOS 15 #define USB_DT_DEVICE_CAPABILITY 16 -#define USB_DT_SUPERSPEED_USB_ENDPOINT_COMPANION 48 -#define USB_DT_SUPERSPEEDPLUS_ISOCHRONOUS_ENDPOINT_COMPANION 49 struct usb_device_capability_descriptor { uint8_t bLength; @@ -45,18 +43,7 @@ struct usb_bos_descriptor { #define USB_DT_BOS_SIZE 5 /* USB Device Capability Types - USB 3.1 Table 9-14 */ -#define USB_DC_WIRELESS_USB 1 -#define USB_DC_USB_2_0_EXTENSION 2 -#define USB_DC_SUPERSPEED_USB 3 -#define USB_DC_CONTAINER_ID 4 -#define USB_DC_PLATFORM 5 -#define USB_DC_POWER_DELIVERY_CAPABILITY 6 -#define USB_DC_BATTERY_INFO_CAPABILITY 7 -#define USB_DC_PD_CONSUMER_PORT_CAPABILITY 8 -#define USB_DC_PD_PROVIDER_PORT_CAPABILITY 9 -#define USB_DC_SUPERSPEED_PLUS 10 -#define USB_DC_PRECISION_TIME_MEASUREMENT 11 -#define USB_DC_WIRELESS_USB_EXT 12 +#define USB_DC_PLATFORM 5 extern void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store); diff --git a/webusb.c b/webusb.c new file mode 100644 index 000000000..beb909c08 --- /dev/null +++ b/webusb.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "util.h" +#include "webusb.h" +#include "usb21_standard.h" + +const struct webusb_platform_descriptor webusb_platform_capability_descriptor = { + .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DC_PLATFORM, + .bReserved = 0, + .platformCapabilityUUID = WEBUSB_UUID, + .bcdVersion = 0x0100, + .bVendorCode = WEBUSB_VENDOR_CODE, + .iLandingPage = 1 +}; + +static const char* webusb_https_url; + +static int webusb_control_vendor_request(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback* complete) { + (void)complete; + (void)usbd_dev; + + if (req->bRequest != WEBUSB_VENDOR_CODE) { + return USBD_REQ_NEXT_CALLBACK; + } + + int status = USBD_REQ_NOTSUPP; + switch (req->wIndex) { + case WEBUSB_REQ_GET_URL: { + struct webusb_url_descriptor* url = (struct webusb_url_descriptor*)(*buf); + uint16_t index = req->wValue; + if (index == 0) { + return USBD_REQ_NOTSUPP; + } + + if (index == 1) { + size_t url_len = strlen(webusb_https_url); + url->bLength = WEBUSB_DT_URL_DESCRIPTOR_SIZE + url_len; + url->bDescriptorType = WEBUSB_DT_URL; + url->bScheme = WEBUSB_URL_SCHEME_HTTPS; + memcpy(&url->URL, webusb_https_url, url_len); + *len = MIN(*len, url->bLength); + status = USBD_REQ_HANDLED; + } else { + // TODO: stall instead? + status = USBD_REQ_NOTSUPP; + } + break; + } + default: { + status = USBD_REQ_NOTSUPP; + break; + } + } + + return status; +} + +static void webusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { + (void)wValue; + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + webusb_control_vendor_request); +} + +void webusb_setup(usbd_device* usbd_dev, const char* https_url) { + webusb_https_url = https_url; + + usbd_register_set_config_callback(usbd_dev, webusb_set_config); +} diff --git a/webusb.h b/webusb.h new file mode 100644 index 000000000..342408f1f --- /dev/null +++ b/webusb.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WEBUSB_H_INCLUDED +#define WEBUSB_H_INCLUDED + +#include +#include "webusb_defs.h" + +// Arbitrary +#define WEBUSB_VENDOR_CODE 0x01 + +extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor; +extern void webusb_setup(usbd_device* usbd_dev, const char* https_url); + +#endif diff --git a/webusb_defs.h b/webusb_defs.h new file mode 100644 index 000000000..45b5f2478 --- /dev/null +++ b/webusb_defs.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WEBUSB_DEFS_H_INCLUDED +#define WEBUSB_DEFS_H_INCLUDED + +#include + +#define WEBUSB_REQ_GET_URL 0x02 + +#define WEBUSB_DT_DESCRIPTOR_SET_HEADER 0 +#define WEBUSB_DT_CONFIGURATION_SUBSET_HEADER 1 +#define WEBUSB_DT_FUNCTION_SUBSET_HEADER 2 +#define WEBUSB_DT_URL 3 + +#define WEBUSB_URL_SCHEME_HTTP 0 +#define WEBUSB_URL_SCHEME_HTTPS 1 + +struct webusb_platform_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bReserved; + uint8_t platformCapabilityUUID[16]; + uint16_t bcdVersion; + uint8_t bVendorCode; + uint8_t iLandingPage; +} __attribute__((packed)); + +#define WEBUSB_PLATFORM_DESCRIPTOR_SIZE sizeof(struct webusb_platform_descriptor) + +// from https://wicg.github.io/webusb/#webusb-platform-capability-descriptor +// see also this (for endianness explanation) +// https://github.com/WICG/webusb/issues/115#issuecomment-352206549 +#define WEBUSB_UUID {0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} + +struct webusb_url_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bScheme; + char URL[]; +} __attribute__((packed)); + +#define WEBUSB_DT_URL_DESCRIPTOR_SIZE 3 + +#endif diff --git a/winusb.c b/winusb.c new file mode 100644 index 000000000..afdaf8b70 --- /dev/null +++ b/winusb.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "util.h" +#include "winusb.h" + +static int usb_descriptor_type(uint16_t wValue) { + return wValue >> 8; +} + +static int usb_descriptor_index(uint16_t wValue) { + return wValue & 0xFF; +} + +static struct winusb_compatible_id_descriptor winusb_wcid = { + .header = { + .dwLength = sizeof(struct winusb_compatible_id_descriptor_header) + + 1 * sizeof(struct winusb_compatible_id_function_section), + .bcdVersion = WINUSB_BCD_VERSION, + .wIndex = WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR, + .bNumSections = 1, + .reserved = { 0, 0, 0, 0, 0, 0, 0 }, + }, + .functions = { + { + // note - bInterfaceNumber is rewritten in winusb_setup with the correct interface number + .bInterfaceNumber = 0, + .reserved0 = { 1 }, + .compatibleId = "WINUSB", + .subCompatibleId = "", + .reserved1 = { 0, 0, 0, 0, 0, 0} + }, + } +}; + +static const struct usb_string_descriptor winusb_string_descriptor = { + .bLength = 0x12, + .bDescriptorType = USB_DT_STRING, + .wData = WINUSB_EXTRA_STRING +}; + +static const struct winusb_extended_properties_descriptor guid = { + .header = { + .dwLength = sizeof(struct winusb_extended_properties_descriptor_header) + + 1 * sizeof (struct winusb_extended_properties_feature_descriptor), + .bcdVersion = WINUSB_BCD_VERSION, + .wIndex = WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR, + .wNumFeatures = 1, + }, + .features = { + { + .dwLength = sizeof(struct winusb_extended_properties_feature_descriptor), + .dwPropertyDataType = WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE, + .wNameLength = WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C, + .name = WINUSB_EXTENDED_PROPERTIES_GUID_NAME, + .dwPropertyDataLength = WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C, + .propertyData = WINUSB_EXTENDED_PROPERTIES_GUID_DATA, + }, + } +}; + +static int winusb_descriptor_request(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback* complete) { + (void)complete; + (void)usbd_dev; + + if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD) { + return USBD_REQ_NEXT_CALLBACK; + } + + if (req->bRequest == USB_REQ_GET_DESCRIPTOR && usb_descriptor_type(req->wValue) == USB_DT_STRING) { + if (usb_descriptor_index(req->wValue) == WINUSB_EXTRA_STRING_INDEX) { + *buf = (uint8_t*)(&winusb_string_descriptor); + *len = MIN(*len, winusb_string_descriptor.bLength); + return USBD_REQ_HANDLED; + } + } + return USBD_REQ_NEXT_CALLBACK; +} + +static int winusb_control_vendor_request(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback* complete) { + (void)complete; + (void)usbd_dev; + + if (req->bRequest != WINUSB_MS_VENDOR_CODE) { + return USBD_REQ_NEXT_CALLBACK; + } + + int status = USBD_REQ_NOTSUPP; + if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_DEVICE) && + (req->wIndex == WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR)) { + *buf = (uint8_t*)(&winusb_wcid); + *len = MIN(*len, winusb_wcid.header.dwLength); + status = USBD_REQ_HANDLED; + + } else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_INTERFACE) && + (req->wIndex == WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR) && + (usb_descriptor_index(req->wValue) == winusb_wcid.functions[0].bInterfaceNumber)) { + + *buf = (uint8_t*)(&guid); + *len = MIN(*len, guid.header.dwLength); + status = USBD_REQ_HANDLED; + + } else { + status = USBD_REQ_NOTSUPP; + } + + return status; +} + +static void winusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { + (void)wValue; + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_VENDOR, + USB_REQ_TYPE_TYPE, + winusb_control_vendor_request); +} + +void winusb_setup(usbd_device* usbd_dev, uint8_t interface) { + winusb_wcid.functions[0].bInterfaceNumber = interface; + + usbd_register_set_config_callback(usbd_dev, winusb_set_config); + + /* Windows probes the compatible ID before setting the configuration, + so also register the callback now */ + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_VENDOR, + USB_REQ_TYPE_TYPE, + winusb_control_vendor_request); + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_DEVICE, + USB_REQ_TYPE_RECIPIENT, + winusb_descriptor_request); +} + diff --git a/winusb.h b/winusb.h new file mode 100644 index 000000000..16a6df115 --- /dev/null +++ b/winusb.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WINUSB_H_INCLUDED +#define WINUSB_H_INCLUDED + +#include "winusb_defs.h" + +// Arbitrary, but must be equivalent to the last character in extra string +#define WINUSB_MS_VENDOR_CODE '!' +#define WINUSB_EXTRA_STRING {'M', 'S', 'F', 'T', '1', '0', '0', WINUSB_MS_VENDOR_CODE} + +extern void winusb_setup(usbd_device* usbd_dev, uint8_t interface); + +#endif diff --git a/winusb_defs.h b/winusb_defs.h new file mode 100644 index 000000000..830e6b154 --- /dev/null +++ b/winusb_defs.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2016, Devan Lai + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WINUSB_DEFS_H_INCLUDED +#define WINUSB_DEFS_H_INCLUDED + +#include + +/* Microsoft OS 1.0 descriptors */ + +/* Extended Compat ID OS Feature Descriptor Specification */ +#define WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR 0x04 +#define WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR 0x05 +#define WINUSB_BCD_VERSION 0x0100 + +// Apparently using DeviceInterfaceGUID does not always work on Windows 7. +// DeviceInterfaceGUIDs does seem to work. +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME u"DeviceInterfaceGUIDs" +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) +#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) / 2) + +// extra null is intentional - it's an array of GUIDs with 1 item +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\x00" +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) +#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) / 2) +#define WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE 7 + +#define WINUSB_EXTRA_STRING_INDEX 0xee + +/* Table 2. Function Section */ +struct winusb_compatible_id_function_section { + uint8_t bInterfaceNumber; + uint8_t reserved0[1]; + char compatibleId[8]; + char subCompatibleId[8]; + uint8_t reserved1[6]; +} __attribute__((packed)); + +/* Table 1. Header Section */ +struct winusb_compatible_id_descriptor_header { + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint8_t bNumSections; + uint8_t reserved[7]; +} __attribute__((packed)); + +struct winusb_compatible_id_descriptor { + struct winusb_compatible_id_descriptor_header header; + struct winusb_compatible_id_function_section functions[]; +} __attribute__((packed)); + +struct winusb_extended_properties_feature_descriptor { + uint32_t dwLength; + uint32_t dwPropertyDataType; + uint16_t wNameLength; + uint16_t name[WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U]; + uint32_t dwPropertyDataLength; + uint16_t propertyData[WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U]; +} __attribute__((packed)); + +struct winusb_extended_properties_descriptor_header { + uint32_t dwLength; + uint16_t bcdVersion; + uint16_t wIndex; + uint16_t wNumFeatures; +} __attribute__((packed)); + +struct winusb_extended_properties_descriptor { + struct winusb_extended_properties_descriptor_header header; + struct winusb_extended_properties_feature_descriptor features[]; +} __attribute__((packed)); + +#endif