Merge pull request #5481 from dhalbert/hid-boot-protocol
HID Boot device support; HID feature report support
This commit is contained in:
commit
dc4e5cb33b
|
@ -551,6 +551,10 @@ msgstr ""
|
|||
msgid "Bit depth must be multiple of 8."
|
||||
msgstr ""
|
||||
|
||||
#: supervisor/shared/safe_mode.c
|
||||
msgid "Boot device must be first device (interface #0)."
|
||||
msgstr ""
|
||||
|
||||
#: ports/mimxrt10xx/common-hal/busio/UART.c
|
||||
msgid "Both RX and TX required for flow control"
|
||||
msgstr ""
|
||||
|
|
|
@ -50,7 +50,8 @@
|
|||
//| Use a size of ``0`` for a report that is not an OUT report.
|
||||
//| "OUT" is with respect to the host.
|
||||
//|
|
||||
//| ``report_ids``, ``in_report_lengths``, and ``out_report_lengths`` must all be the same length.
|
||||
//| ``report_ids``, ``in_report_lengths``, and ``out_report_lengths`` must all have the
|
||||
//| same number of elements.
|
||||
//|
|
||||
//| Here is an example of a `Device` with a descriptor that specifies two report IDs, 3 and 4.
|
||||
//| Report ID 3 sends an IN report of length 5, and receives an OUT report of length 6.
|
||||
|
@ -192,7 +193,7 @@ STATIC mp_obj_t usb_hid_device_send_report(size_t n_args, const mp_obj_t *pos_ar
|
|||
MP_DEFINE_CONST_FUN_OBJ_KW(usb_hid_device_send_report_obj, 1, usb_hid_device_send_report);
|
||||
|
||||
//| def get_last_received_report(self, report_id: Optional[int] = None) -> bytes:
|
||||
//| """Get the last received HID OUT report for the given report ID.
|
||||
//| """Get the last received HID OUT or feature report for the given report ID.
|
||||
//| The report ID may be omitted if there is no report ID, or only one report ID.
|
||||
//| Return `None` if nothing received.
|
||||
//| """
|
||||
|
|
|
@ -40,6 +40,11 @@
|
|||
//| """Tuple of all active HID device interfaces.
|
||||
//| The default set of devices is ``Device.KEYBOARD, Device.MOUSE, Device.CONSUMER_CONTROL``,
|
||||
//| On boards where `usb_hid` is disabled by default, `devices` is an empty tuple.
|
||||
//|
|
||||
//| If a boot device is enabled by `usb_hid.enable()`, *and* the host has requested a boot device,
|
||||
//| the `devices` tuple is **replaced** when ``code.py`` starts with a single-element tuple
|
||||
//| containing a `Device` that describes the boot device chosen (keyboard or mouse).
|
||||
//| The request for a boot device overrides any other HID devices.
|
||||
//| """
|
||||
//|
|
||||
|
||||
|
@ -60,7 +65,7 @@ STATIC mp_obj_t usb_hid_disable(void) {
|
|||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(usb_hid_disable_obj, usb_hid_disable);
|
||||
|
||||
//| def enable(devices: Optional[Sequence[Device]]) -> None:
|
||||
//| def enable(devices: Optional[Sequence[Device]], boot_device: int = 0) -> None:
|
||||
//| """Specify which USB HID devices that will be available.
|
||||
//| Can be called in ``boot.py``, before USB is connected.
|
||||
//|
|
||||
|
@ -68,15 +73,53 @@ MP_DEFINE_CONST_FUN_OBJ_0(usb_hid_disable_obj, usb_hid_disable);
|
|||
//| 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 or else it will not work.
|
||||
//| :param int boot_device: If non-zero, inform the host that support for a
|
||||
//| a boot HID device is available.
|
||||
//| If ``boot_device=1``, a boot keyboard is available.
|
||||
//| If ``boot_device=2``, a boot mouse is available. No other values are allowed.
|
||||
//| See below.
|
||||
//|
|
||||
//| If you enable too many devices at once, you will run out of USB endpoints.
|
||||
//| The number of available endpoints varies by microcontroller.
|
||||
//| CircuitPython will go into safe mode after running ``boot.py`` to inform you if
|
||||
//| not enough endpoints are available.
|
||||
//|
|
||||
//| **Boot Devices**
|
||||
//|
|
||||
//| Boot devices implement a fixed, predefined report descriptor, defined in
|
||||
//| https://www.usb.org/sites/default/files/hid1_12.pdf, Appendix B. A USB host
|
||||
//| can request to use the boot device if the USB device says it is available.
|
||||
//| Usually only a BIOS or other kind of limited-functionality
|
||||
//| host needs boot keyboard support.
|
||||
//|
|
||||
//| For example, to make a boot keyboard available, you can use this code::
|
||||
//|
|
||||
//| usb_hid.enable((Device.KEYBOARD), boot_device=1) # 1 for a keyboard
|
||||
//|
|
||||
//| If the host requests the boot keyboard, the report descriptor provided by `Device.KEYBOARD`
|
||||
//| will be ignored, and the predefined report descriptor will be used.
|
||||
//| But if the host does not request the boot keyboard,
|
||||
//| the descriptor provided by `Device.KEYBOARD` will be used.
|
||||
//|
|
||||
//| The HID boot device must usually be the first or only device presented by CircuitPython.
|
||||
//| The HID device will be USB interface number 0.
|
||||
//| To make sure it is the first device, disable other USB devices, including CDC and MSC (CIRCUITPY).
|
||||
//| If you specify a non-zero ``boot_device``, and it is not the first device, CircuitPython
|
||||
//| will enter safe mode to report this error.
|
||||
//| """
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t usb_hid_enable(mp_obj_t devices) {
|
||||
STATIC mp_obj_t usb_hid_enable(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_devices, ARG_boot_device };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_devices, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_boot_device, MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_obj_t devices = args[ARG_devices].u_obj;
|
||||
const mp_int_t len = mp_obj_get_int(mp_obj_len(devices));
|
||||
for (mp_int_t i = 0; i < len; i++) {
|
||||
mp_obj_t item = mp_obj_subscr(devices, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL);
|
||||
|
@ -85,21 +128,44 @@ STATIC mp_obj_t usb_hid_enable(mp_obj_t devices) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!common_hal_usb_hid_enable(devices)) {
|
||||
uint8_t boot_device =
|
||||
(uint8_t)mp_arg_validate_int_range(args[ARG_boot_device].u_int, 0, 2, MP_QSTR_boot_device);
|
||||
|
||||
if (!common_hal_usb_hid_enable(devices, boot_device)) {
|
||||
mp_raise_RuntimeError(translate("Cannot change USB devices now"));
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(usb_hid_enable_obj, usb_hid_enable);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(usb_hid_enable_obj, 1, usb_hid_enable);
|
||||
|
||||
//| def get_boot_device() -> int:
|
||||
//| """
|
||||
//| :return: the boot device requested by the host, if any.
|
||||
//| Returns 0 if the host did not request a boot device, or if `usb_hid.enable()`
|
||||
//| was called with ``boot_device=0``, the default, which disables boot device support.
|
||||
//| If the host did request a boot device,
|
||||
//| returns the value of ``boot_device`` set in `usb_hid.enable()`:
|
||||
//| ``1`` for a boot keyboard, or ``2`` for boot mouse.
|
||||
//| However, the standard devices provided by CircuitPython, `Device.KEYBOARD` and `Device.MOUSE`,
|
||||
//| describe reports that match the boot device reports, so you don't need to check this
|
||||
//| if you are using those devices.
|
||||
//| :rtype int:
|
||||
//| """
|
||||
//|
|
||||
STATIC mp_obj_t usb_hid_get_boot_device(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(common_hal_usb_hid_get_boot_device());
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(usb_hid_get_boot_device_obj, usb_hid_get_boot_device);
|
||||
|
||||
// usb_hid.devices is set once the usb devices are determined, after boot.py runs.
|
||||
STATIC mp_map_elem_t usb_hid_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Device), MP_OBJ_FROM_PTR(&usb_hid_device_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_devices), mp_const_none },
|
||||
{ MP_ROM_QSTR(MP_QSTR_disable), MP_OBJ_FROM_PTR(&usb_hid_disable_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_enable), MP_OBJ_FROM_PTR(&usb_hid_enable_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Device), MP_OBJ_FROM_PTR(&usb_hid_device_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_devices), mp_const_none },
|
||||
{ MP_ROM_QSTR(MP_QSTR_disable), MP_OBJ_FROM_PTR(&usb_hid_disable_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_enable), MP_OBJ_FROM_PTR(&usb_hid_enable_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_boot_device), MP_OBJ_FROM_PTR(&usb_hid_get_boot_device_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_MUTABLE_DICT(usb_hid_module_globals, usb_hid_module_globals_table);
|
||||
|
|
|
@ -36,6 +36,7 @@ extern mp_obj_tuple_t common_hal_usb_hid_devices;
|
|||
void usb_hid_set_devices(mp_obj_t devices);
|
||||
|
||||
bool common_hal_usb_hid_disable(void);
|
||||
bool common_hal_usb_hid_enable(const mp_obj_t devices_seq);
|
||||
bool common_hal_usb_hid_enable(const mp_obj_t devices_seq, uint8_t boot_device);
|
||||
uint8_t common_hal_usb_hid_get_boot_device(void);
|
||||
|
||||
#endif // SHARED_BINDINGS_USB_HID_H
|
||||
|
|
|
@ -244,7 +244,7 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t *
|
|||
}
|
||||
|
||||
mp_obj_t common_hal_usb_hid_device_get_last_received_report(usb_hid_device_obj_t *self, uint8_t report_id) {
|
||||
// report_id has already been validated for this deveice.
|
||||
// report_id has already been validated for this device.
|
||||
size_t id_idx = get_report_id_idx(self, report_id);
|
||||
return mp_obj_new_bytes(self->out_report_buffers[id_idx], self->out_report_lengths[id_idx]);
|
||||
}
|
||||
|
@ -266,11 +266,11 @@ void usb_hid_device_create_report_buffers(usb_hid_device_obj_t *self) {
|
|||
}
|
||||
|
||||
|
||||
// Callbacks invoked when we received Get_Report request through control endpoint
|
||||
// Callback invoked when we receive Get_Report request through control endpoint
|
||||
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
|
||||
(void)itf;
|
||||
// only support Input Report
|
||||
if (report_type != HID_REPORT_TYPE_INPUT) {
|
||||
// Support Input Report and Feature Report
|
||||
if (report_type != HID_REPORT_TYPE_INPUT && report_type != HID_REPORT_TYPE_FEATURE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -289,14 +289,14 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Callbacks invoked when we received Set_Report request through control endpoint
|
||||
// Callback invoked when we receive Set_Report request through control endpoint
|
||||
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {
|
||||
(void)itf;
|
||||
if (report_type == HID_REPORT_TYPE_INVALID) {
|
||||
report_id = buffer[0];
|
||||
buffer++;
|
||||
bufsize--;
|
||||
} else if (report_type != HID_REPORT_TYPE_OUTPUT) {
|
||||
} else if (report_type != HID_REPORT_TYPE_OUTPUT && report_type != HID_REPORT_TYPE_FEATURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include "py/gc.h"
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/usb_hid/__init__.h"
|
||||
#include "shared-module/usb_hid/Device.h"
|
||||
#include "shared-bindings/usb_hid/Device.h"
|
||||
#include "supervisor/memory.h"
|
||||
#include "supervisor/usb.h"
|
||||
|
||||
|
@ -44,7 +44,9 @@ static const uint8_t usb_hid_descriptor_template[] = {
|
|||
0x02, // 4 bNumEndpoints 2
|
||||
0x03, // 5 bInterfaceClass: HID
|
||||
0x00, // 6 bInterfaceSubClass: NOBOOT
|
||||
#define HID_DESCRIPTOR_SUBCLASS_INDEX (6)
|
||||
0x00, // 7 bInterfaceProtocol: NONE
|
||||
#define HID_DESCRIPTOR_INTERFACE_PROTOCOL_INDEX (7)
|
||||
0xFF, // 8 iInterface (String Index) [SET AT RUNTIME]
|
||||
#define HID_DESCRIPTOR_INTERFACE_STRING_INDEX (8)
|
||||
|
||||
|
@ -81,6 +83,14 @@ static usb_hid_device_obj_t hid_devices[MAX_HID_DEVICES];
|
|||
// If 0, USB HID is disabled.
|
||||
static mp_int_t num_hid_devices;
|
||||
|
||||
// Which boot device is available? 0: no boot devices, 1: boot keyboard, 2: boot mouse.
|
||||
// This value is set by usb_hid.enable(), and used to build the HID interface descriptor.
|
||||
// The value is remembered here from boot.py to code.py.
|
||||
static uint8_t hid_boot_device;
|
||||
|
||||
// Whether a boot device was requested by a SET_PROTOCOL request from the host.
|
||||
static bool hid_boot_device_requested;
|
||||
|
||||
// This tuple is store in usb_hid.devices.
|
||||
static mp_obj_tuple_t *hid_devices_tuple;
|
||||
|
||||
|
@ -96,13 +106,56 @@ static mp_obj_tuple_t default_hid_devices_tuple = {
|
|||
},
|
||||
};
|
||||
|
||||
// These describe the standard descriptors used for boot keyboard and mouse, which don't use report IDs.
|
||||
// When the host requests a boot device, replace whatever HID devices were enabled with a tuple
|
||||
// containing just one of these, since the host is uninterested in other devices.
|
||||
// The driver code will then use the proper report length and send_report() will not send a report ID.
|
||||
static const usb_hid_device_obj_t boot_keyboard_obj = {
|
||||
.base = {
|
||||
.type = &usb_hid_device_type,
|
||||
},
|
||||
.report_descriptor = NULL,
|
||||
.report_descriptor_length = 0,
|
||||
.usage_page = 0x01,
|
||||
.usage = 0x06,
|
||||
.num_report_ids = 1,
|
||||
.report_ids = { 0, },
|
||||
.in_report_lengths = { 8, },
|
||||
.out_report_lengths = { 1, },
|
||||
};
|
||||
|
||||
static const usb_hid_device_obj_t boot_mouse_obj = {
|
||||
.base = {
|
||||
.type = &usb_hid_device_type,
|
||||
},
|
||||
.report_descriptor = NULL,
|
||||
.report_descriptor_length = 0,
|
||||
.usage_page = 0x01,
|
||||
.usage = 0x02,
|
||||
.num_report_ids = 1,
|
||||
.report_ids = { 0, },
|
||||
.in_report_lengths = { 4, },
|
||||
.out_report_lengths = { 0, },
|
||||
};
|
||||
|
||||
bool usb_hid_enabled(void) {
|
||||
return num_hid_devices > 0;
|
||||
}
|
||||
|
||||
uint8_t usb_hid_boot_device(void) {
|
||||
return hid_boot_device;
|
||||
}
|
||||
|
||||
// Returns 1 or 2 if host requested a boot device and boot protocol was enabled in the interface descriptor.
|
||||
uint8_t common_hal_usb_hid_get_boot_device(void) {
|
||||
return hid_boot_device_requested ? hid_boot_device : 0;
|
||||
}
|
||||
|
||||
void usb_hid_set_defaults(void) {
|
||||
hid_boot_device = 0;
|
||||
hid_boot_device_requested = false;
|
||||
common_hal_usb_hid_enable(
|
||||
CIRCUITPY_USB_HID_ENABLED_DEFAULT ? &default_hid_devices_tuple : mp_const_empty_tuple);
|
||||
CIRCUITPY_USB_HID_ENABLED_DEFAULT ? &default_hid_devices_tuple : mp_const_empty_tuple, 0);
|
||||
}
|
||||
|
||||
// This is the interface descriptor, not the report descriptor.
|
||||
|
@ -113,12 +166,17 @@ size_t usb_hid_descriptor_length(void) {
|
|||
static const char usb_hid_interface_name[] = USB_INTERFACE_NAME " HID";
|
||||
|
||||
// This is the interface descriptor, not the report descriptor.
|
||||
size_t usb_hid_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string, uint16_t report_descriptor_length) {
|
||||
size_t usb_hid_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string, uint16_t report_descriptor_length, uint8_t boot_device) {
|
||||
memcpy(descriptor_buf, usb_hid_descriptor_template, sizeof(usb_hid_descriptor_template));
|
||||
|
||||
descriptor_buf[HID_DESCRIPTOR_INTERFACE_INDEX] = descriptor_counts->current_interface;
|
||||
descriptor_counts->current_interface++;
|
||||
|
||||
if (boot_device > 0) {
|
||||
descriptor_buf[HID_DESCRIPTOR_SUBCLASS_INDEX] = 1; // BOOT protocol (device) available.
|
||||
descriptor_buf[HID_DESCRIPTOR_INTERFACE_PROTOCOL_INDEX] = boot_device; // 1: keyboard, 2: mouse
|
||||
}
|
||||
|
||||
usb_add_interface_string(*current_interface_string, usb_hid_interface_name);
|
||||
descriptor_buf[HID_DESCRIPTOR_INTERFACE_STRING_INDEX] = *current_interface_string;
|
||||
(*current_interface_string)++;
|
||||
|
@ -151,10 +209,10 @@ static void usb_hid_set_devices_from_hid_devices(void) {
|
|||
}
|
||||
|
||||
bool common_hal_usb_hid_disable(void) {
|
||||
return common_hal_usb_hid_enable(mp_const_empty_tuple);
|
||||
return common_hal_usb_hid_enable(mp_const_empty_tuple, 0);
|
||||
}
|
||||
|
||||
bool common_hal_usb_hid_enable(const mp_obj_t devices) {
|
||||
bool common_hal_usb_hid_enable(const mp_obj_t devices, uint8_t boot_device) {
|
||||
// We can't change the devices once we're connected.
|
||||
if (tud_connected()) {
|
||||
return false;
|
||||
|
@ -167,6 +225,8 @@ bool common_hal_usb_hid_enable(const mp_obj_t devices) {
|
|||
|
||||
num_hid_devices = num_devices;
|
||||
|
||||
hid_boot_device = boot_device;
|
||||
|
||||
// Remember the devices in static storage so they live across VMs.
|
||||
for (mp_int_t i = 0; i < num_hid_devices; i++) {
|
||||
// devices has already been validated to contain only usb_hid_device_obj_t objects.
|
||||
|
@ -182,6 +242,17 @@ bool common_hal_usb_hid_enable(const mp_obj_t devices) {
|
|||
|
||||
// Called when HID devices are ready to be used, when code.py or the REPL starts running.
|
||||
void usb_hid_setup_devices(void) {
|
||||
|
||||
// If the host requested a boot device, replace the current list of devices
|
||||
// with a single-element tuple containing the proper boot device.
|
||||
if (hid_boot_device_requested) {
|
||||
memcpy(&hid_devices[0],
|
||||
// Will be 1 (keyboard) or 2 (mouse).
|
||||
hid_boot_device == 1 ? &boot_keyboard_obj : &boot_mouse_obj,
|
||||
sizeof(usb_hid_device_obj_t));
|
||||
num_hid_devices = 1;
|
||||
}
|
||||
|
||||
usb_hid_set_devices_from_hid_devices();
|
||||
|
||||
// Create report buffers on the heap.
|
||||
|
@ -272,9 +343,15 @@ bool usb_hid_get_device_with_report_id(uint8_t report_id, usb_hid_device_obj_t *
|
|||
return false;
|
||||
}
|
||||
|
||||
// Invoked when GET HID REPORT DESCRIPTOR is received.
|
||||
// Application return pointer to descriptor
|
||||
// Callback invoked when we receive a GET HID REPORT DESCRIPTOR
|
||||
// Application returns pointer to descriptor
|
||||
// Descriptor contents must exist long enough for transfer to complete
|
||||
uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) {
|
||||
return (uint8_t *)hid_report_descriptor_allocation->ptr;
|
||||
}
|
||||
|
||||
// Callback invoked when we receive a SET_PROTOCOL request.
|
||||
// Protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
|
||||
void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol) {
|
||||
hid_boot_device_requested = (protocol == HID_PROTOCOL_BOOT);
|
||||
}
|
||||
|
|
|
@ -33,9 +33,10 @@
|
|||
extern usb_hid_device_obj_t usb_hid_devices[];
|
||||
|
||||
bool usb_hid_enabled(void);
|
||||
uint8_t usb_hid_boot_device(void);
|
||||
void usb_hid_set_defaults(void);
|
||||
|
||||
size_t usb_hid_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string, uint16_t report_descriptor_length);
|
||||
size_t usb_hid_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string, uint16_t report_descriptor_length, uint8_t boot_device);
|
||||
size_t usb_hid_descriptor_length(void);
|
||||
size_t usb_hid_report_descriptor_length(void);
|
||||
|
||||
|
|
|
@ -169,6 +169,9 @@ void print_safe_mode_message(safe_mode_t reason) {
|
|||
case USB_TOO_MANY_INTERFACE_NAMES:
|
||||
message = translate("USB devices specify too many interface names.");
|
||||
break;
|
||||
case USB_BOOT_DEVICE_NOT_INTERFACE_ZERO:
|
||||
message = translate("Boot device must be first device (interface #0).");
|
||||
break;
|
||||
case WATCHDOG_RESET:
|
||||
message = translate("Watchdog timer expired.");
|
||||
break;
|
||||
|
|
|
@ -46,6 +46,7 @@ typedef enum {
|
|||
WATCHDOG_RESET,
|
||||
USB_TOO_MANY_ENDPOINTS,
|
||||
USB_TOO_MANY_INTERFACE_NAMES,
|
||||
USB_BOOT_DEVICE_NOT_INTERFACE_ZERO,
|
||||
NO_HEAP,
|
||||
} safe_mode_t;
|
||||
|
||||
|
|
|
@ -228,9 +228,14 @@ static void usb_build_configuration_descriptor(void) {
|
|||
|
||||
#if CIRCUITPY_USB_HID
|
||||
if (usb_hid_enabled()) {
|
||||
if (usb_hid_boot_device() > 0 && descriptor_counts.current_interface > 0) {
|
||||
// Hosts using boot devices generally to expect them to be at interface zero,
|
||||
// and will not work properly otherwise.
|
||||
reset_into_safe_mode(USB_BOOT_DEVICE_NOT_INTERFACE_ZERO);
|
||||
}
|
||||
descriptor_buf_remaining += usb_hid_add_descriptor(
|
||||
descriptor_buf_remaining, &descriptor_counts, ¤t_interface_string,
|
||||
usb_hid_report_descriptor_length());
|
||||
usb_hid_report_descriptor_length(), usb_hid_boot_device());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue