diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/6fire/Makefile | 2 | ||||
-rw-r--r-- | sound/usb/Makefile | 4 | ||||
-rw-r--r-- | sound/usb/card.c | 4 | ||||
-rw-r--r-- | sound/usb/hiface/Makefile | 2 | ||||
-rw-r--r-- | sound/usb/misc/Makefile | 2 | ||||
-rw-r--r-- | sound/usb/mixer.c | 7 | ||||
-rw-r--r-- | sound/usb/mixer_quirks.c | 2 | ||||
-rw-r--r-- | sound/usb/mixer_scarlett2.c | 2843 | ||||
-rw-r--r-- | sound/usb/quirks-table.h | 38 | ||||
-rw-r--r-- | sound/usb/quirks.c | 78 | ||||
-rw-r--r-- | sound/usb/usx2y/Makefile | 4 |
11 files changed, 2471 insertions, 515 deletions
diff --git a/sound/usb/6fire/Makefile b/sound/usb/6fire/Makefile index 7d353bbf74..587f25c64e 100644 --- a/sound/usb/6fire/Makefile +++ b/sound/usb/6fire/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-usb-6fire-objs += chip.o comm.o midi.o control.o firmware.o pcm.o +snd-usb-6fire-y += chip.o comm.o midi.o control.o firmware.o pcm.o obj-$(CONFIG_SND_USB_6FIRE) += snd-usb-6fire.o diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 8c657c2753..0532499dbc 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -3,7 +3,7 @@ # Makefile for ALSA # -snd-usb-audio-objs := card.o \ +snd-usb-audio-y := card.o \ clock.o \ endpoint.o \ format.o \ @@ -25,7 +25,7 @@ snd-usb-audio-objs := card.o \ snd-usb-audio-$(CONFIG_SND_USB_AUDIO_MIDI_V2) += midi2.o snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o -snd-usbmidi-lib-objs := midi.o +snd-usbmidi-lib-y := midi.o # Toplevel Module Dependency obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usbmidi-lib.o diff --git a/sound/usb/card.c b/sound/usb/card.c index 1b2edc0fd2..bdb04fa37a 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -425,6 +425,10 @@ static const struct usb_audio_device_name usb_audio_names[] = { DEVICE_NAME(0x0fd9, 0x0008, "Hauppauge", "HVR-950Q"), + /* Dock/Stand for HP Engage Go */ + PROFILE_NAME(0x103c, 0x830a, "HP", "HP Engage Go Dock", + "HP-Engage-Go-Dock"), + /* Stanton/N2IT Final Scratch v1 device ('Scratchamp') */ DEVICE_NAME(0x103d, 0x0100, "Stanton", "ScratchAmp"), DEVICE_NAME(0x103d, 0x0101, "Stanton", "ScratchAmp"), diff --git a/sound/usb/hiface/Makefile b/sound/usb/hiface/Makefile index 8f3b24e7d6..997c1558d0 100644 --- a/sound/usb/hiface/Makefile +++ b/sound/usb/hiface/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-usb-hiface-objs := chip.o pcm.o +snd-usb-hiface-y := chip.o pcm.o obj-$(CONFIG_SND_USB_HIFACE) += snd-usb-hiface.o diff --git a/sound/usb/misc/Makefile b/sound/usb/misc/Makefile index 068ecd7bc0..3e9f4adc28 100644 --- a/sound/usb/misc/Makefile +++ b/sound/usb/misc/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-ua101-objs := ua101.o +snd-ua101-y := ua101.o obj-$(CONFIG_SND_USB_UA101) += snd-ua101.o diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 409fc11646..d1bdb0b93b 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1211,6 +1211,13 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, cval->res = 16; } break; + case USB_ID(0x1bcf, 0x2281): /* HD Webcam */ + if (!strcmp(kctl->id.name, "Mic Capture Volume")) { + usb_audio_info(chip, + "set resolution quirk: cval->res = 16\n"); + cval->res = 16; + } + break; } } diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 065a4be0d7..212b5e6443 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3447,6 +3447,8 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x1235, 0x8213): /* Focusrite Scarlett 8i6 3rd Gen */ case USB_ID(0x1235, 0x8214): /* Focusrite Scarlett 18i8 3rd Gen */ case USB_ID(0x1235, 0x8215): /* Focusrite Scarlett 18i20 3rd Gen */ + case USB_ID(0x1235, 0x8216): /* Focusrite Vocaster One */ + case USB_ID(0x1235, 0x8217): /* Focusrite Vocaster Two */ case USB_ID(0x1235, 0x8218): /* Focusrite Scarlett Solo 4th Gen */ case USB_ID(0x1235, 0x8219): /* Focusrite Scarlett 2i2 4th Gen */ case USB_ID(0x1235, 0x821a): /* Focusrite Scarlett 4i4 4th Gen */ diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index bd114be537..1150cf1049 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -85,8 +85,10 @@ * controls * - disable/enable MSD mode * - disable/enable standalone mode - * - input gain, autogain, safe mode + * - input mute, gain, autogain, safe mode * - direct monitor mixes + * - compressor and EQ + * - Bluetooth volume * * <ditaa> * /--------------\ 18chn 20chn /--------------\ @@ -174,22 +176,24 @@ /* some gui mixers can't handle negative ctl values */ #define SCARLETT2_VOLUME_BIAS 127 -/* maximum preamp input gain and value - * values are from 0 to 70, preamp gain is from 0 to 69 dB +/* maximum preamp input gain value + * (the corresponding value in dB is per-device) */ #define SCARLETT2_MAX_GAIN_VALUE 70 -#define SCARLETT2_MAX_GAIN_DB 69 -/* mixer range from -80dB to +6dB in 0.5dB steps */ +/* maximum Bluetooth volume value */ +#define SCARLETT2_MAX_BLUETOOTH_VOLUME 30 + +/* mixer range from -80dB to +12dB 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_DB 12 #define SCARLETT2_MIXER_MAX_VALUE \ ((SCARLETT2_MIXER_MAX_DB - SCARLETT2_MIXER_MIN_DB) * 2) #define SCARLETT2_MIXER_VALUE_COUNT (SCARLETT2_MIXER_MAX_VALUE + 1) /* map from (dB + 80) * 2 to mixer value - * for dB in 0 .. 172: int(8192 * pow(10, ((dB - 160) / 2 / 20))) + * for dB in 0 .. 184: int(8192 * pow(10, ((dB - 160) / 2 / 20))) */ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, @@ -205,7 +209,8 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { 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 + 16345, 17313, 18339, 19426, 20577, 21796, 23088, 24456, 25905, + 27440, 29066, 30788, 32612 }; /* Maximum number of analogue outputs */ @@ -215,6 +220,8 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { #define SCARLETT2_LEVEL_SWITCH_MAX 2 #define SCARLETT2_PAD_SWITCH_MAX 8 #define SCARLETT2_AIR_SWITCH_MAX 8 +#define SCARLETT2_DSP_SWITCH_MAX 2 +#define SCARLETT2_INPUT_MUTE_SWITCH_MAX 2 #define SCARLETT2_PHANTOM_SWITCH_MAX 2 #define SCARLETT2_INPUT_GAIN_MAX 2 @@ -245,6 +252,59 @@ static const u16 scarlett2_mixer_values[SCARLETT2_MIXER_VALUE_COUNT] = { /* Maximum number of meters (sum of output port counts) */ #define SCARLETT2_MAX_METERS 65 +/* Compressor parameter data + * + * The compressor parameters are 32-bit fixed point values with 24 + * bits of fraction. Integer values are sufficient for the parameters + * except for ratio which we can set in 0.5:1 steps. + */ +struct compressor_param { + const char *name; + snd_ctl_elem_type_t type; + s32 min; + s32 max; + int scale_bits; +}; + +/* The available compressor parameters on the Vocaster: + * - Enable: Off, On + * - Threshold: -40dB to 0dB + * - Ratio: 1:1 to 50:1 in 0.5:1 steps + * - Knee Width: 0dB to 10dB + * - Attack: 30ms to 127ms + * - Release: 30ms to 127ms + * - Makeup Gain: 0dB to 24dB + */ +static const struct compressor_param compressor_params[] = { + { "Enable", SNDRV_CTL_ELEM_TYPE_BOOLEAN, 0, 1, 0 }, + { "Threshold", SNDRV_CTL_ELEM_TYPE_INTEGER, -40, 0, 24 }, + { "Ratio", SNDRV_CTL_ELEM_TYPE_INTEGER, 2, 100, 23 }, + { "Knee Width", SNDRV_CTL_ELEM_TYPE_INTEGER, 0, 10, 24 }, + { "Attack", SNDRV_CTL_ELEM_TYPE_INTEGER, 30, 127, 24 }, + { "Release", SNDRV_CTL_ELEM_TYPE_INTEGER, 30, 127, 24 }, + { "Makeup Gain", SNDRV_CTL_ELEM_TYPE_INTEGER, 0, 24, 24 }, +}; + +#define SCARLETT2_COMPRESSOR_PARAM_COUNT ARRAY_SIZE(compressor_params) +#define SCARLETT2_COMPRESSOR_CTLS_MAX \ + (SCARLETT2_COMPRESSOR_PARAM_COUNT * SCARLETT2_DSP_SWITCH_MAX) + +/* Maximum number of filter controls */ +#define SCARLETT2_PRECOMP_FLT_CTLS_MAX (2 * SCARLETT2_DSP_SWITCH_MAX) +#define SCARLETT2_PEQ_FLT_CTLS_MAX (3 * SCARLETT2_DSP_SWITCH_MAX) + +/* Number of biquad filter coefficients */ +#define SCARLETT2_BIQUAD_COEFFS 5 + +/* Maximum number of filter coefficient values */ +#define SCARLETT2_PRECOMP_FLT_VALUES_MAX \ + (SCARLETT2_PRECOMP_FLT_CTLS_MAX * SCARLETT2_BIQUAD_COEFFS) +#define SCARLETT2_PEQ_FLT_VALUES_MAX \ + (SCARLETT2_PEQ_FLT_CTLS_MAX * SCARLETT2_BIQUAD_COEFFS) + +/* Maximum number of PEQ filter slots */ +#define SCARLETT2_PEQ_FLT_SLOTS_MAX 4 + /* Hardware port types: * - None (no input to mux) * - Analogue I/O @@ -277,6 +337,17 @@ enum { SCARLETT2_DIM_MUTE_COUNT }; +/* Autogain target values */ + +#define SCARLETT2_AG_TARGET_MIN (-30) + +enum { + SCARLETT2_AG_HOT_TARGET, + SCARLETT2_AG_MEAN_TARGET, + SCARLETT2_AG_PEAK_TARGET, + SCARLETT2_AG_TARGET_COUNT +}; + /* Flash Write State */ enum { SCARLETT2_FLASH_WRITE_STATE_IDLE, @@ -295,7 +366,7 @@ static const char *const scarlett2_dim_mute_names[SCARLETT2_DIM_MUTE_COUNT] = { * If autogain_switch is set, autogain_status is set to 0 (Running). * The other status values are from the raw_autogain_status value + 1. */ -static const char *const scarlett2_autogain_status_texts[] = { +static const char *const scarlett2_autogain_status_gen4[] = { "Running", "Success", "SuccessDRover", @@ -304,7 +375,20 @@ static const char *const scarlett2_autogain_status_texts[] = { "FailMaxGainLimit", "FailClipped", "Cancelled", - "Invalid" + "Invalid", + NULL +}; + +static const char *const scarlett2_autogain_status_vocaster[] = { + "Running", + "Success", + "FailPG", + "FailRange", + "WarnMaxCap", + "WarnMinCap", + "Cancelled", + "Invalid", + NULL }; /* Power Status Values */ @@ -321,6 +405,7 @@ struct scarlett2_notification { void (*func)(struct usb_mixer_interface *mixer); }; +static void scarlett2_notify_ack(struct usb_mixer_interface *mixer); static void scarlett2_notify_sync(struct usb_mixer_interface *mixer); static void scarlett2_notify_dim_mute(struct usb_mixer_interface *mixer); static void scarlett2_notify_monitor(struct usb_mixer_interface *mixer); @@ -328,6 +413,8 @@ static void scarlett2_notify_volume(struct usb_mixer_interface *mixer); static void scarlett2_notify_input_level(struct usb_mixer_interface *mixer); static void scarlett2_notify_input_pad(struct usb_mixer_interface *mixer); static void scarlett2_notify_input_air(struct usb_mixer_interface *mixer); +static void scarlett2_notify_input_dsp(struct usb_mixer_interface *mixer); +static void scarlett2_notify_input_mute(struct usb_mixer_interface *mixer); static void scarlett2_notify_input_phantom(struct usb_mixer_interface *mixer); static void scarlett2_notify_input_other(struct usb_mixer_interface *mixer); static void scarlett2_notify_input_select(struct usb_mixer_interface *mixer); @@ -339,11 +426,12 @@ static void scarlett2_notify_direct_monitor(struct usb_mixer_interface *mixer); static void scarlett2_notify_power_status(struct usb_mixer_interface *mixer); static void scarlett2_notify_pcm_input_switch( struct usb_mixer_interface *mixer); +static void scarlett2_notify_bluetooth(struct usb_mixer_interface *mixer); /* Arrays of notification callback functions */ static const struct scarlett2_notification scarlett2_notifications[] = { - { 0x00000001, NULL }, /* ack, gets ignored */ + { 0x00000001, scarlett2_notify_ack }, { 0x00000008, scarlett2_notify_sync }, { 0x00200000, scarlett2_notify_dim_mute }, { 0x00400000, scarlett2_notify_monitor }, @@ -353,14 +441,26 @@ static const struct scarlett2_notification scarlett2_notifications[] = { }; static const struct scarlett2_notification scarlett3a_notifications[] = { - { 0x00000001, NULL }, /* ack, gets ignored */ + { 0x00000001, scarlett2_notify_ack }, { 0x00800000, scarlett2_notify_input_other }, { 0x01000000, scarlett2_notify_direct_monitor }, { 0, NULL } }; +static const struct scarlett2_notification vocaster_notifications[] = { + { 0x00000001, scarlett2_notify_ack }, + { 0x00000008, scarlett2_notify_sync }, + { 0x00200000, scarlett2_notify_input_mute }, + { 0x00400000, scarlett2_notify_autogain }, + { 0x04000000, scarlett2_notify_input_dsp }, + { 0x08000000, scarlett2_notify_input_gain }, + { 0x10000000, scarlett2_notify_input_phantom }, + { 0x20000000, scarlett2_notify_bluetooth }, + { 0, NULL } +}; + static const struct scarlett2_notification scarlett4_solo_notifications[] = { - { 0x00000001, NULL }, /* ack, gets ignored */ + { 0x00000001, scarlett2_notify_ack }, { 0x00000008, scarlett2_notify_sync }, { 0x00400000, scarlett2_notify_input_air }, { 0x00800000, scarlett2_notify_direct_monitor }, @@ -371,7 +471,7 @@ static const struct scarlett2_notification scarlett4_solo_notifications[] = { }; static const struct scarlett2_notification scarlett4_2i2_notifications[] = { - { 0x00000001, NULL }, /* ack, gets ignored */ + { 0x00000001, scarlett2_notify_ack }, { 0x00000008, scarlett2_notify_sync }, { 0x00200000, scarlett2_notify_input_safe }, { 0x00400000, scarlett2_notify_autogain }, @@ -387,7 +487,7 @@ static const struct scarlett2_notification scarlett4_2i2_notifications[] = { }; static const struct scarlett2_notification scarlett4_4i4_notifications[] = { - { 0x00000001, NULL }, /* ack, gets ignored */ + { 0x00000001, scarlett2_notify_ack }, { 0x00000008, scarlett2_notify_sync }, { 0x00200000, scarlett2_notify_input_safe }, { 0x00400000, scarlett2_notify_autogain }, @@ -414,6 +514,13 @@ enum { SCARLETT2_CONFIG_PAD_SWITCH, SCARLETT2_CONFIG_MSD_SWITCH, SCARLETT2_CONFIG_AIR_SWITCH, + SCARLETT2_CONFIG_DSP_SWITCH, + SCARLETT2_CONFIG_COMPRESSOR_PARAMS, + SCARLETT2_CONFIG_PRECOMP_FLT_SWITCH, + SCARLETT2_CONFIG_PRECOMP_FLT_PARAMS, + SCARLETT2_CONFIG_PEQ_FLT_SWITCH, + SCARLETT2_CONFIG_PEQ_FLT_PARAMS, + SCARLETT2_CONFIG_INPUT_MUTE_SWITCH, SCARLETT2_CONFIG_STANDALONE_SWITCH, SCARLETT2_CONFIG_PHANTOM_SWITCH, SCARLETT2_CONFIG_PHANTOM_PERSISTENCE, @@ -423,6 +530,9 @@ enum { SCARLETT2_CONFIG_TALKBACK_MAP, SCARLETT2_CONFIG_AUTOGAIN_SWITCH, SCARLETT2_CONFIG_AUTOGAIN_STATUS, + SCARLETT2_CONFIG_AG_HOT_TARGET, + SCARLETT2_CONFIG_AG_MEAN_TARGET, + SCARLETT2_CONFIG_AG_PEAK_TARGET, SCARLETT2_CONFIG_INPUT_GAIN, SCARLETT2_CONFIG_SAFE_SWITCH, SCARLETT2_CONFIG_INPUT_SELECT_SWITCH, @@ -431,15 +541,30 @@ enum { SCARLETT2_CONFIG_POWER_LOW, SCARLETT2_CONFIG_PCM_INPUT_SWITCH, SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN, + SCARLETT2_CONFIG_BLUETOOTH_VOLUME, + SCARLETT2_CONFIG_SPDIF_MODE, SCARLETT2_CONFIG_COUNT }; +/* Autogain target configuration parameters and names */ + +static const int scarlett2_ag_target_configs[] = { + [SCARLETT2_AG_HOT_TARGET] = SCARLETT2_CONFIG_AG_HOT_TARGET, + [SCARLETT2_AG_MEAN_TARGET] = SCARLETT2_CONFIG_AG_MEAN_TARGET, + [SCARLETT2_AG_PEAK_TARGET] = SCARLETT2_CONFIG_AG_PEAK_TARGET +}; + +static const char *const scarlett2_ag_target_names[] = { + "Hot", "Mean", "Peak" +}; + /* Location, size, and activation command number for the configuration - * parameters. Size is in bits and may be 0, 1, 8, or 16. + * parameters. Size is in bits and may be 1, 8, 16, or 32. * - * A size of 0 indicates that the parameter is a byte-sized Scarlett - * Gen 4 configuration which is written through the gen4_write_addr - * location (but still read through the given offset location). + * Vocaster and 4th Gen devices have a parameter buffer to set certain + * configuration parameters. When pbuf is set, rather than writing to + * the given offset, the channel and value are written to the + * parameter buffer and the activate command is sent to the device. * * Some Gen 4 configuration parameters are written with 0x02 for a * desired value of 0x01, and 0x03 for 0x00. These are indicated with @@ -451,15 +576,28 @@ struct scarlett2_config { u16 offset; u8 size; u8 activate; + u8 pbuf; u8 mute; }; struct scarlett2_config_set { const struct scarlett2_notification *notifications; - u16 gen4_write_addr; + u16 param_buf_addr; + const unsigned int *input_gain_tlv; + const char *const *autogain_status_texts; const struct scarlett2_config items[SCARLETT2_CONFIG_COUNT]; }; +/* Input gain TLV dB ranges */ + +static const DECLARE_TLV_DB_MINMAX( + db_scale_vocaster_gain, 0, 70 * 100 +); + +static const DECLARE_TLV_DB_MINMAX( + db_scale_gen4_gain, 0, 69 * 100 +); + /* Gen 2 devices without SW/HW volume switch: 6i6, 18i8 */ static const struct scarlett2_config_set scarlett2_config_set_gen2a = { @@ -618,31 +756,87 @@ static const struct scarlett2_config_set scarlett2_config_set_gen3c = { [SCARLETT2_CONFIG_TALKBACK_MAP] = { .offset = 0xb0, .size = 16, .activate = 10 }, + + [SCARLETT2_CONFIG_SPDIF_MODE] = { + .offset = 0x94, .size = 8, .activate = 6 }, + } +}; + +/* Vocaster */ +static const struct scarlett2_config_set scarlett2_config_set_vocaster = { + .notifications = vocaster_notifications, + .param_buf_addr = 0x1bc, + .input_gain_tlv = db_scale_vocaster_gain, + .autogain_status_texts = scarlett2_autogain_status_vocaster, + .items = { + [SCARLETT2_CONFIG_MSD_SWITCH] = { + .offset = 0x9d, .size = 8, .activate = 6 }, + + [SCARLETT2_CONFIG_AUTOGAIN_SWITCH] = { + .offset = 0x1c0, .size = 8, .activate = 19, .pbuf = 1 }, + + [SCARLETT2_CONFIG_AUTOGAIN_STATUS] = { + .offset = 0x1c2, .size = 8, }, + + [SCARLETT2_CONFIG_AG_HOT_TARGET] = { + .offset = 0xc1, .size = 8, .activate = 29, .pbuf = 1 }, + + [SCARLETT2_CONFIG_INPUT_GAIN] = { + .offset = 0x9f, .size = 8, .activate = 21, .pbuf = 1 }, + + [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { + .offset = 0x9c, .size = 1, .activate = 20, .pbuf = 1 }, + + [SCARLETT2_CONFIG_DSP_SWITCH] = { + .offset = 0x1c4, .size = 8, .activate = 22, .pbuf = 1 }, + + [SCARLETT2_CONFIG_COMPRESSOR_PARAMS] = { + .offset = 0x1c8, .size = 32, .activate = 23 }, + + [SCARLETT2_CONFIG_PRECOMP_FLT_SWITCH] = { + .offset = 0x7c, .size = 32, .activate = 27 }, + + [SCARLETT2_CONFIG_PRECOMP_FLT_PARAMS] = { + .offset = 0x200, .size = 32, .activate = 27 }, + + [SCARLETT2_CONFIG_PEQ_FLT_SWITCH] = { + .offset = 0x84, .size = 32, .activate = 27 }, + + [SCARLETT2_CONFIG_PEQ_FLT_PARAMS] = { + .offset = 0x250, .size = 32, .activate = 27 }, + + [SCARLETT2_CONFIG_INPUT_MUTE_SWITCH] = { + .offset = 0x1be, .size = 8, .activate = 17, .pbuf = 1 }, + + [SCARLETT2_CONFIG_BLUETOOTH_VOLUME] = { + .offset = 0xbf, .size = 8, .activate = 28 }, } }; /* Solo Gen 4 */ static const struct scarlett2_config_set scarlett2_config_set_gen4_solo = { .notifications = scarlett4_solo_notifications, - .gen4_write_addr = 0xd8, + .param_buf_addr = 0xd8, .items = { [SCARLETT2_CONFIG_MSD_SWITCH] = { .offset = 0x47, .size = 8, .activate = 4 }, [SCARLETT2_CONFIG_DIRECT_MONITOR] = { - .offset = 0x108, .activate = 12 }, + .offset = 0x108, .size = 8, .activate = 12, .pbuf = 1 }, [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { - .offset = 0x46, .activate = 9, .mute = 1 }, + .offset = 0x46, .size = 8, .activate = 9, .pbuf = 1, + .mute = 1 }, [SCARLETT2_CONFIG_LEVEL_SWITCH] = { - .offset = 0x3d, .activate = 10, .mute = 1 }, + .offset = 0x3d, .size = 8, .activate = 10, .pbuf = 1, + .mute = 1 }, [SCARLETT2_CONFIG_AIR_SWITCH] = { - .offset = 0x3e, .activate = 11 }, + .offset = 0x3e, .size = 8, .activate = 11, .pbuf = 1 }, [SCARLETT2_CONFIG_PCM_INPUT_SWITCH] = { - .offset = 0x206, .activate = 25 }, + .offset = 0x206, .size = 8, .activate = 25, .pbuf = 1 }, [SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN] = { .offset = 0x232, .size = 16, .activate = 26 } @@ -652,40 +846,50 @@ static const struct scarlett2_config_set scarlett2_config_set_gen4_solo = { /* 2i2 Gen 4 */ static const struct scarlett2_config_set scarlett2_config_set_gen4_2i2 = { .notifications = scarlett4_2i2_notifications, - .gen4_write_addr = 0xfc, + .param_buf_addr = 0xfc, + .input_gain_tlv = db_scale_gen4_gain, + .autogain_status_texts = scarlett2_autogain_status_gen4, .items = { [SCARLETT2_CONFIG_MSD_SWITCH] = { - .offset = 0x49, .size = 8, .activate = 4 }, // 0x41 ?? + .offset = 0x49, .size = 8, .activate = 4 }, [SCARLETT2_CONFIG_DIRECT_MONITOR] = { - .offset = 0x14a, .activate = 16 }, + .offset = 0x14a, .size = 8, .activate = 16, .pbuf = 1 }, [SCARLETT2_CONFIG_AUTOGAIN_SWITCH] = { - .offset = 0x135, .activate = 10 }, + .offset = 0x135, .size = 8, .activate = 10, .pbuf = 1 }, [SCARLETT2_CONFIG_AUTOGAIN_STATUS] = { - .offset = 0x137 }, + .offset = 0x137, .size = 8 }, + + [SCARLETT2_CONFIG_AG_MEAN_TARGET] = { + .offset = 0x131, .size = 8, .activate = 29, .pbuf = 1 }, + + [SCARLETT2_CONFIG_AG_PEAK_TARGET] = { + .offset = 0x132, .size = 8, .activate = 30, .pbuf = 1 }, [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { - .offset = 0x48, .activate = 11, .mute = 1 }, + .offset = 0x48, .size = 8, .activate = 11, .pbuf = 1, + .mute = 1 }, [SCARLETT2_CONFIG_INPUT_GAIN] = { - .offset = 0x4b, .activate = 12 }, + .offset = 0x4b, .size = 8, .activate = 12, .pbuf = 1 }, [SCARLETT2_CONFIG_LEVEL_SWITCH] = { - .offset = 0x3c, .activate = 13, .mute = 1 }, + .offset = 0x3c, .size = 8, .activate = 13, .pbuf = 1, + .mute = 1 }, [SCARLETT2_CONFIG_SAFE_SWITCH] = { - .offset = 0x147, .activate = 14 }, + .offset = 0x147, .size = 8, .activate = 14, .pbuf = 1 }, [SCARLETT2_CONFIG_AIR_SWITCH] = { - .offset = 0x3e, .activate = 15 }, + .offset = 0x3e, .size = 8, .activate = 15, .pbuf = 1 }, [SCARLETT2_CONFIG_INPUT_SELECT_SWITCH] = { - .offset = 0x14b, .activate = 17 }, + .offset = 0x14b, .size = 8, .activate = 17, .pbuf = 1 }, [SCARLETT2_CONFIG_INPUT_LINK_SWITCH] = { - .offset = 0x14e, .activate = 18 }, + .offset = 0x14e, .size = 8, .activate = 18, .pbuf = 1 }, [SCARLETT2_CONFIG_DIRECT_MONITOR_GAIN] = { .offset = 0x2a0, .size = 16, .activate = 36 } @@ -695,37 +899,47 @@ static const struct scarlett2_config_set scarlett2_config_set_gen4_2i2 = { /* 4i4 Gen 4 */ static const struct scarlett2_config_set scarlett2_config_set_gen4_4i4 = { .notifications = scarlett4_4i4_notifications, - .gen4_write_addr = 0x130, + .param_buf_addr = 0x130, + .input_gain_tlv = db_scale_gen4_gain, + .autogain_status_texts = scarlett2_autogain_status_gen4, .items = { [SCARLETT2_CONFIG_MSD_SWITCH] = { .offset = 0x5c, .size = 8, .activate = 4 }, [SCARLETT2_CONFIG_AUTOGAIN_SWITCH] = { - .offset = 0x13e, .activate = 10 }, + .offset = 0x13e, .size = 8, .activate = 10, .pbuf = 1 }, [SCARLETT2_CONFIG_AUTOGAIN_STATUS] = { - .offset = 0x140 }, + .offset = 0x140, .size = 8 }, + + [SCARLETT2_CONFIG_AG_MEAN_TARGET] = { + .offset = 0x13a, .size = 8, .activate = 23, .pbuf = 1 }, + + [SCARLETT2_CONFIG_AG_PEAK_TARGET] = { + .offset = 0x13b, .size = 8, .activate = 24, .pbuf = 1 }, [SCARLETT2_CONFIG_PHANTOM_SWITCH] = { - .offset = 0x5a, .activate = 11, .mute = 1 }, + .offset = 0x5a, .size = 8, .activate = 11, .pbuf = 1, + .mute = 1 }, [SCARLETT2_CONFIG_INPUT_GAIN] = { - .offset = 0x5e, .activate = 12 }, + .offset = 0x5e, .size = 8, .activate = 12, .pbuf = 1 }, [SCARLETT2_CONFIG_LEVEL_SWITCH] = { - .offset = 0x4e, .activate = 13, .mute = 1 }, + .offset = 0x4e, .size = 8, .activate = 13, .pbuf = 1, + .mute = 1 }, [SCARLETT2_CONFIG_SAFE_SWITCH] = { - .offset = 0x150, .activate = 14 }, + .offset = 0x150, .size = 8, .activate = 14, .pbuf = 1 }, [SCARLETT2_CONFIG_AIR_SWITCH] = { - .offset = 0x50, .activate = 15 }, + .offset = 0x50, .size = 8, .activate = 15, .pbuf = 1 }, [SCARLETT2_CONFIG_INPUT_SELECT_SWITCH] = { - .offset = 0x153, .activate = 16 }, + .offset = 0x153, .size = 8, .activate = 16, .pbuf = 1 }, [SCARLETT2_CONFIG_INPUT_LINK_SWITCH] = { - .offset = 0x156, .activate = 17 }, + .offset = 0x156, .size = 8, .activate = 17, .pbuf = 1 }, [SCARLETT2_CONFIG_MASTER_VOLUME] = { .offset = 0x32, .size = 16 }, @@ -734,10 +948,10 @@ static const struct scarlett2_config_set scarlett2_config_set_gen4_4i4 = { .offset = 0x3a, .size = 16 }, [SCARLETT2_CONFIG_POWER_EXT] = { - .offset = 0x168 }, + .offset = 0x168, .size = 8 }, [SCARLETT2_CONFIG_POWER_LOW] = { - .offset = 0x16d } + .offset = 0x16d, .size = 8 } } }; @@ -768,6 +982,9 @@ static const struct scarlett2_config_set scarlett2_config_set_clarett = { [SCARLETT2_CONFIG_STANDALONE_SWITCH] = { .offset = 0x8d, .size = 8, .activate = 6 }, + + [SCARLETT2_CONFIG_SPDIF_MODE] = { + .offset = 0x9e, .size = 8, .activate = 4 }, } }; @@ -895,6 +1112,23 @@ struct scarlett2_device_info { */ u8 air_option; + /* the number of analogue inputs with DSP control */ + u8 dsp_input_count; + + /* number of pre-compressor filters */ + u8 precomp_flt_count; + + /* number of parametric EQ filters */ + u8 peq_flt_count; + + /* number of PEQ filters plus unused slots */ + u8 peq_flt_total_count; + + /* the number of analogue inputs with a software switchable + * mute control + */ + u8 mute_input_count; + /* the number of phantom (48V) software switchable controls */ u8 phantom_count; @@ -907,6 +1141,9 @@ struct scarlett2_device_info { /* the number of inputs with software-controllable gain */ u8 gain_input_count; + /* the number of inputs with safe mode */ + u8 safe_input_count; + /* the number of direct monitor options * (0 = none, 1 = mono only, 2 = mono/stereo) */ @@ -915,6 +1152,14 @@ struct scarlett2_device_info { /* the number of DSP channels */ u8 dsp_count; + /* has a Bluetooth module with volume control */ + u8 has_bluetooth; + + /* S/PDIF Source/Digital I/O mode control */ + const char * const spdif_mode_control_name; + const u8 *spdif_mode_values; + const char * const *spdif_mode_texts; + /* remap analogue outputs; 18i8 Gen 3 has "line 3/4" connected * internally to the analogue 7/8 outputs */ @@ -942,7 +1187,9 @@ struct scarlett2_device_info { struct scarlett2_data { struct usb_mixer_interface *mixer; struct mutex usb_mutex; /* prevent sending concurrent USB requests */ + struct completion cmd_done; struct mutex data_mutex; /* lock access to this data */ + u8 running; u8 hwdep_in_use; u8 selected_flash_segment_id; u8 flash_write_state; @@ -960,6 +1207,7 @@ struct scarlett2_data { u8 num_mix_out; u8 num_line_out; u8 num_monitor_mix_ctls; + u8 num_autogain_status_texts; u32 firmware_version; u8 flash_segment_nums[SCARLETT2_SEGMENT_ID_COUNT]; u8 flash_segment_blocks[SCARLETT2_SEGMENT_ID_COUNT]; @@ -970,6 +1218,8 @@ struct scarlett2_data { u8 input_level_updated; u8 input_pad_updated; u8 input_air_updated; + u8 input_dsp_updated; + u8 input_mute_updated; u8 input_phantom_updated; u8 input_select_updated; u8 input_gain_updated; @@ -982,6 +1232,7 @@ struct scarlett2_data { u8 mix_updated; u8 speaker_switching_switched; u8 power_status_updated; + u8 bluetooth_updated; u8 sync; u8 master_vol; u8 headphone_vol; @@ -992,6 +1243,13 @@ struct scarlett2_data { u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX]; u8 dim_mute[SCARLETT2_DIM_MUTE_COUNT]; u8 air_switch[SCARLETT2_AIR_SWITCH_MAX]; + u8 dsp_switch[SCARLETT2_DSP_SWITCH_MAX]; + s32 compressor_values[SCARLETT2_COMPRESSOR_CTLS_MAX]; + s32 precomp_flt_values[SCARLETT2_PRECOMP_FLT_VALUES_MAX]; + s32 peq_flt_values[SCARLETT2_PEQ_FLT_VALUES_MAX]; + u8 precomp_flt_switch[SCARLETT2_DSP_SWITCH_MAX]; + u8 peq_flt_switch[SCARLETT2_DSP_SWITCH_MAX]; + u8 input_mute_switch[SCARLETT2_INPUT_MUTE_SWITCH_MAX]; u8 phantom_switch[SCARLETT2_PHANTOM_SWITCH_MAX]; u8 phantom_persistence; u8 input_select_switch; @@ -999,6 +1257,7 @@ struct scarlett2_data { u8 gain[SCARLETT2_INPUT_GAIN_MAX]; u8 autogain_switch[SCARLETT2_INPUT_GAIN_MAX]; u8 autogain_status[SCARLETT2_INPUT_GAIN_MAX]; + s8 ag_targets[SCARLETT2_AG_TARGET_COUNT]; u8 safe_switch[SCARLETT2_INPUT_GAIN_MAX]; u8 pcm_input_switch; u8 direct_monitor_switch; @@ -1008,6 +1267,8 @@ struct scarlett2_data { u8 msd_switch; u8 standalone_switch; u8 power_status; + u8 bluetooth_volume; + u8 spdif_mode; u8 meter_level_map[SCARLETT2_MAX_METERS]; struct snd_kcontrol *sync_ctl; struct snd_kcontrol *master_vol_ctl; @@ -1019,20 +1280,29 @@ struct scarlett2_data { struct snd_kcontrol *level_ctls[SCARLETT2_LEVEL_SWITCH_MAX]; struct snd_kcontrol *pad_ctls[SCARLETT2_PAD_SWITCH_MAX]; struct snd_kcontrol *air_ctls[SCARLETT2_AIR_SWITCH_MAX]; + struct snd_kcontrol *dsp_ctls[SCARLETT2_DSP_SWITCH_MAX]; + struct snd_kcontrol *input_mute_ctls[SCARLETT2_INPUT_MUTE_SWITCH_MAX]; struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX]; struct snd_kcontrol *input_select_ctl; struct snd_kcontrol *input_link_ctls[SCARLETT2_INPUT_GAIN_MAX / 2]; struct snd_kcontrol *input_gain_ctls[SCARLETT2_INPUT_GAIN_MAX]; struct snd_kcontrol *autogain_ctls[SCARLETT2_INPUT_GAIN_MAX]; struct snd_kcontrol *autogain_status_ctls[SCARLETT2_INPUT_GAIN_MAX]; + struct snd_kcontrol *ag_target_ctls[SCARLETT2_AG_TARGET_COUNT]; struct snd_kcontrol *safe_ctls[SCARLETT2_INPUT_GAIN_MAX]; struct snd_kcontrol *pcm_input_switch_ctl; struct snd_kcontrol *mux_ctls[SCARLETT2_MUX_MAX]; struct snd_kcontrol *mix_ctls[SCARLETT2_MIX_MAX]; + struct snd_kcontrol *compressor_ctls[SCARLETT2_COMPRESSOR_CTLS_MAX]; + struct snd_kcontrol *precomp_flt_ctls[SCARLETT2_PRECOMP_FLT_CTLS_MAX]; + struct snd_kcontrol *peq_flt_ctls[SCARLETT2_PEQ_FLT_CTLS_MAX]; + struct snd_kcontrol *precomp_flt_switch_ctls[SCARLETT2_DSP_SWITCH_MAX]; + struct snd_kcontrol *peq_flt_switch_ctls[SCARLETT2_DSP_SWITCH_MAX]; struct snd_kcontrol *direct_monitor_ctl; struct snd_kcontrol *speaker_switching_ctl; struct snd_kcontrol *talkback_ctl; struct snd_kcontrol *power_status_ctl; + struct snd_kcontrol *bluetooth_volume_ctl; u8 mux[SCARLETT2_MUX_MAX]; u8 mix[SCARLETT2_MIX_MAX]; u8 monitor_mix[SCARLETT2_MONITOR_MIX_MAX]; @@ -1326,6 +1596,14 @@ static const struct scarlett2_device_info s8i6_gen3_info = { } }; +static const u8 scarlett2_spdif_s18i8_gen3_values[] = { 0, 2, 0xff }; + +static const char * const scarlett2_spdif_s18i8_gen3_texts[] = { + "RCA", + "Optical", + NULL +}; + static const struct scarlett2_device_info s18i8_gen3_info = { .config_set = &scarlett2_config_set_gen3c, .has_speaker_switching = 1, @@ -1335,6 +1613,10 @@ static const struct scarlett2_device_info s18i8_gen3_info = { .phantom_count = 2, .inputs_per_phantom = 2, + .spdif_mode_control_name = "S/PDIF Mode Capture Enum", + .spdif_mode_values = scarlett2_spdif_s18i8_gen3_values, + .spdif_mode_texts = scarlett2_spdif_s18i8_gen3_texts, + .line_out_remap_enable = 1, .line_out_remap = { 0, 1, 6, 7, 2, 3, 4, 5 }, .line_out_unmap = { 0, 1, 4, 5, 6, 7, 2, 3 }, @@ -1405,6 +1687,15 @@ static const struct scarlett2_device_info s18i8_gen3_info = { } }; +static const u8 scarlett2_spdif_s18i20_gen3_values[] = { 0, 6, 1, 0xff }; + +static const char * const scarlett2_spdif_s18i20_gen3_texts[] = { + "S/PDIF RCA", + "S/PDIF Optical", + "Dual ADAT", + NULL +}; + static const struct scarlett2_device_info s18i20_gen3_info = { .config_set = &scarlett2_config_set_gen3c, .has_speaker_switching = 1, @@ -1415,6 +1706,10 @@ static const struct scarlett2_device_info s18i20_gen3_info = { .phantom_count = 2, .inputs_per_phantom = 4, + .spdif_mode_control_name = "Digital I/O Mode Capture Enum", + .spdif_mode_values = scarlett2_spdif_s18i20_gen3_values, + .spdif_mode_texts = scarlett2_spdif_s18i20_gen3_texts, + .line_out_descrs = { "Monitor 1 L", "Monitor 1 R", @@ -1475,6 +1770,91 @@ static const struct scarlett2_device_info s18i20_gen3_info = { } }; +static const struct scarlett2_device_info vocaster_one_info = { + .config_set = &scarlett2_config_set_vocaster, + .min_firmware_version = 1769, + + .phantom_count = 1, + .inputs_per_phantom = 1, + .dsp_count = 1, + .dsp_input_count = 1, + .precomp_flt_count = 2, + .peq_flt_count = 3, + .peq_flt_total_count = 4, + .mute_input_count = 1, + .gain_input_count = 1, + + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 2, 4 }, + [SCARLETT2_PORT_TYPE_MIX] = { 9, 9 }, + [SCARLETT2_PORT_TYPE_PCM] = { 4, 10 }, + }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_MIX, 8, 1 }, + { SCARLETT2_PORT_TYPE_PCM, 5, 5 }, + { SCARLETT2_PORT_TYPE_MIX, 6, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 0, 5 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 6 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 4 }, + { 0, 0, 0 }, + } }, + + .meter_map = { + { 12, 1 }, + { 18, 5 }, + { 10, 2 }, + { 13, 5 }, + { 4, 6 }, + { 0, 4 }, + { 0, 0 } + } +}; + +static const struct scarlett2_device_info vocaster_two_info = { + .config_set = &scarlett2_config_set_vocaster, + .min_firmware_version = 1769, + + .phantom_count = 2, + .inputs_per_phantom = 1, + .dsp_count = 2, + .dsp_input_count = 2, + .precomp_flt_count = 2, + .peq_flt_count = 3, + .peq_flt_total_count = 4, + .mute_input_count = 2, + .gain_input_count = 2, + .has_bluetooth = 1, + + .port_count = { + [SCARLETT2_PORT_TYPE_NONE] = { 1, 0 }, + [SCARLETT2_PORT_TYPE_ANALOGUE] = { 6, 6 }, + [SCARLETT2_PORT_TYPE_MIX] = { 12, 14 }, + [SCARLETT2_PORT_TYPE_PCM] = { 4, 14 }, + }, + + .mux_assignment = { { + { SCARLETT2_PORT_TYPE_MIX, 12, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 6, 8 }, + { SCARLETT2_PORT_TYPE_MIX, 10, 2 }, + { SCARLETT2_PORT_TYPE_PCM, 0, 6 }, + { SCARLETT2_PORT_TYPE_MIX, 0, 10 }, + { SCARLETT2_PORT_TYPE_ANALOGUE, 0, 6 }, + { 0, 0, 0 }, + } }, + + .meter_map = { + { 18, 2 }, + { 26, 8 }, + { 16, 2 }, + { 20, 6 }, + { 6, 10 }, + { 0, 6 }, + { 0, 0 } + } +}; + static const struct scarlett2_device_info solo_gen4_info = { .config_set = &scarlett2_config_set_gen4_solo, .min_firmware_version = 2115, @@ -1539,6 +1919,7 @@ static const struct scarlett2_device_info s2i2_gen4_info = { .phantom_count = 1, .inputs_per_phantom = 2, .gain_input_count = 2, + .safe_input_count = 2, .direct_monitor = 2, .dsp_count = 2, @@ -1592,6 +1973,7 @@ static const struct scarlett2_device_info s4i4_gen4_info = { .phantom_count = 2, .inputs_per_phantom = 1, .gain_input_count = 2, + .safe_input_count = 2, .dsp_count = 2, .port_count = { @@ -1676,11 +2058,24 @@ static const struct scarlett2_device_info clarett_2pre_info = { } }; +static const u8 scarlett2_spdif_clarett_values[] = { 0, 1, 2, 0xff }; + +static const char * const scarlett2_spdif_clarett_texts[] = { + "None", + "Optical", + "RCA", + NULL +}; + static const struct scarlett2_device_info clarett_4pre_info = { .config_set = &scarlett2_config_set_clarett, .level_input_count = 2, .air_input_count = 4, + .spdif_mode_control_name = "S/PDIF Source Capture Enum", + .spdif_mode_values = scarlett2_spdif_clarett_values, + .spdif_mode_texts = scarlett2_spdif_clarett_texts, + .line_out_descrs = { "Monitor L", "Monitor R", @@ -1733,6 +2128,10 @@ static const struct scarlett2_device_info clarett_8pre_info = { .level_input_count = 2, .air_input_count = 8, + .spdif_mode_control_name = "S/PDIF Source Capture Enum", + .spdif_mode_values = scarlett2_spdif_clarett_values, + .spdif_mode_texts = scarlett2_spdif_clarett_texts, + .line_out_descrs = { "Monitor L", "Monitor R", @@ -1806,6 +2205,10 @@ static const struct scarlett2_device_entry scarlett2_devices[] = { { USB_ID(0x1235, 0x8214), &s18i8_gen3_info, "Scarlett Gen 3" }, { USB_ID(0x1235, 0x8215), &s18i20_gen3_info, "Scarlett Gen 3" }, + /* Supported Vocaster devices */ + { USB_ID(0x1235, 0x8216), &vocaster_one_info, "Vocaster" }, + { USB_ID(0x1235, 0x8217), &vocaster_two_info, "Vocaster" }, + /* Supported Gen 4 devices */ { USB_ID(0x1235, 0x8218), &solo_gen4_info, "Scarlett Gen 4" }, { USB_ID(0x1235, 0x8219), &s2i2_gen4_info, "Scarlett Gen 4" }, @@ -1856,6 +2259,7 @@ static int scarlett2_get_port_start_num( #define SCARLETT2_USB_ERASE_SEGMENT 0x00004002 #define SCARLETT2_USB_GET_ERASE 0x00004003 #define SCARLETT2_USB_WRITE_SEGMENT 0x00004004 +#define SCARLETT2_USB_READ_SEGMENT 0x00004005 #define SCARLETT2_USB_GET_SYNC 0x00006004 #define SCARLETT2_USB_GET_DATA 0x00800000 #define SCARLETT2_USB_SET_DATA 0x00800001 @@ -1866,7 +2270,7 @@ static int scarlett2_get_port_start_num( #define SCARLETT2_USB_METER_LEVELS_GET_MAGIC 1 #define SCARLETT2_FLASH_BLOCK_SIZE 4096 -#define SCARLETT2_FLASH_WRITE_MAX 1024 +#define SCARLETT2_FLASH_RW_MAX 1024 #define SCARLETT2_SEGMENT_NUM_MIN 1 #define SCARLETT2_SEGMENT_NUM_MAX 4 @@ -1960,6 +2364,17 @@ static int scarlett2_usb( goto unlock; } + if (!wait_for_completion_timeout(&private->cmd_done, + msecs_to_jiffies(1000))) { + usb_audio_err( + mixer->chip, + "%s USB request timed out, cmd %x\n", + private->series_name, cmd); + + err = -ETIMEDOUT; + goto unlock; + } + /* send a second message to get the response */ err = scarlett2_usb_rx(dev, private->bInterfaceNumber, @@ -2065,7 +2480,7 @@ static int scarlett2_usb_get_config( if (!config_item->offset) return -EFAULT; - /* Gen 4 style parameters are always 1 byte */ + /* Writes to the parameter buffer are always 1 byte */ size = config_item->size ? config_item->size : 8; /* For byte-sized parameters, retrieve directly into buf */ @@ -2079,6 +2494,11 @@ static int scarlett2_usb_get_config( for (i = 0; i < count; i++, buf_16++) *buf_16 = le16_to_cpu(*(__le16 *)buf_16); + } else if (size == 4) { + u32 *buf_32 = buf; + + for (i = 0; i < count; i++, buf_32++) + *buf_32 = le32_to_cpu(*(__le32 *)buf_32); } return 0; } @@ -2118,6 +2538,54 @@ static int scarlett2_usb_set_data( &req, sizeof(u32) * 2 + size, NULL, 0); } +/* Send a SCARLETT2_USB_SET_DATA command with multiple values. + * offset: location in the device's data space + * size: size in bytes of each value (1, 2, 4) + * count: number of values + */ +static int scarlett2_usb_set_data_buf( + struct usb_mixer_interface *mixer, + int offset, int size, int count, void *buf) +{ + struct scarlett2_data *private = mixer->private_data; + int bytes = size * count; + struct { + __le32 offset; + __le32 size; + u8 data[]; + } __packed *req; + int err; + int buf_size = struct_size(req, data, bytes); + + req = kmalloc(buf_size, GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->offset = cpu_to_le32(offset); + req->size = cpu_to_le32(bytes); + if (size == 1) { + memcpy(req->data, buf, count); + } else if (size == 2) { + u16 *buf_16 = buf; + int i; + + for (i = 0; i < count; i++) + ((__le16 *)req->data)[i] = cpu_to_le16(buf_16[i]); + } else { + u32 *buf_32 = buf; + int i; + + for (i = 0; i < count; i++) + ((__le32 *)req->data)[i] = cpu_to_le32(buf_32[i]); + } + + err = scarlett2_usb(private->mixer, SCARLETT2_USB_SET_DATA, + req, buf_size, NULL, 0); + + kfree(req); + return err; +} + /* Send a SCARLETT2_USB_DATA_CMD command. * Configuration changes require activation with this after they have * been uploaded by a previous SCARLETT2_USB_SET_DATA. @@ -2152,34 +2620,30 @@ static int scarlett2_usb_set_config( if (!config_item->offset) return -EFAULT; - /* Gen 4 style writes are selected with size = 0; - * these are only byte-sized values written through a shared - * location, different to the read address - */ - if (!config_item->size) { - if (!config_set->gen4_write_addr) + /* Write via the parameter buffer? */ + if (config_item->pbuf) { + if (!config_set->param_buf_addr) return -EFAULT; - /* Place index in gen4_write_addr + 1 */ + /* Place index in param_buf_addr + 1 */ err = scarlett2_usb_set_data( - mixer, config_set->gen4_write_addr + 1, 1, index); + mixer, config_set->param_buf_addr + 1, 1, index); if (err < 0) return err; - /* Place value in gen4_write_addr */ + /* Place value in param_buf_addr */ err = scarlett2_usb_set_data( - mixer, config_set->gen4_write_addr, 1, value); + mixer, config_set->param_buf_addr, 1, value); if (err < 0) return err; - /* Request the interface do the write */ + /* Activate the write through the parameter buffer */ return scarlett2_usb_activate_config( mixer, config_item->activate); } - /* Not-Gen 4 style needs NVRAM save, supports - * bit-modification, and writing is done to the same place - * that the value can be read from + /* Direct writes (not via the parameter buffer) need NVRAM + * save and support bit-modification */ /* Cancel any pending NVRAM save */ @@ -2213,7 +2677,7 @@ static int scarlett2_usb_set_config( value = tmp; } - /* Send the configuration parameter data */ + /* Write the new value */ err = scarlett2_usb_set_data(mixer, offset, size, value); if (err < 0) return err; @@ -2223,8 +2687,10 @@ static int scarlett2_usb_set_config( if (err < 0) return err; - /* Gen 2 style writes to Gen 4 devices don't need saving */ - if (config_set->gen4_write_addr) + /* Interfaces with parameter buffer writes don't need a + * separate save step + */ + if (config_set->param_buf_addr) return 0; /* Schedule the change to be written to NVRAM */ @@ -2234,6 +2700,47 @@ static int scarlett2_usb_set_config( return 0; } +/* Send USB messages to set a SCARLETT2_CONFIG_* parameter with + * multiple values + */ +static int scarlett2_usb_set_config_buf( + struct usb_mixer_interface *mixer, + int config_item_num, int index, int count, void *buf) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_config_set *config_set = private->config_set; + const struct scarlett2_config *config_item = + &config_set->items[config_item_num]; + int offset, size; + int err; + + /* Check that the configuration item is present in the + * configuration set used by this device + */ + if (!config_item->offset) + return -EFAULT; + + /* 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; + + /* Bit updates not supported */ + } else { + return -EFAULT; + } + + /* Write the new values */ + err = scarlett2_usb_set_data_buf(mixer, offset, size, count, buf); + if (err < 0) + return err; + + /* Activate the change */ + return scarlett2_usb_activate_config(mixer, config_item->activate); +} + /* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */ static void scarlett2_config_save(struct usb_mixer_interface *mixer) { @@ -2862,6 +3369,7 @@ static int scarlett2_update_autogain(struct usb_mixer_interface *mixer) const struct scarlett2_device_info *info = private->info; int err, i; u8 raw_autogain_status[SCARLETT2_INPUT_GAIN_MAX]; + s8 ag_target_values[SCARLETT2_AG_TARGET_COUNT]; private->autogain_updated = 0; @@ -2893,12 +3401,27 @@ static int scarlett2_update_autogain(struct usb_mixer_interface *mixer) if (private->autogain_switch[i]) private->autogain_status[i] = 0; else if (raw_autogain_status[i] < - ARRAY_SIZE(scarlett2_autogain_status_texts) - 1) + private->num_autogain_status_texts - 1) private->autogain_status[i] = raw_autogain_status[i] + 1; else private->autogain_status[i] = - ARRAY_SIZE(scarlett2_autogain_status_texts) - 1; + private->num_autogain_status_texts - 1; + + + for (int i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + if (scarlett2_has_config_item(private, + scarlett2_ag_target_configs[i])) { + err = scarlett2_usb_get_config( + mixer, scarlett2_ag_target_configs[i], + 1, &ag_target_values[i]); + if (err < 0) + return err; + } + + /* convert from negative dBFS as used by the device */ + for (int i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + private->ag_targets[i] = -ag_target_values[i]; return 0; } @@ -2911,19 +3434,34 @@ static void scarlett2_autogain_update_access(struct usb_mixer_interface *mixer) int val = !scarlett2_autogain_is_running(private); int i; - scarlett2_set_ctl_access(private->input_select_ctl, val); - for (i = 0; i < info->gain_input_count / 2; i++) - scarlett2_set_ctl_access(private->input_link_ctls[i], val); - for (i = 0; i < info->gain_input_count; i++) { + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_SELECT_SWITCH)) + scarlett2_set_ctl_access(private->input_select_ctl, val); + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) + for (i = 0; i < info->gain_input_count / 2; i++) + scarlett2_set_ctl_access(private->input_link_ctls[i], + val); + for (i = 0; i < info->gain_input_count; i++) scarlett2_set_ctl_access(private->input_gain_ctls[i], val); + for (i = 0; i < info->safe_input_count; i++) scarlett2_set_ctl_access(private->safe_ctls[i], val); - } for (i = 0; i < info->level_input_count; i++) scarlett2_set_ctl_access(private->level_ctls[i], val); for (i = 0; i < info->air_input_count; i++) scarlett2_set_ctl_access(private->air_ctls[i], val); + for (i = 0; i < info->mute_input_count; i++) + scarlett2_set_ctl_access(private->input_mute_ctls[i], val); for (i = 0; i < info->phantom_count; i++) scarlett2_set_ctl_access(private->phantom_ctls[i], val); + for (i = 0; i < info->dsp_input_count; i++) + scarlett2_set_ctl_access(private->dsp_ctls[i], val); + + for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + if (scarlett2_has_config_item(private, + scarlett2_ag_target_configs[i])) + scarlett2_set_ctl_access( + private->ag_target_ctls[i], val); } /* Notify of access mode change for all controls read-only while @@ -2936,26 +3474,42 @@ static void scarlett2_autogain_notify_access(struct usb_mixer_interface *mixer) const struct scarlett2_device_info *info = private->info; int i; - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, - &private->input_select_ctl->id); - for (i = 0; i < info->gain_input_count / 2; i++) + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_SELECT_SWITCH)) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, - &private->input_link_ctls[i]->id); - for (i = 0; i < info->gain_input_count; i++) { + &private->input_select_ctl->id); + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) + for (i = 0; i < info->gain_input_count / 2; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->input_link_ctls[i]->id); + for (i = 0; i < info->gain_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &private->input_gain_ctls[i]->id); + for (i = 0; i < info->safe_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &private->safe_ctls[i]->id); - } for (i = 0; i < info->level_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &private->level_ctls[i]->id); for (i = 0; i < info->air_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &private->air_ctls[i]->id); + for (i = 0; i < info->dsp_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->dsp_ctls[i]->id); + for (i = 0; i < info->mute_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->input_mute_ctls[i]->id); for (i = 0; i < info->phantom_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &private->phantom_ctls[i]->id); + + for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + if (scarlett2_has_config_item(private, + scarlett2_ag_target_configs[i])) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->ag_target_ctls[i]->id); } /* Call scarlett2_update_autogain() and @@ -3124,10 +3678,13 @@ unlock: static int scarlett2_autogain_status_ctl_info( struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + return snd_ctl_enum_info( uinfo, 1, - ARRAY_SIZE(scarlett2_autogain_status_texts), - scarlett2_autogain_status_texts); + private->num_autogain_status_texts, + private->config_set->autogain_status_texts); } static const struct snd_kcontrol_new scarlett2_autogain_switch_ctl = { @@ -3146,6 +3703,122 @@ static const struct snd_kcontrol_new scarlett2_autogain_status_ctl = { .get = scarlett2_autogain_status_ctl_get, }; +/*** Autogain Target Controls ***/ + +static int scarlett2_ag_target_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + 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 err; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_autogain_updated(mixer); + if (err < 0) + goto unlock; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = SCARLETT2_AG_TARGET_MIN; + uinfo->value.integer.max = 0; + uinfo->value.integer.step = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_ag_target_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 err = 0; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + if (private->autogain_updated) { + err = scarlett2_update_autogain(mixer); + if (err < 0) + goto unlock; + } + + ucontrol->value.integer.value[0] = private->ag_targets[elem->control]; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_ag_target_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; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_put_during_autogain(mixer); + if (err < 0) + goto unlock; + + oval = private->ag_targets[index]; + val = clamp(ucontrol->value.integer.value[0], + (long)SCARLETT2_AG_TARGET_MIN, 0L); + + if (oval == val) + goto unlock; + + private->ag_targets[index] = val; + + /* Send new value to the device */ + err = scarlett2_usb_set_config( + mixer, scarlett2_ag_target_configs[index], 1, -val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const DECLARE_TLV_DB_MINMAX( + db_scale_ag_target, SCARLETT2_AG_TARGET_MIN * 100, 0 +); + +static const struct snd_kcontrol_new scarlett2_ag_target_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .name = "", + .info = scarlett2_ag_target_ctl_info, + .get = scarlett2_ag_target_ctl_get, + .put = scarlett2_ag_target_ctl_put, + .tlv = { .p = db_scale_ag_target } +}; + /*** Input Select Control ***/ static int scarlett2_update_input_select(struct usb_mixer_interface *mixer) @@ -3157,7 +3830,9 @@ static int scarlett2_update_input_select(struct usb_mixer_interface *mixer) private->input_select_updated = 0; - if (!link_count) + if (!scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_SELECT_SWITCH) || + !link_count) return 0; err = scarlett2_usb_get_config( @@ -3545,10 +4220,6 @@ unlock: return err; } -static const DECLARE_TLV_DB_MINMAX( - db_scale_scarlett2_gain, 0, SCARLETT2_MAX_GAIN_DB * 100 -); - static const struct snd_kcontrol_new scarlett2_input_gain_ctl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -3558,7 +4229,6 @@ static const struct snd_kcontrol_new scarlett2_input_gain_ctl = { .get = scarlett2_input_gain_ctl_get, .put = scarlett2_input_gain_ctl_put, .private_value = 0, /* max value */ - .tlv = { .p = db_scale_scarlett2_gain } }; /*** Safe Controls ***/ @@ -3570,12 +4240,12 @@ static int scarlett2_update_input_safe(struct usb_mixer_interface *mixer) private->input_safe_updated = 0; - if (!info->gain_input_count) + if (!info->safe_input_count) return 0; return scarlett2_usb_get_config( mixer, SCARLETT2_CONFIG_SAFE_SWITCH, - info->gain_input_count, private->safe_switch); + info->safe_input_count, private->safe_switch); } static int scarlett2_safe_ctl_get(struct snd_kcontrol *kctl, @@ -4567,6 +5237,670 @@ static const struct snd_kcontrol_new scarlett2_air_ctl[2] = { } }; +/*** DSP Switch Control ***/ + +static int scarlett2_update_input_dsp(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + private->input_dsp_updated = 0; + + if (!info->dsp_input_count) + return 0; + + return scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_DSP_SWITCH, + info->dsp_input_count, private->dsp_switch); +} + +static int scarlett2_dsp_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 err = 0; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + if (private->input_dsp_updated) { + err = scarlett2_update_input_dsp(mixer); + if (err < 0) + goto unlock; + } + ucontrol->value.integer.value[0] = private->dsp_switch[elem->control]; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_dsp_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; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_put_during_autogain(mixer); + if (err < 0) + goto unlock; + + oval = private->dsp_switch[index]; + val = ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->dsp_switch[index] = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_DSP_SWITCH, + index, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_dsp_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_autogain_disables_ctl_info, + .get = scarlett2_dsp_ctl_get, + .put = scarlett2_dsp_ctl_put, +}; + +/*** DSP Compressor Parameter Controls ***/ + +static int scarlett2_update_compressor_values(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int err, i, j; + + if (!info->dsp_input_count) + return 0; + + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_COMPRESSOR_PARAMS, + SCARLETT2_COMPRESSOR_PARAM_COUNT * info->dsp_input_count, + private->compressor_values); + + if (err < 0) + return err; + + for (i = 0; i < SCARLETT2_COMPRESSOR_PARAM_COUNT; i++) { + const struct compressor_param *param = &compressor_params[i]; + + for (j = 0; j < info->dsp_input_count; j++) { + int idx = i + j * SCARLETT2_COMPRESSOR_PARAM_COUNT; + int val = private->compressor_values[idx]; + + val >>= param->scale_bits; + val = clamp(val, param->min, param->max); + private->compressor_values[idx] = val; + } + } + + return 0; +} + +static int scarlett2_compressor_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->compressor_values[elem->control]; + return 0; +} + +static int scarlett2_compressor_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 channel = index / SCARLETT2_COMPRESSOR_PARAM_COUNT; + int param_index = index % SCARLETT2_COMPRESSOR_PARAM_COUNT; + int oval, val, err; + s32 scaled_val; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_put_during_autogain(mixer); + if (err < 0) + goto unlock; + + oval = private->compressor_values[index]; + val = ucontrol->value.integer.value[0]; + if (oval == val) + goto unlock; + + private->compressor_values[index] = val; + + const struct compressor_param *param = &compressor_params[param_index]; + + scaled_val = val << param->scale_bits; + + /* Send change to the device */ + + /* The channel needs to be put in the parameter buffer index + * field (param_buf_addr + 1); the value field isn't used in + * this case. + */ + err = scarlett2_usb_set_data( + mixer, private->config_set->param_buf_addr + 1, 1, channel); + if (err < 0) + goto unlock; + + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_COMPRESSOR_PARAMS, index, scaled_val); + if (err < 0) + goto unlock; + + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_compressor_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + int control = elem->control % SCARLETT2_COMPRESSOR_PARAM_COUNT; + + uinfo->type = compressor_params[control].type; + uinfo->count = 1; + uinfo->value.integer.min = compressor_params[control].min; + uinfo->value.integer.max = compressor_params[control].max; + uinfo->value.integer.step = 1; + return 0; +} + +static const struct snd_kcontrol_new scarlett2_compressor_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .name = "", + .info = scarlett2_compressor_ctl_info, + .get = scarlett2_compressor_ctl_get, + .put = scarlett2_compressor_ctl_put, +}; + +/*** DSP Pre-Compressor and PEQ Filter Controls ***/ + +static int scarlett2_precomp_flt_switch_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->precomp_flt_switch[elem->control]; + + return 0; +} + +static int scarlett2_peq_flt_switch_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->peq_flt_switch[elem->control]; + + return 0; +} + +static int scarlett2_precomp_flt_switch_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); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + oval = private->precomp_flt_switch[elem->control]; + val = ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->precomp_flt_switch[elem->control] = val; + + /* Send change to the device */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_PRECOMP_FLT_SWITCH, + elem->control, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_peq_flt_switch_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); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + oval = private->peq_flt_switch[elem->control]; + val = ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->peq_flt_switch[elem->control] = val; + + /* Send change to the device */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_PEQ_FLT_SWITCH, + elem->control, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_precomp_flt_switch_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_precomp_flt_switch_ctl_get, + .put = scarlett2_precomp_flt_switch_ctl_put, +}; + +static const struct snd_kcontrol_new scarlett2_peq_flt_switch_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .name = "", + .info = snd_ctl_boolean_mono_info, + .get = scarlett2_peq_flt_switch_ctl_get, + .put = scarlett2_peq_flt_switch_ctl_put, +}; + +static int scarlett2_update_filter_values(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int err, i, j, k, src_idx, dst_idx; + s32 peq_flt_values[SCARLETT2_DSP_SWITCH_MAX * + SCARLETT2_PEQ_FLT_SLOTS_MAX * + SCARLETT2_BIQUAD_COEFFS]; + + if (!info->dsp_input_count) + return 0; + + /* Get filter switch values */ + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PRECOMP_FLT_SWITCH, + info->dsp_input_count, private->precomp_flt_switch); + if (err < 0) + return err; + + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PEQ_FLT_SWITCH, + info->dsp_input_count * info->peq_flt_count, + private->peq_flt_switch); + if (err < 0) + return err; + + /* Get pre-compressor filter values directly */ + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PRECOMP_FLT_PARAMS, + info->dsp_input_count * + info->precomp_flt_count * + SCARLETT2_BIQUAD_COEFFS, + private->precomp_flt_values); + + if (err < 0) + return err; + + /* PEQ filter values need to be copied via buffer because of + * padding after peq_flt_count up to peq_flt_total_count + */ + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_PEQ_FLT_PARAMS, + info->dsp_input_count * + info->peq_flt_total_count * + SCARLETT2_BIQUAD_COEFFS, + peq_flt_values); + + for (i = 0, dst_idx = 0; i < info->dsp_input_count; i++) { + src_idx = i * + info->peq_flt_total_count * + SCARLETT2_BIQUAD_COEFFS; + for (j = 0; j < info->peq_flt_count; j++) + for (k = 0; + k < SCARLETT2_BIQUAD_COEFFS; + k++, src_idx++, dst_idx++) + private->peq_flt_values[dst_idx] = + peq_flt_values[src_idx]; + } + + return 0; +} + +static int scarlett2_precomp_flt_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; + int i, idx; + + for (i = 0, idx = elem->control * SCARLETT2_BIQUAD_COEFFS; + i < SCARLETT2_BIQUAD_COEFFS; + i++, idx++) + ucontrol->value.integer.value[i] = + private->precomp_flt_values[idx]; + + return 0; +} + +static int scarlett2_peq_flt_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; + int i, idx; + + for (i = 0, idx = elem->control * SCARLETT2_BIQUAD_COEFFS; + i < SCARLETT2_BIQUAD_COEFFS; + i++, idx++) + ucontrol->value.integer.value[i] = + private->peq_flt_values[idx]; + + return 0; +} + +static int scarlett2_precomp_flt_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 * SCARLETT2_BIQUAD_COEFFS; + int i, oval, val, err; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_put_during_autogain(mixer); + if (err < 0) + goto unlock; + + /* Check if any of the values have changed; if not, return */ + for (i = 0; i < SCARLETT2_BIQUAD_COEFFS; i++) { + oval = private->precomp_flt_values[index + i]; + val = ucontrol->value.integer.value[i]; + if (oval != val) + break; + } + + if (i == SCARLETT2_BIQUAD_COEFFS) + goto unlock; + + /* Update the values */ + for (i = 0; i < SCARLETT2_BIQUAD_COEFFS; i++) + private->precomp_flt_values[index + i] = + ucontrol->value.integer.value[i]; + + /* Send change to the device */ + err = scarlett2_usb_set_data( + mixer, private->config_set->param_buf_addr, 1, index); + if (err < 0) + goto unlock; + + err = scarlett2_usb_set_config_buf( + mixer, SCARLETT2_CONFIG_PRECOMP_FLT_PARAMS, + index, SCARLETT2_BIQUAD_COEFFS, + &private->precomp_flt_values[index]); + + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_peq_flt_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 struct scarlett2_device_info *info = private->info; + + int src_index = elem->control * SCARLETT2_BIQUAD_COEFFS; + int dst_index = ( + elem->control / + info->peq_flt_count * + info->peq_flt_total_count + + elem->control % info->peq_flt_count + ) * SCARLETT2_BIQUAD_COEFFS; + int i, oval, val, err; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_put_during_autogain(mixer); + if (err < 0) + goto unlock; + + /* Check if any of the values have changed; if not, return */ + for (i = 0; i < SCARLETT2_BIQUAD_COEFFS; i++) { + oval = private->peq_flt_values[src_index + i]; + val = ucontrol->value.integer.value[i]; + if (oval != val) + break; + } + + if (i == SCARLETT2_BIQUAD_COEFFS) + goto unlock; + + /* Update the values */ + for (i = 0; i < SCARLETT2_BIQUAD_COEFFS; i++) + private->peq_flt_values[src_index + i] = + ucontrol->value.integer.value[i]; + + /* Send change to the device */ + err = scarlett2_usb_set_data( + mixer, private->config_set->param_buf_addr, 1, dst_index); + if (err < 0) + goto unlock; + + err = scarlett2_usb_set_config_buf( + mixer, SCARLETT2_CONFIG_PEQ_FLT_PARAMS, + dst_index, SCARLETT2_BIQUAD_COEFFS, + &private->peq_flt_values[src_index]); + + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_flt_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = SCARLETT2_BIQUAD_COEFFS; + uinfo->value.integer.min = INT_MIN; + uinfo->value.integer.max = INT_MAX; + uinfo->value.integer.step = 1; + return 0; +} + +static const struct snd_kcontrol_new scarlett2_precomp_flt_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .name = "", + .info = scarlett2_flt_ctl_info, + .get = scarlett2_precomp_flt_ctl_get, + .put = scarlett2_precomp_flt_ctl_put, +}; + +static const struct snd_kcontrol_new scarlett2_peq_flt_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_CARD, + .name = "", + .info = scarlett2_flt_ctl_info, + .get = scarlett2_peq_flt_ctl_get, + .put = scarlett2_peq_flt_ctl_put, +}; + +/*** Input Mute Switch Controls ***/ + +static int scarlett2_update_input_mute(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + + private->input_mute_updated = 0; + + if (!info->mute_input_count) + return 0; + + return scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_INPUT_MUTE_SWITCH, + info->mute_input_count, private->input_mute_switch); +} + +static int scarlett2_input_mute_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 err = 0; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + if (private->input_mute_updated) { + err = scarlett2_update_input_mute(mixer); + if (err < 0) + goto unlock; + } + ucontrol->value.integer.value[0] = + private->input_mute_switch[elem->control]; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static int scarlett2_input_mute_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct usb_mixer_interface *mixer = elem->head.mixer; + struct scarlett2_data *private = mixer->private_data; + + int index = elem->control; + int oval, val, err; + + mutex_lock(&private->data_mutex); + + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } + + err = scarlett2_check_put_during_autogain(mixer); + if (err < 0) + goto unlock; + + oval = private->input_mute_switch[index]; + val = ucontrol->value.integer.value[0]; + + if (oval == val) + goto unlock; + + private->input_mute_switch[index] = val; + + /* Send switch change to the device */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_INPUT_MUTE_SWITCH, + index, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; +} + +static const struct snd_kcontrol_new scarlett2_input_mute_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_autogain_disables_ctl_info, + .get = scarlett2_input_mute_ctl_get, + .put = scarlett2_input_mute_ctl_put, +}; + /*** Phantom Switch Controls ***/ static int scarlett2_update_input_phantom(struct usb_mixer_interface *mixer) @@ -5406,6 +6740,69 @@ static int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) /*** Create the analogue input controls ***/ +static int scarlett2_add_dsp_ctls(struct usb_mixer_interface *mixer, int i) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int j, err; + char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + const char *compr_fmt = "Line In %d Compressor %s"; + const char *flt_switch_fmt = "Line In %d %s Filter Enable"; + const char *flt_fmt = "Line In %d %s Coefficients %d"; + + /* Add compressor controls */ + for (j = 0; j < SCARLETT2_COMPRESSOR_PARAM_COUNT; j++) { + const struct compressor_param *param = &compressor_params[j]; + int idx = i * SCARLETT2_COMPRESSOR_PARAM_COUNT + j; + + scnprintf(s, sizeof(s), compr_fmt, i + 1, param->name); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_compressor_ctl, + i * SCARLETT2_COMPRESSOR_PARAM_COUNT + j, + 1, s, &private->compressor_ctls[idx]); + if (err < 0) + return err; + } + + /* Add filter enable controls */ + scnprintf(s, sizeof(s), flt_switch_fmt, i + 1, "Pre-Comp"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_precomp_flt_switch_ctl, + i, 1, s, &private->precomp_flt_switch_ctls[i]); + if (err < 0) + return err; + + scnprintf(s, sizeof(s), flt_switch_fmt, i + 1, "PEQ"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_peq_flt_switch_ctl, + i, 1, s, &private->peq_flt_switch_ctls[i]); + if (err < 0) + return err; + + /* Add filter coefficient controls */ + for (j = 0; j < info->precomp_flt_count; j++) { + scnprintf(s, sizeof(s), flt_fmt, i + 1, "Pre-Comp", j + 1); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_precomp_flt_ctl, + i * info->precomp_flt_count + j, + 1, s, &private->precomp_flt_switch_ctls[j]); + if (err < 0) + return err; + } + + for (j = 0; j < info->peq_flt_count; j++) { + scnprintf(s, sizeof(s), flt_fmt, i + 1, "PEQ", j + 1); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_peq_flt_ctl, + i * info->peq_flt_count + j, + 1, s, &private->peq_flt_switch_ctls[j]); + if (err < 0) + return err; + } + + return 0; +} + static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; @@ -5445,6 +6842,29 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) return err; } + /* Add input DSP controls */ + for (i = 0; i < info->dsp_input_count; i++) { + scnprintf(s, sizeof(s), fmt, i + 1, "DSP", "Switch"); + err = scarlett2_add_new_ctl(mixer, &scarlett2_dsp_ctl, + i, 1, s, &private->dsp_ctls[i]); + if (err < 0) + return err; + + err = scarlett2_add_dsp_ctls(mixer, i); + if (err < 0) + return err; + } + + /* Add input mute controls */ + for (i = 0; i < info->mute_input_count; i++) { + scnprintf(s, sizeof(s), fmt, i + 1, "Mute", "Switch"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_input_mute_ctl, + i, 1, s, &private->input_mute_ctls[i]); + if (err < 0) + return err; + } + /* Add input phantom controls */ if (info->inputs_per_phantom == 1) { for (i = 0; i < info->phantom_count; i++) { @@ -5481,58 +6901,81 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) return err; } - /* Add software-controllable input gain controls */ - if (info->gain_input_count) { + /* Add input select/link controls */ + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_SELECT_SWITCH)) { err = scarlett2_add_new_ctl( mixer, &scarlett2_input_select_ctl, 0, 1, "Input Select Capture Enum", &private->input_select_ctl); if (err < 0) return err; + } - for (i = 0; i < info->gain_input_count; i++) { - if (i % 2) { - scnprintf(s, sizeof(s), - "Line In %d-%d Link Capture Switch", - i, i + 1); - err = scarlett2_add_new_ctl( - mixer, &scarlett2_input_link_ctl, - i / 2, 1, s, - &private->input_link_ctls[i / 2]); - if (err < 0) - return err; - } - - scnprintf(s, sizeof(s), fmt, i + 1, - "Gain", "Volume"); + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) { + for (i = 0; i < info->gain_input_count / 2; i++) { + scnprintf(s, sizeof(s), + "Line In %d-%d Link Capture Switch", + (i * 2) + 1, (i * 2) + 2); err = scarlett2_add_new_ctl( - mixer, &scarlett2_input_gain_ctl, - i, 1, s, &private->input_gain_ctls[i]); + mixer, &scarlett2_input_link_ctl, + i, 1, s, &private->input_link_ctls[i]); if (err < 0) return err; + } + } - scnprintf(s, sizeof(s), fmt, i + 1, - "Autogain", "Switch"); - err = scarlett2_add_new_ctl( - mixer, &scarlett2_autogain_switch_ctl, - i, 1, s, &private->autogain_ctls[i]); - if (err < 0) - return err; + /* Add software-controllable input gain controls */ + for (i = 0; i < info->gain_input_count; i++) { + scnprintf(s, sizeof(s), fmt, i + 1, + "Gain", "Volume"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_input_gain_ctl, + i, 1, s, &private->input_gain_ctls[i]); + if (err < 0) + return err; + private->input_gain_ctls[i]->tlv.p = + private->config_set->input_gain_tlv; - scnprintf(s, sizeof(s), fmt, i + 1, - "Autogain Status", "Enum"); - err = scarlett2_add_new_ctl( - mixer, &scarlett2_autogain_status_ctl, - i, 1, s, &private->autogain_status_ctls[i]); + scnprintf(s, sizeof(s), fmt, i + 1, + "Autogain", "Switch"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_autogain_switch_ctl, + i, 1, s, &private->autogain_ctls[i]); + if (err < 0) + return err; + + scnprintf(s, sizeof(s), fmt, i + 1, + "Autogain Status", "Enum"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_autogain_status_ctl, + i, 1, s, &private->autogain_status_ctls[i]); + } + + /* Add autogain target controls */ + for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + if (scarlett2_has_config_item(private, + scarlett2_ag_target_configs[i])) { - scnprintf(s, sizeof(s), fmt, i + 1, - "Safe", "Switch"); + scnprintf(s, sizeof(s), "Autogain %s Target", + scarlett2_ag_target_names[i]); err = scarlett2_add_new_ctl( - mixer, &scarlett2_safe_ctl, - i, 1, s, &private->safe_ctls[i]); + mixer, &scarlett2_ag_target_ctl, + i, 1, s, &private->ag_target_ctls[i]); if (err < 0) return err; } + + /* Add safe-mode input switch controls */ + for (i = 0; i < info->safe_input_count; i++) { + scnprintf(s, sizeof(s), fmt, i + 1, + "Safe", "Switch"); + err = scarlett2_add_new_ctl( + mixer, &scarlett2_safe_ctl, + i, 1, s, &private->safe_ctls[i]); + if (err < 0) + return err; } /* Add PCM Input Switch control */ @@ -6383,413 +7826,238 @@ static int scarlett2_add_power_status_ctl(struct usb_mixer_interface *mixer) &private->power_status_ctl); } -/*** Cleanup/Suspend Callbacks ***/ +/*** Bluetooth Volume ***/ -static void scarlett2_private_free(struct usb_mixer_interface *mixer) -{ - struct scarlett2_data *private = mixer->private_data; - - cancel_delayed_work_sync(&private->work); - kfree(private); - mixer->private_data = NULL; -} - -static void scarlett2_private_suspend(struct usb_mixer_interface *mixer) +static int scarlett2_update_bluetooth_volume(struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; + int err; - if (cancel_delayed_work_sync(&private->work)) - scarlett2_config_save(private->mixer); -} - -/*** Initialisation ***/ - -static void scarlett2_count_io(struct scarlett2_data *private) -{ - const struct scarlett2_device_info *info = private->info; - const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; - int port_type, srcs = 0, dsts = 0; - - /* Count the number of mux sources and destinations */ - for (port_type = 0; - port_type < SCARLETT2_PORT_TYPE_COUNT; - port_type++) { - srcs += port_count[port_type][SCARLETT2_PORT_IN]; - dsts += port_count[port_type][SCARLETT2_PORT_OUT]; - } - - private->num_mux_srcs = srcs; - private->num_mux_dsts = dsts; - - /* Mixer inputs are mux outputs and vice versa. - * Scarlett Gen 4 DSP I/O uses SCARLETT2_PORT_TYPE_MIX but - * doesn't have mixer controls. - */ - private->num_mix_in = - port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT] - - info->dsp_count; + private->bluetooth_updated = 0; - private->num_mix_out = - port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN] - - info->dsp_count; + if (!private->info->has_bluetooth) + return 0; - /* Number of analogue line outputs */ - private->num_line_out = - port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; + err = scarlett2_usb_get_config(mixer, + SCARLETT2_CONFIG_BLUETOOTH_VOLUME, + 1, &private->bluetooth_volume); + if (err < 0) + return err; - /* Number of monitor mix controls */ - private->num_monitor_mix_ctls = - info->direct_monitor * 2 * private->num_mix_in; + return 0; } -/* 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) +static int scarlett2_bluetooth_volume_ctl_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) { - struct usb_host_config *config = dev->actconfig; - int i; + 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 err = 0; - 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; + mutex_lock(&private->data_mutex); - if (desc->bInterfaceClass != 255) - continue; + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } - 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; + if (private->bluetooth_updated) { + err = scarlett2_update_bluetooth_volume(mixer); + if (err < 0) + goto unlock; } + ucontrol->value.integer.value[0] = private->bluetooth_volume; - return -EINVAL; +unlock: + mutex_unlock(&private->data_mutex); + return err; } -/* Initialise private data */ -static int scarlett2_init_private(struct usb_mixer_interface *mixer, - const struct scarlett2_device_entry *entry) +static int scarlett2_bluetooth_volume_ctl_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) { - struct scarlett2_data *private = - kzalloc(sizeof(struct scarlett2_data), GFP_KERNEL); + 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; - if (!private) - return -ENOMEM; + mutex_lock(&private->data_mutex); - mutex_init(&private->usb_mutex); - mutex_init(&private->data_mutex); - INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work); + if (private->hwdep_in_use) { + err = -EBUSY; + goto unlock; + } - mixer->private_data = private; - mixer->private_free = scarlett2_private_free; - mixer->private_suspend = scarlett2_private_suspend; + oval = private->bluetooth_volume; + val = clamp(ucontrol->value.integer.value[0], + 0L, (long)SCARLETT2_MAX_BLUETOOTH_VOLUME); - private->info = entry->info; - private->config_set = entry->info->config_set; - private->series_name = entry->series_name; - scarlett2_count_io(private); - private->scarlett2_seq = 0; - private->mixer = mixer; + if (oval == val) + goto unlock; - return scarlett2_find_fc_interface(mixer->chip->dev, private); + private->bluetooth_volume = val; + err = scarlett2_usb_set_config(mixer, + SCARLETT2_CONFIG_BLUETOOTH_VOLUME, + 0, val); + if (err == 0) + err = 1; + +unlock: + mutex_unlock(&private->data_mutex); + return err; } -/* Cargo cult proprietary initialisation sequence */ -static int scarlett2_usb_init(struct usb_mixer_interface *mixer) +static int scarlett2_bluetooth_volume_ctl_info( + struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { - struct usb_device *dev = mixer->chip->dev; - struct scarlett2_data *private = mixer->private_data; - u8 step0_buf[24]; - u8 step2_buf[84]; - 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, - step0_buf, sizeof(step0_buf)); - if (err < 0) - return err; - - /* 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; - err = scarlett2_usb(mixer, SCARLETT2_USB_INIT_2, - NULL, 0, - step2_buf, sizeof(step2_buf)); - if (err < 0) - return err; - - /* extract 4-byte firmware version from step2_buf[8] */ - private->firmware_version = le32_to_cpu(*(__le32 *)(step2_buf + 8)); - usb_audio_info(mixer->chip, - "Firmware version %d\n", - private->firmware_version); - + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = SCARLETT2_MAX_BLUETOOTH_VOLUME; + uinfo->value.integer.step = 1; return 0; } -/* Get the flash segment numbers for the App_Settings and App_Upgrade - * segments and put them in the private data - */ -static int scarlett2_get_flash_segment_nums(struct usb_mixer_interface *mixer) +static const struct snd_kcontrol_new scarlett2_bluetooth_volume_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_bluetooth_volume_ctl_info, + .get = scarlett2_bluetooth_volume_ctl_get, + .put = scarlett2_bluetooth_volume_ctl_put, +}; + +static int scarlett2_add_bluetooth_volume_ctl( + struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; - int err, count, i; - - struct { - __le32 size; - __le32 count; - u8 unknown[8]; - } __packed flash_info; - - struct { - __le32 size; - __le32 flags; - char name[16]; - } __packed segment_info; - err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_FLASH, - NULL, 0, - &flash_info, sizeof(flash_info)); - if (err < 0) - return err; - - count = le32_to_cpu(flash_info.count); - - /* sanity check count */ - if (count < SCARLETT2_SEGMENT_NUM_MIN || - count > SCARLETT2_SEGMENT_NUM_MAX + 1) { - usb_audio_err(mixer->chip, - "invalid flash segment count: %d\n", count); - return -EINVAL; - } - - for (i = 0; i < count; i++) { - __le32 segment_num_req = cpu_to_le32(i); - int flash_segment_id; - - err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_SEGMENT, - &segment_num_req, sizeof(segment_num_req), - &segment_info, sizeof(segment_info)); - if (err < 0) { - usb_audio_err(mixer->chip, - "failed to get flash segment info %d: %d\n", - i, err); - return err; - } - - if (!strncmp(segment_info.name, - SCARLETT2_SEGMENT_SETTINGS_NAME, 16)) - flash_segment_id = SCARLETT2_SEGMENT_ID_SETTINGS; - else if (!strncmp(segment_info.name, - SCARLETT2_SEGMENT_FIRMWARE_NAME, 16)) - flash_segment_id = SCARLETT2_SEGMENT_ID_FIRMWARE; - else - continue; - - private->flash_segment_nums[flash_segment_id] = i; - private->flash_segment_blocks[flash_segment_id] = - le32_to_cpu(segment_info.size) / - SCARLETT2_FLASH_BLOCK_SIZE; - } - - /* segment 0 is App_Gold and we never want to touch that, so - * use 0 as the "not-found" value - */ - if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_SETTINGS]) { - usb_audio_err(mixer->chip, - "failed to find flash segment %s\n", - SCARLETT2_SEGMENT_SETTINGS_NAME); - return -EINVAL; - } - if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_FIRMWARE]) { - usb_audio_err(mixer->chip, - "failed to find flash segment %s\n", - SCARLETT2_SEGMENT_FIRMWARE_NAME); - return -EINVAL; - } + if (!private->info->has_bluetooth) + return 0; - return 0; + /* Add Bluetooth volume control */ + return scarlett2_add_new_ctl(mixer, &scarlett2_bluetooth_volume_ctl, + 0, 1, "Bluetooth Capture Volume", + &private->bluetooth_volume_ctl); } -/* Read configuration from the interface on start */ -static int scarlett2_read_configs(struct usb_mixer_interface *mixer) +/*** S/PDIF Mode Controls ***/ + +static int scarlett2_update_spdif_mode(struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; - const struct scarlett2_device_info *info = private->info; int err, i; + u8 mode; + const u8 *mode_values = private->info->spdif_mode_values; - if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_MSD_SWITCH)) { - err = scarlett2_usb_get_config( - mixer, SCARLETT2_CONFIG_MSD_SWITCH, - 1, &private->msd_switch); - if (err < 0) - return err; - } - - if (private->firmware_version < info->min_firmware_version) { - usb_audio_err(mixer->chip, - "Focusrite %s firmware version %d is too old; " - "need %d", - private->series_name, - private->firmware_version, - info->min_firmware_version); - return 0; - } - - /* no other controls are created if MSD mode is on */ - if (private->msd_switch) + if (!private->info->spdif_mode_control_name) return 0; - err = scarlett2_update_input_level(mixer); - if (err < 0) - return err; - - err = scarlett2_update_input_pad(mixer); + err = scarlett2_usb_get_config(mixer, SCARLETT2_CONFIG_SPDIF_MODE, + 1, &mode); if (err < 0) return err; - err = scarlett2_update_input_air(mixer); - if (err < 0) - return err; + private->spdif_mode = 0; - err = scarlett2_update_input_phantom(mixer); - if (err < 0) - return err; - - err = scarlett2_update_direct_monitor(mixer); - if (err < 0) - return err; - - /* the rest of the configuration is for devices with a mixer */ - if (!scarlett2_has_mixer(private)) - return 0; - - err = scarlett2_update_monitor_mix(mixer); - if (err < 0) - return err; - - err = scarlett2_update_monitor_other(mixer); - if (err < 0) - return err; + for (i = 0; *mode_values != 0xff; i++, mode_values++) + if (*mode_values == mode) { + private->spdif_mode = i; + break; + } - if (scarlett2_has_config_item(private, - SCARLETT2_CONFIG_STANDALONE_SWITCH)) { - err = scarlett2_usb_get_config( - mixer, SCARLETT2_CONFIG_STANDALONE_SWITCH, - 1, &private->standalone_switch); - if (err < 0) - return err; - } + return 0; +} - if (scarlett2_has_config_item(private, - SCARLETT2_CONFIG_POWER_EXT)) { - err = scarlett2_update_power_status(mixer); - if (err < 0) - return err; - } +static int scarlett2_spdif_mode_ctl_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + struct usb_mixer_elem_info *elem = kctl->private_data; + struct scarlett2_data *private = elem->head.mixer->private_data; + const char * const *mode_texts = private->info->spdif_mode_texts; + int count = 0; - err = scarlett2_update_sync(mixer); - if (err < 0) - return err; + while (*mode_texts++) + count++; - if (scarlett2_has_config_item(private, - SCARLETT2_CONFIG_LINE_OUT_VOLUME)) { - s16 sw_vol[SCARLETT2_ANALOGUE_MAX]; + return snd_ctl_enum_info(uinfo, 1, count, + private->info->spdif_mode_texts); +} - /* read SW line out volume */ - err = scarlett2_usb_get_config( - mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME, - private->num_line_out, &sw_vol); - if (err < 0) - return err; +static int scarlett2_spdif_mode_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; - for (i = 0; i < private->num_line_out; i++) - private->vol[i] = clamp( - sw_vol[i] + SCARLETT2_VOLUME_BIAS, - 0, SCARLETT2_VOLUME_BIAS); + ucontrol->value.enumerated.item[0] = private->spdif_mode; + return 0; +} - /* read SW mute */ - err = scarlett2_usb_get_config( - mixer, SCARLETT2_CONFIG_MUTE_SWITCH, - private->num_line_out, &private->mute_switch); - if (err < 0) - return err; +static int scarlett2_spdif_mode_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; + int i; - for (i = 0; i < private->num_line_out; i++) - private->mute_switch[i] = - !!private->mute_switch[i]; + mutex_lock(&private->data_mutex); - /* read SW/HW switches */ - if (scarlett2_has_config_item(private, - SCARLETT2_CONFIG_SW_HW_SWITCH)) { - err = scarlett2_usb_get_config( - mixer, SCARLETT2_CONFIG_SW_HW_SWITCH, - private->num_line_out, - &private->vol_sw_hw_switch); - if (err < 0) - return err; + oval = private->spdif_mode; + val = ucontrol->value.enumerated.item[0]; - for (i = 0; i < private->num_line_out; i++) - private->vol_sw_hw_switch[i] = - !!private->vol_sw_hw_switch[i]; - } + if (val < 0) { + err = -EINVAL; + goto unlock; } - err = scarlett2_update_volumes(mixer); - if (err < 0) - return err; + for (i = 0; i <= val; i++) + if (private->info->spdif_mode_values[i] == 0xff) { + err = -EINVAL; + goto unlock; + } - err = scarlett2_update_dim_mute(mixer); - if (err < 0) - return err; + if (oval == val) + goto unlock; - err = scarlett2_update_input_select(mixer); - if (err < 0) - return err; + private->spdif_mode = val; - err = scarlett2_update_input_gain(mixer); - if (err < 0) - return err; + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_SPDIF_MODE, 0, + private->info->spdif_mode_values[val]); + if (!err) + err = 1; - err = scarlett2_update_autogain(mixer); - if (err < 0) - return err; +unlock: + mutex_unlock(&private->data_mutex); + return err; +} - err = scarlett2_update_input_safe(mixer); - if (err < 0) - return err; +static const struct snd_kcontrol_new scarlett2_spdif_mode_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", + .info = scarlett2_spdif_mode_ctl_info, + .get = scarlett2_spdif_mode_ctl_get, + .put = scarlett2_spdif_mode_ctl_put, +}; - if (scarlett2_has_config_item(private, - SCARLETT2_CONFIG_PCM_INPUT_SWITCH)) { - err = scarlett2_update_pcm_input_switch(mixer); - if (err < 0) - return err; - } +static int scarlett2_add_spdif_mode_ctl(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; - err = scarlett2_update_mix(mixer); - if (err < 0) - return err; + if (!private->info->spdif_mode_control_name) + return 0; - return scarlett2_usb_get_mux(mixer); + return scarlett2_add_new_ctl(mixer, &scarlett2_spdif_mode_ctl, + 0, 1, + private->info->spdif_mode_control_name, + NULL); } +/*** Notification Handlers ***/ + /* Notify on sync change */ static void scarlett2_notify_sync(struct usb_mixer_interface *mixer) { @@ -6902,6 +8170,36 @@ static void scarlett2_notify_input_air(struct usb_mixer_interface *mixer) &private->air_ctls[i]->id); } +/* Notify on input DSP switch change */ +static void scarlett2_notify_input_dsp(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_dsp_updated = 1; + + for (i = 0; i < info->dsp_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->dsp_ctls[i]->id); +} + +/* Notify on input mute switch change */ +static void scarlett2_notify_input_mute(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_mute_updated = 1; + + for (i = 0; i < info->mute_input_count; i++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->input_mute_ctls[i]->id); +} + /* Notify on input phantom switch change */ static void scarlett2_notify_input_phantom(struct usb_mixer_interface *mixer) { @@ -6936,7 +8234,8 @@ static void scarlett2_notify_input_select(struct usb_mixer_interface *mixer) const struct scarlett2_device_info *info = private->info; int i; - if (!info->gain_input_count) + if (!scarlett2_has_config_item(private, + SCARLETT2_CONFIG_INPUT_SELECT_SWITCH)) return; private->input_select_updated = 1; @@ -6988,6 +8287,12 @@ static void scarlett2_notify_autogain(struct usb_mixer_interface *mixer) &private->autogain_status_ctls[i]->id); } + for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + if (scarlett2_has_config_item(private, + scarlett2_ag_target_configs[i])) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, + &private->ag_target_ctls[i]->id); + scarlett2_autogain_notify_access(mixer); } @@ -6999,12 +8304,12 @@ static void scarlett2_notify_input_safe(struct usb_mixer_interface *mixer) const struct scarlett2_device_info *info = private->info; int i; - if (!info->gain_input_count) + if (!info->safe_input_count) return; private->input_safe_updated = 1; - for (i = 0; i < info->gain_input_count; i++) + for (i = 0; i < info->safe_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &private->safe_ctls[i]->id); } @@ -7107,6 +8412,33 @@ static void scarlett2_notify_pcm_input_switch(struct usb_mixer_interface *mixer) scarlett2_notify_mux(mixer); } +/* Notify on Bluetooth change */ +static void scarlett2_notify_bluetooth(struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + + if (!private->info->has_bluetooth) + return; + + private->bluetooth_updated = 1; + + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &private->bluetooth_volume_ctl->id); +} + +/* Handle acknowledgement that a command was received; let + * scarlett2_usb() know that it can proceed + */ +static void scarlett2_notify_ack(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + + /* if running == 0, ignore ACKs */ + if (private->running) + complete(&private->cmd_done); +} + /* Interrupt callback */ static void scarlett2_notify(struct urb *urb) { @@ -7123,6 +8455,12 @@ static void scarlett2_notify(struct urb *urb) data = le32_to_cpu(*(__le32 *)urb->transfer_buffer); + /* Ignore notifications except ACK during initialisation. + * ACK is 0x00000001 on every device. + */ + if (private->running < 2) + data &= 1; + while (data && notifications->mask) { if (data & notifications->mask) { data &= ~notifications->mask; @@ -7143,9 +8481,141 @@ requeue: ustatus != -ESHUTDOWN) { urb->dev = mixer->chip->dev; usb_submit_urb(urb, GFP_ATOMIC); + } else { + complete(&private->cmd_done); } } +/*** Cleanup/Suspend Callbacks ***/ + +static void scarlett2_private_free(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + + cancel_delayed_work_sync(&private->work); + kfree(private); + mixer->private_data = NULL; +} + +static void scarlett2_private_suspend(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + + if (cancel_delayed_work_sync(&private->work)) + scarlett2_config_save(private->mixer); +} + +/*** Initialisation ***/ + +static void scarlett2_count_io(struct scarlett2_data *private) +{ + const struct scarlett2_device_info *info = private->info; + const struct scarlett2_config_set *config_set = info->config_set; + const int (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count; + int port_type, srcs = 0, dsts = 0, i; + + /* Count the number of mux sources and destinations */ + for (port_type = 0; + port_type < SCARLETT2_PORT_TYPE_COUNT; + port_type++) { + srcs += port_count[port_type][SCARLETT2_PORT_IN]; + dsts += port_count[port_type][SCARLETT2_PORT_OUT]; + } + + private->num_mux_srcs = srcs; + private->num_mux_dsts = dsts; + + /* Mixer inputs are mux outputs and vice versa. + * Scarlett Gen 4 DSP I/O uses SCARLETT2_PORT_TYPE_MIX but + * doesn't have mixer controls. + */ + private->num_mix_in = + port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_OUT] - + info->dsp_count; + + private->num_mix_out = + port_count[SCARLETT2_PORT_TYPE_MIX][SCARLETT2_PORT_IN] - + info->dsp_count; + + /* Number of analogue line outputs */ + private->num_line_out = + port_count[SCARLETT2_PORT_TYPE_ANALOGUE][SCARLETT2_PORT_OUT]; + + /* Number of monitor mix controls */ + private->num_monitor_mix_ctls = + info->direct_monitor * 2 * private->num_mix_in; + + /* Number of autogain status texts */ + if (config_set->autogain_status_texts) { + const char * const *texts = config_set->autogain_status_texts; + + for (i = 0; texts[i]; i++) + ; + private->num_autogain_status_texts = i; + } +} + +/* 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; +} + +/* Initialise private data */ +static int scarlett2_init_private(struct usb_mixer_interface *mixer, + const struct scarlett2_device_entry *entry) +{ + struct scarlett2_data *private = + kzalloc(sizeof(struct scarlett2_data), GFP_KERNEL); + + if (!private) + return -ENOMEM; + + mutex_init(&private->usb_mutex); + mutex_init(&private->data_mutex); + INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work); + + mixer->private_data = private; + mixer->private_free = scarlett2_private_free; + mixer->private_suspend = scarlett2_private_suspend; + + private->info = entry->info; + private->config_set = entry->info->config_set; + private->series_name = entry->series_name; + scarlett2_count_io(private); + private->scarlett2_seq = 0; + private->mixer = mixer; + + return scarlett2_find_fc_interface(mixer->chip->dev, private); +} + +/* Submit a URB to receive notifications from the device */ static int scarlett2_init_notify(struct usb_mixer_interface *mixer) { struct usb_device *dev = mixer->chip->dev; @@ -7174,9 +8644,341 @@ static int scarlett2_init_notify(struct usb_mixer_interface *mixer) transfer_buffer, private->wMaxPacketSize, scarlett2_notify, mixer, private->bInterval); + init_completion(&private->cmd_done); + return usb_submit_urb(mixer->urb, GFP_KERNEL); } +/* 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 step0_buf[24]; + u8 step2_buf[84]; + 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, + step0_buf, sizeof(step0_buf)); + if (err < 0) + return err; + + /* Set up the interrupt polling for notifications. + * When running is: + * 0: all notifications are ignored + * 1: only ACKs are handled + * 2: all notifications are handled + */ + err = scarlett2_init_notify(mixer); + if (err < 0) + return err; + + /* sleep for a moment in case of an outstanding ACK */ + msleep(20); + + /* start handling ACKs, but no other notifications until the + * ALSA controls have been created + */ + private->running = 1; + + /* 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; + err = scarlett2_usb(mixer, SCARLETT2_USB_INIT_2, + NULL, 0, + step2_buf, sizeof(step2_buf)); + if (err < 0) + return err; + + /* extract 4-byte firmware version from step2_buf[8] */ + private->firmware_version = le32_to_cpu(*(__le32 *)(step2_buf + 8)); + usb_audio_info(mixer->chip, + "Firmware version %d\n", + private->firmware_version); + + return 0; +} + +/* Get the flash segment numbers for the App_Settings and App_Upgrade + * segments and put them in the private data + */ +static int scarlett2_get_flash_segment_nums(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + int err, count, i; + + struct { + __le32 size; + __le32 count; + u8 unknown[8]; + } __packed flash_info; + + struct { + __le32 size; + __le32 flags; + char name[16]; + } __packed segment_info; + + err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_FLASH, + NULL, 0, + &flash_info, sizeof(flash_info)); + if (err < 0) + return err; + + count = le32_to_cpu(flash_info.count); + + /* sanity check count */ + if (count < SCARLETT2_SEGMENT_NUM_MIN || + count > SCARLETT2_SEGMENT_NUM_MAX + 1) { + usb_audio_err(mixer->chip, + "invalid flash segment count: %d\n", count); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + __le32 segment_num_req = cpu_to_le32(i); + int flash_segment_id; + + err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_SEGMENT, + &segment_num_req, sizeof(segment_num_req), + &segment_info, sizeof(segment_info)); + if (err < 0) { + usb_audio_err(mixer->chip, + "failed to get flash segment info %d: %d\n", + i, err); + return err; + } + + if (!strncmp(segment_info.name, + SCARLETT2_SEGMENT_SETTINGS_NAME, 16)) + flash_segment_id = SCARLETT2_SEGMENT_ID_SETTINGS; + else if (!strncmp(segment_info.name, + SCARLETT2_SEGMENT_FIRMWARE_NAME, 16)) + flash_segment_id = SCARLETT2_SEGMENT_ID_FIRMWARE; + else + continue; + + private->flash_segment_nums[flash_segment_id] = i; + private->flash_segment_blocks[flash_segment_id] = + le32_to_cpu(segment_info.size) / + SCARLETT2_FLASH_BLOCK_SIZE; + } + + /* segment 0 is App_Gold and we never want to touch that, so + * use 0 as the "not-found" value + */ + if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_SETTINGS]) { + usb_audio_err(mixer->chip, + "failed to find flash segment %s\n", + SCARLETT2_SEGMENT_SETTINGS_NAME); + return -EINVAL; + } + if (!private->flash_segment_nums[SCARLETT2_SEGMENT_ID_FIRMWARE]) { + usb_audio_err(mixer->chip, + "failed to find flash segment %s\n", + SCARLETT2_SEGMENT_FIRMWARE_NAME); + return -EINVAL; + } + + return 0; +} + +/* Read configuration from the interface on start */ +static int scarlett2_read_configs(struct usb_mixer_interface *mixer) +{ + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + int err, i; + + if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_MSD_SWITCH)) { + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_MSD_SWITCH, + 1, &private->msd_switch); + if (err < 0) + return err; + } + + if (private->firmware_version < info->min_firmware_version) { + usb_audio_err(mixer->chip, + "Focusrite %s firmware version %d is too old; " + "need %d", + private->series_name, + private->firmware_version, + info->min_firmware_version); + return 0; + } + + /* no other controls are created if MSD mode is on */ + if (private->msd_switch) + return 0; + + err = scarlett2_update_input_level(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_pad(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_air(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_dsp(mixer); + if (err < 0) + return err; + + err = scarlett2_update_compressor_values(mixer); + if (err < 0) + return err; + + err = scarlett2_update_filter_values(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_mute(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_phantom(mixer); + if (err < 0) + return err; + + err = scarlett2_update_direct_monitor(mixer); + if (err < 0) + return err; + + /* the rest of the configuration is for devices with a mixer */ + if (!scarlett2_has_mixer(private)) + return 0; + + err = scarlett2_update_monitor_mix(mixer); + if (err < 0) + return err; + + err = scarlett2_update_monitor_other(mixer); + if (err < 0) + return err; + + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_STANDALONE_SWITCH)) { + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_STANDALONE_SWITCH, + 1, &private->standalone_switch); + if (err < 0) + return err; + } + + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_POWER_EXT)) { + err = scarlett2_update_power_status(mixer); + if (err < 0) + return err; + } + + err = scarlett2_update_sync(mixer); + if (err < 0) + return err; + + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_LINE_OUT_VOLUME)) { + s16 sw_vol[SCARLETT2_ANALOGUE_MAX]; + + /* read SW line out volume */ + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME, + private->num_line_out, &sw_vol); + if (err < 0) + return err; + + for (i = 0; i < private->num_line_out; i++) + private->vol[i] = clamp( + sw_vol[i] + SCARLETT2_VOLUME_BIAS, + 0, SCARLETT2_VOLUME_BIAS); + + /* read SW mute */ + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_MUTE_SWITCH, + private->num_line_out, &private->mute_switch); + if (err < 0) + return err; + + for (i = 0; i < private->num_line_out; i++) + private->mute_switch[i] = + !!private->mute_switch[i]; + + /* read SW/HW switches */ + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_SW_HW_SWITCH)) { + err = scarlett2_usb_get_config( + mixer, SCARLETT2_CONFIG_SW_HW_SWITCH, + private->num_line_out, + &private->vol_sw_hw_switch); + if (err < 0) + return err; + + for (i = 0; i < private->num_line_out; i++) + private->vol_sw_hw_switch[i] = + !!private->vol_sw_hw_switch[i]; + } + } + + err = scarlett2_update_volumes(mixer); + if (err < 0) + return err; + + err = scarlett2_update_dim_mute(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_select(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_gain(mixer); + if (err < 0) + return err; + + err = scarlett2_update_autogain(mixer); + if (err < 0) + return err; + + err = scarlett2_update_input_safe(mixer); + if (err < 0) + return err; + + if (scarlett2_has_config_item(private, + SCARLETT2_CONFIG_PCM_INPUT_SWITCH)) { + err = scarlett2_update_pcm_input_switch(mixer); + if (err < 0) + return err; + } + + err = scarlett2_update_bluetooth_volume(mixer); + if (err < 0) + return err; + + err = scarlett2_update_spdif_mode(mixer); + if (err < 0) + return err; + + err = scarlett2_update_mix(mixer); + if (err < 0) + return err; + + return scarlett2_usb_get_mux(mixer); +} + static const struct scarlett2_device_entry *get_scarlett2_device_entry( struct usb_mixer_interface *mixer) { @@ -7297,6 +9099,16 @@ static int snd_scarlett2_controls_create( if (err < 0) return err; + /* Create the Bluetooth volume control */ + err = scarlett2_add_bluetooth_volume_ctl(mixer); + if (err < 0) + return err; + + /* Create the S/PDIF mode control */ + err = scarlett2_add_spdif_mode_ctl(mixer); + if (err < 0) + return err; + /* Set the access mode of controls disabled during * autogain/phantom power switching. */ @@ -7305,10 +9117,8 @@ static int snd_scarlett2_controls_create( scarlett2_phantom_update_access(mixer); } - /* Set up the interrupt polling */ - err = scarlett2_init_notify(mixer); - if (err < 0) - return err; + /* Start handling all notifications */ + private->running = 2; return 0; } @@ -7397,7 +9207,7 @@ static int scarlett2_reboot(struct usb_mixer_interface *mixer) return scarlett2_usb(mixer, SCARLETT2_USB_REBOOT, NULL, 0, NULL, 0); } -/* Select a flash segment for erasing (and possibly writing to) */ +/* Select a flash segment for reading/erasing/writing */ static int scarlett2_ioctl_select_flash_segment( struct usb_mixer_interface *mixer, unsigned long arg) @@ -7578,6 +9388,84 @@ static int scarlett2_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, } } +static long scarlett2_hwdep_read(struct snd_hwdep *hw, + char __user *buf, + long count, loff_t *offset) +{ + struct usb_mixer_interface *mixer = hw->private_data; + struct scarlett2_data *private = mixer->private_data; + int segment_id, segment_num, err; + int flash_size; + + /* SCARLETT2_USB_READ_SEGMENT request data */ + struct { + __le32 segment_num; + __le32 offset; + __le32 len; + } __packed req; + + u8 *resp; + + /* Flash segment must first be selected */ + if (private->flash_write_state != SCARLETT2_FLASH_WRITE_STATE_SELECTED) + return -EINVAL; + + /* Get the selected flash segment number */ + segment_id = private->selected_flash_segment_id; + if (segment_id < 0 || segment_id >= SCARLETT2_SEGMENT_ID_COUNT) + return -EINVAL; + + segment_num = private->flash_segment_nums[segment_id]; + if (segment_num < 0 || + segment_num > SCARLETT2_SEGMENT_NUM_MAX) + return -EFAULT; + + /* Validate the offset and count */ + if (count < 0 || *offset < 0) + return -EINVAL; + + /* Reached EOF? */ + flash_size = private->flash_segment_blocks[segment_id] * + SCARLETT2_FLASH_BLOCK_SIZE; + if (!count || *offset >= flash_size) + return 0; + + /* Limit the numbers of bytes read to SCARLETT2_FLASH_RW_MAX */ + if (count > SCARLETT2_FLASH_RW_MAX) + count = SCARLETT2_FLASH_RW_MAX; + + /* Limit read to EOF */ + if (*offset + count >= flash_size) + count = flash_size - *offset; + + /* Create and send the request */ + req.segment_num = cpu_to_le32(segment_num); + req.offset = cpu_to_le32(*offset); + req.len = cpu_to_le32(count); + + resp = kzalloc(count, GFP_KERNEL); + if (!resp) + return -ENOMEM; + + err = scarlett2_usb(mixer, SCARLETT2_USB_READ_SEGMENT, + &req, sizeof(req), resp, count); + if (err < 0) + goto error; + + /* Copy the response to userspace */ + if (copy_to_user(buf, resp, count)) { + err = -EFAULT; + goto error; + } + + *offset += count; + err = count; + +error: + kfree(resp); + return err; +} + static long scarlett2_hwdep_write(struct snd_hwdep *hw, const char __user *buf, long count, loff_t *offset) @@ -7596,7 +9484,7 @@ static long scarlett2_hwdep_write(struct snd_hwdep *hw, } __packed *req; /* Calculate the maximum permitted in data[] */ - const size_t max_data_size = SCARLETT2_FLASH_WRITE_MAX - + const size_t max_data_size = SCARLETT2_FLASH_RW_MAX - offsetof(typeof(*req), data); /* If erasing, wait for it to complete */ @@ -7633,7 +9521,7 @@ static long scarlett2_hwdep_write(struct snd_hwdep *hw, if (!count) return 0; - /* Limit the *req size to SCARLETT2_FLASH_WRITE_MAX */ + /* Limit the *req size to SCARLETT2_FLASH_RW_MAX */ if (count > max_data_size) count = max_data_size; @@ -7694,6 +9582,7 @@ static int scarlett2_hwdep_init(struct usb_mixer_interface *mixer) hw->exclusive = 1; hw->ops.open = scarlett2_hwdep_open; hw->ops.ioctl = scarlett2_hwdep_ioctl; + hw->ops.read = scarlett2_hwdep_read; hw->ops.write = scarlett2_hwdep_write; hw->ops.release = scarlett2_hwdep_release; diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 5d72dc8441..73abc38a54 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3013,21 +3013,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), .type = QUIRK_AUDIO_FIXED_ENDPOINT, .data = &(const struct audioformat) { .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .fmt_bits = 24, .channels = 4, .iface = 2, .altsetting = 1, .altset_idx = 1, .attributes = 0x00, - .endpoint = 0x01, + .endpoint = USB_RECIP_INTERFACE | USB_DIR_OUT, .ep_attr = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .nr_rates = 1, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, .rate_table = (unsigned int[]) { - 48000 - } + 44100, 48000, 88200, 96000 + }, + .sync_ep = USB_RECIP_INTERFACE | USB_DIR_IN, + .sync_iface = 3, + .sync_altsetting = 1, + .sync_ep_idx = 1, + .implicit_fb = 1, } }, { @@ -3035,22 +3042,25 @@ YAMAHA_DEVICE(0x7010, "UB99"), .type = QUIRK_AUDIO_FIXED_ENDPOINT, .data = &(const struct audioformat) { .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .fmt_bits = 24, .channels = 4, .iface = 3, .altsetting = 1, .altset_idx = 1, - .endpoint = 0x81, .attributes = 0x00, + .endpoint = USB_RECIP_INTERFACE | USB_DIR_IN, .ep_attr = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, .maxpacksize = 0x009c, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .nr_rates = 1, + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, .rate_table = (unsigned int[]) { - 48000 - } + 44100, 48000, 88200, 96000 + }, + .implicit_fb = 0, } }, { diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 09712e61c6..ea063a14cd 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -984,21 +984,13 @@ static int snd_usb_axefx3_boot_quirk(struct usb_device *dev) return 0; } -static void mbox3_setup_48_24_magic(struct usb_device *dev) +static void mbox3_setup_defaults(struct usb_device *dev) { /* The Mbox 3 is "little endian" */ /* max volume is: 0x0000. */ /* min volume is: 0x0080 (shown in little endian form) */ - - /* Load 48000Hz rate into buffer */ - u8 com_buff[4] = {0x80, 0xbb, 0x00, 0x00}; - - /* Set 48000Hz sample rate */ - snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), - 0x01, 0x21, 0x0100, 0x0001, &com_buff, 4); //Is this really needed? - snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), - 0x01, 0x21, 0x0100, 0x8101, &com_buff, 4); + u8 com_buff[2]; /* Deactivate Tuner */ /* on = 0x01*/ @@ -1008,6 +1000,8 @@ static void mbox3_setup_48_24_magic(struct usb_device *dev) 0x01, 0x21, 0x0003, 0x2001, &com_buff, 1); /* Set clock source to Internal (as opposed to S/PDIF) */ + /* Internal = 0x01*/ + /* S/PDIF = 0x02*/ com_buff[0] = 0x01; snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 1, 0x21, 0x0100, 0x8001, &com_buff, 1); @@ -1113,9 +1107,11 @@ static void mbox3_setup_48_24_magic(struct usb_device *dev) 1, 0x21, 0x0107, 0x4201, &com_buff, 2); /* Toggle allowing host control */ + /* Not needed com_buff[0] = 0x02; snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 3, 0x21, 0x0000, 0x2001, &com_buff, 1); + */ /* Do not dim fx returns */ com_buff[0] = 0x00; @@ -1259,26 +1255,27 @@ static int snd_usb_mbox3_boot_quirk(struct usb_device *dev) descriptor_size = le16_to_cpu(get_cfg_desc(config)->wTotalLength); if (descriptor_size != MBOX3_DESCRIPTOR_SIZE) { - dev_err(&dev->dev, "Invalid descriptor size=%d.\n", descriptor_size); + dev_err(&dev->dev, "MBOX3: Invalid descriptor size=%d.\n", descriptor_size); return -ENODEV; } - dev_dbg(&dev->dev, "device initialised!\n"); + dev_dbg(&dev->dev, "MBOX3: device initialised!\n"); err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor)); config = dev->actconfig; if (err < 0) - dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err); + dev_dbg(&dev->dev, "MBOX3: error usb_get_descriptor: %d\n", err); err = usb_reset_configuration(dev); if (err < 0) - dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err); - dev_dbg(&dev->dev, "mbox3_boot: new boot length = %d\n", + dev_dbg(&dev->dev, "MBOX3: error usb_reset_configuration: %d\n", err); + + dev_dbg(&dev->dev, "MBOX3: new boot length = %d\n", le16_to_cpu(get_cfg_desc(config)->wTotalLength)); - mbox3_setup_48_24_magic(dev); - dev_info(&dev->dev, "Digidesign Mbox 3: 24bit 48kHz"); + mbox3_setup_defaults(dev); + dev_info(&dev->dev, "MBOX3: Initialized."); return 0; /* Successful boot */ } @@ -1734,6 +1731,46 @@ static int pioneer_djm_set_format_quirk(struct snd_usb_substream *subs, return 0; } +static void mbox3_set_format_quirk(struct snd_usb_substream *subs, + const struct audioformat *fmt) +{ + __le32 buff4 = 0; + u8 buff1 = 0x01; + u32 new_rate = subs->data_endpoint->cur_rate; + u32 current_rate; + + // Get current rate from card and check if changing it is needed + snd_usb_ctl_msg(subs->dev, usb_rcvctrlpipe(subs->dev, 0), + 0x01, 0x21 | USB_DIR_IN, 0x0100, 0x8101, &buff4, 4); + current_rate = le32_to_cpu(buff4); + dev_dbg(&subs->dev->dev, + "MBOX3: Current configured sample rate: %d", current_rate); + if (current_rate == new_rate) { + dev_dbg(&subs->dev->dev, + "MBOX3: No change needed (current rate:%d == new rate:%d)", + current_rate, new_rate); + return; + } + + // Set new rate + dev_info(&subs->dev->dev, + "MBOX3: Changing sample rate to: %d", new_rate); + buff4 = cpu_to_le32(new_rate); + snd_usb_ctl_msg(subs->dev, usb_sndctrlpipe(subs->dev, 0), + 0x01, 0x21, 0x0100, 0x8101, &buff4, 4); + + // Set clock source to Internal + snd_usb_ctl_msg(subs->dev, usb_sndctrlpipe(subs->dev, 0), + 0x01, 0x21, 0x0100, 0x8001, &buff1, 1); + + // Check whether the change was successful + buff4 = 0; + snd_usb_ctl_msg(subs->dev, usb_rcvctrlpipe(subs->dev, 0), + 0x01, 0x21 | USB_DIR_IN, 0x0100, 0x8101, &buff4, 4); + if (new_rate != le32_to_cpu(buff4)) + dev_warn(&subs->dev->dev, "MBOX3: Couldn't set the sample rate"); +} + void snd_usb_set_format_quirk(struct snd_usb_substream *subs, const struct audioformat *fmt) { @@ -1755,6 +1792,9 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, case USB_ID(0x08e4, 0x0163): /* Pioneer DJM-850 */ pioneer_djm_set_format_quirk(subs, 0x0086); break; + case USB_ID(0x0dba, 0x5000): + mbox3_set_format_quirk(subs, fmt); /* Digidesign Mbox 3 */ + break; } } @@ -2085,6 +2125,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_CTL_MSG_DELAY_1M), DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */ QUIRK_FLAG_CTL_MSG_DELAY_1M), + DEVICE_FLG(0x0c45, 0x6340, /* Sonix HD USB Camera */ + QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */ QUIRK_FLAG_FIXED_RATE), DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */ @@ -2127,6 +2169,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x19f7, 0x0035, /* RODE NT-USB+ */ QUIRK_FLAG_GET_SAMPLE_RATE), + DEVICE_FLG(0x1bcf, 0x2281, /* HD Webcam */ + QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */ diff --git a/sound/usb/usx2y/Makefile b/sound/usb/usx2y/Makefile index cc4c2f1efa..fc033aba03 100644 --- a/sound/usb/usx2y/Makefile +++ b/sound/usb/usx2y/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -snd-usb-usx2y-objs := usbusx2y.o usX2Yhwdep.o usx2yhwdeppcm.o -snd-usb-us122l-objs := us122l.o +snd-usb-usx2y-y := usbusx2y.o usX2Yhwdep.o usx2yhwdeppcm.o +snd-usb-us122l-y := us122l.o obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-usx2y.o obj-$(CONFIG_SND_USB_US122L) += snd-usb-us122l.o |