Author: hselasky
Date: Thu Jan  3 09:29:37 2019
New Revision: 342728
URL: https://svnweb.freebsd.org/changeset/base/342728

Log:
  MFC r342456:
  Fix reading of USB sample rate descriptor for SPL Crimson Rev 1.
  
  Read first one entry, then try to read the full rate descriptor table.
  
  PR:                   234380
  Sponsored by:         Mellanox Technologies

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

Modified: stable/9/sys/dev/sound/usb/uaudio.c
==============================================================================
--- stable/9/sys/dev/sound/usb/uaudio.c Thu Jan  3 09:28:18 2019        
(r342727)
+++ stable/9/sys/dev/sound/usb/uaudio.c Thu Jan  3 09:29:37 2019        
(r342728)
@@ -1493,7 +1493,8 @@ uaudio20_check_rate(struct usb_device *udev, uint8_t i
 {
        struct usb_device_request req;
        usb_error_t error;
-       uint8_t data[255];
+#define        UAUDIO20_MAX_RATES 32   /* we support at maxium 32 rates */
+       uint8_t data[2 + UAUDIO20_MAX_RATES * 12];
        uint16_t actlen;
        uint16_t rates;
        uint16_t x;
@@ -1505,19 +1506,57 @@ uaudio20_check_rate(struct usb_device *udev, uint8_t i
        req.bRequest = UA20_CS_RANGE;
        USETW2(req.wValue, UA20_CS_SAM_FREQ_CONTROL, 0);
        USETW2(req.wIndex, clockid, iface_no);
-       USETW(req.wLength, 255);
+       /*
+        * Assume there is at least one rate to begin with, else some
+        * devices might refuse to return the USB descriptor:
+        */
+       USETW(req.wLength, (2 + 1 * 12));
 
-        error = usbd_do_request_flags(udev, NULL, &req, data,
+       error = usbd_do_request_flags(udev, NULL, &req, data,
            USB_SHORT_XFER_OK, &actlen, USB_DEFAULT_TIMEOUT);
 
-       if (error != 0 || actlen < 2)
-               return (USB_ERR_INVAL);
+       if (error != 0 || actlen < 2) {
+               /*
+                * Likely the descriptor doesn't fit into the supplied
+                * buffer. Try using a larger buffer and see if that
+                * helps:
+                */
+               rates = MIN(UAUDIO20_MAX_RATES, (255 - 2) / 12);
+               error = USB_ERR_INVAL;
+       } else {
+               rates = UGETW(data);
 
-       rates = data[0] | (data[1] << 8);
+               if (rates > UAUDIO20_MAX_RATES) {
+                       DPRINTF("Too many rates truncating to %d\n", 
UAUDIO20_MAX_RATES);
+                       rates = UAUDIO20_MAX_RATES;
+                       error = USB_ERR_INVAL;
+               } else if (rates > 1) {
+                       DPRINTF("Need to read full rate descriptor\n");
+                       error = USB_ERR_INVAL;
+               }
+       }
+
+       if (error != 0) {
+               /*
+                * Try to read full rate descriptor.
+                */
+               actlen = (2 + rates * 12);
+
+               USETW(req.wLength, actlen);
+
+               error = usbd_do_request_flags(udev, NULL, &req, data,
+                   USB_SHORT_XFER_OK, &actlen, USB_DEFAULT_TIMEOUT);
+       
+               if (error != 0 || actlen < 2)
+                       return (USB_ERR_INVAL);
+
+               rates = UGETW(data);
+       }
+
        actlen = (actlen - 2) / 12;
 
        if (rates > actlen) {
-               DPRINTF("Too many rates\n");
+               DPRINTF("Too many rates truncating to %d\n", actlen);
                rates = actlen;
        }
 
_______________________________________________
svn-src-stable-9@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-9
To unsubscribe, send any mail to "svn-src-stable-9-unsubscr...@freebsd.org"

Reply via email to