mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
usb_host: Fix error when fetching LANGID table
USB devices may support string descriptors in multiple languages. The supported languages are stored in a LANGID table, which itself is a string descriptor at index 0. When fetching the LANGID table itself, the USB 2.0 specification does not specify what LANGID to use, thus the Hub driver would use the default LANGID "ENUM_LANGID". However, this would cause some devices to stall. This commit fixes the issue by always requesting the LANGID table itself using a LANGID of 0.
This commit is contained in:
parent
3f1cff699d
commit
6e9500ad13
@ -288,33 +288,34 @@ static bool enum_stage_second_reset(enum_ctrl_t *enum_ctrl)
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint8_t get_string_desc_index(enum_ctrl_t *enum_ctrl)
|
||||
static void get_string_desc_index_and_langid(enum_ctrl_t *enum_ctrl, uint8_t *index, uint16_t *langid)
|
||||
{
|
||||
uint8_t index;
|
||||
switch (enum_ctrl->stage) {
|
||||
case ENUM_STAGE_GET_SHORT_LANGID_TABLE:
|
||||
case ENUM_STAGE_GET_FULL_LANGID_TABLE:
|
||||
index = 0; //The LANGID table uses an index of 0
|
||||
*index = 0; //The LANGID table uses an index of 0
|
||||
*langid = 0; //Getting the LANGID table itself should use a LANGID of 0
|
||||
break;
|
||||
case ENUM_STAGE_GET_SHORT_MANU_STR_DESC:
|
||||
case ENUM_STAGE_GET_FULL_MANU_STR_DESC:
|
||||
index = enum_ctrl->iManufacturer;
|
||||
*index = enum_ctrl->iManufacturer;
|
||||
*langid = ENUM_LANGID; //Use the default LANGID
|
||||
break;
|
||||
case ENUM_STAGE_GET_SHORT_PROD_STR_DESC:
|
||||
case ENUM_STAGE_GET_FULL_PROD_STR_DESC:
|
||||
index = enum_ctrl->iProduct;
|
||||
*index = enum_ctrl->iProduct;
|
||||
*langid = ENUM_LANGID; //Use the default LANGID
|
||||
break;
|
||||
case ENUM_STAGE_GET_SHORT_SER_STR_DESC:
|
||||
case ENUM_STAGE_GET_FULL_SER_STR_DESC:
|
||||
index = enum_ctrl->iSerialNumber;
|
||||
*index = enum_ctrl->iSerialNumber;
|
||||
*langid = ENUM_LANGID; //Use the default LANGID
|
||||
break;
|
||||
default:
|
||||
//Should not occur
|
||||
index = 0;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl)
|
||||
@ -369,11 +370,13 @@ static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl)
|
||||
case ENUM_STAGE_GET_SHORT_MANU_STR_DESC:
|
||||
case ENUM_STAGE_GET_SHORT_PROD_STR_DESC:
|
||||
case ENUM_STAGE_GET_SHORT_SER_STR_DESC: {
|
||||
uint8_t index = get_string_desc_index(enum_ctrl);
|
||||
uint8_t index;
|
||||
uint16_t langid;
|
||||
get_string_desc_index_and_langid(enum_ctrl, &index, &langid);
|
||||
//Get only the header of the string descriptor
|
||||
USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)transfer->data_buffer,
|
||||
index,
|
||||
ENUM_LANGID,
|
||||
langid,
|
||||
sizeof(usb_str_desc_t));
|
||||
transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(sizeof(usb_str_desc_t), enum_ctrl->bMaxPacketSize0);
|
||||
//IN data stage should return exactly sizeof(usb_str_desc_t) bytes
|
||||
@ -384,11 +387,13 @@ static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl)
|
||||
case ENUM_STAGE_GET_FULL_MANU_STR_DESC:
|
||||
case ENUM_STAGE_GET_FULL_PROD_STR_DESC:
|
||||
case ENUM_STAGE_GET_FULL_SER_STR_DESC: {
|
||||
uint8_t index = get_string_desc_index(enum_ctrl);
|
||||
uint8_t index;
|
||||
uint16_t langid;
|
||||
get_string_desc_index_and_langid(enum_ctrl, &index, &langid);
|
||||
//Get the full string descriptor at a particular index, requesting the descriptors exact length
|
||||
USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)transfer->data_buffer,
|
||||
index,
|
||||
ENUM_LANGID,
|
||||
langid,
|
||||
enum_ctrl->str_desc_bLength);
|
||||
transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(enum_ctrl->str_desc_bLength, enum_ctrl->bMaxPacketSize0);
|
||||
//IN data stage should return exactly str_desc_bLength bytes
|
||||
@ -415,12 +420,12 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
|
||||
//Check transfer status
|
||||
usb_transfer_t *transfer = &dequeued_enum_urb->transfer;
|
||||
if (transfer->status != USB_TRANSFER_STATUS_COMPLETED) {
|
||||
ESP_LOGE(HUB_DRIVER_TAG, "Bad transfer status: %s", enum_stage_strings[enum_ctrl->stage]);
|
||||
ESP_LOGE(HUB_DRIVER_TAG, "Bad transfer status %d: %s", transfer->status, enum_stage_strings[enum_ctrl->stage]);
|
||||
return false;
|
||||
}
|
||||
//Check IN transfer returned the expected correct number of bytes
|
||||
if (enum_ctrl->expect_num_bytes != 0 && enum_ctrl->expect_num_bytes != transfer->actual_num_bytes) {
|
||||
ESP_LOGE(HUB_DRIVER_TAG, "Incorrect number of bytes returned: %s", enum_stage_strings[enum_ctrl->stage]);
|
||||
ESP_LOGE(HUB_DRIVER_TAG, "Incorrect number of bytes returned %d: %s", transfer->actual_num_bytes, enum_stage_strings[enum_ctrl->stage]);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user