Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 25 Dec 2018 10:15:48 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r342456 - head/sys/dev/sound/usb
Message-ID:  <201812251015.wBPAFmd5037058@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Tue Dec 25 10:15:48 2018
New Revision: 342456
URL: https://svnweb.freebsd.org/changeset/base/342456

Log:
  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
  MFC after:		1 week
  Sponsored by:		Mellanox Technologies

Modified:
  head/sys/dev/sound/usb/uaudio.c

Modified: head/sys/dev/sound/usb/uaudio.c
==============================================================================
--- head/sys/dev/sound/usb/uaudio.c	Tue Dec 25 07:39:34 2018	(r342455)
+++ head/sys/dev/sound/usb/uaudio.c	Tue Dec 25 10:15:48 2018	(r342456)
@@ -1520,7 +1520,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;
@@ -1532,19 +1533,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;
 	}
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201812251015.wBPAFmd5037058>