Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 55 additions & 30 deletions src/host/usbh.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@
// Function Inline and Prototypes
//--------------------------------------------------------------------+
static bool enum_new_device(hcd_event_t* event);
static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
static void process_remove_event(hcd_event_t *event);
static void remove_device_tree(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);

Expand All @@ -320,7 +321,7 @@
TU_VERIFY(dev_addr > 0 && dev_addr <= TOTAL_DEVICES, NULL);
return &_usbh_devices[dev_addr-1];
}

Check notice

Code scanning / CodeQL

Unused static function Note

Static function is_hub_addr is unreachable (
remove_device_tree
must be removed at the same time)
Static function is_hub_addr is unreachable
TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) {
return (CFG_TUH_HUB > 0) && (daddr > CFG_TUH_DEVICE_MAX); //-V560
}
Expand Down Expand Up @@ -540,8 +541,8 @@
hcd_deinit(rhport);
_usbh_data.controller_id = TUSB_INDEX_INVALID_8;

// "unplug" all devices on this rhport (hub_addr = 0, hub_port = 0)
process_removed_device(rhport, 0, 0);
// remove all devices on this rhport (hub_addr = 0, hub_port = 0)
remove_device_tree(rhport, 0, 0);

// deinit host stack if no controller is active
if (!tuh_inited()) {
Expand Down Expand Up @@ -605,6 +606,11 @@

switch (event.event_id) {
case HCD_EVENT_DEVICE_ATTACH:
// Should we miss the hub detach event due to high traffic, Or due to physical debouncing, some devices can
// cause multiple attaches (actually reset) without detach event.
// Force remove currently mounted with the same bus info (rhport, hub addr, hub port) if exists
process_remove_event(&event);

// due to the shared control buffer, we must fully complete enumerating one device first.
// TODO better to have an separated queue for newly attached devices
if (_usbh_data.enumerating_daddr == TUSB_INDEX_INVALID_8) {
Expand All @@ -625,15 +631,7 @@

case HCD_EVENT_DEVICE_REMOVE:
TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
if (_usbh_data.enumerating_daddr == 0 &&
event.rhport == _usbh_data.dev0_bus.rhport &&
event.connection.hub_addr == _usbh_data.dev0_bus.hub_addr &&
event.connection.hub_port == _usbh_data.dev0_bus.hub_port) {
// dev0 is unplugged while enumerating (not yet assigned an address)
usbh_device_close(_usbh_data.dev0_bus.rhport, 0);
} else {
process_removed_device(event.rhport, event.connection.hub_addr, event.connection.hub_port);
}
process_remove_event(&event);
break;

case HCD_EVENT_XFER_COMPLETE: {
Expand Down Expand Up @@ -1321,8 +1319,22 @@
//--------------------------------------------------------------------+
// Detaching
//--------------------------------------------------------------------+
// a device unplugged from rhport:hub_addr:hub_port
static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) {

// process detach event from rhport:hub_addr:hub_port
static void process_remove_event(hcd_event_t *event) {
if (_usbh_data.enumerating_daddr == 0 &&
event->rhport == _usbh_data.dev0_bus.rhport &&
event->connection.hub_addr == _usbh_data.dev0_bus.hub_addr &&
event->connection.hub_port == _usbh_data.dev0_bus.hub_port) {
// dev0 is unplugged while enumerating (not yet assigned an address)
usbh_device_close(_usbh_data.dev0_bus.rhport, 0);
} else {
remove_device_tree(event->rhport, event->connection.hub_addr, event->connection.hub_port);
}
}

// remove a device at rhport:hub_addr:hub_port and all of its downstream
static void remove_device_tree(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) {
// Find the all devices (star-network) under port that is unplugged
#if CFG_TUH_HUB
uint8_t removing_hubs[CFG_TUH_HUB] = { 0 };
Expand Down Expand Up @@ -1427,7 +1439,7 @@

static uint8_t enum_get_new_address(bool is_hub);
static bool enum_parse_configuration_desc (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
static void enum_full_complete(void);
static void enum_full_complete(bool success);
static void process_enumeration(tuh_xfer_t* xfer);

// start a new enumeration process
Expand All @@ -1449,7 +1461,7 @@

if (!hcd_port_connect_status(dev0_bus->rhport)) {
TU_LOG_USBH("Device unplugged while debouncing\r\n");
enum_full_complete();
enum_full_complete(false);
return true;
}

Expand All @@ -1460,7 +1472,7 @@

if (!hcd_port_connect_status(dev0_bus->rhport)) {
// device unplugged while delaying
enum_full_complete();
enum_full_complete(false);
return true;
}

Expand Down Expand Up @@ -1506,7 +1518,7 @@
}

if (!retry) {
enum_full_complete(); // complete as failed
enum_full_complete(false); // complete as failed
}
return;
}
Expand All @@ -1529,7 +1541,7 @@

if (0 == port_status.status.connection) {
TU_LOG_USBH("Device unplugged from hub while debouncing\r\n");
enum_full_complete();
enum_full_complete(false);
return;
}

Expand Down Expand Up @@ -1566,7 +1578,7 @@

if (0 == port_status.status.connection) {
TU_LOG_USBH("Device unplugged from hub (not addressed yet)\r\n");
enum_full_complete();
enum_full_complete(false);
return;
}

Expand All @@ -1582,7 +1594,11 @@

// TODO probably doesn't need to open/close each enumeration
uint8_t const addr0 = 0;
TU_ASSERT(usbh_edpt_control_open(addr0, 8),);
if (!usbh_edpt_control_open(addr0, 8)) {
// Stop enumeration gracefully
enum_full_complete(false);
TU_ASSERT(false,);
}

// Get first 8 bytes of device descriptor for control endpoint size
TU_LOG_USBH("Get 8 byte of Device Descriptor\r\n");
Expand All @@ -1592,10 +1608,6 @@
}

case ENUM_SET_ADDR: {
// Due to physical debouncing, some devices can cause multiple attaches (actually reset) without detach event
// Force remove currently mounted with the same bus info (rhport, hub addr, hub port) if exists
process_removed_device(dev0_bus->rhport, dev0_bus->hub_addr, dev0_bus->hub_port);

const tusb_desc_device_t *desc_device = (const tusb_desc_device_t *) _usbh_epbuf.ctrl;
const uint8_t new_addr = enum_get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
TU_ASSERT(new_addr != 0,);
Expand All @@ -1620,7 +1632,12 @@

usbh_device_close(dev0_bus->rhport, 0); // close dev0

TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->bMaxPacketSize0),); // open new control endpoint
if (!usbh_edpt_control_open(new_addr, new_dev->bMaxPacketSize0)) { // open new control endpoint
// Stop enumeration gracefully
clear_device(new_dev);
enum_full_complete(false);
TU_ASSERT(false,);
}

TU_LOG_USBH("Get Device Descriptor\r\n");
TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t),
Expand Down Expand Up @@ -1774,6 +1791,12 @@
TU_LOG_USBH("Device configured\r\n");
dev->configured = 1;

#if CFG_TUH_HUB
if (_usbh_data.dev0_bus.hub_addr != 0) {
hub_edpt_status_xfer(_usbh_data.dev0_bus.hub_addr); // get next hub status
}
#endif

// Parse configuration & set up drivers
// driver_open() must not make any usb transfer
TU_ASSERT(enum_parse_configuration_desc(daddr, (tusb_desc_configuration_t*) _usbh_epbuf.ctrl),);
Expand All @@ -1787,7 +1810,7 @@
}

default:
enum_full_complete(); // stop enumeration if unknown state
enum_full_complete(false); // stop enumeration if unknown state
break;
}
}
Expand Down Expand Up @@ -1890,7 +1913,7 @@

// all interface are configured
if (itf_num == CFG_TUH_INTERFACE_MAX) {
enum_full_complete();
enum_full_complete(true);

if (is_hub_addr(dev_addr)) {
TU_LOG_USBH("HUB address = %u is mounted\r\n", dev_addr);
Expand All @@ -1901,12 +1924,14 @@
}
}

static void enum_full_complete(void) {
static void enum_full_complete(bool success) {
(void)success;
// mark enumeration as complete
_usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8;

#if CFG_TUH_HUB
if (_usbh_data.dev0_bus.hub_addr != 0) {
// Hub status is already requested in case of successful enumeration
if (_usbh_data.dev0_bus.hub_addr != 0 && !success) {
hub_edpt_status_xfer(_usbh_data.dev0_bus.hub_addr); // get next hub status
}
#endif
Expand Down