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(