// SPDX-License-Identifier: GPL-2.0 /* * Focusrite Scarlett 2 Protocol Driver for ALSA * (including Scarlett 2nd Gen, 3rd Gen, 4th Gen, Clarett USB, and * Clarett+ series products) * * Supported models: * - 6i6/18i8/18i20 Gen 2 * - Solo/2i2/4i4/8i6/18i8/18i20 Gen 3 * - Solo/2i2/4i4 Gen 4 * - Clarett 2Pre/4Pre/8Pre USB * - Clarett+ 2Pre/4Pre/8Pre * * Copyright (c) 2018-2024 by Geoffrey D. Bennett <g at b4.vu> * Copyright (c) 2020-2021 by Vladimir Sadovnikov <sadko4u@gmail.com> * Copyright (c) 2022 by Christian Colglazier <christian@cacolglazier.com> * * Based on the Scarlett (Gen 1) Driver for ALSA: * * Copyright (c) 2013 by Tobias Hoffmann * Copyright (c) 2013 by Robin Gareus <robin at gareus.org> * Copyright (c) 2002 by Takashi Iwai <tiwai at suse.de> * Copyright (c) 2014 by Chris J Arges <chris.j.arges at canonical.com> * * Many codes borrowed from audio.c by * Alan Cox (alan at lxorguk.ukuu.org.uk) * Thomas Sailer (sailer at ife.ee.ethz.ch) * * Code cleanup: * David Henningsson <david.henningsson at canonical.com>
*/
/* The protocol was reverse engineered by looking at the communication * between Focusrite Control 2.3.4 and the Focusrite(R) Scarlett 18i20 * (firmware 1083) using usbmon in July-August 2018. * * Scarlett 18i8 support added in April 2019. * * Scarlett 6i6 support added in June 2019 (thanks to Martin Wittmann * for providing usbmon output and testing). * * Scarlett 4i4/8i6 Gen 3 support added in May 2020 (thanks to Laurent * Debricon for donating a 4i4 and to Fredrik Unger for providing 8i6 * usbmon output and testing). * * Scarlett 18i8/18i20 Gen 3 support added in June 2020 (thanks to * Darren Jaeckel, Alex Sedlack, and Clovis Lunel for providing usbmon * output, protocol traces and testing). * * Support for loading mixer volume and mux configuration from the * interface during driver initialisation added in May 2021 (thanks to * Vladimir Sadovnikov for figuring out how). * * Support for Solo/2i2 Gen 3 added in May 2021 (thanks to Alexander * Vorona for 2i2 protocol traces). * * Support for phantom power, direct monitoring, speaker switching, * and talkback added in May-June 2021. * * Support for Clarett+ 8Pre added in Aug 2022 by Christian * Colglazier. * * Support for Clarett 8Pre USB added in Sep 2023 (thanks to Philippe * Perrot for confirmation). * * Support for Clarett+ 4Pre and 2Pre added in Sep 2023 (thanks to * Gregory Rozzo for donating a 4Pre, and David Sherwood and Patrice * Peterson for usbmon output). * * Support for Clarett 2Pre and 4Pre USB added in Oct 2023. * * Support for firmware updates added in Dec 2023. * * Support for Scarlett Solo/2i2/4i4 Gen 4 added in Dec 2023 (thanks * to many LinuxMusicians people and to Focusrite for hardware * donations). * * This ALSA mixer gives access to (model-dependent): * - input, output, mixer-matrix muxes * - mixer-matrix gain stages * - gain/volume/mute controls * - level meters * - line/inst level, pad, and air controls * - phantom power, direct monitor, speaker switching, and talkback * controls * - disable/enable MSD mode * - disable/enable standalone mode * - input mute, gain, autogain, safe mode * - direct monitor mixes * - compressor and EQ * - Bluetooth volume * * <ditaa> * /--------------\ 18chn 20chn /--------------\ * | Hardware in +--+------\ /-------------+--+ ALSA PCM out | * \--------------/ | | | | \--------------/ * | | | /-----\ | * | | | | | | * | v v v | | * | +---------------+ | | * | \ Matrix Mux / | | * | +-----+-----+ | | * | | | | * | |18chn | | * | | | | * | | 10chn| | * | v | | * | +------------+ | | * | | Mixer | | | * | | Matrix | | | * | | | | | * | | 18x10 Gain | | | * | | stages | | | * | +-----+------+ | | * | | | | * |18chn |10chn | |20chn * | | | | * | +----------/ | * | | | * v v v * =========================== * +---------------+ +--—------------+ * \ Output Mux / \ Capture Mux / * +---+---+---+ +-----+-----+ * | | | * 10chn| | |18chn * | | | * /--------------\ | | | /--------------\ * | S/PDIF, ADAT |<--/ |10chn \-->| ALSA PCM in | * | Hardware out | | \--------------/ * \--------------/ | * v * +-------------+ Software gain per channel. * | Master Gain |<-- 18i20 only: Switch per channel * +------+------+ to select HW or SW gain control. * | * |10chn * /--------------\ | * | Analogue |<------/ * | Hardware out | * \--------------/ * </ditaa> * * Gen 3/4 devices have a Mass Storage Device (MSD) mode where a small * disk with registration and driver download information is presented * to the host. To access the full functionality of the device without * proprietary software, MSD mode can be disabled by: * - holding down the 48V button for five seconds while powering on * the device, or * - using this driver and alsamixer to change the "MSD Mode" setting * to Off and power-cycling the device
*/
/* Maximum number of analogue outputs */ #define SCARLETT2_ANALOGUE_MAX 10
/* Maximum number of various input controls */ #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
/* Maximum number of inputs to the mixer */ #define SCARLETT2_INPUT_MIX_MAX 25
/* Maximum number of outputs from the mixer */ #define SCARLETT2_OUTPUT_MIX_MAX 12
/* Maximum number of mixer gain controls */ #define SCARLETT2_MIX_MAX (SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX)
/* Maximum number of direct monitor mixer gain controls * 1 (Solo) or 2 (2i2) direct monitor selections (Mono & Stereo) * 2 Mix outputs (A/Left & B/Right) * 4 Mix inputs
*/ #define SCARLETT2_MONITOR_MIX_MAX (2 * 2 * 4)
/* Maximum size of the data in the USB mux assignment message: * 20 inputs, 20 outputs, 25 matrix inputs, 12 spare
*/ #define SCARLETT2_MUX_MAX 77
/* Maximum number of sources (sum of input port counts) */ #define SCARLETT2_MAX_SRCS 52
/* 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 { constchar *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
*/ staticconststruct 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 },
};
/* The autogain_status is set based on the autogain_switch and * raw_autogain_status values. * * If autogain_switch is set, autogain_status is set to 0 (Running). * The other status values are from the raw_autogain_status value + 1.
*/ staticconstchar *const scarlett2_autogain_status_gen4[] = { "Running", "Success", "SuccessDRover", "WarnMinGainLimit", "FailDRunder", "FailMaxGainLimit", "FailClipped", "Cancelled", "Invalid",
NULL
};
/* Location, size, and activation command number for the configuration * parameters. Size is in bits and may be 1, 8, 16, or 32. * * 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 * mute set to 1. 0x02 and 0x03 are temporary values while the device * makes the change and the channel and/or corresponding DSP channel * output is muted.
*/ struct scarlett2_config {
u16 offset;
u8 size;
u8 activate;
u8 pbuf;
u8 mute;
};
/* Description of each hardware port type: * - id: hardware ID of this port type * - src_descr: printf format string for mux input selections * - src_num_offset: added to channel number for the fprintf * - dst_descr: printf format string for mixer controls
*/ struct scarlett2_port {
u16 id; constchar * const src_descr; int src_num_offset; constchar * const dst_descr; constchar * const dsp_src_descr; constchar * const dsp_dst_descr;
};
/* Number of mux tables: one for each band of sample rates * (44.1/48kHz, 88.2/96kHz, and 176.4/176kHz)
*/ #define SCARLETT2_MUX_TABLES 3
/* Maximum number of entries in a mux table */ #define SCARLETT2_MAX_MUX_ENTRIES 10
/* One entry within mux_assignment defines the port type and range of * ports to add to the set_mux message. The end of the list is marked * with count == 0.
*/ struct scarlett2_mux_entry {
u8 port_type;
u8 start;
u8 count;
};
/* Maximum number of entries in a mux table */ #define SCARLETT2_MAX_METER_ENTRIES 9
/* One entry within meter_assignment defines the range of mux outputs * that consecutive meter entries are mapped to. The end of the list * is marked with count == 0.
*/ struct scarlett2_meter_entry {
u8 start;
u8 count;
};
struct scarlett2_device_info { /* which set of configuration parameters the device uses */ conststruct scarlett2_config_set *config_set;
/* minimum firmware version required */
u16 min_firmware_version;
/* has a downloadable device map */
u8 has_devmap;
/* support for main/alt speaker switching */
u8 has_speaker_switching;
/* support for talkback microphone */
u8 has_talkback;
/* the number of analogue inputs with a software switchable * level control that can be set to line or instrument
*/
u8 level_input_count;
/* the first input with a level control (0-based) */
u8 level_input_first;
/* the number of analogue inputs with a software switchable * 10dB pad control
*/
u8 pad_input_count;
/* the number of analogue inputs with a software switchable * "air" control
*/
u8 air_input_count;
/* the first input with an air control (0-based) */
u8 air_input_first;
/* number of additional air options * 0 for air presence only (Gen 3) * 1 for air presence+drive (Gen 4)
*/
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;
/* the first input with phantom power control (0-based) */
u8 phantom_first;
/* the number of inputs each phantom switch controls */
u8 inputs_per_phantom;
/* 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)
*/
u8 direct_monitor;
/* the number of DSP channels */
u8 dsp_count;
/* has a Bluetooth module with volume control */
u8 has_bluetooth;
/* remap analogue outputs; 18i8 Gen 3 has "line 3/4" connected * internally to the analogue 7/8 outputs
*/
u8 line_out_remap_enable;
u8 line_out_remap[SCARLETT2_ANALOGUE_MAX];
u8 line_out_unmap[SCARLETT2_ANALOGUE_MAX];
/* additional description for the line out volume controls */ constchar * const line_out_descrs[SCARLETT2_ANALOGUE_MAX];
/* number of sources/destinations of each port type */ constint port_count[SCARLETT2_PORT_TYPE_COUNT][SCARLETT2_PORT_DIRNS];
/* layout/order of the entries in the set_mux message */ struct scarlett2_mux_entry mux_assignment[SCARLETT2_MUX_TABLES]
[SCARLETT2_MAX_MUX_ENTRIES];
/* map from meter level order returned by * SCARLETT2_USB_GET_METER to index into mux[] entries (same * as the order returned by scarlett2_meter_ctl_get())
*/ struct scarlett2_meter_entry meter_map[SCARLETT2_MAX_METER_ENTRIES];
};
/* get the starting port index number for a given port type/direction */ staticint scarlett2_get_port_start_num( constint port_count[][SCARLETT2_PORT_DIRNS], int direction, int port_type)
{ int i, num = 0;
for (i = 0; i < port_type; i++)
num += port_count[i][direction];
/* Gen 4 device firmware provides access to a base64-encoded * zlib-compressed JSON description of the device's capabilities and * configuration. This device map is made available in * /proc/asound/cardX/device-map.json.zz.b64
*/ #define SCARLETT2_DEVMAP_BLOCK_SIZE 1024 #define SCARLETT2_DEVMAP_FILENAME "device-map.json.zz.b64"
staticvoid scarlett2_fill_request_header(struct scarlett2_data *private, struct scarlett2_usb_packet *req,
u32 cmd, u16 req_size)
{ /* sequence must go up by 1 for each request */
u16 seq = private->scarlett2_seq++;
/* Send a USB message to get data; result placed in *buf */ staticint scarlett2_usb_get( struct usb_mixer_interface *mixer, int offset, void *buf, int size)
{ struct {
__le32 offset;
__le32 size;
} __packed req;
/* Return true if the given configuration item is present in the * configuration set used by this device.
*/ staticint scarlett2_has_config_item( struct scarlett2_data *private, int config_item_num)
{ return !!private->config_set->items[config_item_num].offset;
}
/* Send a USB message to get configuration parameters; result placed in *buf */ staticint scarlett2_usb_get_config( struct usb_mixer_interface *mixer, int config_item_num, int count, void *buf)
{ struct scarlett2_data *private = mixer->private_data; conststruct scarlett2_config *config_item =
&private->config_set->items[config_item_num]; int size, err, i;
u8 *buf_8;
u8 value;
/* Check that the configuration item is present in the * configuration set used by this device
*/ if (!config_item->offset) return -EFAULT;
/* 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 */ if (size >= 8) {
size = size / 8 * count;
err = scarlett2_usb_get(mixer, config_item->offset, buf, size); if (err < 0) return err; if (size == 2) {
u16 *buf_16 = buf;
for (i = 0; i < count; i++, buf_16++)
*buf_16 = le16_to_cpu(*(__le16 *)buf_16);
} elseif (size == 4) {
u32 *buf_32 = buf;
for (i = 0; i < count; i++, buf_32++)
*buf_32 = le32_to_cpu(*(__le32 *)buf_32);
} return0;
}
/* For bit-sized parameters, retrieve into value */
err = scarlett2_usb_get(mixer, config_item->offset, &value, 1); if (err < 0) return err;
/* then unpack from value into buf[] */
buf_8 = buf; for (i = 0; i < 8 && i < count; i++, value >>= 1)
*buf_8++ = value & 1;
return0;
}
/* Send a SCARLETT2_USB_SET_DATA command. * offset: location in the device's data space * size: size in bytes of the value (1, 2, 4)
*/ staticint scarlett2_usb_set_data( struct usb_mixer_interface *mixer, int offset, int size, int value)
{ struct scarlett2_data *private = mixer->private_data; struct {
__le32 offset;
__le32 size;
__le32 value;
} __packed req;
/* 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
*/ staticint 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;
/* 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. * The value for activate needed is determined by the configuration * item.
*/ staticint scarlett2_usb_activate_config( struct usb_mixer_interface *mixer, int activate)
{
__le32 req;
/* Send USB messages to set a SCARLETT2_CONFIG_* parameter */ staticint scarlett2_usb_set_config( struct usb_mixer_interface *mixer, int config_item_num, int index, int value)
{ struct scarlett2_data *private = mixer->private_data; conststruct scarlett2_config_set *config_set = private->config_set; conststruct 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;
/* Write via the parameter buffer? */ if (config_item->pbuf) { if (!config_set->param_buf_addr) return -EFAULT;
/* Place index in param_buf_addr + 1 */
err = scarlett2_usb_set_data(
mixer, config_set->param_buf_addr + 1, 1, index); if (err < 0) return err;
/* Place value in param_buf_addr */
err = scarlett2_usb_set_data(
mixer, config_set->param_buf_addr, 1, value); if (err < 0) return err;
/* Activate the write through the parameter buffer */ return scarlett2_usb_activate_config(
mixer, config_item->activate);
}
/* Direct writes (not via the parameter buffer) need NVRAM * save and support bit-modification
*/
/* Cancel any pending NVRAM save */
cancel_delayed_work_sync(&private->work);
/* Convert config_item->size in bits to size in bytes and * calculate offset
*/ if (config_item->size >= 8) {
size = config_item->size / 8;
offset = config_item->offset + index * size;
/* If updating a bit, retrieve the old value, set/clear the * bit as needed, and update value
*/
} else {
u8 tmp;
/* Write the new value */
err = scarlett2_usb_set_data(mixer, offset, size, value); if (err < 0) return err;
/* Activate the change */
err = scarlett2_usb_activate_config(mixer, config_item->activate); if (err < 0) return err;
/* Interfaces with parameter buffer writes don't need a * separate save step
*/ if (config_set->param_buf_addr) return0;
/* Schedule the change to be written to NVRAM */ if (config_item->activate != SCARLETT2_USB_CONFIG_SAVE)
schedule_delayed_work(&private->work, msecs_to_jiffies(2000));
return0;
}
/* Send USB messages to set a SCARLETT2_CONFIG_* parameter with * multiple values
*/ staticint 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; conststruct scarlett2_config_set *config_set = private->config_set; conststruct 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);
}
err = scarlett2_usb_activate_config(mixer, SCARLETT2_USB_CONFIG_SAVE); if (err < 0)
usb_audio_err(mixer->chip, "config save failed: %d\n", err);
}
/* Delayed work to save config */ staticvoid scarlett2_config_save_work(struct work_struct *work)
{ struct scarlett2_data *private =
container_of(work, struct scarlett2_data, work.work);
scarlett2_config_save(private->mixer);
}
/* Send a USB message to get sync status; result placed in *sync */ staticint scarlett2_usb_get_sync_status( struct usb_mixer_interface *mixer,
u8 *sync)
{
__le32 data; int err;
/* Return true if the device has a mixer that we can control */ staticint scarlett2_has_mixer(struct scarlett2_data *private)
{ return !!private->info->mux_assignment[0][0].count;
}
/* Map from mixer value to (db + 80) * 2 * (reverse of scarlett2_mixer_values[])
*/ staticint scarlett2_mixer_value_to_db(int value)
{ int i;
for (i = 0; i < SCARLETT2_MIXER_VALUE_COUNT; i++) if (scarlett2_mixer_values[i] >= value) return i; return SCARLETT2_MIXER_MAX_VALUE;
}
/* Send a USB message to get the volumes for all inputs of one mix * and put the values into private->mix[]
*/ staticint scarlett2_usb_get_mix(struct usb_mixer_interface *mixer, int mix_num)
{ struct scarlett2_data *private = mixer->private_data;
int num_mixer_in = private->num_mix_in; int err, i, j;
for (i = 0, j = mix_num * num_mixer_in; i < num_mixer_in; i++, j++) private->mix[j] = scarlett2_mixer_value_to_db(
le16_to_cpu(data[i]));
return0;
}
/* Send a USB message to set the volumes for all inputs of one mix * (values obtained from private->mix[])
*/ staticint scarlett2_usb_set_mix(struct usb_mixer_interface *mixer, int mix_num)
{ struct scarlett2_data *private = mixer->private_data;
/* Convert a port number index (per info->port_count) to a hardware ID */ static u32 scarlett2_mux_src_num_to_id( constint port_count[][SCARLETT2_PORT_DIRNS], int num)
{ int port_type;
for (port_type = 0;
port_type < SCARLETT2_PORT_TYPE_COUNT;
port_type++) { if (num < port_count[port_type][SCARLETT2_PORT_IN]) return scarlett2_ports[port_type].id | num;
num -= port_count[port_type][SCARLETT2_PORT_IN];
}
/* Oops */ return0;
}
/* Convert a hardware ID to a port number index */ static u32 scarlett2_mux_id_to_num( constint port_count[][SCARLETT2_PORT_DIRNS], int direction, u32 id)
{ int port_type; int port_num = 0;
for (port_type = 0;
port_type < SCARLETT2_PORT_TYPE_COUNT;
port_type++) { int base = scarlett2_ports[port_type].id; int count = port_count[port_type][direction];
if (id >= base && id < base + count) return port_num + id - base;
port_num += count;
}
/* Oops */ return -1;
}
/* Convert one mux entry from the interface and load into private->mux[] */ staticvoid scarlett2_usb_populate_mux(struct scarlett2_data *private,
u32 mux_entry)
{ conststruct scarlett2_device_info *info = private->info; constint (*port_count)[SCARLETT2_PORT_DIRNS] = info->port_count;
/* Update the meter level map * * The meter level data from the interface (SCARLETT2_USB_GET_METER * request) is returned in mux_assignment order, but to avoid exposing * that to userspace, scarlett2_meter_ctl_get() rearranges the data * into scarlett2_ports order using the meter_level_map[] array which * is set up by this function. * * In addition, the meter level data values returned from the * interface are invalid for destinations where: * * - the source is "Off"; therefore we set those values to zero (map * value of 255) * * - the source is assigned to a previous (with respect to the * mux_assignment order) destination; therefore we set those values * to the value previously reported for that source
*/ staticvoid scarlett2_update_meter_level_map(struct scarlett2_data *private)
{ conststruct scarlett2_device_info *info = private->info; conststruct scarlett2_meter_entry *entry;
/* sources already assigned to a destination * value is 255 for None, otherwise the value of i * (index into array returned by * scarlett2_usb_get_meter_levels())
*/
u8 seen_src[SCARLETT2_MAX_SRCS] = { 1 };
u8 seen_src_value[SCARLETT2_MAX_SRCS] = { 255 };
/* index in meter_map[] order */ int i = 0;
/* go through the meter_map[] entries */ for (entry = info->meter_map;
entry->count;
entry++) {
/* fill in each meter_level_map[] entry */ int j, mux_idx;
/* convert mux_idx using line_out_unmap[] */ int map_mux_idx = (
info->line_out_remap_enable &&
mux_idx < private->num_line_out
) ? info->line_out_unmap[mux_idx]
: mux_idx;
/* check which source is connected, and if * that source is already connected elsewhere, * use that existing connection's destination * for this meter entry instead
*/ int mux_src = private->mux[mux_idx];
/* Send USB message to get mux inputs and then populate private->mux[] */ staticint scarlett2_usb_get_mux(struct usb_mixer_interface *mixer)
{ struct scarlett2_data *private = mixer->private_data; int count = private->num_mux_dsts; int err, i;
/* set mux settings for each rate */ for (table = 0; table < SCARLETT2_MUX_TABLES; table++) { conststruct scarlett2_mux_entry *entry;
/* i counts over the output array */ int i = 0, err;
req.num = cpu_to_le16(table);
/* loop through each entry */ for (entry = info->mux_assignment[table];
entry->count;
entry++) { int j; int port_type = entry->port_type; int port_idx = entry->start; int mux_idx = scarlett2_get_port_start_num(port_count,
SCARLETT2_PORT_OUT, port_type) + port_idx; int dst_id = scarlett2_ports[port_type].id + port_idx;
/* Empty slots */ if (!dst_id) { for (j = 0; j < entry->count; j++)
req.data[i++] = 0; continue;
}
/* Non-empty mux slots use the lower 12 bits * for the destination and next 12 bits for * the source
*/ for (j = 0; j < entry->count; j++) { int src_id = scarlett2_mux_src_num_to_id(
port_count, private->mux[mux_idx++]);
req.data[i++] = cpu_to_le32(dst_id |
src_id << 12);
dst_id++;
}
}
err = scarlett2_usb(mixer, SCARLETT2_USB_SET_MUX,
&req, (i + 1) * sizeof(u32),
NULL, 0); if (err < 0) return err;
}
scarlett2_update_meter_level_map(private);
return0;
}
/* Send USB message to get meter levels */ staticint scarlett2_usb_get_meter_levels(struct usb_mixer_interface *mixer,
u16 num_meters, u16 *levels)
{ struct {
__le16 pad;
__le16 num_meters;
__le32 magic;
} __packed req;
__le32 resp[SCARLETT2_MAX_METERS]; int i, err;
/* copy, convert to u16 */ for (i = 0; i < num_meters; i++)
levels[i] = le32_to_cpu(resp[i]);
return0;
}
/* For config items with mute=1, xor bits 0 & 1 together to get the * current/next state. This won't have any effect on values which are * only ever 0/1.
*/ static uint8_t scarlett2_decode_muteable(uint8_t v)
{ return (v ^ (v >> 1)) & 1;
}
/*** Control Functions ***/
/* helper function to create a new control */ staticint scarlett2_add_new_ctl(struct usb_mixer_interface *mixer, conststruct snd_kcontrol_new *ncontrol, int index, int channels, constchar *name, struct snd_kcontrol **kctl_return)
{ struct snd_kcontrol *kctl; struct usb_mixer_elem_info *elem; int err;
elem = kzalloc(sizeof(*elem), GFP_KERNEL); if (!elem) return -ENOMEM;
/* We set USB_MIXER_BESPOKEN type, so that the core USB mixer code * ignores them for resume and other operations. * Also, the head.id field is set to 0, as we don't use this field.
*/
elem->head.mixer = mixer;
elem->control = index;
elem->head.id = 0;
elem->channels = channels;
elem->val_type = USB_MIXER_BESPOKEN;
/* Update sync control after receiving notification that the status * has changed
*/ staticint scarlett2_update_sync(struct usb_mixer_interface *mixer)
{ struct scarlett2_data *private = mixer->private_data;
/* Forward declarations as phantom power and autogain can disable each other */ staticint scarlett2_check_input_phantom_updated(struct usb_mixer_interface *); staticint scarlett2_phantom_is_switching(struct scarlett2_data *, int);
/* Set the access mode of a control to read-only (val = 0) or * read-write (val = 1).
*/ staticvoid scarlett2_set_ctl_access(struct snd_kcontrol *kctl, int val)
{ if (val)
kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_WRITE; else
kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE;
}
/* Check if autogain is running on any input */ staticint scarlett2_autogain_is_running(struct scarlett2_data *private)
{ int i;
/* autogain_status[] is 0 if autogain is running */ for (i = 0; i < private->info->gain_input_count; i++) if (!private->autogain_status[i]) return1;
/* Translate autogain_switch and raw_autogain_status into * autogain_status. * * When autogain_switch[] is set, the status is the first * element in scarlett2_autogain_status_texts[] (Running). The * subsequent elements correspond to the status value from the * device (raw_autogain_status[]) + 1. The last element is * "Invalid", in case the device reports a status outside the * range of scarlett2_autogain_status_texts[].
*/ for (i = 0; i < info->gain_input_count; i++) if (private->autogain_switch[i]) private->autogain_status[i] = 0; elseif (raw_autogain_status[i] < private->num_autogain_status_texts - 1) private->autogain_status[i] =
raw_autogain_status[i] + 1; else private->autogain_status[i] = private->num_autogain_status_texts - 1;
for (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 (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) private->ag_targets[i] = -ag_target_values[i];
return0;
}
/* Update access mode for controls affected by autogain */ staticvoid scarlett2_autogain_update_access(struct usb_mixer_interface *mixer)
{ struct scarlett2_data *private = mixer->private_data; conststruct scarlett2_device_info *info = private->info; int val = !scarlett2_autogain_is_running(private); int 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; 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 * autogain runs.
*/ staticvoid scarlett2_autogain_notify_access(struct usb_mixer_interface *mixer)
{ struct snd_card *card = mixer->chip->card; struct scarlett2_data *private = mixer->private_data; conststruct scarlett2_device_info *info = private->info; int i;
if (scarlett2_has_config_item(private,
SCARLETT2_CONFIG_INPUT_SELECT_SWITCH))
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO,
&private->input_select_ctl->id); if (scarlett2_has_config_item(private,
SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) for (i = 0; i < info->gain_input_count; 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 * scarlett2_autogain_update_access() if autogain_updated is set.
*/ staticint scarlett2_check_autogain_updated( struct usb_mixer_interface *mixer)
{ struct scarlett2_data *private = mixer->private_data; int err;
if (!private->autogain_updated) return0;
err = scarlett2_update_autogain(mixer); if (err < 0) return err;
scarlett2_autogain_update_access(mixer);
return0;
}
/* If autogain_updated is set when a *_ctl_put() function for a * control that is meant to be read-only while autogain is running, * update the autogain status and access mode of affected controls. * Return -EPERM if autogain is running.
*/ staticint scarlett2_check_put_during_autogain( struct usb_mixer_interface *mixer)
{ int err = scarlett2_check_autogain_updated(mixer);
if (err < 0) return err;
if (scarlett2_autogain_is_running(mixer->private_data)) return -EPERM;
int inputs = private->info->gain_input_count; int i, err; char **values = kcalloc(inputs, sizeof(char *), GFP_KERNEL);
if (!values) return -ENOMEM;
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;
/* Loop through each input */ for (i = 0; i < inputs; i++) {
values[i] = kasprintf(GFP_KERNEL, "Input %d", i + 1); if (!values[i]) {
err = -ENOMEM; goto unlock;
}
}
err = snd_ctl_enum_info(uinfo, 1, i,
(constchar * const *)values);
unlock:
mutex_unlock(&private->data_mutex);
for (i = 0; i < inputs; i++)
kfree(values[i]);
kfree(values);
if (scarlett2_has_config_item(private,
SCARLETT2_CONFIG_SW_HW_SWITCH)) for (i = 0; i < private->num_line_out; i++) if (private->vol_sw_hw_switch[i]) private->vol[i] = private->master_vol;
}
if (scarlett2_has_config_item(private,
SCARLETT2_CONFIG_HEADPHONE_VOLUME)) {
err = scarlett2_usb_get_config(
mixer, SCARLETT2_CONFIG_HEADPHONE_VOLUME, 1, &vol); if (err < 0) return err;
/* Notify of write bit and possible value change */
snd_ctl_notify(card,
SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
&private->vol_ctls[index]->id);
snd_ctl_notify(card,
SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
&private->mute_ctls[index]->id);
}
staticint scarlett2_sw_hw_change(struct usb_mixer_interface *mixer, int ctl_index, int val)
{ struct scarlett2_data *private = mixer->private_data; int index = line_out_remap(private, ctl_index); int err;
private->vol_sw_hw_switch[index] = val;
/* Change access mode to RO (hardware controlled volume) * or RW (software controlled volume)
*/
scarlett2_vol_ctl_set_writable(mixer, ctl_index, !val);
int index = elem->control + info->level_input_first; 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->level_switch[index];
val = !!ucontrol->value.enumerated.item[0];
if (oval == val) goto unlock;
private->level_switch[index] = val;
/* To set the Gen 4 muteable controls, bit 1 gets set instead */ if (private->config_set->items[SCARLETT2_CONFIG_LEVEL_SWITCH].mute)
val = (!val) | 0x02;
/* Send switch change to the device */
err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_LEVEL_SWITCH,
index, val); if (err == 0)
err = 1;
int index = elem->control; int channel = index / SCARLETT2_COMPRESSOR_PARAM_COUNT; int param_index = index % SCARLETT2_COMPRESSOR_PARAM_COUNT; conststruct compressor_param *param = &compressor_params[param_index];
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;
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;
/* 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); if (err < 0) return err;
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];
}
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;
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;
if (scarlett2_has_config_item(private,
SCARLETT2_CONFIG_PHANTOM_PERSISTENCE)) {
err = scarlett2_usb_get_config(
mixer, SCARLETT2_CONFIG_PHANTOM_PERSISTENCE, 1, &private->phantom_persistence); if (err < 0) return err;
}
return0;
}
/* Check if phantom power on the given input is currently changing state */ staticint scarlett2_phantom_is_switching( struct scarlett2_data *private, int line_num)
{ conststruct scarlett2_device_info *info = private->info; int index = line_num / info->inputs_per_phantom;
/* Update autogain controls' access mode when phantom power changes state */ staticvoid scarlett2_phantom_update_access(struct usb_mixer_interface *mixer)
{ struct scarlett2_data *private = mixer->private_data; conststruct scarlett2_device_info *info = private->info; int i;
/* Disable autogain controls if phantom power is changing state */ for (i = 0; i < info->gain_input_count; i++) { int val = !scarlett2_phantom_is_switching(private, i);
/* when speaker switching gets enabled, switch the main/alt speakers * to HW volume and disable those controls
*/ staticint scarlett2_speaker_switch_enable(struct usb_mixer_interface *mixer)
{ struct snd_card *card = mixer->chip->card; struct scarlett2_data *private = mixer->private_data; int i, err;
for (i = 0; i < 4; i++) { int index = line_out_remap(private, i);
/* switch the main/alt speakers to HW volume */ if (!private->vol_sw_hw_switch[index]) {
err = scarlett2_sw_hw_change(private->mixer, i, 1); if (err < 0) return err;
}
/* disable the line out SW/HW switch */
scarlett2_sw_hw_ctl_ro(private, i);
snd_ctl_notify(card,
SNDRV_CTL_EVENT_MASK_VALUE |
SNDRV_CTL_EVENT_MASK_INFO,
&private->sw_hw_ctls[i]->id);
}
/* when the next monitor-other notify comes in, update the mux * configuration
*/ private->speaker_switching_switched = 1;
return0;
}
/* when speaker switching gets disabled, reenable the hw/sw controls * and invalidate the routing
*/ staticvoid scarlett2_speaker_switch_disable(struct usb_mixer_interface *mixer)
{ struct snd_card *card = mixer->chip->card; struct scarlett2_data *private = mixer->private_data; int i;
/* enable the line out SW/HW switch */ for (i = 0; i < 4; i++) {
scarlett2_sw_hw_ctl_rw(private, i);
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO,
&private->sw_hw_ctls[i]->id);
}
/* when the next monitor-other notify comes in, update the mux * configuration
*/ private->speaker_switching_switched = 1;
}
/* if speaker switching is enabled, select main or alt */
err = scarlett2_usb_set_config(
mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH, 0, val == 2); if (err < 0) goto unlock;
/* update controls if speaker switching gets enabled or disabled */ if (!oval && val)
err = scarlett2_speaker_switch_enable(mixer); elseif (oval && !val)
scarlett2_speaker_switch_disable(mixer);
/* if talkback is enabled, select main or alt */
err = scarlett2_usb_set_config(
mixer, SCARLETT2_CONFIG_MONITOR_OTHER_SWITCH, 1, val == 2); if (err == 0)
err = 1;
/* Remaining controls are only applicable if the device * has per-channel line-out volume controls.
*/ if (!scarlett2_has_config_item(private,
SCARLETT2_CONFIG_LINE_OUT_VOLUME)) return0;
/* Add volume controls */ for (i = 0; i < private->num_line_out; i++) { int index = line_out_remap(private, i);
/* Fader */ if (info->line_out_descrs[i])
snprintf(s, sizeof(s), "Line %02d (%s) Playback Volume",
i + 1, info->line_out_descrs[i]); else
snprintf(s, sizeof(s), "Line %02d Playback Volume",
i + 1);
err = scarlett2_add_new_ctl(mixer,
&scarlett2_line_out_volume_ctl,
i, 1, s, &private->vol_ctls[i]); if (err < 0) return err;
/* Mute Switch */
snprintf(s, sizeof(s), "Line %02d Mute Playback Switch",
i + 1);
err = scarlett2_add_new_ctl(mixer,
&scarlett2_mute_ctl,
i, 1, s,
&private->mute_ctls[i]); if (err < 0) return err;
/* SW/HW Switch */ if (scarlett2_has_config_item(private,
SCARLETT2_CONFIG_SW_HW_SWITCH)) {
/* Make the fader and mute controls read-only if the * SW/HW switch is set to HW
*/ if (private->vol_sw_hw_switch[index])
scarlett2_vol_ctl_set_writable(mixer, i, 0);
scnprintf(s, sizeof(s), "Line Out %02d Volume Control Playback Enum",
i + 1);
err = scarlett2_add_new_ctl(mixer,
&scarlett2_sw_hw_enum_ctl,
i, 1, s,
&private->sw_hw_ctls[i]); if (err < 0) return err;
/* Make the switch read-only if the line is * involved in speaker switching
*/ if (private->speaker_switching_switch && i < 4)
scarlett2_sw_hw_ctl_ro(private, i);
}
}
/* Add dim/mute controls */ if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_DIM_MUTE)) for (i = 0; i < SCARLETT2_DIM_MUTE_COUNT; i++) {
err = scarlett2_add_new_ctl(
mixer, &scarlett2_dim_mute_ctl,
i, 1, scarlett2_dim_mute_names[i],
&private->dim_mute_ctls[i]); if (err < 0) return err;
}
return0;
}
/*** Create the analogue input controls ***/
staticint scarlett2_add_dsp_ctls(struct usb_mixer_interface *mixer, int i)
{ struct scarlett2_data *private = mixer->private_data; conststruct scarlett2_device_info *info = private->info; int j, err; char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; constchar *compr_fmt = "Line In %d Compressor %s"; constchar *flt_switch_fmt = "Line In %d %s Filter Enable"; constchar *flt_fmt = "Line In %d %s Coefficients %d";
/* Add compressor controls */ for (j = 0; j < SCARLETT2_COMPRESSOR_PARAM_COUNT; j++) { conststruct 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 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++) {
scnprintf(s, sizeof(s), fmt,
i + 1 + info->phantom_first, "Phantom Power", "Switch");
err = scarlett2_add_new_ctl(
mixer, &scarlett2_phantom_ctl,
i, 1, s, &private->phantom_ctls[i]); if (err < 0) return err;
}
} elseif (info->inputs_per_phantom > 1) { for (i = 0; i < info->phantom_count; i++) { int from = i * info->inputs_per_phantom + 1; int to = (i + 1) * info->inputs_per_phantom;
scnprintf(s, sizeof(s), fmt2, from, to, "Phantom Power", "Switch");
err = scarlett2_add_new_ctl(
mixer, &scarlett2_phantom_ctl,
i, 1, s, &private->phantom_ctls[i]); if (err < 0) return err;
}
} if (info->phantom_count &&
scarlett2_has_config_item(private,
SCARLETT2_CONFIG_PHANTOM_PERSISTENCE)) {
err = scarlett2_add_new_ctl(
mixer, &scarlett2_phantom_persistence_ctl, 0, 1, "Phantom Power Persistence Capture Switch", NULL); if (err < 0) return err;
}
if (scarlett2_has_config_item(private,
SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) { for (i = 0; i < info->gain_input_count; i++) {
scnprintf(s, sizeof(s), "Line In %d Link Capture Switch", i + 1);
err = scarlett2_add_new_ctl(
mixer, &scarlett2_input_link_ctl,
i, 1, s, &private->input_link_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", "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])) {
if (!scarlett2_has_config_item(private,
SCARLETT2_CONFIG_POWER_EXT)) return0;
/* Add power status control */ return scarlett2_add_new_ctl(mixer, &scarlett2_power_status_ctl, 0, 1, "Power Status Card Enum",
&private->power_status_ctl);
}
for (i = 0; i < private->num_line_out; i++) if (private->vol_sw_hw_switch[line_out_remap(private, i)])
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
&private->vol_ctls[i]->id);
}
if (!scarlett2_has_config_item(private, SCARLETT2_CONFIG_SW_HW_SWITCH)) return;
private->dim_mute_updated = 1;
for (i = 0; i < SCARLETT2_DIM_MUTE_COUNT; i++)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
&private->dim_mute_ctls[i]->id);
for (i = 0; i < private->num_line_out; i++) if (private->vol_sw_hw_switch[line_out_remap(private, i)])
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
&private->mute_ctls[i]->id);
}
for (i = 0; i < info->gain_input_count; i++) {
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
&private->autogain_ctls[i]->id);
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
&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);
if (info->has_speaker_switching)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
&private->speaker_switching_ctl->id);
if (info->has_talkback)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
&private->talkback_ctl->id);
/* if speaker switching was recently enabled or disabled, * invalidate the dim/mute and mux enum controls
*/ if (private->speaker_switching_switched) { int i;
/* Handle acknowledgement that a command was received; let * scarlett2_usb() know that it can proceed
*/ staticvoid 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);
}
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; if (notifications->func)
notifications->func(mixer);
}
notifications++;
}
if (data)
usb_audio_warn(mixer->chip, "%s: Unhandled notification: 0x%08x\n",
__func__, data);
/* 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) { constchar * 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
*/ staticint 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;
/* 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;
/* 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);
return0;
}
/* Get the flash segment numbers for the App_Settings and App_Upgrade * segments and put them in the private data
*/ staticint scarlett2_get_flash_segment_nums(struct usb_mixer_interface *mixer)
{ struct scarlett2_data *private = mixer->private_data; int err, count, i;
/* 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;
}
return0;
}
/* Read configuration from the interface on start */ staticint scarlett2_read_configs(struct usb_mixer_interface *mixer)
{ struct scarlett2_data *private = mixer->private_data; conststruct 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); return0;
}
/* no other controls are created if MSD mode is on */ if (private->msd_switch) return0;
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)) return0;
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);
/* Initialise private data */
err = scarlett2_init_private(mixer, entry); if (err < 0) return err;
private = mixer->private_data;
/* Send proprietary USB initialisation sequence */
err = scarlett2_usb_init(mixer); if (err < 0) return err;
/* Get the upgrade & settings flash segment numbers */
err = scarlett2_get_flash_segment_nums(mixer); if (err < 0) return err;
/* Add firmware version control */
err = scarlett2_add_firmware_version_ctl(mixer); if (err < 0) return err;
/* Add minimum firmware version control */
err = scarlett2_add_min_firmware_version_ctl(mixer); if (err < 0) return err;
/* Read volume levels and controls from the interface */
err = scarlett2_read_configs(mixer); if (err < 0) return err;
/* Create the MSD control */
err = scarlett2_add_msd_ctl(mixer); if (err < 0) return err;
/* If MSD mode is enabled, or if the firmware version is too * old, don't create any other controls
*/ if (private->msd_switch || private->firmware_version < private->info->min_firmware_version) return0;
/* Create the analogue output controls */
err = scarlett2_add_line_out_ctls(mixer); if (err < 0) return err;
/* Create the analogue input controls */
err = scarlett2_add_line_in_ctls(mixer); if (err < 0) return err;
/* Create the input, output, and mixer mux input selections */
err = scarlett2_add_mux_enums(mixer); if (err < 0) return err;
/* Create the matrix mixer controls */
err = scarlett2_add_mixer_ctls(mixer); if (err < 0) return err;
/* Create the level meter controls */
err = scarlett2_add_meter_ctl(mixer); if (err < 0) return err;
/* Create the sync control */
err = scarlett2_add_sync_ctl(mixer); if (err < 0) return err;
/* Create the direct monitor control(s) */
err = scarlett2_add_direct_monitor_ctls(mixer); if (err < 0) return err;
/* Create the speaker switching control */
err = scarlett2_add_speaker_switch_ctl(mixer); if (err < 0) return err;
/* Create the talkback controls */
err = scarlett2_add_talkback_ctls(mixer); if (err < 0) return err;
/* Create the standalone control */
err = scarlett2_add_standalone_ctl(mixer); if (err < 0) return err;
/* Create the power status control */
err = scarlett2_add_power_status_ctl(mixer); 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.
*/ if (private->info->gain_input_count) {
scarlett2_autogain_update_access(mixer);
scarlett2_phantom_update_access(mixer);
}
/* Start handling all notifications */ private->running = 2;
return0;
}
/*** hwdep interface ***/
/* Set private->hwdep_in_use; prevents access to the ALSA controls * while doing a config erase/firmware upgrade.
*/ staticvoid scarlett2_lock(struct scarlett2_data *private)
{
mutex_lock(&private->data_mutex); private->hwdep_in_use = 1;
mutex_unlock(&private->data_mutex);
}
/* Call SCARLETT2_USB_GET_ERASE to get the erase progress */ staticint scarlett2_get_erase_progress(struct usb_mixer_interface *mixer)
{ struct scarlett2_data *private = mixer->private_data; int segment_id, segment_num, err;
u8 erase_resp;
/* Repeatedly call scarlett2_get_erase_progress() until it returns * 0xff (erase complete) or we've waited 10 seconds (it usually takes * <3 seconds).
*/ staticint scarlett2_wait_for_erase(struct usb_mixer_interface *mixer)
{ int i, err;
for (i = 0; i < 100; i++) {
err = scarlett2_get_erase_progress(mixer); if (err < 0) return err;
if (err == 0xff) return0;
msleep(100);
}
return -ETIMEDOUT;
}
/* Reboot the device; wait for the erase to complete if one is in * progress.
*/ staticint scarlett2_reboot(struct usb_mixer_interface *mixer)
{ struct scarlett2_data *private = mixer->private_data;
if (private->flash_write_state ==
SCARLETT2_FLASH_WRITE_STATE_ERASING) { int err = scarlett2_wait_for_erase(mixer);
/* If erasing, wait for it to complete */ if (private->flash_write_state == SCARLETT2_FLASH_WRITE_STATE_ERASING) { int err = scarlett2_wait_for_erase(mixer);
if (err < 0) return err;
}
/* Save the selected segment ID and set the state to SELECTED */ private->selected_flash_segment_id = segment_id; private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_SELECTED;
if (copy_to_user((void __user *)arg, &progress, sizeof(progress))) return -EFAULT;
/* If the erase is complete, change the state from ERASING to * WRITE.
*/ if (progress.progress == 0xff) private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_WRITE;
/* If erasing, wait for it to complete */ if (private->flash_write_state ==
SCARLETT2_FLASH_WRITE_STATE_ERASING) { int err = scarlett2_wait_for_erase(mixer);
if (err < 0) return err;
}
/* Set the state to IDLE */ private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_IDLE;
/* Calculate the maximum permitted in data[] */ const size_t max_data_size = SCARLETT2_FLASH_RW_MAX -
offsetof(typeof(*req), data);
/* If erasing, wait for it to complete */ if (private->flash_write_state ==
SCARLETT2_FLASH_WRITE_STATE_ERASING) {
err = scarlett2_wait_for_erase(mixer); if (err < 0) return err; private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_WRITE;
/* Check that an erase has been done & completed */
} elseif (private->flash_write_state !=
SCARLETT2_FLASH_WRITE_STATE_WRITE) { return -EINVAL;
}
/* Check that we're writing to the upgrade firmware */
segment_id = private->selected_flash_segment_id; if (segment_id != SCARLETT2_SEGMENT_ID_FIRMWARE) return -EINVAL;
/* Return from the SELECTED or WRITE state to IDLE. * The ERASING state is left as-is, and checked on next open.
*/ if (private && private->hwdep_in_use && private->flash_write_state != SCARLETT2_FLASH_WRITE_STATE_ERASING) private->flash_write_state = SCARLETT2_FLASH_WRITE_STATE_IDLE;
return0;
}
staticint scarlett2_hwdep_init(struct usb_mixer_interface *mixer)
{ struct snd_hwdep *hw; int err;
resp_buf = kmalloc(block_size, GFP_KERNEL); if (!resp_buf) return -ENOMEM;
while (count > 0) { /* SCARLETT2_USB_GET_DEVMAP reads only on block boundaries, * so we need to read a whole block and copy the requested * chunk to userspace.
*/
__le32 req; int err;
/* offset within the block that we're reading */
size_t offset = pos % block_size;
/* read_size is block_size except for the last block */
size_t block_start = pos - offset;
size_t read_size = min_t(size_t,
block_size,
entry->size - block_start);
/* size of the chunk to copy to userspace */
size_t copy_size = min_t(size_t, count, read_size - offset);
/* If the device doesn't support the DEVMAP commands, don't * create the /proc/asound/cardX/scarlett.json.zlib entry
*/ if (!info->has_devmap) return0;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.278Bemerkung:
(vorverarbeitet am 2026-06-07)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.