mirror of https://github.com/torvalds/linux.git
ALSA: scarlett2: Add Vocaster speaker/headphone mute controls
Add support for the speaker and headphone mute controls on Focusrite Vocaster interfaces. Unlike other Focusrite interfaces, these mute controls are per-output, not per-channel. Signed-off-by: Geoffrey D. Bennett <g@b4.vu> Link: https://patch.msgid.link/aLm2Dy6+O/eLTGVn@m.b4.vu Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
400f60b274
commit
cbd676874e
|
|
@ -10,8 +10,9 @@
|
||||||
* - Solo/2i2/4i4 Gen 4
|
* - Solo/2i2/4i4 Gen 4
|
||||||
* - Clarett 2Pre/4Pre/8Pre USB
|
* - Clarett 2Pre/4Pre/8Pre USB
|
||||||
* - Clarett+ 2Pre/4Pre/8Pre
|
* - Clarett+ 2Pre/4Pre/8Pre
|
||||||
|
* - Vocaster One/Two
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018-2024 by Geoffrey D. Bennett <g at b4.vu>
|
* Copyright (c) 2018-2025 by Geoffrey D. Bennett <g at b4.vu>
|
||||||
* Copyright (c) 2020-2021 by Vladimir Sadovnikov <sadko4u@gmail.com>
|
* Copyright (c) 2020-2021 by Vladimir Sadovnikov <sadko4u@gmail.com>
|
||||||
* Copyright (c) 2022 by Christian Colglazier <christian@cacolglazier.com>
|
* Copyright (c) 2022 by Christian Colglazier <christian@cacolglazier.com>
|
||||||
*
|
*
|
||||||
|
|
@ -75,6 +76,9 @@
|
||||||
* to many LinuxMusicians people and to Focusrite for hardware
|
* to many LinuxMusicians people and to Focusrite for hardware
|
||||||
* donations).
|
* donations).
|
||||||
*
|
*
|
||||||
|
* Support for Vocaster One and Two added in Mar 2024 (thanks to many
|
||||||
|
* LinuxMusicians people and to Focusrite for hardware donations).
|
||||||
|
*
|
||||||
* This ALSA mixer gives access to (model-dependent):
|
* This ALSA mixer gives access to (model-dependent):
|
||||||
* - input, output, mixer-matrix muxes
|
* - input, output, mixer-matrix muxes
|
||||||
* - mixer-matrix gain stages
|
* - mixer-matrix gain stages
|
||||||
|
|
@ -364,6 +368,21 @@ static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = {
|
||||||
"Mute Playback Switch", "Dim Playback Switch"
|
"Mute Playback Switch", "Dim Playback Switch"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Vocaster One speaker/headphone mute names */
|
||||||
|
static const char *const vocaster_one_sp_hp_mute_names[] = {
|
||||||
|
"Speaker Mute Playback Switch",
|
||||||
|
"Headphones Mute Playback Switch",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Vocaster Two speaker/headphone mute names */
|
||||||
|
static const char *const vocaster_two_sp_hp_mute_names[] = {
|
||||||
|
"Speaker Mute Playback Switch",
|
||||||
|
"Headphones 1 Mute Playback Switch",
|
||||||
|
"Headphones 2 Mute Playback Switch",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
/* The autogain_status is set based on the autogain_switch and
|
/* The autogain_status is set based on the autogain_switch and
|
||||||
* raw_autogain_status values.
|
* raw_autogain_status values.
|
||||||
*
|
*
|
||||||
|
|
@ -547,6 +566,7 @@ enum {
|
||||||
SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN,
|
SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN,
|
||||||
SCARLETT2_CONFIG_BLUETOOTH_VOLUME,
|
SCARLETT2_CONFIG_BLUETOOTH_VOLUME,
|
||||||
SCARLETT2_CONFIG_SPDIF_MODE,
|
SCARLETT2_CONFIG_SPDIF_MODE,
|
||||||
|
SCARLETT2_CONFIG_SP_HP_MUTE,
|
||||||
SCARLETT2_CONFIG_COUNT
|
SCARLETT2_CONFIG_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -814,6 +834,9 @@ static const struct scarlett2_config_set scarlett2_config_set_vocaster = {
|
||||||
|
|
||||||
[SCARLETT2_CONFIG_BLUETOOTH_VOLUME] = {
|
[SCARLETT2_CONFIG_BLUETOOTH_VOLUME] = {
|
||||||
.offset = 0xbf, .size = 8, .activate = 28 },
|
.offset = 0xbf, .size = 8, .activate = 28 },
|
||||||
|
|
||||||
|
[SCARLETT2_CONFIG_SP_HP_MUTE] = {
|
||||||
|
.offset = 0xab, .size = 8, .activate = 10 },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1177,6 +1200,9 @@ struct scarlett2_device_info {
|
||||||
/* additional description for the line out volume controls */
|
/* additional description for the line out volume controls */
|
||||||
const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX];
|
const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX];
|
||||||
|
|
||||||
|
/* Vocaster speaker/headphone mute control names */
|
||||||
|
const char * const *sp_hp_mute_names;
|
||||||
|
|
||||||
/* number of sources/destinations of each port type */
|
/* number of sources/destinations of each port type */
|
||||||
const int port_count[SCARLETT2_PORT_TYPE_COUNT][SCARLETT2_PORT_DIRNS];
|
const int port_count[SCARLETT2_PORT_TYPE_COUNT][SCARLETT2_PORT_DIRNS];
|
||||||
|
|
||||||
|
|
@ -1249,6 +1275,7 @@ struct scarlett2_data {
|
||||||
u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX];
|
u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX];
|
||||||
u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX];
|
u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX];
|
||||||
u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT];
|
u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT];
|
||||||
|
u8 sp_hp_mute;
|
||||||
u8 air_switch[SCARLETT2_AIR_SWITCH_MAX];
|
u8 air_switch[SCARLETT2_AIR_SWITCH_MAX];
|
||||||
u8 dsp_switch[SCARLETT2_DSP_SWITCH_MAX];
|
u8 dsp_switch[SCARLETT2_DSP_SWITCH_MAX];
|
||||||
s32 compressor_values[SCARLETT2_COMPRESSOR_CTLS_MAX];
|
s32 compressor_values[SCARLETT2_COMPRESSOR_CTLS_MAX];
|
||||||
|
|
@ -1791,6 +1818,7 @@ static const struct scarlett2_device_info vocaster_one_info = {
|
||||||
.peq_flt_total_count = 4,
|
.peq_flt_total_count = 4,
|
||||||
.mute_input_count = 1,
|
.mute_input_count = 1,
|
||||||
.gain_input_count = 1,
|
.gain_input_count = 1,
|
||||||
|
.sp_hp_mute_names = vocaster_one_sp_hp_mute_names,
|
||||||
|
|
||||||
.port_count = {
|
.port_count = {
|
||||||
[SCARLETT2_PORT_TYPE_NONE] = { 1, 0 },
|
[SCARLETT2_PORT_TYPE_NONE] = { 1, 0 },
|
||||||
|
|
@ -1835,6 +1863,7 @@ static const struct scarlett2_device_info vocaster_two_info = {
|
||||||
.mute_input_count = 2,
|
.mute_input_count = 2,
|
||||||
.gain_input_count = 2,
|
.gain_input_count = 2,
|
||||||
.has_bluetooth = 1,
|
.has_bluetooth = 1,
|
||||||
|
.sp_hp_mute_names = vocaster_two_sp_hp_mute_names,
|
||||||
|
|
||||||
.port_count = {
|
.port_count = {
|
||||||
[SCARLETT2_PORT_TYPE_NONE] = { 1, 0 },
|
[SCARLETT2_PORT_TYPE_NONE] = { 1, 0 },
|
||||||
|
|
@ -6293,6 +6322,61 @@ static const struct snd_kcontrol_new scarlett2_dim_mute_ctl = {
|
||||||
.put = scarlett2_dim_mute_ctl_put
|
.put = scarlett2_dim_mute_ctl_put
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*** Vocaster Speaker/Headphone Mute Controls ***/
|
||||||
|
|
||||||
|
static int scarlett2_sp_hp_mute_ctl_get(struct snd_kcontrol *kctl,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct usb_mixer_elem_info *elem = kctl->private_data;
|
||||||
|
struct scarlett2_data *private = elem->head.mixer->private_data;
|
||||||
|
|
||||||
|
ucontrol->value.integer.value[0] =
|
||||||
|
!!(private->sp_hp_mute & (1 << elem->control));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scarlett2_sp_hp_mute_ctl_put(struct snd_kcontrol *kctl,
|
||||||
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
|
{
|
||||||
|
struct usb_mixer_elem_info *elem = kctl->private_data;
|
||||||
|
struct usb_mixer_interface *mixer = elem->head.mixer;
|
||||||
|
struct scarlett2_data *private = mixer->private_data;
|
||||||
|
int index = elem->control;
|
||||||
|
int val, err;
|
||||||
|
|
||||||
|
guard(mutex)(&private->data_mutex);
|
||||||
|
|
||||||
|
if (private->hwdep_in_use)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
val = private->sp_hp_mute;
|
||||||
|
|
||||||
|
if (ucontrol->value.integer.value[0])
|
||||||
|
val |= (1 << index);
|
||||||
|
else
|
||||||
|
val &= ~(1 << index);
|
||||||
|
|
||||||
|
if (val == private->sp_hp_mute)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
private->sp_hp_mute = val;
|
||||||
|
|
||||||
|
/* Send change to the device */
|
||||||
|
err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SP_HP_MUTE,
|
||||||
|
0, val);
|
||||||
|
|
||||||
|
return err < 0 ? err : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct snd_kcontrol_new scarlett2_sp_hp_mute_ctl = {
|
||||||
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.name = "",
|
||||||
|
.info = snd_ctl_boolean_mono_info,
|
||||||
|
.get = scarlett2_sp_hp_mute_ctl_get,
|
||||||
|
.put = scarlett2_sp_hp_mute_ctl_put
|
||||||
|
};
|
||||||
|
|
||||||
/*** Create the analogue output controls ***/
|
/*** Create the analogue output controls ***/
|
||||||
|
|
||||||
static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer)
|
static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer)
|
||||||
|
|
@ -6325,6 +6409,17 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add Vocaster speaker/headphone mute controls */
|
||||||
|
if (private->info->sp_hp_mute_names)
|
||||||
|
for (i = 0; private->info->sp_hp_mute_names[i]; i++) {
|
||||||
|
err = scarlett2_add_new_ctl(
|
||||||
|
mixer, &scarlett2_sp_hp_mute_ctl,
|
||||||
|
i, 1, private->info->sp_hp_mute_names[i],
|
||||||
|
NULL);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Remaining controls are only applicable if the device
|
/* Remaining controls are only applicable if the device
|
||||||
* has per-channel line-out volume controls.
|
* has per-channel line-out volume controls.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue