Skip to content

Commit

Permalink
refactor(core): improve USB events handling, more extensible implemen…
Browse files Browse the repository at this point in the history
…tation

[no changelog]
  • Loading branch information
TychoVrahe committed Dec 12, 2024
1 parent 7d9a53c commit f5a0f84
Show file tree
Hide file tree
Showing 20 changed files with 159 additions and 60 deletions.
27 changes: 19 additions & 8 deletions core/embed/io/usb/inc/io/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@

#define USB_PACKET_LEN 64

typedef enum {
USB_EVENT_NONE = 0,
USB_EVENT_CONFIGURED = 1,
USB_EVENT_DECONFIGURED = 2,
} usb_event_t;

typedef union {
bool configured;
} usb_state_t;

// clang-format off
//
// USB stack high-level state machine
Expand Down Expand Up @@ -94,25 +104,26 @@ void usb_deinit(void);
// Initializes the USB stack (and hardware) and starts all registered class
// drivers.
//
// This function can called after all class drivers are registered or after
// This function can be called after all class drivers are registered or after
// `usb_stop()` is called.
//
// Returns `sectrue` if the USB stack is started successfully.
secbool usb_start(void);

// Stops USB driver and its class drivers
//
// Unitializes the USB stack (and hardware) but leaves all configuration intact,
// so it can be started again with `usb_start()`.
// Uninitializes the USB stack (and hardware) but leaves all configuration
// intact, so it can be started again with `usb_start()`.
//
// When the USB stack is stopped, it does not respond to any USB events and
// the CPU can go to stop/standby mode.
void usb_stop(void);

// Returns `sectrue` if the device is connected to the host (or is expected to
// be)
//
// TODO: Review and clarify the logic of this function in the future
secbool usb_configured(void);
// Reads USB event
// Return USB_EVENT_NONE if no event is available
usb_event_t usb_get_event(void);

// Reads USB state into `state`
void usb_get_state(usb_state_t *state);

#endif
71 changes: 55 additions & 16 deletions core/embed/io/usb/stm32/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ typedef struct {
// Set to `sectrue` if the USB stack was ready sinced the last start
secbool was_ready;

// Current state of USB configuration
secbool configured;

} usb_driver_t;

