Skip to content

Add supervisor.set_usb_identification(manufacturer, product, vid, pid) function #6247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions ports/atmel-samd/mpconfigport.mk
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,11 @@ CIRCUITPY_ULAB = 0
CIRCUITPY_VECTORIO = 0
CIRCUITPY_ZLIB = 0

# TODO: In CircuitPython 8.0, turn this back on, after `busio.OneWire` is removed.
# We'd like a smoother transition, but we can't afford the space to have both
# `busio.OneWire` and `onewireio.OneWire` present on these tiny builds.
# Turn off a few more things that don't fit in 192kB

ifeq ($(INTERNAL_FLASH_FILESYSTEM),1)
CIRCUITPY_ONEWIREIO ?= 0
CIRCUITPY_USB_IDENTIFICATION ?= 0
endif

MICROPY_PY_ASYNC_AWAIT = 0
Expand Down
3 changes: 3 additions & 0 deletions py/circuitpy_mpconfig.mk
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,9 @@ CFLAGS += -DCIRCUITPY_USB_HID_ENABLED_DEFAULT=$(CIRCUITPY_USB_HID_ENABLED_DEFAUL
CIRCUITPY_USB_HOST ?= 0
CFLAGS += -DCIRCUITPY_USB_HOST=$(CIRCUITPY_USB_HOST)

CIRCUITPY_USB_IDENTIFICATION ?= $(CIRCUITPY_USB)
CFLAGS += -DCIRCUITPY_USB_IDENTIFICATION=$(CIRCUITPY_USB_IDENTIFICATION)

# MIDI is available by default, but is not turned on if there are fewer than 8 endpoints.
CIRCUITPY_USB_MIDI ?= $(CIRCUITPY_USB)
CFLAGS += -DCIRCUITPY_USB_MIDI=$(CIRCUITPY_USB_MIDI)
Expand Down
70 changes: 70 additions & 0 deletions shared-bindings/supervisor/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
#include "supervisor/shared/translate/translate.h"
#include "supervisor/shared/workflow.h"

#if CIRCUITPY_USB_IDENTIFICATION
#include "supervisor/usb.h"
#endif

#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/supervisor/__init__.h"
#include "shared-bindings/time/__init__.h"
Expand Down Expand Up @@ -298,6 +302,71 @@ STATIC mp_obj_t supervisor_reset_terminal(mp_obj_t x_pixels, mp_obj_t y_pixels)
}
MP_DEFINE_CONST_FUN_OBJ_2(supervisor_reset_terminal_obj, supervisor_reset_terminal);

//| def set_usb_identification(manufacturer: Optional[str] = None, product: Optional[str] = None, vid: int = -1, pid: int = -1) -> None:
//| """Override identification constants in the USB Device Descriptor.
//|
//| If passed, `manufacturer` and `product` must be ASCII strings (or buffers) of at most 126
//| characters. Any omitted arguments will be left at their default values.
//|
//| This method must be called in boot.py to have any effect.

//| Not available on boards without native USB support.
//| """
//| ...
//|
STATIC mp_obj_t supervisor_set_usb_identification(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
#if CIRCUITPY_USB_IDENTIFICATION
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_manufacturer, MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_product, MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_vid, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_pid, MP_ARG_INT, {.u_int = -1} },
};
struct {
mp_arg_val_t manufacturer;
mp_arg_val_t product;
mp_arg_val_t vid;
mp_arg_val_t pid;
} args;
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);

if (!usb_identification_allocation) {
usb_identification_allocation = allocate_memory(sizeof(usb_identification_t), false, true);
}
usb_identification_t *identification = (usb_identification_t *)usb_identification_allocation->ptr;

mp_arg_validate_int_range(args.vid.u_int, -1, (1 << 16) - 1, MP_QSTR_vid);
mp_arg_validate_int_range(args.pid.u_int, -1, (1 << 16) - 1, MP_QSTR_pid);

identification->vid = args.vid.u_int > -1 ? args.vid.u_int : USB_VID;
identification->pid = args.pid.u_int > -1 ? args.pid.u_int : USB_PID;

