Date: Thu, 4 Nov 2010 19:24:21 +0000 (UTC) From: Hans Petter Selasky <hselasky@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r214804 - head/sys/dev/usb Message-ID: <201011041924.oA4JOLDx070560@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201011041924.oA4JOLDx070560>