Skip to content
Open
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
76 changes: 51 additions & 25 deletions src/host/usbh.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ TU_ATTR_ALWAYS_INLINE static inline usbh_class_driver_t const *get_driver(uint8_
// Function Inline and Prototypes
//--------------------------------------------------------------------+
static bool enum_new_device(hcd_event_t* event);
static void process_detach_event(hcd_event_t* event);
static void process_removed_device(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 Down Expand Up @@ -605,6 +606,11 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {

switch (event.event_id) {
case HCD_EVENT_DEVICE_ATTACH:
// We have likely missed the hub detach event due to high traffic, detach the device first if exists
// 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_detach_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 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {

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_detach_event(&event);
break;

case HCD_EVENT_XFER_COMPLETE: {
Expand Down Expand Up @@ -1314,6 +1312,20 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt,
//--------------------------------------------------------------------+
// Detaching
//--------------------------------------------------------------------+

// process detach event from rhport:hub_addr:hub_port
static void process_detach_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 {
process_removed_device(event->rhport, event->connection.hub_addr, event->connection.hub_port);
}
}

// 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) {
// Find the all devices (star-network) under port that is unplugged
Expand Down Expand Up @@ -1420,7 +1432,7 @@ enum {

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 @@ -1442,7 +1454,7 @@ static bool enum_new_device(hcd_event_t* event) {

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 @@ -1453,7 +1465,7 @@ static bool enum_new_device(hcd_event_t* event) {

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 @@ -1499,7 +1511,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
}

if (!retry) {
enum_full_complete(); // complete as failed
enum_full_complete(false); // complete as failed
}
return;
}
Expand All @@ -1522,7 +1534,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {

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 @@ -1559,7 +1571,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {

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 @@ -1575,7 +1587,11 @@ static void process_enumeration(tuh_xfer_t* xfer) {

// 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 @@ -1585,10 +1601,6 @@ static void process_enumeration(tuh_xfer_t* xfer) {
}

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 @@ -1613,7 +1625,12 @@ static void process_enumeration(tuh_xfer_t* xfer) {

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 @@ -1767,6 +1784,12 @@ static void process_enumeration(tuh_xfer_t* xfer) {
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 @@ -1780,7 +1803,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
}

default:
enum_full_complete(); // stop enumeration if unknown state
enum_full_complete(false); // stop enumeration if unknown state
break;
}
}
Expand Down Expand Up @@ -1917,7 +1940,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) {

// 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 @@ -1928,14 +1951,17 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) {
}
}

static void enum_full_complete(void) {
static void enum_full_complete(bool 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
}
#else
(void) success;
#endif

}
Expand Down
Loading