ALSA: usb-audio: Add support for Presonus Studio 1810c
This patch adds support for Presonus Studio 1810c, a usb interface
that's UAC2 compliant with a few quirks and a few extra hw-specific
controls. I've tested all 3 altsettings and the added switch
controls and they work as expected.
More infos on the card:
https://www.presonus.com/products/Studio-1810c
Note that this work is based on packet inspection with
usbmon. I just wanted to get this card to work for using
it on our open-source radio station:
https://github.com/UoC-Radio
v2 address issues reported by Takashi:
* Properly get/set enum type controls
* Prevent race condition on switch_get/set
* Various control naming changes
* Various coding style fixes
v3 improve readability of sample rate filtering
and some other minor changes.
Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
Link: https://lore.kernel.org/r/5e47481a.1c69fb81.befb3.8dac@mx.google.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/usb/format.c b/sound/usb/format.c
index 9260136..51e9fca 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -226,6 +226,36 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
return 0;
}
+
+/*
+ * Presonus Studio 1810c supports a limited set of sampling
+ * rates per altsetting but reports the full set each time.
+ * If we don't filter out the unsupported rates and attempt
+ * to configure the card, it will hang refusing to do any
+ * further audio I/O until a hard reset is performed.
+ *
+ * The list of supported rates per altsetting (set of available
+ * I/O channels) is described in the owner's manual, section 2.2.
+ */
+static bool s1810c_valid_sample_rate(struct audioformat *fp,
+ unsigned int rate)
+{
+ switch (fp->altsetting) {
+ case 1:
+ /* All ADAT ports available */
+ return rate <= 48000;
+ case 2:
+ /* Half of ADAT ports available */
+ return (rate == 88200 || rate == 96000);
+ case 3:
+ /* Analog I/O only (no S/PDIF nor ADAT) */
+ return rate >= 176400;
+ default:
+ return false;
+ }
+ return false;
+}
+
/*
* 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
@@ -262,6 +292,12 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
}
for (rate = min; rate <= max; rate += res) {
+
+ /* Filter out invalid rates on Presonus Studio 1810c */
+ if (chip->usb_id == USB_ID(0x0194f, 0x010c) &&
+ !s1810c_valid_sample_rate(fp, rate))
+ goto skip_rate;
+
if (fp->rate_table)
fp->rate_table[nr_rates] = rate;
if (!fp->rate_min || rate < fp->rate_min)
@@ -276,6 +312,7 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
break;
}
+skip_rate:
/* avoid endless loop */
if (res == 0)
break;