mp_buffer_info_t info;
if (args.manufacturer.u_obj != mp_const_none) {
mp_get_buffer_raise(args.manufacturer.u_obj, &info, MP_BUFFER_READ);
mp_arg_validate_length_range(info.len, 0, 126, MP_QSTR_manufacturer);
memcpy(identification->manufacturer_name, info.buf, info.len);
identification->manufacturer_name[info.len] = 0;
} else {
strcpy(identification->manufacturer_name, USB_MANUFACTURER);
}

if (args.product.u_obj != mp_const_none) {
mp_get_buffer_raise(args.product.u_obj, &info, MP_BUFFER_READ);
mp_arg_validate_length_range(info.len, 0, 126, MP_QSTR_product);
memcpy(identification->product_name, info.buf, info.len);
identification->product_name[info.len] = 0;
} else {
strcpy(identification->product_name, USB_PRODUCT);
}

return mp_const_none;
#else
mp_raise_NotImplementedError(NULL);
#endif
}
MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_set_usb_identification_obj, 0, supervisor_set_usb_identification);

STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_supervisor) },
{ MP_ROM_QSTR(MP_QSTR_set_rgb_status_brightness), MP_ROM_PTR(&supervisor_set_rgb_status_brightness_obj) },
Expand All @@ -310,6 +379,7 @@ STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_get_previous_traceback), MP_ROM_PTR(&supervisor_get_previous_traceback_obj) },
{ MP_ROM_QSTR(MP_QSTR_disable_ble_workflow), MP_ROM_PTR(&supervisor_disable_ble_workflow_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset_terminal), MP_ROM_PTR(&supervisor_reset_terminal_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_usb_identification), MP_ROM_PTR(&supervisor_set_usb_identification_obj) },
{ MP_ROM_QSTR(MP_QSTR_status_bar), MP_ROM_PTR(&shared_module_supervisor_status_bar_obj) },
};

Expand Down
36 changes: 34 additions & 2 deletions supervisor/shared/usb/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,13 @@ void usb_set_defaults(void) {
#endif
};

#if CIRCUITPY_USB_IDENTIFICATION
supervisor_allocation *usb_identification_allocation;
#endif

