mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-03-03 00:36:06 +00:00
refactor(core/embed): refactor usb driver
[no changelog]
This commit is contained in:
parent
8e429b0352
commit
0bc1d1f706
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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
|
@ -17,6 +17,14 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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,
|
||||
};
|
@ -17,6 +17,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 = {};
|
@ -17,36 +17,73 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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,
|
||||
};
|
@ -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))
|
||||
|
131
core/embed/trezorhal/stm32f4/usb/usbd_internal.h
Normal file
131
core/embed/trezorhal/stm32f4/usb/usbd_internal.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_USBD_INTERNAL_H
|
||||
#define TREZORHAL_USBD_INTERNAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
@ -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;
|
||||
|
@ -23,86 +23,9 @@
|
||||
#include <stdint.h>
|
||||
#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);
|
||||
|
@ -17,22 +17,11 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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 <stdint.h>
|
||||
#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
|
@ -17,73 +17,11 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_USB_CLASS_VCP_H
|
||||
#define TREZORHAL_USB_CLASS_VCP_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
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
|
@ -17,14 +17,10 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user