Cache configuration descriptor

We use it to open endpoints as they are used. Fetching the descriptor
as needed can cause issues with devices that we're expecting a control
packet while another transaction was ongoing. Specifically, a usb
thumb drive didn't expect a control transaction while doing a SCSI
transaction.

This PR also aborts transactions on timeout or ctrl-c interrupt. It
doesn't always recover though...
This commit is contained in:
Scott Shawcroft 2023-08-02 11:03:43 -07:00
parent 9cc4b4cd37
commit 59e6cab252
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
4 changed files with 33 additions and 18 deletions

View File

@ -1473,6 +1473,10 @@ msgstr ""
msgid "No capture in progress"
msgstr ""
#: shared-module/usb/core/Device.c
msgid "No configuration set"
msgstr ""
#: shared-bindings/_bleio/PacketBuffer.c
msgid "No connection: length cannot be determined"
msgstr ""

View File

@ -123,7 +123,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_manufacturer_obj, usb_core_device_
MP_PROPERTY_GETTER(usb_core_device_manufacturer_obj,
(mp_obj_t)&usb_core_device_get_manufacturer_obj);
//| def set_configuration(self, configuration=None):
//| def set_configuration(self, configuration=1):
//| """Set the active configuration.
//|
//| The configuration parameter is the bConfigurationValue field of the
@ -136,7 +136,7 @@ MP_PROPERTY_GETTER(usb_core_device_manufacturer_obj,
STATIC mp_obj_t usb_core_device_set_configuration(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_configuration };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_configuration, MP_ARG_INT, {.u_int = 0x100} },
{ MP_QSTR_configuration, MP_ARG_INT, {.u_int = 1} },
};
usb_core_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];

View File

@ -132,13 +132,23 @@ mp_obj_t common_hal_usb_core_device_get_manufacturer(usb_core_device_obj_t *self
}
void common_hal_usb_core_device_set_configuration(usb_core_device_obj_t *self, mp_int_t configuration) {
if (configuration == 0x100) {
tusb_desc_configuration_t desc;
if (!tuh_descriptor_get_configuration(self->device_number, 0, &desc, sizeof(desc), _transfer_done_cb, 0) ||
!_wait_for_callback()) {
return;
}
configuration = desc.bConfigurationValue;
// We assume that the config index is one less than the value.
uint8_t config_index = configuration - 1;
// Get the configuration descriptor and cache it. We'll use it later to open
// endpoints.
// Get only the config descriptor first.
tusb_desc_configuration_t desc;
if (!tuh_descriptor_get_configuration(self->device_number, config_index, &desc, sizeof(desc), _transfer_done_cb, 0) ||
!_wait_for_callback()) {
return;
}
// Get the config descriptor plus interfaces and endpoints.
self->configuration_descriptor = m_realloc(self->configuration_descriptor, desc.wTotalLength);
if (!tuh_descriptor_get_configuration(self->device_number, config_index, self->configuration_descriptor, desc.wTotalLength, _transfer_done_cb, 0) ||
!_wait_for_callback()) {
return;
}
tuh_configuration_set(self->device_number, configuration, _transfer_done_cb, 0);
_wait_for_callback();
@ -159,6 +169,7 @@ STATIC size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout) {
RUN_BACKGROUND_TASKS;
}
if (mp_hal_is_interrupted()) {
tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr);
return 0;
}
xfer_result_t result = _xfer_result;
@ -167,6 +178,7 @@ STATIC size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout) {
mp_raise_usb_core_USBError(translate("Pipe error"));
}
if (result == 0xff) {
tuh_edpt_abort_xfer(xfer->daddr, xfer->ep_addr);
mp_raise_usb_core_USBTimeoutError();
}
if (result == XFER_RESULT_SUCCESS) {
@ -191,17 +203,13 @@ STATIC bool _open_endpoint(usb_core_device_obj_t *self, mp_int_t endpoint) {
return true;
}
// Fetch the full configuration descriptor and search for the endpoint's descriptor.
uint8_t desc_buf[128];
if (!tuh_descriptor_get_configuration(self->device_number, self->configuration_index, &desc_buf, sizeof(desc_buf), _transfer_done_cb, 0) ||
!_wait_for_callback()) {
return false;
if (self->configuration_descriptor == NULL) {
mp_raise_usb_core_USBError(translate("No configuration set"));
}
tusb_desc_configuration_t *desc_cfg = (tusb_desc_configuration_t *)desc_buf;
tusb_desc_configuration_t *desc_cfg = (tusb_desc_configuration_t *)self->configuration_descriptor;
uint32_t total_length = tu_le16toh(desc_cfg->wTotalLength);
// Cap to the buffer size we requested.
total_length = MIN(total_length, sizeof(desc_buf));
uint8_t const *desc_end = ((uint8_t const *)desc_cfg) + total_length;
uint8_t const *p_desc = tu_desc_next(desc_cfg);
@ -287,6 +295,7 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self,
RUN_BACKGROUND_TASKS;
}
if (mp_hal_is_interrupted()) {
tuh_edpt_abort_xfer(xfer.daddr, xfer.ep_addr);
return 0;
}
xfer_result_t result = _xfer_result;
@ -295,6 +304,7 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self,
mp_raise_usb_core_USBError(translate("Pipe error"));
}
if (result == 0xff) {
tuh_edpt_abort_xfer(xfer.daddr, xfer.ep_addr);
mp_raise_usb_core_USBTimeoutError();
}
if (result == XFER_RESULT_SUCCESS) {

View File

@ -32,7 +32,8 @@
typedef struct {
mp_obj_base_t base;
uint8_t device_number;
uint8_t configuration_index; // not number
uint8_t configuration_index; // not bConfigurationValue
uint8_t *configuration_descriptor; // Contains the length of the all descriptors.
uint8_t open_endpoints[8];
} usb_core_device_obj_t;