2019-07-28 18:12:45 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
2022-08-09 07:32:41 +03:00
* Focusrite Scarlett Gen 2 / 3 and Clarett + Driver for ALSA
2019-07-28 18:12:45 +03:00
*
2021-06-22 20:01:37 +03:00
* Supported models :
* - 6 i6 / 18 i8 / 18 i20 Gen 2
2021-06-22 20:02:31 +03:00
* - Solo / 2 i2 / 4 i4 / 8 i6 / 18 i8 / 18 i20 Gen 3
2022-08-09 07:32:41 +03:00
* - Clarett + 8 Pre
2021-06-22 20:01:37 +03:00
*
2022-03-06 18:21:04 +03:00
* Copyright ( c ) 2018 - 2022 by Geoffrey D . Bennett < g at b4 . vu >
2021-06-22 20:02:31 +03:00
* Copyright ( c ) 2020 - 2021 by Vladimir Sadovnikov < sadko4u @ gmail . com >
2022-08-09 07:32:41 +03:00
* Copyright ( c ) 2022 by Christian Colglazier < christian @ cacolglazier . com >
2019-07-28 18:12:45 +03:00
*
* Based on the Scarlett ( Gen 1 ) Driver for ALSA :
*
* Copyright ( c ) 2013 by Tobias Hoffmann
* Copyright ( c ) 2013 by Robin Gareus < robin at gareus . org >
* Copyright ( c ) 2002 by Takashi Iwai < tiwai at suse . de >
* Copyright ( c ) 2014 by Chris J Arges < chris . j . arges at canonical . com >
*
* Many codes borrowed from audio . c by
* Alan Cox ( alan at lxorguk . ukuu . org . uk )
* Thomas Sailer ( sailer at ife . ee . ethz . ch )
*
* Code cleanup :
* David Henningsson < david . henningsson at canonical . com >
*/
/* The protocol was reverse engineered by looking at the communication
* between Focusrite Control 2.3 .4 and the Focusrite ( R ) Scarlett 18 i20
* ( firmware 1083 ) using usbmon in July - August 2018.
*
* Scarlett 18 i8 support added in April 2019.
*
* Scarlett 6 i6 support added in June 2019 ( thanks to Martin Wittmann
* for providing usbmon output and testing ) .
*
2021-06-22 20:01:37 +03:00
* Scarlett 4 i4 / 8 i6 Gen 3 support added in May 2020 ( thanks to Laurent
* Debricon for donating a 4 i4 and to Fredrik Unger for providing 8 i6
* usbmon output and testing ) .
*
* Scarlett 18 i8 / 18 i20 Gen 3 support added in June 2020 ( thanks to
* Darren Jaeckel , Alex Sedlack , and Clovis Lunel for providing usbmon
* output , protocol traces and testing ) .
*
2021-06-07 22:13:51 +03:00
* Support for loading mixer volume and mux configuration from the
* interface during driver initialisation added in May 2021 ( thanks to
* Vladimir Sadovnikov for figuring out how ) .
*
2021-06-22 20:02:31 +03:00
* Support for Solo / 2 i2 Gen 3 added in May 2021 ( thanks to Alexander
* Vorona for 2 i2 protocol traces ) .
*
2021-06-22 20:04:13 +03:00
* Support for phantom power , direct monitoring , speaker switching ,
* and talkback added in May - June 2021.
2021-06-22 20:02:40 +03:00
*
2022-08-09 07:32:41 +03:00
* Support for Clarett + 8 Pre added in Aug 2022 by Christian
* Colglazier .
*
2021-06-22 20:01:52 +03:00
* This ALSA mixer gives access to ( model - dependent ) :
2019-07-28 18:12:45 +03:00
* - input , output , mixer - matrix muxes
2021-06-22 20:01:37 +03:00
* - mixer - matrix gain stages
2021-06-21 21:09:39 +03:00
* - gain / volume / mute controls
2019-07-28 18:12:45 +03:00
* - level meters
2021-06-22 20:02:36 +03:00
* - line / inst level , pad , and air controls
2021-06-22 20:04:13 +03:00
* - phantom power , direct monitor , speaker switching , and talkback
* controls
2021-06-22 20:01:52 +03:00
* - disable / enable MSD mode
2022-03-06 18:21:39 +03:00
* - disable / enable standalone mode
2019-07-28 18:12:45 +03:00
*
* < ditaa >
* / - - - - - - - - - - - - - - \ 18 chn 20 chn / - - - - - - - - - - - - - - \
* | Hardware in + - - + - - - - - - \ / - - - - - - - - - - - - - + - - + ALSA PCM out |
* \ - - - - - - - - - - - - - - / | | | | \ - - - - - - - - - - - - - - /
* | | | / - - - - - \ |
* | | | | | |
* | v v v | |
* | + - - - - - - - - - - - - - - - + | |
* | \ Matrix Mux / | |
* | + - - - - - + - - - - - + | |
* | | | |
* | | 18 chn | |
* | | | |
* | | 10 chn | |
* | v | |
* | + - - - - - - - - - - - - + | |
* | | Mixer | | |
* | | Matrix | | |
* | | | | |
* | | 18 x10 Gain | | |
* | | stages | | |
* | + - - - - - + - - - - - - + | |
* | | | |
* | 18 chn | 10 chn | | 20 chn
* | | | |
* | + - - - - - - - - - - / |
* | | |
* v v v
* = = = = = = = = = = = = = = = = = = = = = = = = = = =
* + - - - - - - - - - - - - - - - + + - - — - - - - - - - - - - - - +
* \ Output Mux / \ Capture Mux /
* + - - - + - - - + - - - + + - - - - - + - - - - - +
* | | |
* 10 chn | | | 18 chn
* | | |
* / - - - - - - - - - - - - - - \ | | | / - - - - - - - - - - - - - - \
* | S / PDIF , ADAT | < - - / | 10 chn \ - - > | ALSA PCM in |
* | Hardware out | | \ - - - - - - - - - - - - - - /
* \ - - - - - - - - - - - - - - / |
* v
* + - - - - - - - - - - - - - + Software gain per channel .
* | Master Gain | < - - 18 i20 only : Switch per channel
* + - - - - - - + - - - - - - + to select HW or SW gain control .
* |
* | 10 chn
* / - - - - - - - - - - - - - - \ |
* | Analogue | < - - - - - - /
* | Hardware out |
* \ - - - - - - - - - - - - - - /
* < / ditaa >
*
2021-06-22 20:01:52 +03:00
* Gen 3 devices have a Mass Storage Device ( MSD ) mode where a small
* disk with registration and driver download information is presented
* to the host . To access the full functionality of the device without
* proprietary software , MSD mode can be disabled by :
* - holding down the 48 V button for five seconds while powering on
* the device , or
* - using this driver and alsamixer to change the " MSD Mode " setting
* to Off and power - cycling the device
2019-07-28 18:12:45 +03:00
*/
# include <linux/slab.h>
# include <linux/usb.h>
# include <linux/moduleparam.h>
# include <sound/control.h>
# include <sound/tlv.h>
# include "usbaudio.h"
# include "mixer.h"
# include "helper.h"
# include "mixer_scarlett_gen2.h"
2021-06-22 20:01:52 +03:00
/* device_setup value to allow turning MSD mode back on */
# define SCARLETT2_MSD_ENABLE 0x02
2023-09-14 20:31:57 +03:00
/* device_setup value to disable this mixer driver */
# define SCARLETT2_DISABLE 0x04
2019-07-28 18:12:45 +03:00
/* some gui mixers can't handle negative ctl values */
# define SCARLETT2_VOLUME_BIAS 127
/* mixer range from -80dB to +6dB in 0.5dB steps */
# define SCARLETT2_MIXER_MIN_DB -80
# define SCARLETT2_MIXER_BIAS (-SCARLETT2_MIXER_MIN_DB * 2)
# define SCARLETT2_MIXER_MAX_DB 6
# define SCARLETT2_MIXER_MAX_VALUE \
( ( SCARLETT2_MIXER_MAX_DB - SCARLETT2_MIXER_MIN_DB ) * 2 )
2021-06-07 22:13:25 +03:00
# define SCARLETT2_MIXER_VALUE_COUNT (SCARLETT2_MIXER_MAX_VALUE + 1)
2019-07-28 18:12:45 +03:00
/* map from (dB + 80) * 2 to mixer value
* for dB in 0 . . 172 : int ( 8192 * pow ( 10 , ( ( dB - 160 ) / 2 / 20 ) ) )
*/
2021-06-07 22:13:25 +03:00
static const u16 scarlett2_mixer_values [ SCARLETT2_MIXER_VALUE_COUNT ] = {
2019-07-28 18:12:45 +03:00
0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 , 2 , 2 , 2 ,
2 , 2 , 3 , 3 , 3 , 3 , 3 , 4 , 4 , 4 , 4 , 5 , 5 , 5 , 6 , 6 , 6 , 7 , 7 , 8 , 8 ,
9 , 9 , 10 , 10 , 11 , 12 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 ,
23 , 24 , 25 , 27 , 29 , 30 , 32 , 34 , 36 , 38 , 41 , 43 , 46 , 48 , 51 ,
54 , 57 , 61 , 65 , 68 , 73 , 77 , 81 , 86 , 91 , 97 , 103 , 109 , 115 ,
122 , 129 , 137 , 145 , 154 , 163 , 173 , 183 , 194 , 205 , 217 , 230 ,
244 , 259 , 274 , 290 , 307 , 326 , 345 , 365 , 387 , 410 , 434 , 460 ,
487 , 516 , 547 , 579 , 614 , 650 , 689 , 730 , 773 , 819 , 867 , 919 ,
973 , 1031 , 1092 , 1157 , 1225 , 1298 , 1375 , 1456 , 1543 , 1634 ,
1731 , 1833 , 1942 , 2057 , 2179 , 2308 , 2445 , 2590 , 2744 , 2906 ,
3078 , 3261 , 3454 , 3659 , 3876 , 4105 , 4349 , 4606 , 4879 , 5168 ,
5475 , 5799 , 6143 , 6507 , 6892 , 7301 , 7733 , 8192 , 8677 , 9191 ,
9736 , 10313 , 10924 , 11571 , 12257 , 12983 , 13752 , 14567 , 15430 ,
16345
} ;
/* Maximum number of analogue outputs */
# define SCARLETT2_ANALOGUE_MAX 10
/* Maximum number of level and pad switches */
# define SCARLETT2_LEVEL_SWITCH_MAX 2
2021-06-22 20:01:37 +03:00
# define SCARLETT2_PAD_SWITCH_MAX 8
2021-06-22 20:02:36 +03:00
# define SCARLETT2_AIR_SWITCH_MAX 8
2021-06-22 20:02:40 +03:00
# define SCARLETT2_PHANTOM_SWITCH_MAX 2
2019-07-28 18:12:45 +03:00
/* Maximum number of inputs to the mixer */
2021-06-22 20:01:37 +03:00
# define SCARLETT2_INPUT_MIX_MAX 25
2019-07-28 18:12:45 +03:00
/* Maximum number of outputs from the mixer */
2021-06-22 20:01:37 +03:00
# define SCARLETT2_OUTPUT_MIX_MAX 12
2019-07-28 18:12:45 +03:00
/* Maximum size of the data in the USB mux assignment message:
2021-06-22 20:01:37 +03:00
* 20 inputs , 20 outputs , 25 matrix inputs , 12 spare
2019-07-28 18:12:45 +03:00
*/
2021-06-22 20:01:37 +03:00
# define SCARLETT2_MUX_MAX 77
2019-07-28 18:12:45 +03:00
2021-06-21 21:09:46 +03:00
/* Maximum number of meters (sum of output port counts) */
2021-06-22 20:01:37 +03:00
# define SCARLETT2_MAX_METERS 65
2019-07-28 18:12:45 +03:00
2022-03-06 18:21:04 +03:00
/* There are three different sets of configuration parameters across
* the devices
*/
enum {
SCARLETT2_CONFIG_SET_NO_MIXER = 0 ,
SCARLETT2_CONFIG_SET_GEN_2 = 1 ,
SCARLETT2_CONFIG_SET_GEN_3 = 2 ,
2022-08-09 07:32:41 +03:00
SCARLETT2_CONFIG_SET_CLARETT = 3 ,
SCARLETT2_CONFIG_SET_COUNT = 4
2022-03-06 18:21:04 +03:00
} ;
2019-07-28 18:12:45 +03:00
/* Hardware port types:
* - None ( no input to mux )
* - Analogue I / O
* - S / PDIF I / O
* - ADAT I / O
* - Mixer I / O
* - PCM I / O
*/
enum {
2021-06-20 19:46:28 +03:00
SCARLETT2_PORT_TYPE_NONE = 0 ,
2019-07-28 18:12:45 +03:00
SCARLETT2_PORT_TYPE_ANALOGUE = 1 ,
2021-06-20 19:46:28 +03:00
SCARLETT2_PORT_TYPE_SPDIF = 2 ,
SCARLETT2_PORT_TYPE_ADAT = 3 ,
SCARLETT2_PORT_TYPE_MIX = 4 ,
SCARLETT2_PORT_TYPE_PCM = 5 ,
SCARLETT2_PORT_TYPE_COUNT = 6 ,
2019-07-28 18:12:45 +03:00
} ;
2021-06-21 21:09:41 +03:00
/* I/O count of each port type kept in struct scarlett2_ports */
2019-07-28 18:12:45 +03:00
enum {
2021-06-21 21:09:41 +03:00
SCARLETT2_PORT_IN = 0 ,
SCARLETT2_PORT_OUT = 1 ,
SCARLETT2_PORT_DIRNS = 2 ,
2019-07-28 18:12:45 +03:00
} ;
2021-06-20 19:46:36 +03:00
/* Dim/Mute buttons on the 18i20 */
2021-06-21 21:09:39 +03:00
enum {
SCARLETT2_BUTTON_MUTE = 0 ,
SCARLETT2_BUTTON_DIM = 1 ,
SCARLETT2_DIM_MUTE_COUNT = 2 ,
} ;
2019-07-28 18:12:45 +03:00
2021-06-20 19:46:36 +03:00
static const char * const scarlett2_dim_mute_names [ SCARLETT2_DIM_MUTE_COUNT ] = {
2021-07-22 23:11:53 +03:00
" Mute Playback Switch " , " Dim Playback Switch "
2019-07-28 18:12:45 +03:00
} ;
/* Description of each hardware port type:
2021-06-21 21:09:43 +03:00
* - id : hardware ID of this port type
2019-07-28 18:12:45 +03:00
* - src_descr : printf format string for mux input selections
* - src_num_offset : added to channel number for the fprintf
* - dst_descr : printf format string for mixer controls
*/
2021-06-21 21:09:43 +03:00
struct scarlett2_port {
2019-07-28 18:12:45 +03:00
u16 id ;
const char * const src_descr ;
int src_num_offset ;
const char * const dst_descr ;
} ;
2021-06-21 21:09:43 +03:00
static const struct scarlett2_port scarlett2_ports [ SCARLETT2_PORT_TYPE_COUNT ] = {
[ SCARLETT2_PORT_TYPE_NONE ] = {
. id = 0x000 ,
. src_descr = " Off "
} ,
[ SCARLETT2_PORT_TYPE_ANALOGUE ] = {
. id = 0x080 ,
. src_descr = " Analogue %d " ,
. src_num_offset = 1 ,
. dst_descr = " Analogue Output %02d Playback "
} ,
[ SCARLETT2_PORT_TYPE_SPDIF ] = {
. id = 0x180 ,
. src_descr = " S/PDIF %d " ,
. src_num_offset = 1 ,
. dst_descr = " S/PDIF Output %d Playback "
} ,
[ SCARLETT2_PORT_TYPE_ADAT ] = {
. id = 0x200 ,
. src_descr = " ADAT %d " ,
. src_num_offset = 1 ,
. dst_descr = " ADAT Output %d Playback "
} ,
[ SCARLETT2_PORT_TYPE_MIX ] = {
. id = 0x300 ,
. src_descr = " Mix %c " ,
. src_num_offset = ' A ' ,
. dst_descr = " Mixer Input %02d Capture "
} ,
[ SCARLETT2_PORT_TYPE_PCM ] = {
. id = 0x600 ,
. src_descr = " PCM %d " ,
. src_num_offset = 1 ,
. dst_descr = " PCM %02d Capture "
} ,
} ;
2021-06-21 21:09:41 +03:00
/* Number of mux tables: one for each band of sample rates
* ( 44.1 / 48 kHz , 88.2 / 96 kHz , and 176.4 / 176 kHz )
*/
# define SCARLETT2_MUX_TABLES 3
/* Maximum number of entries in a mux table */
2021-06-22 20:01:37 +03:00
# define SCARLETT2_MAX_MUX_ENTRIES 10
2021-06-21 21:09:41 +03:00
/* One entry within mux_assignment defines the port type and range of
* ports to add to the set_mux message . The end of the list is marked
* with count = = 0.
*/
struct scarlett2_mux_entry {
u8 port_type ;
u8 start ;
u8 count ;
} ;
2019-07-28 18:12:45 +03:00
struct scarlett2_device_info {
2021-06-21 21:09:31 +03:00
u32 usb_id ; /* USB device identifier */
2021-06-21 21:09:35 +03:00
2021-06-22 20:01:52 +03:00
/* Gen 3 devices have an internal MSD mode switch that needs
* to be disabled in order to access the full functionality of
* the device .
*/
u8 has_msd_mode ;
2022-03-06 18:21:04 +03:00
/* which set of configuration parameters the device uses */
u8 config_set ;
2021-06-22 20:02:31 +03:00
2021-06-21 21:09:35 +03:00
/* line out hw volume is sw controlled */
u8 line_out_hw_vol ;
2021-06-22 20:03:58 +03:00
/* support for main/alt speaker switching */
u8 has_speaker_switching ;
2021-06-22 20:04:13 +03:00
/* support for talkback microphone */
u8 has_talkback ;
2021-06-21 21:09:35 +03:00
/* the number of analogue inputs with a software switchable
* level control that can be set to line or instrument
*/
u8 level_input_count ;
2021-06-22 20:02:31 +03:00
/* the first input with a level control (0-based) */
u8 level_input_first ;
2021-06-21 21:09:35 +03:00
/* the number of analogue inputs with a software switchable
* 10 dB pad control
*/
u8 pad_input_count ;
2021-06-22 20:02:36 +03:00
/* the number of analogue inputs with a software switchable
* " air " control
*/
u8 air_input_count ;
2021-06-22 20:02:40 +03:00
/* the number of phantom (48V) software switchable controls */
u8 phantom_count ;
/* the number of inputs each phantom switch controls */
u8 inputs_per_phantom ;
2021-06-22 20:03:08 +03:00
/* the number of direct monitor options
* ( 0 = none , 1 = mono only , 2 = mono / stereo )
*/
u8 direct_monitor ;
2021-06-22 20:03:16 +03:00
/* remap analogue outputs; 18i8 Gen 3 has "line 3/4" connected
* internally to the analogue 7 / 8 outputs
*/
u8 line_out_remap_enable ;
u8 line_out_remap [ SCARLETT2_ANALOGUE_MAX ] ;
2021-06-21 21:09:35 +03:00
/* additional description for the line out volume controls */
2019-07-28 18:12:45 +03:00
const char * const line_out_descrs [ SCARLETT2_ANALOGUE_MAX ] ;
2021-06-21 21:09:35 +03:00
2021-06-21 21:09:43 +03:00
/* number of sources/destinations of each port type */
const int port_count [ SCARLETT2_PORT_TYPE_COUNT ] [ SCARLETT2_PORT_DIRNS ] ;
2021-06-21 21:09:41 +03:00
/* layout/order of the entries in the set_mux message */
struct scarlett2_mux_entry mux_assignment [ SCARLETT2_MUX_TABLES ]
[ SCARLETT2_MAX_MUX_ENTRIES ] ;
2019-07-28 18:12:45 +03:00
} ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data {
2019-07-28 18:12:45 +03:00
struct usb_mixer_interface * mixer ;
struct mutex usb_mutex ; /* prevent sending concurrent USB requests */
struct mutex data_mutex ; /* lock access to this data */
struct delayed_work work ;
const struct scarlett2_device_info * info ;
2021-06-20 19:46:52 +03:00
__u8 bInterfaceNumber ;
__u8 bEndpointAddress ;
__u16 wMaxPacketSize ;
__u8 bInterval ;
2019-07-28 18:12:45 +03:00
int num_mux_srcs ;
2021-06-07 22:13:51 +03:00
int num_mux_dsts ;
2019-07-28 18:12:45 +03:00
u16 scarlett2_seq ;
2021-06-21 21:09:24 +03:00
u8 sync_updated ;
2019-07-28 18:12:45 +03:00
u8 vol_updated ;
2021-06-22 20:01:44 +03:00
u8 input_other_updated ;
2021-06-22 20:03:08 +03:00
u8 monitor_other_updated ;
2021-06-22 20:03:50 +03:00
u8 mux_updated ;
2021-06-22 20:03:58 +03:00
u8 speaker_switching_switched ;
2021-06-21 21:09:24 +03:00
u8 sync ;
2019-07-28 18:12:45 +03:00
u8 master_vol ;
u8 vol [ SCARLETT2_ANALOGUE_MAX ] ;
u8 vol_sw_hw_switch [ SCARLETT2_ANALOGUE_MAX ] ;
2021-06-21 21:09:39 +03:00
u8 mute_switch [ SCARLETT2_ANALOGUE_MAX ] ;
2019-07-28 18:12:45 +03:00
u8 level_switch [ SCARLETT2_LEVEL_SWITCH_MAX ] ;
u8 pad_switch [ SCARLETT2_PAD_SWITCH_MAX ] ;
2021-06-20 19:46:36 +03:00
u8 dim_mute [ SCARLETT2_DIM_MUTE_COUNT ] ;
2021-06-22 20:02:36 +03:00
u8 air_switch [ SCARLETT2_AIR_SWITCH_MAX ] ;
2021-06-22 20:02:40 +03:00
u8 phantom_switch [ SCARLETT2_PHANTOM_SWITCH_MAX ] ;
u8 phantom_persistence ;
2021-06-22 20:03:08 +03:00
u8 direct_monitor_switch ;
2021-06-22 20:03:58 +03:00
u8 speaker_switching_switch ;
2021-06-22 20:04:13 +03:00
u8 talkback_switch ;
u8 talkback_map [ SCARLETT2_OUTPUT_MIX_MAX ] ;
2021-06-22 20:01:52 +03:00
u8 msd_switch ;
2022-03-06 18:21:39 +03:00
u8 standalone_switch ;
2021-06-21 21:09:24 +03:00
struct snd_kcontrol * sync_ctl ;
2019-07-28 18:12:45 +03:00
struct snd_kcontrol * master_vol_ctl ;
struct snd_kcontrol * vol_ctls [ SCARLETT2_ANALOGUE_MAX ] ;
2021-06-22 20:03:45 +03:00
struct snd_kcontrol * sw_hw_ctls [ SCARLETT2_ANALOGUE_MAX ] ;
2021-06-21 21:09:39 +03:00
struct snd_kcontrol * mute_ctls [ SCARLETT2_ANALOGUE_MAX ] ;
2021-06-20 19:46:36 +03:00
struct snd_kcontrol * dim_mute_ctls [ SCARLETT2_DIM_MUTE_COUNT ] ;
2021-06-22 20:01:44 +03:00
struct snd_kcontrol * level_ctls [ SCARLETT2_LEVEL_SWITCH_MAX ] ;
struct snd_kcontrol * pad_ctls [ SCARLETT2_PAD_SWITCH_MAX ] ;
2021-06-22 20:02:36 +03:00
struct snd_kcontrol * air_ctls [ SCARLETT2_AIR_SWITCH_MAX ] ;
2021-06-22 20:02:40 +03:00
struct snd_kcontrol * phantom_ctls [ SCARLETT2_PHANTOM_SWITCH_MAX ] ;
2021-06-22 20:03:45 +03:00
struct snd_kcontrol * mux_ctls [ SCARLETT2_MUX_MAX ] ;
2021-06-22 20:03:08 +03:00
struct snd_kcontrol * direct_monitor_ctl ;
2021-06-22 20:03:58 +03:00
struct snd_kcontrol * speaker_switching_ctl ;
2021-06-22 20:04:13 +03:00
struct snd_kcontrol * talkback_ctl ;
2019-07-28 18:12:45 +03:00
u8 mux [ SCARLETT2_MUX_MAX ] ;
u8 mix [ SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX ] ;
} ;
/*** Model-specific data ***/
static const struct scarlett2_device_info s6i6_gen2_info = {
2021-06-21 21:09:31 +03:00
. usb_id = USB_ID ( 0x1235 , 0x8203 ) ,
2022-03-06 18:21:04 +03:00
. config_set = SCARLETT2_CONFIG_SET_GEN_2 ,
2019-07-28 18:12:45 +03:00
. level_input_count = 2 ,
. pad_input_count = 2 ,
. line_out_descrs = {
2021-06-21 21:09:18 +03:00
" Headphones 1 L " ,
" Headphones 1 R " ,
" Headphones 2 L " ,
" Headphones 2 R " ,
2019-07-28 18:12:45 +03:00
} ,
2021-06-21 21:09:43 +03:00
. port_count = {
[ SCARLETT2_PORT_TYPE_NONE ] = { 1 , 0 } ,
[ SCARLETT2_PORT_TYPE_ANALOGUE ] = { 4 , 4 } ,
[ SCARLETT2_PORT_TYPE_SPDIF ] = { 2 , 2 } ,
[ SCARLETT2_PORT_TYPE_MIX ] = { 10 , 18 } ,
[ SCARLETT2_PORT_TYPE_PCM ] = { 6 , 6 } ,
2019-07-28 18:12:45 +03:00
} ,
2021-06-21 21:09:41 +03:00
. mux_assignment = { {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 6 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 4 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 8 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 6 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 4 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 8 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 6 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 4 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 8 } ,
{ 0 , 0 , 0 } ,
} } ,
2019-07-28 18:12:45 +03:00
} ;
static const struct scarlett2_device_info s18i8_gen2_info = {
2021-06-21 21:09:31 +03:00
. usb_id = USB_ID ( 0x1235 , 0x8204 ) ,
2022-03-06 18:21:04 +03:00
. config_set = SCARLETT2_CONFIG_SET_GEN_2 ,
2019-07-28 18:12:45 +03:00
. level_input_count = 2 ,
. pad_input_count = 4 ,
. line_out_descrs = {
" Monitor L " ,
" Monitor R " ,
" Headphones 1 L " ,
" Headphones 1 R " ,
" Headphones 2 L " ,
" Headphones 2 R " ,
} ,
2021-06-21 21:09:43 +03:00
. port_count = {
[ SCARLETT2_PORT_TYPE_NONE ] = { 1 , 0 } ,
[ SCARLETT2_PORT_TYPE_ANALOGUE ] = { 8 , 6 } ,
[ SCARLETT2_PORT_TYPE_SPDIF ] = { 2 , 2 } ,
[ SCARLETT2_PORT_TYPE_ADAT ] = { 8 , 0 } ,
[ SCARLETT2_PORT_TYPE_MIX ] = { 10 , 18 } ,
[ SCARLETT2_PORT_TYPE_PCM ] = { 8 , 18 } ,
2019-07-28 18:12:45 +03:00
} ,
2021-06-21 21:09:41 +03:00
. mux_assignment = { {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 6 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 8 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 14 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 6 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 8 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 6 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 4 } ,
{ 0 , 0 , 0 } ,
} } ,
2019-07-28 18:12:45 +03:00
} ;
static const struct scarlett2_device_info s18i20_gen2_info = {
2021-06-21 21:09:31 +03:00
. usb_id = USB_ID ( 0x1235 , 0x8201 ) ,
2022-03-06 18:21:04 +03:00
. config_set = SCARLETT2_CONFIG_SET_GEN_2 ,
2019-07-28 18:12:45 +03:00
. line_out_hw_vol = 1 ,
. line_out_descrs = {
" Monitor L " ,
" Monitor R " ,
NULL ,
NULL ,
NULL ,
NULL ,
" Headphones 1 L " ,
" Headphones 1 R " ,
" Headphones 2 L " ,
" Headphones 2 R " ,
} ,
2021-06-21 21:09:43 +03:00
. port_count = {
[ SCARLETT2_PORT_TYPE_NONE ] = { 1 , 0 } ,
[ SCARLETT2_PORT_TYPE_ANALOGUE ] = { 8 , 10 } ,
[ SCARLETT2_PORT_TYPE_SPDIF ] = { 2 , 2 } ,
[ SCARLETT2_PORT_TYPE_ADAT ] = { 8 , 8 } ,
[ SCARLETT2_PORT_TYPE_MIX ] = { 10 , 18 } ,
[ SCARLETT2_PORT_TYPE_PCM ] = { 20 , 18 } ,
2019-07-28 18:12:45 +03:00
} ,
2021-06-21 21:09:41 +03:00
. mux_assignment = { {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_ADAT , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 8 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 14 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_ADAT , 0 , 4 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 8 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 6 } ,
{ 0 , 0 , 0 } ,
} } ,
2019-07-28 18:12:45 +03:00
} ;
2021-06-22 20:02:31 +03:00
static const struct scarlett2_device_info solo_gen3_info = {
. usb_id = USB_ID ( 0x1235 , 0x8211 ) ,
. has_msd_mode = 1 ,
2022-03-06 18:21:04 +03:00
. config_set = SCARLETT2_CONFIG_SET_NO_MIXER ,
2021-06-22 20:02:31 +03:00
. level_input_count = 1 ,
. level_input_first = 1 ,
2021-06-22 20:02:36 +03:00
. air_input_count = 1 ,
2021-06-22 20:02:40 +03:00
. phantom_count = 1 ,
. inputs_per_phantom = 1 ,
2021-06-22 20:03:08 +03:00
. direct_monitor = 1 ,
2021-06-22 20:02:31 +03:00
} ;
static const struct scarlett2_device_info s2i2_gen3_info = {
. usb_id = USB_ID ( 0x1235 , 0x8210 ) ,
. has_msd_mode = 1 ,
2022-03-06 18:21:04 +03:00
. config_set = SCARLETT2_CONFIG_SET_NO_MIXER ,
2021-06-22 20:02:31 +03:00
. level_input_count = 2 ,
2021-06-22 20:02:36 +03:00
. air_input_count = 2 ,
2021-06-22 20:02:40 +03:00
. phantom_count = 1 ,
. inputs_per_phantom = 2 ,
2021-06-22 20:03:08 +03:00
. direct_monitor = 2 ,
2021-06-22 20:02:31 +03:00
} ;
2021-06-22 20:01:37 +03:00
static const struct scarlett2_device_info s4i4_gen3_info = {
. usb_id = USB_ID ( 0x1235 , 0x8212 ) ,
2021-06-22 20:01:52 +03:00
. has_msd_mode = 1 ,
2022-03-06 18:21:04 +03:00
. config_set = SCARLETT2_CONFIG_SET_GEN_3 ,
2021-06-22 20:01:37 +03:00
. level_input_count = 2 ,
. pad_input_count = 2 ,
2021-06-22 20:02:36 +03:00
. air_input_count = 2 ,
2021-06-22 20:02:40 +03:00
. phantom_count = 1 ,
. inputs_per_phantom = 2 ,
2021-06-22 20:01:37 +03:00
. line_out_descrs = {
" Monitor L " ,
" Monitor R " ,
" Headphones L " ,
" Headphones R " ,
} ,
. port_count = {
[ SCARLETT2_PORT_TYPE_NONE ] = { 1 , 0 } ,
[ SCARLETT2_PORT_TYPE_ANALOGUE ] = { 4 , 4 } ,
[ SCARLETT2_PORT_TYPE_MIX ] = { 6 , 8 } ,
[ SCARLETT2_PORT_TYPE_PCM ] = { 4 , 6 } ,
} ,
. mux_assignment = { {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 6 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 4 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 16 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 6 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 4 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 16 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 6 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 4 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 16 } ,
{ 0 , 0 , 0 } ,
} } ,
} ;
static const struct scarlett2_device_info s8i6_gen3_info = {
. usb_id = USB_ID ( 0x1235 , 0x8213 ) ,
2021-06-22 20:01:52 +03:00
. has_msd_mode = 1 ,
2022-03-06 18:21:04 +03:00
. config_set = SCARLETT2_CONFIG_SET_GEN_3 ,
2021-06-22 20:01:37 +03:00
. level_input_count = 2 ,
. pad_input_count = 2 ,
2021-06-22 20:02:36 +03:00
. air_input_count = 2 ,
2021-06-22 20:02:40 +03:00
. phantom_count = 1 ,
. inputs_per_phantom = 2 ,
2021-06-22 20:01:37 +03:00
. line_out_descrs = {
" Headphones 1 L " ,
" Headphones 1 R " ,
" Headphones 2 L " ,
" Headphones 2 R " ,
} ,
. port_count = {
[ SCARLETT2_PORT_TYPE_NONE ] = { 1 , 0 } ,
[ SCARLETT2_PORT_TYPE_ANALOGUE ] = { 6 , 4 } ,
[ SCARLETT2_PORT_TYPE_SPDIF ] = { 2 , 2 } ,
[ SCARLETT2_PORT_TYPE_MIX ] = { 8 , 8 } ,
[ SCARLETT2_PORT_TYPE_PCM ] = { 6 , 10 } ,
} ,
. mux_assignment = { {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 4 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_PCM , 8 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 18 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 4 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_PCM , 8 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 18 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 4 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_PCM , 8 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 18 } ,
{ 0 , 0 , 0 } ,
} } ,
} ;
static const struct scarlett2_device_info s18i8_gen3_info = {
. usb_id = USB_ID ( 0x1235 , 0x8214 ) ,
2021-06-22 20:01:52 +03:00
. has_msd_mode = 1 ,
2022-03-06 18:21:04 +03:00
. config_set = SCARLETT2_CONFIG_SET_GEN_3 ,
2021-06-22 20:01:37 +03:00
. line_out_hw_vol = 1 ,
2021-06-22 20:03:58 +03:00
. has_speaker_switching = 1 ,
2021-06-22 20:01:37 +03:00
. level_input_count = 2 ,
2021-06-27 16:22:26 +03:00
. pad_input_count = 4 ,
2021-06-22 20:02:36 +03:00
. air_input_count = 4 ,
2021-06-22 20:02:40 +03:00
. phantom_count = 2 ,
. inputs_per_phantom = 2 ,
2021-06-22 20:01:37 +03:00
2021-06-22 20:03:16 +03:00
. line_out_remap_enable = 1 ,
. line_out_remap = { 0 , 1 , 6 , 7 , 2 , 3 , 4 , 5 } ,
2021-06-22 20:01:37 +03:00
. line_out_descrs = {
" Monitor L " ,
" Monitor R " ,
2021-06-22 20:03:16 +03:00
" Alt Monitor L " ,
" Alt Monitor R " ,
2021-06-22 20:01:37 +03:00
" Headphones 1 L " ,
" Headphones 1 R " ,
" Headphones 2 L " ,
" Headphones 2 R " ,
} ,
. port_count = {
[ SCARLETT2_PORT_TYPE_NONE ] = { 1 , 0 } ,
[ SCARLETT2_PORT_TYPE_ANALOGUE ] = { 8 , 8 } ,
[ SCARLETT2_PORT_TYPE_SPDIF ] = { 2 , 2 } ,
[ SCARLETT2_PORT_TYPE_ADAT ] = { 8 , 0 } ,
[ SCARLETT2_PORT_TYPE_MIX ] = { 10 , 20 } ,
[ SCARLETT2_PORT_TYPE_PCM ] = { 8 , 20 } ,
} ,
. mux_assignment = { {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_PCM , 12 , 8 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 6 , 2 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 2 , 4 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_PCM , 10 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 20 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 10 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_PCM , 12 , 4 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 6 , 2 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 2 , 4 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_PCM , 10 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 20 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 10 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 6 , 2 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 2 , 4 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 20 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 10 } ,
{ 0 , 0 , 0 } ,
} } ,
} ;
static const struct scarlett2_device_info s18i20_gen3_info = {
. usb_id = USB_ID ( 0x1235 , 0x8215 ) ,
2021-06-22 20:01:52 +03:00
. has_msd_mode = 1 ,
2022-03-06 18:21:04 +03:00
. config_set = SCARLETT2_CONFIG_SET_GEN_3 ,
2021-06-22 20:01:37 +03:00
. line_out_hw_vol = 1 ,
2021-06-22 20:03:58 +03:00
. has_speaker_switching = 1 ,
2021-06-22 20:04:13 +03:00
. has_talkback = 1 ,
2021-06-22 20:01:37 +03:00
. level_input_count = 2 ,
. pad_input_count = 8 ,
2021-06-22 20:02:36 +03:00
. air_input_count = 8 ,
2021-06-22 20:02:40 +03:00
. phantom_count = 2 ,
. inputs_per_phantom = 4 ,
2021-06-22 20:01:37 +03:00
. line_out_descrs = {
" Monitor 1 L " ,
" Monitor 1 R " ,
" Monitor 2 L " ,
" Monitor 2 R " ,
NULL ,
NULL ,
" Headphones 1 L " ,
" Headphones 1 R " ,
" Headphones 2 L " ,
" Headphones 2 R " ,
} ,
. port_count = {
[ SCARLETT2_PORT_TYPE_NONE ] = { 1 , 0 } ,
[ SCARLETT2_PORT_TYPE_ANALOGUE ] = { 9 , 10 } ,
[ SCARLETT2_PORT_TYPE_SPDIF ] = { 2 , 2 } ,
[ SCARLETT2_PORT_TYPE_ADAT ] = { 8 , 8 } ,
[ SCARLETT2_PORT_TYPE_MIX ] = { 12 , 25 } ,
[ SCARLETT2_PORT_TYPE_PCM ] = { 20 , 20 } ,
} ,
. mux_assignment = { {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_PCM , 10 , 10 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_ADAT , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_PCM , 8 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 25 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 12 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_PCM , 10 , 8 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_ADAT , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_PCM , 8 , 2 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 25 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 10 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 24 } ,
{ 0 , 0 , 0 } ,
} } ,
} ;
2022-08-09 07:32:41 +03:00
static const struct scarlett2_device_info clarett_8pre_info = {
. usb_id = USB_ID ( 0x1235 , 0x820c ) ,
. config_set = SCARLETT2_CONFIG_SET_CLARETT ,
. line_out_hw_vol = 1 ,
. level_input_count = 2 ,
. air_input_count = 8 ,
. line_out_descrs = {
" Monitor L " ,
" Monitor R " ,
NULL ,
NULL ,
NULL ,
NULL ,
" Headphones 1 L " ,
" Headphones 1 R " ,
" Headphones 2 L " ,
" Headphones 2 R " ,
} ,
. port_count = {
[ SCARLETT2_PORT_TYPE_NONE ] = { 1 , 0 } ,
[ SCARLETT2_PORT_TYPE_ANALOGUE ] = { 8 , 10 } ,
[ SCARLETT2_PORT_TYPE_SPDIF ] = { 2 , 2 } ,
[ SCARLETT2_PORT_TYPE_ADAT ] = { 8 , 8 } ,
[ SCARLETT2_PORT_TYPE_MIX ] = { 10 , 18 } ,
[ SCARLETT2_PORT_TYPE_PCM ] = { 20 , 18 } ,
} ,
. mux_assignment = { {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_ADAT , 0 , 8 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 8 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 14 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_ADAT , 0 , 4 } ,
{ SCARLETT2_PORT_TYPE_MIX , 0 , 18 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 8 } ,
{ 0 , 0 , 0 } ,
} , {
{ SCARLETT2_PORT_TYPE_PCM , 0 , 12 } ,
{ SCARLETT2_PORT_TYPE_ANALOGUE , 0 , 10 } ,
{ SCARLETT2_PORT_TYPE_SPDIF , 0 , 2 } ,
{ SCARLETT2_PORT_TYPE_NONE , 0 , 22 } ,
{ 0 , 0 , 0 } ,
} } ,
} ;
2021-06-21 21:09:31 +03:00
static const struct scarlett2_device_info * scarlett2_devices [ ] = {
/* Supported Gen 2 devices */
& s6i6_gen2_info ,
& s18i8_gen2_info ,
& s18i20_gen2_info ,
2021-06-22 20:01:37 +03:00
/* Supported Gen 3 devices */
2021-06-22 20:02:31 +03:00
& solo_gen3_info ,
& s2i2_gen3_info ,
2021-06-22 20:01:37 +03:00
& s4i4_gen3_info ,
& s8i6_gen3_info ,
& s18i8_gen3_info ,
& s18i20_gen3_info ,
2022-08-09 07:32:41 +03:00
/* Supported Clarett+ devices */
& clarett_8pre_info ,
2021-06-21 21:09:31 +03:00
/* End of list */
NULL
} ;
2019-07-28 18:12:45 +03:00
/* get the starting port index number for a given port type/direction */
2021-06-21 21:09:43 +03:00
static int scarlett2_get_port_start_num (
const int port_count [ ] [ SCARLETT2_PORT_DIRNS ] ,
int direction , int port_type )
2019-07-28 18:12:45 +03:00
{
int i , num = 0 ;
for ( i = 0 ; i < port_type ; i + + )
2021-06-21 21:09:43 +03:00
num + = port_count [ i ] [ direction ] ;
2019-07-28 18:12:45 +03:00
return num ;
}
/*** USB Interactions ***/
2021-06-21 21:09:24 +03:00
/* Notifications from the interface */
2021-06-22 20:03:08 +03:00
# define SCARLETT2_USB_NOTIFY_SYNC 0x00000008
# define SCARLETT2_USB_NOTIFY_DIM_MUTE 0x00200000
# define SCARLETT2_USB_NOTIFY_MONITOR 0x00400000
# define SCARLETT2_USB_NOTIFY_INPUT_OTHER 0x00800000
# define SCARLETT2_USB_NOTIFY_MONITOR_OTHER 0x01000000
2019-07-28 18:12:45 +03:00
/* Commands for sending/receiving requests/responses */
2021-06-21 21:09:13 +03:00
# define SCARLETT2_USB_CMD_INIT 0
2021-06-21 21:09:06 +03:00
# define SCARLETT2_USB_CMD_REQ 2
# define SCARLETT2_USB_CMD_RESP 3
2019-07-28 18:12:45 +03:00
2021-06-21 21:09:13 +03:00
# define SCARLETT2_USB_INIT_1 0x00000000
# define SCARLETT2_USB_INIT_2 0x00000002
2021-06-20 19:46:28 +03:00
# define SCARLETT2_USB_GET_METER 0x00001001
# define SCARLETT2_USB_GET_MIX 0x00002001
# define SCARLETT2_USB_SET_MIX 0x00002002
# define SCARLETT2_USB_GET_MUX 0x00003001
# define SCARLETT2_USB_SET_MUX 0x00003002
2021-06-21 21:09:24 +03:00
# define SCARLETT2_USB_GET_SYNC 0x00006004
2021-06-20 19:46:28 +03:00
# define SCARLETT2_USB_GET_DATA 0x00800000
# define SCARLETT2_USB_SET_DATA 0x00800001
# define SCARLETT2_USB_DATA_CMD 0x00800002
2019-07-28 18:12:45 +03:00
# define SCARLETT2_USB_CONFIG_SAVE 6
# define SCARLETT2_USB_VOLUME_STATUS_OFFSET 0x31
# define SCARLETT2_USB_METER_LEVELS_GET_MAGIC 1
2021-06-22 20:02:31 +03:00
/* volume status is read together (matches scarlett2_config_items[1]) */
2019-07-28 18:12:45 +03:00
struct scarlett2_usb_volume_status {
2021-06-20 19:46:36 +03:00
/* dim/mute buttons */
u8 dim_mute [ SCARLETT2_DIM_MUTE_COUNT ] ;
2019-07-28 18:12:45 +03:00
u8 pad1 ;
/* software volume setting */
s16 sw_vol [ SCARLETT2_ANALOGUE_MAX ] ;
/* actual volume of output inc. dim (-18dB) */
s16 hw_vol [ SCARLETT2_ANALOGUE_MAX ] ;
2021-06-21 21:09:39 +03:00
/* internal mute buttons */
u8 mute_switch [ SCARLETT2_ANALOGUE_MAX ] ;
2019-07-28 18:12:45 +03:00
/* sw (0) or hw (1) controlled */
u8 sw_hw_switch [ SCARLETT2_ANALOGUE_MAX ] ;
u8 pad3 [ 6 ] ;
/* front panel volume knob */
s16 master_vol ;
} __packed ;
/* Configuration parameters that can be read and written */
enum {
2021-06-20 19:46:36 +03:00
SCARLETT2_CONFIG_DIM_MUTE = 0 ,
2019-07-28 18:12:45 +03:00
SCARLETT2_CONFIG_LINE_OUT_VOLUME = 1 ,
2021-06-21 21:09:39 +03:00
SCARLETT2_CONFIG_MUTE_SWITCH = 2 ,
SCARLETT2_CONFIG_SW_HW_SWITCH = 3 ,
SCARLETT2_CONFIG_LEVEL_SWITCH = 4 ,
SCARLETT2_CONFIG_PAD_SWITCH = 5 ,
2021-06-22 20:01:52 +03:00
SCARLETT2_CONFIG_MSD_SWITCH = 6 ,
2021-06-22 20:02:36 +03:00
SCARLETT2_CONFIG_AIR_SWITCH = 7 ,
2022-03-06 18:21:39 +03:00
SCARLETT2_CONFIG_STANDALONE_SWITCH = 8 ,
SCARLETT2_CONFIG_PHANTOM_SWITCH = 9 ,
SCARLETT2_CONFIG_PHANTOM_PERSISTENCE = 10 ,
SCARLETT2_CONFIG_DIRECT_MONITOR = 11 ,
SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH = 12 ,
SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE = 13 ,
SCARLETT2_CONFIG_TALKBACK_MAP = 14 ,
SCARLETT2_CONFIG_COUNT = 15
2019-07-28 18:12:45 +03:00
} ;
/* Location, size, and activation command number for the configuration
2021-06-22 20:02:25 +03:00
* parameters . Size is in bits and may be 1 , 8 , or 16.
2019-07-28 18:12:45 +03:00
*/
struct scarlett2_config {
u8 offset ;
u8 size ;
u8 activate ;
} ;
static const struct scarlett2_config
2022-03-06 18:21:04 +03:00
scarlett2_config_items [ SCARLETT2_CONFIG_SET_COUNT ]
[ SCARLETT2_CONFIG_COUNT ] =
2021-06-22 20:02:31 +03:00
2022-03-06 18:21:04 +03:00
/* Devices without a mixer (Gen 3 Solo and 2i2) */
2021-06-22 20:02:31 +03:00
{ {
[ SCARLETT2_CONFIG_MSD_SWITCH ] = {
. offset = 0x04 , . size = 8 , . activate = 6 } ,
2021-06-22 20:02:40 +03:00
[ SCARLETT2_CONFIG_PHANTOM_PERSISTENCE ] = {
. offset = 0x05 , . size = 8 , . activate = 6 } ,
[ SCARLETT2_CONFIG_PHANTOM_SWITCH ] = {
. offset = 0x06 , . size = 8 , . activate = 3 } ,
2021-06-22 20:03:08 +03:00
[ SCARLETT2_CONFIG_DIRECT_MONITOR ] = {
. offset = 0x07 , . size = 8 , . activate = 4 } ,
2021-06-22 20:02:31 +03:00
[ SCARLETT2_CONFIG_LEVEL_SWITCH ] = {
. offset = 0x08 , . size = 1 , . activate = 7 } ,
2021-06-22 20:02:36 +03:00
[ SCARLETT2_CONFIG_AIR_SWITCH ] = {
. offset = 0x09 , . size = 1 , . activate = 8 } ,
2022-03-06 18:21:04 +03:00
/* Gen 2 devices: 6i6, 18i8, 18i20 */
} , {
[ SCARLETT2_CONFIG_DIM_MUTE ] = {
. offset = 0x31 , . size = 8 , . activate = 2 } ,
[ SCARLETT2_CONFIG_LINE_OUT_VOLUME ] = {
. offset = 0x34 , . size = 16 , . activate = 1 } ,
[ SCARLETT2_CONFIG_MUTE_SWITCH ] = {
. offset = 0x5c , . size = 8 , . activate = 1 } ,
[ SCARLETT2_CONFIG_SW_HW_SWITCH ] = {
. offset = 0x66 , . size = 8 , . activate = 3 } ,
[ SCARLETT2_CONFIG_LEVEL_SWITCH ] = {
. offset = 0x7c , . size = 8 , . activate = 7 } ,
[ SCARLETT2_CONFIG_PAD_SWITCH ] = {
. offset = 0x84 , . size = 8 , . activate = 8 } ,
2022-03-06 18:21:39 +03:00
[ SCARLETT2_CONFIG_STANDALONE_SWITCH ] = {
. offset = 0x8d , . size = 8 , . activate = 6 } ,
2022-03-06 18:21:04 +03:00
/* Gen 3 devices: 4i4, 8i6, 18i8, 18i20 */
2021-06-22 20:02:31 +03:00
} , {
2021-06-21 21:09:29 +03:00
[ SCARLETT2_CONFIG_DIM_MUTE ] = {
2021-06-22 20:02:25 +03:00
. offset = 0x31 , . size = 8 , . activate = 2 } ,
2019-07-28 18:12:45 +03:00
2021-06-21 21:09:29 +03:00
[ SCARLETT2_CONFIG_LINE_OUT_VOLUME ] = {
2021-06-22 20:02:25 +03:00
. offset = 0x34 , . size = 16 , . activate = 1 } ,
2019-07-28 18:12:45 +03:00
2021-06-21 21:09:39 +03:00
[ SCARLETT2_CONFIG_MUTE_SWITCH ] = {
2021-06-22 20:02:25 +03:00
. offset = 0x5c , . size = 8 , . activate = 1 } ,
2021-06-21 21:09:39 +03:00
2021-06-21 21:09:29 +03:00
[ SCARLETT2_CONFIG_SW_HW_SWITCH ] = {
2021-06-22 20:02:25 +03:00
. offset = 0x66 , . size = 8 , . activate = 3 } ,
2019-07-28 18:12:45 +03:00
2021-06-21 21:09:29 +03:00
[ SCARLETT2_CONFIG_LEVEL_SWITCH ] = {
2021-06-22 20:02:25 +03:00
. offset = 0x7c , . size = 8 , . activate = 7 } ,
2019-07-28 18:12:45 +03:00
2021-06-21 21:09:29 +03:00
[ SCARLETT2_CONFIG_PAD_SWITCH ] = {
2021-06-22 20:02:25 +03:00
. offset = 0x84 , . size = 8 , . activate = 8 } ,
2021-06-22 20:01:52 +03:00
2021-06-22 20:02:36 +03:00
[ SCARLETT2_CONFIG_AIR_SWITCH ] = {
. offset = 0x8c , . size = 8 , . activate = 8 } ,
2022-03-06 18:21:39 +03:00
[ SCARLETT2_CONFIG_STANDALONE_SWITCH ] = {
. offset = 0x95 , . size = 8 , . activate = 6 } ,
2021-06-22 20:02:40 +03:00
[ SCARLETT2_CONFIG_PHANTOM_SWITCH ] = {
. offset = 0x9c , . size = 1 , . activate = 8 } ,
2021-06-22 20:01:52 +03:00
[ SCARLETT2_CONFIG_MSD_SWITCH ] = {
2021-06-22 20:02:25 +03:00
. offset = 0x9d , . size = 8 , . activate = 6 } ,
2021-06-22 20:02:40 +03:00
[ SCARLETT2_CONFIG_PHANTOM_PERSISTENCE ] = {
. offset = 0x9e , . size = 8 , . activate = 6 } ,
2021-06-22 20:03:58 +03:00
[ SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH ] = {
. offset = 0x9f , . size = 1 , . activate = 10 } ,
[ SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE ] = {
. offset = 0xa0 , . size = 1 , . activate = 10 } ,
2021-06-22 20:04:13 +03:00
[ SCARLETT2_CONFIG_TALKBACK_MAP ] = {
. offset = 0xb0 , . size = 16 , . activate = 10 } ,
2022-08-09 07:32:41 +03:00
/* Clarett+ 8Pre */
} , {
[ SCARLETT2_CONFIG_DIM_MUTE ] = {
. offset = 0x31 , . size = 8 , . activate = 2 } ,
[ SCARLETT2_CONFIG_LINE_OUT_VOLUME ] = {
. offset = 0x34 , . size = 16 , . activate = 1 } ,
[ SCARLETT2_CONFIG_MUTE_SWITCH ] = {
. offset = 0x5c , . size = 8 , . activate = 1 } ,
[ SCARLETT2_CONFIG_SW_HW_SWITCH ] = {
. offset = 0x66 , . size = 8 , . activate = 3 } ,
[ SCARLETT2_CONFIG_LEVEL_SWITCH ] = {
. offset = 0x7c , . size = 8 , . activate = 7 } ,
[ SCARLETT2_CONFIG_AIR_SWITCH ] = {
. offset = 0x95 , . size = 8 , . activate = 8 } ,
[ SCARLETT2_CONFIG_STANDALONE_SWITCH ] = {
. offset = 0x8d , . size = 8 , . activate = 6 } ,
2021-06-22 20:02:31 +03:00
} } ;
2019-07-28 18:12:45 +03:00
/* proprietary request/response format */
struct scarlett2_usb_packet {
2020-02-01 11:05:29 +03:00
__le32 cmd ;
__le16 size ;
__le16 seq ;
__le32 error ;
__le32 pad ;
2019-07-28 18:12:45 +03:00
u8 data [ ] ;
} ;
2021-06-20 19:46:39 +03:00
static void scarlett2_fill_request_header ( struct scarlett2_data * private ,
2019-07-28 18:12:45 +03:00
struct scarlett2_usb_packet * req ,
u32 cmd , u16 req_size )
{
/* sequence must go up by 1 for each request */
u16 seq = private - > scarlett2_seq + + ;
req - > cmd = cpu_to_le32 ( cmd ) ;
req - > size = cpu_to_le16 ( req_size ) ;
req - > seq = cpu_to_le16 ( seq ) ;
req - > error = 0 ;
req - > pad = 0 ;
}
2021-06-21 21:09:06 +03:00
static int scarlett2_usb_tx ( struct usb_device * dev , int interface ,
void * buf , u16 size )
{
return snd_usb_ctl_msg ( dev , usb_sndctrlpipe ( dev , 0 ) ,
SCARLETT2_USB_CMD_REQ ,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT ,
0 , interface , buf , size ) ;
}
static int scarlett2_usb_rx ( struct usb_device * dev , int interface ,
u32 usb_req , void * buf , u16 size )
{
return snd_usb_ctl_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) ,
usb_req ,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN ,
0 , interface , buf , size ) ;
}
2019-07-28 18:12:45 +03:00
/* Send a proprietary format request to the Scarlett interface */
static int scarlett2_usb (
struct usb_mixer_interface * mixer , u32 cmd ,
void * req_data , u16 req_size , void * resp_data , u16 resp_size )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-21 21:09:06 +03:00
struct usb_device * dev = mixer - > chip - > dev ;
2021-06-20 19:46:30 +03:00
struct scarlett2_usb_packet * req , * resp = NULL ;
2022-01-21 00:16:00 +03:00
size_t req_buf_size = struct_size ( req , data , req_size ) ;
size_t resp_buf_size = struct_size ( resp , data , resp_size ) ;
2021-06-20 19:46:30 +03:00
int err ;
2019-07-28 18:12:45 +03:00
req = kmalloc ( req_buf_size , GFP_KERNEL ) ;
if ( ! req ) {
err = - ENOMEM ;
goto error ;
}
resp = kmalloc ( resp_buf_size , GFP_KERNEL ) ;
if ( ! resp ) {
err = - ENOMEM ;
goto error ;
}
mutex_lock ( & private - > usb_mutex ) ;
/* build request message and send it */
scarlett2_fill_request_header ( private , req , cmd , req_size ) ;
if ( req_size )
memcpy ( req - > data , req_data , req_size ) ;
2021-06-21 21:09:06 +03:00
err = scarlett2_usb_tx ( dev , private - > bInterfaceNumber ,
req , req_buf_size ) ;
2019-07-28 18:12:45 +03:00
if ( err ! = req_buf_size ) {
usb_audio_err (
mixer - > chip ,
2021-06-22 20:01:37 +03:00
" Scarlett Gen 2/3 USB request result cmd %x was %d \n " ,
2019-07-28 18:12:45 +03:00
cmd , err ) ;
err = - EINVAL ;
goto unlock ;
}
/* send a second message to get the response */
2021-06-21 21:09:06 +03:00
err = scarlett2_usb_rx ( dev , private - > bInterfaceNumber ,
SCARLETT2_USB_CMD_RESP ,
resp , resp_buf_size ) ;
2019-07-28 18:12:45 +03:00
/* validate the response */
if ( err ! = resp_buf_size ) {
usb_audio_err (
mixer - > chip ,
2021-06-22 20:01:37 +03:00
" Scarlett Gen 2/3 USB response result cmd %x was %d "
2022-01-21 00:16:00 +03:00
" expected %zu \n " ,
2021-06-21 21:09:13 +03:00
cmd , err , resp_buf_size ) ;
2019-07-28 18:12:45 +03:00
err = - EINVAL ;
goto unlock ;
}
2021-06-21 21:09:13 +03:00
/* cmd/seq/size should match except when initialising
* seq sent = 1 , response = 0
*/
2019-07-28 18:12:45 +03:00
if ( resp - > cmd ! = req - > cmd | |
2021-06-21 21:09:13 +03:00
( resp - > seq ! = req - > seq & &
( le16_to_cpu ( req - > seq ) ! = 1 | | resp - > seq ! = 0 ) ) | |
2019-07-28 18:12:45 +03:00
resp_size ! = le16_to_cpu ( resp - > size ) | |
resp - > error | |
resp - > pad ) {
usb_audio_err (
mixer - > chip ,
2021-06-22 20:01:37 +03:00
" Scarlett Gen 2/3 USB invalid response; "
2019-07-28 18:12:45 +03:00
" cmd tx/rx %d/%d seq %d/%d size %d/%d "
" error %d pad %d \n " ,
2020-02-01 11:05:29 +03:00
le32_to_cpu ( req - > cmd ) , le32_to_cpu ( resp - > cmd ) ,
2019-07-28 18:12:45 +03:00
le16_to_cpu ( req - > seq ) , le16_to_cpu ( resp - > seq ) ,
resp_size , le16_to_cpu ( resp - > size ) ,
2020-02-01 11:05:29 +03:00
le32_to_cpu ( resp - > error ) ,
le32_to_cpu ( resp - > pad ) ) ;
2019-07-28 18:12:45 +03:00
err = - EINVAL ;
goto unlock ;
}
2021-06-21 21:09:13 +03:00
if ( resp_data & & resp_size > 0 )
2019-07-28 18:12:45 +03:00
memcpy ( resp_data , resp - > data , resp_size ) ;
unlock :
mutex_unlock ( & private - > usb_mutex ) ;
error :
kfree ( req ) ;
kfree ( resp ) ;
return err ;
}
2021-06-22 20:02:09 +03:00
/* Send a USB message to get data; result placed in *buf */
static int scarlett2_usb_get (
struct usb_mixer_interface * mixer ,
int offset , void * buf , int size )
{
struct {
__le32 offset ;
__le32 size ;
} __packed req ;
req . offset = cpu_to_le32 ( offset ) ;
req . size = cpu_to_le32 ( size ) ;
return scarlett2_usb ( mixer , SCARLETT2_USB_GET_DATA ,
& req , sizeof ( req ) , buf , size ) ;
}
/* Send a USB message to get configuration parameters; result placed in *buf */
static int scarlett2_usb_get_config (
struct usb_mixer_interface * mixer ,
int config_item_num , int count , void * buf )
{
2021-06-22 20:02:31 +03:00
struct scarlett2_data * private = mixer - > private_data ;
const struct scarlett2_device_info * info = private - > info ;
2021-06-22 20:02:09 +03:00
const struct scarlett2_config * config_item =
2022-03-06 18:21:04 +03:00
& scarlett2_config_items [ info - > config_set ] [ config_item_num ] ;
2021-06-22 20:02:25 +03:00
int size , err , i ;
2021-06-27 08:12:03 +03:00
u8 * buf_8 ;
2021-06-22 20:02:25 +03:00
u8 value ;
2021-06-22 20:02:09 +03:00
2021-06-22 20:02:25 +03:00
/* For byte-sized parameters, retrieve directly into buf */
if ( config_item - > size > = 8 ) {
size = config_item - > size / 8 * count ;
2021-06-22 20:04:09 +03:00
err = scarlett2_usb_get ( mixer , config_item - > offset , buf , size ) ;
if ( err < 0 )
return err ;
2021-06-27 08:12:03 +03:00
if ( size = = 2 ) {
u16 * buf_16 = buf ;
for ( i = 0 ; i < count ; i + + , buf_16 + + )
* buf_16 = le16_to_cpu ( * ( __le16 * ) buf_16 ) ;
}
2021-06-22 20:04:09 +03:00
return 0 ;
2021-06-22 20:02:25 +03:00
}
/* For bit-sized parameters, retrieve into value */
err = scarlett2_usb_get ( mixer , config_item - > offset , & value , 1 ) ;
if ( err < 0 )
return err ;
/* then unpack from value into buf[] */
2021-06-27 08:12:03 +03:00
buf_8 = buf ;
2021-06-22 20:02:25 +03:00
for ( i = 0 ; i < 8 & & i < count ; i + + , value > > = 1 )
2021-06-27 08:12:03 +03:00
* buf_8 + + = value & 1 ;
2021-06-22 20:02:25 +03:00
return 0 ;
2021-06-22 20:02:09 +03:00
}
2019-07-28 18:12:45 +03:00
/* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */
static void scarlett2_config_save ( struct usb_mixer_interface * mixer )
{
2020-02-01 11:05:29 +03:00
__le32 req = cpu_to_le32 ( SCARLETT2_USB_CONFIG_SAVE ) ;
2019-07-28 18:12:45 +03:00
scarlett2_usb ( mixer , SCARLETT2_USB_DATA_CMD ,
& req , sizeof ( u32 ) ,
NULL , 0 ) ;
}
/* Delayed work to save config */
static void scarlett2_config_save_work ( struct work_struct * work )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private =
container_of ( work , struct scarlett2_data , work . work ) ;
2019-07-28 18:12:45 +03:00
scarlett2_config_save ( private - > mixer ) ;
}
2021-06-22 20:02:36 +03:00
/* Send a USB message to set a SCARLETT2_CONFIG_* parameter */
2019-07-28 18:12:45 +03:00
static int scarlett2_usb_set_config (
struct usb_mixer_interface * mixer ,
int config_item_num , int index , int value )
{
2021-06-22 20:02:31 +03:00
struct scarlett2_data * private = mixer - > private_data ;
const struct scarlett2_device_info * info = private - > info ;
2021-06-20 19:46:48 +03:00
const struct scarlett2_config * config_item =
2022-03-06 18:21:04 +03:00
& scarlett2_config_items [ info - > config_set ] [ config_item_num ] ;
2019-07-28 18:12:45 +03:00
struct {
2020-02-01 11:05:29 +03:00
__le32 offset ;
__le32 bytes ;
__le32 value ;
2019-07-28 18:12:45 +03:00
} __packed req ;
2020-02-01 11:05:29 +03:00
__le32 req2 ;
2021-06-22 20:02:25 +03:00
int offset , size ;
2019-07-28 18:12:45 +03:00
int err ;
/* Cancel any pending NVRAM save */
cancel_delayed_work_sync ( & private - > work ) ;
2021-06-22 20:02:25 +03:00
/* Convert config_item->size in bits to size in bytes and
* calculate offset
*/
if ( config_item - > size > = 8 ) {
size = config_item - > size / 8 ;
offset = config_item - > offset + index * size ;
/* If updating a bit, retrieve the old value, set/clear the
* bit as needed , and update value
*/
} else {
u8 tmp ;
size = 1 ;
offset = config_item - > offset ;
scarlett2_usb_get ( mixer , offset , & tmp , 1 ) ;
if ( value )
tmp | = ( 1 < < index ) ;
else
tmp & = ~ ( 1 < < index ) ;
value = tmp ;
}
2019-07-28 18:12:45 +03:00
/* Send the configuration parameter data */
2021-06-22 20:02:25 +03:00
req . offset = cpu_to_le32 ( offset ) ;
req . bytes = cpu_to_le32 ( size ) ;
2019-07-28 18:12:45 +03:00
req . value = cpu_to_le32 ( value ) ;
err = scarlett2_usb ( mixer , SCARLETT2_USB_SET_DATA ,
2021-06-22 20:02:25 +03:00
& req , sizeof ( u32 ) * 2 + size ,
2019-07-28 18:12:45 +03:00
NULL , 0 ) ;
if ( err < 0 )
return err ;
/* Activate the change */
2021-06-20 19:46:48 +03:00
req2 = cpu_to_le32 ( config_item - > activate ) ;
2019-07-28 18:12:45 +03:00
err = scarlett2_usb ( mixer , SCARLETT2_USB_DATA_CMD ,
& req2 , sizeof ( req2 ) , NULL , 0 ) ;
if ( err < 0 )
return err ;
/* Schedule the change to be written to NVRAM */
2021-06-22 20:01:52 +03:00
if ( config_item - > activate ! = SCARLETT2_USB_CONFIG_SAVE )
schedule_delayed_work ( & private - > work , msecs_to_jiffies ( 2000 ) ) ;
2019-07-28 18:12:45 +03:00
return 0 ;
}
2021-06-21 21:09:24 +03:00
/* Send a USB message to get sync status; result placed in *sync */
static int scarlett2_usb_get_sync_status (
struct usb_mixer_interface * mixer ,
u8 * sync )
{
__le32 data ;
int err ;
err = scarlett2_usb ( mixer , SCARLETT2_USB_GET_SYNC ,
NULL , 0 , & data , sizeof ( data ) ) ;
if ( err < 0 )
return err ;
* sync = ! ! data ;
return 0 ;
}
2019-07-28 18:12:45 +03:00
/* Send a USB message to get volume status; result placed in *buf */
static int scarlett2_usb_get_volume_status (
struct usb_mixer_interface * mixer ,
struct scarlett2_usb_volume_status * buf )
{
return scarlett2_usb_get ( mixer , SCARLETT2_USB_VOLUME_STATUS_OFFSET ,
buf , sizeof ( * buf ) ) ;
}
2021-06-07 22:13:25 +03:00
/* Send a USB message to get the volumes for all inputs of one mix
* and put the values into private - > mix [ ]
*/
static int scarlett2_usb_get_mix ( struct usb_mixer_interface * mixer ,
int mix_num )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-07 22:13:25 +03:00
const struct scarlett2_device_info * info = private - > info ;
int num_mixer_in =
2021-06-21 21:09:43 +03:00
info - > port_count [ SCARLETT2_PORT_TYPE_MIX ] [ SCARLETT2_PORT_OUT ] ;
2021-06-07 22:13:25 +03:00
int err , i , j , k ;
struct {
__le16 mix_num ;
__le16 count ;
} __packed req ;
__le16 data [ SCARLETT2_INPUT_MIX_MAX ] ;
req . mix_num = cpu_to_le16 ( mix_num ) ;
req . count = cpu_to_le16 ( num_mixer_in ) ;
err = scarlett2_usb ( mixer , SCARLETT2_USB_GET_MIX ,
& req , sizeof ( req ) ,
data , num_mixer_in * sizeof ( u16 ) ) ;
if ( err < 0 )
return err ;
for ( i = 0 , j = mix_num * num_mixer_in ; i < num_mixer_in ; i + + , j + + ) {
u16 mixer_value = le16_to_cpu ( data [ i ] ) ;
for ( k = 0 ; k < SCARLETT2_MIXER_VALUE_COUNT ; k + + )
if ( scarlett2_mixer_values [ k ] > = mixer_value )
break ;
if ( k = = SCARLETT2_MIXER_VALUE_COUNT )
k = SCARLETT2_MIXER_MAX_VALUE ;
private - > mix [ j ] = k ;
}
return 0 ;
}
2019-07-28 18:12:45 +03:00
/* Send a USB message to set the volumes for all inputs of one mix
* ( values obtained from private - > mix [ ] )
*/
static int scarlett2_usb_set_mix ( struct usb_mixer_interface * mixer ,
2021-06-20 19:46:28 +03:00
int mix_num )
2019-07-28 18:12:45 +03:00
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2019-07-28 18:12:45 +03:00
const struct scarlett2_device_info * info = private - > info ;
struct {
2020-02-01 11:05:29 +03:00
__le16 mix_num ;
__le16 data [ SCARLETT2_INPUT_MIX_MAX ] ;
2019-07-28 18:12:45 +03:00
} __packed req ;
int i , j ;
int num_mixer_in =
2021-06-21 21:09:43 +03:00
info - > port_count [ SCARLETT2_PORT_TYPE_MIX ] [ SCARLETT2_PORT_OUT ] ;
2019-07-28 18:12:45 +03:00
req . mix_num = cpu_to_le16 ( mix_num ) ;
for ( i = 0 , j = mix_num * num_mixer_in ; i < num_mixer_in ; i + + , j + + )
req . data [ i ] = cpu_to_le16 (
scarlett2_mixer_values [ private - > mix [ j ] ]
) ;
return scarlett2_usb ( mixer , SCARLETT2_USB_SET_MIX ,
& req , ( num_mixer_in + 1 ) * sizeof ( u16 ) ,
NULL , 0 ) ;
}
2021-06-21 21:09:43 +03:00
/* Convert a port number index (per info->port_count) to a hardware ID */
static u32 scarlett2_mux_src_num_to_id (
const int port_count [ ] [ SCARLETT2_PORT_DIRNS ] , int num )
2019-07-28 18:12:45 +03:00
{
int port_type ;
for ( port_type = 0 ;
port_type < SCARLETT2_PORT_TYPE_COUNT ;
port_type + + ) {
2021-06-21 21:09:43 +03:00
if ( num < port_count [ port_type ] [ SCARLETT2_PORT_IN ] )
return scarlett2_ports [ port_type ] . id | num ;
num - = port_count [ port_type ] [ SCARLETT2_PORT_IN ] ;
2019-07-28 18:12:45 +03:00
}
/* Oops */
return 0 ;
}
2021-06-07 22:13:51 +03:00
/* Convert a hardware ID to a port number index */
2021-06-21 21:09:43 +03:00
static u32 scarlett2_mux_id_to_num (
const int port_count [ ] [ SCARLETT2_PORT_DIRNS ] , int direction , u32 id )
2021-06-07 22:13:51 +03:00
{
int port_type ;
int port_num = 0 ;
for ( port_type = 0 ;
port_type < SCARLETT2_PORT_TYPE_COUNT ;
port_type + + ) {
2021-06-21 21:09:43 +03:00
int base = scarlett2_ports [ port_type ] . id ;
int count = port_count [ port_type ] [ direction ] ;
2021-06-07 22:13:51 +03:00
2021-06-21 21:09:43 +03:00
if ( id > = base & & id < base + count )
return port_num + id - base ;
2021-06-07 22:13:51 +03:00
port_num + = count ;
}
/* Oops */
return - 1 ;
}
/* Convert one mux entry from the interface and load into private->mux[] */
2021-06-20 19:46:39 +03:00
static void scarlett2_usb_populate_mux ( struct scarlett2_data * private ,
2021-06-07 22:13:51 +03:00
u32 mux_entry )
{
const struct scarlett2_device_info * info = private - > info ;
2021-06-21 21:09:43 +03:00
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2021-06-07 22:13:51 +03:00
int dst_idx , src_idx ;
2021-06-21 21:09:43 +03:00
dst_idx = scarlett2_mux_id_to_num ( port_count , SCARLETT2_PORT_OUT ,
2021-06-07 22:13:51 +03:00
mux_entry & 0xFFF ) ;
if ( dst_idx < 0 )
return ;
if ( dst_idx > = private - > num_mux_dsts ) {
usb_audio_err ( private - > mixer - > chip ,
" BUG: scarlett2_mux_id_to_num(%06x, OUT): %d >= %d " ,
mux_entry , dst_idx , private - > num_mux_dsts ) ;
return ;
}
2021-06-21 21:09:43 +03:00
src_idx = scarlett2_mux_id_to_num ( port_count , SCARLETT2_PORT_IN ,
2021-06-07 22:13:51 +03:00
mux_entry > > 12 ) ;
if ( src_idx < 0 )
return ;
if ( src_idx > = private - > num_mux_srcs ) {
usb_audio_err ( private - > mixer - > chip ,
" BUG: scarlett2_mux_id_to_num(%06x, IN): %d >= %d " ,
mux_entry , src_idx , private - > num_mux_srcs ) ;
return ;
}
private - > mux [ dst_idx ] = src_idx ;
}
/* Send USB message to get mux inputs and then populate private->mux[] */
static int scarlett2_usb_get_mux ( struct usb_mixer_interface * mixer )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-07 22:13:51 +03:00
int count = private - > num_mux_dsts ;
int err , i ;
struct {
__le16 num ;
__le16 count ;
} __packed req ;
__le32 data [ SCARLETT2_MUX_MAX ] ;
2021-06-22 20:03:50 +03:00
private - > mux_updated = 0 ;
2021-06-07 22:13:51 +03:00
req . num = 0 ;
req . count = cpu_to_le16 ( count ) ;
err = scarlett2_usb ( mixer , SCARLETT2_USB_GET_MUX ,
& req , sizeof ( req ) ,
data , count * sizeof ( u32 ) ) ;
if ( err < 0 )
return err ;
for ( i = 0 ; i < count ; i + + )
scarlett2_usb_populate_mux ( private , le32_to_cpu ( data [ i ] ) ) ;
return 0 ;
}
2019-07-28 18:12:45 +03:00
/* Send USB messages to set mux inputs */
static int scarlett2_usb_set_mux ( struct usb_mixer_interface * mixer )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2019-07-28 18:12:45 +03:00
const struct scarlett2_device_info * info = private - > info ;
2021-06-21 21:09:43 +03:00
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2021-06-21 21:09:41 +03:00
int table ;
2019-07-28 18:12:45 +03:00
struct {
2020-02-01 11:05:29 +03:00
__le16 pad ;
__le16 num ;
__le32 data [ SCARLETT2_MUX_MAX ] ;
2019-07-28 18:12:45 +03:00
} __packed req ;
req . pad = 0 ;
2021-06-21 21:09:41 +03:00
/* set mux settings for each rate */
for ( table = 0 ; table < SCARLETT2_MUX_TABLES ; table + + ) {
const struct scarlett2_mux_entry * entry ;
/* i counts over the output array */
int i = 0 , err ;
req . num = cpu_to_le16 ( table ) ;
/* loop through each entry */
for ( entry = info - > mux_assignment [ table ] ;
entry - > count ;
entry + + ) {
int j ;
int port_type = entry - > port_type ;
int port_idx = entry - > start ;
2021-06-21 21:09:43 +03:00
int mux_idx = scarlett2_get_port_start_num ( port_count ,
2021-06-21 21:09:41 +03:00
SCARLETT2_PORT_OUT , port_type ) + port_idx ;
2021-06-21 21:09:43 +03:00
int dst_id = scarlett2_ports [ port_type ] . id + port_idx ;
2021-06-21 21:09:41 +03:00
/* Empty slots */
if ( ! dst_id ) {
for ( j = 0 ; j < entry - > count ; j + + )
req . data [ i + + ] = 0 ;
continue ;
}
/* Non-empty mux slots use the lower 12 bits
* for the destination and next 12 bits for
* the source
*/
for ( j = 0 ; j < entry - > count ; j + + ) {
int src_id = scarlett2_mux_src_num_to_id (
2021-06-21 21:09:43 +03:00
port_count , private - > mux [ mux_idx + + ] ) ;
2021-06-21 21:09:41 +03:00
req . data [ i + + ] = cpu_to_le32 ( dst_id |
src_id < < 12 ) ;
dst_id + + ;
}
2019-07-28 18:12:45 +03:00
}
err = scarlett2_usb ( mixer , SCARLETT2_USB_SET_MUX ,
& req , ( i + 1 ) * sizeof ( u32 ) ,
NULL , 0 ) ;
if ( err < 0 )
return err ;
}
return 0 ;
}
/* Send USB message to get meter levels */
static int scarlett2_usb_get_meter_levels ( struct usb_mixer_interface * mixer ,
2021-06-21 21:09:46 +03:00
u16 num_meters , u16 * levels )
2019-07-28 18:12:45 +03:00
{
struct {
2020-02-01 11:05:29 +03:00
__le16 pad ;
__le16 num_meters ;
__le32 magic ;
2019-07-28 18:12:45 +03:00
} __packed req ;
2021-06-21 21:09:46 +03:00
u32 resp [ SCARLETT2_MAX_METERS ] ;
2019-07-28 18:12:45 +03:00
int i , err ;
req . pad = 0 ;
2021-06-21 21:09:46 +03:00
req . num_meters = cpu_to_le16 ( num_meters ) ;
2019-07-28 18:12:45 +03:00
req . magic = cpu_to_le32 ( SCARLETT2_USB_METER_LEVELS_GET_MAGIC ) ;
2021-06-20 19:46:28 +03:00
err = scarlett2_usb ( mixer , SCARLETT2_USB_GET_METER ,
2021-06-21 21:09:46 +03:00
& req , sizeof ( req ) , resp , num_meters * sizeof ( u32 ) ) ;
2019-07-28 18:12:45 +03:00
if ( err < 0 )
return err ;
/* copy, convert to u16 */
2021-06-21 21:09:46 +03:00
for ( i = 0 ; i < num_meters ; i + + )
2019-07-28 18:12:45 +03:00
levels [ i ] = resp [ i ] ;
return 0 ;
}
/*** Control Functions ***/
/* helper function to create a new control */
static int scarlett2_add_new_ctl ( struct usb_mixer_interface * mixer ,
const struct snd_kcontrol_new * ncontrol ,
int index , int channels , const char * name ,
struct snd_kcontrol * * kctl_return )
{
struct snd_kcontrol * kctl ;
struct usb_mixer_elem_info * elem ;
int err ;
elem = kzalloc ( sizeof ( * elem ) , GFP_KERNEL ) ;
if ( ! elem )
return - ENOMEM ;
2021-06-22 20:00:49 +03:00
/* We set USB_MIXER_BESPOKEN type, so that the core USB mixer code
* ignores them for resume and other operations .
* Also , the head . id field is set to 0 , as we don ' t use this field .
*/
2019-07-28 18:12:45 +03:00
elem - > head . mixer = mixer ;
elem - > control = index ;
2021-06-22 20:00:49 +03:00
elem - > head . id = 0 ;
2019-07-28 18:12:45 +03:00
elem - > channels = channels ;
2021-06-22 20:00:49 +03:00
elem - > val_type = USB_MIXER_BESPOKEN ;
2019-07-28 18:12:45 +03:00
kctl = snd_ctl_new1 ( ncontrol , elem ) ;
if ( ! kctl ) {
kfree ( elem ) ;
return - ENOMEM ;
}
kctl - > private_free = snd_usb_mixer_elem_free ;
ALSA: Convert strlcpy to strscpy when return value is unused
strlcpy is deprecated. see: Documentation/process/deprecated.rst
Change the calls that do not use the strlcpy return value to the
preferred strscpy.
Done with cocci script:
@@
expression e1, e2, e3;
@@
- strlcpy(
+ strscpy(
e1, e2, e3);
This cocci script leaves the instances where the return value is
used unchanged.
After this patch, sound/ has 3 uses of strlcpy() that need to be
manually inspected for conversion and changed one day.
$ git grep -w strlcpy sound/
sound/usb/card.c: len = strlcpy(card->longname, s, sizeof(card->longname));
sound/usb/mixer.c: return strlcpy(buf, p->name, buflen);
sound/usb/mixer.c: return strlcpy(buf, p->names[index], buflen);
Miscellenea:
o Remove trailing whitespace in conversion of sound/core/hwdep.c
Link: https://lore.kernel.org/lkml/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw@mail.gmail.com/
Signed-off-by: Joe Perches <joe@perches.com>
Acked-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/22b393d1790bb268769d0bab7bacf0866dcb0c14.camel@perches.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-01-04 20:17:34 +03:00
strscpy ( kctl - > id . name , name , sizeof ( kctl - > id . name ) ) ;
2019-07-28 18:12:45 +03:00
err = snd_usb_mixer_add_control ( & elem - > head , kctl ) ;
if ( err < 0 )
return err ;
if ( kctl_return )
* kctl_return = kctl ;
return 0 ;
}
2021-06-21 21:09:24 +03:00
/*** Sync Control ***/
/* Update sync control after receiving notification that the status
* has changed
*/
static int scarlett2_update_sync ( struct usb_mixer_interface * mixer )
{
struct scarlett2_data * private = mixer - > private_data ;
private - > sync_updated = 0 ;
return scarlett2_usb_get_sync_status ( mixer , & private - > sync ) ;
}
static int scarlett2_sync_ctl_info ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_info * uinfo )
{
static const char * texts [ 2 ] = {
" Unlocked " , " Locked "
} ;
return snd_ctl_enum_info ( uinfo , 1 , 2 , texts ) ;
}
static int scarlett2_sync_ctl_get ( 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 ;
mutex_lock ( & private - > data_mutex ) ;
if ( private - > sync_updated )
scarlett2_update_sync ( mixer ) ;
ucontrol - > value . enumerated . item [ 0 ] = private - > sync ;
mutex_unlock ( & private - > data_mutex ) ;
return 0 ;
}
static const struct snd_kcontrol_new scarlett2_sync_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. access = SNDRV_CTL_ELEM_ACCESS_READ ,
. name = " " ,
. info = scarlett2_sync_ctl_info ,
. get = scarlett2_sync_ctl_get
} ;
static int scarlett2_add_sync_ctl ( struct usb_mixer_interface * mixer )
{
struct scarlett2_data * private = mixer - > private_data ;
2021-06-22 20:02:31 +03:00
/* devices without a mixer also don't support reporting sync status */
2022-03-06 18:21:04 +03:00
if ( private - > info - > config_set = = SCARLETT2_CONFIG_SET_NO_MIXER )
2021-06-22 20:02:31 +03:00
return 0 ;
2021-06-21 21:09:24 +03:00
return scarlett2_add_new_ctl ( mixer , & scarlett2_sync_ctl ,
0 , 1 , " Sync Status " , & private - > sync_ctl ) ;
}
2019-07-28 18:12:45 +03:00
/*** Analogue Line Out Volume Controls ***/
/* Update hardware volume controls after receiving notification that
* they have changed
*/
static int scarlett2_update_volumes ( struct usb_mixer_interface * mixer )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-20 19:46:34 +03:00
const struct scarlett2_device_info * info = private - > info ;
2021-06-21 21:09:43 +03:00
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2019-07-28 18:12:45 +03:00
struct scarlett2_usb_volume_status volume_status ;
int num_line_out =
2021-06-21 21:09:43 +03:00
port_count [ SCARLETT2_PORT_TYPE_ANALOGUE ] [ SCARLETT2_PORT_OUT ] ;
2019-07-28 18:12:45 +03:00
int err , i ;
2021-06-21 21:09:39 +03:00
int mute ;
2019-07-28 18:12:45 +03:00
private - > vol_updated = 0 ;
err = scarlett2_usb_get_volume_status ( mixer , & volume_status ) ;
if ( err < 0 )
return err ;
private - > master_vol = clamp (
volume_status . master_vol + SCARLETT2_VOLUME_BIAS ,
0 , SCARLETT2_VOLUME_BIAS ) ;
2021-06-20 19:46:34 +03:00
if ( info - > line_out_hw_vol )
2021-06-20 19:46:36 +03:00
for ( i = 0 ; i < SCARLETT2_DIM_MUTE_COUNT ; i + + )
private - > dim_mute [ i ] = ! ! volume_status . dim_mute [ i ] ;
2019-07-28 18:12:45 +03:00
2021-06-21 21:09:39 +03:00
mute = private - > dim_mute [ SCARLETT2_BUTTON_MUTE ] ;
for ( i = 0 ; i < num_line_out ; i + + )
if ( private - > vol_sw_hw_switch [ i ] ) {
private - > vol [ i ] = private - > master_vol ;
private - > mute_switch [ i ] = mute ;
}
2019-07-28 18:12:45 +03:00
return 0 ;
}
static int scarlett2_volume_ctl_info ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_info * uinfo )
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = elem - > channels ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = SCARLETT2_VOLUME_BIAS ;
uinfo - > value . integer . step = 1 ;
return 0 ;
}
static int scarlett2_master_volume_ctl_get ( 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 ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2019-07-28 18:12:45 +03:00
2021-06-20 19:46:43 +03:00
mutex_lock ( & private - > data_mutex ) ;
if ( private - > vol_updated )
2019-07-28 18:12:45 +03:00
scarlett2_update_volumes ( mixer ) ;
2021-06-20 19:46:43 +03:00
mutex_unlock ( & private - > data_mutex ) ;
2019-07-28 18:12:45 +03:00
ucontrol - > value . integer . value [ 0 ] = private - > master_vol ;
return 0 ;
}
2021-06-22 20:03:16 +03:00
static int line_out_remap ( struct scarlett2_data * private , int index )
{
const struct scarlett2_device_info * info = private - > info ;
if ( ! info - > line_out_remap_enable )
return index ;
return info - > line_out_remap [ index ] ;
}
2019-07-28 18:12:45 +03:00
static int scarlett2_volume_ctl_get ( 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 ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-22 20:03:16 +03:00
int index = line_out_remap ( private , elem - > control ) ;
2019-07-28 18:12:45 +03:00
2021-06-20 19:46:43 +03:00
mutex_lock ( & private - > data_mutex ) ;
if ( private - > vol_updated )
2019-07-28 18:12:45 +03:00
scarlett2_update_volumes ( mixer ) ;
2021-06-20 19:46:43 +03:00
mutex_unlock ( & private - > data_mutex ) ;
2019-07-28 18:12:45 +03:00
ucontrol - > value . integer . value [ 0 ] = private - > vol [ index ] ;
return 0 ;
}
static int scarlett2_volume_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 ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-22 20:03:16 +03:00
int index = line_out_remap ( private , elem - > control ) ;
2019-07-28 18:12:45 +03:00
int oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > vol [ index ] ;
val = ucontrol - > value . integer . value [ 0 ] ;
if ( oval = = val )
goto unlock ;
private - > vol [ index ] = val ;
err = scarlett2_usb_set_config ( mixer , SCARLETT2_CONFIG_LINE_OUT_VOLUME ,
index , val - SCARLETT2_VOLUME_BIAS ) ;
if ( err = = 0 )
err = 1 ;
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const DECLARE_TLV_DB_MINMAX (
db_scale_scarlett2_gain , - SCARLETT2_VOLUME_BIAS * 100 , 0
) ;
static const struct snd_kcontrol_new scarlett2_master_volume_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. access = SNDRV_CTL_ELEM_ACCESS_READ |
SNDRV_CTL_ELEM_ACCESS_TLV_READ ,
. name = " " ,
. info = scarlett2_volume_ctl_info ,
. get = scarlett2_master_volume_ctl_get ,
. private_value = 0 , /* max value */
. tlv = { . p = db_scale_scarlett2_gain }
} ;
static const struct snd_kcontrol_new scarlett2_line_out_volume_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ ,
. name = " " ,
. info = scarlett2_volume_ctl_info ,
. get = scarlett2_volume_ctl_get ,
. put = scarlett2_volume_ctl_put ,
. private_value = 0 , /* max value */
. tlv = { . p = db_scale_scarlett2_gain }
} ;
2021-06-21 21:09:39 +03:00
/*** Mute Switch Controls ***/
static int scarlett2_mute_ctl_get ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_value * ucontrol )
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
2021-07-22 23:12:48 +03:00
struct usb_mixer_interface * mixer = elem - > head . mixer ;
struct scarlett2_data * private = mixer - > private_data ;
2021-06-22 20:03:16 +03:00
int index = line_out_remap ( private , elem - > control ) ;
2021-06-21 21:09:39 +03:00
2021-07-22 23:12:48 +03:00
mutex_lock ( & private - > data_mutex ) ;
if ( private - > vol_updated )
scarlett2_update_volumes ( mixer ) ;
mutex_unlock ( & private - > data_mutex ) ;
2021-06-21 21:09:39 +03:00
ucontrol - > value . integer . value [ 0 ] = private - > mute_switch [ index ] ;
return 0 ;
}
static int scarlett2_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 ;
2021-06-22 20:03:16 +03:00
int index = line_out_remap ( private , elem - > control ) ;
2021-06-21 21:09:39 +03:00
int oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > mute_switch [ index ] ;
val = ! ! ucontrol - > value . integer . value [ 0 ] ;
if ( oval = = val )
goto unlock ;
private - > mute_switch [ index ] = val ;
/* Send mute change to the device */
err = scarlett2_usb_set_config ( mixer , SCARLETT2_CONFIG_MUTE_SWITCH ,
index , val ) ;
2021-06-27 16:22:56 +03:00
if ( err = = 0 )
err = 1 ;
2021-06-21 21:09:39 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_mute_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = snd_ctl_boolean_mono_info ,
. get = scarlett2_mute_ctl_get ,
. put = scarlett2_mute_ctl_put ,
} ;
2019-07-28 18:12:45 +03:00
/*** HW/SW Volume Switch Controls ***/
2021-06-22 20:03:58 +03:00
static void scarlett2_sw_hw_ctl_ro ( struct scarlett2_data * private , int index )
{
private - > sw_hw_ctls [ index ] - > vd [ 0 ] . access & =
~ SNDRV_CTL_ELEM_ACCESS_WRITE ;
}
static void scarlett2_sw_hw_ctl_rw ( struct scarlett2_data * private , int index )
{
private - > sw_hw_ctls [ index ] - > vd [ 0 ] . access | =
SNDRV_CTL_ELEM_ACCESS_WRITE ;
}
2019-07-28 18:12:45 +03:00
static int scarlett2_sw_hw_enum_ctl_info ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_info * uinfo )
{
static const char * const values [ 2 ] = {
" SW " , " HW "
} ;
return snd_ctl_enum_info ( uinfo , 1 , 2 , values ) ;
}
static int scarlett2_sw_hw_enum_ctl_get ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_value * ucontrol )
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = elem - > head . mixer - > private_data ;
2021-06-22 20:03:16 +03:00
int index = line_out_remap ( private , elem - > control ) ;
2019-07-28 18:12:45 +03:00
2021-06-22 20:03:16 +03:00
ucontrol - > value . enumerated . item [ 0 ] = private - > vol_sw_hw_switch [ index ] ;
2019-07-28 18:12:45 +03:00
return 0 ;
}
2021-06-21 21:09:37 +03:00
static void scarlett2_vol_ctl_set_writable ( struct usb_mixer_interface * mixer ,
int index , int value )
{
struct scarlett2_data * private = mixer - > private_data ;
2021-06-21 21:09:39 +03:00
struct snd_card * card = mixer - > chip - > card ;
2021-06-21 21:09:37 +03:00
2021-06-21 21:09:39 +03:00
/* Set/Clear write bits */
if ( value ) {
2021-06-21 21:09:37 +03:00
private - > vol_ctls [ index ] - > vd [ 0 ] . access | =
SNDRV_CTL_ELEM_ACCESS_WRITE ;
2021-06-21 21:09:39 +03:00
private - > mute_ctls [ index ] - > vd [ 0 ] . access | =
SNDRV_CTL_ELEM_ACCESS_WRITE ;
} else {
2021-06-21 21:09:37 +03:00
private - > vol_ctls [ index ] - > vd [ 0 ] . access & =
~ SNDRV_CTL_ELEM_ACCESS_WRITE ;
2021-06-21 21:09:39 +03:00
private - > mute_ctls [ index ] - > vd [ 0 ] . access & =
~ SNDRV_CTL_ELEM_ACCESS_WRITE ;
}
2021-06-21 21:09:37 +03:00
2021-07-22 23:13:26 +03:00
/* Notify of write bit and possible value change */
snd_ctl_notify ( card ,
SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO ,
2021-06-21 21:09:37 +03:00
& private - > vol_ctls [ index ] - > id ) ;
2021-07-22 23:13:26 +03:00
snd_ctl_notify ( card ,
SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO ,
2021-06-21 21:09:39 +03:00
& private - > mute_ctls [ index ] - > id ) ;
2021-06-21 21:09:37 +03:00
}
2021-06-22 20:03:36 +03:00
static int scarlett2_sw_hw_change ( struct usb_mixer_interface * mixer ,
int ctl_index , int val )
2019-07-28 18:12:45 +03:00
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-22 20:03:16 +03:00
int index = line_out_remap ( private , ctl_index ) ;
2021-06-22 20:03:36 +03:00
int err ;
2019-07-28 18:12:45 +03:00
private - > vol_sw_hw_switch [ index ] = val ;
/* Change access mode to RO (hardware controlled volume)
* or RW ( software controlled volume )
*/
2021-06-22 20:03:16 +03:00
scarlett2_vol_ctl_set_writable ( mixer , ctl_index , ! val ) ;
2019-07-28 18:12:45 +03:00
2021-06-21 21:09:39 +03:00
/* Reset volume/mute to master volume/mute */
2019-07-28 18:12:45 +03:00
private - > vol [ index ] = private - > master_vol ;
2021-06-21 21:09:39 +03:00
private - > mute_switch [ index ] = private - > dim_mute [ SCARLETT2_BUTTON_MUTE ] ;
2019-07-28 18:12:45 +03:00
/* Set SW volume to current HW volume */
err = scarlett2_usb_set_config (
mixer , SCARLETT2_CONFIG_LINE_OUT_VOLUME ,
index , private - > master_vol - SCARLETT2_VOLUME_BIAS ) ;
if ( err < 0 )
2021-06-22 20:03:36 +03:00
return err ;
2019-07-28 18:12:45 +03:00
2021-06-21 21:09:39 +03:00
/* Set SW mute to current HW mute */
err = scarlett2_usb_set_config (
mixer , SCARLETT2_CONFIG_MUTE_SWITCH ,
index , private - > dim_mute [ SCARLETT2_BUTTON_MUTE ] ) ;
if ( err < 0 )
2021-06-22 20:03:36 +03:00
return err ;
2021-06-21 21:09:39 +03:00
2019-07-28 18:12:45 +03:00
/* Send SW/HW switch change to the device */
2021-06-22 20:03:36 +03:00
return scarlett2_usb_set_config ( mixer , SCARLETT2_CONFIG_SW_HW_SWITCH ,
index , val ) ;
}
static int scarlett2_sw_hw_enum_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 ctl_index = elem - > control ;
int index = line_out_remap ( private , ctl_index ) ;
int oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > vol_sw_hw_switch [ index ] ;
val = ! ! ucontrol - > value . enumerated . item [ 0 ] ;
if ( oval = = val )
goto unlock ;
err = scarlett2_sw_hw_change ( mixer , ctl_index , val ) ;
2021-06-20 19:46:45 +03:00
if ( err = = 0 )
err = 1 ;
2019-07-28 18:12:45 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_sw_hw_enum_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = scarlett2_sw_hw_enum_ctl_info ,
. get = scarlett2_sw_hw_enum_ctl_get ,
. put = scarlett2_sw_hw_enum_ctl_put ,
} ;
/*** Line Level/Instrument Level Switch Controls ***/
2021-06-22 20:01:44 +03:00
static int scarlett2_update_input_other ( struct usb_mixer_interface * mixer )
{
struct scarlett2_data * private = mixer - > private_data ;
const struct scarlett2_device_info * info = private - > info ;
private - > input_other_updated = 0 ;
if ( info - > level_input_count ) {
int err = scarlett2_usb_get_config (
mixer , SCARLETT2_CONFIG_LEVEL_SWITCH ,
2021-06-22 20:02:31 +03:00
info - > level_input_count + info - > level_input_first ,
private - > level_switch ) ;
2021-06-22 20:01:44 +03:00
if ( err < 0 )
return err ;
}
if ( info - > pad_input_count ) {
int err = scarlett2_usb_get_config (
mixer , SCARLETT2_CONFIG_PAD_SWITCH ,
info - > pad_input_count , private - > pad_switch ) ;
if ( err < 0 )
return err ;
}
2021-06-22 20:02:36 +03:00
if ( info - > air_input_count ) {
int err = scarlett2_usb_get_config (
mixer , SCARLETT2_CONFIG_AIR_SWITCH ,
info - > air_input_count , private - > air_switch ) ;
if ( err < 0 )
return err ;
}
2021-06-22 20:02:40 +03:00
if ( info - > phantom_count ) {
int err = scarlett2_usb_get_config (
mixer , SCARLETT2_CONFIG_PHANTOM_SWITCH ,
info - > phantom_count , private - > phantom_switch ) ;
if ( err < 0 )
return err ;
err = scarlett2_usb_get_config (
mixer , SCARLETT2_CONFIG_PHANTOM_PERSISTENCE ,
1 , & private - > phantom_persistence ) ;
if ( err < 0 )
return err ;
}
2021-06-22 20:01:44 +03:00
return 0 ;
}
2019-07-28 18:12:45 +03:00
static int scarlett2_level_enum_ctl_info ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_info * uinfo )
{
static const char * const values [ 2 ] = {
" Line " , " Inst "
} ;
return snd_ctl_enum_info ( uinfo , 1 , 2 , values ) ;
}
static int scarlett2_level_enum_ctl_get ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_value * ucontrol )
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
2021-06-22 20:01:44 +03:00
struct usb_mixer_interface * mixer = elem - > head . mixer ;
struct scarlett2_data * private = mixer - > private_data ;
2021-06-22 20:02:31 +03:00
const struct scarlett2_device_info * info = private - > info ;
int index = elem - > control + info - > level_input_first ;
2019-07-28 18:12:45 +03:00
2021-06-22 20:01:44 +03:00
mutex_lock ( & private - > data_mutex ) ;
if ( private - > input_other_updated )
scarlett2_update_input_other ( mixer ) ;
2021-06-22 20:02:31 +03:00
ucontrol - > value . enumerated . item [ 0 ] = private - > level_switch [ index ] ;
2021-06-22 20:01:44 +03:00
mutex_unlock ( & private - > data_mutex ) ;
2019-07-28 18:12:45 +03:00
return 0 ;
}
static int scarlett2_level_enum_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 ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-22 20:02:31 +03:00
const struct scarlett2_device_info * info = private - > info ;
2019-07-28 18:12:45 +03:00
2021-06-22 20:02:31 +03:00
int index = elem - > control + info - > level_input_first ;
2019-07-28 18:12:45 +03:00
int oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > level_switch [ index ] ;
2021-06-20 19:46:47 +03:00
val = ! ! ucontrol - > value . enumerated . item [ 0 ] ;
2019-07-28 18:12:45 +03:00
if ( oval = = val )
goto unlock ;
private - > level_switch [ index ] = val ;
/* Send switch change to the device */
err = scarlett2_usb_set_config ( mixer , SCARLETT2_CONFIG_LEVEL_SWITCH ,
index , val ) ;
2021-06-20 19:46:45 +03:00
if ( err = = 0 )
err = 1 ;
2019-07-28 18:12:45 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_level_enum_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = scarlett2_level_enum_ctl_info ,
. get = scarlett2_level_enum_ctl_get ,
. put = scarlett2_level_enum_ctl_put ,
} ;
/*** Pad Switch Controls ***/
static int scarlett2_pad_ctl_get ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_value * ucontrol )
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
2021-06-22 20:01:44 +03:00
struct usb_mixer_interface * mixer = elem - > head . mixer ;
struct scarlett2_data * private = mixer - > private_data ;
2019-07-28 18:12:45 +03:00
2021-06-22 20:01:44 +03:00
mutex_lock ( & private - > data_mutex ) ;
if ( private - > input_other_updated )
scarlett2_update_input_other ( mixer ) ;
2021-06-20 19:46:47 +03:00
ucontrol - > value . integer . value [ 0 ] =
2019-07-28 18:12:45 +03:00
private - > pad_switch [ elem - > control ] ;
2021-06-22 20:01:44 +03:00
mutex_unlock ( & private - > data_mutex ) ;
2019-07-28 18:12:45 +03:00
return 0 ;
}
static int scarlett2_pad_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 ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2019-07-28 18:12:45 +03:00
int index = elem - > control ;
int oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > pad_switch [ index ] ;
val = ! ! ucontrol - > value . integer . value [ 0 ] ;
if ( oval = = val )
goto unlock ;
private - > pad_switch [ index ] = val ;
/* Send switch change to the device */
err = scarlett2_usb_set_config ( mixer , SCARLETT2_CONFIG_PAD_SWITCH ,
index , val ) ;
2021-06-20 19:46:45 +03:00
if ( err = = 0 )
err = 1 ;
2019-07-28 18:12:45 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_pad_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = snd_ctl_boolean_mono_info ,
. get = scarlett2_pad_ctl_get ,
. put = scarlett2_pad_ctl_put ,
} ;
2021-06-22 20:02:36 +03:00
/*** Air Switch Controls ***/
static int scarlett2_air_ctl_get ( 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 ;
mutex_lock ( & private - > data_mutex ) ;
if ( private - > input_other_updated )
scarlett2_update_input_other ( mixer ) ;
ucontrol - > value . integer . value [ 0 ] = private - > air_switch [ elem - > control ] ;
mutex_unlock ( & private - > data_mutex ) ;
return 0 ;
}
static int scarlett2_air_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 oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > air_switch [ index ] ;
val = ! ! ucontrol - > value . integer . value [ 0 ] ;
if ( oval = = val )
goto unlock ;
private - > air_switch [ index ] = val ;
/* Send switch change to the device */
err = scarlett2_usb_set_config ( mixer , SCARLETT2_CONFIG_AIR_SWITCH ,
index , val ) ;
2021-06-27 16:22:56 +03:00
if ( err = = 0 )
err = 1 ;
2021-06-22 20:02:36 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_air_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = snd_ctl_boolean_mono_info ,
. get = scarlett2_air_ctl_get ,
. put = scarlett2_air_ctl_put ,
} ;
2021-06-22 20:02:40 +03:00
/*** Phantom Switch Controls ***/
static int scarlett2_phantom_ctl_get ( 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 ;
mutex_lock ( & private - > data_mutex ) ;
if ( private - > input_other_updated )
scarlett2_update_input_other ( mixer ) ;
ucontrol - > value . integer . value [ 0 ] =
private - > phantom_switch [ elem - > control ] ;
mutex_unlock ( & private - > data_mutex ) ;
return 0 ;
}
static int scarlett2_phantom_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 oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > phantom_switch [ index ] ;
val = ! ! ucontrol - > value . integer . value [ 0 ] ;
if ( oval = = val )
goto unlock ;
private - > phantom_switch [ index ] = val ;
/* Send switch change to the device */
err = scarlett2_usb_set_config ( mixer , SCARLETT2_CONFIG_PHANTOM_SWITCH ,
index , val ) ;
2021-06-27 16:22:56 +03:00
if ( err = = 0 )
err = 1 ;
2021-06-22 20:02:40 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_phantom_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = snd_ctl_boolean_mono_info ,
. get = scarlett2_phantom_ctl_get ,
. put = scarlett2_phantom_ctl_put ,
} ;
/*** Phantom Persistence Control ***/
static int scarlett2_phantom_persistence_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 - > phantom_persistence ;
return 0 ;
}
static int scarlett2_phantom_persistence_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 oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > phantom_persistence ;
val = ! ! ucontrol - > value . integer . value [ 0 ] ;
if ( oval = = val )
goto unlock ;
private - > phantom_persistence = val ;
/* Send switch change to the device */
err = scarlett2_usb_set_config (
mixer , SCARLETT2_CONFIG_PHANTOM_PERSISTENCE , index , val ) ;
2021-06-27 16:22:56 +03:00
if ( err = = 0 )
err = 1 ;
2021-06-22 20:02:40 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_phantom_persistence_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = snd_ctl_boolean_mono_info ,
. get = scarlett2_phantom_persistence_ctl_get ,
. put = scarlett2_phantom_persistence_ctl_put ,
} ;
2021-06-22 20:03:08 +03:00
/*** Direct Monitor Control ***/
static int scarlett2_update_monitor_other ( struct usb_mixer_interface * mixer )
{
struct scarlett2_data * private = mixer - > private_data ;
const struct scarlett2_device_info * info = private - > info ;
2021-06-22 20:03:58 +03:00
int err ;
2021-06-22 20:04:13 +03:00
/* monitor_other_enable[0] enables speaker switching
* monitor_other_enable [ 1 ] enables talkback
*/
2021-06-22 20:03:58 +03:00
u8 monitor_other_enable [ 2 ] ;
2021-06-22 20:04:13 +03:00
/* monitor_other_switch[0] activates the alternate speakers
* monitor_other_switch [ 1 ] activates talkback
*/
2021-06-22 20:03:58 +03:00
u8 monitor_other_switch [ 2 ] ;
2021-06-22 20:03:08 +03:00
private - > monitor_other_updated = 0 ;
if ( info - > direct_monitor )
return scarlett2_usb_get_config (
mixer , SCARLETT2_CONFIG_DIRECT_MONITOR ,
1 , & private - > direct_monitor_switch ) ;
2021-06-22 20:04:13 +03:00
/* if it doesn't do speaker switching then it also doesn't do
* talkback
*/
2021-06-22 20:03:58 +03:00
if ( ! info - > has_speaker_switching )
return 0 ;
err = scarlett2_usb_get_config (
mixer , SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE ,
2 , monitor_other_enable ) ;
if ( err < 0 )
return err ;
err = scarlett2_usb_get_config (
mixer , SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH ,
2 , monitor_other_switch ) ;
if ( err < 0 )
return err ;
if ( ! monitor_other_enable [ 0 ] )
private - > speaker_switching_switch = 0 ;
else
private - > speaker_switching_switch = monitor_other_switch [ 0 ] + 1 ;
2021-06-22 20:04:13 +03:00
if ( info - > has_talkback ) {
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] =
info - > port_count ;
int num_mixes =
port_count [ SCARLETT2_PORT_TYPE_MIX ] [ SCARLETT2_PORT_IN ] ;
u16 bitmap ;
int i ;
if ( ! monitor_other_enable [ 1 ] )
private - > talkback_switch = 0 ;
else
private - > talkback_switch = monitor_other_switch [ 1 ] + 1 ;
err = scarlett2_usb_get_config ( mixer ,
SCARLETT2_CONFIG_TALKBACK_MAP ,
1 , & bitmap ) ;
2021-09-29 10:35:40 +03:00
if ( err < 0 )
return err ;
2021-06-22 20:04:13 +03:00
for ( i = 0 ; i < num_mixes ; i + + , bitmap > > = 1 )
private - > talkback_map [ i ] = bitmap & 1 ;
}
2021-06-22 20:03:08 +03:00
return 0 ;
}
static int scarlett2_direct_monitor_ctl_get (
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 = elem - > head . mixer - > private_data ;
mutex_lock ( & private - > data_mutex ) ;
if ( private - > monitor_other_updated )
scarlett2_update_monitor_other ( mixer ) ;
ucontrol - > value . enumerated . item [ 0 ] = private - > direct_monitor_switch ;
mutex_unlock ( & private - > data_mutex ) ;
return 0 ;
}
static int scarlett2_direct_monitor_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 oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > direct_monitor_switch ;
val = min ( ucontrol - > value . enumerated . item [ 0 ] , 2U ) ;
if ( oval = = val )
goto unlock ;
private - > direct_monitor_switch = val ;
/* Send switch change to the device */
err = scarlett2_usb_set_config (
mixer , SCARLETT2_CONFIG_DIRECT_MONITOR , index , val ) ;
2021-06-27 16:22:56 +03:00
if ( err = = 0 )
err = 1 ;
2021-06-22 20:03:08 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static int scarlett2_direct_monitor_stereo_enum_ctl_info (
struct snd_kcontrol * kctl , struct snd_ctl_elem_info * uinfo )
{
static const char * const values [ 3 ] = {
" Off " , " Mono " , " Stereo "
} ;
return snd_ctl_enum_info ( uinfo , 1 , 3 , values ) ;
}
/* Direct Monitor for Solo is mono-only and only needs a boolean control
* Direct Monitor for 2 i2 is selectable between Off / Mono / Stereo
*/
static const struct snd_kcontrol_new scarlett2_direct_monitor_ctl [ 2 ] = {
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = snd_ctl_boolean_mono_info ,
. get = scarlett2_direct_monitor_ctl_get ,
. put = scarlett2_direct_monitor_ctl_put ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = scarlett2_direct_monitor_stereo_enum_ctl_info ,
. get = scarlett2_direct_monitor_ctl_get ,
. put = scarlett2_direct_monitor_ctl_put ,
}
} ;
static int scarlett2_add_direct_monitor_ctl ( struct usb_mixer_interface * mixer )
{
struct scarlett2_data * private = mixer - > private_data ;
const struct scarlett2_device_info * info = private - > info ;
2021-07-22 23:12:08 +03:00
const char * s ;
2021-06-22 20:03:08 +03:00
if ( ! info - > direct_monitor )
return 0 ;
2021-07-22 23:12:08 +03:00
s = info - > direct_monitor = = 1
? " Direct Monitor Playback Switch "
: " Direct Monitor Playback Enum " ;
2021-06-22 20:03:08 +03:00
return scarlett2_add_new_ctl (
mixer , & scarlett2_direct_monitor_ctl [ info - > direct_monitor - 1 ] ,
2021-07-22 23:12:08 +03:00
0 , 1 , s , & private - > direct_monitor_ctl ) ;
2021-06-22 20:03:08 +03:00
}
2021-06-22 20:03:58 +03:00
/*** Speaker Switching Control ***/
static int scarlett2_speaker_switch_enum_ctl_info (
struct snd_kcontrol * kctl , struct snd_ctl_elem_info * uinfo )
{
static const char * const values [ 3 ] = {
" Off " , " Main " , " Alt "
} ;
return snd_ctl_enum_info ( uinfo , 1 , 3 , values ) ;
}
static int scarlett2_speaker_switch_enum_ctl_get (
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 ;
mutex_lock ( & private - > data_mutex ) ;
if ( private - > monitor_other_updated )
scarlett2_update_monitor_other ( mixer ) ;
ucontrol - > value . enumerated . item [ 0 ] = private - > speaker_switching_switch ;
mutex_unlock ( & private - > data_mutex ) ;
return 0 ;
}
/* when speaker switching gets enabled, switch the main/alt speakers
* to HW volume and disable those controls
*/
2021-06-27 16:22:56 +03:00
static int scarlett2_speaker_switch_enable ( struct usb_mixer_interface * mixer )
2021-06-22 20:03:58 +03:00
{
struct snd_card * card = mixer - > chip - > card ;
struct scarlett2_data * private = mixer - > private_data ;
2021-06-27 16:22:56 +03:00
int i , err ;
2021-06-22 20:03:58 +03:00
for ( i = 0 ; i < 4 ; i + + ) {
int index = line_out_remap ( private , i ) ;
/* switch the main/alt speakers to HW volume */
2021-06-27 16:22:56 +03:00
if ( ! private - > vol_sw_hw_switch [ index ] ) {
err = scarlett2_sw_hw_change ( private - > mixer , i , 1 ) ;
if ( err < 0 )
return err ;
}
2021-06-22 20:03:58 +03:00
/* disable the line out SW/HW switch */
scarlett2_sw_hw_ctl_ro ( private , i ) ;
2021-07-22 23:13:26 +03:00
snd_ctl_notify ( card ,
SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO ,
2021-06-22 20:03:58 +03:00
& private - > sw_hw_ctls [ i ] - > id ) ;
}
/* when the next monitor-other notify comes in, update the mux
* configuration
*/
private - > speaker_switching_switched = 1 ;
2021-06-27 16:22:56 +03:00
return 0 ;
2021-06-22 20:03:58 +03:00
}
/* when speaker switching gets disabled, reenable the hw/sw controls
* and invalidate the routing
*/
static void scarlett2_speaker_switch_disable ( struct usb_mixer_interface * mixer )
{
struct snd_card * card = mixer - > chip - > card ;
struct scarlett2_data * private = mixer - > private_data ;
int i ;
/* enable the line out SW/HW switch */
for ( i = 0 ; i < 4 ; i + + ) {
scarlett2_sw_hw_ctl_rw ( private , i ) ;
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_INFO ,
& private - > sw_hw_ctls [ i ] - > id ) ;
}
/* when the next monitor-other notify comes in, update the mux
* configuration
*/
private - > speaker_switching_switched = 1 ;
}
static int scarlett2_speaker_switch_enum_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 oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > speaker_switching_switch ;
val = min ( ucontrol - > value . enumerated . item [ 0 ] , 2U ) ;
if ( oval = = val )
goto unlock ;
private - > speaker_switching_switch = val ;
/* enable/disable speaker switching */
err = scarlett2_usb_set_config (
mixer , SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE ,
0 , ! ! val ) ;
if ( err < 0 )
goto unlock ;
/* if speaker switching is enabled, select main or alt */
err = scarlett2_usb_set_config (
mixer , SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH ,
0 , val = = 2 ) ;
if ( err < 0 )
goto unlock ;
/* update controls if speaker switching gets enabled or disabled */
if ( ! oval & & val )
2021-06-27 16:22:56 +03:00
err = scarlett2_speaker_switch_enable ( mixer ) ;
2021-06-22 20:03:58 +03:00
else if ( oval & & ! val )
scarlett2_speaker_switch_disable ( mixer ) ;
2021-06-27 16:22:56 +03:00
if ( err = = 0 )
err = 1 ;
2021-06-22 20:03:58 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_speaker_switch_enum_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = scarlett2_speaker_switch_enum_ctl_info ,
. get = scarlett2_speaker_switch_enum_ctl_get ,
. put = scarlett2_speaker_switch_enum_ctl_put ,
} ;
static int scarlett2_add_speaker_switch_ctl (
struct usb_mixer_interface * mixer )
{
struct scarlett2_data * private = mixer - > private_data ;
const struct scarlett2_device_info * info = private - > info ;
if ( ! info - > has_speaker_switching )
return 0 ;
return scarlett2_add_new_ctl (
mixer , & scarlett2_speaker_switch_enum_ctl ,
0 , 1 , " Speaker Switching Playback Enum " ,
& private - > speaker_switching_ctl ) ;
}
2021-06-22 20:04:13 +03:00
/*** Talkback and Talkback Map Controls ***/
static int scarlett2_talkback_enum_ctl_info (
struct snd_kcontrol * kctl , struct snd_ctl_elem_info * uinfo )
{
static const char * const values [ 3 ] = {
" Disabled " , " Off " , " On "
} ;
return snd_ctl_enum_info ( uinfo , 1 , 3 , values ) ;
}
static int scarlett2_talkback_enum_ctl_get (
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 ;
mutex_lock ( & private - > data_mutex ) ;
if ( private - > monitor_other_updated )
scarlett2_update_monitor_other ( mixer ) ;
ucontrol - > value . enumerated . item [ 0 ] = private - > talkback_switch ;
mutex_unlock ( & private - > data_mutex ) ;
return 0 ;
}
static int scarlett2_talkback_enum_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 oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > talkback_switch ;
val = min ( ucontrol - > value . enumerated . item [ 0 ] , 2U ) ;
if ( oval = = val )
goto unlock ;
private - > talkback_switch = val ;
/* enable/disable talkback */
err = scarlett2_usb_set_config (
mixer , SCARLETT2_CONFIG_MONITOR_OTHER_ENABLE ,
1 , ! ! val ) ;
if ( err < 0 )
goto unlock ;
/* if talkback is enabled, select main or alt */
err = scarlett2_usb_set_config (
mixer , SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH ,
1 , val = = 2 ) ;
2021-06-27 16:22:56 +03:00
if ( err = = 0 )
err = 1 ;
2021-06-22 20:04:13 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_talkback_enum_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = scarlett2_talkback_enum_ctl_info ,
. get = scarlett2_talkback_enum_ctl_get ,
. put = scarlett2_talkback_enum_ctl_put ,
} ;
static int scarlett2_talkback_map_ctl_get (
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 ;
ucontrol - > value . integer . value [ 0 ] = private - > talkback_map [ index ] ;
return 0 ;
}
static int scarlett2_talkback_map_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 ;
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] =
private - > info - > port_count ;
int num_mixes = port_count [ SCARLETT2_PORT_TYPE_MIX ] [ SCARLETT2_PORT_IN ] ;
int index = elem - > control ;
int oval , val , err = 0 , i ;
u16 bitmap = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > talkback_map [ index ] ;
val = ! ! ucontrol - > value . integer . value [ 0 ] ;
if ( oval = = val )
goto unlock ;
private - > talkback_map [ index ] = val ;
for ( i = 0 ; i < num_mixes ; i + + )
bitmap | = private - > talkback_map [ i ] < < i ;
/* Send updated bitmap to the device */
err = scarlett2_usb_set_config ( mixer , SCARLETT2_CONFIG_TALKBACK_MAP ,
0 , bitmap ) ;
2021-06-27 16:22:56 +03:00
if ( err = = 0 )
err = 1 ;
2021-06-22 20:04:13 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_talkback_map_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = snd_ctl_boolean_mono_info ,
. get = scarlett2_talkback_map_ctl_get ,
. put = scarlett2_talkback_map_ctl_put ,
} ;
static int scarlett2_add_talkback_ctls (
struct usb_mixer_interface * mixer )
{
struct scarlett2_data * private = mixer - > private_data ;
const struct scarlett2_device_info * info = private - > info ;
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
int num_mixes = port_count [ SCARLETT2_PORT_TYPE_MIX ] [ SCARLETT2_PORT_IN ] ;
int err , i ;
char s [ SNDRV_CTL_ELEM_ID_NAME_MAXLEN ] ;
if ( ! info - > has_talkback )
return 0 ;
err = scarlett2_add_new_ctl (
mixer , & scarlett2_talkback_enum_ctl ,
0 , 1 , " Talkback Playback Enum " ,
& private - > talkback_ctl ) ;
if ( err < 0 )
return err ;
for ( i = 0 ; i < num_mixes ; i + + ) {
snprintf ( s , sizeof ( s ) ,
" Talkback Mix %c Playback Switch " , i + ' A ' ) ;
err = scarlett2_add_new_ctl ( mixer , & scarlett2_talkback_map_ctl ,
i , 1 , s , NULL ) ;
if ( err < 0 )
return err ;
}
return 0 ;
}
2021-06-20 19:46:36 +03:00
/*** Dim/Mute Controls ***/
2019-07-28 18:12:45 +03:00
2021-06-20 19:46:36 +03:00
static int scarlett2_dim_mute_ctl_get ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_value * ucontrol )
2019-07-28 18:12:45 +03:00
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
struct usb_mixer_interface * mixer = elem - > head . mixer ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2019-07-28 18:12:45 +03:00
2021-06-20 19:46:43 +03:00
mutex_lock ( & private - > data_mutex ) ;
if ( private - > vol_updated )
2019-07-28 18:12:45 +03:00
scarlett2_update_volumes ( mixer ) ;
2021-06-20 19:46:43 +03:00
mutex_unlock ( & private - > data_mutex ) ;
2019-07-28 18:12:45 +03:00
2021-06-20 19:46:47 +03:00
ucontrol - > value . integer . value [ 0 ] = private - > dim_mute [ elem - > control ] ;
2019-07-28 18:12:45 +03:00
return 0 ;
}
2021-06-20 19:46:36 +03:00
static int scarlett2_dim_mute_ctl_put ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_value * ucontrol )
2019-07-28 18:12:45 +03:00
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
struct usb_mixer_interface * mixer = elem - > head . mixer ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-21 21:09:39 +03:00
const struct scarlett2_device_info * info = private - > info ;
2021-06-21 21:09:43 +03:00
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2021-06-21 21:09:39 +03:00
int num_line_out =
2021-06-21 21:09:43 +03:00
port_count [ SCARLETT2_PORT_TYPE_ANALOGUE ] [ SCARLETT2_PORT_OUT ] ;
2019-07-28 18:12:45 +03:00
int index = elem - > control ;
2021-06-21 21:09:39 +03:00
int oval , val , err = 0 , i ;
2019-07-28 18:12:45 +03:00
mutex_lock ( & private - > data_mutex ) ;
2021-06-20 19:46:36 +03:00
oval = private - > dim_mute [ index ] ;
2019-07-28 18:12:45 +03:00
val = ! ! ucontrol - > value . integer . value [ 0 ] ;
if ( oval = = val )
goto unlock ;
2021-06-20 19:46:36 +03:00
private - > dim_mute [ index ] = val ;
2019-07-28 18:12:45 +03:00
/* Send switch change to the device */
2021-06-20 19:46:36 +03:00
err = scarlett2_usb_set_config ( mixer , SCARLETT2_CONFIG_DIM_MUTE ,
2019-07-28 18:12:45 +03:00
index , val ) ;
2021-06-20 19:46:45 +03:00
if ( err = = 0 )
err = 1 ;
2019-07-28 18:12:45 +03:00
2021-06-21 21:09:39 +03:00
if ( index = = SCARLETT2_BUTTON_MUTE )
2021-06-22 20:03:16 +03:00
for ( i = 0 ; i < num_line_out ; i + + ) {
int line_index = line_out_remap ( private , i ) ;
if ( private - > vol_sw_hw_switch [ line_index ] ) {
private - > mute_switch [ line_index ] = val ;
2021-06-21 21:09:39 +03:00
snd_ctl_notify ( mixer - > chip - > card ,
2021-07-22 23:13:26 +03:00
SNDRV_CTL_EVENT_MASK_VALUE ,
2021-06-21 21:09:39 +03:00
& private - > mute_ctls [ i ] - > id ) ;
}
2021-06-22 20:03:16 +03:00
}
2021-06-21 21:09:39 +03:00
2019-07-28 18:12:45 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
2021-06-20 19:46:36 +03:00
static const struct snd_kcontrol_new scarlett2_dim_mute_ctl = {
2019-07-28 18:12:45 +03:00
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = snd_ctl_boolean_mono_info ,
2021-06-20 19:46:36 +03:00
. get = scarlett2_dim_mute_ctl_get ,
. put = scarlett2_dim_mute_ctl_put
2019-07-28 18:12:45 +03:00
} ;
/*** Create the analogue output controls ***/
static int scarlett2_add_line_out_ctls ( struct usb_mixer_interface * mixer )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2019-07-28 18:12:45 +03:00
const struct scarlett2_device_info * info = private - > info ;
2021-06-21 21:09:43 +03:00
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2019-07-28 18:12:45 +03:00
int num_line_out =
2021-06-21 21:09:43 +03:00
port_count [ SCARLETT2_PORT_TYPE_ANALOGUE ] [ SCARLETT2_PORT_OUT ] ;
2019-07-28 18:12:45 +03:00
int err , i ;
char s [ SNDRV_CTL_ELEM_ID_NAME_MAXLEN ] ;
/* Add R/O HW volume control */
if ( info - > line_out_hw_vol ) {
snprintf ( s , sizeof ( s ) , " Master HW Playback Volume " ) ;
err = scarlett2_add_new_ctl ( mixer ,
& scarlett2_master_volume_ctl ,
0 , 1 , s , & private - > master_vol_ctl ) ;
if ( err < 0 )
return err ;
}
/* Add volume controls */
for ( i = 0 ; i < num_line_out ; i + + ) {
2021-06-22 20:03:16 +03:00
int index = line_out_remap ( private , i ) ;
2019-07-28 18:12:45 +03:00
/* Fader */
if ( info - > line_out_descrs [ i ] )
snprintf ( s , sizeof ( s ) ,
" Line %02d (%s) Playback Volume " ,
i + 1 , info - > line_out_descrs [ i ] ) ;
else
snprintf ( s , sizeof ( s ) ,
" Line %02d Playback Volume " ,
i + 1 ) ;
err = scarlett2_add_new_ctl ( mixer ,
& scarlett2_line_out_volume_ctl ,
i , 1 , s , & private - > vol_ctls [ i ] ) ;
if ( err < 0 )
return err ;
2021-06-21 21:09:39 +03:00
/* Mute Switch */
snprintf ( s , sizeof ( s ) ,
" Line %02d Mute Playback Switch " ,
i + 1 ) ;
err = scarlett2_add_new_ctl ( mixer ,
& scarlett2_mute_ctl ,
i , 1 , s ,
& private - > mute_ctls [ i ] ) ;
if ( err < 0 )
return err ;
/* Make the fader and mute controls read-only if the
* SW / HW switch is set to HW
*/
2021-06-22 20:03:16 +03:00
if ( private - > vol_sw_hw_switch [ index ] )
2021-06-21 21:09:37 +03:00
scarlett2_vol_ctl_set_writable ( mixer , i , 0 ) ;
2019-07-28 18:12:45 +03:00
/* SW/HW Switch */
if ( info - > line_out_hw_vol ) {
snprintf ( s , sizeof ( s ) ,
" Line Out %02d Volume Control Playback Enum " ,
i + 1 ) ;
err = scarlett2_add_new_ctl ( mixer ,
& scarlett2_sw_hw_enum_ctl ,
2021-06-22 20:03:45 +03:00
i , 1 , s ,
& private - > sw_hw_ctls [ i ] ) ;
2019-07-28 18:12:45 +03:00
if ( err < 0 )
return err ;
2021-06-22 20:03:58 +03:00
/* Make the switch read-only if the line is
* involved in speaker switching
*/
if ( private - > speaker_switching_switch & & i < 4 )
scarlett2_sw_hw_ctl_ro ( private , i ) ;
2019-07-28 18:12:45 +03:00
}
}
2021-06-20 19:46:36 +03:00
/* Add dim/mute controls */
2021-06-20 19:46:34 +03:00
if ( info - > line_out_hw_vol )
2021-06-20 19:46:36 +03:00
for ( i = 0 ; i < SCARLETT2_DIM_MUTE_COUNT ; i + + ) {
2021-06-20 19:46:34 +03:00
err = scarlett2_add_new_ctl (
2021-06-20 19:46:36 +03:00
mixer , & scarlett2_dim_mute_ctl ,
i , 1 , scarlett2_dim_mute_names [ i ] ,
& private - > dim_mute_ctls [ i ] ) ;
2021-06-20 19:46:34 +03:00
if ( err < 0 )
return err ;
}
2019-07-28 18:12:45 +03:00
return 0 ;
}
/*** Create the analogue input controls ***/
static int scarlett2_add_line_in_ctls ( struct usb_mixer_interface * mixer )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2019-07-28 18:12:45 +03:00
const struct scarlett2_device_info * info = private - > info ;
int err , i ;
char s [ SNDRV_CTL_ELEM_ID_NAME_MAXLEN ] ;
2021-06-21 21:09:26 +03:00
const char * fmt = " Line In %d %s Capture %s " ;
2021-06-22 20:02:40 +03:00
const char * fmt2 = " Line In %d-%d %s Capture %s " ;
2019-07-28 18:12:45 +03:00
/* Add input level (line/inst) controls */
for ( i = 0 ; i < info - > level_input_count ; i + + ) {
2021-06-22 20:02:31 +03:00
snprintf ( s , sizeof ( s ) , fmt , i + 1 + info - > level_input_first ,
" Level " , " Enum " ) ;
2019-07-28 18:12:45 +03:00
err = scarlett2_add_new_ctl ( mixer , & scarlett2_level_enum_ctl ,
2021-06-22 20:01:44 +03:00
i , 1 , s , & private - > level_ctls [ i ] ) ;
2019-07-28 18:12:45 +03:00
if ( err < 0 )
return err ;
}
/* Add input pad controls */
for ( i = 0 ; i < info - > pad_input_count ; i + + ) {
2021-06-21 21:09:26 +03:00
snprintf ( s , sizeof ( s ) , fmt , i + 1 , " Pad " , " Switch " ) ;
2019-07-28 18:12:45 +03:00
err = scarlett2_add_new_ctl ( mixer , & scarlett2_pad_ctl ,
2021-06-22 20:01:44 +03:00
i , 1 , s , & private - > pad_ctls [ i ] ) ;
2019-07-28 18:12:45 +03:00
if ( err < 0 )
return err ;
}
2021-06-22 20:02:36 +03:00
/* Add input air controls */
for ( i = 0 ; i < info - > air_input_count ; i + + ) {
snprintf ( s , sizeof ( s ) , fmt , i + 1 , " Air " , " Switch " ) ;
err = scarlett2_add_new_ctl ( mixer , & scarlett2_air_ctl ,
i , 1 , s , & private - > air_ctls [ i ] ) ;
if ( err < 0 )
return err ;
}
2021-06-22 20:02:40 +03:00
/* Add input phantom controls */
if ( info - > inputs_per_phantom = = 1 ) {
for ( i = 0 ; i < info - > phantom_count ; i + + ) {
snprintf ( s , sizeof ( s ) , fmt , i + 1 ,
" Phantom Power " , " Switch " ) ;
err = scarlett2_add_new_ctl (
mixer , & scarlett2_phantom_ctl ,
i , 1 , s , & private - > phantom_ctls [ i ] ) ;
if ( err < 0 )
return err ;
}
} else if ( info - > inputs_per_phantom > 1 ) {
for ( i = 0 ; i < info - > phantom_count ; i + + ) {
int from = i * info - > inputs_per_phantom + 1 ;
int to = ( i + 1 ) * info - > inputs_per_phantom ;
2023-09-15 11:27:52 +03:00
scnprintf ( s , sizeof ( s ) , fmt2 , from , to ,
" Phantom Power " , " Switch " ) ;
2021-06-22 20:02:40 +03:00
err = scarlett2_add_new_ctl (
mixer , & scarlett2_phantom_ctl ,
i , 1 , s , & private - > phantom_ctls [ i ] ) ;
if ( err < 0 )
return err ;
}
}
if ( info - > phantom_count ) {
err = scarlett2_add_new_ctl (
mixer , & scarlett2_phantom_persistence_ctl , 0 , 1 ,
" Phantom Power Persistence Capture Switch " , NULL ) ;
if ( err < 0 )
return err ;
}
2019-07-28 18:12:45 +03:00
return 0 ;
}
/*** Mixer Volume Controls ***/
static int scarlett2_mixer_ctl_info ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_info * uinfo )
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = elem - > channels ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = SCARLETT2_MIXER_MAX_VALUE ;
uinfo - > value . integer . step = 1 ;
return 0 ;
}
static int scarlett2_mixer_ctl_get ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_value * ucontrol )
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = elem - > head . mixer - > private_data ;
2019-07-28 18:12:45 +03:00
ucontrol - > value . integer . value [ 0 ] = private - > mix [ elem - > control ] ;
return 0 ;
}
static int scarlett2_mixer_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 ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2019-07-28 18:12:45 +03:00
const struct scarlett2_device_info * info = private - > info ;
2021-06-21 21:09:43 +03:00
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2019-07-28 18:12:45 +03:00
int oval , val , num_mixer_in , mix_num , err = 0 ;
2021-06-20 19:46:41 +03:00
int index = elem - > control ;
2019-07-28 18:12:45 +03:00
mutex_lock ( & private - > data_mutex ) ;
2021-06-20 19:46:41 +03:00
oval = private - > mix [ index ] ;
2019-07-28 18:12:45 +03:00
val = ucontrol - > value . integer . value [ 0 ] ;
2021-06-21 21:09:43 +03:00
num_mixer_in = port_count [ SCARLETT2_PORT_TYPE_MIX ] [ SCARLETT2_PORT_OUT ] ;
2021-06-20 19:46:41 +03:00
mix_num = index / num_mixer_in ;
2019-07-28 18:12:45 +03:00
if ( oval = = val )
goto unlock ;
2021-06-20 19:46:41 +03:00
private - > mix [ index ] = val ;
2019-07-28 18:12:45 +03:00
err = scarlett2_usb_set_mix ( mixer , mix_num ) ;
if ( err = = 0 )
err = 1 ;
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const DECLARE_TLV_DB_MINMAX (
db_scale_scarlett2_mixer ,
SCARLETT2_MIXER_MIN_DB * 100 ,
SCARLETT2_MIXER_MAX_DB * 100
) ;
static const struct snd_kcontrol_new scarlett2_mixer_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ ,
. name = " " ,
. info = scarlett2_mixer_ctl_info ,
. get = scarlett2_mixer_ctl_get ,
. put = scarlett2_mixer_ctl_put ,
. private_value = SCARLETT2_MIXER_MAX_DB , /* max value */
. tlv = { . p = db_scale_scarlett2_mixer }
} ;
static int scarlett2_add_mixer_ctls ( struct usb_mixer_interface * mixer )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-21 21:09:43 +03:00
const struct scarlett2_device_info * info = private - > info ;
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2019-07-28 18:12:45 +03:00
int err , i , j ;
int index ;
char s [ SNDRV_CTL_ELEM_ID_NAME_MAXLEN ] ;
2021-06-21 21:09:43 +03:00
int num_inputs =
port_count [ SCARLETT2_PORT_TYPE_MIX ] [ SCARLETT2_PORT_OUT ] ;
int num_outputs =
port_count [ SCARLETT2_PORT_TYPE_MIX ] [ SCARLETT2_PORT_IN ] ;
2019-07-28 18:12:45 +03:00
2021-06-20 19:46:30 +03:00
for ( i = 0 , index = 0 ; i < num_outputs ; i + + )
2019-07-28 18:12:45 +03:00
for ( j = 0 ; j < num_inputs ; j + + , index + + ) {
snprintf ( s , sizeof ( s ) ,
" Mix %c Input %02d Playback Volume " ,
' A ' + i , j + 1 ) ;
err = scarlett2_add_new_ctl ( mixer , & scarlett2_mixer_ctl ,
index , 1 , s , NULL ) ;
if ( err < 0 )
return err ;
}
return 0 ;
}
/*** Mux Source Selection Controls ***/
static int scarlett2_mux_src_enum_ctl_info ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_info * uinfo )
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = elem - > head . mixer - > private_data ;
2021-06-21 21:09:43 +03:00
const struct scarlett2_device_info * info = private - > info ;
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2019-07-28 18:12:45 +03:00
unsigned int item = uinfo - > value . enumerated . item ;
int items = private - > num_mux_srcs ;
int port_type ;
uinfo - > type = SNDRV_CTL_ELEM_TYPE_ENUMERATED ;
uinfo - > count = elem - > channels ;
uinfo - > value . enumerated . items = items ;
if ( item > = items )
item = uinfo - > value . enumerated . item = items - 1 ;
for ( port_type = 0 ;
port_type < SCARLETT2_PORT_TYPE_COUNT ;
port_type + + ) {
2021-06-21 21:09:43 +03:00
if ( item < port_count [ port_type ] [ SCARLETT2_PORT_IN ] ) {
const struct scarlett2_port * port =
& scarlett2_ports [ port_type ] ;
2019-07-28 18:12:45 +03:00
sprintf ( uinfo - > value . enumerated . name ,
2021-06-21 21:09:43 +03:00
port - > src_descr , item + port - > src_num_offset ) ;
2019-07-28 18:12:45 +03:00
return 0 ;
}
2021-06-21 21:09:43 +03:00
item - = port_count [ port_type ] [ SCARLETT2_PORT_IN ] ;
2019-07-28 18:12:45 +03:00
}
return - EINVAL ;
}
static int scarlett2_mux_src_enum_ctl_get ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_value * ucontrol )
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
2021-06-22 20:03:50 +03:00
struct usb_mixer_interface * mixer = elem - > head . mixer ;
struct scarlett2_data * private = mixer - > private_data ;
2021-06-22 20:03:16 +03:00
const struct scarlett2_device_info * info = private - > info ;
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
int line_out_count =
port_count [ SCARLETT2_PORT_TYPE_ANALOGUE ] [ SCARLETT2_PORT_OUT ] ;
int index = elem - > control ;
if ( index < line_out_count )
index = line_out_remap ( private , index ) ;
2019-07-28 18:12:45 +03:00
2021-06-22 20:03:50 +03:00
mutex_lock ( & private - > data_mutex ) ;
if ( private - > mux_updated )
scarlett2_usb_get_mux ( mixer ) ;
2021-06-22 20:03:16 +03:00
ucontrol - > value . enumerated . item [ 0 ] = private - > mux [ index ] ;
2021-06-22 20:03:50 +03:00
mutex_unlock ( & private - > data_mutex ) ;
2019-07-28 18:12:45 +03:00
return 0 ;
}
static int scarlett2_mux_src_enum_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 ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-22 20:03:16 +03:00
const struct scarlett2_device_info * info = private - > info ;
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
int line_out_count =
port_count [ SCARLETT2_PORT_TYPE_ANALOGUE ] [ SCARLETT2_PORT_OUT ] ;
2019-07-28 18:12:45 +03:00
int index = elem - > control ;
int oval , val , err = 0 ;
2021-06-22 20:03:16 +03:00
if ( index < line_out_count )
index = line_out_remap ( private , index ) ;
2019-07-28 18:12:45 +03:00
mutex_lock ( & private - > data_mutex ) ;
oval = private - > mux [ index ] ;
2021-06-20 19:46:47 +03:00
val = min ( ucontrol - > value . enumerated . item [ 0 ] ,
private - > num_mux_srcs - 1U ) ;
2019-07-28 18:12:45 +03:00
if ( oval = = val )
goto unlock ;
private - > mux [ index ] = val ;
err = scarlett2_usb_set_mux ( mixer ) ;
if ( err = = 0 )
err = 1 ;
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_mux_src_enum_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = scarlett2_mux_src_enum_ctl_info ,
. get = scarlett2_mux_src_enum_ctl_get ,
. put = scarlett2_mux_src_enum_ctl_put ,
} ;
static int scarlett2_add_mux_enums ( struct usb_mixer_interface * mixer )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-21 21:09:43 +03:00
const struct scarlett2_device_info * info = private - > info ;
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2019-07-28 18:12:45 +03:00
int port_type , channel , i ;
for ( i = 0 , port_type = 0 ;
port_type < SCARLETT2_PORT_TYPE_COUNT ;
port_type + + ) {
for ( channel = 0 ;
2021-06-21 21:09:43 +03:00
channel < port_count [ port_type ] [ SCARLETT2_PORT_OUT ] ;
2019-07-28 18:12:45 +03:00
channel + + , i + + ) {
int err ;
char s [ SNDRV_CTL_ELEM_ID_NAME_MAXLEN ] ;
2021-06-21 21:09:43 +03:00
const char * const descr =
scarlett2_ports [ port_type ] . dst_descr ;
2019-07-28 18:12:45 +03:00
snprintf ( s , sizeof ( s ) - 5 , descr , channel + 1 ) ;
strcat ( s , " Enum " ) ;
err = scarlett2_add_new_ctl ( mixer ,
& scarlett2_mux_src_enum_ctl ,
2021-06-22 20:03:45 +03:00
i , 1 , s ,
& private - > mux_ctls [ i ] ) ;
2019-07-28 18:12:45 +03:00
if ( err < 0 )
return err ;
}
}
return 0 ;
}
/*** Meter Controls ***/
static int scarlett2_meter_ctl_info ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_info * uinfo )
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = elem - > channels ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 4095 ;
uinfo - > value . integer . step = 1 ;
return 0 ;
}
static int scarlett2_meter_ctl_get ( struct snd_kcontrol * kctl ,
struct snd_ctl_elem_value * ucontrol )
{
struct usb_mixer_elem_info * elem = kctl - > private_data ;
2021-06-21 21:09:46 +03:00
u16 meter_levels [ SCARLETT2_MAX_METERS ] ;
2019-07-28 18:12:45 +03:00
int i , err ;
2021-06-21 21:09:46 +03:00
err = scarlett2_usb_get_meter_levels ( elem - > head . mixer , elem - > channels ,
meter_levels ) ;
2019-07-28 18:12:45 +03:00
if ( err < 0 )
return err ;
for ( i = 0 ; i < elem - > channels ; i + + )
ucontrol - > value . integer . value [ i ] = meter_levels [ i ] ;
return 0 ;
}
static const struct snd_kcontrol_new scarlett2_meter_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_PCM ,
. access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE ,
. name = " " ,
. info = scarlett2_meter_ctl_info ,
. get = scarlett2_meter_ctl_get
} ;
static int scarlett2_add_meter_ctl ( struct usb_mixer_interface * mixer )
{
2021-06-21 21:09:46 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-22 20:02:31 +03:00
/* devices without a mixer also don't support reporting levels */
2022-03-06 18:21:04 +03:00
if ( private - > info - > config_set = = SCARLETT2_CONFIG_SET_NO_MIXER )
2021-06-22 20:02:31 +03:00
return 0 ;
2019-07-28 18:12:45 +03:00
return scarlett2_add_new_ctl ( mixer , & scarlett2_meter_ctl ,
2021-06-21 21:09:46 +03:00
0 , private - > num_mux_dsts ,
2019-07-28 18:12:45 +03:00
" Level Meter " , NULL ) ;
}
2021-06-22 20:01:52 +03:00
/*** MSD Controls ***/
static int scarlett2_msd_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 - > msd_switch ;
return 0 ;
}
static int scarlett2_msd_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 oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > msd_switch ;
val = ! ! ucontrol - > value . integer . value [ 0 ] ;
if ( oval = = val )
goto unlock ;
private - > msd_switch = val ;
/* Send switch change to the device */
err = scarlett2_usb_set_config ( mixer , SCARLETT2_CONFIG_MSD_SWITCH ,
0 , val ) ;
2021-06-27 16:22:56 +03:00
if ( err = = 0 )
err = 1 ;
2021-06-22 20:01:52 +03:00
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_msd_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = snd_ctl_boolean_mono_info ,
. get = scarlett2_msd_ctl_get ,
. put = scarlett2_msd_ctl_put ,
} ;
static int scarlett2_add_msd_ctl ( struct usb_mixer_interface * mixer )
{
struct scarlett2_data * private = mixer - > private_data ;
const struct scarlett2_device_info * info = private - > info ;
if ( ! info - > has_msd_mode )
return 0 ;
/* If MSD mode is off, hide the switch by default */
if ( ! private - > msd_switch & & ! ( mixer - > chip - > setup & SCARLETT2_MSD_ENABLE ) )
return 0 ;
/* Add MSD control */
return scarlett2_add_new_ctl ( mixer , & scarlett2_msd_ctl ,
2021-07-22 23:11:53 +03:00
0 , 1 , " MSD Mode Switch " , NULL ) ;
2021-06-22 20:01:52 +03:00
}
2022-03-06 18:21:39 +03:00
/*** Standalone Control ***/
static int scarlett2_standalone_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 - > standalone_switch ;
return 0 ;
}
static int scarlett2_standalone_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 oval , val , err = 0 ;
mutex_lock ( & private - > data_mutex ) ;
oval = private - > standalone_switch ;
val = ! ! ucontrol - > value . integer . value [ 0 ] ;
if ( oval = = val )
goto unlock ;
private - > standalone_switch = val ;
/* Send switch change to the device */
err = scarlett2_usb_set_config ( mixer ,
SCARLETT2_CONFIG_STANDALONE_SWITCH ,
0 , val ) ;
if ( err = = 0 )
err = 1 ;
unlock :
mutex_unlock ( & private - > data_mutex ) ;
return err ;
}
static const struct snd_kcontrol_new scarlett2_standalone_ctl = {
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " " ,
. info = snd_ctl_boolean_mono_info ,
. get = scarlett2_standalone_ctl_get ,
. put = scarlett2_standalone_ctl_put ,
} ;
static int scarlett2_add_standalone_ctl ( struct usb_mixer_interface * mixer )
{
struct scarlett2_data * private = mixer - > private_data ;
if ( private - > info - > config_set = = SCARLETT2_CONFIG_SET_NO_MIXER )
return 0 ;
/* Add standalone control */
return scarlett2_add_new_ctl ( mixer , & scarlett2_standalone_ctl ,
0 , 1 , " Standalone Switch " , NULL ) ;
}
2019-07-28 18:12:45 +03:00
/*** Cleanup/Suspend Callbacks ***/
static void scarlett2_private_free ( struct usb_mixer_interface * mixer )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2019-07-28 18:12:45 +03:00
cancel_delayed_work_sync ( & private - > work ) ;
kfree ( private ) ;
mixer - > private_data = NULL ;
}
static void scarlett2_private_suspend ( struct usb_mixer_interface * mixer )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2019-07-28 18:12:45 +03:00
if ( cancel_delayed_work_sync ( & private - > work ) )
scarlett2_config_save ( private - > mixer ) ;
}
/*** Initialisation ***/
2021-06-20 19:46:39 +03:00
static void scarlett2_count_mux_io ( struct scarlett2_data * private )
2019-07-28 18:12:45 +03:00
{
2021-06-21 21:09:43 +03:00
const struct scarlett2_device_info * info = private - > info ;
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2021-06-07 22:13:51 +03:00
int port_type , srcs = 0 , dsts = 0 ;
2019-07-28 18:12:45 +03:00
for ( port_type = 0 ;
port_type < SCARLETT2_PORT_TYPE_COUNT ;
2021-06-07 22:13:51 +03:00
port_type + + ) {
2021-06-21 21:09:43 +03:00
srcs + = port_count [ port_type ] [ SCARLETT2_PORT_IN ] ;
dsts + = port_count [ port_type ] [ SCARLETT2_PORT_OUT ] ;
2019-07-28 18:12:45 +03:00
}
2021-06-07 22:13:51 +03:00
private - > num_mux_srcs = srcs ;
private - > num_mux_dsts = dsts ;
2019-07-28 18:12:45 +03:00
}
2021-06-20 19:46:52 +03:00
/* Look through the interface descriptors for the Focusrite Control
* interface ( bInterfaceClass = 255 Vendor Specific Class ) and set
* bInterfaceNumber , bEndpointAddress , wMaxPacketSize , and bInterval
* in private
*/
static int scarlett2_find_fc_interface ( struct usb_device * dev ,
struct scarlett2_data * private )
{
struct usb_host_config * config = dev - > actconfig ;
int i ;
for ( i = 0 ; i < config - > desc . bNumInterfaces ; i + + ) {
struct usb_interface * intf = config - > interface [ i ] ;
struct usb_interface_descriptor * desc =
& intf - > altsetting [ 0 ] . desc ;
struct usb_endpoint_descriptor * epd ;
if ( desc - > bInterfaceClass ! = 255 )
continue ;
epd = get_endpoint ( intf - > altsetting , 0 ) ;
private - > bInterfaceNumber = desc - > bInterfaceNumber ;
private - > bEndpointAddress = epd - > bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK ;
private - > wMaxPacketSize = le16_to_cpu ( epd - > wMaxPacketSize ) ;
private - > bInterval = epd - > bInterval ;
return 0 ;
}
return - EINVAL ;
}
2021-06-21 21:09:13 +03:00
/* Initialise private data */
2019-07-28 18:12:45 +03:00
static int scarlett2_init_private ( struct usb_mixer_interface * mixer ,
const struct scarlett2_device_info * info )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private =
kzalloc ( sizeof ( struct scarlett2_data ) , GFP_KERNEL ) ;
2019-07-28 18:12:45 +03:00
if ( ! private )
return - ENOMEM ;
mutex_init ( & private - > usb_mutex ) ;
mutex_init ( & private - > data_mutex ) ;
INIT_DELAYED_WORK ( & private - > work , scarlett2_config_save_work ) ;
2021-06-20 19:46:52 +03:00
mixer - > private_data = private ;
mixer - > private_free = scarlett2_private_free ;
mixer - > private_suspend = scarlett2_private_suspend ;
2019-07-28 18:12:45 +03:00
private - > info = info ;
2021-06-07 22:13:51 +03:00
scarlett2_count_mux_io ( private ) ;
2019-07-28 18:12:45 +03:00
private - > scarlett2_seq = 0 ;
private - > mixer = mixer ;
2021-06-20 19:46:52 +03:00
2021-06-21 21:09:13 +03:00
return scarlett2_find_fc_interface ( mixer - > chip - > dev , private ) ;
}
/* Cargo cult proprietary initialisation sequence */
static int scarlett2_usb_init ( struct usb_mixer_interface * mixer )
{
struct usb_device * dev = mixer - > chip - > dev ;
struct scarlett2_data * private = mixer - > private_data ;
u8 buf [ 24 ] ;
int err ;
if ( usb_pipe_type_check ( dev , usb_sndctrlpipe ( dev , 0 ) ) )
return - EINVAL ;
/* step 0 */
err = scarlett2_usb_rx ( dev , private - > bInterfaceNumber ,
SCARLETT2_USB_CMD_INIT , buf , sizeof ( buf ) ) ;
2021-06-20 19:46:52 +03:00
if ( err < 0 )
return err ;
2019-07-28 18:12:45 +03:00
2021-06-21 21:09:13 +03:00
/* step 1 */
private - > scarlett2_seq = 1 ;
err = scarlett2_usb ( mixer , SCARLETT2_USB_INIT_1 , NULL , 0 , NULL , 0 ) ;
if ( err < 0 )
return err ;
/* step 2 */
private - > scarlett2_seq = 1 ;
return scarlett2_usb ( mixer , SCARLETT2_USB_INIT_2 , NULL , 0 , NULL , 84 ) ;
2019-07-28 18:12:45 +03:00
}
2021-06-07 22:13:25 +03:00
/* Read configuration from the interface on start */
2019-07-28 18:12:45 +03:00
static int scarlett2_read_configs ( struct usb_mixer_interface * mixer )
{
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2019-07-28 18:12:45 +03:00
const struct scarlett2_device_info * info = private - > info ;
2021-06-21 21:09:43 +03:00
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2019-07-28 18:12:45 +03:00
int num_line_out =
2021-06-21 21:09:43 +03:00
port_count [ SCARLETT2_PORT_TYPE_ANALOGUE ] [ SCARLETT2_PORT_OUT ] ;
2021-06-07 22:13:25 +03:00
int num_mixer_out =
2021-06-21 21:09:43 +03:00
port_count [ SCARLETT2_PORT_TYPE_MIX ] [ SCARLETT2_PORT_IN ] ;
2019-07-28 18:12:45 +03:00
struct scarlett2_usb_volume_status volume_status ;
int err , i ;
2021-06-22 20:01:52 +03:00
if ( info - > has_msd_mode ) {
err = scarlett2_usb_get_config (
mixer , SCARLETT2_CONFIG_MSD_SWITCH ,
1 , & private - > msd_switch ) ;
if ( err < 0 )
return err ;
/* no other controls are created if MSD mode is on */
if ( private - > msd_switch )
return 0 ;
}
2021-06-22 20:01:44 +03:00
err = scarlett2_update_input_other ( mixer ) ;
if ( err < 0 )
return err ;
2019-07-28 18:12:45 +03:00
2021-06-22 20:03:08 +03:00
err = scarlett2_update_monitor_other ( mixer ) ;
if ( err < 0 )
return err ;
2021-06-22 20:02:31 +03:00
/* the rest of the configuration is for devices with a mixer */
2022-03-06 18:21:04 +03:00
if ( info - > config_set = = SCARLETT2_CONFIG_SET_NO_MIXER )
2021-06-22 20:02:31 +03:00
return 0 ;
2022-03-06 18:21:39 +03:00
err = scarlett2_usb_get_config (
mixer , SCARLETT2_CONFIG_STANDALONE_SWITCH ,
1 , & private - > standalone_switch ) ;
if ( err < 0 )
return err ;
2021-06-21 21:09:24 +03:00
err = scarlett2_update_sync ( mixer ) ;
if ( err < 0 )
return err ;
2019-07-28 18:12:45 +03:00
err = scarlett2_usb_get_volume_status ( mixer , & volume_status ) ;
if ( err < 0 )
return err ;
2021-06-21 21:09:39 +03:00
if ( info - > line_out_hw_vol )
for ( i = 0 ; i < SCARLETT2_DIM_MUTE_COUNT ; i + + )
private - > dim_mute [ i ] = ! ! volume_status . dim_mute [ i ] ;
2019-07-28 18:12:45 +03:00
private - > master_vol = clamp (
volume_status . master_vol + SCARLETT2_VOLUME_BIAS ,
0 , SCARLETT2_VOLUME_BIAS ) ;
for ( i = 0 ; i < num_line_out ; i + + ) {
2021-06-21 21:09:39 +03:00
int volume , mute ;
2019-07-28 18:12:45 +03:00
private - > vol_sw_hw_switch [ i ] =
info - > line_out_hw_vol
& & volume_status . sw_hw_switch [ i ] ;
volume = private - > vol_sw_hw_switch [ i ]
? volume_status . master_vol
: volume_status . sw_vol [ i ] ;
volume = clamp ( volume + SCARLETT2_VOLUME_BIAS ,
0 , SCARLETT2_VOLUME_BIAS ) ;
private - > vol [ i ] = volume ;
2021-06-21 21:09:39 +03:00
mute = private - > vol_sw_hw_switch [ i ]
? private - > dim_mute [ SCARLETT2_BUTTON_MUTE ]
: volume_status . mute_switch [ i ] ;
private - > mute_switch [ i ] = mute ;
}
2019-07-28 18:12:45 +03:00
2021-06-07 22:13:25 +03:00
for ( i = 0 ; i < num_mixer_out ; i + + ) {
err = scarlett2_usb_get_mix ( mixer , i ) ;
if ( err < 0 )
return err ;
}
2021-06-07 22:13:51 +03:00
return scarlett2_usb_get_mux ( mixer ) ;
2019-07-28 18:12:45 +03:00
}
2021-06-21 21:09:24 +03:00
/* Notify on sync change */
static void scarlett2_notify_sync (
struct usb_mixer_interface * mixer )
{
struct scarlett2_data * private = mixer - > private_data ;
private - > sync_updated = 1 ;
snd_ctl_notify ( mixer - > chip - > card , SNDRV_CTL_EVENT_MASK_VALUE ,
& private - > sync_ctl - > id ) ;
}
2021-06-20 19:46:36 +03:00
/* Notify on monitor change */
static void scarlett2_notify_monitor (
2019-07-28 18:12:45 +03:00
struct usb_mixer_interface * mixer )
{
2021-06-22 20:03:16 +03:00
struct snd_card * card = mixer - > chip - > card ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-21 21:09:20 +03:00
const struct scarlett2_device_info * info = private - > info ;
2021-06-21 21:09:43 +03:00
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2019-07-28 18:12:45 +03:00
int num_line_out =
2021-06-21 21:09:43 +03:00
port_count [ SCARLETT2_PORT_TYPE_ANALOGUE ] [ SCARLETT2_PORT_OUT ] ;
2019-07-28 18:12:45 +03:00
int i ;
2021-06-21 21:09:20 +03:00
/* if line_out_hw_vol is 0, there are no controls to update */
if ( ! info - > line_out_hw_vol )
return ;
2019-07-28 18:12:45 +03:00
private - > vol_updated = 1 ;
snd_ctl_notify ( mixer - > chip - > card , SNDRV_CTL_EVENT_MASK_VALUE ,
& private - > master_vol_ctl - > id ) ;
2021-06-22 20:03:16 +03:00
for ( i = 0 ; i < num_line_out ; i + + )
if ( private - > vol_sw_hw_switch [ line_out_remap ( private , i ) ] )
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_VALUE ,
& private - > vol_ctls [ i ] - > id ) ;
2019-07-28 18:12:45 +03:00
}
2021-06-20 19:46:36 +03:00
/* Notify on dim/mute change */
static void scarlett2_notify_dim_mute (
2019-07-28 18:12:45 +03:00
struct usb_mixer_interface * mixer )
{
2021-06-21 21:09:39 +03:00
struct snd_card * card = mixer - > chip - > card ;
2021-06-20 19:46:39 +03:00
struct scarlett2_data * private = mixer - > private_data ;
2021-06-20 19:46:34 +03:00
const struct scarlett2_device_info * info = private - > info ;
2021-06-21 21:09:43 +03:00
const int ( * port_count ) [ SCARLETT2_PORT_DIRNS ] = info - > port_count ;
2021-06-21 21:09:39 +03:00
int num_line_out =
2021-06-21 21:09:43 +03:00
port_count [ SCARLETT2_PORT_TYPE_ANALOGUE ] [ SCARLETT2_PORT_OUT ] ;
2019-07-28 18:12:45 +03:00
int i ;
private - > vol_updated = 1 ;
2021-06-20 19:46:34 +03:00
if ( ! info - > line_out_hw_vol )
return ;
2021-06-20 19:46:36 +03:00
for ( i = 0 ; i < SCARLETT2_DIM_MUTE_COUNT ; i + + )
2021-06-21 21:09:39 +03:00
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_VALUE ,
2021-06-20 19:46:36 +03:00
& private - > dim_mute_ctls [ i ] - > id ) ;
2021-06-21 21:09:39 +03:00
for ( i = 0 ; i < num_line_out ; i + + )
2021-06-22 20:03:16 +03:00
if ( private - > vol_sw_hw_switch [ line_out_remap ( private , i ) ] )
2021-06-21 21:09:39 +03:00
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_VALUE ,
& private - > mute_ctls [ i ] - > id ) ;
2019-07-28 18:12:45 +03:00
}
2021-06-22 20:02:36 +03:00
/* Notify on "input other" change (level/pad/air) */
2021-06-22 20:01:44 +03:00
static void scarlett2_notify_input_other (
struct usb_mixer_interface * mixer )
{
struct snd_card * card = mixer - > chip - > card ;
struct scarlett2_data * private = mixer - > private_data ;
const struct scarlett2_device_info * info = private - > info ;
int i ;
private - > input_other_updated = 1 ;
for ( i = 0 ; i < info - > level_input_count ; i + + )
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_VALUE ,
& private - > level_ctls [ i ] - > id ) ;
for ( i = 0 ; i < info - > pad_input_count ; i + + )
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_VALUE ,
& private - > pad_ctls [ i ] - > id ) ;
2021-06-22 20:02:36 +03:00
for ( i = 0 ; i < info - > air_input_count ; i + + )
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_VALUE ,
& private - > air_ctls [ i ] - > id ) ;
2021-06-22 20:02:40 +03:00
for ( i = 0 ; i < info - > phantom_count ; i + + )
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_VALUE ,
& private - > phantom_ctls [ i ] - > id ) ;
2021-06-22 20:01:44 +03:00
}
2021-06-22 20:04:13 +03:00
/* Notify on "monitor other" change (direct monitor, speaker
* switching , talkback )
*/
2021-06-22 20:03:08 +03:00
static void scarlett2_notify_monitor_other (
struct usb_mixer_interface * mixer )
{
struct snd_card * card = mixer - > chip - > card ;
2021-06-22 20:03:58 +03:00
struct scarlett2_data * private = mixer - > private_data ;
const struct scarlett2_device_info * info = private - > info ;
2021-06-22 20:03:08 +03:00
private - > monitor_other_updated = 1 ;
2021-06-22 20:03:58 +03:00
if ( info - > direct_monitor ) {
2021-06-22 20:03:08 +03:00
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_VALUE ,
& private - > direct_monitor_ctl - > id ) ;
2021-06-22 20:03:58 +03:00
return ;
}
if ( info - > has_speaker_switching )
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_VALUE ,
& private - > speaker_switching_ctl - > id ) ;
2021-06-22 20:04:13 +03:00
if ( info - > has_talkback )
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_VALUE ,
& private - > talkback_ctl - > id ) ;
2021-06-22 20:03:58 +03:00
/* if speaker switching was recently enabled or disabled,
* invalidate the dim / mute and mux enum controls
*/
if ( private - > speaker_switching_switched ) {
int i ;
scarlett2_notify_dim_mute ( mixer ) ;
private - > speaker_switching_switched = 0 ;
private - > mux_updated = 1 ;
for ( i = 0 ; i < private - > num_mux_dsts ; i + + )
snd_ctl_notify ( card , SNDRV_CTL_EVENT_MASK_VALUE ,
& private - > mux_ctls [ i ] - > id ) ;
}
2021-06-22 20:03:08 +03:00
}
2019-07-28 18:12:45 +03:00
/* Interrupt callback */
2021-06-20 19:46:36 +03:00
static void scarlett2_notify ( struct urb * urb )
2019-07-28 18:12:45 +03:00
{
struct usb_mixer_interface * mixer = urb - > context ;
int len = urb - > actual_length ;
int ustatus = urb - > status ;
u32 data ;
2021-06-20 19:46:32 +03:00
if ( ustatus ! = 0 | | len ! = 8 )
2019-07-28 18:12:45 +03:00
goto requeue ;
2021-06-20 19:46:32 +03:00
data = le32_to_cpu ( * ( __le32 * ) urb - > transfer_buffer ) ;
2021-06-21 21:09:24 +03:00
if ( data & SCARLETT2_USB_NOTIFY_SYNC )
scarlett2_notify_sync ( mixer ) ;
2021-06-20 19:46:36 +03:00
if ( data & SCARLETT2_USB_NOTIFY_MONITOR )
scarlett2_notify_monitor ( mixer ) ;
if ( data & SCARLETT2_USB_NOTIFY_DIM_MUTE )
scarlett2_notify_dim_mute ( mixer ) ;
2021-06-22 20:01:44 +03:00
if ( data & SCARLETT2_USB_NOTIFY_INPUT_OTHER )
scarlett2_notify_input_other ( mixer ) ;
2021-06-22 20:03:08 +03:00
if ( data & SCARLETT2_USB_NOTIFY_MONITOR_OTHER )
scarlett2_notify_monitor_other ( mixer ) ;
2019-07-28 18:12:45 +03:00
requeue :
if ( ustatus ! = - ENOENT & &
ustatus ! = - ECONNRESET & &
ustatus ! = - ESHUTDOWN ) {
urb - > dev = mixer - > chip - > dev ;
usb_submit_urb ( urb , GFP_ATOMIC ) ;
}
}
2021-06-20 19:46:36 +03:00
static int scarlett2_init_notify ( struct usb_mixer_interface * mixer )
2019-07-28 18:12:45 +03:00
{
struct usb_device * dev = mixer - > chip - > dev ;
2021-06-20 19:46:52 +03:00
struct scarlett2_data * private = mixer - > private_data ;
unsigned int pipe = usb_rcvintpipe ( dev , private - > bEndpointAddress ) ;
2019-07-28 18:12:45 +03:00
void * transfer_buffer ;
if ( mixer - > urb ) {
usb_audio_err ( mixer - > chip ,
" %s: mixer urb already in use! \n " , __func__ ) ;
return 0 ;
}
2020-09-14 18:37:46 +03:00
if ( usb_pipe_type_check ( dev , pipe ) )
2019-07-28 18:12:45 +03:00
return - EINVAL ;
mixer - > urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! mixer - > urb )
return - ENOMEM ;
2021-06-20 19:46:52 +03:00
transfer_buffer = kmalloc ( private - > wMaxPacketSize , GFP_KERNEL ) ;
2019-07-28 18:12:45 +03:00
if ( ! transfer_buffer )
return - ENOMEM ;
usb_fill_int_urb ( mixer - > urb , dev , pipe ,
2021-06-20 19:46:52 +03:00
transfer_buffer , private - > wMaxPacketSize ,
scarlett2_notify , mixer , private - > bInterval ) ;
2019-07-28 18:12:45 +03:00
return usb_submit_urb ( mixer - > urb , GFP_KERNEL ) ;
}
2021-06-21 21:09:33 +03:00
static int snd_scarlett_gen2_controls_create ( struct usb_mixer_interface * mixer )
2019-07-28 18:12:45 +03:00
{
2021-06-21 21:09:33 +03:00
const struct scarlett2_device_info * * info = scarlett2_devices ;
2019-07-28 18:12:45 +03:00
int err ;
2021-06-21 21:09:33 +03:00
/* Find device in scarlett2_devices */
while ( * info & & ( * info ) - > usb_id ! = mixer - > chip - > usb_id )
info + + ;
if ( ! * info )
return - EINVAL ;
2021-06-21 21:09:13 +03:00
/* Initialise private data */
2021-06-21 21:09:33 +03:00
err = scarlett2_init_private ( mixer , * info ) ;
2019-07-28 18:12:45 +03:00
if ( err < 0 )
2021-06-21 21:09:13 +03:00
return err ;
/* Send proprietary USB initialisation sequence */
err = scarlett2_usb_init ( mixer ) ;
if ( err < 0 )
2019-07-28 18:12:45 +03:00
return err ;
/* Read volume levels and controls from the interface */
err = scarlett2_read_configs ( mixer ) ;
if ( err < 0 )
return err ;
2021-06-22 20:01:52 +03:00
/* Create the MSD control */
err = scarlett2_add_msd_ctl ( mixer ) ;
if ( err < 0 )
return err ;
/* If MSD mode is enabled, don't create any other controls */
if ( ( ( struct scarlett2_data * ) mixer - > private_data ) - > msd_switch )
return 0 ;
2019-07-28 18:12:45 +03:00
/* Create the analogue output controls */
err = scarlett2_add_line_out_ctls ( mixer ) ;
if ( err < 0 )
return err ;
/* Create the analogue input controls */
err = scarlett2_add_line_in_ctls ( mixer ) ;
if ( err < 0 )
return err ;
/* Create the input, output, and mixer mux input selections */
err = scarlett2_add_mux_enums ( mixer ) ;
if ( err < 0 )
return err ;
/* Create the matrix mixer controls */
err = scarlett2_add_mixer_ctls ( mixer ) ;
if ( err < 0 )
return err ;
/* Create the level meter controls */
err = scarlett2_add_meter_ctl ( mixer ) ;
if ( err < 0 )
return err ;
2021-06-21 21:09:24 +03:00
/* Create the sync control */
err = scarlett2_add_sync_ctl ( mixer ) ;
if ( err < 0 )
return err ;
2021-06-22 20:03:08 +03:00
/* Create the direct monitor control */
err = scarlett2_add_direct_monitor_ctl ( mixer ) ;
if ( err < 0 )
return err ;
2021-06-22 20:03:58 +03:00
/* Create the speaker switching control */
err = scarlett2_add_speaker_switch_ctl ( mixer ) ;
if ( err < 0 )
return err ;
2021-06-22 20:04:13 +03:00
/* Create the talkback controls */
err = scarlett2_add_talkback_ctls ( mixer ) ;
if ( err < 0 )
return err ;
2022-03-06 18:21:39 +03:00
/* Create the standalone control */
err = scarlett2_add_standalone_ctl ( mixer ) ;
if ( err < 0 )
return err ;
2021-06-21 21:09:20 +03:00
/* Set up the interrupt polling */
err = scarlett2_init_notify ( mixer ) ;
if ( err < 0 )
return err ;
2019-07-28 18:12:45 +03:00
return 0 ;
}
2021-05-21 11:20:13 +03:00
int snd_scarlett_gen2_init ( struct usb_mixer_interface * mixer )
{
struct snd_usb_audio * chip = mixer - > chip ;
int err ;
/* only use UAC_VERSION_2 */
if ( ! mixer - > protocol )
return 0 ;
2023-09-14 20:31:57 +03:00
if ( chip - > setup & SCARLETT2_DISABLE ) {
2021-05-21 11:20:13 +03:00
usb_audio_info ( chip ,
2023-09-14 20:31:57 +03:00
" Focusrite Scarlett Gen 2/3 Mixer Driver disabled "
" by modprobe options (snd_usb_audio "
" vid=0x%04x pid=0x%04x device_setup=%d) \n " ,
2021-05-21 11:20:13 +03:00
USB_ID_VENDOR ( chip - > usb_id ) ,
2023-09-14 20:31:57 +03:00
USB_ID_PRODUCT ( chip - > usb_id ) ,
SCARLETT2_DISABLE ) ;
2021-05-21 11:20:13 +03:00
return 0 ;
}
usb_audio_info ( chip ,
2023-09-14 20:31:57 +03:00
" Focusrite Scarlett Gen 2/3 Mixer Driver enabled (pid=0x%04x); "
" report any issues to g@b4.vu " ,
2021-05-21 11:20:13 +03:00
USB_ID_PRODUCT ( chip - > usb_id ) ) ;
2021-06-21 21:09:33 +03:00
err = snd_scarlett_gen2_controls_create ( mixer ) ;
2021-05-21 11:20:13 +03:00
if ( err < 0 )
usb_audio_err ( mixer - > chip ,
" Error initialising Scarlett Mixer Driver: %d " ,
err ) ;
return err ;
}