diff options
Diffstat (limited to 'freebsd/sys/dev/usb/usb_request.c')
-rw-r--r-- | freebsd/sys/dev/usb/usb_request.c | 80 |
1 files changed, 57 insertions, 23 deletions
diff --git a/freebsd/sys/dev/usb/usb_request.c b/freebsd/sys/dev/usb/usb_request.c index 167a7228..e9137bd2 100644 --- a/freebsd/sys/dev/usb/usb_request.c +++ b/freebsd/sys/dev/usb/usb_request.c @@ -50,7 +50,6 @@ #include <dev/usb/usb.h> #include <dev/usb/usbdi.h> #include <dev/usb/usbdi_util.h> -#include <dev/usb/usb_ioctl.h> #include <dev/usb/usbhid.h> #define USB_DEBUG_VAR usb_debug @@ -74,6 +73,11 @@ static int usb_no_cs_fail; SYSCTL_INT(_hw_usb, OID_AUTO, no_cs_fail, CTLFLAG_RW, &usb_no_cs_fail, 0, "USB clear stall failures are ignored, if set"); +static int usb_full_ddesc; + +SYSCTL_INT(_hw_usb, OID_AUTO, full_ddesc, CTLFLAG_RW, + &usb_full_ddesc, 0, "USB always read complete device descriptor, if set"); + #ifdef USB_DEBUG #ifdef USB_REQ_DEBUG /* The following structures are used in connection to fault injection. */ @@ -712,6 +716,17 @@ done: if ((mtx != NULL) && (mtx != &Giant)) mtx_lock(mtx); + switch (err) { + case USB_ERR_NORMAL_COMPLETION: + case USB_ERR_SHORT_XFER: + case USB_ERR_STALLED: + case USB_ERR_CANCELLED: + break; + default: + DPRINTF("I/O error - waiting a bit for TT cleanup\n"); + usb_pause_mtx(mtx, hz / 16); + break; + } return ((usb_error_t)err); } @@ -999,7 +1014,7 @@ usbd_req_get_desc(struct usb_device *udev, USETW(req.wLength, min_len); err = usbd_do_request_flags(udev, mtx, &req, - desc, 0, NULL, 1000); + desc, 0, NULL, 500 /* ms */); if (err) { if (!retries) { @@ -1884,32 +1899,41 @@ usbd_setup_device_desc(struct usb_device *udev, struct mtx *mtx) */ switch (udev->speed) { case USB_SPEED_FULL: - case USB_SPEED_LOW: + if (usb_full_ddesc != 0) { + /* get full device descriptor */ + err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); + if (err == 0) + break; + } + + /* get partial device descriptor, some devices crash on this */ err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc, USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0); - if (err != 0) { - DPRINTFN(0, "getting device descriptor " - "at addr %d failed, %s\n", udev->address, - usbd_errstr(err)); - return (err); - } + if (err != 0) + break; + + /* get the full device descriptor */ + err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); break; + default: DPRINTF("Minimum MaxPacketSize is large enough " - "to hold the complete device descriptor\n"); - break; - } - - /* get the full device descriptor */ - err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); + "to hold the complete device descriptor or " + "only once MaxPacketSize choice\n"); - /* try one more time, if error */ - if (err) + /* get the full device descriptor */ err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); - if (err) { - DPRINTF("addr=%d, getting full desc failed\n", - udev->address); + /* try one more time, if error */ + if (err != 0) + err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); + break; + } + + if (err != 0) { + DPRINTFN(0, "getting device descriptor " + "at addr %d failed, %s\n", udev->address, + usbd_errstr(err)); return (err); } @@ -1954,6 +1978,7 @@ usbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx) return (USB_ERR_INVAL); } retry: +#if USB_HAVE_TT_SUPPORT /* * Try to reset the High Speed parent HUB of a LOW- or FULL- * speed device, if any. @@ -1961,15 +1986,24 @@ retry: if (udev->parent_hs_hub != NULL && udev->speed != USB_SPEED_HIGH) { DPRINTF("Trying to reset parent High Speed TT.\n"); - err = usbd_req_reset_tt(udev->parent_hs_hub, NULL, - udev->hs_port_no); + if (udev->parent_hs_hub == parent_hub && + (uhub_count_active_host_ports(parent_hub, USB_SPEED_LOW) + + uhub_count_active_host_ports(parent_hub, USB_SPEED_FULL)) == 1) { + /* we can reset the whole TT */ + err = usbd_req_reset_tt(parent_hub, NULL, + udev->hs_port_no); + } else { + /* only reset a particular device and endpoint */ + err = usbd_req_clear_tt_buffer(udev->parent_hs_hub, NULL, + udev->hs_port_no, old_addr, UE_CONTROL, 0); + } if (err) { DPRINTF("Resetting parent High " "Speed TT failed (%s).\n", usbd_errstr(err)); } } - +#endif /* Try to warm reset first */ if (parent_hub->speed == USB_SPEED_SUPER) usbd_req_warm_reset_port(parent_hub, mtx, udev->port_no); |