// USB driver instance
Expand Down Expand Up @@ -118,20 +121,21 @@ secbool usb_init(const usb_dev_info_t *dev_info) {
// Device descriptor
drv->dev_desc.bLength = sizeof(usb_device_descriptor_t);
drv->dev_desc.bDescriptorType = USB_DESC_TYPE_DEVICE;
drv->dev_desc.bcdUSB =
(sectrue == drv->usb21_enabled) ? 0x0210 : 0x0200; // USB 2.1 or USB 2.0
// USB 2.1 or USB 2.0
drv->dev_desc.bcdUSB = (sectrue == drv->usb21_enabled) ? 0x0210 : 0x0200;
drv->dev_desc.bDeviceClass = dev_info->device_class;
drv->dev_desc.bDeviceSubClass = dev_info->device_subclass;
drv->dev_desc.bDeviceProtocol = dev_info->device_protocol;
drv->dev_desc.bMaxPacketSize0 = USB_MAX_EP0_SIZE;
drv->dev_desc.idVendor = dev_info->vendor_id;
drv->dev_desc.idProduct = dev_info->product_id;
drv->dev_desc.bcdDevice = dev_info->release_num;
drv->dev_desc.iManufacturer =
USBD_IDX_MFC_STR; // Index of manufacturer string
drv->dev_desc.iProduct = USBD_IDX_PRODUCT_STR; // Index of product string
drv->dev_desc.iSerialNumber =
USBD_IDX_SERIAL_STR; // Index of serial number string
// Index of manufacturer string
drv->dev_desc.iManufacturer = USBD_IDX_MFC_STR;
// Index of product string
drv->dev_desc.iProduct = USBD_IDX_PRODUCT_STR;
// Index of serial number string
drv->dev_desc.iSerialNumber = USBD_IDX_SERIAL_STR;
drv->dev_desc.bNumConfigurations = 1;

// String table
Expand All @@ -158,17 +162,19 @@ secbool usb_init(const usb_dev_info_t *dev_info) {
// Configuration descriptor
drv->config_desc->bLength = sizeof(usb_config_descriptor_t);
drv->config_desc->bDescriptorType = USB_DESC_TYPE_CONFIGURATION;
drv->config_desc->wTotalLength =
sizeof(usb_config_descriptor_t); // will be updated later via
// usb_alloc_class_descriptors()
drv->config_desc->bNumInterfaces =
0; // will be updated later via usb_set_iface_class()
// will be updated later via usb_alloc_class_descriptors()
drv->config_desc->wTotalLength = sizeof(usb_config_descriptor_t);
// will be updated later via usb_set_iface_class()
drv->config_desc->bNumInterfaces = 0;
drv->config_desc->bConfigurationValue = 0x01;
drv->config_desc->iConfiguration = 0;
drv->config_desc->bmAttributes =
0x80; // 0x80 = bus powered; 0xC0 = self powered
drv->config_desc->bMaxPower = 0x32; // Maximum Power Consumption in 2mA units
// 0x80 = bus powered; 0xC0 = self powered
drv->config_desc->bmAttributes = 0x80;
// Maximum Power Consumption in 2mA units
drv->config_desc->bMaxPower = 0x32;

// starting with this flag set, to avoid false warnings
drv->configured = sectrue;
drv->initialized = sectrue;

return sectrue;
Expand Down Expand Up @@ -241,7 +247,7 @@ void usb_stop(void) {
memset(&drv->dev_handle, 0, sizeof(drv->dev_handle));
}

secbool usb_configured(void) {
static secbool usb_configured(void) {
usb_driver_t *drv = &g_usb_driver;

if (drv->initialized != sectrue) {
Expand Down Expand Up @@ -295,6 +301,39 @@ secbool usb_configured(void) {
return ready;
}

usb_event_t usb_get_event(void) {
usb_driver_t *drv = &g_usb_driver;

if (drv->initialized != sectrue) {
// The driver is not initialized
return false;
}

secbool configured = usb_configured();
if (configured != drv->configured) {
drv->configured = configured;
if (configured == sectrue) {
return USB_EVENT_CONFIGURED;
} else {
return USB_EVENT_DECONFIGURED;
}
}

return USB_EVENT_NONE;
}

void usb_get_state(usb_state_t *state) {
usb_driver_t *drv = &g_usb_driver;

usb_state_t s = {0};

if (drv->initialized == sectrue) {
s.configured = drv->configured == sectrue;
}

*state = s;
}

// ==========================================================================
// Utility functions for USB class drivers
// ==========================================================================
Expand Down
6 changes: 6 additions & 0 deletions core/embed/io/usb/unix/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,3 +322,9 @@ secbool usb_configured(void) {

return sectrue;
}

usb_event_t usb_get_event(void) { return USB_EVENT_NONE; }

void usb_get_state(usb_state_t *state) {
state->configured = usb_configured() == sectrue;
}
3 changes: 2 additions & 1 deletion core/embed/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,8 @@ fn generate_trezorhal_bindings() {
// toif
.allowlist_type("toif_format_t")
//usb
.allowlist_function("usb_configured")
.allowlist_type("usb_event_t")
.allowlist_function("usb_get_state")
// touch
.allowlist_function("touch_get_event")
// button
Expand Down
6 changes: 5 additions & 1 deletion core/embed/rust/src/trezorhal/usb.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use super::ffi;

pub fn usb_configured() -> bool {
unsafe { ffi::usb_configured() == ffi::sectrue }
unsafe {
let mut state: ffi::usb_state_t = core::mem::zeroed();
ffi::usb_get_state(&mut state as *mut ffi::usb_state_t);
state.configured
}
}
9 changes: 3 additions & 6 deletions core/embed/rust/src/ui/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@ pub mod button;
#[cfg(feature = "touch")]
pub mod touch;

pub mod usb;

#[cfg(feature = "button")]
pub use button::{ButtonEvent, PhysicalButton};
#[cfg(feature = "touch")]
pub use touch::{SwipeEvent, TouchEvent};

#[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))]
pub enum USBEvent {
/// USB host has connected/disconnected.
Connected(bool),
}
pub use usb::USBEvent;
20 changes: 20 additions & 0 deletions core/embed/rust/src/ui/event/usb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::error::Error;

#[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))]
pub enum USBEvent {
/// USB host has connected/disconnected.
Configured,
Deconfigured,
}

impl USBEvent {
pub fn new(event: u32) -> Result<Self, Error> {
let result = match event {
1 => Self::Configured,
2 => Self::Deconfigured,
_ => return Err(Error::OutOfRange),
};
Ok(result)
}
}
2 changes: 1 addition & 1 deletion core/embed/rust/src/ui/layout/obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ extern "C" fn ui_layout_usb_event(n_args: usize, args: *const Obj) -> Obj {
return Err(Error::TypeError);
}
let this: Gc<LayoutObj> = args[0].try_into()?;
let event = USBEvent::Connected(args[1].try_into()?);
let event = USBEvent::new(args[1].try_into()?)?;
let msg = this.inner_mut().obj_event(Event::USB(event))?;
Ok(msg)
};
Expand Down
4 changes: 2 additions & 2 deletions core/embed/rust/src/ui/model_mercury/component/homescreen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
ui::{
component::{Component, Event, EventCtx, Timer},
display::{image::ImageInfo, Color, Font},
event::{TouchEvent, USBEvent},
event::TouchEvent,
geometry::{Alignment, Alignment2D, Offset, Point, Rect},
layout::util::get_user_custom_image,
model_mercury::constant,
Expand Down Expand Up @@ -500,7 +500,7 @@ impl Homescreen {
}

fn event_usb(&mut self, ctx: &mut EventCtx, event: Event) {
if let Event::USB(USBEvent::Connected(_)) = event {
if let Event::USB(_) = event {
ctx.request_paint();
}
}
Expand Down
3 changes: 1 addition & 2 deletions core/embed/rust/src/ui/model_tr/component/homescreen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use crate::{
image::{ImageInfo, ToifFormat},
Font, Icon,
},
event::USBEvent,
geometry::{Alignment, Alignment2D, Insets, Offset, Point, Rect},
layout::util::get_user_custom_image,
shape,
Expand Down Expand Up @@ -164,7 +163,7 @@ impl Homescreen {
}

fn event_usb(&mut self, ctx: &mut EventCtx, event: Event) {
if let Event::USB(USBEvent::Connected(_)) = event {
if let Event::USB(_) = event {
ctx.request_paint();
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/embed/rust/src/ui/model_tt/component/homescreen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
toif::Icon,
Color, Font,
},
event::{TouchEvent, USBEvent},
event::TouchEvent,
geometry::{Alignment, Alignment2D, Insets, Offset, Point, Rect},
layout::util::get_user_custom_image,
model_tt::{constant, theme::IMAGE_HOMESCREEN},
Expand Down Expand Up @@ -130,7 +130,7 @@ impl Homescreen {
}

fn event_usb(&mut self, ctx: &mut EventCtx, event: Event) {
if let Event::USB(USBEvent::Connected(_)) = event {
if let Event::USB(_) = event {
self.paint_notification_only = true;
ctx.request_paint();
}
Expand Down
9 changes: 7 additions & 2 deletions core/embed/sys/syscall/stm32/syscall_dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,13 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
usb_stop();
} break;

case SYSCALL_USB_CONFIGURED: {
args[0] = usb_configured();
case SYSCALL_USB_GET_EVENT: {
args[0] = usb_get_event();
} break;

case SYSCALL_USB_GET_STATE: {
usb_state_t *state = (usb_state_t *)args[0];
usb_get_state__verified(state);
} break;

case SYSCALL_USB_HID_ADD: {
Expand Down
3 changes: 2 additions & 1 deletion core/embed/sys/syscall/stm32/syscall_numbers.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ typedef enum {
SYSCALL_USB_DEINIT,
SYSCALL_USB_START,
SYSCALL_USB_STOP,
SYSCALL_USB_CONFIGURED,
SYSCALL_USB_GET_EVENT,
SYSCALL_USB_GET_STATE,

SYSCALL_USB_HID_ADD,
SYSCALL_USB_HID_CAN_READ,
Expand Down
8 changes: 6 additions & 2 deletions core/embed/sys/syscall/stm32/syscall_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,12 @@ secbool usb_start(void) { return (secbool)syscall_invoke0(SYSCALL_USB_START); }

void usb_stop(void) { syscall_invoke0(SYSCALL_USB_STOP); }

secbool usb_configured(void) {
return (secbool)syscall_invoke0(SYSCALL_USB_CONFIGURED);
usb_event_t usb_get_event(void) {
return (usb_event_t)syscall_invoke0(SYSCALL_USB_GET_EVENT);
}

void usb_get_state(usb_state_t *state) {
syscall_invoke1((uint32_t)state, SYSCALL_USB_GET_STATE);
}

// =============================================================================
Expand Down
12 changes: 12 additions & 0 deletions core/embed/sys/syscall/stm32/syscall_verifiers.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,18 @@ void display_copy_rgb565__verified(const gfx_bitblt_t *bb) {

// ---------------------------------------------------------------------

void usb_get_state__verified(usb_state_t *state) {
if (!probe_write_access(state, sizeof(*state))) {
goto access_violation;
}

usb_get_state(state);
return;

access_violation:
apptask_access_violation();
}

int usb_hid_read__verified(uint8_t iface_num, uint8_t *buf, uint32_t len) {
if (!probe_write_access(buf, len)) {
goto access_violation;
Expand Down
4 changes: 4 additions & 0 deletions core/embed/sys/syscall/stm32/syscall_verifiers.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ void display_fill__verified(const gfx_bitblt_t *bb);

void display_copy_rgb565__verified(const gfx_bitblt_t *bb);

// ---------------------------------------------------------------------
#include <io/usb.h>
void usb_get_state__verified(usb_state_t *state);

// ---------------------------------------------------------------------
#include <io/usb_hid.h>

Expand Down
Loading

0 comments on commit f5a0f84

Please sign in to comment.