Commit c032044e authored by Cyan Nyan's avatar Cyan Nyan Committed by Takashi Iwai

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: default avatarCyan Nyan <cyan.vtb@gmail.com>
[Lina: Added 2x/4x sample rate support & boot/format quirks]
Co-developed-by: default avatarAsahi Lina <lina@asahilina.net>
Signed-off-by: default avatarAsahi Lina <lina@asahilina.net>
Link: https://patch.msgid.link/20240903-rme-digiface-v2-1-71b06c912e97@asahilina.netSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 40a024b8
......@@ -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;
}
}
......
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