Skip to content

Commit 2c48050

Browse files
committed
add various check for disconncted device, also fix hathach#1511 un-roll recursive hub removal with usbh queue
1 parent 1c4f22a commit 2c48050

File tree

1 file changed

+82
-42
lines changed

1 file changed

+82
-42
lines changed

src/host/usbh.c

Lines changed: 82 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,12 @@ typedef struct {
8181

8282
// Device State
8383
struct TU_ATTR_PACKED {
84-
volatile uint8_t connected : 1;
85-
volatile uint8_t addressed : 1;
86-
volatile uint8_t configured : 1;
87-
volatile uint8_t suspended : 1;
84+
volatile uint8_t connected : 1; // After 1st transfer
85+
volatile uint8_t addressed : 1; // After SET_ADDR
86+
volatile uint8_t configured : 1; // After SET_CONFIG and all drivers are configured
87+
volatile uint8_t suspended : 1; // Bus suspended
88+
89+
// volatile uint8_t removing : 1; // Physically disconnected, waiting to be processed by usbh
8890
};
8991

9092
// Device Descriptor
@@ -248,7 +250,7 @@ static inline usbh_device_t* get_device(uint8_t dev_addr)
248250
}
249251

250252
static bool enum_new_device(hcd_event_t* event);
251-
static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
253+
static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
252254
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
253255
static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
254256

@@ -420,7 +422,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
420422

421423
case HCD_EVENT_DEVICE_REMOVE:
422424
TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
423-
process_device_unplugged(event.rhport, event.connection.hub_addr, event.connection.hub_port);
425+
process_removing_device(event.rhport, event.connection.hub_addr, event.connection.hub_port);
424426

425427
#if CFG_TUH_HUB
426428
// TODO remove
@@ -450,7 +452,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
450452
else
451453
{
452454
usbh_device_t* dev = get_device(event.dev_addr);
453-
TU_ASSERT(dev, );
455+
TU_VERIFY(dev && dev->connected, );
454456

455457
dev->ep_status[epnum][ep_dir].busy = 0;
456458
dev->ep_status[epnum][ep_dir].claimed = 0;
@@ -739,29 +741,33 @@ void usbh_int_set(bool enabled)
739741
// TODO has some duplication code with device, refactor later
740742
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
741743
{
744+
// Note: addr0 only use tuh_control_xfer
742745
usbh_device_t* dev = get_device(dev_addr);
743-
744-
// addr0 only use tuh_control_xfer
745-
TU_ASSERT(dev);
746+
TU_ASSERT(dev && dev->connected);
746747

747748
uint8_t const epnum = tu_edpt_number(ep_addr);
748749
uint8_t const dir = tu_edpt_dir(ep_addr);
749750

750-
return tu_edpt_claim(&dev->ep_status[epnum][dir], _usbh_mutex);
751+
TU_VERIFY(tu_edpt_claim(&dev->ep_status[epnum][dir], _usbh_mutex));
752+
TU_LOG_USBH("[%u] Claimed EP 0x%02x\r\n", dev_addr, ep_addr);
753+
754+
return true;
751755
}
752756

753757
// TODO has some duplication code with device, refactor later
754758
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
755759
{
760+
// Note: addr0 only use tuh_control_xfer
756761
usbh_device_t* dev = get_device(dev_addr);
757-
758-
// addr0 only use tuh_control_xfer
759-
TU_ASSERT(dev);
762+
TU_VERIFY(dev && dev->connected);
760763

761764
uint8_t const epnum = tu_edpt_number(ep_addr);
762765
uint8_t const dir = tu_edpt_dir(ep_addr);
763766

764-
return tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex);
767+
TU_VERIFY(tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex));
768+
TU_LOG_USBH("[%u] Released EP 0x%02x\r\n", dev_addr, ep_addr);
769+
770+
return true;
765771
}
766772

767773
// TODO has some duplication code with device, refactor later
@@ -870,7 +876,7 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr)
870876
switch (event->event_id)
871877
{
872878
// case HCD_EVENT_DEVICE_REMOVE:
873-
//
879+
// // mark device as removing to prevent further xfer before the event is processed in usbh task
874880
// break;
875881

876882
default:
@@ -1116,7 +1122,7 @@ uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_i
11161122
}
11171123

11181124
//--------------------------------------------------------------------+
1119-
//
1125+
// Detaching
11201126
//--------------------------------------------------------------------+
11211127

11221128
TU_ATTR_ALWAYS_INLINE
@@ -1125,45 +1131,79 @@ static inline bool is_hub_addr(uint8_t daddr)
11251131
return (CFG_TUH_HUB > 0) && (daddr > CFG_TUH_DEVICE_MAX);
11261132
}
11271133

