diff options
Diffstat (limited to 'sound/usb/mixer_quirks.c')
-rw-r--r-- | sound/usb/mixer_quirks.c | 885 |
1 files changed, 822 insertions, 63 deletions
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 065a4be0d771..aad205df93b2 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -14,6 +14,7 @@ * Przemek Rudy (prudy1@o2.pl) */ +#include <linux/bitfield.h> #include <linux/hid.h> #include <linux/init.h> #include <linux/math64.h> @@ -37,6 +38,7 @@ #include "mixer_us16x08.h" #include "mixer_s1810c.h" #include "helper.h" +#include "fcp.h" struct std_mono_table { unsigned int unitid, control, cmask; @@ -1043,7 +1045,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer, err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, pval & 0xff00, - snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8), + snd_usb_ctrl_intf(mixer->hostif) | ((pval & 0xff) << 8), value, 2); if (err < 0) return err; @@ -1077,7 +1079,7 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list) UAC_SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, pval & 0xff00, - snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8), + snd_usb_ctrl_intf(list->mixer->hostif) | ((pval & 0xff) << 8), value, 2); snd_usb_unlock_shutdown(chip); return err; @@ -1139,7 +1141,7 @@ static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) for (out = 0; out < 8; out++) { control = out + 1; for (in = 0; in < 8; in++) { - cmask = 1 << in; + cmask = BIT(in); snprintf(name, sizeof(name), "AIn%d - Out%d Capture Volume", in + 1, out + 1); @@ -1150,7 +1152,7 @@ static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) return err; } for (in = 8; in < 16; in++) { - cmask = 1 << in; + cmask = BIT(in); snprintf(name, sizeof(name), "DIn%d - Out%d Playback Volume", in - 7, out + 1); @@ -1215,7 +1217,7 @@ static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer) const unsigned int control = 7; for (ch = 0; ch < 4; ++ch) { - cmask = 1 << ch; + cmask = BIT(ch); snprintf(name, sizeof(name), "Effect Return %d Volume", ch + 1); err = snd_create_std_mono_ctl(mixer, id, control, @@ -1239,7 +1241,7 @@ static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) const unsigned int control = 9; for (ch = 0; ch < 8; ++ch) { - cmask = 1 << ch; + cmask = BIT(ch); snprintf(name, sizeof(name), "Effect Send AIn%d Volume", ch + 1); err = snd_create_std_mono_ctl(mixer, id, control, cmask, @@ -1249,7 +1251,7 @@ static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) return err; } for (ch = 8; ch < 16; ++ch) { - cmask = 1 << ch; + cmask = BIT(ch); snprintf(name, sizeof(name), "Effect Send DIn%d Volume", ch - 7); err = snd_create_std_mono_ctl(mixer, id, control, cmask, @@ -1352,7 +1354,7 @@ static int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer) chan - num_outs + 1, out + 1); } - cmask = (out == 0) ? 0 : 1 << (out - 1); + cmask = (out == 0) ? 0 : BIT(out - 1); offset = chan * num_outs; err = snd_create_std_mono_ctl_offset(mixer, id, control, cmask, val_type, offset, name, @@ -1438,7 +1440,7 @@ static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer) chan - num_outs + 1); } - cmask = (chan == 0) ? 0 : 1 << (chan - 1); + cmask = (chan == 0) ? 0 : BIT(chan - 1); err = snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, name, &snd_usb_mixer_vol_tlv); @@ -1480,7 +1482,7 @@ static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer chan + 1); cmask = (chan == 0) ? 0 : - 1 << (chan + (chan % 2) * num_outs - 1); + BIT(chan + (chan % 2) * num_outs - 1); err = snd_create_std_mono_ctl_offset(mixer, id, control, cmask, val_type, offset, name, &snd_usb_mixer_vol_tlv); @@ -1998,7 +2000,7 @@ static int realtek_hda_get(struct snd_usb_audio *chip, u32 cmd, u32 *value) static int realtek_ctl_connector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; + struct usb_mixer_elem_info *cval = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = cval->head.mixer->chip; u32 pv = kcontrol->private_value; u32 node_id = pv & 0xff; @@ -2115,24 +2117,25 @@ static int dell_dock_mixer_create(struct usb_mixer_interface *mixer) return 0; } -static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id) +static void dell_dock_init_vol(struct usb_mixer_interface *mixer, int ch, int id) { + struct snd_usb_audio *chip = mixer->chip; u16 buf = 0; snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, (UAC_FU_VOLUME << 8) | ch, - snd_usb_ctrl_intf(chip) | (id << 8), + snd_usb_ctrl_intf(mixer->hostif) | (id << 8), &buf, 2); } static int dell_dock_mixer_init(struct usb_mixer_interface *mixer) { /* fix to 0dB playback volumes */ - dell_dock_init_vol(mixer->chip, 1, 16); - dell_dock_init_vol(mixer->chip, 2, 16); - dell_dock_init_vol(mixer->chip, 1, 19); - dell_dock_init_vol(mixer->chip, 2, 19); + dell_dock_init_vol(mixer, 1, 16); + dell_dock_init_vol(mixer, 2, 16); + dell_dock_init_vol(mixer, 1, 19); + dell_dock_init_vol(mixer, 2, 19); return 0; } @@ -2541,14 +2544,23 @@ enum { #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_MAIN_OUT_CH_OFFSET 992 +#define SND_BBFPRO_MIXER_IDX_MASK 0x3ff #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 65536 // +6dB +#define SND_BBFPRO_GAIN_CHANNEL_MASK 0x03 +#define SND_BBFPRO_GAIN_CHANNEL_SHIFT 7 +#define SND_BBFPRO_GAIN_VAL_MASK 0x7f +#define SND_BBFPRO_GAIN_VAL_MIN 0 +#define SND_BBFPRO_GAIN_VAL_MIC_MAX 65 +#define SND_BBFPRO_GAIN_VAL_LINE_MAX 18 // 9db in 0.5db incraments + #define SND_BBFPRO_USBREQ_CTL_REG1 0x10 #define SND_BBFPRO_USBREQ_CTL_REG2 0x17 +#define SND_BBFPRO_USBREQ_GAIN 0x1a #define SND_BBFPRO_USBREQ_MIXER 0x12 static int snd_bbfpro_ctl_update(struct usb_mixer_interface *mixer, u8 reg, @@ -2568,12 +2580,12 @@ static int snd_bbfpro_ctl_update(struct usb_mixer_interface *mixer, u8 reg, usb_idx = 3; usb_val = value ? 3 : 0; } else { - usb_idx = 1 << index; + usb_idx = BIT(index); usb_val = value ? usb_idx : 0; } } else { usb_req = SND_BBFPRO_USBREQ_CTL_REG2; - usb_idx = 1 << index; + usb_idx = BIT(index); usb_val = value ? usb_idx : 0; } @@ -2695,6 +2707,114 @@ static int snd_bbfpro_ctl_resume(struct usb_mixer_elem_list *list) return snd_bbfpro_ctl_update(list->mixer, reg, idx, value); } +static int snd_bbfpro_gain_update(struct usb_mixer_interface *mixer, + u8 channel, u8 gain) +{ + int err; + struct snd_usb_audio *chip = mixer->chip; + + if (channel < 2) { + // XLR preamp: 3-bit fine, 5-bit coarse; special case >60 + if (gain < 60) + gain = ((gain % 3) << 5) | (gain / 3); + else + gain = ((gain % 6) << 5) | (60 / 3); + } + + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), + SND_BBFPRO_USBREQ_GAIN, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + gain, channel, NULL, 0); + + snd_usb_unlock_shutdown(chip); + return err; +} + +static int snd_bbfpro_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int value = kcontrol->private_value & SND_BBFPRO_GAIN_VAL_MASK; + + ucontrol->value.integer.value[0] = value; + return 0; +} + +static int snd_bbfpro_gain_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int pv, channel; + + pv = kcontrol->private_value; + channel = (pv >> SND_BBFPRO_GAIN_CHANNEL_SHIFT) & + SND_BBFPRO_GAIN_CHANNEL_MASK; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = SND_BBFPRO_GAIN_VAL_MIN; + + if (channel < 2) + uinfo->value.integer.max = SND_BBFPRO_GAIN_VAL_MIC_MAX; + else + uinfo->value.integer.max = SND_BBFPRO_GAIN_VAL_LINE_MAX; + + return 0; +} + +static int snd_bbfpro_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int pv, channel, old_value, value, err; + + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + struct usb_mixer_interface *mixer = list->mixer; + + pv = kcontrol->private_value; + channel = (pv >> SND_BBFPRO_GAIN_CHANNEL_SHIFT) & + SND_BBFPRO_GAIN_CHANNEL_MASK; + old_value = pv & SND_BBFPRO_GAIN_VAL_MASK; + value = ucontrol->value.integer.value[0]; + + if (value < SND_BBFPRO_GAIN_VAL_MIN) + return -EINVAL; + + if (channel < 2) { + if (value > SND_BBFPRO_GAIN_VAL_MIC_MAX) + return -EINVAL; + } else { + if (value > SND_BBFPRO_GAIN_VAL_LINE_MAX) + return -EINVAL; + } + + if (value == old_value) + return 0; + + err = snd_bbfpro_gain_update(mixer, channel, value); + if (err < 0) + return err; + + kcontrol->private_value = + (channel << SND_BBFPRO_GAIN_CHANNEL_SHIFT) | value; + return 1; +} + +static int snd_bbfpro_gain_resume(struct usb_mixer_elem_list *list) +{ + int pv, channel, value; + struct snd_kcontrol *kctl = list->kctl; + + pv = kctl->private_value; + channel = (pv >> SND_BBFPRO_GAIN_CHANNEL_SHIFT) & + SND_BBFPRO_GAIN_CHANNEL_MASK; + value = pv & SND_BBFPRO_GAIN_VAL_MASK; + + return snd_bbfpro_gain_update(list->mixer, channel, value); +} + static int snd_bbfpro_vol_update(struct usb_mixer_interface *mixer, u16 index, u32 value) { @@ -2790,6 +2910,15 @@ static const struct snd_kcontrol_new snd_bbfpro_ctl_control = { .put = snd_bbfpro_ctl_put }; +static const struct snd_kcontrol_new snd_bbfpro_gain_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .index = 0, + .info = snd_bbfpro_gain_info, + .get = snd_bbfpro_gain_get, + .put = snd_bbfpro_gain_put +}; + static const struct snd_kcontrol_new snd_bbfpro_vol_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -2813,6 +2942,18 @@ static int snd_bbfpro_ctl_add(struct usb_mixer_interface *mixer, u8 reg, &knew, NULL); } +static int snd_bbfpro_gain_add(struct usb_mixer_interface *mixer, u8 channel, + char *name) +{ + struct snd_kcontrol_new knew = snd_bbfpro_gain_control; + + knew.name = name; + knew.private_value = channel << SND_BBFPRO_GAIN_CHANNEL_SHIFT; + + return add_single_ctl_with_resume(mixer, 0, snd_bbfpro_gain_resume, + &knew, NULL); +} + static int snd_bbfpro_vol_add(struct usb_mixer_interface *mixer, u16 index, char *name) { @@ -2860,6 +3001,29 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) } } + // Main out volume + for (i = 0 ; i < 12 ; ++i) { + snprintf(name, sizeof(name), "Main-Out %s", output[i]); + // Main outs are offset to 992 + err = snd_bbfpro_vol_add(mixer, + i + SND_BBFPRO_MIXER_MAIN_OUT_CH_OFFSET, + name); + if (err < 0) + return err; + } + + // Input gain + for (i = 0 ; i < 4 ; ++i) { + if (i < 2) + snprintf(name, sizeof(name), "Mic-%s Gain", input[i]); + else + snprintf(name, sizeof(name), "Line-%s Gain", input[i]); + + err = snd_bbfpro_gain_add(mixer, 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, @@ -2926,7 +3090,416 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) } /* - * Pioneer DJ DJM Mixers + * RME Digiface USB + */ + +#define RME_DIGIFACE_READ_STATUS 17 +#define RME_DIGIFACE_STATUS_REG0L 0 +#define RME_DIGIFACE_STATUS_REG0H 1 +#define RME_DIGIFACE_STATUS_REG1L 2 +#define RME_DIGIFACE_STATUS_REG1H 3 +#define RME_DIGIFACE_STATUS_REG2L 4 +#define RME_DIGIFACE_STATUS_REG2H 5 +#define RME_DIGIFACE_STATUS_REG3L 6 +#define RME_DIGIFACE_STATUS_REG3H 7 + +#define RME_DIGIFACE_CTL_REG1 16 +#define RME_DIGIFACE_CTL_REG2 18 + +/* Reg is overloaded, 0-7 for status halfwords or 16 or 18 for control registers */ +#define RME_DIGIFACE_REGISTER(reg, mask) (((reg) << 16) | (mask)) +#define RME_DIGIFACE_INVERT BIT(31) + +/* Nonconst helpers */ +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + +static int snd_rme_digiface_write_reg(struct snd_kcontrol *kcontrol, int item, u16 mask, u16 val) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + struct snd_usb_audio *chip = list->mixer->chip; + struct usb_device *dev = chip->dev; + int err; + + err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + item, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + val, mask, NULL, 0); + if (err < 0) + dev_err(&dev->dev, + "unable to issue control set request %d (ret = %d)", + item, err); + return err; +} + +static int snd_rme_digiface_read_status(struct snd_kcontrol *kcontrol, u32 status[4]) +{ + struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); + struct snd_usb_audio *chip = list->mixer->chip; + struct usb_device *dev = chip->dev; + __le32 buf[4]; + int err; + + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + RME_DIGIFACE_READ_STATUS, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, 0, + buf, sizeof(buf)); + if (err < 0) { + dev_err(&dev->dev, + "unable to issue status read request (ret = %d)", + err); + } else { + for (int i = 0; i < ARRAY_SIZE(buf); i++) + status[i] = le32_to_cpu(buf[i]); + } + return err; +} + +static int snd_rme_digiface_get_status_val(struct snd_kcontrol *kcontrol) +{ + int err; + u32 status[4]; + bool invert = kcontrol->private_value & RME_DIGIFACE_INVERT; + u8 reg = (kcontrol->private_value >> 16) & 0xff; + u16 mask = kcontrol->private_value & 0xffff; + u16 val; + + err = snd_rme_digiface_read_status(kcontrol, status); + if (err < 0) + return err; + + switch (reg) { + /* Status register halfwords */ + case RME_DIGIFACE_STATUS_REG0L ... RME_DIGIFACE_STATUS_REG3H: + break; + case RME_DIGIFACE_CTL_REG1: /* Control register 1, present in halfword 3L */ + reg = RME_DIGIFACE_STATUS_REG3L; + break; + case RME_DIGIFACE_CTL_REG2: /* Control register 2, present in halfword 3H */ + reg = RME_DIGIFACE_STATUS_REG3H; + break; + default: + return -EINVAL; + } + + if (reg & 1) + val = status[reg >> 1] >> 16; + else + val = status[reg >> 1] & 0xffff; + + if (invert) + val ^= mask; + + return field_get(mask, val); +} + +static int snd_rme_digiface_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int freq = snd_rme_digiface_get_status_val(kcontrol); + + if (freq < 0) + return freq; + if (freq >= ARRAY_SIZE(snd_rme_rate_table)) + return -EIO; + + ucontrol->value.integer.value[0] = snd_rme_rate_table[freq]; + return 0; +} + +static int snd_rme_digiface_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int val = snd_rme_digiface_get_status_val(kcontrol); + + if (val < 0) + return val; + + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int snd_rme_digiface_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + bool invert = kcontrol->private_value & RME_DIGIFACE_INVERT; + u8 reg = (kcontrol->private_value >> 16) & 0xff; + u16 mask = kcontrol->private_value & 0xffff; + u16 val = field_prep(mask, ucontrol->value.enumerated.item[0]); + + if (invert) + val ^= mask; + + return snd_rme_digiface_write_reg(kcontrol, reg, mask, val); +} + +static int snd_rme_digiface_current_sync_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = snd_rme_digiface_enum_get(kcontrol, ucontrol); + + /* 7 means internal for current sync */ + if (ucontrol->value.enumerated.item[0] == 7) + ucontrol->value.enumerated.item[0] = 0; + + return ret; +} + +static int snd_rme_digiface_sync_state_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u32 status[4]; + int err; + bool valid, sync; + + err = snd_rme_digiface_read_status(kcontrol, status); + if (err < 0) + return err; + + valid = status[0] & BIT(kcontrol->private_value); + sync = status[0] & BIT(5 + kcontrol->private_value); + + if (!valid) + ucontrol->value.enumerated.item[0] = SND_RME_CLOCK_NOLOCK; + else if (!sync) + ucontrol->value.enumerated.item[0] = SND_RME_CLOCK_LOCK; + else + ucontrol->value.enumerated.item[0] = SND_RME_CLOCK_SYNC; + return 0; +} + + +static int snd_rme_digiface_format_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const format[] = { + "ADAT", "S/PDIF" + }; + + return snd_ctl_enum_info(uinfo, 1, + ARRAY_SIZE(format), format); +} + + +static int snd_rme_digiface_sync_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const sync_sources[] = { + "Internal", "Input 1", "Input 2", "Input 3", "Input 4" + }; + + return snd_ctl_enum_info(uinfo, 1, + ARRAY_SIZE(sync_sources), sync_sources); +} + +static int snd_rme_digiface_rate_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 = 0; + uinfo->value.integer.max = 200000; + uinfo->value.integer.step = 0; + return 0; +} + +static const struct snd_kcontrol_new snd_rme_digiface_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input 1 Sync", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_sync_state_info, + .get = snd_rme_digiface_sync_state_get, + .private_value = 0, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input 1 Format", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_digiface_format_info, + .get = snd_rme_digiface_enum_get, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0H, BIT(0)) | + RME_DIGIFACE_INVERT, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input 1 Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_digiface_rate_info, + .get = snd_rme_digiface_rate_get, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(3, 0)), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input 2 Sync", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_sync_state_info, + .get = snd_rme_digiface_sync_state_get, + .private_value = 1, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input 2 Format", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_digiface_format_info, + .get = snd_rme_digiface_enum_get, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, BIT(13)) | + RME_DIGIFACE_INVERT, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input 2 Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_digiface_rate_info, + .get = snd_rme_digiface_rate_get, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(7, 4)), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input 3 Sync", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_sync_state_info, + .get = snd_rme_digiface_sync_state_get, + .private_value = 2, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input 3 Format", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_digiface_format_info, + .get = snd_rme_digiface_enum_get, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, BIT(14)) | + RME_DIGIFACE_INVERT, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input 3 Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_digiface_rate_info, + .get = snd_rme_digiface_rate_get, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(11, 8)), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input 4 Sync", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_sync_state_info, + .get = snd_rme_digiface_sync_state_get, + .private_value = 3, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input 4 Format", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_digiface_format_info, + .get = snd_rme_digiface_enum_get, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, GENMASK(15, 12)) | + RME_DIGIFACE_INVERT, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input 4 Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_digiface_rate_info, + .get = snd_rme_digiface_rate_get, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1L, GENMASK(3, 0)), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Output 1 Format", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_rme_digiface_format_info, + .get = snd_rme_digiface_enum_get, + .put = snd_rme_digiface_enum_put, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(0)), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Output 2 Format", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_rme_digiface_format_info, + .get = snd_rme_digiface_enum_get, + .put = snd_rme_digiface_enum_put, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(1)), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Output 3 Format", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_rme_digiface_format_info, + .get = snd_rme_digiface_enum_get, + .put = snd_rme_digiface_enum_put, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(3)), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Output 4 Format", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_rme_digiface_format_info, + .get = snd_rme_digiface_enum_get, + .put = snd_rme_digiface_enum_put, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG2, BIT(4)), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Sync Source", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_rme_digiface_sync_source_info, + .get = snd_rme_digiface_enum_get, + .put = snd_rme_digiface_enum_put, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG1, GENMASK(2, 0)), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Current Sync Source", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_digiface_sync_source_info, + .get = snd_rme_digiface_current_sync_get, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG0L, GENMASK(12, 10)), + }, + { + /* + * This is writeable, but it is only set by the PCM rate. + * Mixer apps currently need to drive the mixer using raw USB requests, + * so they can also change this that way to configure the rate for + * stand-alone operation when the PCM is closed. + */ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "System Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_rate_info, + .get = snd_rme_digiface_rate_get, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_CTL_REG1, GENMASK(6, 3)), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Current Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_rme_rate_info, + .get = snd_rme_digiface_rate_get, + .private_value = RME_DIGIFACE_REGISTER(RME_DIGIFACE_STATUS_REG1H, GENMASK(7, 4)), + } +}; + +static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(snd_rme_digiface_controls); ++i) { + err = add_single_ctl_with_resume(mixer, 0, + NULL, + &snd_rme_digiface_controls[i], + NULL); + if (err < 0) + return err; + } + + return 0; +} + +/* + * Pioneer DJ / AlphaTheta DJM Mixers * * These devices generally have options for soft-switching the playback and * capture sources in addition to the recording level. Although different @@ -2943,17 +3516,26 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) #define SND_DJM_CAP_CDLINE 0x01 #define SND_DJM_CAP_DIGITAL 0x02 #define SND_DJM_CAP_PHONO 0x03 +#define SND_DJM_CAP_PREFADER 0x05 #define SND_DJM_CAP_PFADER 0x06 #define SND_DJM_CAP_XFADERA 0x07 #define SND_DJM_CAP_XFADERB 0x08 #define SND_DJM_CAP_MIC 0x09 #define SND_DJM_CAP_AUX 0x0d #define SND_DJM_CAP_RECOUT 0x0a +#define SND_DJM_CAP_RECOUT_NOMIC 0x0e #define SND_DJM_CAP_NONE 0x0f +#define SND_DJM_CAP_FXSEND 0x10 #define SND_DJM_CAP_CH1PFADER 0x11 #define SND_DJM_CAP_CH2PFADER 0x12 #define SND_DJM_CAP_CH3PFADER 0x13 #define SND_DJM_CAP_CH4PFADER 0x14 +#define SND_DJM_CAP_EXT1SEND 0x21 +#define SND_DJM_CAP_EXT2SEND 0x22 +#define SND_DJM_CAP_CH1PREFADER 0x31 +#define SND_DJM_CAP_CH2PREFADER 0x32 +#define SND_DJM_CAP_CH3PREFADER 0x33 +#define SND_DJM_CAP_CH4PREFADER 0x34 // Playback types #define SND_DJM_PB_CH1 0x00 @@ -2979,6 +3561,8 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) #define SND_DJM_900NXS2_IDX 0x3 #define SND_DJM_750MK2_IDX 0x4 #define SND_DJM_450_IDX 0x5 +#define SND_DJM_A9_IDX 0x6 +#define SND_DJM_V10_IDX 0x7 #define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \ @@ -3007,7 +3591,7 @@ struct snd_djm_ctl { u16 wIndex; }; -static const char *snd_djm_get_label_caplevel(u16 wvalue) +static const char *snd_djm_get_label_caplevel_common(u16 wvalue) { switch (wvalue) { case 0x0000: return "-19dB"; @@ -3018,6 +3602,20 @@ static const char *snd_djm_get_label_caplevel(u16 wvalue) } }; +// Models like DJM-A9 or DJM-V10 have different capture levels than others +static const char *snd_djm_get_label_caplevel_high(u16 wvalue) +{ + switch (wvalue) { + case 0x0000: return "+15dB"; + case 0x0100: return "+12dB"; + case 0x0200: return "+9dB"; + case 0x0300: return "+6dB"; + case 0x0400: return "+3dB"; + case 0x0500: return "0dB"; + default: return NULL; + } +}; + static const char *snd_djm_get_label_cap_common(u16 wvalue) { switch (wvalue & 0x00ff) { @@ -3030,12 +3628,20 @@ static const char *snd_djm_get_label_cap_common(u16 wvalue) case SND_DJM_CAP_XFADERB: return "Cross Fader B"; case SND_DJM_CAP_MIC: return "Mic"; case SND_DJM_CAP_RECOUT: return "Rec Out"; + case SND_DJM_CAP_RECOUT_NOMIC: return "Rec Out without Mic"; case SND_DJM_CAP_AUX: return "Aux"; case SND_DJM_CAP_NONE: return "None"; + case SND_DJM_CAP_FXSEND: return "FX SEND"; + case SND_DJM_CAP_CH1PREFADER: return "Pre Fader Ch1"; + case SND_DJM_CAP_CH2PREFADER: return "Pre Fader Ch2"; + case SND_DJM_CAP_CH3PREFADER: return "Pre Fader Ch3"; + case SND_DJM_CAP_CH4PREFADER: return "Pre Fader Ch4"; case SND_DJM_CAP_CH1PFADER: return "Post Fader Ch1"; case SND_DJM_CAP_CH2PFADER: return "Post Fader Ch2"; case SND_DJM_CAP_CH3PFADER: return "Post Fader Ch3"; case SND_DJM_CAP_CH4PFADER: return "Post Fader Ch4"; + case SND_DJM_CAP_EXT1SEND: return "EXT1 SEND"; + case SND_DJM_CAP_EXT2SEND: return "EXT2 SEND"; default: return NULL; } }; @@ -3051,6 +3657,15 @@ static const char *snd_djm_get_label_cap_850(u16 wvalue) } }; +static const char *snd_djm_get_label_caplevel(u8 device_idx, u16 wvalue) +{ + switch (device_idx) { + case SND_DJM_A9_IDX: return snd_djm_get_label_caplevel_high(wvalue); + case SND_DJM_V10_IDX: return snd_djm_get_label_caplevel_high(wvalue); + default: return snd_djm_get_label_caplevel_common(wvalue); + } +}; + static const char *snd_djm_get_label_cap(u8 device_idx, u16 wvalue) { switch (device_idx) { @@ -3072,7 +3687,7 @@ static const char *snd_djm_get_label_pb(u16 wvalue) static const char *snd_djm_get_label(u8 device_idx, u16 wvalue, u16 windex) { switch (windex) { - case SND_DJM_WINDEX_CAPLVL: return snd_djm_get_label_caplevel(wvalue); + case SND_DJM_WINDEX_CAPLVL: return snd_djm_get_label_caplevel(device_idx, wvalue); case SND_DJM_WINDEX_CAP: return snd_djm_get_label_cap(device_idx, wvalue); case SND_DJM_WINDEX_PB: return snd_djm_get_label_pb(wvalue); default: return NULL; @@ -3083,7 +3698,6 @@ static const char *snd_djm_get_label(u8 device_idx, u16 wvalue, u16 windex) static const u16 snd_djm_opts_cap_level[] = { 0x0000, 0x0100, 0x0200, 0x0300 }; - // DJM-250MK2 static const u16 snd_djm_opts_250mk2_cap1[] = { 0x0103, 0x0100, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d, 0x010a }; @@ -3099,13 +3713,13 @@ static const u16 snd_djm_opts_250mk2_pb2[] = { 0x0200, 0x0201, 0x0204 }; static const u16 snd_djm_opts_250mk2_pb3[] = { 0x0300, 0x0301, 0x0304 }; static const struct snd_djm_ctl snd_djm_ctls_250mk2[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Ch1 Input", 250mk2_cap1, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", 250mk2_cap2, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", 250mk2_cap3, 0, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch1 Output", 250mk2_pb1, 0, SND_DJM_WINDEX_PB), - SND_DJM_CTL("Ch2 Output", 250mk2_pb2, 1, SND_DJM_WINDEX_PB), - SND_DJM_CTL("Ch3 Output", 250mk2_pb3, 2, SND_DJM_WINDEX_PB) + SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", 250mk2_cap1, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", 250mk2_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", 250mk2_cap3, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Output 1 Playback Switch", 250mk2_pb1, 0, SND_DJM_WINDEX_PB), + SND_DJM_CTL("Output 2 Playback Switch", 250mk2_pb2, 1, SND_DJM_WINDEX_PB), + SND_DJM_CTL("Output 3 Playback Switch", 250mk2_pb3, 2, SND_DJM_WINDEX_PB) }; @@ -3124,13 +3738,13 @@ static const u16 snd_djm_opts_450_pb2[] = { 0x0200, 0x0201, 0x0204 }; static const u16 snd_djm_opts_450_pb3[] = { 0x0300, 0x0301, 0x0304 }; static const struct snd_djm_ctl snd_djm_ctls_450[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Ch1 Input", 450_cap1, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", 450_cap2, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", 450_cap3, 0, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch1 Output", 450_pb1, 0, SND_DJM_WINDEX_PB), - SND_DJM_CTL("Ch2 Output", 450_pb2, 1, SND_DJM_WINDEX_PB), - SND_DJM_CTL("Ch3 Output", 450_pb3, 2, SND_DJM_WINDEX_PB) + SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", 450_cap1, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", 450_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", 450_cap3, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Output 1 Playback Switch", 450_pb1, 0, SND_DJM_WINDEX_PB), + SND_DJM_CTL("Output 2 Playback Switch", 450_pb2, 1, SND_DJM_WINDEX_PB), + SND_DJM_CTL("Output 3 Playback Switch", 450_pb3, 2, SND_DJM_WINDEX_PB) }; @@ -3145,11 +3759,11 @@ static const u16 snd_djm_opts_750_cap4[] = { 0x0401, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f }; static const struct snd_djm_ctl snd_djm_ctls_750[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Ch1 Input", 750_cap1, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", 750_cap2, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", 750_cap3, 0, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch4 Input", 750_cap4, 0, SND_DJM_WINDEX_CAP) + SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", 750_cap1, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", 750_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", 750_cap3, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 4 Capture Switch", 750_cap4, 0, SND_DJM_WINDEX_CAP) }; @@ -3164,11 +3778,11 @@ static const u16 snd_djm_opts_850_cap4[] = { 0x0400, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f }; static const struct snd_djm_ctl snd_djm_ctls_850[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Ch1 Input", 850_cap1, 1, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", 850_cap2, 0, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", 850_cap3, 0, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch4 Input", 850_cap4, 1, SND_DJM_WINDEX_CAP) + SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", 850_cap1, 1, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", 850_cap2, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", 850_cap3, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 4 Capture Switch", 850_cap4, 1, SND_DJM_WINDEX_CAP) }; @@ -3185,12 +3799,12 @@ static const u16 snd_djm_opts_900nxs2_cap5[] = { 0x0507, 0x0508, 0x0509, 0x050a, 0x0511, 0x0512, 0x0513, 0x0514 }; static const struct snd_djm_ctl snd_djm_ctls_900nxs2[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Ch1 Input", 900nxs2_cap1, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", 900nxs2_cap2, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", 900nxs2_cap3, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch4 Input", 900nxs2_cap4, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch5 Input", 900nxs2_cap5, 3, SND_DJM_WINDEX_CAP) + SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", 900nxs2_cap1, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", 900nxs2_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", 900nxs2_cap3, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 4 Capture Switch", 900nxs2_cap4, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 5 Capture Switch", 900nxs2_cap5, 3, SND_DJM_WINDEX_CAP) }; // DJM-750MK2 @@ -3211,17 +3825,85 @@ static const u16 snd_djm_opts_750mk2_pb3[] = { 0x0300, 0x0301, 0x0304 }; static const struct snd_djm_ctl snd_djm_ctls_750mk2[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), - SND_DJM_CTL("Ch1 Input", 750mk2_cap1, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch2 Input", 750mk2_cap2, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch3 Input", 750mk2_cap3, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch4 Input", 750mk2_cap4, 2, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch5 Input", 750mk2_cap5, 3, SND_DJM_WINDEX_CAP), - SND_DJM_CTL("Ch1 Output", 750mk2_pb1, 0, SND_DJM_WINDEX_PB), - SND_DJM_CTL("Ch2 Output", 750mk2_pb2, 1, SND_DJM_WINDEX_PB), - SND_DJM_CTL("Ch3 Output", 750mk2_pb3, 2, SND_DJM_WINDEX_PB) + SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", 750mk2_cap1, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", 750mk2_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", 750mk2_cap3, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 4 Capture Switch", 750mk2_cap4, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 5 Capture Switch", 750mk2_cap5, 3, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Output 1 Playback Switch", 750mk2_pb1, 0, SND_DJM_WINDEX_PB), + SND_DJM_CTL("Output 2 Playback Switch", 750mk2_pb2, 1, SND_DJM_WINDEX_PB), + SND_DJM_CTL("Output 3 Playback Switch", 750mk2_pb3, 2, SND_DJM_WINDEX_PB) +}; + + +// DJM-A9 +static const u16 snd_djm_opts_a9_cap_level[] = { + 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500 }; +static const u16 snd_djm_opts_a9_cap1[] = { + 0x0107, 0x0108, 0x0109, 0x010a, 0x010e, + 0x111, 0x112, 0x113, 0x114, 0x0131, 0x132, 0x133, 0x134 }; +static const u16 snd_djm_opts_a9_cap2[] = { + 0x0201, 0x0202, 0x0203, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020e }; +static const u16 snd_djm_opts_a9_cap3[] = { + 0x0301, 0x0302, 0x0303, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030e }; +static const u16 snd_djm_opts_a9_cap4[] = { + 0x0401, 0x0402, 0x0403, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040e }; +static const u16 snd_djm_opts_a9_cap5[] = { + 0x0501, 0x0502, 0x0503, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050a, 0x050e }; + +static const struct snd_djm_ctl snd_djm_ctls_a9[] = { + SND_DJM_CTL("Master Input Level Capture Switch", a9_cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Master Input Capture Switch", a9_cap1, 3, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 1 Capture Switch", a9_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", a9_cap3, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", a9_cap4, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 4 Capture Switch", a9_cap5, 2, SND_DJM_WINDEX_CAP) }; +// DJM-V10 +static const u16 snd_djm_opts_v10_cap_level[] = { + 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500 +}; +static const u16 snd_djm_opts_v10_cap1[] = { + 0x0103, + 0x0100, 0x0102, 0x0106, 0x0110, 0x0107, + 0x0108, 0x0109, 0x010a, 0x0121, 0x0122 +}; +static const u16 snd_djm_opts_v10_cap2[] = { + 0x0200, 0x0202, 0x0206, 0x0210, 0x0207, + 0x0208, 0x0209, 0x020a, 0x0221, 0x0222 +}; +static const u16 snd_djm_opts_v10_cap3[] = { + 0x0303, + 0x0300, 0x0302, 0x0306, 0x0310, 0x0307, + 0x0308, 0x0309, 0x030a, 0x0321, 0x0322 +}; +static const u16 snd_djm_opts_v10_cap4[] = { + 0x0403, + 0x0400, 0x0402, 0x0406, 0x0410, 0x0407, + 0x0408, 0x0409, 0x040a, 0x0421, 0x0422 +}; +static const u16 snd_djm_opts_v10_cap5[] = { + 0x0500, 0x0502, 0x0506, 0x0510, 0x0507, + 0x0508, 0x0509, 0x050a, 0x0521, 0x0522 +}; +static const u16 snd_djm_opts_v10_cap6[] = { + 0x0603, + 0x0600, 0x0602, 0x0606, 0x0610, 0x0607, + 0x0608, 0x0609, 0x060a, 0x0621, 0x0622 +}; + +static const struct snd_djm_ctl snd_djm_ctls_v10[] = { + SND_DJM_CTL("Master Input Level Capture Switch", v10_cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Input 1 Capture Switch", v10_cap1, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 2 Capture Switch", v10_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 3 Capture Switch", v10_cap3, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 4 Capture Switch", v10_cap4, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 5 Capture Switch", v10_cap5, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Input 6 Capture Switch", v10_cap6, 0, SND_DJM_WINDEX_CAP) + // playback channels are fixed and controlled by hardware knobs on the mixer +}; static const struct snd_djm_device snd_djm_devices[] = { [SND_DJM_250MK2_IDX] = SND_DJM_DEVICE(250mk2), @@ -3230,6 +3912,8 @@ static const struct snd_djm_device snd_djm_devices[] = { [SND_DJM_900NXS2_IDX] = SND_DJM_DEVICE(900nxs2), [SND_DJM_750MK2_IDX] = SND_DJM_DEVICE(750mk2), [SND_DJM_450_IDX] = SND_DJM_DEVICE(450), + [SND_DJM_A9_IDX] = SND_DJM_DEVICE(a9), + [SND_DJM_V10_IDX] = SND_DJM_DEVICE(v10), }; @@ -3447,6 +4131,8 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x1235, 0x8213): /* Focusrite Scarlett 8i6 3rd Gen */ case USB_ID(0x1235, 0x8214): /* Focusrite Scarlett 18i8 3rd Gen */ case USB_ID(0x1235, 0x8215): /* Focusrite Scarlett 18i20 3rd Gen */ + case USB_ID(0x1235, 0x8216): /* Focusrite Vocaster One */ + case USB_ID(0x1235, 0x8217): /* Focusrite Vocaster Two */ case USB_ID(0x1235, 0x8218): /* Focusrite Scarlett Solo 4th Gen */ case USB_ID(0x1235, 0x8219): /* Focusrite Scarlett 2i2 4th Gen */ case USB_ID(0x1235, 0x821a): /* Focusrite Scarlett 4i4 4th Gen */ @@ -3459,6 +4145,12 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) err = snd_scarlett2_init(mixer); break; + case USB_ID(0x1235, 0x821b): /* Focusrite Scarlett 16i16 4th Gen */ + case USB_ID(0x1235, 0x821c): /* Focusrite Scarlett 18i16 4th Gen */ + case USB_ID(0x1235, 0x821d): /* Focusrite Scarlett 18i20 4th Gen */ + err = snd_fcp_init(mixer); + break; + case USB_ID(0x041e, 0x323b): /* Creative Sound Blaster E1 */ err = snd_soundblaster_e1_switch_create(mixer); break; @@ -3468,6 +4160,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) break; err = dell_dock_mixer_init(mixer); break; + case USB_ID(0x0bda, 0x402e): /* Dell WD19 dock */ + err = dell_dock_mixer_create(mixer); + break; case USB_ID(0x2a39, 0x3fd2): /* RME ADI-2 Pro */ case USB_ID(0x2a39, 0x3fd3): /* RME ADI-2 DAC */ @@ -3478,9 +4173,16 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x194f, 0x010c): /* Presonus Studio 1810c */ err = snd_sc1810_init_mixer(mixer); break; + case USB_ID(0x194f, 0x010d): /* Presonus Studio 1824c */ + err = snd_sc1810_init_mixer(mixer); + break; case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */ err = snd_bbfpro_controls_create(mixer); break; + case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */ + case USB_ID(0x2a39, 0x3fa0): /* RME Digiface USB (alternate) */ + err = snd_rme_digiface_controls_create(mixer); + break; case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */ err = snd_djm_controls_create(mixer, SND_DJM_250MK2_IDX); break; @@ -3499,6 +4201,12 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */ err = snd_djm_controls_create(mixer, SND_DJM_900NXS2_IDX); break; + case USB_ID(0x2b73, 0x003c): /* Pioneer DJ / AlphaTheta DJM-A9 */ + err = snd_djm_controls_create(mixer, SND_DJM_A9_IDX); + break; + case USB_ID(0x2b73, 0x0034): /* Pioneer DJ DJM-V10 */ + err = snd_djm_controls_create(mixer, SND_DJM_V10_IDX); + break; } return err; @@ -3575,6 +4283,52 @@ static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer, } } +/* + * Some Plantronics headsets have control names that don't meet ALSA naming + * standards. This function fixes nonstandard source names. By the time + * this function is called the control name should look like one of these: + * "source names Playback Volume" + * "source names Playback Switch" + * "source names Capture Volume" + * "source names Capture Switch" + * If any of the trigger words are found in the name then the name will + * be changed to: + * "Headset Playback Volume" + * "Headset Playback Switch" + * "Headset Capture Volume" + * "Headset Capture Switch" + * depending on the current suffix. + */ +static void snd_fix_plt_name(struct snd_usb_audio *chip, + struct snd_ctl_elem_id *id) +{ + /* no variant of "Sidetone" should be added to this list */ + static const char * const trigger[] = { + "Earphone", "Microphone", "Receive", "Transmit" + }; + static const char * const suffix[] = { + " Playback Volume", " Playback Switch", + " Capture Volume", " Capture Switch" + }; + int i; + + for (i = 0; i < ARRAY_SIZE(trigger); i++) + if (strstr(id->name, trigger[i])) + goto triggered; + usb_audio_dbg(chip, "no change in %s\n", id->name); + return; + +triggered: + for (i = 0; i < ARRAY_SIZE(suffix); i++) + if (strstr(id->name, suffix[i])) { + usb_audio_dbg(chip, "fixing kctl name %s\n", id->name); + snprintf(id->name, sizeof(id->name), "Headset%s", + suffix[i]); + return; + } + usb_audio_dbg(chip, "something wrong in kctl name %s\n", id->name); +} + void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, struct usb_mixer_elem_info *cval, int unitid, struct snd_kcontrol *kctl) @@ -3592,5 +4346,10 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, cval->min_mute = 1; break; } + + /* ALSA-ify some Plantronics headset control names */ + if (USB_ID_VENDOR(mixer->chip->usb_id) == 0x047f && + (cval->control == UAC_FU_MUTE || cval->control == UAC_FU_VOLUME)) + snd_fix_plt_name(mixer->chip, &kctl->id); } |