summaryrefslogtreecommitdiff
path: root/src/host/usbh.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/host/usbh.c')
-rw-r--r--src/host/usbh.c161
1 files changed, 76 insertions, 85 deletions
diff --git a/src/host/usbh.c b/src/host/usbh.c
index de53bfd03..94d075813 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -1,25 +1,6 @@
/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
+ * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org)
+ * SPDX-License-Identifier: MIT
*
* This file is part of the TinyUSB stack.
*/
@@ -325,26 +306,14 @@ static usbh_class_driver_t const usbh_class_drivers[] = {
},
#endif
- #if CFG_TUH_VENDOR
- {
- .name = DRIVER_NAME("VENDOR"),
- .init = cush_init,
- .deinit = cush_deinit,
- .open = cush_open,
- .set_config = cush_set_config,
- .xfer_cb = cush_isr,
- .close = cush_close
- }
- #endif
};
-enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) };
-
// Additional class drivers implemented by application
static usbh_class_driver_t const * _app_driver = NULL;
-static uint8_t _app_driver_count = 0;
+static const uint8_t _builtin_driver_count = TU_ARRAY_SIZE(usbh_class_drivers);
+static uint8_t _app_driver_count = 0;
-#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT)
+#define TOTAL_DRIVER_COUNT (_app_driver_count + _builtin_driver_count)
// virtually joins built-in and application drivers together.
// Application is positioned first to allow overwriting built-in ones.
@@ -354,7 +323,7 @@ TU_ATTR_ALWAYS_INLINE static inline usbh_class_driver_t const *get_driver(uint8_
driver = &_app_driver[drv_id];
} else {
drv_id -= _app_driver_count;
- if (drv_id < BUILTIN_DRIVER_COUNT) {
+ if (_builtin_driver_count > 0 && drv_id < _builtin_driver_count) {
driver = &usbh_class_drivers[drv_id];
}
}
@@ -417,12 +386,6 @@ TU_ATTR_ALWAYS_INLINE static inline void usbh_device_close(uint8_t rhport, uint8
_usbh_data.daddr_gen[daddr]++;
(void) osal_mutex_unlock(_usbh_mutex);
- // If this device has in-flight control xfer, complete as FAILED
- usbh_ctrl_xfer_info_t* ctrl_info = &_usbh_data.ctrl_xfer_info;
- if (daddr == ctrl_info->daddr && ctrl_info->stage != CONTROL_STAGE_IDLE) {
- control_xfer_complete(daddr, XFER_RESULT_FAILED);
- }
-
// invalidate if enumerating
if (daddr == _usbh_data.enumerating_daddr) {
_usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8;
@@ -431,6 +394,12 @@ TU_ATTR_ALWAYS_INLINE static inline void usbh_device_close(uint8_t rhport, uint8
_usbh_data.call_after.func = NULL;
}
}
+
+ // If this device has in-flight control xfer, complete as FAILED
+ usbh_ctrl_xfer_info_t* ctrl_info = &_usbh_data.ctrl_xfer_info;
+ if (daddr == ctrl_info->daddr && ctrl_info->stage != CONTROL_STAGE_IDLE) {
+ control_xfer_complete(daddr, XFER_RESULT_FAILED);
+ }
}
//--------------------------------------------------------------------+
@@ -566,6 +535,7 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
// Get application driver if available
_app_driver = usbh_app_driver_get_cb(&_app_driver_count);
+ TU_ASSERT(_app_driver_count + _builtin_driver_count <= UINT8_MAX);
// Device
tu_memclr(_usbh_devices, sizeof(_usbh_devices));
@@ -1130,7 +1100,10 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t
// DATA stage: initial data toggle is always 1
control_xfer_set_stage(CONTROL_STAGE_DATA);
const uint8_t ep_data = tu_edpt_addr(0, request->bmRequestType_bit.direction);
- TU_ASSERT(hcd_edpt_xfer(rhport, daddr, ep_data, ctrl_info->buffer, request->wLength));
+ if (!hcd_edpt_xfer(rhport, daddr, ep_data, ctrl_info->buffer, request->wLength)) {
+ control_xfer_complete(daddr, XFER_RESULT_FAILED);
+ return false;
+ }
return true;
}
TU_ATTR_FALLTHROUGH;
@@ -1145,7 +1118,10 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t
// ACK stage: toggle is always 1
control_xfer_set_stage(CONTROL_STAGE_ACK);
const uint8_t ep_status = tu_edpt_addr(0, 1 - request->bmRequestType_bit.direction);
- TU_ASSERT(hcd_edpt_xfer(rhport, daddr, ep_status, NULL, 0));
+ if (!hcd_edpt_xfer(rhport, daddr, ep_status, NULL, 0)) {
+ control_xfer_complete(daddr, XFER_RESULT_FAILED);
+ return false;
+ }
break;
}
@@ -1747,8 +1723,10 @@ static void enum_delay_async(uintptr_t state) {
if (dev0_bus->hub_addr != 0) {
// connected via hub
TU_VERIFY(dev0_bus->hub_port != 0, );
- TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration,
- ENUM_HUB_RERSET), );
+ if (!hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration,
+ ENUM_HUB_RERSET)) {
+ enum_full_complete(false);
+ }
} else
#endif
{
@@ -1791,9 +1769,11 @@ static void enum_delay_async(uintptr_t state) {
case ENUM_AFTER_RESET_HUB_DELAY:
case ENUM_AFTER_RESET_HUB_DELAY_RETRY:
// get status after reset complete to check for reset change
- TU_ASSERT(hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration,
- state == ENUM_AFTER_RESET_HUB_DELAY ? ENUM_HUB_CLEAR_RESET
- : ENUM_HUB_CLEAR_RESET_RETRY), );
+ if (!hub_port_get_status(dev0_bus->hub_addr, dev0_bus->hub_port, NULL, process_enumeration,
+ state == ENUM_AFTER_RESET_HUB_DELAY ? ENUM_HUB_CLEAR_RESET
+ : ENUM_HUB_CLEAR_RESET_RETRY)) {
+ enum_full_complete(false);
+ }
break;
#endif
@@ -1806,7 +1786,9 @@ static void enum_delay_async(uintptr_t state) {
}
// Get first 8 bytes of device descriptor for control endpoint size
TU_LOG_USBH("Get 8 byte of Device Descriptor\r\n");
- TU_ASSERT(tuh_descriptor_get_device(0, _usbh_epbuf.ctrl, 8, process_enumeration, ENUM_SET_ADDR), );
+ if (!tuh_descriptor_get_device(0, _usbh_epbuf.ctrl, 8, process_enumeration, ENUM_SET_ADDR)) {
+ enum_full_complete(false);
+ }
break;
case ENUM_AFTER_SET_ADDRESS_RECOVERY_DELAY: {
@@ -1815,13 +1797,14 @@ static void enum_delay_async(uintptr_t state) {
TU_ASSERT(new_dev, );
if (!usbh_edpt_control_open(new_addr, new_dev->desc_device.bMaxPacketSize0)) {
TU_LOG_USBH("Failed to open new device's control endpoint\r\n");
- clear_device(new_dev);
enum_full_complete(false);
return;
}
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_STRING_LANGUAGE_ID_LEN), );
+ if (!tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t), process_enumeration,
+ ENUM_GET_STRING_LANGUAGE_ID_LEN)) {
+ enum_full_complete(false);
+ }
break;
}
@@ -1866,8 +1849,8 @@ static void process_enumeration(tuh_xfer_t *xfer) {
TU_LOG_USBH("Device unplugged from hub while debouncing\r\n");
is_enum_failed = true;
} else {
- TU_ASSERT(hub_port_reset(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration,
- ENUM_HUB_RESET_COMPLETE), );
+ is_enum_failed = !hub_port_reset(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration,
+ ENUM_HUB_RESET_COMPLETE);
}
break;
}
@@ -1884,8 +1867,8 @@ static void process_enumeration(tuh_xfer_t *xfer) {
if (1 == port_status.change.reset) {
// Acknowledge Port Reset Change
- TU_ASSERT(hub_port_clear_reset_change(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration,
- ENUM_HUB_CLEAR_RESET_COMPLETE), );
+ is_enum_failed = !hub_port_clear_reset_change(dev0_bus->hub_addr, dev0_bus->hub_port, process_enumeration,
+ ENUM_HUB_CLEAR_RESET_COMPLETE);
} else if (state == ENUM_HUB_CLEAR_RESET) {
// retry one more time if reset change not set yet
usbh_defer_func_ms_async(ENUM_RESET_HUB_DELAY_MS, enum_delay_async, ENUM_AFTER_RESET_HUB_DELAY_RETRY);
@@ -1930,10 +1913,9 @@ static void process_enumeration(tuh_xfer_t *xfer) {
usbh_device_t* new_dev = get_device(new_addr);
new_dev->bus_info = *dev0_bus;
- new_dev->connected = 1;
new_dev->desc_device.bMaxPacketSize0 = desc_device->bMaxPacketSize0;
- TU_ASSERT(tuh_address_set(0, new_addr, process_enumeration, ENUM_GET_DEVICE_DESC), );
+ is_enum_failed = !tuh_address_set(0, new_addr, process_enumeration, ENUM_GET_DEVICE_DESC);
break;
}
@@ -1941,6 +1923,7 @@ static void process_enumeration(tuh_xfer_t *xfer) {
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->connected = 1;
new_dev->addressed = 1;
_usbh_data.enumerating_daddr = new_addr;
@@ -1958,15 +1941,15 @@ static void process_enumeration(tuh_xfer_t *xfer) {
memcpy(&dev->desc_device, (const uint8_t*) desc_device + offsetof(tusb_desc_device_t, bcdUSB), sizeof(desc_device_noheader_t));
tuh_enum_descriptor_device_cb(daddr, desc_device); // callback
- tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, 2,
- process_enumeration, ENUM_GET_STRING_LANGUAGE_ID);
+ is_enum_failed = !tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, 2,
+ process_enumeration, ENUM_GET_STRING_LANGUAGE_ID);
break;
}
case ENUM_GET_STRING_LANGUAGE_ID: {
const uint8_t str_len = xfer->buffer[0];
- tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, str_len,
- process_enumeration, ENUM_GET_STRING_MANUFACTURER_LEN);
+ is_enum_failed = !tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, str_len,
+ process_enumeration, ENUM_GET_STRING_MANUFACTURER_LEN);
break;
}
@@ -1976,8 +1959,8 @@ static void process_enumeration(tuh_xfer_t *xfer) {
langid = tu_le16toh(desc_langid->utf16le[0]); // previous request is langid
}
if (dev->desc_device.iManufacturer != 0) {
- tuh_descriptor_get_string(daddr, dev->desc_device.iManufacturer, langid, _usbh_epbuf.ctrl, 2,
- process_enumeration, ENUM_GET_STRING_MANUFACTURER);
+ is_enum_failed = !tuh_descriptor_get_string(daddr, dev->desc_device.iManufacturer, langid, _usbh_epbuf.ctrl, 2,
+ process_enumeration, ENUM_GET_STRING_MANUFACTURER);
break;
}
TU_ATTR_FALLTHROUGH;
@@ -1987,8 +1970,8 @@ static void process_enumeration(tuh_xfer_t *xfer) {
if (dev->desc_device.iManufacturer != 0) {
langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request
const uint8_t str_len = xfer->buffer[0];
- tuh_descriptor_get_string(daddr, dev->desc_device.iManufacturer, langid, _usbh_epbuf.ctrl, str_len,
- process_enumeration, ENUM_GET_STRING_PRODUCT_LEN);
+ is_enum_failed = !tuh_descriptor_get_string(daddr, dev->desc_device.iManufacturer, langid, _usbh_epbuf.ctrl,
+ str_len, process_enumeration, ENUM_GET_STRING_PRODUCT_LEN);
break;
}
TU_ATTR_FALLTHROUGH;
@@ -1999,8 +1982,8 @@ static void process_enumeration(tuh_xfer_t *xfer) {
if (state == ENUM_GET_STRING_PRODUCT_LEN) {
langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through
}
- tuh_descriptor_get_string(
- daddr, dev->desc_device.iProduct, langid, _usbh_epbuf.ctrl, 2, process_enumeration, ENUM_GET_STRING_PRODUCT);
+ is_enum_failed = !tuh_descriptor_get_string(daddr, dev->desc_device.iProduct, langid, _usbh_epbuf.ctrl, 2,
+ process_enumeration, ENUM_GET_STRING_PRODUCT);
break;
}
TU_ATTR_FALLTHROUGH;
@@ -2010,8 +1993,8 @@ static void process_enumeration(tuh_xfer_t *xfer) {
if (dev->desc_device.iProduct != 0) {
langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request
const uint8_t str_len = xfer->buffer[0];
- tuh_descriptor_get_string(daddr, dev->desc_device.iProduct, langid, _usbh_epbuf.ctrl, str_len,
- process_enumeration, ENUM_GET_STRING_SERIAL_LEN);
+ is_enum_failed = !tuh_descriptor_get_string(daddr, dev->desc_device.iProduct, langid, _usbh_epbuf.ctrl, str_len,
+ process_enumeration, ENUM_GET_STRING_SERIAL_LEN);
break;
}
TU_ATTR_FALLTHROUGH;
@@ -2022,8 +2005,8 @@ static void process_enumeration(tuh_xfer_t *xfer) {
if (state == ENUM_GET_STRING_SERIAL_LEN) {
langid = tu_le16toh(xfer->setup->wIndex); // get langid from previous setup packet if not fall through
}
- tuh_descriptor_get_string(
- daddr, dev->desc_device.iSerialNumber, langid, _usbh_epbuf.ctrl, 2, process_enumeration, ENUM_GET_STRING_SERIAL);
+ is_enum_failed = !tuh_descriptor_get_string(daddr, dev->desc_device.iSerialNumber, langid, _usbh_epbuf.ctrl, 2,
+ process_enumeration, ENUM_GET_STRING_SERIAL);
break;
}
TU_ATTR_FALLTHROUGH;
@@ -2033,8 +2016,8 @@ static void process_enumeration(tuh_xfer_t *xfer) {
if (dev->desc_device.iSerialNumber != 0) {
langid = tu_le16toh(xfer->setup->wIndex); // langid from length's request
const uint8_t str_len = xfer->buffer[0];
- tuh_descriptor_get_string(daddr, dev->desc_device.iSerialNumber, langid, _usbh_epbuf.ctrl, str_len,
- process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC);
+ is_enum_failed = !tuh_descriptor_get_string(daddr, dev->desc_device.iSerialNumber, langid, _usbh_epbuf.ctrl,
+ str_len, process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC);
break;
}
TU_ATTR_FALLTHROUGH;
@@ -2044,8 +2027,8 @@ static void process_enumeration(tuh_xfer_t *xfer) {
// Get 9-byte for total length
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),);
+ is_enum_failed = !tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9,
+ process_enumeration, ENUM_GET_FULL_CONFIG_DESC);
break;
}
@@ -2061,21 +2044,21 @@ static void process_enumeration(tuh_xfer_t *xfer) {
// Get full configuration descriptor
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),);
+ is_enum_failed = !tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, total_len,
+ process_enumeration, ENUM_SET_CONFIG);
break;
}
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+1u, process_enumeration, ENUM_CONFIG_DRIVER),);
+ is_enum_failed = !tuh_configuration_set(daddr, config_idx+1u, process_enumeration, ENUM_CONFIG_DRIVER);
} else {
config_idx++;
TU_ASSERT(config_idx < dev->desc_device.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),);
+ is_enum_failed = !tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9,
+ process_enumeration, ENUM_GET_FULL_CONFIG_DESC);
}
break;
}
@@ -2179,7 +2162,8 @@ static bool enum_parse_configuration_desc(uint8_t dev_addr, tusb_desc_configurat
TU_LOG_USBH(" %s opened\r\n", driver->name);
// bind found driver to all interfaces and endpoint within drv_len
- tu_bind_driver_to_ep_itf(drv_id, dev->ep2drv, dev->itf2drv, CFG_TUH_INTERFACE_MAX, p_desc, drv_len);
+ TU_ASSERT(tu_bind_driver_to_ep_itf(drv_id, dev->ep2drv, dev->itf2drv, CFG_TUH_INTERFACE_MAX,
+ CFG_TUH_ENDPOINT_MAX, p_desc, drv_len));
p_desc += drv_len; // next Interface
break; // exit driver find loop
@@ -2229,12 +2213,19 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) {
}
static void enum_full_complete(bool success) {
- (void)success;
TU_LOG_USBH("Enumeration complete: success = %u\r\n", success);
+ const uint8_t daddr = _usbh_data.enumerating_daddr;
_usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; // mark enumeration as complete
_usbh_data.call_after.func = NULL;
+ if (!success && daddr <= TOTAL_DEVICES) {
+ usbh_device_close(_usbh_data.dev0_bus.rhport, daddr);
+ if (daddr > 0) {
+ clear_device(get_device(daddr));
+ }
+ }
+
#if CFG_TUH_HUB
// Hub status is already requested in case of successful enumeration
if (!success && _usbh_data.dev0_bus.hub_addr != 0) {