Skip to content

Commit 21b29a7

Browse files
committed
supervisor: Add supervisor.set_usb_identification() function
1 parent 7ad35bf commit 21b29a7

File tree

4 files changed

+107
-15
lines changed

4 files changed

+107
-15
lines changed

shared-bindings/supervisor/__init__.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "supervisor/shared/traceback.h"
3939
#include "supervisor/shared/translate.h"
4040
#include "supervisor/shared/workflow.h"
41+
#include "supervisor/usb.h"
4142

4243
#include "shared-bindings/microcontroller/__init__.h"
4344
#include "shared-bindings/supervisor/__init__.h"
@@ -311,6 +312,64 @@ STATIC mp_obj_t supervisor_reset_terminal(mp_obj_t x_pixels, mp_obj_t y_pixels)
311312
}
312313
MP_DEFINE_CONST_FUN_OBJ_2(supervisor_reset_terminal_obj, supervisor_reset_terminal);
313314

315+
//| def set_usb_identification(manufacturer: Optional[str] = None, product: Optional[str] = None, vid: int = -1, pid: int = -1) -> None:
316+
//| """Override identification constants in the USB Device Descriptor.
317+
//|
318+
//| If passed, `manufacturer` and `product` must be ASCII strings (or buffers) of at most 126
319+
//| characters. Any omitted arguments will be left at their default values.
320+
//|
321+
//| This method must be called in boot.py to have any effect."""
322+
//| ...
323+
//|
324+
STATIC mp_obj_t supervisor_set_usb_identification(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
325+
static const mp_arg_t allowed_args[] = {
326+
{ MP_QSTR_manufacturer, MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
327+
{ MP_QSTR_product, MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
328+
{ MP_QSTR_vid, MP_ARG_INT, {.u_int = -1} },
329+
{ MP_QSTR_pid, MP_ARG_INT, {.u_int = -1} },
330+
};
331+
struct {
332+
mp_arg_val_t manufacturer;
333+
mp_arg_val_t product;
334+
mp_arg_val_t vid;
335+
mp_arg_val_t pid;
336+
} args;
337+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);
338+
339+
if (!usb_identification_allocation) {
340+
usb_identification_allocation = allocate_memory(sizeof(usb_identification_t), false, true);
341+
}
342+
usb_identification_t *identification = (usb_identification_t *)usb_identification_allocation->ptr;
343+
344+
mp_arg_validate_int_range(args.vid.u_int, -1, (1 << 16) - 1, MP_QSTR_vid);
345+
mp_arg_validate_int_range(args.pid.u_int, -1, (1 << 16) - 1, MP_QSTR_pid);
346+
347+
identification->vid = args.vid.u_int > -1 ? args.vid.u_int : USB_VID;
348+
identification->pid = args.pid.u_int > -1 ? args.pid.u_int : USB_PID;
349+
350+
mp_buffer_info_t info;
351+
if (args.manufacturer.u_obj != mp_const_none) {
352+
mp_get_buffer_raise(args.manufacturer.u_obj, &info, MP_BUFFER_READ);
353+
mp_arg_validate_length_range(info.len, 0, 126, MP_QSTR_manufacturer);
354+
memcpy(identification->manufacturer_name, info.buf, info.len);
355+
identification->manufacturer_name[info.len] = 0;
356+
} else {
357+
memcpy(identification->manufacturer_name, USB_MANUFACTURER, sizeof(USB_MANUFACTURER));
358+
}
359+
360+
if (args.product.u_obj != mp_const_none) {
361+
mp_get_buffer_raise(args.product.u_obj, &info, MP_BUFFER_READ);
362+
mp_arg_validate_length_range(info.len, 0, 126, MP_QSTR_product);
363+
memcpy(identification->product_name, info.buf, info.len);
364+
identification->product_name[info.len] = 0;
365+
} else {
366+
memcpy(identification->product_name, USB_MANUFACTURER, sizeof(USB_MANUFACTURER));
367+
}
368+
369+
return mp_const_none;
370+
}
371+
MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_set_usb_identification_obj, 0, supervisor_set_usb_identification);
372+
314373
STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
315374
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_supervisor) },
316375
{ MP_ROM_QSTR(MP_QSTR_enable_autoreload), MP_ROM_PTR(&supervisor_enable_autoreload_obj) },
@@ -325,6 +384,7 @@ STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
325384
{ MP_ROM_QSTR(MP_QSTR_get_previous_traceback), MP_ROM_PTR(&supervisor_get_previous_traceback_obj) },
326385
{ MP_ROM_QSTR(MP_QSTR_disable_ble_workflow), MP_ROM_PTR(&supervisor_disable_ble_workflow_obj) },
327386
{ MP_ROM_QSTR(MP_QSTR_reset_terminal), MP_ROM_PTR(&supervisor_reset_terminal_obj) },
387+
{ MP_ROM_QSTR(MP_QSTR_set_usb_identification), MP_ROM_PTR(&supervisor_set_usb_identification_obj) },
328388
};
329389

