Author: hselasky
Date: Mon Jul 30 09:22:21 2018
New Revision: 336888
URL: https://svnweb.freebsd.org/changeset/base/336888

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

Modified:
  stable/9/sys/dev/usb/usb_request.c
Directory Properties:
  stable/9/sys/   (props changed)

Modified: stable/9/sys/dev/usb/usb_request.c
==============================================================================
--- stable/9/sys/dev/usb/usb_request.c  Mon Jul 30 09:21:19 2018        
(r336887)
+++ stable/9/sys/dev/usb/usb_request.c  Mon Jul 30 09:22:21 2018        
(r336888)
@@ -981,7 +981,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",
@@ -1003,6 +1003,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;
@@ -1013,7 +1039,6 @@ usbd_req_get_desc(struct usb_device *udev,
 
                        continue;
                }
-               buf = desc;
 
                if (min_len == max_len) {
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to