ALSA: usb-audio: Add quirk for RME Digiface USB
[ Upstream commit c032044e96 ]
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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
307ae9e1da
commit
d1bcccee26
+170
-1
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user