summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2013-03-13 15:38:01 +0000
committerhselasky <hselasky@FreeBSD.org>2013-03-13 15:38:01 +0000
commit2dd657bd7aafaa0d84f9879afac81a09b1b6994a (patch)
tree14ef109da101eccc8fa4e029d607411fe9ea7377
parent0b8d7927213de8679fda3f58d460b754fe2f65f0 (diff)
downloadFreeBSD-src-2dd657bd7aafaa0d84f9879afac81a09b1b6994a.zip
FreeBSD-src-2dd657bd7aafaa0d84f9879afac81a09b1b6994a.tar.gz
- Make quirk for reading device descriptor from broken USB devices.
Else they won't enumerate at all: hw.usb.full_ddesc=1 - Reduce the USB descriptor read timeout from 1000ms to 500ms. Typical value for LOW speed devices is 50-100ms. - Enumerate USB device a maximum of 3 times when a port connection change event is detected, before giving up. MFC after: 1 month
-rw-r--r--sys/dev/usb/usb_device.c10
-rw-r--r--sys/dev/usb/usb_request.c52
2 files changed, 40 insertions, 22 deletions
diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c
index 1c40815..43378c0 100644
--- a/sys/dev/usb/usb_device.c
+++ b/sys/dev/usb/usb_device.c
@@ -1698,10 +1698,14 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
err = usbd_setup_device_desc(udev, NULL);
if (err != 0) {
- /* XXX try to re-enumerate the device */
+ /* try to enumerate two more times */
err = usbd_req_re_enumerate(udev, NULL);
- if (err)
- goto done;
+ if (err != 0) {
+ err = usbd_req_re_enumerate(udev, NULL);
+ if (err != 0) {
+ goto done;
+ }
+ }
}
/*
diff --git a/sys/dev/usb/usb_request.c b/sys/dev/usb/usb_request.c
index 1a366d6..d24a39f 100644
--- a/sys/dev/usb/usb_request.c
+++ b/sys/dev/usb/usb_request.c
@@ -76,6 +76,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. */
@@ -1002,7 +1007,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) {
@@ -1887,32 +1892,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;
- }
+ "to hold the complete device descriptor or "
+ "only once MaxPacketSize choice\n");
- /* get the full device descriptor */
- err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc);
-
- /* 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);
}
OpenPOWER on IntegriCloud