// Some dynamic USB data must be saved after boot.py. How much is needed?
size_t usb_boot_py_data_size(void) {
size_t size = 0;
size_t size = sizeof(usb_identification_t);

#if CIRCUITPY_USB_HID
size += usb_hid_report_descriptor_length();
Expand All @@ -135,19 +139,47 @@ size_t usb_boot_py_data_size(void) {

// Fill in the data to save.
void usb_get_boot_py_data(uint8_t *temp_storage, size_t temp_storage_size) {
#if CIRCUITPY_USB_IDENTIFICATION
if (usb_identification_allocation) {
memcpy(temp_storage, usb_identification_allocation->ptr, sizeof(usb_identification_t));
free_memory(usb_identification_allocation);
}
#else
if (false) {
}
#endif
else {
usb_identification_t defaults;
// This compiles to less code than using a struct initializer.
defaults.vid = USB_VID;
defaults.pid = USB_PID;
strcpy(defaults.manufacturer_name, USB_MANUFACTURER);
strcpy(defaults.product_name, USB_PRODUCT);
memcpy(temp_storage, &defaults, sizeof(defaults));
}

temp_storage += sizeof(usb_identification_t);
temp_storage_size -= sizeof(usb_identification_t);

#if CIRCUITPY_USB_HID
usb_hid_build_report_descriptor(temp_storage, temp_storage_size);
#endif
}

// After VM is gone, save data into non-heap storage (storage_allocations).
void usb_return_boot_py_data(uint8_t *temp_storage, size_t temp_storage_size) {
usb_identification_t identification;
memcpy(&identification, temp_storage, sizeof(usb_identification_t));

temp_storage += sizeof(usb_identification_t);
temp_storage_size -= sizeof(usb_identification_t);

#if CIRCUITPY_USB_HID
usb_hid_save_report_descriptor(temp_storage, temp_storage_size);
#endif

// Now we can also build the rest of the descriptors and place them in storage_allocations.
usb_build_descriptors();
usb_build_descriptors(&identification);
}

// Call this when ready to run code.py or a REPL, and a VM has been started.
Expand Down
21 changes: 9 additions & 12 deletions supervisor/shared/usb/usb_desc.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ static supervisor_allocation *device_descriptor_allocation;
static supervisor_allocation *configuration_descriptor_allocation;
static supervisor_allocation *string_descriptors_allocation;

static const char manufacturer_name[] = USB_MANUFACTURER;
static const char product_name[] = USB_PRODUCT;

// Serial number string is UID length * 2 (2 nibbles per byte) + 1 byte for null termination.
static char serial_number_hex_string[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH * 2 + 1];

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

static void usb_build_device_descriptor(uint16_t vid, uint16_t pid) {
static void usb_build_device_descriptor(const usb_identification_t *identification) {
device_descriptor_allocation =
allocate_memory(align32_size(sizeof(device_descriptor_template)),
/*high_address*/ false, /*movable*/ false);
uint8_t *device_descriptor = (uint8_t *)device_descriptor_allocation->ptr;
memcpy(device_descriptor, device_descriptor_template, sizeof(device_descriptor_template));

device_descriptor[DEVICE_VID_LO_INDEX] = vid & 0xFF;
device_descriptor[DEVICE_VID_HI_INDEX] = vid >> 8;
device_descriptor[DEVICE_PID_LO_INDEX] = pid & 0xFF;
device_descriptor[DEVICE_PID_HI_INDEX] = pid >> 8;
device_descriptor[DEVICE_VID_LO_INDEX] = identification->vid & 0xFF;
device_descriptor[DEVICE_VID_HI_INDEX] = identification->vid >> 8;
device_descriptor[DEVICE_PID_LO_INDEX] = identification->pid & 0xFF;
device_descriptor[DEVICE_PID_HI_INDEX] = identification->pid >> 8;

usb_add_interface_string(current_interface_string, manufacturer_name);
usb_add_interface_string(current_interface_string, identification->manufacturer_name);
device_descriptor[DEVICE_MANUFACTURER_STRING_INDEX] = current_interface_string;
current_interface_string++;

usb_add_interface_string(current_interface_string, product_name);
usb_add_interface_string(current_interface_string, identification->product_name);
device_descriptor[DEVICE_PRODUCT_STRING_INDEX] = current_interface_string;
current_interface_string++;

Expand Down Expand Up @@ -319,7 +316,7 @@ static void usb_build_interface_string_table(void) {

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

Expand All @@ -336,7 +333,7 @@ void usb_build_descriptors(void) {
current_interface_string = 1;
collected_interface_strings_length = 0;

usb_build_device_descriptor(USB_VID, USB_PID);
usb_build_device_descriptor(identification);
usb_build_configuration_descriptor();
usb_build_interface_string_table();
}
Expand Down
13 changes: 12 additions & 1 deletion supervisor/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <stddef.h>
#include <stdint.h>

#include "supervisor/memory.h"

// Ports must call this as frequently as they can in order to keep the USB
// connection alive and responsive. Normally this is called from background
// tasks after the USB IRQ handler is executed, but in specific circumstances
Expand Down Expand Up @@ -58,10 +60,19 @@ typedef struct {
size_t num_out_endpoints;
} descriptor_counts_t;

typedef struct {
uint16_t vid;
uint16_t pid;
char manufacturer_name[128];
char product_name[128];
} usb_identification_t;

extern supervisor_allocation *usb_identification_allocation;

// Shared implementation.
bool usb_enabled(void);
void usb_add_interface_string(uint8_t interface_string_index, const char str[]);
void usb_build_descriptors(void);
void usb_build_descriptors(const usb_identification_t *identification);
void usb_disconnect(void);
void usb_init(void);
void usb_set_defaults(void);
Expand Down