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:
Hans Petter Selasky 2011-07-16 12:50:30 +00:00
parent 25630ba729
commit f6bd103ef0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=224095

View File

@ -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;