From 556a126917d67dad53b7cf70da8abc5ffec42c65 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 23 Apr 2021 21:44:13 -0400 Subject: [PATCH] wip: getting closer --- shared-bindings/usb_hid/__init__.c | 15 ++++-- shared-bindings/usb_hid/__init__.h | 8 +++ shared-module/usb_hid/Device.c | 8 ++- shared-module/usb_hid/Device.h | 5 +- shared-module/usb_hid/__init__.c | 80 ++++++++++++++++++++++++++---- supervisor/shared/memory.c | 5 ++ 6 files changed, 104 insertions(+), 17 deletions(-) diff --git a/shared-bindings/usb_hid/__init__.c b/shared-bindings/usb_hid/__init__.c index 6558c98e64..fdecba53df 100644 --- a/shared-bindings/usb_hid/__init__.c +++ b/shared-bindings/usb_hid/__init__.c @@ -40,14 +40,14 @@ //| """Tuple of all active HID device interfaces.""" //| -//| def configure_usb(devices: Sequence[Device, ...]=) -> None: +//| def configure_usb(devices: Optional[Sequence[Device, ...]]) -> None: //| """Configure the USB HID devices that will be available. //| Can be called in ``boot.py``, before USB is connected. //| //| :param Sequence devices: `Device` objects. //| If `devices` is empty, HID is disabled. The order of the ``Devices`` //| may matter to the host. For instance, for MacOS, put the mouse device -//| before any Gamepad or Digitizer HID device. +//| before any Gamepad or Digitizer HID device or else it will not work. //| ... //| STATIC mp_obj_t usb_hid_configure_usb(mp_obj_t devices) { @@ -61,10 +61,15 @@ STATIC mp_obj_t usb_hid_configure_usb(mp_obj_t devices) { } } - if (!common_hal_usb_hid_configure_usb(descriptors)) { - mp_raise_RuntimeError(translate("Cannot change USB devices now")); + switch (common_hal_usb_hid_configure_usb(descriptors)) { + case USB_CONFIG_TOO_LATE: + mp_raise_RuntimeError(translate("Cannot change USB devices now")); + break; + case USB_CONFIG_NON_DEVICE: + mp_raise_ValueError_varg(translate("non-Device in %q", MP_QSTR_devices)); + break; + default: } - return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(usb_hid_configure_usb_obj, usb_hid_configure_usb); diff --git a/shared-bindings/usb_hid/__init__.h b/shared-bindings/usb_hid/__init__.h index 3d56fbfd02..352d1f5a9a 100644 --- a/shared-bindings/usb_hid/__init__.h +++ b/shared-bindings/usb_hid/__init__.h @@ -32,4 +32,12 @@ extern mp_obj_tuple_t common_hal_usb_hid_devices; +typedef enum { + USB_CONFIG_OK = 0, + USB_CONFIG_TOO_LATE = 1, + USB_CONFIG_NON_DEVICE = 2, +} usb_hid_configure_status; + +usb_hid_configure_status common_hal_usb_hid_configure_usb(mp_obj_t devices); + #endif // SHARED_BINDINGS_USB_HID_H diff --git a/shared-module/usb_hid/Device.c b/shared-module/usb_hid/Device.c index d87fe3dff4..368372df89 100644 --- a/shared-module/usb_hid/Device.c +++ b/shared-module/usb_hid/Device.c @@ -156,7 +156,13 @@ const usb_hid_device_obj_t usb_hid_device_consumer_control_obj = { void common_hal_usb_hid_device_construct(usb_hid_dev_obj_t *self, mp_obj_array_t *descriptor, uint8_t usage_page, uint8_t usage, uint8_t in_report_length, uint8_t out_report_length, uint8_t report_id_index) { // report buffer pointers are NULL at start, and are created on demand. - self->descriptor = descriptor; + self->descriptor_obj = descriptor; + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(descriptor, &bufinfo, MP_BUFFER_READ); + self->descriptor = bufinfo.buf; + self->descriptor_length = bufinfo.len; + self->usage_page = usage_page; self->usage = usage; self->in_report_length = in_report_length; diff --git a/shared-module/usb_hid/Device.h b/shared-module/usb_hid/Device.h index 5b2caf369f..f15b70d79a 100644 --- a/shared-module/usb_hid/Device.h +++ b/shared-module/usb_hid/Device.h @@ -34,9 +34,12 @@ typedef struct { mp_obj_base_t base; + // If not MP_OBJ_NULL, points to Python array object whose contents are the descriptor. + mp_obj_t descriptor_obj; + // If not NULL, points to raw bytes that are the descriptor. + uint8_t *descriptor; uint8_t *in_report_buffer; uint8_t *out_report_buffer; - uint8_t *descriptor; uint16_t descriptor_length; uint8_t usage_page; uint8_t usage; diff --git a/shared-module/usb_hid/__init__.c b/shared-module/usb_hid/__init__.c index f234709df6..e48f882f93 100644 --- a/shared-module/usb_hid/__init__.c +++ b/shared-module/usb_hid/__init__.c @@ -53,14 +53,18 @@ static const uint8_t usb_hid_descriptor_template[] = { // Is the HID device enabled? bool usb_hid_enabled; -mp_obj_t usb_hid_devices; +supervisor_allocation *combined_hid_report_descriptor_allocation; +supervisor_allocation *devices_allocation; + +// This is the interface descriptor, not the report descriptor. size_t usb_hid_descriptor_length(void) { return sizeof(usb_hid_descriptor); } -static const char[] usb_hid_interface_name = USB_INTERFACE_NAME " Mass Storage"; +static const char[] usb_hid_interface_name = USB_INTERFACE_NAME " HID"; +// This is the interface descriptor, nto the report descriptor. size_t usb_hid_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interface, uint8_t *current_endpoint, uint8_t* current_interface_string, uint16_t report_descriptor_length) { memcpy(descriptor_buf, usb_hid_descriptor_template, sizeof(usb_hid_descriptor_template)); @@ -74,23 +78,79 @@ size_t usb_hid_add_descriptor(uint8_t *descriptor_buf, uint8_t *current_interfac return sizeof(usb_hid_descriptor_template); } -void usb_hid_build_report_descriptor() { -} - -bool common_hal_usb_hid_configure_usb(mp_obj_t devices) { +usb_hid_configure_status common_hal_usb_hid_configure_usb(mp_obj_t devices) { // We can't change the devices once we're connected. if (tud_connected()) { - return false; + return USB_CONFIG_TOO_LATE; } // Assume no devices to start. usb_hid_enabled = false; if (devices == mp_const_none) { - return true; + return USB_CONFIG_OK; } -} -void usb_hid_build_report + size_t total_report_descriptors_length = 0; + + // Build a combined report descriptor + + mp_int_t len = mp_obj_get_int(mp_obj_len(devices)); + + // First get the total size. + for (size_t i = 0; i < len; i++) { + mp_obj_t item = mp_obj_subscr(devices, mp_obj_new_small_int(i), MP_OBJ_SENTINEL); + if (!MP_OBJ_IS_TYPE(item, &usb_hid_device_type)) { + return USB_CONFIG_NON_DEVICE; for (size_t i = 0; i < len; i++) { + mp_obj_t item = (devices, mp_obj_new_small_int(i), MP_OBJ_SENTINEL); + if (!MP_OBJ_IS_TYPE(item, &usb_hid_device_type)) { + return USB_CONFIG_NON_DEVICE; + } + total_report_descriptors_length += device->report_descriptor_length; + } + + } + total_report_descriptors_length += device->report_descriptor_length; + } + if (len == 1) { + // Don't need space for a report id if there's only one device. + total_report_descriptors_length -= 2; + } + + // Allocate storage that persists across VMs to build the combined descriptor + // and to remember the device details. + + // allocate_memory(length, highaddress=false, movable=true) + combined_hid_report_descriptor_allocation = allocate_memory(total_report_descriptors_length, false, true); + + devices_allocation = allocate_memory(sizeof(usb_hid_device_obj_t) * len); + usb_hid_device_obj_t devices[] = (devices[]) device_details_allocation->ptr; + + uint8_t *descriptor_start = combined_hid_report_descriptor_allocation->ptr; + + for (size_t i = 0; i < len; i++) { + usb_hid_device_obj_t *device = MP_OBJ_TO_PTR(devices, mp_obj_new_small_int(i), MP_OBJ_SENTINEL); + + // Copy the report descriptor for this device. + if (len == 1) { + // Theres only one device, so it shouldn't have a report ID. + // Copy the descriptor, but splice out the report id indicator and value (2 bytes). + memcpy(descriptor_start, device->descriptor, device->report_id_index - 1); + descriptor_start += device->report_id_index - 1; + memcpy(descriptor_start, device->descriptor + device->report_id_index + 1, + device->report_descriptor_length - device->report_id_index - 1); + } else { + // Copy the whole descriptor and fill in the report id. + memcpy(descriptor_start, device->descriptor, device->descriptor_len); + descriptor_start[device->report_id_index] = i + 1; + descriptor_start += device->descriptor_len; + } + + // Copy the device data and discard any descriptor-bytes object pointer. + memcpy(&devices[i], device, sizeof(usb_hid_device_obj_t)); + devices[i].descriptor_obj = mp_const_none; + } + +} void usb_hid_gc_collect(void) { // Once tud_mounted() is true, we're done with the constructed descriptors. diff --git a/supervisor/shared/memory.c b/supervisor/shared/memory.c index 30482ea7b9..16015d1ae0 100644 --- a/supervisor/shared/memory.c +++ b/supervisor/shared/memory.c @@ -45,6 +45,9 @@ enum { , CIRCUITPY_SUPERVISOR_MOVABLE_ALLOC_COUNT = 0 + #if CIRCUITPY_USB_HID + + 2 + #endif #if CIRCUITPY_DISPLAYIO #if CIRCUITPY_TERMINALIO + 1 @@ -308,9 +311,11 @@ void supervisor_move_memory(void) { // Notify clients that their movable allocations may have moved. old_allocations = &old_allocations_array[0]; + #if CIRCUITPY_DISPLAYIO supervisor_display_move_memory(); #endif + // Add calls to further clients here. old_allocations = NULL; }