diff options
| author | Hans Petter Selasky <hselasky@FreeBSD.org> | 2011-07-23 08:55:05 +0000 |
|---|---|---|
| committer | Hans Petter Selasky <hselasky@FreeBSD.org> | 2011-07-23 08:55:05 +0000 |
| commit | 6e159fb75a4a57da0c16771dee3a542494f3dd4d (patch) | |
| tree | a79b77fb51c2d2af0a4a086d28cfb5a64bac0bd4 /sys/dev/usb | |
| parent | d46177ee55e5fdfa36039017b52f774b5e034aa5 (diff) | |
Notes
Diffstat (limited to 'sys/dev/usb')
| -rw-r--r-- | sys/dev/usb/usb_request.c | 35 |
1 files changed, 28 insertions, 7 deletions
diff --git a/sys/dev/usb/usb_request.c b/sys/dev/usb/usb_request.c index 4358ef42030b..bb5e0daa8591 100644 --- a/sys/dev/usb/usb_request.c +++ b/sys/dev/usb/usb_request.c @@ -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; |
