void mp_hal_set_vcp_iface(int iface_num); enum { USB_CLOSED = 0, USB_OPENED = 1, }; /// class USB: /// ''' /// USB device configuration. /// ''' typedef struct _mp_obj_USB_t { mp_obj_base_t base; mp_obj_list_t ifaces; usb_dev_info_t info; mp_int_t state; } 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 ((len >= min_len) && (len <= max_len)) { if (len == 0 && s == NULL) { return ""; } else { return s; } } else { return NULL; } } /// def __init__(self, /// vendor_id: int, /// product_id: int, /// release_num: int, /// manufacturer: str='', /// product: str='', /// serial_number: str='', /// configuration: str='', /// interface: str='') -> None: /// ''' /// ''' STATIC mp_obj_t mod_trezorio_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, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, { MP_QSTR_product, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, { MP_QSTR_serial_number, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, { MP_QSTR_configuration, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, { MP_QSTR_interface, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, }; 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 = get_0str(vals[3].u_obj, 0, 32); const char *product = get_0str(vals[4].u_obj, 0, 32); const char *serial_number = get_0str(vals[5].u_obj, 0, 32); const char *configuration = get_0str(vals[6].u_obj, 0, 32); const char *interface = get_0str(vals[7].u_obj, 0, 32); CHECK_PARAM_RANGE(vendor_id, 0, 65535) CHECK_PARAM_RANGE(product_id, 0, 65535) CHECK_PARAM_RANGE(release_num, 0, 65535) if (manufacturer == NULL) { mp_raise_ValueError("manufacturer is invalid"); } if (product == NULL) { mp_raise_ValueError("product is invalid"); } if (serial_number == NULL) { mp_raise_ValueError("serial_number is invalid"); } if (configuration == NULL) { mp_raise_ValueError("configuration is invalid"); } if (interface == NULL) { mp_raise_ValueError("interface is invalid"); } mp_obj_USB_t *o = m_new_obj(mp_obj_USB_t); o->base.type = type; o->state = USB_CLOSED; 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 = manufacturer; o->info.product = product; o->info.serial_number = serial_number; o->info.configuration = configuration; o->info.interface = interface; mp_obj_list_init(&o->ifaces, 0); return MP_OBJ_FROM_PTR(o); } /// def add(self, iface: Union[HID, VCP, WebUSB]) -> None: /// ''' /// Registers passed interface into the USB stack. /// ''' STATIC mp_obj_t mod_trezorio_USB_add(mp_obj_t self, mp_obj_t iface) { mp_obj_USB_t *o = MP_OBJ_TO_PTR(self); if (o->state != USB_CLOSED) { mp_raise_msg(&mp_type_RuntimeError, "already initialized"); } mp_obj_list_append(MP_OBJ_FROM_PTR(&o->ifaces), iface); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorio_USB_add_obj, mod_trezorio_USB_add); /// def open(self) -> None: /// ''' /// Initializes the USB stack. /// ''' STATIC mp_obj_t mod_trezorio_USB_open(mp_obj_t self) { mp_obj_USB_t *o = MP_OBJ_TO_PTR(self); if (o->state != USB_CLOSED) { mp_raise_msg(&mp_type_RuntimeError, "already initialized"); } size_t iface_cnt; mp_obj_t *iface_objs; mp_obj_get_array(MP_OBJ_FROM_PTR(&o->ifaces), &iface_cnt, &iface_objs); // Initialize the USB stack usb_init(&o->info); int vcp_iface_num = -1; // Add all interfaces for (size_t i = 0; i < iface_cnt; i++) { mp_obj_t iface = iface_objs[i]; if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_HID_type)) { mp_obj_HID_t *hid = MP_OBJ_TO_PTR(iface); if (sectrue != 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_trezorio_WebUSB_type)) { mp_obj_WebUSB_t *webusb = MP_OBJ_TO_PTR(iface); if (sectrue != usb_webusb_add(&webusb->info)) { usb_deinit(); mp_raise_msg(&mp_type_RuntimeError, "failed to add WebUSB interface"); } } else if (MP_OBJ_IS_TYPE(iface, &mod_trezorio_VCP_type)) { mp_obj_VCP_t *vcp = MP_OBJ_TO_PTR(iface); if (sectrue != usb_vcp_add(&vcp->info)) { usb_deinit(); mp_raise_msg(&mp_type_RuntimeError, "failed to add VCP interface"); } vcp_iface_num = vcp->info.iface_num; } else { usb_deinit(); mp_raise_TypeError("expected HID, WebUSB or VCP type"); } } // Start the USB stack usb_start(); o->state = USB_OPENED; // If we found any VCP interfaces, use the last one for stdio, // otherwise disable the stdio support mp_hal_set_vcp_iface(vcp_iface_num); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_USB_open_obj, mod_trezorio_USB_open); /// def close(self) -> None: /// ''' /// Cleans up the USB stack. /// ''' STATIC mp_obj_t mod_trezorio_USB_close(mp_obj_t self) { mp_obj_USB_t *o = MP_OBJ_TO_PTR(self); if (o->state != USB_OPENED) { mp_raise_msg(&mp_type_RuntimeError, "not initialized"); } usb_stop(); usb_deinit(); mp_obj_list_set_len(MP_OBJ_FROM_PTR(&o->ifaces), 0); mp_seq_clear(o->ifaces.items, 0, o->ifaces.alloc, sizeof(*o->ifaces.items)); o->info.vendor_id = 0; o->info.product_id = 0; o->info.release_num = 0; o->info.manufacturer = NULL; o->info.product = NULL; o->info.serial_number = NULL; o->state = USB_CLOSED; return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_USB_close_obj, mod_trezorio_USB_close); STATIC mp_obj_t mod_trezorio_USB___del__(mp_obj_t self) { mp_obj_USB_t *o = MP_OBJ_TO_PTR(self); if (o->state != USB_CLOSED) { usb_stop(); usb_deinit(); o->state = USB_CLOSED; } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_USB___del___obj, mod_trezorio_USB___del__); STATIC const mp_rom_map_elem_t mod_trezorio_USB_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&mod_trezorio_USB_add_obj) }, { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_trezorio_USB_open_obj) }, { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mod_trezorio_USB_close_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mod_trezorio_USB___del___obj) }, }; STATIC MP_DEFINE_CONST_DICT(mod_trezorio_USB_locals_dict, mod_trezorio_USB_locals_dict_table); STATIC const mp_obj_type_t mod_trezorio_USB_type = { { &mp_type_type }, .name = MP_QSTR_USB, .make_new = mod_trezorio_USB_make_new, .locals_dict = (void*)&mod_trezorio_USB_locals_dict, };