Author: hselasky
Date: Wed Jun 27 12:08:12 2018
New Revision: 335700
URL: https://svnweb.freebsd.org/changeset/base/335700

Log:
  Improve the kernel's USB descriptor reading function.
  Some USB devices does not allow a partial descriptor readout.
  
  Found by:     bz@
  MFC after:    1 week
  Sponsored by: Mellanox Technologies

Modified:
  head/sys/dev/usb/usb_request.c

Modified: head/sys/dev/usb/usb_request.c
==============================================================================
--- head/sys/dev/usb/usb_request.c      Wed Jun 27 07:24:07 2018        
(r335699)
+++ head/sys/dev/usb/usb_request.c      Wed Jun 27 12:08:12 2018        
(r335700)
@@ -990,7 +990,7 @@ usbd_req_get_desc(struct usb_device *udev,
     uint8_t retries)
 {
        struct usb_device_request req;
-       uint8_t *buf;
+       uint8_t *buf = desc;
        usb_error_t err;
 
        DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n",
@@ -1012,6 +1012,32 @@ usbd_req_get_desc(struct usb_device *udev,
                err = usbd_do_request_flags(udev, mtx, &req,
                    desc, 0, NULL, 500 /* ms */);
 
+               if (err != 0 && err != USB_ERR_TIMEOUT &&
+                   min_len != max_len) {
+                       /* clear descriptor data */
+                       memset(desc, 0, max_len);
+
+                       /* try to read full descriptor length */
+                       USETW(req.wLength, max_len);
+
+                       err = usbd_do_request_flags(udev, mtx, &req,
+                           desc, USB_SHORT_XFER_OK, NULL, 500 /* ms */);
+
+                       if (err == 0) {
+                               /* verify length */
+                               if (buf[0] > max_len)
+                                       buf[0] = max_len;
+                               else if (buf[0] < 2)
+                                       err = USB_ERR_INVAL;
+
+                               min_len = buf[0];
+
+                               /* enforce descriptor type */
+                               buf[1] = type;
+                               goto done;
+                       }
+               }
+
                if (err) {
                        if (!retries) {
                                goto done;
@@ -1022,7 +1048,6 @@ usbd_req_get_desc(struct usb_device *udev,
 
                        continue;
                }
-               buf = desc;
 
                if (min_len == max_len) {
 
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to