Skip to content

Commit f84eafc

Browse files
authored
Merge pull request #2310 from hathach/fix-usbh-enumeration-removal-race
Fix usbh enumeration removal race
2 parents f3eaf06 + 9377fd6 commit f84eafc

File tree

2 files changed

+48
-42
lines changed

2 files changed

+48
-42
lines changed

src/host/usbh.c

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,12 @@ typedef struct
5555
uint8_t rhport;
5656
uint8_t hub_addr;
5757
uint8_t hub_port;
58-
uint8_t speed;
59-
60-
// enumeration is in progress, done when all interfaces are configured
61-
volatile uint8_t enumerating;
6258

63-
// struct TU_ATTR_PACKED {
64-
// uint8_t speed : 4; // packed speed to save footprint
65-
// volatile uint8_t enumerating : 1;
66-
// uint8_t TU_RESERVED : 3;
67-
// };
59+
struct TU_ATTR_PACKED {
60+
uint8_t speed : 4; // packed speed to save footprint
61+
volatile uint8_t enumerating : 1; // enumeration is in progress, false if not connected or all interfaces are configured
62+
uint8_t TU_RESERVED : 3;
63+
};
6864
} usbh_dev0_t;
6965

7066
typedef struct {
@@ -431,8 +427,8 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
431427
switch (event.event_id)
432428
{
433429
case HCD_EVENT_DEVICE_ATTACH:
434-
// due to the shared _usbh_ctrl_buf, we must complete enumerating
435-
// one device before enumerating another one.
430+
// due to the shared _usbh_ctrl_buf, we must complete enumerating one device before enumerating another one.
431+
// TODO better to have an separated queue for newly attached devices
436432
if ( _dev0.enumerating ) {
437433
TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport);
438434

@@ -556,11 +552,17 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) {
556552
// EP0 with setup packet
557553
TU_VERIFY(xfer->ep_addr == 0 && xfer->setup);
558554

559-
// pre-check to help reducing mutex lock
560-
TU_VERIFY(_ctrl_xfer.stage == CONTROL_STAGE_IDLE);
561-
555+
// Check if device is still connected (enumerating for dev0)
562556
uint8_t const daddr = xfer->daddr;
557+
if ( daddr == 0 ) {
558+
if (!_dev0.enumerating) return false;
559+
} else {
560+
usbh_device_t const* dev = get_device(daddr);
561+
if (dev && dev->connected == 0) return false;
562+
}
563563

564+
// pre-check to help reducing mutex lock
565+
TU_VERIFY(_ctrl_xfer.stage == CONTROL_STAGE_IDLE);
564566
(void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
565567

566568
bool const is_idle = (_ctrl_xfer.stage == CONTROL_STAGE_IDLE);
@@ -917,19 +919,23 @@ void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info)
917919
}
918920
}
919921

920-
TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr)
921-
{
922-
switch (event->event_id)
923-
{
924-
// case HCD_EVENT_DEVICE_REMOVE:
925-
// // FIXME device remove from a hub need an HCD API for hcd to free up endpoint
926-
// // mark device as removing to prevent further xfer before the event is processed in usbh task
927-
// break;
922+
TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) {
923+
switch (event->event_id) {
924+
case HCD_EVENT_DEVICE_REMOVE:
925+
// FIXME device remove from a hub need an HCD API for hcd to free up endpoint
926+
// mark device as removing to prevent further xfer before the event is processed in usbh task
928927

929-
default:
930-
osal_queue_send(_usbh_q, event, in_isr);
931-
break;
928+
// Check if dev0 is removed
929+
if ((event->rhport == _dev0.rhport) && (event->connection.hub_addr == _dev0.hub_addr) &&
930+
(event->connection.hub_port == _dev0.hub_port)) {
931+
_dev0.enumerating = 0;
932+
}
933+
break;
934+
935+
default: break;
932936
}
937+
938+
osal_queue_send(_usbh_q, event, in_isr);
933939
}
934940

935941
//--------------------------------------------------------------------+
@@ -1294,28 +1300,28 @@ static bool _parse_configuration_descriptor (uint8_t dev_addr, tusb_desc_configu
12941300
static void enum_full_complete(void);
12951301

12961302
// process device enumeration
1297-
static void process_enumeration(tuh_xfer_t* xfer)
1298-
{
1303+
static void process_enumeration(tuh_xfer_t* xfer) {
12991304
// Retry a few times with transfers in enumeration since device can be unstable when starting up
13001305
enum {
13011306
ATTEMPT_COUNT_MAX = 3,
13021307
ATTEMPT_DELAY_MS = 100
13031308
};
13041309
static uint8_t failed_count = 0;
13051310

1306-
if (XFER_RESULT_SUCCESS != xfer->result)
1307-
{
1311+
if (XFER_RESULT_SUCCESS != xfer->result) {
13081312
// retry if not reaching max attempt
1309-
if ( failed_count < ATTEMPT_COUNT_MAX )
1310-
{
1313+
bool retry = _dev0.enumerating && (failed_count < ATTEMPT_COUNT_MAX);
1314+
if ( retry ) {
13111315
failed_count++;
13121316
osal_task_delay(ATTEMPT_DELAY_MS); // delay a bit
13131317
TU_LOG1("Enumeration attempt %u\r\n", failed_count);
1314-
TU_ASSERT(tuh_control_xfer(xfer), );
1315-
}else
1316-
{
1318+
retry = tuh_control_xfer(xfer);
1319+
}
1320+
1321+
if (!retry) {
13171322
enum_full_complete();
13181323
}
1324+
13191325
return;
13201326
}
13211327
failed_count = 0;

src/portable/raspberrypi/pio_usb/hcd_pio_usb.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,6 @@ void __no_inline_not_in_flash_func(pio_usb_host_irq_handler)(uint8_t root_id) {
182182
root_port_t *rport = PIO_USB_ROOT_PORT(root_id);
183183
uint32_t const ints = rport->ints;
184184

185-
if ( ints & PIO_USB_INTS_CONNECT_BITS ) {
186-
hcd_event_device_attach(tu_rhport, true);
187-
}
188-
189-
if ( ints & PIO_USB_INTS_DISCONNECT_BITS ) {
190-
hcd_event_device_remove(tu_rhport, true);
191-
}
192-
193185
if ( ints & PIO_USB_INTS_ENDPOINT_COMPLETE_BITS ) {
194186
handle_endpoint_irq(rport, XFER_RESULT_SUCCESS, &rport->ep_complete);
195187
}
@@ -202,6 +194,14 @@ void __no_inline_not_in_flash_func(pio_usb_host_irq_handler)(uint8_t root_id) {
202194
handle_endpoint_irq(rport, XFER_RESULT_FAILED, &rport->ep_error);
203195
}
204196

197+
if ( ints & PIO_USB_INTS_CONNECT_BITS ) {
198+
hcd_event_device_attach(tu_rhport, true);
199+
}
200+
201+
if ( ints & PIO_USB_INTS_DISCONNECT_BITS ) {
202+
hcd_event_device_remove(tu_rhport, true);
203+
}
204+
205205
// clear all
206206
rport->ints &= ~ints;
207207
}

0 commit comments

Comments
 (0)