1134+
//static void mark_removing_device_isr(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) {
1135+
// for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) {
1136+
// usbh_device_t *dev = &_usbh_devices[dev_id];
1137+
// uint8_t const daddr = dev_id + 1;
1138+
//
1139+
// // hub_addr = 0 means roothub, hub_port = 0 means all devices of downstream hub
1140+
// if (dev->rhport == rhport && dev->connected &&
1141+
// (hub_addr == 0 || dev->hub_addr == hub_addr) &&
1142+
// (hub_port == 0 || dev->hub_port == hub_port)) {
1143+
// if (is_hub_addr(daddr)) {
1144+
// // If the device itself is a usb hub, mark all downstream devices.
1145+
// // FIXME recursive calls
1146+
// mark_removing_device_isr(rhport, daddr, 0);
1147+
// }
1148+
//
1149+
// dev->removing = 1;
1150+
// }
1151+
// }
1152+
//}
1153+
11281154
// a device unplugged from rhport:hub_addr:hub_port
1129-
static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port)
1155+
static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port)
11301156
{
11311157
//------------- find the all devices (star-network) under port that is unplugged -------------//
11321158
// TODO mark as disconnected in ISR, also handle dev0
1133-
for ( uint8_t dev_id = 0; dev_id < TU_ARRAY_SIZE(_usbh_devices); dev_id++ )
1134-
{
1135-
usbh_device_t* dev = &_usbh_devices[dev_id];
1136-
uint8_t const dev_addr = dev_id+1;
11371159

1138-
if (dev->rhport == rhport &&
1139-
(hub_addr == 0 || dev->hub_addr == hub_addr) && // hub_addr = 0 means roothub
1140-
(hub_port == 0 || dev->hub_port == hub_port) && // hub_port = 0 means all devices of downstream hub
1141-
dev->connected)
1142-
{
1143-
TU_LOG_USBH("Device unplugged address = %u\r\n", dev_addr);
1160+
#if 0
1161+
// index as hub addr, value is hub port (0xFF for invalid)
1162+
uint8_t removing_hubs[CFG_TUH_HUB];
1163+
memset(removing_hubs, TUSB_INDEX_INVALID_8, sizeof(removing_hubs));
11441164

1145-
if (is_hub_addr(dev_addr))
1146-
{
1147-
TU_LOG(USBH_DEBUG, " is a HUB device\r\n", dev_addr);
1148-
// If the device itself is a usb hub, unplug downstream devices.
1149-
// FIXME un-roll recursive calls to prevent potential stack overflow
1150-
process_device_unplugged(rhport, dev_addr, 0);
1151-
}else
1152-
{
1165+
removing_hubs[hub_addr-CFG_TUH_DEVICE_MAX] = hub_port;
1166+
1167+
// consecutive non-removing hub
1168+
uint8_t nop_count = 0;
1169+
#endif
1170+
1171+
for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) {
1172+
usbh_device_t *dev = &_usbh_devices[dev_id];
1173+
uint8_t const daddr = dev_id + 1;
1174+
1175+
// hub_addr = 0 means roothub, hub_port = 0 means all devices of downstream hub
1176+
if (dev->rhport == rhport && dev->connected &&
1177+
(hub_addr == 0 || dev->hub_addr == hub_addr) &&
1178+
(hub_port == 0 || dev->hub_port == hub_port)) {
1179+
TU_LOG_USBH("Device unplugged address = %u\r\n", daddr);
1180+
1181+
if (is_hub_addr(daddr)) {
1182+
TU_LOG(USBH_DEBUG, " is a HUB device\r\n", daddr);
1183+
1184+
// Submit removed event If the device itself is a hub (un-rolled recursive)
1185+
// TODO a better to unroll recursrive is using array of removing_hubs and mark it here
1186+
hcd_event_t event;
1187+
event.rhport = rhport;
1188+
event.event_id = HCD_EVENT_DEVICE_REMOVE;
1189+
event.connection.hub_addr = daddr;
1190+
event.connection.hub_port = 0;
1191+
1192+
hcd_event_handler(&event, false);
1193+
} else {
11531194
// Invoke callback before closing driver (maybe call it later ?)
1154-
if (tuh_umount_cb) tuh_umount_cb(dev_addr);
1195+
if (tuh_umount_cb) tuh_umount_cb(daddr);
11551196
}
11561197

11571198
// Close class driver
1158-
for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
1159-
{
1160-
usbh_class_drivers[drv_id].close(dev_addr);
1199+
for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) {
1200+
usbh_class_drivers[drv_id].close(daddr);
11611201
}
11621202

1163-
hcd_device_close(rhport, dev_addr);
1203+
hcd_device_close(rhport, daddr);
11641204
clear_device(dev);
11651205
// abort on-going control xfer if any
1166-
if (_ctrl_xfer.daddr == dev_addr) _set_control_xfer_stage(CONTROL_STAGE_IDLE);
1206+
if (_ctrl_xfer.daddr == daddr) _set_control_xfer_stage(CONTROL_STAGE_IDLE);
11671207
}
11681208
}
11691209
}

0 commit comments

Comments
 (0)