Add code to warm reset a USB 3.0 port.

Approved by:	thompsa (mentor)
This commit is contained in:
Hans Petter Selasky 2010-11-04 19:24:21 +00:00
parent d74698ca2e
commit cbb75751a7
2 changed files with 100 additions and 5 deletions

View File

@ -741,7 +741,7 @@ done:
/*------------------------------------------------------------------------*
* usbd_req_reset_port
*
* This function will instruct an USB HUB to perform a reset sequence
* This function will instruct a USB HUB to perform a reset sequence
* on the specified port number.
*
* Returns:
@ -793,10 +793,6 @@ usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
if (err) {
goto done;
}
/* if the device disappeared, just give up */
if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) {
goto done;
}
/* check if reset is complete */
if (UGETW(ps.wPortChange) & UPS_C_PORT_RESET) {
break;
@ -833,6 +829,103 @@ done:
return (err);
}
/*------------------------------------------------------------------------*
* usbd_req_warm_reset_port
*
* This function will instruct an USB HUB to perform a warm reset
* sequence on the specified port number. This kind of reset is not
* mandatory for LOW-, FULL- and HIGH-speed USB HUBs and is targeted
* for SUPER-speed USB HUBs.
*
* Returns:
* 0: Success. The USB device should now be available again.
* Else: Failure. No USB device is present and the USB port should be
* disabled.
*------------------------------------------------------------------------*/
usb_error_t
usbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
{
struct usb_port_status ps;
usb_error_t err;
uint16_t n;
#ifdef USB_DEBUG
uint16_t pr_poll_delay;
uint16_t pr_recovery_delay;
#endif
err = usbd_req_set_port_feature(udev, mtx, port, UHF_BH_PORT_RESET);
if (err) {
goto done;
}
#ifdef USB_DEBUG
/* range check input parameters */
pr_poll_delay = usb_pr_poll_delay;
if (pr_poll_delay < 1) {
pr_poll_delay = 1;
} else if (pr_poll_delay > 1000) {
pr_poll_delay = 1000;
}
pr_recovery_delay = usb_pr_recovery_delay;
if (pr_recovery_delay > 1000) {
pr_recovery_delay = 1000;
}
#endif
n = 0;
while (1) {
#ifdef USB_DEBUG
/* wait for the device to recover from reset */
usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay));
n += pr_poll_delay;
#else
/* wait for the device to recover from reset */
usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY));
n += USB_PORT_RESET_DELAY;
#endif
err = usbd_req_get_port_status(udev, mtx, &ps, port);
if (err) {
goto done;
}
/* if the device disappeared, just give up */
if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) {
goto done;
}
/* check if reset is complete */
if (UGETW(ps.wPortChange) & UPS_C_BH_PORT_RESET) {
break;
}
/* check for timeout */
if (n > 1000) {
n = 0;
break;
}
}
/* clear port reset first */
err = usbd_req_clear_port_feature(
udev, mtx, port, UHF_C_BH_PORT_RESET);
if (err) {
goto done;
}
/* check for timeout */
if (n == 0) {
err = USB_ERR_TIMEOUT;
goto done;
}
#ifdef USB_DEBUG
/* wait for the device to recover from reset */
usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay));
#else
/* wait for the device to recover from reset */
usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY));
#endif
done:
DPRINTFN(2, "port %d warm reset returning error=%s\n",
port, usbd_errstr(err));
return (err);
}
/*------------------------------------------------------------------------*
* usbd_req_get_desc
*

View File

@ -65,6 +65,8 @@ usb_error_t usbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx,
struct usb_port_status *ps, uint8_t port);
usb_error_t usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx,
uint8_t port);
usb_error_t usbd_req_warm_reset_port(struct usb_device *udev,
struct mtx *mtx, uint8_t port);
usb_error_t usbd_req_set_address(struct usb_device *udev, struct mtx *mtx,
uint16_t addr);
usb_error_t usbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx,