Commit 8dc5efe3 authored by Nick Kossifidis's avatar Nick Kossifidis Committed by Takashi Iwai

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: default avatarNick Kossifidis <mickflemm@gmail.com>
Link: https://lore.kernel.org/r/5e47481a.1c69fb81.befb3.8dac@mx.google.comSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 146f6697
......@@ -13,6 +13,7 @@ snd-usb-audio-objs := card.o \
mixer_scarlett.o \
mixer_scarlett_gen2.o \
mixer_us16x08.o \
mixer_s1810c.o \
pcm.o \
power.o \
proc.o \
......
......@@ -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;
......
......@@ -34,6 +34,7 @@
#include "mixer_scarlett.h"
#include "mixer_scarlett_gen2.h"
#include "mixer_us16x08.h"
#include "mixer_s1810c.h"
#include "helper.h"
struct std_mono_table {
......@@ -2277,6 +2278,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
case USB_ID(0x2a39, 0x3fd4): /* RME */
err = snd_rme_controls_create(mixer);
break;
case USB_ID(0x0194f, 0x010c): /* Presonus Studio 1810c */
err = snd_sc1810_init_mixer(mixer);
break;
}
return err;
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Presonus Studio 1810c driver for ALSA
* Copyright (C) 2019 Nick Kossifidis <mickflemm@gmail.com>
*/
int snd_sc1810_init_mixer(struct usb_mixer_interface *mixer);
......@@ -1252,6 +1252,38 @@ static int fasttrackpro_skip_setting_quirk(struct snd_usb_audio *chip,
return 0; /* keep this altsetting */
}
static int s1810c_skip_setting_quirk(struct snd_usb_audio *chip,
int iface, int altno)
{
/*
* Altno settings:
*
* Playback (Interface 1):
* 1: 6 Analog + 2 S/PDIF
* 2: 6 Analog + 2 S/PDIF
* 3: 6 Analog
*
* Capture (Interface 2):
* 1: 8 Analog + 2 S/PDIF + 8 ADAT
* 2: 8 Analog + 2 S/PDIF + 4 ADAT
* 3: 8 Analog
*/
/*
* I'll leave 2 as the default one and
* use device_setup to switch to the
* other two.
*/
if ((chip->setup == 0 || chip->setup > 2) && altno != 2)
return 1;
else if (chip->setup == 1 && altno != 1)
return 1;
else if (chip->setup == 2 && altno != 3)
return 1;
return 0;
}
int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip,
int iface,
int altno)
......@@ -1265,6 +1297,10 @@ int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip,
/* fasttrackpro usb: skip altsets incompatible with device_setup */
if (chip->usb_id == USB_ID(0x0763, 0x2012))
return fasttrackpro_skip_setting_quirk(chip, iface, altno);
/* presonus studio 1810c: skip altsets incompatible with device_setup */
if (chip->usb_id == USB_ID(0x0194f, 0x010c))
return s1810c_skip_setting_quirk(chip, iface, altno);
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment