ALSA: usb-audio: Add quirk for RME Digiface USB

Add trivial support for audio streaming on the RME Digiface USB. Binds
only to the first interface to allow userspace to directly drive the
complex I/O and matrix mixer controls.

Signed-off-by: Cyan Nyan <cyan.vtb@gmail.com>
[Lina: Added 2x/4x sample rate support & boot/format quirks]
Co-developed-by: Asahi Lina <lina@asahilina.net>
Signed-off-by: Asahi Lina <lina@asahilina.net>
Link: https://patch.msgid.link/20240903-rme-digiface-v2-1-71b06c912e97@asahilina.net
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Cyan Nyan 2024-09-03 19:52:29 +09:00 committed by Takashi Iwai
parent 40a024b81d
commit c032044e96
2 changed files with 228 additions and 1 deletions

View File

@ -3604,6 +3604,175 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
{
/* Only claim interface 0 */
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_PRODUCT |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_NUMBER,
.idVendor = 0x2a39,
.idProduct = 0x3f8c,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceNumber = 0,
QUIRK_DRIVER_INFO {
QUIRK_DATA_COMPOSITE {
/*
* Three modes depending on sample rate band,
* with different channel counts for in/out
*/
{
QUIRK_DATA_AUDIOFORMAT(0) {
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.channels = 34, // outputs
.fmt_bits = 24,
.iface = 0,
.altsetting = 1,
.altset_idx = 1,
.endpoint = 0x02,
.ep_idx = 1,
.ep_attr = USB_ENDPOINT_XFER_ISOC |
USB_ENDPOINT_SYNC_ASYNC,
.rates = SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000,
.rate_min = 32000,
.rate_max = 48000,
.nr_rates = 3,
.rate_table = (unsigned int[]) {
32000, 44100, 48000,
},
.sync_ep = 0x81,
.sync_iface = 0,
.sync_altsetting = 1,
.sync_ep_idx = 0,
.implicit_fb = 1,
},
},
{
QUIRK_DATA_AUDIOFORMAT(0) {
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.channels = 18, // outputs
.fmt_bits = 24,
.iface = 0,
.altsetting = 1,
.altset_idx = 1,
.endpoint = 0x02,
.ep_idx = 1,
.ep_attr = USB_ENDPOINT_XFER_ISOC |
USB_ENDPOINT_SYNC_ASYNC,
.rates = SNDRV_PCM_RATE_64000 |
SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000,
.rate_min = 64000,
.rate_max = 96000,
.nr_rates = 3,
.rate_table = (unsigned int[]) {
64000, 88200, 96000,
},
.sync_ep = 0x81,
.sync_iface = 0,
.sync_altsetting = 1,
.sync_ep_idx = 0,
.implicit_fb = 1,
},
},
{
QUIRK_DATA_AUDIOFORMAT(0) {
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.channels = 10, // outputs
.fmt_bits = 24,
.iface = 0,
.altsetting = 1,
.altset_idx = 1,
.endpoint = 0x02,
.ep_idx = 1,
.ep_attr = USB_ENDPOINT_XFER_ISOC |
USB_ENDPOINT_SYNC_ASYNC,
.rates = SNDRV_PCM_RATE_KNOT |
SNDRV_PCM_RATE_176400 |
SNDRV_PCM_RATE_192000,
.rate_min = 128000,
.rate_max = 192000,
.nr_rates = 3,
.rate_table = (unsigned int[]) {
128000, 176400, 192000,
},
.sync_ep = 0x81,
.sync_iface = 0,
.sync_altsetting = 1,
.sync_ep_idx = 0,
.implicit_fb = 1,
},
},
{
QUIRK_DATA_AUDIOFORMAT(0) {
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.channels = 32, // inputs
.fmt_bits = 24,
.iface = 0,
.altsetting = 1,
.altset_idx = 1,
.endpoint = 0x81,
.ep_attr = USB_ENDPOINT_XFER_ISOC |
USB_ENDPOINT_SYNC_ASYNC,
.rates = SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000,
.rate_min = 32000,
.rate_max = 48000,
.nr_rates = 3,
.rate_table = (unsigned int[]) {
32000, 44100, 48000,
}
}
},
{
QUIRK_DATA_AUDIOFORMAT(0) {
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.channels = 16, // inputs
.fmt_bits = 24,
.iface = 0,
.altsetting = 1,
.altset_idx = 1,
.endpoint = 0x81,
.ep_attr = USB_ENDPOINT_XFER_ISOC |
USB_ENDPOINT_SYNC_ASYNC,
.rates = SNDRV_PCM_RATE_64000 |
SNDRV_PCM_RATE_88200 |
SNDRV_PCM_RATE_96000,
.rate_min = 64000,
.rate_max = 96000,
.nr_rates = 3,
.rate_table = (unsigned int[]) {
64000, 88200, 96000,
}
}
},
{
QUIRK_DATA_AUDIOFORMAT(0) {
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.channels = 8, // inputs
.fmt_bits = 24,
.iface = 0,
.altsetting = 1,
.altset_idx = 1,
.endpoint = 0x81,
.ep_attr = USB_ENDPOINT_XFER_ISOC |
USB_ENDPOINT_SYNC_ASYNC,
.rates = SNDRV_PCM_RATE_KNOT |
SNDRV_PCM_RATE_176400 |
SNDRV_PCM_RATE_192000,
.rate_min = 128000,
.rate_max = 192000,
.nr_rates = 3,
.rate_table = (unsigned int[]) {
128000, 176400, 192000,
}
}
},
QUIRK_COMPOSITE_END
}
}
},
#undef USB_DEVICE_VENDOR_SPEC
#undef USB_AUDIO_DEVICE

