diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index 685c3bfc44..af6dce6b16 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -112,8 +112,8 @@ static void usb_init_all(secbool usb21_landing) { #ifdef TREZOR_EMULATOR .emu_port = 21324, #else - .ep_in = USB_EP_DIR_IN | 0x01, - .ep_out = USB_EP_DIR_OUT | 0x01, + .ep_in = 0x01, + .ep_out = 0x01, #endif .subclass = 0, .protocol = 0, diff --git a/core/embed/bootloader_ci/main.c b/core/embed/bootloader_ci/main.c index 3db0631a27..ca60278ee3 100644 --- a/core/embed/bootloader_ci/main.c +++ b/core/embed/bootloader_ci/main.c @@ -69,8 +69,8 @@ static void usb_init_all(secbool usb21_landing) { static const usb_webusb_info_t webusb_info = { .iface_num = USB_IFACE_NUM, - .ep_in = USB_EP_DIR_IN | 0x01, - .ep_out = USB_EP_DIR_OUT | 0x01, + .ep_in = 0x01, + .ep_out = 0x01, .subclass = 0, .protocol = 0, .max_packet_len = sizeof(rx_buffer), diff --git a/core/embed/prodtest/main.c b/core/embed/prodtest/main.c index 005819b8cf..2a50696adb 100644 --- a/core/embed/prodtest/main.c +++ b/core/embed/prodtest/main.c @@ -148,8 +148,8 @@ static void usb_init_all(void) { .rx_intr_byte = 3, // Ctrl-C .iface_num = VCP_IFACE, .data_iface_num = 0x01, - .ep_cmd = 0x82, - .ep_in = 0x81, + .ep_cmd = 0x02, + .ep_in = 0x01, .ep_out = 0x01, .polling_interval = 10, .max_packet_len = VCP_PACKET_LEN, diff --git a/core/embed/trezorhal/stm32f4/usb/usb.c b/core/embed/trezorhal/stm32f4/usb/usbd.c similarity index 63% rename from core/embed/trezorhal/stm32f4/usb/usb.c rename to core/embed/trezorhal/stm32f4/usb/usbd.c index 9249c4b9e8..8b9f35f620 100644 --- a/core/embed/trezorhal/stm32f4/usb/usb.c +++ b/core/embed/trezorhal/stm32f4/usb/usbd.c @@ -19,10 +19,12 @@ #include STM32_HAL_H -#include "usb.h" #include "common.h" #include "random_delays.h" +#include "secbool.h" +#include "usb.h" #include "usbd_core.h" +#include "usbd_internal.h" #define USB_MAX_CONFIG_DESC_SIZE 256 #define USB_MAX_STR_SIZE 62 @@ -38,39 +40,49 @@ #error Unable to determine proper USB_PHY_ID to use #endif -#define USB_WINUSB_VENDOR_CODE \ - '!' // arbitrary, but must be equivalent to the last character in extra - // string -#define USB_WINUSB_EXTRA_STRING \ - 'M', 0x00, 'S', 0x00, 'F', 0x00, 'T', 0x00, '1', 0x00, '0', 0x00, '0', 0x00, \ - USB_WINUSB_VENDOR_CODE, 0x00 // MSFT100! -#define USB_WINUSB_EXTRA_STRING_INDEX 0xEE -#define USB_WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR 0x04 -#define USB_WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR 0x05 +typedef struct { + const char *manufacturer; + const char *product; + const char *serial_number; + const char *interface; +} usb_dev_string_table_t; -#define UNCONST(X) ((uint8_t *)(X)) +typedef struct { + // USB class dispatch table + const USBD_ClassTypeDef *class; + // Internal state for USB class driver + uint8_t state[USBD_CLASS_STATE_MAX_SIZE] __attribute__((aligned(8))); +} usb_iface_t; -static usb_device_descriptor_t usb_dev_desc; +typedef struct { + // Handle to the USB device (lower layer driver) + USBD_HandleTypeDef dev_handle; + // Device descriptor + usb_device_descriptor_t dev_desc; + // Device string descriptors + usb_dev_string_table_t str_table; + // Interfaces of registered class drivers + // (each class driver must add 1 or more interfaces) + usb_iface_t ifaces[USBD_MAX_NUM_INTERFACES]; + // Buffer for configuration descriptor and additional descriptors + // (interface, endpoint, ..) added by registered class drivers + uint8_t desc_buffer[USB_MAX_CONFIG_DESC_SIZE] __attribute__((aligned(4))); + // Configuration descriptor (located at the beginning of the desc_buffer) + usb_config_descriptor_t *config_desc; + // Temporary buffer for unicode strings + uint8_t str_buf[USB_MAX_STR_DESC_SIZE] __attribute__((aligned(4))); -// Config descriptor -static uint8_t usb_config_buf[USB_MAX_CONFIG_DESC_SIZE] - __attribute__((aligned(4))); -static usb_config_descriptor_t *usb_config_desc = - (usb_config_descriptor_t *)(usb_config_buf); -static usb_interface_descriptor_t *usb_next_iface_desc; + secbool usb21_enabled; + secbool usb21_landing; -// String descriptor -static uint8_t usb_str_buf[USB_MAX_STR_DESC_SIZE] __attribute__((aligned(4))); -static usb_dev_string_table_t usb_str_table; +} usb_driver_t; -static usb_iface_t usb_ifaces[USBD_MAX_NUM_INTERFACES]; +// USB driver instance +static usb_driver_t g_usb_driver; -static USBD_HandleTypeDef usb_dev_handle; -static const USBD_DescriptorsTypeDef usb_descriptors; +// forward declarations of dispatch functions static const USBD_ClassTypeDef usb_class; - -static secbool usb21_enabled = secfalse; -static secbool usb21_landing = secfalse; +static const USBD_DescriptorsTypeDef usb_descriptors; static secbool __wur check_desc_str(const char *s) { if (NULL == s) return secfalse; @@ -79,28 +91,30 @@ static secbool __wur check_desc_str(const char *s) { } void usb_init(const usb_dev_info_t *dev_info) { + usb_driver_t *usb = &g_usb_driver; + // enable/disable USB 2.1 features - usb21_enabled = dev_info->usb21_enabled; - usb21_landing = dev_info->usb21_landing; + usb->usb21_enabled = dev_info->usb21_enabled; + usb->usb21_landing = dev_info->usb21_landing; // Device descriptor - usb_dev_desc.bLength = sizeof(usb_device_descriptor_t); - usb_dev_desc.bDescriptorType = USB_DESC_TYPE_DEVICE; - usb_dev_desc.bcdUSB = - (sectrue == usb21_enabled) ? 0x0210 : 0x0200; // USB 2.1 or USB 2.0 - usb_dev_desc.bDeviceClass = dev_info->device_class; - usb_dev_desc.bDeviceSubClass = dev_info->device_subclass; - usb_dev_desc.bDeviceProtocol = dev_info->device_protocol; - usb_dev_desc.bMaxPacketSize0 = USB_MAX_EP0_SIZE; - usb_dev_desc.idVendor = dev_info->vendor_id; - usb_dev_desc.idProduct = dev_info->product_id; - usb_dev_desc.bcdDevice = dev_info->release_num; - usb_dev_desc.iManufacturer = - USBD_IDX_MFC_STR; // Index of manufacturer string - usb_dev_desc.iProduct = USBD_IDX_PRODUCT_STR; // Index of product string - usb_dev_desc.iSerialNumber = + usb->dev_desc.bLength = sizeof(usb_device_descriptor_t); + usb->dev_desc.bDescriptorType = USB_DESC_TYPE_DEVICE; + usb->dev_desc.bcdUSB = + (sectrue == usb->usb21_enabled) ? 0x0210 : 0x0200; // USB 2.1 or USB 2.0 + usb->dev_desc.bDeviceClass = dev_info->device_class; + usb->dev_desc.bDeviceSubClass = dev_info->device_subclass; + usb->dev_desc.bDeviceProtocol = dev_info->device_protocol; + usb->dev_desc.bMaxPacketSize0 = USB_MAX_EP0_SIZE; + usb->dev_desc.idVendor = dev_info->vendor_id; + usb->dev_desc.idProduct = dev_info->product_id; + usb->dev_desc.bcdDevice = dev_info->release_num; + usb->dev_desc.iManufacturer = + USBD_IDX_MFC_STR; // Index of manufacturer string + usb->dev_desc.iProduct = USBD_IDX_PRODUCT_STR; // Index of product string + usb->dev_desc.iSerialNumber = USBD_IDX_SERIAL_STR; // Index of serial number string - usb_dev_desc.bNumConfigurations = 1; + usb->dev_desc.bNumConfigurations = 1; // String table ensure(check_desc_str(dev_info->manufacturer), NULL); @@ -108,57 +122,66 @@ void usb_init(const usb_dev_info_t *dev_info) { ensure(check_desc_str(dev_info->serial_number), NULL); ensure(check_desc_str(dev_info->interface), NULL); - usb_str_table.manufacturer = dev_info->manufacturer; - usb_str_table.product = dev_info->product; - usb_str_table.serial_number = dev_info->serial_number; - usb_str_table.interface = dev_info->interface; + usb->str_table.manufacturer = dev_info->manufacturer; + usb->str_table.product = dev_info->product; + usb->str_table.serial_number = dev_info->serial_number; + usb->str_table.interface = dev_info->interface; + + usb->config_desc = (usb_config_descriptor_t *)(usb->desc_buffer); // Configuration descriptor - usb_config_desc->bLength = sizeof(usb_config_descriptor_t); - usb_config_desc->bDescriptorType = USB_DESC_TYPE_CONFIGURATION; - usb_config_desc->wTotalLength = + usb->config_desc->bLength = sizeof(usb_config_descriptor_t); + usb->config_desc->bDescriptorType = USB_DESC_TYPE_CONFIGURATION; + usb->config_desc->wTotalLength = sizeof(usb_config_descriptor_t); // will be updated later via - // usb_desc_add_iface() - usb_config_desc->bNumInterfaces = - 0; // will be updated later via usb_desc_add_iface() - usb_config_desc->bConfigurationValue = 0x01; - usb_config_desc->iConfiguration = 0; - usb_config_desc->bmAttributes = - 0x80; // 0x80 = bus powered; 0xC0 = self powered - usb_config_desc->bMaxPower = 0x32; // Maximum Power Consumption in 2mA units - - // Pointer to interface descriptor data - usb_next_iface_desc = - (usb_interface_descriptor_t *)(usb_config_buf + - usb_config_desc->wTotalLength); + // usb_alloc_class_descriptors() + usb->config_desc->bNumInterfaces = + 0; // will be updated later via usb_set_iface_class() + usb->config_desc->bConfigurationValue = 0x01; + usb->config_desc->iConfiguration = 0; + usb->config_desc->bmAttributes = + 0x80; // 0x80 = bus powered; 0xC0 = self powered + usb->config_desc->bMaxPower = 0x32; // Maximum Power Consumption in 2mA units ensure(sectrue * - (USBD_OK == USBD_Init(&usb_dev_handle, + (USBD_OK == USBD_Init(&usb->dev_handle, (USBD_DescriptorsTypeDef *)&usb_descriptors, USB_PHY_ID)), NULL); ensure(sectrue * - (USBD_OK == USBD_RegisterClass(&usb_dev_handle, + (USBD_OK == USBD_RegisterClass(&usb->dev_handle, (USBD_ClassTypeDef *)&usb_class)), NULL); } void usb_deinit(void) { - USBD_DeInit(&usb_dev_handle); + usb_driver_t *usb = &g_usb_driver; + + USBD_DeInit(&usb->dev_handle); for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { - usb_ifaces[i].type = USB_IFACE_TYPE_DISABLED; + usb->ifaces[i].class = NULL; } } -void usb_start(void) { USBD_Start(&usb_dev_handle); } +void usb_start(void) { + usb_driver_t *usb = &g_usb_driver; -void usb_stop(void) { USBD_Stop(&usb_dev_handle); } + USBD_Start(&usb->dev_handle); +} + +void usb_stop(void) { + usb_driver_t *usb = &g_usb_driver; + + USBD_Stop(&usb->dev_handle); +} secbool usb_configured(void) { + usb_driver_t *usb = &g_usb_driver; + static uint32_t usb_configured_last_ok = 0; uint32_t ticks = hal_ticks_ms(); - const USBD_HandleTypeDef *pdev = &usb_dev_handle; + const USBD_HandleTypeDef *pdev = &usb->dev_handle; if (pdev->dev_state == USBD_STATE_CONFIGURED) { usb_configured_last_ok = hal_ticks_ms(); return sectrue; @@ -189,50 +212,65 @@ secbool usb_configured(void) { return secfalse; } -/* - * Utility functions for USB interfaces - */ +// ========================================================================== +// Utility functions for USB class drivers +// ========================================================================== + +void *usb_get_iface_state(uint8_t iface_num, const USBD_ClassTypeDef *class) { + usb_driver_t *usb = &g_usb_driver; -static usb_iface_t *usb_get_iface(uint8_t iface_num) { if (iface_num < USBD_MAX_NUM_INTERFACES) { - return &usb_ifaces[iface_num]; - } else { - return NULL; // Invalid interface number + usb_iface_t *iface = &usb->ifaces[iface_num]; + + if (iface->class == class) { + return &iface->state; + } + } + + // Invalid interface number or type + return NULL; +} + +void usb_set_iface_class(uint8_t iface_num, const USBD_ClassTypeDef *class) { + usb_driver_t *usb = &g_usb_driver; + + if (iface_num < USBD_MAX_NUM_INTERFACES) { + if (usb->ifaces[iface_num].class == NULL && class != NULL) { + usb->config_desc->bNumInterfaces++; + } + + usb->ifaces[iface_num].class = class; } } -static void *usb_desc_alloc_iface(size_t desc_len) { - if (usb_config_desc->wTotalLength + desc_len < USB_MAX_CONFIG_DESC_SIZE) { - return usb_next_iface_desc; +USBD_HandleTypeDef *usb_get_dev_handle(void) { + usb_driver_t *usb = &g_usb_driver; + + return &usb->dev_handle; +} + +void *usb_alloc_class_descriptors(size_t desc_len) { + usb_driver_t *usb = &g_usb_driver; + + if (usb->config_desc->wTotalLength + desc_len < USB_MAX_CONFIG_DESC_SIZE) { + void *retval = &usb->desc_buffer[usb->config_desc->wTotalLength]; + usb->config_desc->wTotalLength += desc_len; + return retval; } else { return NULL; // Not enough space in the descriptor } } -static void usb_desc_add_iface(size_t desc_len) { - usb_config_desc->bNumInterfaces++; - usb_config_desc->wTotalLength += desc_len; - usb_next_iface_desc = - (usb_interface_descriptor_t *)(usb_config_buf + - usb_config_desc->wTotalLength); -} - -/* - * USB interface implementations - */ - -#include "usb_hid-impl.h" -#include "usb_vcp-impl.h" -#include "usb_webusb-impl.h" - -/* - * USB configuration (device & string descriptors) - */ +// ========================================================================== +// USB configuration (device & string descriptors) +// ========================================================================== static uint8_t *usb_get_dev_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - *length = sizeof(usb_dev_desc); - return (uint8_t *)(&usb_dev_desc); + usb_driver_t *usb = &g_usb_driver; + + *length = sizeof(usb->dev_desc); + return (uint8_t *)(&usb->dev_desc); } static uint8_t *usb_get_langid_str_descriptor(USBD_SpeedTypeDef speed, @@ -248,37 +286,49 @@ static uint8_t *usb_get_langid_str_descriptor(USBD_SpeedTypeDef speed, static uint8_t *usb_get_manufacturer_str_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - USBD_GetString((uint8_t *)usb_str_table.manufacturer, usb_str_buf, length); - return usb_str_buf; + usb_driver_t *usb = &g_usb_driver; + + USBD_GetString((uint8_t *)usb->str_table.manufacturer, usb->str_buf, length); + return usb->str_buf; } static uint8_t *usb_get_product_str_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - USBD_GetString((uint8_t *)usb_str_table.product, usb_str_buf, length); - return usb_str_buf; + usb_driver_t *usb = &g_usb_driver; + + USBD_GetString((uint8_t *)usb->str_table.product, usb->str_buf, length); + return usb->str_buf; } static uint8_t *usb_get_serial_str_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - USBD_GetString((uint8_t *)usb_str_table.serial_number, usb_str_buf, length); - return usb_str_buf; + usb_driver_t *usb = &g_usb_driver; + + USBD_GetString((uint8_t *)usb->str_table.serial_number, usb->str_buf, length); + return usb->str_buf; } static uint8_t *usb_get_configuration_str_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - USBD_GetString((uint8_t *)"", usb_str_buf, length); - return usb_str_buf; + usb_driver_t *usb = &g_usb_driver; + + USBD_GetString((uint8_t *)"", usb->str_buf, length); + return usb->str_buf; } static uint8_t *usb_get_interface_str_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - USBD_GetString((uint8_t *)usb_str_table.interface, usb_str_buf, length); - return usb_str_buf; + usb_driver_t *usb = &g_usb_driver; + + USBD_GetString((uint8_t *)usb->str_table.interface, usb->str_buf, length); + return usb->str_buf; } static uint8_t *usb_get_bos_descriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - if (sectrue == usb21_enabled) { + usb_driver_t *usb = &g_usb_driver; + + if (sectrue == usb->usb21_enabled) { static uint8_t bos[] = { // usb_bos_descriptor { 0x05, // uint8_t bLength @@ -298,7 +348,7 @@ static uint8_t *usb_get_bos_descriptor(USBD_SpeedTypeDef speed, USB_WEBUSB_LANDING_PAGE, // uint8_t iLandingPage // } }; - bos[28] = (sectrue == usb21_landing) ? USB_WEBUSB_LANDING_PAGE : 0; + bos[28] = (sectrue == usb->usb21_landing) ? USB_WEBUSB_LANDING_PAGE : 0; *length = sizeof(bos); return UNCONST(bos); } else { @@ -318,45 +368,49 @@ static const USBD_DescriptorsTypeDef usb_descriptors = { .GetBOSDescriptor = usb_get_bos_descriptor, }; -/* - * USB class (interface dispatch, configuration descriptor) - */ +// ========================================================================== +// USB class (interface dispatch, configuration descriptor) +// ========================================================================== + +#define USB_WINUSB_VENDOR_CODE \ + '!' // arbitrary, but must be equivalent to the last character in extra + // string +#define USB_WINUSB_EXTRA_STRING \ + 'M', 0x00, 'S', 0x00, 'F', 0x00, 'T', 0x00, '1', 0x00, '0', 0x00, '0', 0x00, \ + USB_WINUSB_VENDOR_CODE, 0x00 // MSFT100! +#define USB_WINUSB_EXTRA_STRING_INDEX 0xEE +#define USB_WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR 0x04 +#define USB_WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR 0x05 static uint8_t usb_class_init(USBD_HandleTypeDef *dev, uint8_t cfg_idx) { + usb_driver_t *usb = &g_usb_driver; + for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { - switch (usb_ifaces[i].type) { - case USB_IFACE_TYPE_HID: - usb_hid_class_init(dev, &usb_ifaces[i].hid, cfg_idx); - break; - case USB_IFACE_TYPE_VCP: - usb_vcp_class_init(dev, &usb_ifaces[i].vcp, cfg_idx); - break; - case USB_IFACE_TYPE_WEBUSB: - usb_webusb_class_init(dev, &usb_ifaces[i].webusb, cfg_idx); - break; - default: - break; + usb_iface_t *iface = &usb->ifaces[i]; + if (iface->class != NULL && iface->class->Init != NULL) { + dev->pUserData = iface->state; + iface->class->Init(dev, cfg_idx); } } + + dev->pUserData = NULL; + return USBD_OK; } static uint8_t usb_class_deinit(USBD_HandleTypeDef *dev, uint8_t cfg_idx) { + usb_driver_t *usb = &g_usb_driver; + for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { - switch (usb_ifaces[i].type) { - case USB_IFACE_TYPE_HID: - usb_hid_class_deinit(dev, &usb_ifaces[i].hid, cfg_idx); - break; - case USB_IFACE_TYPE_VCP: - usb_vcp_class_deinit(dev, &usb_ifaces[i].vcp, cfg_idx); - break; - case USB_IFACE_TYPE_WEBUSB: - usb_webusb_class_deinit(dev, &usb_ifaces[i].webusb, cfg_idx); - break; - default: - break; + usb_iface_t *iface = &usb->ifaces[i]; + if (iface->class != NULL && iface->class->DeInit != NULL) { + dev->pUserData = iface->state; + iface->class->DeInit(dev, cfg_idx); } } + + dev->pUserData = NULL; + return USBD_OK; } @@ -367,6 +421,8 @@ static uint8_t usb_class_deinit(USBD_HandleTypeDef *dev, uint8_t cfg_idx) { static uint8_t usb_class_setup(USBD_HandleTypeDef *dev, USBD_SetupReqTypedef *req) { + usb_driver_t *usb = &g_usb_driver; + if (((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_CLASS) && ((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) && ((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_VENDOR)) { @@ -375,7 +431,8 @@ static uint8_t usb_class_setup(USBD_HandleTypeDef *dev, if ((req->bmRequest & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_VENDOR) { if ((req->bmRequest & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE) { - if (sectrue == usb21_enabled && req->bRequest == USB_WEBUSB_VENDOR_CODE) { + if (sectrue == usb->usb21_enabled && + req->bRequest == USB_WEBUSB_VENDOR_CODE) { if (req->wIndex == USB_WEBUSB_REQ_GET_URL && req->wValue == USB_WEBUSB_LANDING_PAGE) { static const char webusb_url[] = { @@ -407,7 +464,7 @@ static uint8_t usb_class_setup(USBD_HandleTypeDef *dev, USBD_CtlError(dev, req); return USBD_FAIL; } - } else if (sectrue == usb21_enabled && + } else if (sectrue == usb->usb21_enabled && req->bRequest == USB_WINUSB_VENDOR_CODE) { if (req->wIndex == USB_WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR) { @@ -440,7 +497,8 @@ static uint8_t usb_class_setup(USBD_HandleTypeDef *dev, } if ((req->bmRequest & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_INTERFACE) { - if (sectrue == usb21_enabled && req->bRequest == USB_WINUSB_VENDOR_CODE) { + if (sectrue == usb->usb21_enabled && + req->bRequest == USB_WINUSB_VENDOR_CODE) { if (req->wIndex == USB_WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR && (req->wValue & 0xFF) == 0) { // reply only if interface is 0 @@ -485,88 +543,89 @@ static uint8_t usb_class_setup(USBD_HandleTypeDef *dev, USBD_CtlError(dev, req); return USBD_FAIL; } - switch (usb_ifaces[req->wIndex].type) { - case USB_IFACE_TYPE_HID: - return usb_hid_class_setup(dev, &usb_ifaces[req->wIndex].hid, req); - case USB_IFACE_TYPE_VCP: - return usb_vcp_class_setup(dev, &usb_ifaces[req->wIndex].vcp, req); - case USB_IFACE_TYPE_WEBUSB: - return usb_webusb_class_setup(dev, &usb_ifaces[req->wIndex].webusb, - req); - default: - wait_random(); - USBD_CtlError(dev, req); - return USBD_FAIL; + + usb_iface_t *iface = &usb->ifaces[req->wIndex]; + if (iface->class != NULL && iface->class->Setup != NULL) { + dev->pUserData = iface->state; + iface->class->Setup(dev, req); + dev->pUserData = NULL; + } else { + wait_random(); + USBD_CtlError(dev, req); + return USBD_FAIL; } } return USBD_OK; } static uint8_t usb_class_data_in(USBD_HandleTypeDef *dev, uint8_t ep_num) { + usb_driver_t *usb = &g_usb_driver; + #ifdef RDI rdi_refresh_session_delay(); #endif + for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { - switch (usb_ifaces[i].type) { - case USB_IFACE_TYPE_HID: - usb_hid_class_data_in(dev, &usb_ifaces[i].hid, ep_num); - break; - case USB_IFACE_TYPE_VCP: - usb_vcp_class_data_in(dev, &usb_ifaces[i].vcp, ep_num); - break; - case USB_IFACE_TYPE_WEBUSB: - usb_webusb_class_data_in(dev, &usb_ifaces[i].webusb, ep_num); - break; - default: - break; + usb_iface_t *iface = &usb->ifaces[i]; + if (iface->class != NULL && iface->class->DataIn != NULL) { + dev->pUserData = iface->state; + iface->class->DataIn(dev, ep_num); } } + + dev->pUserData = NULL; + return USBD_OK; } static uint8_t usb_class_data_out(USBD_HandleTypeDef *dev, uint8_t ep_num) { + usb_driver_t *usb = &g_usb_driver; + #ifdef RDI rdi_refresh_session_delay(); #endif + for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { - switch (usb_ifaces[i].type) { - case USB_IFACE_TYPE_HID: - usb_hid_class_data_out(dev, &usb_ifaces[i].hid, ep_num); - break; - case USB_IFACE_TYPE_VCP: - usb_vcp_class_data_out(dev, &usb_ifaces[i].vcp, ep_num); - break; - case USB_IFACE_TYPE_WEBUSB: - usb_webusb_class_data_out(dev, &usb_ifaces[i].webusb, ep_num); - break; - default: - break; + usb_iface_t *iface = &usb->ifaces[i]; + if (iface->class != NULL && iface->class->DataOut != NULL) { + dev->pUserData = iface->state; + iface->class->DataOut(dev, ep_num); } } + + dev->pUserData = NULL; + return USBD_OK; } static uint8_t usb_class_sof(USBD_HandleTypeDef *dev) { + usb_driver_t *usb = &g_usb_driver; + for (int i = 0; i < USBD_MAX_NUM_INTERFACES; i++) { - switch (usb_ifaces[i].type) { - case USB_IFACE_TYPE_VCP: - usb_vcp_class_sof(dev, &usb_ifaces[i].vcp); - break; - default: - break; + usb_iface_t *iface = &usb->ifaces[i]; + if (iface->class != NULL && iface->class->SOF != NULL) { + dev->pUserData = iface->state; + iface->class->SOF(dev); } } + + dev->pUserData = NULL; + return USBD_OK; } static uint8_t *usb_class_get_cfg_desc(uint16_t *length) { - *length = usb_config_desc->wTotalLength; - return usb_config_buf; + usb_driver_t *usb = &g_usb_driver; + + *length = usb->config_desc->wTotalLength; + return usb->desc_buffer; } static uint8_t *usb_class_get_usrstr_desc(USBD_HandleTypeDef *dev, uint8_t index, uint16_t *length) { - if (sectrue == usb21_enabled && index == USB_WINUSB_EXTRA_STRING_INDEX) { + usb_driver_t *usb = &g_usb_driver; + + if (sectrue == usb->usb21_enabled && index == USB_WINUSB_EXTRA_STRING_INDEX) { static const uint8_t winusb_string_descriptor[] = { 0x12, // bLength USB_DESC_TYPE_STRING, // bDescriptorType diff --git a/core/embed/trezorhal/stm32f4/usb/usb_hid-impl.h b/core/embed/trezorhal/stm32f4/usb/usbd_class_hid.c similarity index 64% rename from core/embed/trezorhal/stm32f4/usb/usb_hid-impl.h rename to core/embed/trezorhal/stm32f4/usb/usbd_class_hid.c index 349822287f..cddb6f10b4 100644 --- a/core/embed/trezorhal/stm32f4/usb/usb_hid-impl.h +++ b/core/embed/trezorhal/stm32f4/usb/usbd_class_hid.c @@ -17,6 +17,14 @@ * along with this program. If not, see . */ +#include "common.h" +#include "random_delays.h" + +#include "usbd_core.h" +#include "usbd_internal.h" + +#include "usb_hid.h" + #define USB_CLASS_HID 0x03 #define USB_DESC_TYPE_HID 0x21 @@ -27,37 +35,81 @@ #define USB_HID_REQ_SET_IDLE 0x0A #define USB_HID_REQ_GET_IDLE 0x02 +typedef struct __attribute__((packed)) { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + uint8_t bReportDescriptorType; + uint16_t wReportDescriptorLength; +} usb_hid_descriptor_t; + +typedef struct __attribute__((packed)) { + usb_interface_descriptor_t iface; + usb_hid_descriptor_t hid; + usb_endpoint_descriptor_t ep_in; + usb_endpoint_descriptor_t ep_out; +} usb_hid_descriptor_block_t; + +/* usb_hid_state_t encapsulates all state used by enabled HID interface. It + * needs to be completely initialized in usb_hid_add and reset in + * usb_hid_class_init. See usb_hid_info_t for details of the configuration + * fields. */ + +typedef struct { + USBD_HandleTypeDef *dev_handle; + const usb_hid_descriptor_block_t *desc_block; + const uint8_t *report_desc; + uint8_t *rx_buffer; + uint8_t ep_in; + uint8_t ep_out; + uint8_t max_packet_len; + uint8_t report_desc_len; + + uint8_t protocol; // For SET_PROTOCOL/GET_PROTOCOL setup reqs + uint8_t idle_rate; // For SET_IDLE/GET_IDLE setup reqs + uint8_t alt_setting; // For SET_INTERFACE/GET_INTERFACE setup reqs + uint8_t last_read_len; // Length of data read into rx_buffer + uint8_t ep_in_is_idle; // Set to 1 after IN endpoint gets idle +} usb_hid_state_t; + +_Static_assert(sizeof(usb_hid_state_t) <= USBD_CLASS_STATE_MAX_SIZE); + +// interface dispatch functions +static const USBD_ClassTypeDef usb_hid_class; + +#define usb_get_hid_state(iface_num) \ + ((usb_hid_state_t *)usb_get_iface_state(iface_num, &usb_hid_class)) + /* usb_hid_add adds and configures new USB HID interface according to * configuration options passed in `info`. */ secbool usb_hid_add(const usb_hid_info_t *info) { - usb_iface_t *iface = usb_get_iface(info->iface_num); + usb_hid_state_t *state = usb_get_iface_state(info->iface_num, NULL); - if (iface == NULL) { + if (state == NULL) { return secfalse; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_DISABLED) { - return secfalse; // Interface is already enabled - } usb_hid_descriptor_block_t *d = - usb_desc_alloc_iface(sizeof(usb_hid_descriptor_block_t)); + usb_alloc_class_descriptors(sizeof(usb_hid_descriptor_block_t)); if (d == NULL) { return secfalse; // Not enough space in the configuration descriptor } - if ((info->ep_in & USB_EP_DIR_MASK) != USB_EP_DIR_IN) { - return secfalse; // IN EP is invalid - } - if ((info->ep_out & USB_EP_DIR_MASK) != USB_EP_DIR_OUT) { - return secfalse; // OUT EP is invalid - } if (info->rx_buffer == NULL) { return secfalse; } if (info->report_desc == NULL) { return secfalse; } + if (info->ep_in >= USBD_MAX_NUM_INTERFACES) { + return secfalse; + } + if (info->ep_out >= USBD_MAX_NUM_INTERFACES) { + return secfalse; + } // Interface descriptor d->iface.bLength = sizeof(usb_interface_descriptor_t); @@ -82,7 +134,7 @@ secbool usb_hid_add(const usb_hid_info_t *info) { // IN endpoint (sending) d->ep_in.bLength = sizeof(usb_endpoint_descriptor_t); d->ep_in.bDescriptorType = USB_DESC_TYPE_ENDPOINT; - d->ep_in.bEndpointAddress = info->ep_in; + d->ep_in.bEndpointAddress = info->ep_in | USB_EP_DIR_IN; d->ep_in.bmAttributes = USBD_EP_TYPE_INTR; d->ep_in.wMaxPacketSize = info->max_packet_len; d->ep_in.bInterval = info->polling_interval; @@ -90,75 +142,67 @@ secbool usb_hid_add(const usb_hid_info_t *info) { // OUT endpoint (receiving) d->ep_out.bLength = sizeof(usb_endpoint_descriptor_t); d->ep_out.bDescriptorType = USB_DESC_TYPE_ENDPOINT; - d->ep_out.bEndpointAddress = info->ep_out; + d->ep_out.bEndpointAddress = info->ep_out | USB_EP_DIR_OUT; d->ep_out.bmAttributes = USBD_EP_TYPE_INTR; d->ep_out.wMaxPacketSize = info->max_packet_len; d->ep_out.bInterval = info->polling_interval; - // Config descriptor - usb_desc_add_iface(sizeof(usb_hid_descriptor_block_t)); - // Interface state - iface->type = USB_IFACE_TYPE_HID; - iface->hid.desc_block = d; - iface->hid.report_desc = info->report_desc; - iface->hid.rx_buffer = info->rx_buffer; - iface->hid.ep_in = info->ep_in; - iface->hid.ep_out = info->ep_out; - iface->hid.max_packet_len = info->max_packet_len; - iface->hid.report_desc_len = info->report_desc_len; - iface->hid.protocol = 0; - iface->hid.idle_rate = 0; - iface->hid.alt_setting = 0; - iface->hid.last_read_len = 0; - iface->hid.ep_in_is_idle = 1; + state->dev_handle = usb_get_dev_handle(); + state->desc_block = d; + state->report_desc = info->report_desc; + state->rx_buffer = info->rx_buffer; + state->ep_in = info->ep_in | USB_EP_DIR_IN; + state->ep_out = info->ep_out | USB_EP_DIR_OUT; + state->max_packet_len = info->max_packet_len; + state->report_desc_len = info->report_desc_len; + state->protocol = 0; + state->idle_rate = 0; + state->alt_setting = 0; + state->last_read_len = 0; + state->ep_in_is_idle = 1; + + usb_set_iface_class(info->iface_num, &usb_hid_class); return sectrue; } secbool usb_hid_can_read(uint8_t iface_num) { - usb_iface_t *iface = usb_get_iface(iface_num); - if (iface == NULL) { + usb_hid_state_t *state = usb_get_hid_state(iface_num); + + if (state == NULL) { return secfalse; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_HID) { - return secfalse; // Invalid interface type - } - if (iface->hid.last_read_len == 0) { + if (state->last_read_len == 0) { return secfalse; // Nothing in the receiving buffer } - if (usb_dev_handle.dev_state != USBD_STATE_CONFIGURED) { + + if (state->dev_handle->dev_state != USBD_STATE_CONFIGURED) { return secfalse; // Device is not configured } return sectrue; } secbool usb_hid_can_write(uint8_t iface_num) { - usb_iface_t *iface = usb_get_iface(iface_num); - if (iface == NULL) { + usb_hid_state_t *state = usb_get_hid_state(iface_num); + if (state == NULL) { return secfalse; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_HID) { - return secfalse; // Invalid interface type - } - if (iface->hid.ep_in_is_idle == 0) { + if (state->ep_in_is_idle == 0) { return secfalse; // Last transmission is not over yet } - if (usb_dev_handle.dev_state != USBD_STATE_CONFIGURED) { + if (state->dev_handle->dev_state != USBD_STATE_CONFIGURED) { return secfalse; // Device is not configured } return sectrue; } int usb_hid_read(uint8_t iface_num, uint8_t *buf, uint32_t len) { - usb_iface_t *iface = usb_get_iface(iface_num); - if (iface == NULL) { + volatile usb_hid_state_t *state = usb_get_hid_state(iface_num); + + if (state == NULL) { return -1; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_HID) { - return -2; // Invalid interface type - } - volatile usb_hid_state_t *state = &iface->hid; // Copy maximum possible amount of data uint32_t last_read_len = state->last_read_len; @@ -171,28 +215,26 @@ int usb_hid_read(uint8_t iface_num, uint8_t *buf, uint32_t len) { state->last_read_len = 0; // Prepare the OUT EP to receive next packet - USBD_LL_PrepareReceive(&usb_dev_handle, state->ep_out, state->rx_buffer, + USBD_LL_PrepareReceive(state->dev_handle, state->ep_out, state->rx_buffer, state->max_packet_len); return last_read_len; } int usb_hid_write(uint8_t iface_num, const uint8_t *buf, uint32_t len) { - usb_iface_t *iface = usb_get_iface(iface_num); - if (iface == NULL) { + volatile usb_hid_state_t *state = usb_get_hid_state(iface_num); + + if (state == NULL) { return -1; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_HID) { - return -2; // Invalid interface type - } - volatile usb_hid_state_t *state = &iface->hid; if (state->ep_in_is_idle == 0) { return 0; // Last transmission is not over yet } state->ep_in_is_idle = 0; - USBD_LL_Transmit(&usb_dev_handle, state->ep_in, UNCONST(buf), (uint16_t)len); + USBD_LL_Transmit(state->dev_handle, state->ep_in, UNCONST(buf), + (uint16_t)len); return len; } @@ -237,8 +279,9 @@ int usb_hid_write_blocking(uint8_t iface_num, const uint8_t *buf, uint32_t len, return usb_hid_write(iface_num, buf, len); } -static void usb_hid_class_init(USBD_HandleTypeDef *dev, usb_hid_state_t *state, - uint8_t cfg_idx) { +static uint8_t usb_hid_class_init(USBD_HandleTypeDef *dev, uint8_t cfg_idx) { + usb_hid_state_t *state = (usb_hid_state_t *)dev->pUserData; + // Open endpoints USBD_LL_OpenEP(dev, state->ep_in, USBD_EP_TYPE_INTR, state->max_packet_len); USBD_LL_OpenEP(dev, state->ep_out, USBD_EP_TYPE_INTR, state->max_packet_len); @@ -253,20 +296,27 @@ static void usb_hid_class_init(USBD_HandleTypeDef *dev, usb_hid_state_t *state, // Prepare the OUT EP to receive next packet USBD_LL_PrepareReceive(dev, state->ep_out, state->rx_buffer, state->max_packet_len); + + return USBD_OK; } -static void usb_hid_class_deinit(USBD_HandleTypeDef *dev, - usb_hid_state_t *state, uint8_t cfg_idx) { +static uint8_t usb_hid_class_deinit(USBD_HandleTypeDef *dev, uint8_t cfg_idx) { + usb_hid_state_t *state = (usb_hid_state_t *)dev->pUserData; + // Flush endpoints USBD_LL_FlushEP(dev, state->ep_in); USBD_LL_FlushEP(dev, state->ep_out); // Close endpoints USBD_LL_CloseEP(dev, state->ep_in); USBD_LL_CloseEP(dev, state->ep_out); + + return USBD_OK; } -static int usb_hid_class_setup(USBD_HandleTypeDef *dev, usb_hid_state_t *state, - USBD_SetupReqTypedef *req) { +static uint8_t usb_hid_class_setup(USBD_HandleTypeDef *dev, + USBD_SetupReqTypedef *req) { + usb_hid_state_t *state = (usb_hid_state_t *)dev->pUserData; + wait_random(); switch (req->bmRequest & USB_REQ_TYPE_MASK) { @@ -339,20 +389,44 @@ static int usb_hid_class_setup(USBD_HandleTypeDef *dev, usb_hid_state_t *state, return USBD_OK; } -static void usb_hid_class_data_in(USBD_HandleTypeDef *dev, - usb_hid_state_t *state, uint8_t ep_num) { +static uint8_t usb_hid_class_data_in(USBD_HandleTypeDef *dev, uint8_t ep_num) { + usb_hid_state_t *state = (usb_hid_state_t *)dev->pUserData; + if ((ep_num | USB_EP_DIR_IN) == state->ep_in) { wait_random(); state->ep_in_is_idle = 1; } + + return USBD_OK; } -static void usb_hid_class_data_out(USBD_HandleTypeDef *dev, - usb_hid_state_t *state, uint8_t ep_num) { +static uint8_t usb_hid_class_data_out(USBD_HandleTypeDef *dev, uint8_t ep_num) { + usb_hid_state_t *state = (usb_hid_state_t *)dev->pUserData; + if (ep_num == state->ep_out) { wait_random(); // Save the report length to indicate we have read something, but don't // schedule next reading until user reads this one state->last_read_len = USBD_LL_GetRxDataSize(dev, ep_num); } + + return USBD_OK; } + +static const USBD_ClassTypeDef usb_hid_class = { + .Init = usb_hid_class_init, + .DeInit = usb_hid_class_deinit, + .Setup = usb_hid_class_setup, + .EP0_TxSent = NULL, + .EP0_RxReady = NULL, + .DataIn = usb_hid_class_data_in, + .DataOut = usb_hid_class_data_out, + .SOF = NULL, + .IsoINIncomplete = NULL, + .IsoOUTIncomplete = NULL, + .GetHSConfigDescriptor = NULL, + .GetFSConfigDescriptor = NULL, + .GetOtherSpeedConfigDescriptor = NULL, + .GetDeviceQualifierDescriptor = NULL, + .GetUsrStrDescriptor = NULL, +}; diff --git a/core/embed/trezorhal/stm32f4/usb/usb_vcp-impl.h b/core/embed/trezorhal/stm32f4/usb/usbd_class_vcp.c similarity index 62% rename from core/embed/trezorhal/stm32f4/usb/usb_vcp-impl.h rename to core/embed/trezorhal/stm32f4/usb/usbd_class_vcp.c index 5652eb7175..d30f308bbd 100644 --- a/core/embed/trezorhal/stm32f4/usb/usb_vcp-impl.h +++ b/core/embed/trezorhal/stm32f4/usb/usbd_class_vcp.c @@ -17,6 +17,13 @@ * along with this program. If not, see . */ +#include "common.h" + +#include "usbd_core.h" +#include "usbd_internal.h" + +#include "usb_vcp.h" + // Communications Device Class Code (bFunctionClass, bInterfaceClass) #define USB_CLASS_CDC 0x02 @@ -50,34 +57,129 @@ #define USB_CDC_GET_LINE_CODING 0x21 #define USB_CDC_SET_CONTROL_LINE_STATE 0x22 +typedef struct __attribute__((packed)) { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint16_t bcdCDC; +} usb_vcp_header_descriptor_t; + +typedef struct __attribute__((packed)) { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; + uint8_t bDataInterface; +} usb_vcp_cm_descriptor_t; + +typedef struct __attribute__((packed)) { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; +} usb_vcp_acm_descriptor_t; + +typedef struct __attribute__((packed)) { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bControlInterface; + uint8_t bSubordinateInterface0; +} usb_vcp_union_descriptor_t; + +typedef struct __attribute__((packed)) { + usb_interface_assoc_descriptor_t assoc; + usb_interface_descriptor_t iface_cdc; + usb_vcp_header_descriptor_t + fheader; // Class-Specific Descriptor Header Format + usb_vcp_cm_descriptor_t fcm; // Call Management Functional Descriptor + usb_vcp_acm_descriptor_t + facm; // Abstract Control Management Functional Descriptor + usb_vcp_union_descriptor_t funion; // Union Interface Functional Descriptor + usb_endpoint_descriptor_t ep_cmd; + usb_interface_descriptor_t iface_data; + usb_endpoint_descriptor_t ep_in; + usb_endpoint_descriptor_t ep_out; +} usb_vcp_descriptor_block_t; + +typedef struct __attribute__((packed)) { + uint32_t dwDTERate; + uint8_t bCharFormat; // usb_cdc_line_coding_bCharFormat_t + uint8_t bParityType; // usb_cdc_line_coding_bParityType_t + uint8_t bDataBits; +} usb_cdc_line_coding_t; + +typedef enum { + USB_CDC_1_STOP_BITS = 0, + USB_CDC_1_5_STOP_BITS = 1, + USB_CDC_2_STOP_BITS = 2, +} usb_cdc_line_coding_bCharFormat_t; + +typedef enum { + USB_CDC_NO_PARITY = 0, + USB_CDC_ODD_PARITY = 1, + USB_CDC_EVEN_PARITY = 2, + USB_CDC_MARK_PARITY = 3, + USB_CDC_SPACE_PARITY = 4, +} usb_cdc_line_coding_bParityType_t; + +/* usb_rbuf_t is used internally for the RX/TX buffering. */ +typedef struct { + size_t cap; + volatile size_t read; + volatile size_t write; + uint8_t *buf; +} usb_rbuf_t; + +// Maximal length of packets on IN CMD EP +#define USB_CDC_MAX_CMD_PACKET_LEN 0x08 + +/* usb_vcp_state_t encapsulates all state used by enabled VCP interface. It + * needs to be completely initialized in usb_vcp_add and reset in + * usb_vcp_class_init. See usb_vcp_info_t for details of the configuration + * fields. */ +typedef struct { + USBD_HandleTypeDef *dev_handle; + const usb_vcp_descriptor_block_t *desc_block; + usb_rbuf_t rx_ring; + usb_rbuf_t tx_ring; + uint8_t *rx_packet; + uint8_t *tx_packet; + void (*rx_intr_fn)(void); + uint8_t rx_intr_byte; + uint8_t ep_cmd; + uint8_t ep_in; + uint8_t ep_out; + uint8_t max_packet_len; + uint8_t ep_in_is_idle; // Set to 1 after IN endpoint gets idle + uint8_t cmd_buffer[USB_CDC_MAX_CMD_PACKET_LEN]; +} usb_vcp_state_t; + +_Static_assert(sizeof(usb_vcp_state_t) <= USBD_CLASS_STATE_MAX_SIZE); + +// interface dispatch functions +static const USBD_ClassTypeDef usb_vcp_class; +static const USBD_ClassTypeDef usb_vcp_data_class; + +#define usb_get_vcp_state(iface_num) \ + ((usb_vcp_state_t *)usb_get_iface_state(iface_num, &usb_vcp_class)) + /* usb_vcp_add adds and configures new USB VCP interface according to * configuration options passed in `info`. */ secbool usb_vcp_add(const usb_vcp_info_t *info) { - usb_iface_t *iface = usb_get_iface(info->iface_num); + usb_vcp_state_t *state = usb_get_iface_state(info->iface_num, NULL); - if (iface == NULL) { + if (state == NULL) { return secfalse; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_DISABLED) { - return secfalse; // Interface is already enabled - } usb_vcp_descriptor_block_t *d = - usb_desc_alloc_iface(sizeof(usb_vcp_descriptor_block_t)); + usb_alloc_class_descriptors(sizeof(usb_vcp_descriptor_block_t)); if (d == NULL) { return secfalse; // Not enough space in the configuration descriptor } - if ((info->ep_cmd & USB_EP_DIR_MASK) != USB_EP_DIR_IN) { - return secfalse; // IN CMD EP is invalid - } - if ((info->ep_in & USB_EP_DIR_MASK) != USB_EP_DIR_IN) { - return secfalse; // IN EP is invalid - } - if ((info->ep_out & USB_EP_DIR_MASK) != USB_EP_DIR_OUT) { - return secfalse; // OUT EP is invalid - } if ((info->rx_buffer_len == 0) || (info->rx_buffer_len & (info->rx_buffer_len - 1)) != 0) { return secfalse; // Capacity needs to be a power of 2 @@ -98,6 +200,15 @@ secbool usb_vcp_add(const usb_vcp_info_t *info) { if (info->tx_packet == NULL) { return secfalse; } + if (info->ep_in >= USBD_MAX_NUM_INTERFACES) { + return secfalse; + } + if (info->ep_out >= USBD_MAX_NUM_INTERFACES) { + return secfalse; + } + if (info->ep_cmd >= USBD_MAX_NUM_INTERFACES) { + return secfalse; + } // Interface association descriptor d->assoc.bLength = sizeof(usb_interface_assoc_descriptor_t); @@ -155,7 +266,7 @@ secbool usb_vcp_add(const usb_vcp_info_t *info) { // IN CMD endpoint (control) d->ep_cmd.bLength = sizeof(usb_endpoint_descriptor_t); d->ep_cmd.bDescriptorType = USB_DESC_TYPE_ENDPOINT; - d->ep_cmd.bEndpointAddress = info->ep_cmd; + d->ep_cmd.bEndpointAddress = info->ep_cmd | USB_EP_DIR_IN; d->ep_cmd.bmAttributes = USBD_EP_TYPE_INTR; d->ep_cmd.wMaxPacketSize = USB_CDC_MAX_CMD_PACKET_LEN; d->ep_cmd.bInterval = info->polling_interval; @@ -174,7 +285,7 @@ secbool usb_vcp_add(const usb_vcp_info_t *info) { // OUT endpoint (receiving) d->ep_out.bLength = sizeof(usb_endpoint_descriptor_t); d->ep_out.bDescriptorType = USB_DESC_TYPE_ENDPOINT; - d->ep_out.bEndpointAddress = info->ep_out; + d->ep_out.bEndpointAddress = info->ep_out | USB_EP_DIR_OUT; d->ep_out.bmAttributes = USBD_EP_TYPE_BULK; d->ep_out.wMaxPacketSize = info->max_packet_len; d->ep_out.bInterval = 0; @@ -182,43 +293,43 @@ secbool usb_vcp_add(const usb_vcp_info_t *info) { // IN endpoint (sending) d->ep_in.bLength = sizeof(usb_endpoint_descriptor_t); d->ep_in.bDescriptorType = USB_DESC_TYPE_ENDPOINT; - d->ep_in.bEndpointAddress = info->ep_in; + d->ep_in.bEndpointAddress = info->ep_in | USB_EP_DIR_IN; d->ep_in.bmAttributes = USBD_EP_TYPE_BULK; d->ep_in.wMaxPacketSize = info->max_packet_len; d->ep_in.bInterval = 0; - // Config descriptor - usb_desc_add_iface(sizeof(usb_vcp_descriptor_block_t)); - usb_config_desc - ->bNumInterfaces++; // usb_vcp_descriptor_block_t contains 2 interfaces - // Interface state + state->dev_handle = usb_get_dev_handle(); + state->desc_block = d; - iface->type = USB_IFACE_TYPE_VCP; - iface->vcp.desc_block = d; + state->rx_ring.buf = info->rx_buffer; + state->rx_ring.cap = info->rx_buffer_len; + state->rx_ring.read = 0; + state->rx_ring.write = 0; - iface->vcp.rx_ring.buf = info->rx_buffer; - iface->vcp.rx_ring.cap = info->rx_buffer_len; - iface->vcp.rx_ring.read = 0; - iface->vcp.rx_ring.write = 0; + state->tx_ring.buf = info->tx_buffer; + state->tx_ring.cap = info->tx_buffer_len; + state->tx_ring.read = 0; + state->tx_ring.write = 0; - iface->vcp.tx_ring.buf = info->tx_buffer; - iface->vcp.tx_ring.cap = info->tx_buffer_len; - iface->vcp.tx_ring.read = 0; - iface->vcp.tx_ring.write = 0; + state->rx_packet = info->rx_packet; + state->tx_packet = info->tx_packet; - iface->vcp.rx_packet = info->rx_packet; - iface->vcp.tx_packet = info->tx_packet; + state->rx_intr_fn = info->rx_intr_fn; + state->rx_intr_byte = info->rx_intr_byte; - iface->vcp.rx_intr_fn = info->rx_intr_fn; - iface->vcp.rx_intr_byte = info->rx_intr_byte; + state->ep_cmd = info->ep_cmd | USB_EP_DIR_IN; + state->ep_in = info->ep_in | USB_EP_DIR_IN; + state->ep_out = info->ep_out | USB_EP_DIR_OUT; + state->max_packet_len = info->max_packet_len; - iface->vcp.ep_cmd = info->ep_cmd; - iface->vcp.ep_in = info->ep_in; - iface->vcp.ep_out = info->ep_out; - iface->vcp.max_packet_len = info->max_packet_len; + state->ep_in_is_idle = 1; - iface->vcp.ep_in_is_idle = 1; + usb_set_iface_class(info->iface_num, &usb_vcp_class); + + // This just make the data interface slot occupied so it can't be reused + // by another class driver. Data interface dispatch functiona are not used. + usb_set_iface_class(info->data_iface_num, &usb_vcp_data_class); return sectrue; } @@ -230,42 +341,32 @@ static inline int ring_empty(usb_rbuf_t *b) { return ring_length(b) == 0; } static inline int ring_full(usb_rbuf_t *b) { return ring_length(b) == b->cap; } secbool usb_vcp_can_read(uint8_t iface_num) { - usb_iface_t *iface = usb_get_iface(iface_num); - if (iface == NULL) { + usb_vcp_state_t *state = usb_get_vcp_state(iface_num); + if (state == NULL) { return secfalse; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_VCP) { - return secfalse; // Invalid interface type - } - if (ring_empty(&iface->vcp.rx_ring)) { + if (ring_empty(&state->rx_ring)) { return secfalse; // Nothing in the rx buffer } return sectrue; } secbool usb_vcp_can_write(uint8_t iface_num) { - usb_iface_t *iface = usb_get_iface(iface_num); - if (iface == NULL) { + usb_vcp_state_t *state = usb_get_vcp_state(iface_num); + if (state == NULL) { return secfalse; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_VCP) { - return secfalse; // Invalid interface type - } - if (ring_full(&iface->vcp.tx_ring)) { + if (ring_full(&state->tx_ring)) { return secfalse; // Tx ring buffer is full } return sectrue; } int usb_vcp_read(uint8_t iface_num, uint8_t *buf, uint32_t len) { - usb_iface_t *iface = usb_get_iface(iface_num); - if (iface == NULL) { + usb_vcp_state_t *state = usb_get_vcp_state(iface_num); + if (state == NULL) { return -1; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_VCP) { - return -2; // Invalid interface type - } - usb_vcp_state_t *state = &iface->vcp; // Read from the rx ring buffer usb_rbuf_t *b = &state->rx_ring; @@ -279,14 +380,10 @@ int usb_vcp_read(uint8_t iface_num, uint8_t *buf, uint32_t len) { } int usb_vcp_write(uint8_t iface_num, const uint8_t *buf, uint32_t len) { - usb_iface_t *iface = usb_get_iface(iface_num); - if (iface == NULL) { + usb_vcp_state_t *state = usb_get_vcp_state(iface_num); + if (state == NULL) { return -1; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_VCP) { - return -2; // Invalid interface type - } - usb_vcp_state_t *state = &iface->vcp; // Write into the tx ring buffer usb_rbuf_t *b = &state->tx_ring; @@ -330,8 +427,9 @@ int usb_vcp_write_blocking(uint8_t iface_num, const uint8_t *buf, uint32_t len, return i; } -static void usb_vcp_class_init(USBD_HandleTypeDef *dev, usb_vcp_state_t *state, - uint8_t cfg_idx) { +static uint8_t usb_vcp_class_init(USBD_HandleTypeDef *dev, uint8_t cfg_idx) { + usb_vcp_state_t *state = (usb_vcp_state_t *)dev->pUserData; + // Open endpoints USBD_LL_OpenEP(dev, state->ep_in, USBD_EP_TYPE_BULK, state->max_packet_len); USBD_LL_OpenEP(dev, state->ep_out, USBD_EP_TYPE_BULK, state->max_packet_len); @@ -348,10 +446,13 @@ static void usb_vcp_class_init(USBD_HandleTypeDef *dev, usb_vcp_state_t *state, // Prepare the OUT EP to receive next packet USBD_LL_PrepareReceive(dev, state->ep_out, state->rx_packet, state->max_packet_len); + + return USBD_OK; } -static void usb_vcp_class_deinit(USBD_HandleTypeDef *dev, - usb_vcp_state_t *state, uint8_t cfg_idx) { +static uint8_t usb_vcp_class_deinit(USBD_HandleTypeDef *dev, uint8_t cfg_idx) { + usb_vcp_state_t *state = (usb_vcp_state_t *)dev->pUserData; + // Flush endpoints USBD_LL_FlushEP(dev, state->ep_in); USBD_LL_FlushEP(dev, state->ep_out); @@ -360,10 +461,14 @@ static void usb_vcp_class_deinit(USBD_HandleTypeDef *dev, USBD_LL_CloseEP(dev, state->ep_in); USBD_LL_CloseEP(dev, state->ep_out); USBD_LL_CloseEP(dev, state->ep_cmd); + + return USBD_OK; } -static int usb_vcp_class_setup(USBD_HandleTypeDef *dev, usb_vcp_state_t *state, - USBD_SetupReqTypedef *req) { +static uint8_t usb_vcp_class_setup(USBD_HandleTypeDef *dev, + USBD_SetupReqTypedef *req) { + usb_vcp_state_t *state = (usb_vcp_state_t *)dev->pUserData; + static const usb_cdc_line_coding_t line_coding = { .dwDTERate = 115200, .bCharFormat = USB_CDC_1_STOP_BITS, @@ -393,15 +498,19 @@ static int usb_vcp_class_setup(USBD_HandleTypeDef *dev, usb_vcp_state_t *state, return USBD_OK; } -static void usb_vcp_class_data_in(USBD_HandleTypeDef *dev, - usb_vcp_state_t *state, uint8_t ep_num) { +static uint8_t usb_vcp_class_data_in(USBD_HandleTypeDef *dev, uint8_t ep_num) { + usb_vcp_state_t *state = (usb_vcp_state_t *)dev->pUserData; + if ((ep_num | USB_EP_DIR_IN) == state->ep_in) { state->ep_in_is_idle = 1; } + + return USBD_OK; } -static void usb_vcp_class_data_out(USBD_HandleTypeDef *dev, - usb_vcp_state_t *state, uint8_t ep_num) { +static uint8_t usb_vcp_class_data_out(USBD_HandleTypeDef *dev, uint8_t ep_num) { + usb_vcp_state_t *state = (usb_vcp_state_t *)dev->pUserData; + if (ep_num == state->ep_out) { uint32_t len = USBD_LL_GetRxDataSize(dev, ep_num); @@ -425,11 +534,15 @@ static void usb_vcp_class_data_out(USBD_HandleTypeDef *dev, USBD_LL_PrepareReceive(dev, state->ep_out, state->rx_packet, state->max_packet_len); } + + return USBD_OK; } -static void usb_vcp_class_sof(USBD_HandleTypeDef *dev, usb_vcp_state_t *state) { +static uint8_t usb_vcp_class_sof(USBD_HandleTypeDef *dev) { + usb_vcp_state_t *state = (usb_vcp_state_t *)dev->pUserData; + if (!state->ep_in_is_idle) { - return; + return USBD_OK; } // Read from the tx ring buffer @@ -447,6 +560,28 @@ static void usb_vcp_class_sof(USBD_HandleTypeDef *dev, usb_vcp_state_t *state) { if (i > 0) { state->ep_in_is_idle = 0; - USBD_LL_Transmit(&usb_dev_handle, state->ep_in, buf, (uint16_t)i); + USBD_LL_Transmit(dev, state->ep_in, buf, (uint16_t)i); } + + return USBD_OK; } + +static const USBD_ClassTypeDef usb_vcp_class = { + .Init = usb_vcp_class_init, + .DeInit = usb_vcp_class_deinit, + .Setup = usb_vcp_class_setup, + .EP0_TxSent = NULL, + .EP0_RxReady = NULL, + .DataIn = usb_vcp_class_data_in, + .DataOut = usb_vcp_class_data_out, + .SOF = usb_vcp_class_sof, + .IsoINIncomplete = NULL, + .IsoOUTIncomplete = NULL, + .GetHSConfigDescriptor = NULL, + .GetFSConfigDescriptor = NULL, + .GetOtherSpeedConfigDescriptor = NULL, + .GetDeviceQualifierDescriptor = NULL, + .GetUsrStrDescriptor = NULL, +}; + +static const USBD_ClassTypeDef usb_vcp_data_class = {}; diff --git a/core/embed/trezorhal/stm32f4/usb/usb_webusb-impl.h b/core/embed/trezorhal/stm32f4/usb/usbd_class_webusb.c similarity index 58% rename from core/embed/trezorhal/stm32f4/usb/usb_webusb-impl.h rename to core/embed/trezorhal/stm32f4/usb/usbd_class_webusb.c index 3ffe4589e8..55fc5448c5 100644 --- a/core/embed/trezorhal/stm32f4/usb/usb_webusb-impl.h +++ b/core/embed/trezorhal/stm32f4/usb/usbd_class_webusb.c @@ -17,36 +17,73 @@ * along with this program. If not, see . */ +#include "common.h" +#include "random_delays.h" + +#include "usbd_core.h" +#include "usbd_internal.h" + +#include "usb_webusb.h" + #define USB_CLASS_WEBUSB 0xFF +typedef struct __attribute__((packed)) { + usb_interface_descriptor_t iface; + usb_endpoint_descriptor_t ep_in; + usb_endpoint_descriptor_t ep_out; +} usb_webusb_descriptor_block_t; + +/* usb_webusb_state_t encapsulates all state used by enabled WebUSB interface. + * It needs to be completely initialized in usb_webusb_add and reset in + * usb_webusb_class_init. See usb_webusb_info_t for details of the + * configuration fields. */ +typedef struct { + USBD_HandleTypeDef *dev_handle; + const usb_webusb_descriptor_block_t *desc_block; + uint8_t *rx_buffer; + uint8_t ep_in; + uint8_t ep_out; + uint8_t max_packet_len; + + uint8_t alt_setting; // For SET_INTERFACE/GET_INTERFACE setup reqs + uint8_t last_read_len; // Length of data read into rx_buffer + uint8_t ep_in_is_idle; // Set to 1 after IN endpoint gets idle +} usb_webusb_state_t; + +_Static_assert(sizeof(usb_webusb_state_t) <= USBD_CLASS_STATE_MAX_SIZE); + +// interface dispatch functions +static const USBD_ClassTypeDef usb_webusb_class; + +#define usb_get_webusb_state(iface_num) \ + ((usb_webusb_state_t *)usb_get_iface_state(iface_num, &usb_webusb_class)) + /* usb_webusb_add adds and configures new USB WebUSB interface according to * configuration options passed in `info`. */ secbool usb_webusb_add(const usb_webusb_info_t *info) { - usb_iface_t *iface = usb_get_iface(info->iface_num); + usb_webusb_state_t *state = + (usb_webusb_state_t *)usb_get_iface_state(info->iface_num, NULL); - if (iface == NULL) { + if (state == NULL) { return secfalse; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_DISABLED) { - return secfalse; // Interface is already enabled - } usb_webusb_descriptor_block_t *d = - usb_desc_alloc_iface(sizeof(usb_webusb_descriptor_block_t)); + usb_alloc_class_descriptors(sizeof(usb_webusb_descriptor_block_t)); if (d == NULL) { return secfalse; // Not enough space in the configuration descriptor } - if ((info->ep_in & USB_EP_DIR_MASK) != USB_EP_DIR_IN) { - return secfalse; // IN EP is invalid - } - if ((info->ep_out & USB_EP_DIR_MASK) != USB_EP_DIR_OUT) { - return secfalse; // OUT EP is invalid - } if (info->rx_buffer == NULL) { return secfalse; } + if (info->ep_in >= USBD_MAX_NUM_INTERFACES) { + return secfalse; + } + if (info->ep_out >= USBD_MAX_NUM_INTERFACES) { + return secfalse; + } // Interface descriptor d->iface.bLength = sizeof(usb_interface_descriptor_t); @@ -62,7 +99,7 @@ secbool usb_webusb_add(const usb_webusb_info_t *info) { // IN endpoint (sending) d->ep_in.bLength = sizeof(usb_endpoint_descriptor_t); d->ep_in.bDescriptorType = USB_DESC_TYPE_ENDPOINT; - d->ep_in.bEndpointAddress = info->ep_in; + d->ep_in.bEndpointAddress = info->ep_in | USB_EP_DIR_IN; d->ep_in.bmAttributes = USBD_EP_TYPE_INTR; d->ep_in.wMaxPacketSize = info->max_packet_len; d->ep_in.bInterval = info->polling_interval; @@ -70,71 +107,60 @@ secbool usb_webusb_add(const usb_webusb_info_t *info) { // OUT endpoint (receiving) d->ep_out.bLength = sizeof(usb_endpoint_descriptor_t); d->ep_out.bDescriptorType = USB_DESC_TYPE_ENDPOINT; - d->ep_out.bEndpointAddress = info->ep_out; + d->ep_out.bEndpointAddress = info->ep_out | USB_EP_DIR_OUT; d->ep_out.bmAttributes = USBD_EP_TYPE_INTR; d->ep_out.wMaxPacketSize = info->max_packet_len; d->ep_out.bInterval = info->polling_interval; - // Config descriptor - usb_desc_add_iface(sizeof(usb_webusb_descriptor_block_t)); - // Interface state - iface->type = USB_IFACE_TYPE_WEBUSB; - iface->webusb.desc_block = d; - iface->webusb.rx_buffer = info->rx_buffer; - iface->webusb.ep_in = info->ep_in; - iface->webusb.ep_out = info->ep_out; - iface->webusb.max_packet_len = info->max_packet_len; - iface->webusb.alt_setting = 0; - iface->webusb.last_read_len = 0; - iface->webusb.ep_in_is_idle = 1; + state->dev_handle = usb_get_dev_handle(); + state->desc_block = d; + state->rx_buffer = info->rx_buffer; + state->ep_in = info->ep_in | USB_EP_DIR_IN; + state->ep_out = info->ep_out | USB_EP_DIR_OUT; + state->max_packet_len = info->max_packet_len; + state->alt_setting = 0; + state->last_read_len = 0; + state->ep_in_is_idle = 1; + + usb_set_iface_class(info->iface_num, &usb_webusb_class); return sectrue; } secbool usb_webusb_can_read(uint8_t iface_num) { - usb_iface_t *iface = usb_get_iface(iface_num); - if (iface == NULL) { + usb_webusb_state_t *state = usb_get_webusb_state(iface_num); + if (state == NULL) { return secfalse; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_WEBUSB) { - return secfalse; // Invalid interface type - } - if (iface->webusb.last_read_len == 0) { + if (state->last_read_len == 0) { return secfalse; // Nothing in the receiving buffer } - if (usb_dev_handle.dev_state != USBD_STATE_CONFIGURED) { + if (state->dev_handle->dev_state != USBD_STATE_CONFIGURED) { return secfalse; // Device is not configured } return sectrue; } secbool usb_webusb_can_write(uint8_t iface_num) { - usb_iface_t *iface = usb_get_iface(iface_num); - if (iface == NULL) { + usb_webusb_state_t *state = usb_get_webusb_state(iface_num); + if (state == NULL) { return secfalse; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_WEBUSB) { - return secfalse; // Invalid interface type - } - if (iface->webusb.ep_in_is_idle == 0) { + if (state->ep_in_is_idle == 0) { return secfalse; // Last transmission is not over yet } - if (usb_dev_handle.dev_state != USBD_STATE_CONFIGURED) { + if (state->dev_handle->dev_state != USBD_STATE_CONFIGURED) { return secfalse; // Device is not configured } return sectrue; } int usb_webusb_read(uint8_t iface_num, uint8_t *buf, uint32_t len) { - usb_iface_t *iface = usb_get_iface(iface_num); - if (iface == NULL) { + volatile usb_webusb_state_t *state = usb_get_webusb_state(iface_num); + if (state == NULL) { return -1; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_WEBUSB) { - return -2; // Invalid interface type - } - volatile usb_webusb_state_t *state = &iface->webusb; // Copy maximum possible amount of data uint32_t last_read_len = state->last_read_len; @@ -147,24 +173,21 @@ int usb_webusb_read(uint8_t iface_num, uint8_t *buf, uint32_t len) { state->last_read_len = 0; // Prepare the OUT EP to receive next packet - USBD_LL_PrepareReceive(&usb_dev_handle, state->ep_out, state->rx_buffer, + USBD_LL_PrepareReceive(state->dev_handle, state->ep_out, state->rx_buffer, state->max_packet_len); return last_read_len; } int usb_webusb_write(uint8_t iface_num, const uint8_t *buf, uint32_t len) { - usb_iface_t *iface = usb_get_iface(iface_num); - if (iface == NULL) { + volatile usb_webusb_state_t *state = usb_get_webusb_state(iface_num); + if (state == NULL) { return -1; // Invalid interface number } - if (iface->type != USB_IFACE_TYPE_WEBUSB) { - return -2; // Invalid interface type - } - volatile usb_webusb_state_t *state = &iface->webusb; state->ep_in_is_idle = 0; - USBD_LL_Transmit(&usb_dev_handle, state->ep_in, UNCONST(buf), (uint16_t)len); + USBD_LL_Transmit(state->dev_handle, state->ep_in, UNCONST(buf), + (uint16_t)len); return len; } @@ -209,8 +232,9 @@ int usb_webusb_write_blocking(uint8_t iface_num, const uint8_t *buf, return usb_webusb_write(iface_num, buf, len); } -static void usb_webusb_class_init(USBD_HandleTypeDef *dev, - usb_webusb_state_t *state, uint8_t cfg_idx) { +static uint8_t usb_webusb_class_init(USBD_HandleTypeDef *dev, uint8_t cfg_idx) { + usb_webusb_state_t *state = (usb_webusb_state_t *)dev->pUserData; + // Open endpoints USBD_LL_OpenEP(dev, state->ep_in, USBD_EP_TYPE_INTR, state->max_packet_len); USBD_LL_OpenEP(dev, state->ep_out, USBD_EP_TYPE_INTR, state->max_packet_len); @@ -223,22 +247,30 @@ static void usb_webusb_class_init(USBD_HandleTypeDef *dev, // Prepare the OUT EP to receive next packet USBD_LL_PrepareReceive(dev, state->ep_out, state->rx_buffer, state->max_packet_len); + + return USBD_OK; } -static void usb_webusb_class_deinit(USBD_HandleTypeDef *dev, - usb_webusb_state_t *state, - uint8_t cfg_idx) { +static uint8_t usb_webusb_class_deinit(USBD_HandleTypeDef *dev, + uint8_t cfg_idx) { + usb_webusb_state_t *state = (usb_webusb_state_t *)dev->pUserData; + // Flush endpoints USBD_LL_FlushEP(dev, state->ep_in); USBD_LL_FlushEP(dev, state->ep_out); // Close endpoints USBD_LL_CloseEP(dev, state->ep_in); USBD_LL_CloseEP(dev, state->ep_out); + + return USBD_OK; } -static int usb_webusb_class_setup(USBD_HandleTypeDef *dev, - usb_webusb_state_t *state, - USBD_SetupReqTypedef *req) { +static uint8_t usb_webusb_class_setup(USBD_HandleTypeDef *dev, + USBD_SetupReqTypedef *req) { + usb_webusb_state_t *state = (usb_webusb_state_t *)dev->pUserData; + + wait_random(); + if ((req->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) { return USBD_OK; } @@ -259,24 +291,50 @@ static int usb_webusb_class_setup(USBD_HandleTypeDef *dev, USBD_CtlError(dev, req); return USBD_FAIL; } + + return USBD_OK; } -static void usb_webusb_class_data_in(USBD_HandleTypeDef *dev, - usb_webusb_state_t *state, - uint8_t ep_num) { +static uint8_t usb_webusb_class_data_in(USBD_HandleTypeDef *dev, + uint8_t ep_num) { + usb_webusb_state_t *state = (usb_webusb_state_t *)dev->pUserData; + if ((ep_num | USB_EP_DIR_IN) == state->ep_in) { wait_random(); state->ep_in_is_idle = 1; } + + return USBD_OK; } -static void usb_webusb_class_data_out(USBD_HandleTypeDef *dev, - usb_webusb_state_t *state, - uint8_t ep_num) { +static uint8_t usb_webusb_class_data_out(USBD_HandleTypeDef *dev, + uint8_t ep_num) { + usb_webusb_state_t *state = (usb_webusb_state_t *)dev->pUserData; + if (ep_num == state->ep_out) { wait_random(); // Save the report length to indicate we have read something, but don't // schedule next reading until user reads this one state->last_read_len = USBD_LL_GetRxDataSize(dev, ep_num); } + + return USBD_OK; } + +static const USBD_ClassTypeDef usb_webusb_class = { + .Init = usb_webusb_class_init, + .DeInit = usb_webusb_class_deinit, + .Setup = usb_webusb_class_setup, + .EP0_TxSent = NULL, + .EP0_RxReady = NULL, + .DataIn = usb_webusb_class_data_in, + .DataOut = usb_webusb_class_data_out, + .SOF = NULL, + .IsoINIncomplete = NULL, + .IsoOUTIncomplete = NULL, + .GetHSConfigDescriptor = NULL, + .GetFSConfigDescriptor = NULL, + .GetOtherSpeedConfigDescriptor = NULL, + .GetDeviceQualifierDescriptor = NULL, + .GetUsrStrDescriptor = NULL, +}; diff --git a/core/embed/trezorhal/stm32f4/usb/usbd_def.h b/core/embed/trezorhal/stm32f4/usb/usbd_def.h index 6f20975a95..82e9f08720 100644 --- a/core/embed/trezorhal/stm32f4/usb/usbd_def.h +++ b/core/embed/trezorhal/stm32f4/usb/usbd_def.h @@ -272,6 +272,8 @@ typedef struct _USBD_HandleTypeDef #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif +#define UNCONST(X) ((uint8_t *)(X)) + #if defined ( __GNUC__ ) #ifndef __weak #define __weak __attribute__((weak)) diff --git a/core/embed/trezorhal/stm32f4/usb/usbd_internal.h b/core/embed/trezorhal/stm32f4/usb/usbd_internal.h new file mode 100644 index 0000000000..9becc8dcc5 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/usb/usbd_internal.h @@ -0,0 +1,131 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TREZORHAL_USBD_INTERNAL_H +#define TREZORHAL_USBD_INTERNAL_H + +#include + +#define USB_EP_DIR_MASK 0x80 +#define USB_EP_DIR_OUT 0x00 +#define USB_EP_DIR_IN 0x80 + +#define USB_WEBUSB_VENDOR_CODE 0x01 // arbitrary +#define USB_WEBUSB_LANDING_PAGE 0x01 // arbitrary + +typedef struct __attribute__((packed)) { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} usb_device_descriptor_t; + +typedef struct __attribute__((packed)) { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wData; +} usb_langid_descriptor_t; + +typedef enum { + USB_LANGID_ENGLISH_US = 0x409, +} usb_language_id_t; + +typedef struct __attribute__((packed)) { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +} usb_config_descriptor_t; + +typedef struct __attribute__((packed)) { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} usb_interface_descriptor_t; + +typedef struct __attribute__((packed)) { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bFirstInterface; + uint8_t bInterfaceCount; + uint8_t bFunctionClass; + uint8_t bFunctionSubClass; + uint8_t bFunctionProtocol; + uint8_t iFunction; +} usb_interface_assoc_descriptor_t; + +typedef struct __attribute__((packed)) { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} usb_endpoint_descriptor_t; + +// Number of reserved bytes for the state of each class. +#define USBD_CLASS_STATE_MAX_SIZE 128 + +// Returns the pointer to class state structure reserved for the +// specified interface number. +// +// The function checks if the interface number is valid and the type +// matches and returns NULL if not. If the `class` is NULL, the function +// returns the valid pointer only if the slot is empty. +// +// The returned array has `USBD_CLASS_STATE_MAX_SIZE` bytes +// and is aligned to 8-byte boundary. +void *usb_get_iface_state(uint8_t iface_num, const USBD_ClassTypeDef *class); + +// Assigns the concrete class to the slot `iface_num`. +void usb_set_iface_class(uint8_t iface_num, const USBD_ClassTypeDef *class); + +// Allocates the buffer for the class driver descriptors +// (interface, endpoint, ...) inside the USB device structure. +// +// The callee must fill the whole buffer with the descriptors. +// +// The function checks if the remaining space is enough and +// returns NULL if not. +void *usb_alloc_class_descriptors(size_t desc_len); + +// Returns the global handle to the USB device. +USBD_HandleTypeDef *usb_get_dev_handle(void); + +#endif // TREZORHAL_USBD_INTERNAL_H diff --git a/core/embed/trezorhal/unix/usb.c b/core/embed/trezorhal/unix/usb.c index 63fb1c6987..0f628e94f7 100644 --- a/core/embed/trezorhal/unix/usb.c +++ b/core/embed/trezorhal/unix/usb.c @@ -38,6 +38,13 @@ #define USBD_MAX_NUM_INTERFACES 8 +typedef enum { + USB_IFACE_TYPE_DISABLED = 0, + USB_IFACE_TYPE_VCP = 1, + USB_IFACE_TYPE_HID = 2, + USB_IFACE_TYPE_WEBUSB = 3, +} usb_iface_type_t; + static struct { usb_iface_type_t type; uint16_t port; diff --git a/core/embed/trezorhal/usb.h b/core/embed/trezorhal/usb.h index b9b27a4de8..0922340e2b 100644 --- a/core/embed/trezorhal/usb.h +++ b/core/embed/trezorhal/usb.h @@ -23,86 +23,9 @@ #include #include "secbool.h" -#define USB_EP_DIR_MASK 0x80 -#define USB_EP_DIR_OUT 0x00 -#define USB_EP_DIR_IN 0x80 - -typedef struct __attribute__((packed)) { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t bcdUSB; - uint8_t bDeviceClass; - uint8_t bDeviceSubClass; - uint8_t bDeviceProtocol; - uint8_t bMaxPacketSize0; - uint16_t idVendor; - uint16_t idProduct; - uint16_t bcdDevice; - uint8_t iManufacturer; - uint8_t iProduct; - uint8_t iSerialNumber; - uint8_t bNumConfigurations; -} usb_device_descriptor_t; - -typedef struct __attribute__((packed)) { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t wData; -} usb_langid_descriptor_t; - -typedef struct __attribute__((packed)) { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t wTotalLength; - uint8_t bNumInterfaces; - uint8_t bConfigurationValue; - uint8_t iConfiguration; - uint8_t bmAttributes; - uint8_t bMaxPower; -} usb_config_descriptor_t; - -typedef struct __attribute__((packed)) { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bInterfaceNumber; - uint8_t bAlternateSetting; - uint8_t bNumEndpoints; - uint8_t bInterfaceClass; - uint8_t bInterfaceSubClass; - uint8_t bInterfaceProtocol; - uint8_t iInterface; -} usb_interface_descriptor_t; - -typedef struct __attribute__((packed)) { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bFirstInterface; - uint8_t bInterfaceCount; - uint8_t bFunctionClass; - uint8_t bFunctionSubClass; - uint8_t bFunctionProtocol; - uint8_t iFunction; -} usb_interface_assoc_descriptor_t; - -typedef struct __attribute__((packed)) { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bEndpointAddress; - uint8_t bmAttributes; - uint16_t wMaxPacketSize; - uint8_t bInterval; -} usb_endpoint_descriptor_t; - -typedef enum { - USB_LANGID_ENGLISH_US = 0x409, -} usb_language_id_t; - -typedef struct { - const char *manufacturer; - const char *product; - const char *serial_number; - const char *interface; -} usb_dev_string_table_t; +#include "usb_hid.h" +#include "usb_vcp.h" +#include "usb_webusb.h" typedef struct { uint8_t device_class; @@ -119,26 +42,6 @@ typedef struct { secbool usb21_landing; } usb_dev_info_t; -typedef enum { - USB_IFACE_TYPE_DISABLED = 0, - USB_IFACE_TYPE_VCP = 1, - USB_IFACE_TYPE_HID = 2, - USB_IFACE_TYPE_WEBUSB = 3, -} usb_iface_type_t; - -#include "usb_hid-defs.h" -#include "usb_vcp-defs.h" -#include "usb_webusb-defs.h" - -typedef struct { - union { - usb_hid_state_t hid; - usb_vcp_state_t vcp; - usb_webusb_state_t webusb; - }; - usb_iface_type_t type; -} usb_iface_t; - void usb_init(const usb_dev_info_t *dev_info); void usb_deinit(void); void usb_start(void); diff --git a/core/embed/trezorhal/usb_hid-defs.h b/core/embed/trezorhal/usb_hid.h similarity index 64% rename from core/embed/trezorhal/usb_hid-defs.h rename to core/embed/trezorhal/usb_hid.h index 9062d71eb1..54b99b05d8 100644 --- a/core/embed/trezorhal/usb_hid-defs.h +++ b/core/embed/trezorhal/usb_hid.h @@ -17,22 +17,11 @@ * along with this program. If not, see . */ -typedef struct __attribute__((packed)) { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t bcdHID; - uint8_t bCountryCode; - uint8_t bNumDescriptors; - uint8_t bReportDescriptorType; - uint16_t wReportDescriptorLength; -} usb_hid_descriptor_t; +#ifndef TREZORHAL_USB_CLASS_HID_H +#define TREZORHAL_USB_CLASS_HID_H -typedef struct __attribute__((packed)) { - usb_interface_descriptor_t iface; - usb_hid_descriptor_t hid; - usb_endpoint_descriptor_t ep_in; - usb_endpoint_descriptor_t ep_out; -} usb_hid_descriptor_block_t; +#include +#include "secbool.h" /* usb_hid_info_t contains all information for setting up a HID interface. All * passed pointers need to live at least until the interface is disabled @@ -54,26 +43,6 @@ typedef struct { uint8_t report_desc_len; // Length of report_desc } usb_hid_info_t; -/* usb_hid_state_t encapsulates all state used by enabled HID interface. It - * needs to be completely initialized in usb_hid_add and reset in - * usb_hid_class_init. See usb_hid_info_t for details of the configuration - * fields. */ -typedef struct { - const usb_hid_descriptor_block_t *desc_block; - const uint8_t *report_desc; - uint8_t *rx_buffer; - uint8_t ep_in; - uint8_t ep_out; - uint8_t max_packet_len; - uint8_t report_desc_len; - - uint8_t protocol; // For SET_PROTOCOL/GET_PROTOCOL setup reqs - uint8_t idle_rate; // For SET_IDLE/GET_IDLE setup reqs - uint8_t alt_setting; // For SET_INTERFACE/GET_INTERFACE setup reqs - uint8_t last_read_len; // Length of data read into rx_buffer - uint8_t ep_in_is_idle; // Set to 1 after IN endpoint gets idle -} usb_hid_state_t; - secbool __wur usb_hid_add(const usb_hid_info_t *hid_info); secbool __wur usb_hid_can_read(uint8_t iface_num); secbool __wur usb_hid_can_write(uint8_t iface_num); @@ -85,3 +54,5 @@ int __wur usb_hid_read_blocking(uint8_t iface_num, uint8_t *buf, uint32_t len, int timeout); int __wur usb_hid_write_blocking(uint8_t iface_num, const uint8_t *buf, uint32_t len, int timeout); + +#endif // TREZORHAL_USB_CLASS_HID_H diff --git a/core/embed/trezorhal/usb_vcp-defs.h b/core/embed/trezorhal/usb_vcp.h similarity index 51% rename from core/embed/trezorhal/usb_vcp-defs.h rename to core/embed/trezorhal/usb_vcp.h index 849aed06f7..8759a11a5c 100644 --- a/core/embed/trezorhal/usb_vcp-defs.h +++ b/core/embed/trezorhal/usb_vcp.h @@ -17,73 +17,11 @@ * along with this program. If not, see . */ +#ifndef TREZORHAL_USB_CLASS_VCP_H +#define TREZORHAL_USB_CLASS_VCP_H + #include - -typedef struct __attribute__((packed)) { - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint16_t bcdCDC; -} usb_vcp_header_descriptor_t; - -typedef struct __attribute__((packed)) { - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bmCapabilities; - uint8_t bDataInterface; -} usb_vcp_cm_descriptor_t; - -typedef struct __attribute__((packed)) { - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bmCapabilities; -} usb_vcp_acm_descriptor_t; - -typedef struct __attribute__((packed)) { - uint8_t bFunctionLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubtype; - uint8_t bControlInterface; - uint8_t bSubordinateInterface0; -} usb_vcp_union_descriptor_t; - -typedef struct __attribute__((packed)) { - usb_interface_assoc_descriptor_t assoc; - usb_interface_descriptor_t iface_cdc; - usb_vcp_header_descriptor_t - fheader; // Class-Specific Descriptor Header Format - usb_vcp_cm_descriptor_t fcm; // Call Management Functional Descriptor - usb_vcp_acm_descriptor_t - facm; // Abstract Control Management Functional Descriptor - usb_vcp_union_descriptor_t funion; // Union Interface Functional Descriptor - usb_endpoint_descriptor_t ep_cmd; - usb_interface_descriptor_t iface_data; - usb_endpoint_descriptor_t ep_in; - usb_endpoint_descriptor_t ep_out; -} usb_vcp_descriptor_block_t; - -typedef struct __attribute__((packed)) { - uint32_t dwDTERate; - uint8_t bCharFormat; // usb_cdc_line_coding_bCharFormat_t - uint8_t bParityType; // usb_cdc_line_coding_bParityType_t - uint8_t bDataBits; -} usb_cdc_line_coding_t; - -typedef enum { - USB_CDC_1_STOP_BITS = 0, - USB_CDC_1_5_STOP_BITS = 1, - USB_CDC_2_STOP_BITS = 2, -} usb_cdc_line_coding_bCharFormat_t; - -typedef enum { - USB_CDC_NO_PARITY = 0, - USB_CDC_ODD_PARITY = 1, - USB_CDC_EVEN_PARITY = 2, - USB_CDC_MARK_PARITY = 3, - USB_CDC_SPACE_PARITY = 4, -} usb_cdc_line_coding_bParityType_t; +#include "secbool.h" /* usb_vcp_info_t contains all information for setting up a VCP interface. All * passed pointers need to live at least until the interface is disabled @@ -117,37 +55,6 @@ typedef struct { // rx_packet } usb_vcp_info_t; -/* usb_rbuf_t is used internally for the RX/TX buffering. */ -typedef struct { - size_t cap; - volatile size_t read; - volatile size_t write; - uint8_t *buf; -} usb_rbuf_t; - -// Maximal length of packets on IN CMD EP -#define USB_CDC_MAX_CMD_PACKET_LEN 0x08 - -/* usb_vcp_state_t encapsulates all state used by enabled VCP interface. It - * needs to be completely initialized in usb_vcp_add and reset in - * usb_vcp_class_init. See usb_vcp_info_t for details of the configuration - * fields. */ -typedef struct { - const usb_vcp_descriptor_block_t *desc_block; - usb_rbuf_t rx_ring; - usb_rbuf_t tx_ring; - uint8_t *rx_packet; - uint8_t *tx_packet; - void (*rx_intr_fn)(void); - uint8_t rx_intr_byte; - uint8_t ep_cmd; - uint8_t ep_in; - uint8_t ep_out; - uint8_t max_packet_len; - uint8_t ep_in_is_idle; // Set to 1 after IN endpoint gets idle - uint8_t cmd_buffer[USB_CDC_MAX_CMD_PACKET_LEN]; -} usb_vcp_state_t; - secbool __wur usb_vcp_add(const usb_vcp_info_t *vcp_info); secbool __wur usb_vcp_can_read(uint8_t iface_num); secbool __wur usb_vcp_can_write(uint8_t iface_num); @@ -158,3 +65,5 @@ int __wur usb_vcp_read_blocking(uint8_t iface_num, uint8_t *buf, uint32_t len, int timeout); int __wur usb_vcp_write_blocking(uint8_t iface_num, const uint8_t *buf, uint32_t len, int timeout); + +#endif // TREZORHAL_USB_CLASS_VCP_H diff --git a/core/embed/trezorhal/usb_webusb-defs.h b/core/embed/trezorhal/usb_webusb.h similarity index 70% rename from core/embed/trezorhal/usb_webusb-defs.h rename to core/embed/trezorhal/usb_webusb.h index aa475bf365..216c3d6b57 100644 --- a/core/embed/trezorhal/usb_webusb-defs.h +++ b/core/embed/trezorhal/usb_webusb.h @@ -17,14 +17,10 @@ * along with this program. If not, see . */ -#define USB_WEBUSB_VENDOR_CODE 0x01 // arbitrary -#define USB_WEBUSB_LANDING_PAGE 0x01 // arbitrary +#ifndef TREZORHAL_USB_CLASS_WEBUSB_H +#define TREZORHAL_USB_CLASS_WEBUSB_H -typedef struct __attribute__((packed)) { - usb_interface_descriptor_t iface; - usb_endpoint_descriptor_t ep_in; - usb_endpoint_descriptor_t ep_out; -} usb_webusb_descriptor_block_t; +#include "secbool.h" /* usb_webusb_info_t contains all information for setting up a WebUSB interface. * All passed pointers need to live at least until the interface is disabled @@ -44,22 +40,6 @@ typedef struct { uint8_t max_packet_len; // Length of the biggest report and of rx_buffer } usb_webusb_info_t; -/* usb_webusb_state_t encapsulates all state used by enabled WebUSB interface. - * It needs to be completely initialized in usb_webusb_add and reset in - * usb_webusb_class_init. See usb_webusb_info_t for details of the - * configuration fields. */ -typedef struct { - const usb_webusb_descriptor_block_t *desc_block; - uint8_t *rx_buffer; - uint8_t ep_in; - uint8_t ep_out; - uint8_t max_packet_len; - - uint8_t alt_setting; // For SET_INTERFACE/GET_INTERFACE setup reqs - uint8_t last_read_len; // Length of data read into rx_buffer - uint8_t ep_in_is_idle; // Set to 1 after IN endpoint gets idle -} usb_webusb_state_t; - secbool __wur usb_webusb_add(const usb_webusb_info_t *webusb_info); secbool __wur usb_webusb_can_read(uint8_t iface_num); secbool __wur usb_webusb_can_write(uint8_t iface_num); @@ -71,3 +51,5 @@ int __wur usb_webusb_read_blocking(uint8_t iface_num, uint8_t *buf, uint32_t len, int timeout); int __wur usb_webusb_write_blocking(uint8_t iface_num, const uint8_t *buf, uint32_t len, int timeout); + +#endif // TREZORHAL_USB_CLASS_WEBUSB_H diff --git a/core/site_scons/models/D001/discovery.py b/core/site_scons/models/D001/discovery.py index 3dd0d2babb..c8e18fbe3a 100644 --- a/core/site_scons/models/D001/discovery.py +++ b/core/site_scons/models/D001/discovery.py @@ -76,11 +76,14 @@ def configure( if "usb" in features_wanted: sources += [ - "embed/trezorhal/stm32f4/usb/usb.c", + "embed/trezorhal/stm32f4/usb/usbd_class_hid.c", + "embed/trezorhal/stm32f4/usb/usbd_class_vcp.c", + "embed/trezorhal/stm32f4/usb/usbd_class_webusb.c", "embed/trezorhal/stm32f4/usb/usbd_conf.c", "embed/trezorhal/stm32f4/usb/usbd_core.c", "embed/trezorhal/stm32f4/usb/usbd_ctlreq.c", "embed/trezorhal/stm32f4/usb/usbd_ioreq.c", + "embed/trezorhal/stm32f4/usb/usbd.c", "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c", ] features_available.append("usb") diff --git a/core/site_scons/models/D002/discovery2.py b/core/site_scons/models/D002/discovery2.py index 42cd6d4e12..94e6fc7598 100644 --- a/core/site_scons/models/D002/discovery2.py +++ b/core/site_scons/models/D002/discovery2.py @@ -82,11 +82,14 @@ def configure( if "usb" in features_wanted: sources += [ - "embed/trezorhal/stm32u5/usb/usb.c", + "embed/trezorhal/stm32u5/usb/usbd_class_hid.c", + "embed/trezorhal/stm32u5/usb/usbd_class_vcp.c", + "embed/trezorhal/stm32u5/usb/usbd_class_webusb.c", "embed/trezorhal/stm32u5/usb/usbd_conf.c", "embed/trezorhal/stm32u5/usb/usbd_core.c", "embed/trezorhal/stm32u5/usb/usbd_ctlreq.c", "embed/trezorhal/stm32u5/usb/usbd_ioreq.c", + "embed/trezorhal/stm32u5/usb/usbd.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_ll_usb.c", ] features_available.append("usb") diff --git a/core/site_scons/models/T1B1/trezor_1.py b/core/site_scons/models/T1B1/trezor_1.py index a1a4da0a1d..df938dfd9d 100644 --- a/core/site_scons/models/T1B1/trezor_1.py +++ b/core/site_scons/models/T1B1/trezor_1.py @@ -42,11 +42,14 @@ def configure( if "usb" in features_wanted: sources += [ - "embed/trezorhal/stm32f4/usb/usb.c", + "embed/trezorhal/stm32f4/usb/usbd_class_hid.c", + "embed/trezorhal/stm32f4/usb/usbd_class_vcp.c", + "embed/trezorhal/stm32f4/usb/usbd_class_webusb.c", "embed/trezorhal/stm32f4/usb/usbd_conf.c", "embed/trezorhal/stm32f4/usb/usbd_core.c", "embed/trezorhal/stm32f4/usb/usbd_ctlreq.c", "embed/trezorhal/stm32f4/usb/usbd_ioreq.c", + "embed/trezorhal/stm32f4/usb/usbd.c", "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c", ] features_available.append("usb") diff --git a/core/site_scons/models/T2B1/trezor_r_v10.py b/core/site_scons/models/T2B1/trezor_r_v10.py index db7e2365c3..7eb33ef442 100644 --- a/core/site_scons/models/T2B1/trezor_r_v10.py +++ b/core/site_scons/models/T2B1/trezor_r_v10.py @@ -65,11 +65,14 @@ def configure( ] if "usb" in features_wanted: sources += [ - "embed/trezorhal/stm32f4/usb/usb.c", + "embed/trezorhal/stm32f4/usb/usbd_class_hid.c", + "embed/trezorhal/stm32f4/usb/usbd_class_vcp.c", + "embed/trezorhal/stm32f4/usb/usbd_class_webusb.c", "embed/trezorhal/stm32f4/usb/usbd_conf.c", "embed/trezorhal/stm32f4/usb/usbd_core.c", "embed/trezorhal/stm32f4/usb/usbd_ctlreq.c", "embed/trezorhal/stm32f4/usb/usbd_ioreq.c", + "embed/trezorhal/stm32f4/usb/usbd.c", "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c", ] features_available.append("usb") diff --git a/core/site_scons/models/T2B1/trezor_r_v3.py b/core/site_scons/models/T2B1/trezor_r_v3.py index 9a29a06176..c7889b8f8e 100644 --- a/core/site_scons/models/T2B1/trezor_r_v3.py +++ b/core/site_scons/models/T2B1/trezor_r_v3.py @@ -62,11 +62,14 @@ def configure( if "usb" in features_wanted: sources += [ - "embed/trezorhal/stm32f4/usb/usb.c", + "embed/trezorhal/stm32f4/usb/usbd_class_hid.c", + "embed/trezorhal/stm32f4/usb/usbd_class_vcp.c", + "embed/trezorhal/stm32f4/usb/usbd_class_webusb.c", "embed/trezorhal/stm32f4/usb/usbd_conf.c", "embed/trezorhal/stm32f4/usb/usbd_core.c", "embed/trezorhal/stm32f4/usb/usbd_ctlreq.c", "embed/trezorhal/stm32f4/usb/usbd_ioreq.c", + "embed/trezorhal/stm32f4/usb/usbd.c", "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c", ] features_available.append("usb") diff --git a/core/site_scons/models/T2B1/trezor_r_v4.py b/core/site_scons/models/T2B1/trezor_r_v4.py index c11de45252..1d55473c35 100644 --- a/core/site_scons/models/T2B1/trezor_r_v4.py +++ b/core/site_scons/models/T2B1/trezor_r_v4.py @@ -58,11 +58,14 @@ def configure( if "usb" in features_wanted: sources += [ - "embed/trezorhal/stm32f4/usb/usb.c", + "embed/trezorhal/stm32f4/usb/usbd_class_hid.c", + "embed/trezorhal/stm32f4/usb/usbd_class_vcp.c", + "embed/trezorhal/stm32f4/usb/usbd_class_webusb.c", "embed/trezorhal/stm32f4/usb/usbd_conf.c", "embed/trezorhal/stm32f4/usb/usbd_core.c", "embed/trezorhal/stm32f4/usb/usbd_ctlreq.c", "embed/trezorhal/stm32f4/usb/usbd_ioreq.c", + "embed/trezorhal/stm32f4/usb/usbd.c", "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c", ] features_available.append("usb") diff --git a/core/site_scons/models/T2B1/trezor_r_v6.py b/core/site_scons/models/T2B1/trezor_r_v6.py index 790927fb41..ecac28d081 100644 --- a/core/site_scons/models/T2B1/trezor_r_v6.py +++ b/core/site_scons/models/T2B1/trezor_r_v6.py @@ -58,11 +58,14 @@ def configure( if "usb" in features_wanted: sources += [ - "embed/trezorhal/stm32f4/usb/usb.c", + "embed/trezorhal/stm32f4/usb/usbd_class_hid.c", + "embed/trezorhal/stm32f4/usb/usbd_class_vcp.c", + "embed/trezorhal/stm32f4/usb/usbd_class_webusb.c", "embed/trezorhal/stm32f4/usb/usbd_conf.c", "embed/trezorhal/stm32f4/usb/usbd_core.c", "embed/trezorhal/stm32f4/usb/usbd_ctlreq.c", "embed/trezorhal/stm32f4/usb/usbd_ioreq.c", + "embed/trezorhal/stm32f4/usb/usbd.c", "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c", ] features_available.append("usb") diff --git a/core/site_scons/models/T2T1/trezor_t.py b/core/site_scons/models/T2T1/trezor_t.py index 78b9a7a32e..6ad7905850 100644 --- a/core/site_scons/models/T2T1/trezor_t.py +++ b/core/site_scons/models/T2T1/trezor_t.py @@ -100,11 +100,14 @@ def configure( if "usb" in features_wanted: sources += [ - "embed/trezorhal/stm32f4/usb/usb.c", + "embed/trezorhal/stm32f4/usb/usbd_class_hid.c", + "embed/trezorhal/stm32f4/usb/usbd_class_vcp.c", + "embed/trezorhal/stm32f4/usb/usbd_class_webusb.c", "embed/trezorhal/stm32f4/usb/usbd_conf.c", "embed/trezorhal/stm32f4/usb/usbd_core.c", "embed/trezorhal/stm32f4/usb/usbd_ctlreq.c", "embed/trezorhal/stm32f4/usb/usbd_ioreq.c", + "embed/trezorhal/stm32f4/usb/usbd.c", "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_ll_usb.c", ] features_available.append("usb") diff --git a/core/site_scons/models/T3T1/trezor_t3t1_revE.py b/core/site_scons/models/T3T1/trezor_t3t1_revE.py index 7e43b8171a..61d13baebc 100644 --- a/core/site_scons/models/T3T1/trezor_t3t1_revE.py +++ b/core/site_scons/models/T3T1/trezor_t3t1_revE.py @@ -100,11 +100,14 @@ def configure( if "usb" in features_wanted: sources += [ - "embed/trezorhal/stm32u5/usb/usb.c", + "embed/trezorhal/stm32u5/usb/usbd_class_hid.c", + "embed/trezorhal/stm32u5/usb/usbd_class_vcp.c", + "embed/trezorhal/stm32u5/usb/usbd_class_webusb.c", "embed/trezorhal/stm32u5/usb/usbd_conf.c", "embed/trezorhal/stm32u5/usb/usbd_core.c", "embed/trezorhal/stm32u5/usb/usbd_ctlreq.c", "embed/trezorhal/stm32u5/usb/usbd_ioreq.c", + "embed/trezorhal/stm32u5/usb/usbd.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_ll_usb.c", ] features_available.append("usb") diff --git a/core/site_scons/models/T3T1/trezor_t3t1_v4.py b/core/site_scons/models/T3T1/trezor_t3t1_v4.py index 8cb8dccbe2..a9951b895e 100644 --- a/core/site_scons/models/T3T1/trezor_t3t1_v4.py +++ b/core/site_scons/models/T3T1/trezor_t3t1_v4.py @@ -102,11 +102,14 @@ def configure( if "usb" in features_wanted: sources += [ - "embed/trezorhal/stm32u5/usb/usb.c", + "embed/trezorhal/stm32u5/usb/usbd_class_hid.c", + "embed/trezorhal/stm32u5/usb/usbd_class_vcp.c", + "embed/trezorhal/stm32u5/usb/usbd_class_webusb.c", "embed/trezorhal/stm32u5/usb/usbd_conf.c", "embed/trezorhal/stm32u5/usb/usbd_core.c", "embed/trezorhal/stm32u5/usb/usbd_ctlreq.c", "embed/trezorhal/stm32u5/usb/usbd_ioreq.c", + "embed/trezorhal/stm32u5/usb/usbd.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_ll_usb.c", ] features_available.append("usb") diff --git a/core/src/usb.py b/core/src/usb.py index 5dde66a1e2..33d43f25ea 100644 --- a/core/src/usb.py +++ b/core/src/usb.py @@ -33,7 +33,7 @@ ENABLE_IFACE_VCP = __debug__ id_wire = next(_iface_iter) iface_wire = io.WebUSB( iface_num=id_wire, - ep_in=0x81 + id_wire, + ep_in=0x01 + id_wire, ep_out=0x01 + id_wire, emu_port=UDP_PORT + _WIRE_PORT_OFFSET, ) @@ -55,7 +55,7 @@ if __debug__ and ENABLE_IFACE_DEBUG: id_debug = next(_iface_iter) iface_debug = io.WebUSB( iface_num=id_debug, - ep_in=0x81 + id_debug, + ep_in=0x01 + id_debug, ep_out=0x01 + id_debug, emu_port=UDP_PORT + _DEBUGLINK_PORT_OFFSET, ) @@ -66,7 +66,7 @@ if not utils.BITCOIN_ONLY and ENABLE_IFACE_WEBAUTHN: id_webauthn = next(_iface_iter) iface_webauthn = io.HID( iface_num=id_webauthn, - ep_in=0x81 + id_webauthn, + ep_in=0x01 + id_webauthn, ep_out=0x01 + id_webauthn, emu_port=UDP_PORT + _WEBAUTHN_PORT_OFFSET, # fmt: off @@ -99,9 +99,9 @@ if __debug__ and ENABLE_IFACE_VCP: iface_vcp = io.VCP( iface_num=id_vcp, data_iface_num=id_vcp_data, - ep_in=0x81 + id_vcp, + ep_in=0x01 + id_vcp, ep_out=0x01 + id_vcp, - ep_cmd=0x81 + id_vcp_data, + ep_cmd=0x01 + id_vcp_data, emu_port=UDP_PORT + _VCP_PORT_OFFSET, ) bus.add(iface_vcp) diff --git a/core/tests/production_tests/main.py b/core/tests/production_tests/main.py index f783c6526d..5a806f0ebd 100644 --- a/core/tests/production_tests/main.py +++ b/core/tests/production_tests/main.py @@ -5,9 +5,9 @@ import utime usb_vcp = io.VCP( iface_num=0x00, data_iface_num=0x01, - ep_in=0x81, + ep_in=0x01, ep_out=0x01, - ep_cmd=0x82, + ep_cmd=0x02, ) usb = io.USB(