diff mbox series

ALSA: usb-audio: Filter out unsupported sample rates on Focusrite devices

Message ID 20200418171908.10402-1-alexander@tsoy.me (mailing list archive)
State New, archived
Headers show
Series ALSA: usb-audio: Filter out unsupported sample rates on Focusrite devices | expand

Commit Message

Alexander Tsoy April 18, 2020, 5:19 p.m. UTC
Many Focusrite devices supports a limited set of sample rates per
altsetting. This includes interfaces with ADAT ports and interfaces with
dedicated feedback channels:
 - Scarlett 18i6, 18i8 1st gen, 18i20 1st gen;
 - Scarlett 18i8 2nd gen, 18i20 2nd gen;
 - all Scarlett 3rd gen devices (feedback channels works only up to 96
   kHz);
 - Clarett 2Pre USB, 4Pre USB, 8Pre USB.

Tested-by: Alexey Skobkin <skobkin-ru@ya.ru>
Signed-off-by: Alexander Tsoy <alexander@tsoy.me>
---
 sound/usb/format.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

Comments

Alexander Tsoy April 18, 2020, 5:44 p.m. UTC | #1
В Сб, 18/04/2020 в 20:19 +0300, Alexander Tsoy пишет:
> Many Focusrite devices supports a limited set of sample rates per
> altsetting. This includes interfaces with ADAT ports and interfaces
> with
> dedicated feedback channels:
>  - Scarlett 18i6, 18i8 1st gen, 18i20 1st gen;
>  - Scarlett 18i8 2nd gen, 18i20 2nd gen;
>  - all Scarlett 3rd gen devices (feedback channels works only up to
> 96
>    kHz);

I might be wrong here. It seems that 3rd gen Scarletts other than 18i8
and 18i20 doesn't expose any additional altsettings to limit number of
channels. I'll resend this patch with updated description.
diff mbox series

Patch

diff --git a/sound/usb/format.c b/sound/usb/format.c
index 50e1874c847c..5ffb457cc88c 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -277,6 +277,52 @@  static bool s1810c_valid_sample_rate(struct audioformat *fp,
 	return false;
 }
 
+/*
+ * Many Focusrite devices supports a limited set of sampling rates per
+ * altsetting. Maximum rate is exposed in the last 4 bytes of Format Type
+ * descriptor which has a non-standard bLength = 10.
+ */
+static bool focusrite_valid_sample_rate(struct snd_usb_audio *chip,
+					struct audioformat *fp,
+					unsigned int rate)
+{
+	struct usb_interface *iface;
+	struct usb_host_interface *alts;
+	unsigned char *fmt;
+	unsigned int max_rate;
+
+	iface = usb_ifnum_to_if(chip->dev, fp->iface);
+	if (!iface)
+		return true;
+
+	alts = &iface->altsetting[fp->altset_idx];
+	fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen,
+				      NULL, UAC_FORMAT_TYPE);
+	if (!fmt)
+		return true;
+
+	if (fmt[0] == 10) { /* bLength */
+		max_rate = combine_quad(&fmt[6]);
+
+		/* Validate max rate */
+		if (max_rate != 48000 &&
+		    max_rate != 96000 &&
+		    max_rate != 192000 &&
+		    max_rate != 384000) {
+
+			usb_audio_info(chip,
+				"%u:%d : unexpected max rate: %u\n",
+				fp->iface, fp->altsetting, max_rate);
+
+			return true;
+		}
+
+		return rate <= max_rate;
+	}
+
+	return true;
+}
+
 /*
  * Helper function to walk the array of sample rate triplets reported by
  * the device. The problem is that we need to parse whole array first to
@@ -319,6 +365,11 @@  static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
 			    !s1810c_valid_sample_rate(fp, rate))
 				goto skip_rate;
 
+			/* Filter out invalid rates on Focusrite devices */
+			if (USB_ID_VENDOR(chip->usb_id) == 0x1235 &&
+			    !focusrite_valid_sample_rate(chip, fp, rate))
+				goto skip_rate;
+
 			if (fp->rate_table)
 				fp->rate_table[nr_rates] = rate;
 			if (!fp->rate_min || rate < fp->rate_min)