View File

@ -1389,6 +1389,27 @@ static int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev)
return 0;
}
static int snd_usb_rme_digiface_boot_quirk(struct usb_device *dev)
{
/* Disable mixer, internal clock, all outputs ADAT, 48kHz, TMS off */
snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
16, 0x40, 0x2410, 0x7fff, NULL, 0);
snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
18, 0x40, 0x0104, 0xffff, NULL, 0);
/* Disable loopback for all inputs */
for (int ch = 0; ch < 32; ch++)
snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
22, 0x40, 0x400, ch, NULL, 0);
/* Unity gain for all outputs */
for (int ch = 0; ch < 34; ch++)
snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
21, 0x40, 0x9000, 0x100 + ch, NULL, 0);
return 0;
}
/*
* Setup quirks
*/
@ -1616,6 +1637,8 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
get_iface_desc(intf->altsetting)->bInterfaceNumber < 3)
return snd_usb_motu_microbookii_boot_quirk(dev);
break;
case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */
return snd_usb_rme_digiface_boot_quirk(dev);
}
return 0;
@ -1771,6 +1794,38 @@ static void mbox3_set_format_quirk(struct snd_usb_substream *subs,
dev_warn(&subs->dev->dev, "MBOX3: Couldn't set the sample rate");
}
static const int rme_digiface_rate_table[] = {
32000, 44100, 48000, 0,
64000, 88200, 96000, 0,
128000, 176400, 192000, 0,
};
static int rme_digiface_set_format_quirk(struct snd_usb_substream *subs)
{
unsigned int cur_rate = subs->data_endpoint->cur_rate;
u16 val;
int speed_mode;
int id;
for (id = 0; id < ARRAY_SIZE(rme_digiface_rate_table); id++) {
if (rme_digiface_rate_table[id] == cur_rate)
break;
}
if (id >= ARRAY_SIZE(rme_digiface_rate_table))
return -EINVAL;
/* 2, 3, 4 for 1x, 2x, 4x */
speed_mode = (id >> 2) + 2;
val = (id << 3) | (speed_mode << 12);
/* Set the sample rate */
snd_usb_ctl_msg(subs->stream->chip->dev,
usb_sndctrlpipe(subs->stream->chip->dev, 0),
16, 0x40, val, 0x7078, NULL, 0);
return 0;
}
void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
const struct audioformat *fmt)
{
@ -1795,6 +1850,9 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
case USB_ID(0x0dba, 0x5000):
mbox3_set_format_quirk(subs, fmt); /* Digidesign Mbox 3 */
break;
case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */
rme_digiface_set_format_quirk(subs);
break;
}
}