--- sys/bus/u4b/serial/uipaq.c +++ sys/bus/u4b/serial/uipaq.c @@ -1126,13 +1126,21 @@ uipaq_attach(device_t dev) req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SET_CONTROL_LINE_STATE; USETW(req.wValue, UCDC_LINE_DTR); USETW(req.wIndex, 0x0); USETW(req.wLength, 0); - for (i = 0; i != 64; i++) { + /* + * NOTE: The original WinCE warm-up loop retried 64 times with a + * 100ms request timeout plus a 100ms pause and no early-out, which + * allows an unresponsive or crafted device to stall the per-bus USB + * explore thread (and the device enum lock) for up to ~13 seconds + * per insertion. Retry only while the request is timing out -- + * which is the genuine "device not ready yet" case -- and give up + * immediately when the request succeeded, was actively rejected, + * or the device is gone. 16 * (100ms + 100ms) still gives the + * device ~3 seconds to become ready. + */ + for (i = 0; i != 16; i++) { error = usbd_do_request_flags(uaa->device, NULL, &req, NULL, 0, NULL, 100); - if (error == 0) + if (error != USB_ERR_TIMEOUT) break; usb_pause_mtx(NULL, hz / 10); }