diff options
Diffstat (limited to 'src/host/usbh.c')
| -rw-r--r-- | src/host/usbh.c | 341 |
1 files changed, 228 insertions, 113 deletions
diff --git a/src/host/usbh.c b/src/host/usbh.c index f022d93f1..778015327 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -44,25 +44,33 @@ #define CFG_TUH_INTERFACE_MAX 8 #endif +enum { + USBH_CONTROL_RETRY_MAX = 3, +}; + //--------------------------------------------------------------------+ // Weak stubs: invoked if no strong implementation is available //--------------------------------------------------------------------+ TU_ATTR_WEAK bool hcd_deinit(uint8_t rhport) { - (void) rhport; - return false; + (void) rhport; return false; } TU_ATTR_WEAK bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { - (void) rhport; - (void) cfg_id; - (void) cfg_param; + (void) rhport; (void) cfg_id; (void) cfg_param; return false; } +TU_ATTR_WEAK void tuh_enum_descriptor_device_cb(uint8_t daddr, const tusb_desc_device_t *desc_device) { + (void) daddr; (void) desc_device; +} + +TU_ATTR_WEAK bool tuh_enum_descriptor_configuration_cb(uint8_t daddr, uint8_t cfg_index, const tusb_desc_configuration_t *desc_config) { + (void) daddr; (void) cfg_index; (void) desc_config; + return true; +} + TU_ATTR_WEAK void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) { - (void) rhport; - (void) eventid; - (void) in_isr; + (void) rhport; (void) eventid; (void) in_isr; } TU_ATTR_WEAK bool hcd_dcache_clean(const void* addr, uint32_t data_size) { @@ -122,6 +130,7 @@ typedef struct { uint8_t i_manufacturer; uint8_t i_product; uint8_t i_serial; + uint8_t bNumConfigurations; // Configuration Descriptor // uint8_t interface_count; // bNumInterfaces alias @@ -188,6 +197,18 @@ static usbh_class_driver_t const usbh_class_drivers[] = { }, #endif + #if CFG_TUH_MIDI + { + .name = DRIVER_NAME("MIDI"), + .init = midih_init, + .deinit = midih_deinit, + .open = midih_open, + .set_config = midih_set_config, + .xfer_cb = midih_xfer_cb, + .close = midih_close + }, + #endif + #if CFG_TUH_HUB { .name = DRIVER_NAME("HUB"), @@ -214,7 +235,6 @@ static usbh_class_driver_t const usbh_class_drivers[] = { }; enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) }; -enum { CONFIG_NUM = 1 }; // default to use configuration 1 // Additional class drivers implemented by application tu_static usbh_class_driver_t const * _app_driver = NULL; @@ -272,9 +292,10 @@ static struct { tuh_xfer_cb_t complete_cb; uintptr_t user_data; - uint8_t daddr; volatile uint8_t stage; + uint8_t daddr; volatile uint16_t actual_len; + uint8_t failed_count; } _ctrl_xfer; typedef struct { @@ -285,7 +306,6 @@ typedef struct { CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf; //------------- Helper Function -------------// - TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) { TU_VERIFY(dev_addr > 0 && dev_addr <= TOTAL_DEVICES, NULL); return &_usbh_devices[dev_addr-1]; @@ -312,6 +332,15 @@ bool tuh_mounted(uint8_t dev_addr) { return dev->configured; } +bool tuh_connected(uint8_t daddr) { + if (daddr == 0) { + return _dev0.enumerating; // dev0 is connected if still enumerating + } else { + const usbh_device_t* dev = get_device(daddr); + return dev && dev->connected; + } +} + bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid) { *vid = *pid = 0; @@ -438,7 +467,9 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { } bool tuh_deinit(uint8_t rhport) { - if (!tuh_rhport_is_active(rhport)) return true; + if (!tuh_rhport_is_active(rhport)) { + return true; + } // deinit host controller hcd_int_disable(rhport); @@ -484,13 +515,11 @@ bool tuh_task_event_ready(void) { * This should be called periodically within the mainloop or rtos thread. * @code - int main(void) - { + int main(void) { application_init(); tusb_init(0, TUSB_ROLE_HOST); - while(1) // the mainloop - { + while(1) { // the mainloop application_code(); tuh_task(); // tinyusb host task } @@ -501,12 +530,14 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { (void) in_isr; // not implemented yet // Skip if stack is not initialized - if (!tuh_inited()) return; + if (!tuh_inited()) { + return; + } // Loop until there is no more events in the queue while (1) { hcd_event_t event; - if (!osal_queue_receive(_usbh_q, &event, timeout_ms)) return; + if (!osal_queue_receive(_usbh_q, &event, timeout_ms)) { return; } switch (event.event_id) { case HCD_EVENT_DEVICE_ATTACH: @@ -635,17 +666,9 @@ static void _control_blocking_complete_cb(tuh_xfer_t* xfer) { // TODO timeout_ms is not supported yet bool tuh_control_xfer (tuh_xfer_t* xfer) { - // EP0 with setup packet - TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); - - // Check if device is still connected (enumerating for dev0) + TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); // EP0 with setup packet const uint8_t daddr = xfer->daddr; - if (daddr == 0) { - TU_VERIFY(_dev0.enumerating); - } else { - const usbh_device_t* dev = get_device(daddr); - TU_VERIFY(dev && dev->connected); - } + TU_VERIFY(tuh_connected(daddr)); // Check if device is still connected (enumerating for dev0) // pre-check to help reducing mutex lock TU_VERIFY(_ctrl_xfer.stage == CONTROL_STAGE_IDLE); @@ -653,14 +676,15 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { bool const is_idle = (_ctrl_xfer.stage == CONTROL_STAGE_IDLE); if (is_idle) { - _ctrl_xfer.stage = CONTROL_STAGE_SETUP; - _ctrl_xfer.daddr = daddr; - _ctrl_xfer.actual_len = 0; + _ctrl_xfer.stage = CONTROL_STAGE_SETUP; + _ctrl_xfer.daddr = daddr; + _ctrl_xfer.actual_len = 0; + _ctrl_xfer.failed_count = 0; - _ctrl_xfer.buffer = xfer->buffer; - _ctrl_xfer.complete_cb = xfer->complete_cb; - _ctrl_xfer.user_data = xfer->user_data; - _usbh_epbuf.request = (*xfer->setup); + _ctrl_xfer.buffer = xfer->buffer; + _ctrl_xfer.complete_cb = xfer->complete_cb; + _ctrl_xfer.user_data = xfer->user_data; + _usbh_epbuf.request = (*xfer->setup); } (void) osal_mutex_unlock(_usbh_mutex); @@ -674,7 +698,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { TU_LOG_BUF_USBH(xfer->setup, 8); if (xfer->complete_cb) { - TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t const*) &_usbh_epbuf.request) ); + TU_ASSERT(hcd_setup_send(rhport, daddr, (uint8_t const *) &_usbh_epbuf.request)); }else { // blocking if complete callback is not provided // change callback to internal blocking, and result as user argument @@ -684,7 +708,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) { _ctrl_xfer.user_data = (uintptr_t) &result; _ctrl_xfer.complete_cb = _control_blocking_complete_cb; - TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_usbh_epbuf.request) ); + TU_ASSERT(hcd_setup_send(rhport, daddr, (uint8_t *) &_usbh_epbuf.request)); while (result == XFER_RESULT_INVALID) { // Note: this can be called within an callback ie. part of tuh_task() @@ -741,28 +765,46 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t const uint8_t rhport = usbh_get_rhport(daddr); tusb_control_request_t const * request = &_usbh_epbuf.request; - if (XFER_RESULT_SUCCESS != result) { - TU_LOG_USBH("[%u:%u] Control %s, xferred_bytes = %" PRIu32 "\r\n", rhport, daddr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED", xferred_bytes); - TU_LOG_BUF_USBH(request, 8); + switch (result) { + case XFER_RESULT_STALLED: + TU_LOG_USBH("[%u:%u] Control STALLED, xferred_bytes = %" PRIu32 "\r\n", rhport, daddr, xferred_bytes); + TU_LOG_BUF_USBH(request, 8); + _control_xfer_complete(daddr, result); + break; + + case XFER_RESULT_FAILED: + if (tuh_connected(daddr) && _ctrl_xfer.failed_count < USBH_CONTROL_RETRY_MAX) { + TU_LOG_USBH("[%u:%u] Control FAILED %u/%u, retrying\r\n", rhport, daddr, _ctrl_xfer.failed_count+1, USBH_CONTROL_RETRY_MAX); + (void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER); + _ctrl_xfer.stage = CONTROL_STAGE_SETUP; + _ctrl_xfer.failed_count++; + _ctrl_xfer.actual_len = 0; // reset actual_len + (void) osal_mutex_unlock(_usbh_mutex); - // terminate transfer if any stage failed - _control_xfer_complete(daddr, result); - }else { - switch(_ctrl_xfer.stage) { - case CONTROL_STAGE_SETUP: - if (request->wLength) { - // DATA stage: initial data toggle is always 1 - _set_control_xfer_stage(CONTROL_STAGE_DATA); - TU_ASSERT( hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength) ); - return true; - } + TU_ASSERT(hcd_setup_send(rhport, daddr, (uint8_t const *) request)); + } else { + TU_LOG_USBH("[%u:%u] Control FAILED, xferred_bytes = %" PRIu32 "\r\n", rhport, daddr, xferred_bytes); + TU_LOG_BUF_USBH(request, 8); + _control_xfer_complete(daddr, result); + } + break; + + case XFER_RESULT_SUCCESS: + switch(_ctrl_xfer.stage) { + case CONTROL_STAGE_SETUP: + if (request->wLength) { + // DATA stage: initial data toggle is always 1 + _set_control_xfer_stage(CONTROL_STAGE_DATA); + TU_ASSERT( hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength) ); + return true; + } TU_ATTR_FALLTHROUGH; - case CONTROL_STAGE_DATA: - if (request->wLength) { - TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, daddr); - TU_LOG_MEM_USBH(_ctrl_xfer.buffer, xferred_bytes, 2); - } + case CONTROL_STAGE_DATA: + if (request->wLength) { + TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, daddr); + TU_LOG_MEM_USBH(_ctrl_xfer.buffer, xferred_bytes, 2); + } _ctrl_xfer.actual_len = (uint16_t) xferred_bytes; @@ -771,23 +813,26 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t TU_ASSERT( hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, 1 - request->bmRequestType_bit.direction), NULL, 0) ); break; - case CONTROL_STAGE_ACK: { - // Abort all pending transfers if SET_CONFIGURATION request - // NOTE: should we force closing all non-control endpoints in the future? - if (request->bRequest == TUSB_REQ_SET_CONFIGURATION && request->bmRequestType == 0x00) { - for(uint8_t epnum=1; epnum<CFG_TUH_ENDPOINT_MAX; epnum++) { - for(uint8_t dir=0; dir<2; dir++) { - tuh_edpt_abort_xfer(daddr, tu_edpt_addr(epnum, dir)); + case CONTROL_STAGE_ACK: { + // Abort all pending transfers if SET_CONFIGURATION request + // NOTE: should we force closing all non-control endpoints in the future? + if (request->bRequest == TUSB_REQ_SET_CONFIGURATION && request->bmRequestType == 0x00) { + for(uint8_t epnum=1; epnum<CFG_TUH_ENDPOINT_MAX; epnum++) { + for(uint8_t dir=0; dir<2; dir++) { + tuh_edpt_abort_xfer(daddr, tu_edpt_addr(epnum, dir)); + } } } + + _control_xfer_complete(daddr, result); + break; } - _control_xfer_complete(daddr, result); - break; + default: return false; // unsupported stage } + break; - default: return false; - } + default: return false; // unsupported result } return true; @@ -908,7 +953,6 @@ bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr) { } // Submit an transfer -// TODO call usbh_edpt_release if failed bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { (void) complete_cb; @@ -963,10 +1007,16 @@ static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size) { } bool tuh_edpt_open(uint8_t dev_addr, tusb_desc_endpoint_t const* desc_ep) { - TU_ASSERT(tu_edpt_validate(desc_ep, tuh_speed_get(dev_addr))); + TU_ASSERT(tu_edpt_validate(desc_ep, tuh_speed_get(dev_addr), true)); return hcd_edpt_open(usbh_get_rhport(dev_addr), dev_addr, desc_ep); } +bool tuh_edpt_close(uint8_t daddr, uint8_t ep_addr) { + TU_VERIFY(0 != tu_edpt_number(ep_addr)); // cannot close EP0 + tuh_edpt_abort_xfer(daddr, ep_addr); // abort any pending transfer + return hcd_edpt_close(usbh_get_rhport(daddr), daddr, ep_addr); +} + bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr) { usbh_device_t* dev = get_device(dev_addr); TU_VERIFY(dev); @@ -1271,13 +1321,17 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu removing_hubs |= TU_BIT(dev_id - CFG_TUH_DEVICE_MAX); } else { // Invoke callback before closing driver (maybe call it later ?) - if (tuh_umount_cb) tuh_umount_cb(daddr); + if (tuh_umount_cb) { + tuh_umount_cb(daddr); + } } // Close class driver for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) { usbh_class_driver_t const* driver = get_driver(drv_id); - if (driver) driver->close(daddr); + if (driver) { + driver->close(daddr); + } } hcd_device_close(rhport, daddr); @@ -1334,39 +1388,42 @@ enum { ENUM_HUB_GET_STATUS_2, ENUM_HUB_CLEAR_RESET_2, ENUM_SET_ADDR, - ENUM_GET_DEVICE_DESC, + ENUM_GET_STRING_LANGUAGE_ID, + ENUM_GET_STRING_MANUFACTURER, + ENUM_GET_STRING_PRODUCT, + ENUM_GET_STRING_SERIAL, ENUM_GET_9BYTE_CONFIG_DESC, ENUM_GET_FULL_CONFIG_DESC, ENUM_SET_CONFIG, ENUM_CONFIG_DRIVER }; -static bool enum_request_set_addr(void); -static bool _parse_configuration_descriptor (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg); +static bool enum_request_set_addr(tusb_desc_device_t const* desc_device); +static bool enum_parse_configuration_desc (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg); static void enum_full_complete(void); // process device enumeration static void process_enumeration(tuh_xfer_t* xfer) { - // Retry a few times with transfers in enumeration since device can be unstable when starting up - enum { - ATTEMPT_COUNT_MAX = 3, - ATTEMPT_DELAY_MS = 100 - }; + // Retry a few times while enumerating since device can be unstable when starting up static uint8_t failed_count = 0; + if (XFER_RESULT_FAILED == xfer->result) { + enum { + ATTEMPT_COUNT_MAX = 3, + ATTEMPT_DELAY_MS = 100 + }; - if (XFER_RESULT_SUCCESS != xfer->result) { // retry if not reaching max attempt + failed_count++; bool retry = _dev0.enumerating && (failed_count < ATTEMPT_COUNT_MAX); - if ( retry ) { - failed_count++; + if (retry) { tusb_time_delay_ms_api(ATTEMPT_DELAY_MS); // delay a bit - TU_LOG1("Enumeration attempt %u\r\n", failed_count); + TU_LOG1("Enumeration attempt %u/%u\r\n", failed_count+1, ATTEMPT_COUNT_MAX); retry = tuh_control_xfer(xfer); } if (!retry) { - enum_full_complete(); + enum_full_complete(); // complete as failed } return; @@ -1375,6 +1432,8 @@ static void process_enumeration(tuh_xfer_t* xfer) { uint8_t const daddr = xfer->daddr; uintptr_t const state = xfer->user_data; + usbh_device_t* dev = get_device(daddr); + uint16_t langid = 0x0409; // default is English switch (state) { #if CFG_TUH_HUB @@ -1457,7 +1516,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { #endif case ENUM_SET_ADDR: - enum_request_set_addr(); + enum_request_set_addr((tusb_desc_device_t*) _usbh_epbuf.ctrl); break; case ENUM_GET_DEVICE_DESC: { @@ -1465,7 +1524,6 @@ static void process_enumeration(tuh_xfer_t* xfer) { tusb_time_delay_ms_api(2); const uint8_t new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue); - usbh_device_t* new_dev = get_device(new_addr); TU_ASSERT(new_dev,); new_dev->addressed = 1; @@ -1479,24 +1537,75 @@ static void process_enumeration(tuh_xfer_t* xfer) { // Get full device descriptor TU_LOG_USBH("Get Device Descriptor\r\n"); TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t), - process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC),); + process_enumeration, ENUM_GET_STRING_LANGUAGE_ID),); break; } - case ENUM_GET_9BYTE_CONFIG_DESC: { - tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl; - usbh_device_t* dev = get_device(daddr); + case ENUM_GET_STRING_LANGUAGE_ID: { + // save the received device descriptor TU_ASSERT(dev,); - + tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl; dev->vid = desc_device->idVendor; dev->pid = desc_device->idProduct; dev->i_manufacturer = desc_device->iManufacturer; dev->i_product = desc_device->iProduct; dev->i_serial = desc_device->iSerialNumber; + dev->bNumConfigurations = desc_device->bNumConfigurations; + + tuh_enum_descriptor_device_cb(daddr, desc_device); // callback + + tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, + process_enumeration, ENUM_GET_STRING_MANUFACTURER); + break; + } + + case ENUM_GET_STRING_MANUFACTURER: { + TU_ASSERT(dev,); + const tusb_desc_string_t* desc_langid = (tusb_desc_string_t const*) _usbh_epbuf.ctrl; + if (desc_langid->bLength >= 4) { + langid = tu_le16toh(desc_langid->utf16le[0]); + } + if (dev->i_manufacturer != 0) { + tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, + process_enumeration, ENUM_GET_STRING_PRODUCT); + break; + } else { + TU_ATTR_FALLTHROUGH; + } + } + + case ENUM_GET_STRING_PRODUCT: { + TU_ASSERT(dev,); + if (state == ENUM_GET_STRING_PRODUCT) { + langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet + } + if (dev->i_product != 0) { + tuh_descriptor_get_string(daddr, dev->i_product, 0x0409, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, + process_enumeration, ENUM_GET_STRING_SERIAL); + break; + } else { + TU_ATTR_FALLTHROUGH; + } + } + + case ENUM_GET_STRING_SERIAL: { + TU_ASSERT(dev,); + if (state == ENUM_GET_STRING_SERIAL) { + langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet + } + if (dev->i_serial != 0) { + tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, + process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC); + break; + } else { + TU_ATTR_FALLTHROUGH; + } + } + case ENUM_GET_9BYTE_CONFIG_DESC: { // Get 9-byte for total length - uint8_t const config_idx = CONFIG_NUM - 1; - TU_LOG_USBH("Get Configuration[0] Descriptor (9 bytes)\r\n"); + uint8_t const config_idx = 0; + TU_LOG_USBH("Get Configuration[%u] Descriptor (9 bytes)\r\n", config_idx); TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9, process_enumeration, ENUM_GET_FULL_CONFIG_DESC),); break; @@ -1506,34 +1615,42 @@ static void process_enumeration(tuh_xfer_t* xfer) { uint8_t const* desc_config = _usbh_epbuf.ctrl; // Use offsetof to avoid pointer to the odd/misaligned address - uint16_t const total_len = tu_le16toh( - tu_unaligned_read16(desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))); + uint16_t const total_len = tu_le16toh(tu_unaligned_read16(desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))); // TODO not enough buffer to hold configuration descriptor TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE,); // Get full configuration descriptor - uint8_t const config_idx = CONFIG_NUM - 1; - TU_LOG_USBH("Get Configuration[0] Descriptor\r\n"); + uint8_t const config_idx = (uint8_t) tu_le16toh(xfer->setup->wIndex); + TU_LOG_USBH("Get Configuration[%u] Descriptor\r\n", config_idx); TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, total_len, process_enumeration, ENUM_SET_CONFIG),); break; } - case ENUM_SET_CONFIG: - TU_ASSERT(tuh_configuration_set(daddr, CONFIG_NUM, process_enumeration, ENUM_CONFIG_DRIVER),); + case ENUM_SET_CONFIG: { + uint8_t config_idx = (uint8_t) tu_le16toh(xfer->setup->wIndex); + if (tuh_enum_descriptor_configuration_cb(daddr, config_idx, (const tusb_desc_configuration_t*) _usbh_epbuf.ctrl)) { + TU_ASSERT(tuh_configuration_set(daddr, config_idx+1, process_enumeration, ENUM_CONFIG_DRIVER),); + } else { + config_idx++; + TU_ASSERT(config_idx < dev->bNumConfigurations,); + TU_LOG_USBH("Get Configuration[%u] Descriptor (9 bytes)\r\n", config_idx); + TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9, + process_enumeration, ENUM_GET_FULL_CONFIG_DESC),); + } break; + } case ENUM_CONFIG_DRIVER: { TU_LOG_USBH("Device configured\r\n"); - usbh_device_t* dev = get_device(daddr); TU_ASSERT(dev,); dev->configured = 1; // Parse configuration & set up drivers // driver_open() must not make any usb transfer - TU_ASSERT(_parse_configuration_descriptor(daddr, (tusb_desc_configuration_t*) _usbh_epbuf.ctrl),); + TU_ASSERT(enum_parse_configuration_desc(daddr, (tusb_desc_configuration_t*) _usbh_epbuf.ctrl),); // Start the Set Configuration process for interfaces (itf = TUSB_INDEX_INVALID_8) // Since driver can perform control transfer within its set_config, this is done asynchronously. @@ -1544,14 +1661,11 @@ static void process_enumeration(tuh_xfer_t* xfer) { } default: - // stop enumeration if unknown state - enum_full_complete(); + enum_full_complete(); // stop enumeration if unknown state break; } } - - static bool enum_new_device(hcd_event_t* event) { _dev0.rhport = event->rhport; _dev0.hub_addr = event->connection.hub_addr; @@ -1621,9 +1735,7 @@ static uint8_t get_new_address(bool is_hub) { return 0; // invalid address } -static bool enum_request_set_addr(void) { - tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl; - +static bool enum_request_set_addr(tusb_desc_device_t const* desc_device) { // Get new address uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB); TU_ASSERT(new_addr != 0); @@ -1661,7 +1773,7 @@ static bool enum_request_set_addr(void) { return true; } -static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg) { +static bool enum_parse_configuration_desc(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg) { usbh_device_t* dev = get_device(dev_addr); uint16_t const total_len = tu_le16toh(desc_cfg->wTotalLength); uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + total_len; @@ -1674,7 +1786,7 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur if ( 0 == tu_desc_len(p_desc) ) { // A zero length descriptor indicates that the device is off spec (e.g. wrong wTotalLength). // Parsed interfaces should still be usable - TU_LOG_USBH("Encountered a zero-length descriptor after %u bytes\r\n", (uint32_t)p_desc - (uint32_t)desc_cfg); + TU_LOG_USBH("Encountered a zero-length descriptor after %" PRIu32 " bytes\r\n", (uint32_t)p_desc - (uint32_t)desc_cfg); break; } @@ -1778,7 +1890,9 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) { TU_LOG_USBH("HUB address = %u is mounted\r\n", dev_addr); }else { // Invoke callback if available - if (tuh_mount_cb) tuh_mount_cb(dev_addr); + if (tuh_mount_cb) { + tuh_mount_cb(dev_addr); + } } } } @@ -1788,8 +1902,9 @@ static void enum_full_complete(void) { _dev0.enumerating = 0; #if CFG_TUH_HUB - // get next hub status - if (_dev0.hub_addr) hub_edpt_status_xfer(_dev0.hub_addr); + if (_dev0.hub_addr) { + hub_edpt_status_xfer(_dev0.hub_addr); // get next hub status + } #endif } |
