Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Geoffrey D. Bennett and committed by
Takashi Iwai
cbd67687 400f60b2

+96 -1
+96 -1
sound/usb/mixer_scarlett2.c
··· 10 10 * - Solo/2i2/4i4 Gen 4 11 11 * - Clarett 2Pre/4Pre/8Pre USB 12 12 * - Clarett+ 2Pre/4Pre/8Pre 13 + * - Vocaster One/Two 13 14 * 14 - * Copyright (c) 2018-2024 by Geoffrey D. Bennett <g at b4.vu> 15 + * Copyright (c) 2018-2025 by Geoffrey D. Bennett <g at b4.vu> 15 16 * Copyright (c) 2020-2021 by Vladimir Sadovnikov <sadko4u@gmail.com> 16 17 * Copyright (c) 2022 by Christian Colglazier <christian@cacolglazier.com> 17 18 * ··· 75 74 * Support for Scarlett Solo/2i2/4i4 Gen 4 added in Dec 2023 (thanks 76 75 * to many LinuxMusicians people and to Focusrite for hardware 77 76 * donations). 77 + * 78 + * Support for Vocaster One and Two added in Mar 2024 (thanks to many 79 + * LinuxMusicians people and to Focusrite for hardware donations). 78 80 * 79 81 * This ALSA mixer gives access to (model-dependent): 80 82 * - input, output, mixer-matrix muxes ··· 368 364 "Mute Playback Switch", "Dim Playback Switch" 369 365 }; 370 366 367 + /* Vocaster One speaker/headphone mute names */ 368 + static const char *const vocaster_one_sp_hp_mute_names[] = { 369 + "Speaker Mute Playback Switch", 370 + "Headphones Mute Playback Switch", 371 + NULL 372 + }; 373 + 374 + /* Vocaster Two speaker/headphone mute names */ 375 + static const char *const vocaster_two_sp_hp_mute_names[] = { 376 + "Speaker Mute Playback Switch", 377 + "Headphones 1 Mute Playback Switch", 378 + "Headphones 2 Mute Playback Switch", 379 + NULL 380 + }; 381 + 371 382 /* The autogain_status is set based on the autogain_switch and 372 383 * raw_autogain_status values. 373 384 * ··· 566 547 SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN, 567 548 SCARLETT2_CONFIG_BLUETOOTH_VOLUME, 568 549 SCARLETT2_CONFIG_SPDIF_MODE, 550 + SCARLETT2_CONFIG_SP_HP_MUTE, 569 551 SCARLETT2_CONFIG_COUNT 570 552 }; 571 553 ··· 834 814 835 815 [SCARLETT2_CONFIG_BLUETOOTH_VOLUME] = { 836 816 .offset = 0xbf, .size = 8, .activate = 28 }, 817 + 818 + [SCARLETT2_CONFIG_SP_HP_MUTE] = { 819 + .offset = 0xab, .size = 8, .activate = 10 }, 837 820 } 838 821 }; 839 822 ··· 1200 1177 /* additional description for the line out volume controls */ 1201 1178 const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX]; 1202 1179 1180 + /* Vocaster speaker/headphone mute control names */ 1181 + const char * const *sp_hp_mute_names; 1182 + 1203 1183 /* number of sources/destinations of each port type */ 1204 1184 const int port_count[SCARLETT2_PORT_TYPE_COUNT][SCARLETT2_PORT_DIRNS]; 1205 1185 ··· 1275 1249 u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX]; 1276 1250 u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX]; 1277 1251 u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT]; 1252 + u8 sp_hp_mute; 1278 1253 u8 air_switch[SCARLETT2_AIR_SWITCH_MAX]; 1279 1254 u8 dsp_switch[SCARLETT2_DSP_SWITCH_MAX]; 1280 1255 s32 compressor_values[SCARLETT2_COMPRESSOR_CTLS_MAX]; ··· 1818 1791 .peq_flt_total_count = 4, 1819 1792 .mute_input_count = 1, 1820 1793 .gain_input_count = 1, 1794 + .sp_hp_mute_names = vocaster_one_sp_hp_mute_names, 1821 1795 1822 1796 .port_count = { 1823 1797 [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, ··· 1863 1835 .mute_input_count = 2, 1864 1836 .gain_input_count = 2, 1865 1837 .has_bluetooth = 1, 1838 + .sp_hp_mute_names = vocaster_two_sp_hp_mute_names, 1866 1839 1867 1840 .port_count = { 1868 1841 [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, ··· 6322 6293 .put = scarlett2_dim_mute_ctl_put 6323 6294 }; 6324 6295 6296 + /*** Vocaster Speaker/Headphone Mute Controls ***/ 6297 + 6298 + static int scarlett2_sp_hp_mute_ctl_get(struct snd_kcontrol *kctl, 6299 + struct snd_ctl_elem_value *ucontrol) 6300 + { 6301 + struct usb_mixer_elem_info *elem = kctl->private_data; 6302 + struct scarlett2_data *private = elem->head.mixer->private_data; 6303 + 6304 + ucontrol->value.integer.value[0] = 6305 + !!(private->sp_hp_mute & (1 << elem->control)); 6306 + 6307 + return 0; 6308 + } 6309 + 6310 + static int scarlett2_sp_hp_mute_ctl_put(struct snd_kcontrol *kctl, 6311 + struct snd_ctl_elem_value *ucontrol) 6312 + { 6313 + struct usb_mixer_elem_info *elem = kctl->private_data; 6314 + struct usb_mixer_interface *mixer = elem->head.mixer; 6315 + struct scarlett2_data *private = mixer->private_data; 6316 + int index = elem->control; 6317 + int val, err; 6318 + 6319 + guard(mutex)(&private->data_mutex); 6320 + 6321 + if (private->hwdep_in_use) 6322 + return -EBUSY; 6323 + 6324 + val = private->sp_hp_mute; 6325 + 6326 + if (ucontrol->value.integer.value[0]) 6327 + val |= (1 << index); 6328 + else 6329 + val &= ~(1 << index); 6330 + 6331 + if (val == private->sp_hp_mute) 6332 + return 0; 6333 + 6334 + private->sp_hp_mute = val; 6335 + 6336 + /* Send change to the device */ 6337 + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SP_HP_MUTE, 6338 + 0, val); 6339 + 6340 + return err < 0 ? err : 1; 6341 + } 6342 + 6343 + static const struct snd_kcontrol_new scarlett2_sp_hp_mute_ctl = { 6344 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 6345 + .name = "", 6346 + .info = snd_ctl_boolean_mono_info, 6347 + .get = scarlett2_sp_hp_mute_ctl_get, 6348 + .put = scarlett2_sp_hp_mute_ctl_put 6349 + }; 6350 + 6325 6351 /*** Create the analogue output controls ***/ 6326 6352 6327 6353 static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) ··· 6408 6324 if (err < 0) 6409 6325 return err; 6410 6326 } 6327 + 6328 + /* Add Vocaster speaker/headphone mute controls */ 6329 + if (private->info->sp_hp_mute_names) 6330 + for (i = 0; private->info->sp_hp_mute_names[i]; i++) { 6331 + err = scarlett2_add_new_ctl( 6332 + mixer, &scarlett2_sp_hp_mute_ctl, 6333 + i, 1, private->info->sp_hp_mute_names[i], 6334 + NULL); 6335 + if (err < 0) 6336 + return err; 6337 + } 6411 6338 6412 6339 /* Remaining controls are only applicable if the device 6413 6340 * has per-channel line-out volume controls.