diff --git a/micropython/extmod/modtrezormsg/modtrezormsg.c b/micropython/extmod/modtrezormsg/modtrezormsg.c index c3b4223daf..5ff86aecec 100644 --- a/micropython/extmod/modtrezormsg/modtrezormsg.c +++ b/micropython/extmod/modtrezormsg/modtrezormsg.c @@ -1,5 +1,5 @@ /* - * Copyright (c) Pavol Rusnak, SatoshiLabs + * Copyright (c) Pavol Rusnak, Jan Pochyla, SatoshiLabs * * Licensed under TREZOR License * see LICENSE file for details @@ -17,18 +17,259 @@ #if defined TREZOR_STM32 #include "modtrezormsg-stm32.h" +#include "pendsv.h" #elif defined TREZOR_UNIX #include "modtrezormsg-unix.h" #else #error Unsupported TREZOR port. Only STM32 and UNIX ports are supported. #endif -#define MAX_INTERFACES 8 +typedef struct _mp_obj_USB_t { + mp_obj_base_t base; + usb_dev_info_t info; +} mp_obj_USB_t; + +static const char *get_0str(mp_obj_t o, size_t min_len, size_t max_len) { + size_t len; + const char *s = mp_obj_str_get_data(o, &len); + if ((s != NULL) && (len >= min_len) && (len <= max_len)) { + return s; + } else { + return NULL; + } +} + +STATIC mp_obj_t mod_TrezorMsg_USB_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + + STATIC const mp_arg_t allowed_args[] = { + { MP_QSTR_vendor_id, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_product_id, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_release_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_manufacturer_str, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_product_str, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_serial_number_str, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_configuration_str, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_interface_str, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); + + const mp_int_t vendor_id = vals[0].u_int; + const mp_int_t product_id = vals[1].u_int; + const mp_int_t release_num = vals[2].u_int; + const char *manufacturer_str = get_0str(vals[3].u_obj, 1, 32); + const char *product_str = get_0str(vals[4].u_obj, 1, 32); + const char *serial_number_str = get_0str(vals[5].u_obj, 1, 32); + const char *configuration_str = get_0str(vals[6].u_obj, 1, 32); + const char *interface_str = get_0str(vals[7].u_obj, 1, 32); + + if (vendor_id < 0 || vendor_id > 65535) { + mp_raise_ValueError("vendor_id is invalid"); + } + if (product_id < 0 || product_id > 65535) { + mp_raise_ValueError("product_id is invalid"); + } + if (manufacturer_str == NULL) { + mp_raise_ValueError("manufacturer_str is invalid"); + } + if (product_str == NULL) { + mp_raise_ValueError("product_str is invalid"); + } + if (serial_number_str == NULL) { + mp_raise_ValueError("serial_number_str is invalid"); + } + if (configuration_str == NULL) { + mp_raise_ValueError("configuration_str is invalid"); + } + if (interface_str == NULL) { + mp_raise_ValueError("interface_str is invalid"); + } + + mp_obj_USB_t *o = m_new_obj(mp_obj_USB_t); + o->base.type = type; + + o->info.vendor_id = (uint16_t)(vendor_id); + o->info.product_id = (uint16_t)(product_id); + o->info.release_num = (uint16_t)(release_num); + o->info.manufacturer_str = (const uint8_t *)(manufacturer_str); + o->info.product_str = (const uint8_t *)(product_str); + o->info.serial_number_str = (const uint8_t *)(serial_number_str); + o->info.configuration_str = (const uint8_t *)(configuration_str); + o->info.interface_str = (const uint8_t *)(interface_str); + + return MP_OBJ_FROM_PTR(o); +} + +STATIC const mp_rom_map_elem_t mod_TrezorMsg_USB_locals_dict_table[] = {}; +STATIC MP_DEFINE_CONST_DICT(mod_TrezorMsg_USB_locals_dict, mod_TrezorMsg_USB_locals_dict_table); + +STATIC const mp_obj_type_t mod_TrezorMsg_USB_type = { + { &mp_type_type }, + .name = MP_QSTR_USB, + .make_new = mod_TrezorMsg_USB_make_new, + .locals_dict = (void*)&mod_TrezorMsg_USB_locals_dict, +}; + +typedef struct _mp_obj_HID_t { + mp_obj_base_t base; + usb_hid_info_t info; +} mp_obj_HID_t; + +STATIC mp_obj_t mod_TrezorMsg_HID_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + + STATIC const mp_arg_t allowed_args[] = { + { MP_QSTR_iface_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_ep_in, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_ep_out, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_subclass, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_protocol, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_polling_interval, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_max_packet_len, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, + { MP_QSTR_report_desc, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); + + const mp_int_t iface_num = vals[0].u_int; + const mp_int_t ep_in = vals[1].u_int; + const mp_int_t ep_out = vals[2].u_int; + const mp_int_t subclass = vals[3].u_int; + const mp_int_t protocol = vals[4].u_int; + const mp_int_t polling_interval = vals[5].u_int; + const mp_int_t max_packet_len = vals[6].u_int; + mp_buffer_info_t report_desc; + mp_get_buffer_raise(vals[7].u_obj, &report_desc, MP_BUFFER_READ); + + if (report_desc.buf == NULL || report_desc.len == 0 || report_desc.len > 255) { + mp_raise_ValueError("report_desc is invalid"); + } + if (iface_num < 0 || iface_num > 32) { + mp_raise_ValueError("iface_num is invalid"); + } + if (ep_in < 0 || ep_in > 255) { + mp_raise_ValueError("ep_in is invalid"); + } + if (ep_out < 0 || ep_out > 255) { + mp_raise_ValueError("ep_out is invalid"); + } + if (subclass < 0 || subclass > 255) { + mp_raise_ValueError("subclass is invalid"); + } + if (protocol < 0 || protocol > 255) { + mp_raise_ValueError("protocol is invalid"); + } + if (polling_interval < 1 || polling_interval > 255) { + mp_raise_ValueError("polling_interval is invalid"); + } + if (max_packet_len != 64) { + mp_raise_ValueError("max_packet_len is invalid"); + } + + mp_obj_HID_t *o = m_new_obj(mp_obj_HID_t); + o->base.type = type; + + o->info.rx_buffer = m_new(uint8_t, max_packet_len); + o->info.report_desc = report_desc.buf; + o->info.iface_num = (uint8_t)(iface_num); + o->info.ep_in = (uint8_t)(ep_in); + o->info.ep_out = (uint8_t)(ep_out); + o->info.subclass = (uint8_t)(subclass); + o->info.protocol = (uint8_t)(protocol); + o->info.polling_interval = (uint8_t)(polling_interval); + o->info.max_packet_len = (uint8_t)(max_packet_len); + o->info.report_desc_len = (uint8_t)(report_desc.len); + + return MP_OBJ_FROM_PTR(o); +} + +STATIC const mp_rom_map_elem_t mod_TrezorMsg_HID_locals_dict_table[] = {}; +STATIC MP_DEFINE_CONST_DICT(mod_TrezorMsg_HID_locals_dict, mod_TrezorMsg_HID_locals_dict_table); + +STATIC const mp_obj_type_t mod_TrezorMsg_HID_type = { + { &mp_type_type }, + .name = MP_QSTR_HID, + .make_new = mod_TrezorMsg_HID_make_new, + .locals_dict = (void*)&mod_TrezorMsg_HID_locals_dict, +}; + +typedef struct _mp_obj_VCP_t { + mp_obj_base_t base; + usb_vcp_info_t info; +} mp_obj_VCP_t; + +STATIC mp_obj_t mod_TrezorMsg_VCP_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + + STATIC const mp_arg_t allowed_args[] = { + { MP_QSTR_iface_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_data_iface_num, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_ep_in, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_ep_out, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_ep_cmd, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals); + + const mp_int_t iface_num = vals[0].u_int; + const mp_int_t data_iface_num = vals[1].u_int; + const mp_int_t ep_in = vals[2].u_int; + const mp_int_t ep_out = vals[3].u_int; + const mp_int_t ep_cmd = vals[4].u_int; + + if (iface_num < 0 || iface_num > 32) { + mp_raise_ValueError("iface_num is invalid"); + } + if (data_iface_num < 0 || data_iface_num > 32) { + mp_raise_ValueError("iface_num is invalid"); + } + if (ep_in < 0 || ep_in > 255) { + mp_raise_ValueError("ep_in is invalid"); + } + if (ep_out < 0 || ep_out > 255) { + mp_raise_ValueError("ep_out is invalid"); + } + if (ep_cmd < 0 || ep_cmd > 255) { + mp_raise_ValueError("ep_cmd is invalid"); + } + + const size_t vcp_buffer_len = 1024; + const size_t vcp_packet_len = 64; + + mp_obj_VCP_t *o = m_new_obj(mp_obj_VCP_t); + o->base.type = type; + + o->info.tx_packet = m_new(uint8_t, vcp_packet_len); + o->info.tx_buffer = m_new(uint8_t, vcp_buffer_len); + o->info.rx_packet = m_new(uint8_t, vcp_packet_len); + o->info.rx_buffer = m_new(uint8_t, vcp_buffer_len); + o->info.tx_buffer_len = vcp_buffer_len; + o->info.rx_buffer_len = vcp_buffer_len; + o->info.rx_intr_fn = pendsv_kbd_intr; + o->info.rx_intr_byte = 3; // Ctrl-C + o->info.iface_num = (uint8_t)(iface_num); + o->info.data_iface_num = (uint8_t)(data_iface_num); + o->info.ep_cmd = (uint8_t)(ep_cmd); + o->info.ep_in = (uint8_t)(ep_in); + o->info.ep_out = (uint8_t)(ep_out); + o->info.polling_interval = 10; + o->info.max_packet_len = (uint8_t)(vcp_packet_len); + + return MP_OBJ_FROM_PTR(o); +} + +STATIC const mp_rom_map_elem_t mod_TrezorMsg_VCP_locals_dict_table[] = {}; +STATIC MP_DEFINE_CONST_DICT(mod_TrezorMsg_VCP_locals_dict, mod_TrezorMsg_VCP_locals_dict_table); + +STATIC const mp_obj_type_t mod_TrezorMsg_VCP_type = { + { &mp_type_type }, + .name = MP_QSTR_VCP, + .make_new = mod_TrezorMsg_VCP_make_new, + .locals_dict = (void*)&mod_TrezorMsg_VCP_locals_dict, +}; typedef struct _mp_obj_Msg_t { mp_obj_base_t base; - uint16_t usage_pages[MAX_INTERFACES]; - mp_uint_t interface_count; + mp_obj_t usb_info; + mp_obj_t usb_ifaces; } mp_obj_Msg_t; STATIC mp_obj_t mod_TrezorMsg_Msg_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -36,64 +277,74 @@ STATIC mp_obj_t mod_TrezorMsg_Msg_make_new(const mp_obj_type_t *type, size_t n_a msg_init(); mp_obj_Msg_t *o = m_new_obj(mp_obj_Msg_t); o->base.type = type; - o->interface_count = 0; + o->usb_info = mp_const_none; + o->usb_ifaces = mp_const_none; return MP_OBJ_FROM_PTR(o); } -/// def trezor.msg.set_interfaces(ifaces: list/tuple) -> None: +/// def trezor.msg.init_usb(usb_info, usb_ifaces) -> None: /// ''' -/// Configures USB interfaces with a list/tuple of (usage_page, ...) +/// Registers passed interfaces and initializes the USB stack /// ''' -STATIC mp_obj_t mod_TrezorMsg_Msg_set_interfaces(mp_obj_t self, mp_obj_t ifaces) { +STATIC mp_obj_t mod_TrezorMsg_Msg_init_usb(mp_obj_t self, mp_obj_t usb_info, mp_obj_t usb_ifaces) { + + if (!MP_OBJ_IS_TYPE(usb_info, &mod_TrezorMsg_USB_type)) { + mp_raise_TypeError("Expected USB type"); + } + mp_obj_USB_t *usb = MP_OBJ_TO_PTR(self); + if (0 != usb_init(&usb->info)) { + mp_raise_msg(&mp_type_RuntimeError, "Failed to initialize USB layer"); + } + size_t iface_cnt; - mp_obj_t *usage_pages; - mp_obj_get_array(ifaces, &iface_cnt, &usage_pages); - if (iface_cnt > MAX_INTERFACES) { - mp_raise_ValueError("Maximum number of interfaces exceeded"); - } - mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self); + mp_obj_t *iface_objs; + mp_obj_get_array(usb_ifaces, &iface_cnt, &iface_objs); + for (size_t i = 0; i < iface_cnt; i++) { - uint16_t usage_page = mp_obj_get_int(usage_pages[i]); - o->usage_pages[i] = usage_page; + mp_obj_t iface = iface_objs[i]; + + if (MP_OBJ_IS_TYPE(iface, &mod_TrezorMsg_HID_type)) { + mp_obj_HID_t *hid = MP_OBJ_TO_PTR(iface); + if (0 != usb_hid_add(&hid->info)) { + usb_deinit(); + mp_raise_msg(&mp_type_RuntimeError, "Failed to add HID interface"); + } + } else if (MP_OBJ_IS_TYPE(iface, &mod_TrezorMsg_VCP_type)) { + mp_obj_VCP_t *vcp = MP_OBJ_TO_PTR(iface); + if (0 != usb_vcp_add(&vcp->info)) { + usb_deinit(); + mp_raise_msg(&mp_type_RuntimeError, "Failed to add VCP interface"); + } + } else { + usb_deinit(); + mp_raise_TypeError("Unknown interface type"); + } } - o->interface_count = iface_cnt; + + if (0 != usb_start()) { + usb_deinit(); + mp_raise_msg(&mp_type_RuntimeError, "Failed to start USB layer"); + } + + mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self); + o->usb_info = usb_info; + o->usb_ifaces = usb_ifaces; + return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorMsg_Msg_set_interfaces_obj, mod_TrezorMsg_Msg_set_interfaces); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorMsg_Msg_init_usb_obj, mod_TrezorMsg_Msg_init_usb); -/// def trezor.msg.get_interfaces() -> tuple: -/// ''' -/// Reads a tuple (of usage pages) of configured USB interfaces -/// ''' -STATIC mp_obj_t mod_TrezorMsg_Msg_get_interfaces(mp_obj_t self) { - mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self); - mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(o->interface_count, NULL)); - for (mp_uint_t i = 0; i < o->interface_count; i++) { - tuple->items[i] = MP_OBJ_NEW_SMALL_INT(o->usage_pages[i]); - } - return MP_OBJ_FROM_PTR(tuple); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorMsg_Msg_get_interfaces_obj, mod_TrezorMsg_Msg_get_interfaces); - -/// def trezor.msg.send(usage_page: int, message: bytes) -> int: +/// def trezor.msg.send(iface: int, message: bytes) -> int: /// ''' /// Sends message using USB HID (device) or UDP (emulator). /// ''' -STATIC mp_obj_t mod_TrezorMsg_Msg_send(mp_obj_t self, mp_obj_t usage_page, mp_obj_t message) { - mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self); - if (o->interface_count == 0) { - mp_raise_TypeError("No interfaces registered"); - } - uint16_t up = mp_obj_get_int(usage_page); - for (uint8_t i = 0; i < o->interface_count; i++) { - if (o->usage_pages[i] == up) { - mp_buffer_info_t msg; - mp_get_buffer_raise(message, &msg, MP_BUFFER_READ); - ssize_t r = msg_send(i, msg.buf, msg.len); - return MP_OBJ_NEW_SMALL_INT(r); - } - } - mp_raise_TypeError("Interface not found"); +STATIC mp_obj_t mod_TrezorMsg_Msg_send(mp_obj_t self, mp_obj_t iface, mp_obj_t message) { + // mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self); + uint8_t i = mp_obj_get_int(iface); + mp_buffer_info_t msg; + mp_get_buffer_raise(message, &msg, MP_BUFFER_READ); + ssize_t r = msg_send(i, msg.buf, msg.len); + return MP_OBJ_NEW_SMALL_INT(r); } STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorMsg_Msg_send_obj, mod_TrezorMsg_Msg_send); @@ -107,12 +358,12 @@ extern uint32_t touch_read(void); // defined in HAL /// Function returns None if timeout specified in microseconds is reached. /// ''' STATIC mp_obj_t mod_TrezorMsg_Msg_select(mp_obj_t self, mp_obj_t timeout_us) { - mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self); + // mp_obj_Msg_t *o = MP_OBJ_TO_PTR(self); int timeout = mp_obj_get_int(timeout_us); if (timeout < 0) { timeout = 0; } - for(;;) { + for (;;) { uint32_t e = touch_read(); if (e) { mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL)); @@ -122,23 +373,19 @@ STATIC mp_obj_t mod_TrezorMsg_Msg_select(mp_obj_t self, mp_obj_t timeout_us) { tuple->items[3] = MP_OBJ_NEW_SMALL_INT((e & 0xFF)); // y position return MP_OBJ_FROM_PTR(tuple); } - // check for interfaces only when some have been registered - if (o->interface_count > 0) { - uint8_t iface; - uint8_t recvbuf[64]; - ssize_t l = msg_recv(&iface, recvbuf, 64); - if (l > 0 && iface < o->interface_count) { - if (l == 8 && memcmp("PINGPING", recvbuf, 8) == 0) { - msg_send(iface, (const uint8_t *)"PONGPONG", 8); - return mp_const_none; - } else { - uint16_t iface_usage_page = o->usage_pages[iface]; - mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(iface_usage_page); - tuple->items[1] = mp_obj_new_str_of_type(&mp_type_bytes, recvbuf, l); - return MP_OBJ_FROM_PTR(tuple); - } - } + uint8_t iface; + uint8_t recvbuf[64]; + ssize_t l = msg_recv(&iface, recvbuf, 64); + if (l > 0) { + if (l == 8 && memcmp("PINGPING", recvbuf, 8) == 0) { + msg_send(iface, (const uint8_t *)"PONGPONG", 8); + return mp_const_none; + } else { + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(iface); + tuple->items[1] = mp_obj_new_str_of_type(&mp_type_bytes, recvbuf, l); + return MP_OBJ_FROM_PTR(tuple); + } } if (timeout <= 0) { break; @@ -151,10 +398,10 @@ STATIC mp_obj_t mod_TrezorMsg_Msg_select(mp_obj_t self, mp_obj_t timeout_us) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorMsg_Msg_select_obj, mod_TrezorMsg_Msg_select); STATIC const mp_rom_map_elem_t mod_TrezorMsg_Msg_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mod_TrezorMsg_Msg_select_obj) }, + { MP_ROM_QSTR(MP_QSTR_init_usb), MP_ROM_PTR(&mod_TrezorMsg_Msg_init_usb_obj) }, + // { MP_ROM_QSTR(MP_QSTR_deinit_usb), MP_ROM_PTR(&mod_TrezorMsg_Msg_deinit_usb_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&mod_TrezorMsg_Msg_send_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_interfaces), MP_ROM_PTR(&mod_TrezorMsg_Msg_set_interfaces_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_interfaces), MP_ROM_PTR(&mod_TrezorMsg_Msg_get_interfaces_obj) }, + { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mod_TrezorMsg_Msg_select_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mod_TrezorMsg_Msg_locals_dict, mod_TrezorMsg_Msg_locals_dict_table); @@ -167,9 +414,11 @@ STATIC const mp_obj_type_t mod_TrezorMsg_Msg_type = { STATIC const mp_rom_map_elem_t mp_module_TrezorMsg_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_TrezorMsg) }, + { MP_ROM_QSTR(MP_QSTR_USB), MP_ROM_PTR(&mod_TrezorMsg_USB_type) }, + { MP_ROM_QSTR(MP_QSTR_HID), MP_ROM_PTR(&mod_TrezorMsg_HID_type) }, + { MP_ROM_QSTR(MP_QSTR_VCP), MP_ROM_PTR(&mod_TrezorMsg_VCP_type) }, { MP_ROM_QSTR(MP_QSTR_Msg), MP_ROM_PTR(&mod_TrezorMsg_Msg_type) }, }; - STATIC MP_DEFINE_CONST_DICT(mp_module_TrezorMsg_globals, mp_module_TrezorMsg_globals_table); const mp_obj_module_t mp_module_TrezorMsg = { diff --git a/micropython/firmware/main.c b/micropython/firmware/main.c index ce3a9f43c1..e661e729c0 100644 --- a/micropython/firmware/main.c +++ b/micropython/firmware/main.c @@ -131,9 +131,9 @@ int main(void) { __fatal_error("touch_init failed"); } - if (0 != usb_init_all()) { - __fatal_error("usb_init_all failed"); - } + // if (0 != usb_init_all()) { + // __fatal_error("usb_init_all failed"); + // } for (;;) { // Stack limit should be less than real stack size, so we have a chance diff --git a/micropython/firmware/mphalport.c b/micropython/firmware/mphalport.c index 92a19c16ec..2c2d0b6140 100644 --- a/micropython/firmware/mphalport.c +++ b/micropython/firmware/mphalport.c @@ -3,7 +3,7 @@ #define VCP_IFACE 0x01 #define VCP_READ_TIMEOUT 25 -#define VCP_WRITE_TIMEOUT 5 +#define VCP_WRITE_TIMEOUT 0 int mp_hal_stdin_rx_chr(void) { uint8_t c = 0; diff --git a/micropython/trezorhal/usb.c b/micropython/trezorhal/usb.c index eb58dfb3a0..c91fb1a47d 100644 --- a/micropython/trezorhal/usb.c +++ b/micropython/trezorhal/usb.c @@ -83,12 +83,9 @@ int usb_init(const usb_dev_info_t *dev_info) { usb_config_desc->bmAttributes = 0x80; // 0x80 = bus powered; 0xc0 = self powered usb_config_desc->bMaxPower = 0xfa; // Maximum Power Consumption in 2mA units - // Reset pointer to interface descriptor data + // Pointer to interface descriptor data usb_next_iface_desc = (usb_interface_descriptor_t *)(usb_config_buf + usb_config_desc->wTotalLength); - // Reset the iface state map - memset(&usb_ifaces, 0, sizeof(usb_ifaces)); - if (0 != USBD_Init(&usb_dev_handle, (USBD_DescriptorsTypeDef*)&usb_descriptors, USB_PHY_FS_ID)) { return 1; } diff --git a/src/main.py b/src/main.py index 61005eb491..fbc1c68003 100644 --- a/src/main.py +++ b/src/main.py @@ -10,6 +10,7 @@ from apps import homescreen from apps import management from apps import wallet from apps import ethereum +from apps import fido_u2f # Initialize all applications if __debug__: @@ -18,6 +19,7 @@ homescreen.boot() management.boot() wallet.boot() ethereum.boot() +fido_u2f.boot() # HACK: keep storage loaded at all times from apps.common import storage @@ -25,14 +27,46 @@ from apps.common import storage # Change backlight to white for better visibility ui.display.backlight(ui.BACKLIGHT_NORMAL) -# Just a demo to show how to register USB ifaces -msg.set_interfaces([0xFF00, 0xFF01, 0xF1D0]) -# and list them -for i, up in enumerate(msg.get_interfaces()): - print("iface %d: usage_page 0x%04x" % (i + 1, up)) +# Register USB ifaces +usb = msg.USB( + vendor_id=0x1209, + product_id=0x53C1, + release_num=0x0002, + manufacturer_str="manufacturer_str", + product_str="product_str", + serial_number_str="serial_number_str", + configuration_str="configuration_str", + interface_str="interface_str", +) +hid_wire_iface = const(0x00) +hid_wire_rdesc = bytes([ + 0x06, 0x00, 0xff, # USAGE_PAGE (Vendor Defined) + 0x09, 0x01, # USAGE (1) + 0xa1, 0x01, # COLLECTION (Application) + 0x09, 0x20, # USAGE (Input Report Data) + 0x15, 0x00, # LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, # LOGICAL_MAXIMUM (255) + 0x75, 0x08, # REPORT_SIZE (8) + 0x95, 0x40, # REPORT_COUNT (64) + 0x81, 0x02, # INPUT (Data,Var,Abs) + 0x09, 0x21, # USAGE (Output Report Data) + 0x15, 0x00, # LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, # LOGICAL_MAXIMUM (255) + 0x75, 0x08, # REPORT_SIZE (8) + 0x95, 0x40, # REPORT_COUNT (64) + 0x91, 0x02, # OUTPUT (Data,Var,Abs) + 0xc0, # END_COLLECTION +]) +hid_wire = msg.HID( + iface_num=hid_wire_iface, + ep_in=0x81, + ep_out=0x01, + report_desc=hid_wire_rdesc, +) +msg.init_usb(usb, (hid_wire,)) # Initialize the wire codec pipeline -wire.setup(0xFF00) +wire.setup(hid_wire_iface) # Load default homescreen from apps.homescreen.homescreen import layout_homescreen