Fix for VirtualBox 4.x and other virtual machines that fail
to generate a port reset change event. MFC after: 1 weeks
This commit is contained in:
parent
25630ba729
commit
f6bd103ef0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=224095
@ -779,10 +779,17 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
|
||||
uint16_t pr_recovery_delay;
|
||||
|
||||
#endif
|
||||
err = usbd_req_set_port_feature(udev, mtx, port, UHF_PORT_RESET);
|
||||
if (err) {
|
||||
/* clear any leftover port reset changes first */
|
||||
usbd_req_clear_port_feature(
|
||||
udev, mtx, port, UHF_C_PORT_RESET);
|
||||
|
||||
/* assert port reset on the given port */
|
||||
err = usbd_req_set_port_feature(
|
||||
udev, mtx, port, UHF_PORT_RESET);
|
||||
|
||||
/* check for errors */
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
#ifdef USB_DEBUG
|
||||
/* range check input parameters */
|
||||
pr_poll_delay = usb_pr_poll_delay;
|
||||
@ -798,6 +805,9 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
|
||||
#endif
|
||||
n = 0;
|
||||
while (1) {
|
||||
uint16_t status;
|
||||
uint16_t change;
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
/* wait for the device to recover from reset */
|
||||
usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay));
|
||||
@ -811,14 +821,25 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
|
||||
if (err) {
|
||||
goto done;
|
||||
}
|
||||
status = UGETW(ps.wPortStatus);
|
||||
change = UGETW(ps.wPortChange);
|
||||
|
||||
/* if the device disappeared, just give up */
|
||||
if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) {
|
||||
if (!(status & UPS_CURRENT_CONNECT_STATUS))
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* check if reset is complete */
|
||||
if (UGETW(ps.wPortChange) & UPS_C_PORT_RESET) {
|
||||
if (change & UPS_C_PORT_RESET)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some Virtual Machines like VirtualBox 4.x fail to
|
||||
* generate a port reset change event. Check if reset
|
||||
* is no longer asserted.
|
||||
*/
|
||||
if (!(status & UPS_RESET))
|
||||
break;
|
||||
|
||||
/* check for timeout */
|
||||
if (n > 1000) {
|
||||
n = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user