svn commit: r214804 - head/sys/dev/usb
Hans Petter Selasky
hselasky at FreeBSD.org
Thu Nov 4 19:24:21 UTC 2010
Author: hselasky
Date: Thu Nov 4 19:24:21 2010
New Revision: 214804
URL: http://svn.freebsd.org/changeset/base/214804
Log:
Add code to warm reset a USB 3.0 port.
Approved by: thompsa (mentor)
Modified:
head/sys/dev/usb/usb_request.c
head/sys/dev/usb/usb_request.h
Modified: head/sys/dev/usb/usb_request.c
==============================================================================
--- head/sys/dev/usb/usb_request.c Thu Nov 4 19:20:03 2010 (r214803)
+++ head/sys/dev/usb/usb_request.c Thu Nov 4 19:24:21 2010 (r214804)
@@ -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,12 +793,105 @@ usbd_req_reset_port(struct usb_device *u
if (err) {
goto done;
}
+ /* check if reset is complete */
+ if (UGETW(ps.wPortChange) & UPS_C_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_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 reset returning error=%s\n",
+ port, usbd_errstr(err));
+ 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_PORT_RESET) {
+ if (UGETW(ps.wPortChange) & UPS_C_BH_PORT_RESET) {
break;
}
/* check for timeout */
@@ -810,7 +903,7 @@ usbd_req_reset_port(struct usb_device *u
/* clear port reset first */
err = usbd_req_clear_port_feature(
- udev, mtx, port, UHF_C_PORT_RESET);
+ udev, mtx, port, UHF_C_BH_PORT_RESET);
if (err) {
goto done;
}
@@ -828,7 +921,7 @@ usbd_req_reset_port(struct usb_device *u
#endif
done:
- DPRINTFN(2, "port %d reset returning error=%s\n",
+ DPRINTFN(2, "port %d warm reset returning error=%s\n",
port, usbd_errstr(err));
return (err);
}
Modified: head/sys/dev/usb/usb_request.h
==============================================================================
--- head/sys/dev/usb/usb_request.h Thu Nov 4 19:20:03 2010 (r214803)
+++ head/sys/dev/usb/usb_request.h Thu Nov 4 19:24:21 2010 (r214804)
@@ -65,6 +65,8 @@ usb_error_t usbd_req_get_port_status(str
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,
More information about the svn-src-head
mailing list