Skip to content

Commit 23426ed

Browse files
committed
fix sigma mouse in adafruit store cause multiple attach connection
1 parent 72cd810 commit 23426ed

File tree

1 file changed

+54
-49
lines changed

1 file changed

+54
-49
lines changed

src/host/usbh.c

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,37 @@ TU_ATTR_ALWAYS_INLINE static inline bool queue_event(hcd_event_t const * event,
307307
return true;
308308
}
309309

310+
TU_ATTR_ALWAYS_INLINE static inline void _control_set_xfer_stage(uint8_t stage) {
311+
if (_usbh_data.ctrl_xfer_info.stage != stage) {
312+
(void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
313+
_usbh_data.ctrl_xfer_info.stage = stage;
314+
(void) osal_mutex_unlock(_usbh_mutex);
315+
}
316+
}
317+
318+
TU_ATTR_ALWAYS_INLINE static inline bool usbh_setup_send(uint8_t daddr, const uint8_t setup_packet[8]) {
319+
const uint8_t rhport = usbh_get_rhport(daddr);
320+
const bool ret = hcd_setup_send(rhport, daddr, setup_packet);
321+
if (!ret) {
322+
_control_set_xfer_stage(CONTROL_STAGE_IDLE);
323+
}
324+
return ret;
325+
}
326+
327+
TU_ATTR_ALWAYS_INLINE static inline void usbh_device_close(uint8_t rhport, uint8_t daddr) {
328+
hcd_device_close(rhport, daddr);
329+
330+
// abort any ongoing control transfer
331+
if (daddr == _usbh_data.ctrl_xfer_info.daddr) {
332+
_control_set_xfer_stage(CONTROL_STAGE_IDLE);
333+
}
334+
335+
// invalidate if enumerating
336+
if (daddr == _usbh_data.enumerating_daddr) {
337+
_usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8;
338+
}
339+
}
340+
310341
//--------------------------------------------------------------------+
311342
// Device API
312343
//--------------------------------------------------------------------+
@@ -530,8 +561,17 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
530561
break;
531562

532563
case HCD_EVENT_DEVICE_REMOVE:
533-
TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
534-
process_removed_device(event.rhport, event.connection.hub_addr, event.connection.hub_port);
564+
TU_LOG1("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
565+
566+
if (_usbh_data.enumerating_daddr == 0 &&
567+
event.rhport == _usbh_data.dev0_bus.rhport &&
568+
event.connection.hub_addr == _usbh_data.dev0_bus.hub_addr &&
569+
event.connection.hub_port == _usbh_data.dev0_bus.hub_port) {
570+
// dev0 is unplugged while enumerating (not yet assigned an address)
571+
usbh_device_close(_usbh_data.dev0_bus.rhport, 0);
572+
} else {
573+
process_removed_device(event.rhport, event.connection.hub_addr, event.connection.hub_port);
574+
}
535575

536576
#if CFG_TUH_HUB
537577
// TODO remove
@@ -623,23 +663,6 @@ static void _control_blocking_complete_cb(tuh_xfer_t* xfer) {
623663
*((xfer_result_t*) xfer->user_data) = xfer->result;
624664
}
625665

626-
TU_ATTR_ALWAYS_INLINE static inline void _control_set_xfer_stage(uint8_t stage) {
627-
if (_usbh_data.ctrl_xfer_info.stage != stage) {
628-
(void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
629-
_usbh_data.ctrl_xfer_info.stage = stage;
630-
(void) osal_mutex_unlock(_usbh_mutex);
631-
}
632-
}
633-
634-
TU_ATTR_ALWAYS_INLINE static inline bool usbh_setup_send(uint8_t daddr, const uint8_t setup_packet[8]) {
635-
const uint8_t rhport = usbh_get_rhport(daddr);
636-
const bool ret = hcd_setup_send(rhport, daddr, setup_packet);
637-
if (!ret) {
638-
_control_set_xfer_stage(CONTROL_STAGE_IDLE);
639-
}
640-
return ret;
641-
}
642-
643666
// TODO timeout_ms is not supported yet
644667
bool tuh_control_xfer (tuh_xfer_t* xfer) {
645668
TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); // EP0 with setup packet
@@ -1270,21 +1293,8 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) {
12701293

12711294
// a device unplugged from rhport:hub_addr:hub_port
12721295
static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) {
1273-
// if dev0 is unplugged while enumerating (not yet assigned an address)
1274-
if (_usbh_data.enumerating_daddr == 0) {
1275-
const tuh_bus_info_t* dev0_bus = &_usbh_data.dev0_bus;
1276-
if ((rhport == dev0_bus->rhport) && (hub_addr == dev0_bus->hub_addr) && (hub_port == dev0_bus->hub_port)) {
1277-
hcd_device_close(dev0_bus->rhport, 0);
1278-
if (_usbh_data.ctrl_xfer_info.daddr == 0) {
1279-
_control_set_xfer_stage(CONTROL_STAGE_IDLE);
1280-
}
1281-
_usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8;
1282-
return;
1283-
}
1284-
}
1285-
1286-
//------------- find the all devices (star-network) under port that is unplugged -------------//
1287-
uint32_t removing_hubs = 0;
1296+
// Find the all devices (star-network) under port that is unplugged
1297+
uint32_t removing_hubs_bm = 0;
12881298
do {
12891299
for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) {
12901300
usbh_device_t* dev = &_usbh_devices[dev_id];
@@ -1298,7 +1308,7 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub
12981308

12991309
if (is_hub_addr(daddr)) {
13001310
TU_LOG_USBH(" is a HUB device %u\r\n", daddr);
1301-
removing_hubs |= TU_BIT(dev_id - CFG_TUH_DEVICE_MAX);
1311+
removing_hubs_bm |= TU_BIT(dev_id - CFG_TUH_DEVICE_MAX);
13021312
} else {
13031313
// Invoke callback before closing driver (maybe call it later ?)
13041314
if (tuh_umount_cb) {
@@ -1314,30 +1324,21 @@ static void process_removed_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub
13141324
}
13151325
}
13161326

1317-
hcd_device_close(rhport, daddr);
1327+
usbh_device_close(rhport, daddr);
13181328
clear_device(dev);
1319-
1320-
// abort ongoing control xfer on this device if any
1321-
if (daddr == _usbh_data.ctrl_xfer_info.daddr) {
1322-
_control_set_xfer_stage(CONTROL_STAGE_IDLE);
1323-
}
1324-
1325-
if (daddr == _usbh_data.enumerating_daddr) {
1326-
_usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8;
1327-
}
13281329
}
13291330
}
13301331

13311332
// if removing a hub, we need to remove all of its downstream devices
13321333
#if CFG_TUH_HUB
1333-
if (removing_hubs == 0) {
1334+
if (removing_hubs_bm == 0) {
13341335
break;
13351336
}
13361337

13371338
// find a marked hub to process
13381339
for (uint8_t h_id = 0; h_id < CFG_TUH_HUB; h_id++) {
1339-
if (tu_bit_test(removing_hubs, h_id)) {
1340-
removing_hubs &= ~TU_BIT(h_id);
1340+
if (tu_bit_test(removing_hubs_bm, h_id)) {
1341+
removing_hubs_bm &= ~TU_BIT(h_id);
13411342

13421343
// update hub_addr and hub_port for next loop
13431344
hub_addr = h_id + 1 + CFG_TUH_DEVICE_MAX;
@@ -1560,6 +1561,10 @@ static void process_enumeration(tuh_xfer_t* xfer) {
15601561
}
15611562

15621563
case ENUM_SET_ADDR: {
1564+
// Due to physical debouncing, some devices can cause multiple attaches (actually reset) without detach event
1565+
// Force remove currently mounted with the same bus info (rhport, hub addr, hub port) if exists
1566+
process_removed_device(dev0_bus->rhport, dev0_bus->hub_addr, dev0_bus->hub_port);
1567+
15631568
const tusb_desc_device_t *desc_device = (const tusb_desc_device_t *) _usbh_epbuf.ctrl;
15641569
const uint8_t new_addr = enum_get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
15651570
TU_ASSERT(new_addr != 0,);
@@ -1582,7 +1587,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
15821587
new_dev->addressed = 1;
15831588
_usbh_data.enumerating_daddr = new_addr;
15841589

1585-
hcd_device_close(dev0_bus->rhport, 0); // close dev0
1590+
usbh_device_close(dev0_bus->rhport, 0); // close dev0
15861591

15871592
TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint
15881593

0 commit comments

Comments
 (0)