summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/usb/usb_request.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/dev/usb/usb_request.c')
-rw-r--r--freebsd/sys/dev/usb/usb_request.c29
1 files changed, 27 insertions, 2 deletions
diff --git a/freebsd/sys/dev/usb/usb_request.c b/freebsd/sys/dev/usb/usb_request.c
index cb69ce0e..d2a15f3c 100644
--- a/freebsd/sys/dev/usb/usb_request.c
+++ b/freebsd/sys/dev/usb/usb_request.c
@@ -992,7 +992,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",
@@ -1014,6 +1014,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;
@@ -1024,7 +1050,6 @@ usbd_req_get_desc(struct usb_device *udev,
continue;
}
- buf = desc;
if (min_len == max_len) {