diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/hda/intel-dsp-config.c | 97 | ||||
-rw-r--r-- | sound/isa/ad1816a/ad1816a.c | 2 | ||||
-rw-r--r-- | sound/pci/ac97/ac97_patch.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/Kconfig | 4 | ||||
-rw-r--r-- | sound/pci/oxygen/xonar_pcm179x.c | 4 | ||||
-rw-r--r-- | sound/usb/mixer_quirks.c | 418 | ||||
-rw-r--r-- | sound/usb/proc.c | 53 |
7 files changed, 558 insertions, 22 deletions
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index be1df80ed013..1c1fdab2a55f 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -1,10 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz> +#include <linux/acpi.h> #include <linux/bits.h> #include <linux/dmi.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_intel.h> #include <sound/core.h> #include <sound/intel-dsp-config.h> #include <sound/intel-nhlt.h> @@ -14,9 +17,13 @@ static int dsp_driver; module_param(dsp_driver, int, 0444); MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)"); -#define FLAG_SST BIT(0) -#define FLAG_SOF BIT(1) -#define FLAG_SOF_ONLY_IF_DMIC BIT(16) +#define FLAG_SST BIT(0) +#define FLAG_SOF BIT(1) +#define FLAG_SOF_ONLY_IF_DMIC BIT(16) +#define FLAG_SOF_ONLY_IF_SOUNDWIRE BIT(17) + +#define FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE (FLAG_SOF_ONLY_IF_DMIC | \ + FLAG_SOF_ONLY_IF_SOUNDWIRE) struct config_entry { u32 flags; @@ -166,7 +173,7 @@ static const struct config_entry config_table[] = { } }, { - .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = 0x9dc8, }, #endif @@ -187,7 +194,7 @@ static const struct config_entry config_table[] = { } }, { - .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = 0xa348, }, #endif @@ -204,18 +211,50 @@ static const struct config_entry config_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), } }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6") + }, + }, + { + /* early version of SKU 09C6 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983") + }, + }, {} } }, { - .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = 0x02c8, }, #endif /* Cometlake-H */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) { - .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .flags = FLAG_SOF, + .device = 0x06c8, + .dmi_table = (const struct dmi_system_id []) { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"), + }, + }, + {} + } + }, + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = 0x06c8, }, #endif @@ -236,7 +275,7 @@ static const struct config_entry config_table[] = { } }, { - .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = 0x34c8, }, #endif @@ -256,9 +295,8 @@ static const struct config_entry config_table[] = { {} } }, - { - .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, .device = 0xa0c8, }, #endif @@ -303,6 +341,28 @@ static int snd_intel_dsp_check_dmic(struct pci_dev *pci) return ret; } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) +static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) +{ + struct sdw_intel_acpi_info info; + acpi_handle handle; + int ret; + + handle = ACPI_HANDLE(&pci->dev); + + ret = sdw_intel_acpi_scan(handle, &info); + if (ret < 0) + return ret; + + return info.link_mask; +} +#else +static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) +{ + return 0; +} +#endif + int snd_intel_dsp_driver_probe(struct pci_dev *pci) { const struct config_entry *cfg; @@ -336,14 +396,18 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) return SND_INTEL_DSP_DRIVER_ANY; if (cfg->flags & FLAG_SOF) { - if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC) { - if (snd_intel_dsp_check_dmic(pci)) { - dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); - return SND_INTEL_DSP_DRIVER_SOF; - } - } else { + if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE && + snd_intel_dsp_check_soundwire(pci) > 0) { + dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n"); + return SND_INTEL_DSP_DRIVER_SOF; + } + if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC && + snd_intel_dsp_check_dmic(pci)) { + dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); return SND_INTEL_DSP_DRIVER_SOF; } + if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE)) + return SND_INTEL_DSP_DRIVER_SOF; } if (cfg->flags & FLAG_SST) @@ -355,3 +419,4 @@ EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel DSP config driver"); +MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT); diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index ce4c8ba2fa98..ca18fe3ff8a5 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c @@ -54,7 +54,7 @@ MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0).") static const struct pnp_card_device_id snd_ad1816a_pnpids[] = { /* Analog Devices AD1815 */ { .id = "ADS7150", .devs = { { .id = "ADS7150" }, { .id = "ADS7151" } } }, - /* Analog Device AD1816? */ + /* Analog Devices AD1816? */ { .id = "ADS7180", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, /* Analog Devices AD1816A - added by Kenneth Platz <kxp@atl.hp.com> */ { .id = "ADS7181", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index ebf926728c5f..45ef0f52ec55 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1356,7 +1356,7 @@ static int patch_cx20551(struct snd_ac97 *ac97) } /* - * Analog Device AD18xx, AD19xx codecs + * Analog Devices AD18xx, AD19xx codecs */ #ifdef CONFIG_PM static void ad18xx_resume(struct snd_ac97 *ac97) diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index e1d3082a4fe9..7ba542e45a3d 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -99,10 +99,10 @@ comment "Set to Y if you want auto-loading the codec driver" depends on SND_HDA=y && SND_HDA_CODEC_REALTEK=m config SND_HDA_CODEC_ANALOG - tristate "Build Analog Device HD-audio codec support" + tristate "Build Analog Devices HD-audio codec support" select SND_HDA_GENERIC help - Say Y or M here to include Analog Device HD-audio codec support in + Say Y or M here to include Analog Devices HD-audio codec support in snd-hda-intel driver, such as AD1986A. comment "Set to Y if you want auto-loading the codec driver" diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 6a0520c4fb5a..cf801a235df9 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -460,7 +460,7 @@ static void xonar_st_init(struct oxygen *chip) data->generic.anti_pop_delay = 100; data->h6 = chip->model.dac_channels_mixer > 2; - data->has_cs2000 = 1; + data->has_cs2000 = true; data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1; data->broken_i2c = true; @@ -502,7 +502,7 @@ static void xonar_xense_init(struct oxygen *chip) xonar_init_ext_power(chip); data->generic.anti_pop_delay = 100; - data->has_cs2000 = 1; + data->has_cs2000 = true; data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1; oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 02b036b2aefb..f0302ad7f5a0 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -2181,6 +2181,421 @@ static int snd_rme_controls_create(struct usb_mixer_interface *mixer) return 0; } +/* + * RME Babyface Pro (FS) + * + * These devices exposes a couple of DSP functions via request to EP0. + * Switches are available via control registers, while routing is controlled + * by controlling the volume on each possible crossing point. + * Volume control is linear, from -inf (dec. 0) to +6dB (dec. 46341) with + * 0dB being at dec. 32768. + */ +enum { + SND_BBFPRO_CTL_REG1 = 0, + SND_BBFPRO_CTL_REG2 +}; + +#define SND_BBFPRO_CTL_REG_MASK 1 +#define SND_BBFPRO_CTL_IDX_MASK 0xff +#define SND_BBFPRO_CTL_IDX_SHIFT 1 +#define SND_BBFPRO_CTL_VAL_MASK 1 +#define SND_BBFPRO_CTL_VAL_SHIFT 9 +#define SND_BBFPRO_CTL_REG1_CLK_MASTER 0 +#define SND_BBFPRO_CTL_REG1_CLK_OPTICAL 1 +#define SND_BBFPRO_CTL_REG1_SPDIF_PRO 7 +#define SND_BBFPRO_CTL_REG1_SPDIF_EMPH 8 +#define SND_BBFPRO_CTL_REG1_SPDIF_OPTICAL 10 +#define SND_BBFPRO_CTL_REG2_48V_AN1 0 +#define SND_BBFPRO_CTL_REG2_48V_AN2 1 +#define SND_BBFPRO_CTL_REG2_SENS_IN3 2 +#define SND_BBFPRO_CTL_REG2_SENS_IN4 3 +#define SND_BBFPRO_CTL_REG2_PAD_AN1 4 +#define SND_BBFPRO_CTL_REG2_PAD_AN2 5 + +#define SND_BBFPRO_MIXER_IDX_MASK 0x1ff +#define SND_BBFPRO_MIXER_VAL_MASK 0x3ffff +#define SND_BBFPRO_MIXER_VAL_SHIFT 9 +#define SND_BBFPRO_MIXER_VAL_MIN 0 // -inf +#define SND_BBFPRO_MIXER_VAL_MAX 46341 // +6dB + +#define SND_BBFPRO_USBREQ_CTL_REG1 0x10 +#define SND_BBFPRO_USBREQ_CTL_REG2 0x17 +#define SND_BBFPRO_USBREQ_MIXER 0x12 + +static int snd_bbfpro_ctl_update(struct usb_mixer_interface *mixer, u8 reg, + u8 index, u8 value) +{ + int err; + u16 usb_req, usb_idx, usb_val; + struct snd_usb_audio *chip = mixer->chip; + + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + + if (reg == SND_BBFPRO_CTL_REG1) { + usb_req = SND_BBFPRO_USBREQ_CTL_REG1; + if (index == SND_BBFPRO_CTL_REG1_CLK_OPTICAL) { + usb_idx = 3; + usb_val = value ? 3 : 0; + } else { + usb_idx = 1 << index; + usb_val = value ? usb_idx : 0; + } + } else { + usb_req = SND_BBFPRO_USBREQ_CTL_REG2; + usb_idx = 1 << index; + usb_val = value ? usb_idx : 0; + } + + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), usb_req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + usb_val, usb_idx, 0, 0); + + snd_usb_unlock_shutdown(chip); + return err; +} + +static int snd_bbfpro_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 reg, idx, val; + int pv; + + pv = kcontrol->private_value; + reg = pv & SND_BBFPRO_CTL_REG_MASK; + idx = (pv >> SND_BBFPRO_CTL_IDX_SHIFT) & SND_BBFPRO_CTL_IDX_MASK; + val = kcontrol->private_value >> SND_BBFPRO_CTL_VAL_SHIFT; + + if ((reg == SND_BBFPRO_CTL_REG1 && + idx == SND_BBFPRO_CTL_REG1_CLK_OPTICAL) || + (reg == SND_BBFPRO_CTL_REG2 && + (idx == SND_BBFPRO_CTL_REG2_SENS_IN3 || + idx == SND_BBFPRO_CTL_REG2_SENS_IN4))) { + ucontrol->value.enumerated.item[0] = val; + } else { + ucontrol->value.integer.value[0] = val; + } + return 0; +} + +static int snd_bbfpro_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + u8 reg, idx; + int pv; + + pv = kcontrol->private_value; + reg = pv & SND_BBFPRO_CTL_REG_MASK; + idx = (pv >> SND_BBFPRO_CTL_IDX_SHIFT) & SND_BBFPRO_CTL_IDX_MASK; + + if (reg == SND_BBFPRO_CTL_REG1 && + idx == SND_BBFPRO_CTL_REG1_CLK_OPTICAL) { + static const char * const texts[2] = { + "AutoSync", + "Internal" + }; + return snd_ctl_enum_info(uinfo, 1, 2, texts); + } else if (reg == SND_BBFPRO_CTL_REG2 && + (idx == SND_BBFPRO_CTL_REG2_SENS_IN3 || + idx == SND_BBFPRO_CTL_REG2_SENS_IN4)) { + static const char * const texts[2] = { + "-10dBV", + "+4dBu" + }; + return snd_ctl_enum_info(uinfo, 1, 2, texts); + } + + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + return 0; +} + +static int snd_bbfpro_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int err; + u8 reg, idx; + int old_value, pv, val; + + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + struct usb_mixer_interface *mixer = list->mixer; + + pv = kcontrol->private_value; + reg = pv & SND_BBFPRO_CTL_REG_MASK; + idx = (pv >> SND_BBFPRO_CTL_IDX_SHIFT) & SND_BBFPRO_CTL_IDX_MASK; + old_value = (pv >> SND_BBFPRO_CTL_VAL_SHIFT) & SND_BBFPRO_CTL_VAL_MASK; + + if ((reg == SND_BBFPRO_CTL_REG1 && + idx == SND_BBFPRO_CTL_REG1_CLK_OPTICAL) || + (reg == SND_BBFPRO_CTL_REG2 && + (idx == SND_BBFPRO_CTL_REG2_SENS_IN3 || + idx == SND_BBFPRO_CTL_REG2_SENS_IN4))) { + val = ucontrol->value.enumerated.item[0]; + } else { + val = ucontrol->value.integer.value[0]; + } + + if (val > 1) + return -EINVAL; + + if (val == old_value) + return 0; + + kcontrol->private_value = reg + | ((idx & SND_BBFPRO_CTL_IDX_MASK) << SND_BBFPRO_CTL_IDX_SHIFT) + | ((val & SND_BBFPRO_CTL_VAL_MASK) << SND_BBFPRO_CTL_VAL_SHIFT); + + err = snd_bbfpro_ctl_update(mixer, reg, idx, val); + return err < 0 ? err : 1; +} + +static int snd_bbfpro_ctl_resume(struct usb_mixer_elem_list *list) +{ + u8 reg, idx; + int value, pv; + + pv = list->kctl->private_value; + reg = pv & SND_BBFPRO_CTL_REG_MASK; + idx = (pv >> SND_BBFPRO_CTL_IDX_SHIFT) & SND_BBFPRO_CTL_IDX_MASK; + value = (pv >> SND_BBFPRO_CTL_VAL_SHIFT) & SND_BBFPRO_CTL_VAL_MASK; + + return snd_bbfpro_ctl_update(list->mixer, reg, idx, value); +} + +static int snd_bbfpro_vol_update(struct usb_mixer_interface *mixer, u16 index, + u32 value) +{ + struct snd_usb_audio *chip = mixer->chip; + int err; + u16 idx; + u16 usb_idx, usb_val; + u32 v; + + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + + idx = index & SND_BBFPRO_MIXER_IDX_MASK; + // 18 bit linear volume, split so 2 bits end up in index. + v = value & SND_BBFPRO_MIXER_VAL_MASK; + usb_idx = idx | (v & 0x3) << 14; + usb_val = (v >> 2) & 0xffff; + + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), + SND_BBFPRO_USBREQ_MIXER, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, + usb_val, usb_idx, 0, 0); + + snd_usb_unlock_shutdown(chip); + return err; +} + +static int snd_bbfpro_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = + kcontrol->private_value >> SND_BBFPRO_MIXER_VAL_SHIFT; + return 0; +} + +static int snd_bbfpro_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = SND_BBFPRO_MIXER_VAL_MIN; + uinfo->value.integer.max = SND_BBFPRO_MIXER_VAL_MAX; + return 0; +} + +static int snd_bbfpro_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int err; + u16 idx; + u32 new_val, old_value, uvalue; + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + struct usb_mixer_interface *mixer = list->mixer; + + uvalue = ucontrol->value.integer.value[0]; + idx = kcontrol->private_value & SND_BBFPRO_MIXER_IDX_MASK; + old_value = kcontrol->private_value >> SND_BBFPRO_MIXER_VAL_SHIFT; + + if (uvalue > SND_BBFPRO_MIXER_VAL_MAX) + return -EINVAL; + + if (uvalue == old_value) + return 0; + + new_val = uvalue & SND_BBFPRO_MIXER_VAL_MASK; + + kcontrol->private_value = idx + | (new_val << SND_BBFPRO_MIXER_VAL_SHIFT); + + err = snd_bbfpro_vol_update(mixer, idx, new_val); + return err < 0 ? err : 1; +} + +static int snd_bbfpro_vol_resume(struct usb_mixer_elem_list *list) +{ + int pv = list->kctl->private_value; + u16 idx = pv & SND_BBFPRO_MIXER_IDX_MASK; + u32 val = (pv >> SND_BBFPRO_MIXER_VAL_SHIFT) + & SND_BBFPRO_MIXER_VAL_MASK; + return snd_bbfpro_vol_update(list->mixer, idx, val); +} + +// Predfine elements +static const struct snd_kcontrol_new snd_bbfpro_ctl_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .index = 0, + .info = snd_bbfpro_ctl_info, + .get = snd_bbfpro_ctl_get, + .put = snd_bbfpro_ctl_put +}; + +static const struct snd_kcontrol_new snd_bbfpro_vol_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .index = 0, + .info = snd_bbfpro_vol_info, + .get = snd_bbfpro_vol_get, + .put = snd_bbfpro_vol_put +}; + +static int snd_bbfpro_ctl_add(struct usb_mixer_interface *mixer, u8 reg, + u8 index, char *name) +{ + struct snd_kcontrol_new knew = snd_bbfpro_ctl_control; + + knew.name = name; + knew.private_value = (reg & SND_BBFPRO_CTL_REG_MASK) + | ((index & SND_BBFPRO_CTL_IDX_MASK) + << SND_BBFPRO_CTL_IDX_SHIFT); + + return add_single_ctl_with_resume(mixer, 0, snd_bbfpro_ctl_resume, + &knew, NULL); +} + +static int snd_bbfpro_vol_add(struct usb_mixer_interface *mixer, u16 index, + char *name) +{ + struct snd_kcontrol_new knew = snd_bbfpro_vol_control; + + knew.name = name; + knew.private_value = index & SND_BBFPRO_MIXER_IDX_MASK; + + return add_single_ctl_with_resume(mixer, 0, snd_bbfpro_vol_resume, + &knew, NULL); +} + +static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) +{ + int err, i, o; + char name[48]; + + static const char * const input[] = { + "AN1", "AN2", "IN3", "IN4", "AS1", "AS2", "ADAT3", + "ADAT4", "ADAT5", "ADAT6", "ADAT7", "ADAT8"}; + + static const char * const output[] = { + "AN1", "AN2", "PH3", "PH4", "AS1", "AS2", "ADAT3", "ADAT4", + "ADAT5", "ADAT6", "ADAT7", "ADAT8"}; + + for (o = 0 ; o < 12 ; ++o) { + for (i = 0 ; i < 12 ; ++i) { + // Line routing + snprintf(name, sizeof(name), + "%s-%s-%s Playback Volume", + (i < 2 ? "Mic" : "Line"), + input[i], output[o]); + err = snd_bbfpro_vol_add(mixer, (26 * o + i), name); + if (err < 0) + return err; + + // PCM routing... yes, it is output remapping + snprintf(name, sizeof(name), + "PCM-%s-%s Playback Volume", + output[i], output[o]); + err = snd_bbfpro_vol_add(mixer, (26 * o + 12 + i), + name); + if (err < 0) + return err; + } + } + + // Control Reg 1 + err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG1, + SND_BBFPRO_CTL_REG1_CLK_OPTICAL, + "Sample Clock Source"); + if (err < 0) + return err; + + err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG1, + SND_BBFPRO_CTL_REG1_SPDIF_PRO, + "IEC958 Pro Mask"); + if (err < 0) + return err; + + err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG1, + SND_BBFPRO_CTL_REG1_SPDIF_EMPH, + "IEC958 Emphasis"); + if (err < 0) + return err; + + err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG1, + SND_BBFPRO_CTL_REG1_SPDIF_OPTICAL, + "IEC958 Switch"); + if (err < 0) + return err; + + // Control Reg 2 + err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, + SND_BBFPRO_CTL_REG2_48V_AN1, + "Mic-AN1 48V"); + if (err < 0) + return err; + + err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, + SND_BBFPRO_CTL_REG2_48V_AN2, + "Mic-AN2 48V"); + if (err < 0) + return err; + + err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, + SND_BBFPRO_CTL_REG2_SENS_IN3, + "Line-IN3 Sens."); + if (err < 0) + return err; + + err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, + SND_BBFPRO_CTL_REG2_SENS_IN4, + "Line-IN4 Sens."); + if (err < 0) + return err; + + err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, + SND_BBFPRO_CTL_REG2_PAD_AN1, + "Mic-AN1 PAD"); + if (err < 0) + return err; + + err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, + SND_BBFPRO_CTL_REG2_PAD_AN2, + "Mic-AN2 PAD"); + if (err < 0) + return err; + + return 0; +} + int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) { int err = 0; @@ -2282,6 +2697,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x0194f, 0x010c): /* Presonus Studio 1810c */ err = snd_sc1810_init_mixer(mixer); break; + case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */ + err = snd_bbfpro_controls_create(mixer); + break; } return err; diff --git a/sound/usb/proc.c b/sound/usb/proc.c index 4174ad11fca6..889c550c9f29 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -54,6 +54,38 @@ void snd_usb_audio_create_proc(struct snd_usb_audio *chip) proc_audio_usbid_read); } +static const char * const channel_labels[] = { + [SNDRV_CHMAP_NA] = "N/A", + [SNDRV_CHMAP_MONO] = "MONO", + [SNDRV_CHMAP_FL] = "FL", + [SNDRV_CHMAP_FR] = "FR", + [SNDRV_CHMAP_FC] = "FC", + [SNDRV_CHMAP_LFE] = "LFE", + [SNDRV_CHMAP_RL] = "RL", + [SNDRV_CHMAP_RR] = "RR", + [SNDRV_CHMAP_FLC] = "FLC", + [SNDRV_CHMAP_FRC] = "FRC", + [SNDRV_CHMAP_RC] = "RC", + [SNDRV_CHMAP_SL] = "SL", + [SNDRV_CHMAP_SR] = "SR", + [SNDRV_CHMAP_TC] = "TC", + [SNDRV_CHMAP_TFL] = "TFL", + [SNDRV_CHMAP_TFC] = "TFC", + [SNDRV_CHMAP_TFR] = "TFR", + [SNDRV_CHMAP_TRL] = "TRL", + [SNDRV_CHMAP_TRC] = "TRC", + [SNDRV_CHMAP_TRR] = "TRR", + [SNDRV_CHMAP_TFLC] = "TFLC", + [SNDRV_CHMAP_TFRC] = "TFRC", + [SNDRV_CHMAP_LLFE] = "LLFE", + [SNDRV_CHMAP_RLFE] = "RLFE", + [SNDRV_CHMAP_TSL] = "TSL", + [SNDRV_CHMAP_TSR] = "TSR", + [SNDRV_CHMAP_BC] = "BC", + [SNDRV_CHMAP_RLC] = "RLC", + [SNDRV_CHMAP_RRC] = "RRC", +}; + /* * proc interface for list the supported pcm formats */ @@ -97,6 +129,27 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s snd_iprintf(buffer, " Data packet interval: %d us\n", 125 * (1 << fp->datainterval)); snd_iprintf(buffer, " Bits: %d\n", fp->fmt_bits); + + if (fp->dsd_raw) + snd_iprintf(buffer, " DSD raw: DOP=%d, bitrev=%d\n", + fp->dsd_dop, fp->dsd_bitrev); + + if (fp->chmap) { + const struct snd_pcm_chmap_elem *map = fp->chmap; + int c; + + snd_iprintf(buffer, " Channel map:"); + for (c = 0; c < map->channels; c++) { + if (map->map[c] >= ARRAY_SIZE(channel_labels) || + !channel_labels[map->map[c]]) + snd_iprintf(buffer, " --"); + else + snd_iprintf(buffer, " %s", + channel_labels[map->map[c]]); + } + snd_iprintf(buffer, "\n"); + } + // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); // snd_iprintf(buffer, " EP Attribute = %#x\n", fp->attributes); } |