mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
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:
parent
40a024b81d
commit
c032044e96
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user