aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2019-01-03 09:29:37 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2019-01-03 09:29:37 +0000
commit48169ee1c083aad7ec3523f08dbab52a2450b5c0 (patch)
tree44cb4b92625eab34e87a1738ecbc78270336ec88 /sys/dev
parent723e7d818e52ab5e0b4ad443c7fa9170f27b2d05 (diff)
Notes
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/sound/usb/uaudio.c53
1 files changed, 46 insertions, 7 deletions
diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c
index bbf1ff8c0f63..d84cf99b40b3 100644
--- a/sys/dev/sound/usb/uaudio.c
+++ b/sys/dev/sound/usb/uaudio.c
@@ -1493,7 +1493,8 @@ uaudio20_check_rate(struct usb_device *udev, uint8_t iface_no,
{
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 iface_no,
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);
+
+ 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);
+ }
- rates = data[0] | (data[1] << 8);
actlen = (actlen - 2) / 12;
if (rates > actlen) {
- DPRINTF("Too many rates\n");
+ DPRINTF("Too many rates truncating to %d\n", actlen);
rates = actlen;
}