330390
STATIC MP_DEFINE_CONST_DICT(supervisor_module_globals, supervisor_module_globals_table);

supervisor/shared/usb/usb.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,11 @@ void usb_set_defaults(void) {
118118
#endif
119119
};
120120

121+
supervisor_allocation *usb_identification_allocation;
122+
121123
// Some dynamic USB data must be saved after boot.py. How much is needed?
122124
size_t usb_boot_py_data_size(void) {
123-
size_t size = 0;
125+
size_t size = sizeof(usb_identification_t);
124126

125127
#if CIRCUITPY_USB_HID
126128
size += usb_hid_report_descriptor_length();
@@ -131,19 +133,41 @@ size_t usb_boot_py_data_size(void) {
131133

132134
// Fill in the data to save.
133135
void usb_get_boot_py_data(uint8_t *temp_storage, size_t temp_storage_size) {
136+
if (usb_identification_allocation) {
137+
memcpy(temp_storage, usb_identification_allocation->ptr, sizeof(usb_identification_t));
138+
free_memory(usb_identification_allocation);
139+
} else {
140+
usb_identification_t defaults = {
141+
.vid = USB_VID,
142+
.pid = USB_PID,
143+
.manufacturer_name = USB_MANUFACTURER,
144+
.product_name = USB_PRODUCT,
145+
};
146+
memcpy(temp_storage, &defaults, sizeof(defaults));
147+
}
148+
149+
temp_storage += sizeof(usb_identification_t);
150+
temp_storage_size -= sizeof(usb_identification_t);
151+
134152
#if CIRCUITPY_USB_HID
135153
usb_hid_build_report_descriptor(temp_storage, temp_storage_size);
136154
#endif
137155
}
138156

139157
// After VM is gone, save data into non-heap storage (storage_allocations).
140158
void usb_return_boot_py_data(uint8_t *temp_storage, size_t temp_storage_size) {
159+
usb_identification_t identification;
160+
memcpy(&identification, temp_storage, sizeof(usb_identification_t));
161+
162+
temp_storage += sizeof(usb_identification_t);
163+
temp_storage_size -= sizeof(usb_identification_t);
164+
141165
#if CIRCUITPY_USB_HID
142166
usb_hid_save_report_descriptor(temp_storage, temp_storage_size);
143167
#endif
144168

145169
// Now we can also build the rest of the descriptors and place them in storage_allocations.
146-
usb_build_descriptors();
170+
usb_build_descriptors(&identification);
147171
}
148172

149173
// Call this when ready to run code.py or a REPL, and a VM has been started.

supervisor/shared/usb/usb_desc.c

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,6 @@ static supervisor_allocation *device_descriptor_allocation;
6868
static supervisor_allocation *configuration_descriptor_allocation;
6969
static supervisor_allocation *string_descriptors_allocation;
7070

71-
static const char manufacturer_name[] = USB_MANUFACTURER;
72-
static const char product_name[] = USB_PRODUCT;
73-
7471
// Serial number string is UID length * 2 (2 nibbles per byte) + 1 byte for null termination.
7572
static char serial_number_hex_string[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH * 2 + 1];
7673

@@ -113,23 +110,23 @@ static const uint8_t configuration_descriptor_template[] = {
113110
0x32, // 8 bMaxPower 100mA
114111
};
115112

116-
static void usb_build_device_descriptor(uint16_t vid, uint16_t pid) {
113+
static void usb_build_device_descriptor(const usb_identification_t *identification) {
117114
device_descriptor_allocation =
118115
allocate_memory(align32_size(sizeof(device_descriptor_template)),
119116
/*high_address*/ false, /*movable*/ false);
120117
uint8_t *device_descriptor = (uint8_t *)device_descriptor_allocation->ptr;
121118
memcpy(device_descriptor, device_descriptor_template, sizeof(device_descriptor_template));
122119

123-
device_descriptor[DEVICE_VID_LO_INDEX] = vid & 0xFF;
124-
device_descriptor[DEVICE_VID_HI_INDEX] = vid >> 8;
125-
device_descriptor[DEVICE_PID_LO_INDEX] = pid & 0xFF;
126-
device_descriptor[DEVICE_PID_HI_INDEX] = pid >> 8;
120+
device_descriptor[DEVICE_VID_LO_INDEX] = identification->vid & 0xFF;
121+
device_descriptor[DEVICE_VID_HI_INDEX] = identification->vid >> 8;
122+
device_descriptor[DEVICE_PID_LO_INDEX] = identification->pid & 0xFF;
123+
device_descriptor[DEVICE_PID_HI_INDEX] = identification->pid >> 8;
127124

128-
usb_add_interface_string(current_interface_string, manufacturer_name);
125+
usb_add_interface_string(current_interface_string, identification->manufacturer_name);
129126
device_descriptor[DEVICE_MANUFACTURER_STRING_INDEX] = current_interface_string;
130127
current_interface_string++;
131128

132-
usb_add_interface_string(current_interface_string, product_name);
129+
usb_add_interface_string(current_interface_string, identification->product_name);
133130
device_descriptor[DEVICE_PRODUCT_STRING_INDEX] = current_interface_string;
134131
current_interface_string++;
135132

@@ -319,7 +316,7 @@ static void usb_build_interface_string_table(void) {
319316

320317
// After boot.py runs, the USB devices to be used have been chosen, and the descriptors can be set up.
321318
// This is called after the VM is finished, because it uses storage_allocations.
322-
void usb_build_descriptors(void) {
319+
void usb_build_descriptors(const usb_identification_t *identification) {
323320
uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH];
324321
common_hal_mcu_processor_get_uid(raw_id);
325322

@@ -336,7 +333,7 @@ void usb_build_descriptors(void) {
336333
current_interface_string = 1;
337334
collected_interface_strings_length = 0;
338335

339-
usb_build_device_descriptor(USB_VID, USB_PID);
336+
usb_build_device_descriptor(identification);
340337
usb_build_configuration_descriptor();
341338
usb_build_interface_string_table();
342339
}

supervisor/usb.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include <stddef.h>
3232
#include <stdint.h>
3333

34+
#include "supervisor/memory.h"
35+
3436
// Ports must call this as frequently as they can in order to keep the USB
3537
// connection alive and responsive. Normally this is called from background
3638
// tasks after the USB IRQ handler is executed, but in specific circumstances
@@ -58,10 +60,19 @@ typedef struct {
5860
size_t num_out_endpoints;
5961
} descriptor_counts_t;
6062

63+
typedef struct {
64+
uint16_t vid;
65+
uint16_t pid;
66+
char manufacturer_name[128];
67+
char product_name[128];
68+
} usb_identification_t;
69+
70+
extern supervisor_allocation *usb_identification_allocation;
71+
6172
// Shared implementation.
6273
bool usb_enabled(void);
6374
void usb_add_interface_string(uint8_t interface_string_index, const char str[]);
64-
void usb_build_descriptors(void);
75+
void usb_build_descriptors(const usb_identification_t *identification);
6576
void usb_disconnect(void);
6677
void usb_init(void);
6778
void usb_set_defaults(void);

0 commit comments

Comments
 (0)