1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
276b188c4SChris J Arges /*
376b188c4SChris J Arges * Scarlett Driver for ALSA
476b188c4SChris J Arges *
576b188c4SChris J Arges * Copyright (c) 2013 by Tobias Hoffmann
676b188c4SChris J Arges * Copyright (c) 2013 by Robin Gareus <robin at gareus.org>
776b188c4SChris J Arges * Copyright (c) 2002 by Takashi Iwai <tiwai at suse.de>
876b188c4SChris J Arges * Copyright (c) 2014 by Chris J Arges <chris.j.arges at canonical.com>
976b188c4SChris J Arges *
1076b188c4SChris J Arges * Many codes borrowed from audio.c by
1176b188c4SChris J Arges * Alan Cox (alan at lxorguk.ukuu.org.uk)
1276b188c4SChris J Arges * Thomas Sailer (sailer at ife.ee.ethz.ch)
1376b188c4SChris J Arges *
1476b188c4SChris J Arges * Code cleanup:
1576b188c4SChris J Arges * David Henningsson <david.henningsson at canonical.com>
1676b188c4SChris J Arges */
1776b188c4SChris J Arges
1876b188c4SChris J Arges /*
1976b188c4SChris J Arges * Rewritten and extended to support more models, e.g. Scarlett 18i8.
2076b188c4SChris J Arges *
2176b188c4SChris J Arges * Auto-detection via UAC2 is not feasible to properly discover the vast
2276b188c4SChris J Arges * majority of features. It's related to both Linux/ALSA's UAC2 as well as
2376b188c4SChris J Arges * Focusrite's implementation of it. Eventually quirks may be sufficient but
24*ff630b6aSgushengxian * right now it's a major headache to work around these things.
2576b188c4SChris J Arges *
2676b188c4SChris J Arges * NB. Neither the OSX nor the win driver provided by Focusrite performs
2776b188c4SChris J Arges * discovery, they seem to operate the same as this driver.
2876b188c4SChris J Arges */
2976b188c4SChris J Arges
3076b188c4SChris J Arges /* Mixer Interface for the Focusrite Scarlett 18i6 audio interface.
3176b188c4SChris J Arges *
3276b188c4SChris J Arges * The protocol was reverse engineered by looking at communication between
3376b188c4SChris J Arges * Scarlett MixControl (v 1.2.128.0) and the Focusrite(R) Scarlett 18i6
3476b188c4SChris J Arges * (firmware v305) using wireshark and usbmon in January 2013.
3576b188c4SChris J Arges * Extended in July 2013.
3676b188c4SChris J Arges *
3776b188c4SChris J Arges * this mixer gives complete access to all features of the device:
3876b188c4SChris J Arges * - change Impedance of inputs (Line-in, Mic / Instrument, Hi-Z)
3976b188c4SChris J Arges * - select clock source
4076b188c4SChris J Arges * - dynamic input to mixer-matrix assignment
4176b188c4SChris J Arges * - 18 x 6 mixer-matrix gain stages
4276b188c4SChris J Arges * - bus routing & volume control
4376b188c4SChris J Arges * - automatic re-initialization on connect if device was power-cycled
4476b188c4SChris J Arges *
4576b188c4SChris J Arges * USB URB commands overview (bRequest = 0x01 = UAC2_CS_CUR)
4676b188c4SChris J Arges * wIndex
4776b188c4SChris J Arges * 0x01 Analog Input line/instrument impedance switch, wValue=0x0901 +
4876b188c4SChris J Arges * channel, data=Line/Inst (2bytes)
4976b188c4SChris J Arges * pad (-10dB) switch, wValue=0x0b01 + channel, data=Off/On (2bytes)
5076b188c4SChris J Arges * ?? wValue=0x0803/04, ?? (2bytes)
5176b188c4SChris J Arges * 0x0a Master Volume, wValue=0x0200+bus[0:all + only 1..4?] data(2bytes)
5276b188c4SChris J Arges * Bus Mute/Unmute wValue=0x0100+bus[0:all + only 1..4?], data(2bytes)
5376b188c4SChris J Arges * 0x28 Clock source, wValue=0x0100, data={1:int,2:spdif,3:adat} (1byte)
5476b188c4SChris J Arges * 0x29 Set Sample-rate, wValue=0x0100, data=sample-rate(4bytes)
5576b188c4SChris J Arges * 0x32 Mixer mux, wValue=0x0600 + mixer-channel, data=input-to-connect(2bytes)
5676b188c4SChris J Arges * 0x33 Output mux, wValue=bus, data=input-to-connect(2bytes)
5776b188c4SChris J Arges * 0x34 Capture mux, wValue=0...18, data=input-to-connect(2bytes)
5876b188c4SChris J Arges * 0x3c Matrix Mixer gains, wValue=mixer-node data=gain(2bytes)
5976b188c4SChris J Arges * ?? [sometimes](4bytes, e.g 0x000003be 0x000003bf ...03ff)
6076b188c4SChris J Arges *
6176b188c4SChris J Arges * USB reads: (i.e. actually issued by original software)
6276b188c4SChris J Arges * 0x01 wValue=0x0901+channel (1byte!!), wValue=0x0b01+channed (1byte!!)
6376b188c4SChris J Arges * 0x29 wValue=0x0100 sample-rate(4bytes)
6476b188c4SChris J Arges * wValue=0x0200 ?? 1byte (only once)
6576b188c4SChris J Arges * 0x2a wValue=0x0100 ?? 4bytes, sample-rate2 ??
6676b188c4SChris J Arges *
6776b188c4SChris J Arges * USB reads with bRequest = 0x03 = UAC2_CS_MEM
6876b188c4SChris J Arges * 0x3c wValue=0x0002 1byte: sync status (locked=1)
6976b188c4SChris J Arges * wValue=0x0000 18*2byte: peak meter (inputs)
7076b188c4SChris J Arges * wValue=0x0001 8(?)*2byte: peak meter (mix)
7176b188c4SChris J Arges * wValue=0x0003 6*2byte: peak meter (pcm/daw)
7276b188c4SChris J Arges *
7376b188c4SChris J Arges * USB write with bRequest = 0x03
7476b188c4SChris J Arges * 0x3c Save settings to hardware: wValue=0x005a, data=0xa5
7576b188c4SChris J Arges *
7676b188c4SChris J Arges *
7776b188c4SChris J Arges * <ditaa>
7876b188c4SChris J Arges * /--------------\ 18chn 6chn /--------------\
7976b188c4SChris J Arges * | Hardware in +--+-------\ /------+--+ ALSA PCM out |
8076b188c4SChris J Arges * \--------------/ | | | | \--------------/
8176b188c4SChris J Arges * | | | |
8276b188c4SChris J Arges * | v v |
8376b188c4SChris J Arges * | +---------------+ |
8476b188c4SChris J Arges * | \ Matrix Mux / |
8576b188c4SChris J Arges * | +-----+-----+ |
8676b188c4SChris J Arges * | | |
8776b188c4SChris J Arges * | | 18chn |
8876b188c4SChris J Arges * | v |
8976b188c4SChris J Arges * | +-----------+ |
9076b188c4SChris J Arges * | | Mixer | |
9176b188c4SChris J Arges * | | Matrix | |
9276b188c4SChris J Arges * | | | |
9376b188c4SChris J Arges * | | 18x6 Gain | |
9476b188c4SChris J Arges * | | stages | |
9576b188c4SChris J Arges * | +-----+-----+ |
9676b188c4SChris J Arges * | | |
9776b188c4SChris J Arges * | | |
9876b188c4SChris J Arges * | 18chn | 6chn | 6chn
9976b188c4SChris J Arges * v v v
10076b188c4SChris J Arges * =========================
10176b188c4SChris J Arges * +---------------+ +--—------------+
10276b188c4SChris J Arges * \ Output Mux / \ Capture Mux /
10376b188c4SChris J Arges * +-----+-----+ +-----+-----+
10476b188c4SChris J Arges * | |
10576b188c4SChris J Arges * | 6chn |
10676b188c4SChris J Arges * v |
10776b188c4SChris J Arges * +-------------+ |
10876b188c4SChris J Arges * | Master Gain | |
10976b188c4SChris J Arges * +------+------+ |
11076b188c4SChris J Arges * | |
11176b188c4SChris J Arges * | 6chn | 18chn
11276b188c4SChris J Arges * | (3 stereo pairs) |
11376b188c4SChris J Arges * /--------------\ | | /--------------\
11476b188c4SChris J Arges * | Hardware out |<--/ \-->| ALSA PCM in |
11576b188c4SChris J Arges * \--------------/ \--------------/
11676b188c4SChris J Arges * </ditaa>
11776b188c4SChris J Arges *
11876b188c4SChris J Arges */
11976b188c4SChris J Arges
12076b188c4SChris J Arges #include <linux/slab.h>
12176b188c4SChris J Arges #include <linux/usb.h>
12276b188c4SChris J Arges #include <linux/usb/audio-v2.h>
12376b188c4SChris J Arges
12476b188c4SChris J Arges #include <sound/core.h>
12576b188c4SChris J Arges #include <sound/control.h>
12676b188c4SChris J Arges #include <sound/tlv.h>
12776b188c4SChris J Arges
12876b188c4SChris J Arges #include "usbaudio.h"
12976b188c4SChris J Arges #include "mixer.h"
13076b188c4SChris J Arges #include "helper.h"
13176b188c4SChris J Arges #include "power.h"
13276b188c4SChris J Arges
13376b188c4SChris J Arges #include "mixer_scarlett.h"
13476b188c4SChris J Arges
13576b188c4SChris J Arges /* some gui mixers can't handle negative ctl values */
13676b188c4SChris J Arges #define SND_SCARLETT_LEVEL_BIAS 128
13776b188c4SChris J Arges #define SND_SCARLETT_MATRIX_IN_MAX 18
13876b188c4SChris J Arges #define SND_SCARLETT_CONTROLS_MAX 10
13976b188c4SChris J Arges #define SND_SCARLETT_OFFSETS_MAX 5
14076b188c4SChris J Arges
14176b188c4SChris J Arges enum {
14276b188c4SChris J Arges SCARLETT_OUTPUTS,
14376b188c4SChris J Arges SCARLETT_SWITCH_IMPEDANCE,
14476b188c4SChris J Arges SCARLETT_SWITCH_PAD,
145bf2aa5caSJens Verwiebe SCARLETT_SWITCH_GAIN,
14676b188c4SChris J Arges };
14776b188c4SChris J Arges
14876b188c4SChris J Arges enum {
14976b188c4SChris J Arges SCARLETT_OFFSET_PCM = 0,
15076b188c4SChris J Arges SCARLETT_OFFSET_ANALOG = 1,
15176b188c4SChris J Arges SCARLETT_OFFSET_SPDIF = 2,
15276b188c4SChris J Arges SCARLETT_OFFSET_ADAT = 3,
15376b188c4SChris J Arges SCARLETT_OFFSET_MIX = 4,
15476b188c4SChris J Arges };
15576b188c4SChris J Arges
15676b188c4SChris J Arges struct scarlett_mixer_elem_enum_info {
15776b188c4SChris J Arges int start;
15876b188c4SChris J Arges int len;
15976b188c4SChris J Arges int offsets[SND_SCARLETT_OFFSETS_MAX];
16076b188c4SChris J Arges char const * const *names;
16176b188c4SChris J Arges };
16276b188c4SChris J Arges
16376b188c4SChris J Arges struct scarlett_mixer_control {
16476b188c4SChris J Arges unsigned char num;
16576b188c4SChris J Arges unsigned char type;
16676b188c4SChris J Arges const char *name;
16776b188c4SChris J Arges };
16876b188c4SChris J Arges
16976b188c4SChris J Arges struct scarlett_device_info {
17076b188c4SChris J Arges int matrix_in;
17176b188c4SChris J Arges int matrix_out;
17276b188c4SChris J Arges int input_len;
17376b188c4SChris J Arges int output_len;
17476b188c4SChris J Arges
17576b188c4SChris J Arges struct scarlett_mixer_elem_enum_info opt_master;
17676b188c4SChris J Arges struct scarlett_mixer_elem_enum_info opt_matrix;
17776b188c4SChris J Arges
17876b188c4SChris J Arges /* initial values for matrix mux */
17976b188c4SChris J Arges int matrix_mux_init[SND_SCARLETT_MATRIX_IN_MAX];
18076b188c4SChris J Arges
18176b188c4SChris J Arges int num_controls; /* number of items in controls */
18276b188c4SChris J Arges const struct scarlett_mixer_control controls[SND_SCARLETT_CONTROLS_MAX];
18376b188c4SChris J Arges };
18476b188c4SChris J Arges
18576b188c4SChris J Arges /********************** Enum Strings *************************/
18676b188c4SChris J Arges
18776b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_pad = {
18876b188c4SChris J Arges .start = 0,
18976b188c4SChris J Arges .len = 2,
19076b188c4SChris J Arges .offsets = {},
19176b188c4SChris J Arges .names = (char const * const []){
19276b188c4SChris J Arges "0dB", "-10dB"
19376b188c4SChris J Arges }
19476b188c4SChris J Arges };
19576b188c4SChris J Arges
196bf2aa5caSJens Verwiebe static const struct scarlett_mixer_elem_enum_info opt_gain = {
197bf2aa5caSJens Verwiebe .start = 0,
198bf2aa5caSJens Verwiebe .len = 2,
199bf2aa5caSJens Verwiebe .offsets = {},
200bf2aa5caSJens Verwiebe .names = (char const * const []){
201bf2aa5caSJens Verwiebe "Lo", "Hi"
202bf2aa5caSJens Verwiebe }
203bf2aa5caSJens Verwiebe };
204bf2aa5caSJens Verwiebe
20576b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_impedance = {
20676b188c4SChris J Arges .start = 0,
20776b188c4SChris J Arges .len = 2,
20876b188c4SChris J Arges .offsets = {},
20976b188c4SChris J Arges .names = (char const * const []){
21076b188c4SChris J Arges "Line", "Hi-Z"
21176b188c4SChris J Arges }
21276b188c4SChris J Arges };
21376b188c4SChris J Arges
21476b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_clock = {
21576b188c4SChris J Arges .start = 1,
21676b188c4SChris J Arges .len = 3,
21776b188c4SChris J Arges .offsets = {},
21876b188c4SChris J Arges .names = (char const * const []){
21976b188c4SChris J Arges "Internal", "SPDIF", "ADAT"
22076b188c4SChris J Arges }
22176b188c4SChris J Arges };
22276b188c4SChris J Arges
22376b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_sync = {
22476b188c4SChris J Arges .start = 0,
22576b188c4SChris J Arges .len = 2,
22676b188c4SChris J Arges .offsets = {},
22776b188c4SChris J Arges .names = (char const * const []){
22876b188c4SChris J Arges "No Lock", "Locked"
22976b188c4SChris J Arges }
23076b188c4SChris J Arges };
23176b188c4SChris J Arges
scarlett_ctl_switch_info(struct snd_kcontrol * kctl,struct snd_ctl_elem_info * uinfo)23276b188c4SChris J Arges static int scarlett_ctl_switch_info(struct snd_kcontrol *kctl,
23376b188c4SChris J Arges struct snd_ctl_elem_info *uinfo)
23476b188c4SChris J Arges {
23576b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data;
23676b188c4SChris J Arges
23776b188c4SChris J Arges uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
23876b188c4SChris J Arges uinfo->count = elem->channels;
23976b188c4SChris J Arges uinfo->value.integer.min = 0;
24076b188c4SChris J Arges uinfo->value.integer.max = 1;
24176b188c4SChris J Arges return 0;
24276b188c4SChris J Arges }
24376b188c4SChris J Arges
scarlett_ctl_switch_get(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)24476b188c4SChris J Arges static int scarlett_ctl_switch_get(struct snd_kcontrol *kctl,
24576b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol)
24676b188c4SChris J Arges {
24776b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data;
24876b188c4SChris J Arges int i, err, val;
24976b188c4SChris J Arges
25076b188c4SChris J Arges for (i = 0; i < elem->channels; i++) {
25176b188c4SChris J Arges err = snd_usb_get_cur_mix_value(elem, i, i, &val);
25276b188c4SChris J Arges if (err < 0)
25376b188c4SChris J Arges return err;
25476b188c4SChris J Arges
25576b188c4SChris J Arges val = !val; /* invert mute logic for mixer */
25676b188c4SChris J Arges ucontrol->value.integer.value[i] = val;
25776b188c4SChris J Arges }
25876b188c4SChris J Arges
25976b188c4SChris J Arges return 0;
26076b188c4SChris J Arges }
26176b188c4SChris J Arges
scarlett_ctl_switch_put(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)26276b188c4SChris J Arges static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl,
26376b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol)
26476b188c4SChris J Arges {
26576b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data;
26676b188c4SChris J Arges int i, changed = 0;
26776b188c4SChris J Arges int err, oval, val;
26876b188c4SChris J Arges
26976b188c4SChris J Arges for (i = 0; i < elem->channels; i++) {
27076b188c4SChris J Arges err = snd_usb_get_cur_mix_value(elem, i, i, &oval);
27176b188c4SChris J Arges if (err < 0)
27276b188c4SChris J Arges return err;
27376b188c4SChris J Arges
27476b188c4SChris J Arges val = ucontrol->value.integer.value[i];
27576b188c4SChris J Arges val = !val;
27676b188c4SChris J Arges if (oval != val) {
27776b188c4SChris J Arges err = snd_usb_set_cur_mix_value(elem, i, i, val);
27876b188c4SChris J Arges if (err < 0)
27976b188c4SChris J Arges return err;
28076b188c4SChris J Arges
28176b188c4SChris J Arges changed = 1;
28276b188c4SChris J Arges }
28376b188c4SChris J Arges }
28476b188c4SChris J Arges
28576b188c4SChris J Arges return changed;
28676b188c4SChris J Arges }
28776b188c4SChris J Arges
scarlett_ctl_resume(struct usb_mixer_elem_list * list)288b61f90eaSTakashi Iwai static int scarlett_ctl_resume(struct usb_mixer_elem_list *list)
289b61f90eaSTakashi Iwai {
2908c558076STakashi Iwai struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list);
291b61f90eaSTakashi Iwai int i;
292b61f90eaSTakashi Iwai
293b61f90eaSTakashi Iwai for (i = 0; i < elem->channels; i++)
294b61f90eaSTakashi Iwai if (elem->cached & (1 << i))
295b61f90eaSTakashi Iwai snd_usb_set_cur_mix_value(elem, i, i,
296b61f90eaSTakashi Iwai elem->cache_val[i]);
297b61f90eaSTakashi Iwai return 0;
298b61f90eaSTakashi Iwai }
299b61f90eaSTakashi Iwai
scarlett_ctl_info(struct snd_kcontrol * kctl,struct snd_ctl_elem_info * uinfo)30076b188c4SChris J Arges static int scarlett_ctl_info(struct snd_kcontrol *kctl,
30176b188c4SChris J Arges struct snd_ctl_elem_info *uinfo)
30276b188c4SChris J Arges {
30376b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data;
30476b188c4SChris J Arges
30576b188c4SChris J Arges uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
30676b188c4SChris J Arges uinfo->count = elem->channels;
30776b188c4SChris J Arges uinfo->value.integer.min = 0;
30876b188c4SChris J Arges uinfo->value.integer.max = (int)kctl->private_value +
30976b188c4SChris J Arges SND_SCARLETT_LEVEL_BIAS;
31076b188c4SChris J Arges uinfo->value.integer.step = 1;
31176b188c4SChris J Arges return 0;
31276b188c4SChris J Arges }
31376b188c4SChris J Arges
scarlett_ctl_get(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)31476b188c4SChris J Arges static int scarlett_ctl_get(struct snd_kcontrol *kctl,
31576b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol)
31676b188c4SChris J Arges {
31776b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data;
31876b188c4SChris J Arges int i, err, val;
31976b188c4SChris J Arges
32076b188c4SChris J Arges for (i = 0; i < elem->channels; i++) {
32176b188c4SChris J Arges err = snd_usb_get_cur_mix_value(elem, i, i, &val);
32276b188c4SChris J Arges if (err < 0)
32376b188c4SChris J Arges return err;
32476b188c4SChris J Arges
32576b188c4SChris J Arges val = clamp(val / 256, -128, (int)kctl->private_value) +
32676b188c4SChris J Arges SND_SCARLETT_LEVEL_BIAS;
32776b188c4SChris J Arges ucontrol->value.integer.value[i] = val;
32876b188c4SChris J Arges }
32976b188c4SChris J Arges
33076b188c4SChris J Arges return 0;
33176b188c4SChris J Arges }
33276b188c4SChris J Arges
scarlett_ctl_put(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)33376b188c4SChris J Arges static int scarlett_ctl_put(struct snd_kcontrol *kctl,
33476b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol)
33576b188c4SChris J Arges {
33676b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data;
33776b188c4SChris J Arges int i, changed = 0;
33876b188c4SChris J Arges int err, oval, val;
33976b188c4SChris J Arges
34076b188c4SChris J Arges for (i = 0; i < elem->channels; i++) {
34176b188c4SChris J Arges err = snd_usb_get_cur_mix_value(elem, i, i, &oval);
34276b188c4SChris J Arges if (err < 0)
34376b188c4SChris J Arges return err;
34476b188c4SChris J Arges
34576b188c4SChris J Arges val = ucontrol->value.integer.value[i] -
34676b188c4SChris J Arges SND_SCARLETT_LEVEL_BIAS;
34776b188c4SChris J Arges val = val * 256;
34876b188c4SChris J Arges if (oval != val) {
34976b188c4SChris J Arges err = snd_usb_set_cur_mix_value(elem, i, i, val);
35076b188c4SChris J Arges if (err < 0)
35176b188c4SChris J Arges return err;
35276b188c4SChris J Arges
35376b188c4SChris J Arges changed = 1;
35476b188c4SChris J Arges }
35576b188c4SChris J Arges }
35676b188c4SChris J Arges
35776b188c4SChris J Arges return changed;
35876b188c4SChris J Arges }
35976b188c4SChris J Arges
scarlett_generate_name(int i,char * dst,int offsets[])36076b188c4SChris J Arges static void scarlett_generate_name(int i, char *dst, int offsets[])
36176b188c4SChris J Arges {
36276b188c4SChris J Arges if (i > offsets[SCARLETT_OFFSET_MIX])
36376b188c4SChris J Arges sprintf(dst, "Mix %c",
36476b188c4SChris J Arges 'A'+(i - offsets[SCARLETT_OFFSET_MIX] - 1));
36576b188c4SChris J Arges else if (i > offsets[SCARLETT_OFFSET_ADAT])
36676b188c4SChris J Arges sprintf(dst, "ADAT %d", i - offsets[SCARLETT_OFFSET_ADAT]);
36776b188c4SChris J Arges else if (i > offsets[SCARLETT_OFFSET_SPDIF])
36876b188c4SChris J Arges sprintf(dst, "SPDIF %d", i - offsets[SCARLETT_OFFSET_SPDIF]);
36976b188c4SChris J Arges else if (i > offsets[SCARLETT_OFFSET_ANALOG])
37076b188c4SChris J Arges sprintf(dst, "Analog %d", i - offsets[SCARLETT_OFFSET_ANALOG]);
37176b188c4SChris J Arges else if (i > offsets[SCARLETT_OFFSET_PCM])
37276b188c4SChris J Arges sprintf(dst, "PCM %d", i - offsets[SCARLETT_OFFSET_PCM]);
37376b188c4SChris J Arges else
37476b188c4SChris J Arges sprintf(dst, "Off");
37576b188c4SChris J Arges }
37676b188c4SChris J Arges
scarlett_ctl_enum_dynamic_info(struct snd_kcontrol * kctl,struct snd_ctl_elem_info * uinfo)37776b188c4SChris J Arges static int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl,
37876b188c4SChris J Arges struct snd_ctl_elem_info *uinfo)
37976b188c4SChris J Arges {
38076b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data;
38176b188c4SChris J Arges struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
38276b188c4SChris J Arges unsigned int items = opt->len;
38376b188c4SChris J Arges
38476b188c4SChris J Arges uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
38576b188c4SChris J Arges uinfo->count = elem->channels;
38676b188c4SChris J Arges uinfo->value.enumerated.items = items;
38776b188c4SChris J Arges
38876b188c4SChris J Arges if (uinfo->value.enumerated.item >= items)
38976b188c4SChris J Arges uinfo->value.enumerated.item = items - 1;
39076b188c4SChris J Arges
39176b188c4SChris J Arges /* generate name dynamically based on item number and offset info */
39276b188c4SChris J Arges scarlett_generate_name(uinfo->value.enumerated.item,
39376b188c4SChris J Arges uinfo->value.enumerated.name,
39476b188c4SChris J Arges opt->offsets);
39576b188c4SChris J Arges
39676b188c4SChris J Arges return 0;
39776b188c4SChris J Arges }
39876b188c4SChris J Arges
scarlett_ctl_enum_info(struct snd_kcontrol * kctl,struct snd_ctl_elem_info * uinfo)39976b188c4SChris J Arges static int scarlett_ctl_enum_info(struct snd_kcontrol *kctl,
40076b188c4SChris J Arges struct snd_ctl_elem_info *uinfo)
40176b188c4SChris J Arges {
40276b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data;
40376b188c4SChris J Arges struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
40476b188c4SChris J Arges
40576b188c4SChris J Arges return snd_ctl_enum_info(uinfo, elem->channels, opt->len,
40676b188c4SChris J Arges (const char * const *)opt->names);
40776b188c4SChris J Arges }
40876b188c4SChris J Arges
scarlett_ctl_enum_get(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)40976b188c4SChris J Arges static int scarlett_ctl_enum_get(struct snd_kcontrol *kctl,
41076b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol)
41176b188c4SChris J Arges {
41276b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data;
41376b188c4SChris J Arges struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
41476b188c4SChris J Arges int err, val;
41576b188c4SChris J Arges
41676b188c4SChris J Arges err = snd_usb_get_cur_mix_value(elem, 0, 0, &val);
41776b188c4SChris J Arges if (err < 0)
41876b188c4SChris J Arges return err;
41976b188c4SChris J Arges
42076b188c4SChris J Arges val = clamp(val - opt->start, 0, opt->len-1);
42176b188c4SChris J Arges
42276b188c4SChris J Arges ucontrol->value.enumerated.item[0] = val;
42376b188c4SChris J Arges
42476b188c4SChris J Arges return 0;
42576b188c4SChris J Arges }
42676b188c4SChris J Arges
scarlett_ctl_enum_put(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)42776b188c4SChris J Arges static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl,
42876b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol)
42976b188c4SChris J Arges {
43076b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data;
43176b188c4SChris J Arges struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
43276b188c4SChris J Arges int err, oval, val;
43376b188c4SChris J Arges
43476b188c4SChris J Arges err = snd_usb_get_cur_mix_value(elem, 0, 0, &oval);
43576b188c4SChris J Arges if (err < 0)
43676b188c4SChris J Arges return err;
43776b188c4SChris J Arges
43876b188c4SChris J Arges val = ucontrol->value.integer.value[0];
43976b188c4SChris J Arges val = val + opt->start;
44076b188c4SChris J Arges if (val != oval) {
44176b188c4SChris J Arges snd_usb_set_cur_mix_value(elem, 0, 0, val);
44276b188c4SChris J Arges return 1;
44376b188c4SChris J Arges }
44476b188c4SChris J Arges return 0;
44576b188c4SChris J Arges }
44676b188c4SChris J Arges
scarlett_ctl_enum_resume(struct usb_mixer_elem_list * list)447b61f90eaSTakashi Iwai static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list)
448b61f90eaSTakashi Iwai {
4498c558076STakashi Iwai struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list);
450b61f90eaSTakashi Iwai
451b61f90eaSTakashi Iwai if (elem->cached)
452b61f90eaSTakashi Iwai snd_usb_set_cur_mix_value(elem, 0, 0, *elem->cache_val);
453b61f90eaSTakashi Iwai return 0;
454b61f90eaSTakashi Iwai }
455b61f90eaSTakashi Iwai
scarlett_ctl_meter_get(struct snd_kcontrol * kctl,struct snd_ctl_elem_value * ucontrol)45676b188c4SChris J Arges static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
45776b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol)
45876b188c4SChris J Arges {
45976b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data;
4603360b84bSTakashi Iwai struct snd_usb_audio *chip = elem->head.mixer->chip;
46176b188c4SChris J Arges unsigned char buf[2 * MAX_CHANNELS] = {0, };
46276b188c4SChris J Arges int wValue = (elem->control << 8) | elem->idx_off;
4633360b84bSTakashi Iwai int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
46476b188c4SChris J Arges int err;
46576b188c4SChris J Arges
46676b188c4SChris J Arges err = snd_usb_ctl_msg(chip->dev,
46776b188c4SChris J Arges usb_rcvctrlpipe(chip->dev, 0),
46876b188c4SChris J Arges UAC2_CS_MEM,
46976b188c4SChris J Arges USB_RECIP_INTERFACE | USB_TYPE_CLASS |
47076b188c4SChris J Arges USB_DIR_IN, wValue, idx, buf, elem->channels);
47176b188c4SChris J Arges if (err < 0)
47276b188c4SChris J Arges return err;
47376b188c4SChris J Arges
47476b188c4SChris J Arges ucontrol->value.enumerated.item[0] = clamp((int)buf[0], 0, 1);
47576b188c4SChris J Arges return 0;
47676b188c4SChris J Arges }
47776b188c4SChris J Arges
47804bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_switch = {
47976b188c4SChris J Arges .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
48076b188c4SChris J Arges .name = "",
48176b188c4SChris J Arges .info = scarlett_ctl_switch_info,
48276b188c4SChris J Arges .get = scarlett_ctl_switch_get,
48376b188c4SChris J Arges .put = scarlett_ctl_switch_put,
48476b188c4SChris J Arges };
48576b188c4SChris J Arges
48676b188c4SChris J Arges static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0);
48776b188c4SChris J Arges
48804bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl = {
48976b188c4SChris J Arges .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
49076b188c4SChris J Arges .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
49176b188c4SChris J Arges SNDRV_CTL_ELEM_ACCESS_TLV_READ,
49276b188c4SChris J Arges .name = "",
49376b188c4SChris J Arges .info = scarlett_ctl_info,
49476b188c4SChris J Arges .get = scarlett_ctl_get,
49576b188c4SChris J Arges .put = scarlett_ctl_put,
49676b188c4SChris J Arges .private_value = 6, /* max value */
49776b188c4SChris J Arges .tlv = { .p = db_scale_scarlett_gain }
49876b188c4SChris J Arges };
49976b188c4SChris J Arges
50004bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_master = {
50176b188c4SChris J Arges .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
50276b188c4SChris J Arges .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
50376b188c4SChris J Arges SNDRV_CTL_ELEM_ACCESS_TLV_READ,
50476b188c4SChris J Arges .name = "",
50576b188c4SChris J Arges .info = scarlett_ctl_info,
50676b188c4SChris J Arges .get = scarlett_ctl_get,
50776b188c4SChris J Arges .put = scarlett_ctl_put,
50876b188c4SChris J Arges .private_value = 6, /* max value */
50976b188c4SChris J Arges .tlv = { .p = db_scale_scarlett_gain }
51076b188c4SChris J Arges };
51176b188c4SChris J Arges
51204bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_enum = {
51376b188c4SChris J Arges .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
51476b188c4SChris J Arges .name = "",
51576b188c4SChris J Arges .info = scarlett_ctl_enum_info,
51676b188c4SChris J Arges .get = scarlett_ctl_enum_get,
51776b188c4SChris J Arges .put = scarlett_ctl_enum_put,
51876b188c4SChris J Arges };
51976b188c4SChris J Arges
52004bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = {
52176b188c4SChris J Arges .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
52276b188c4SChris J Arges .name = "",
52376b188c4SChris J Arges .info = scarlett_ctl_enum_dynamic_info,
52476b188c4SChris J Arges .get = scarlett_ctl_enum_get,
52576b188c4SChris J Arges .put = scarlett_ctl_enum_put,
52676b188c4SChris J Arges };
52776b188c4SChris J Arges
52804bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_sync = {
52976b188c4SChris J Arges .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
53076b188c4SChris J Arges .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
53176b188c4SChris J Arges .name = "",
53276b188c4SChris J Arges .info = scarlett_ctl_enum_info,
53376b188c4SChris J Arges .get = scarlett_ctl_meter_get,
53476b188c4SChris J Arges };
53576b188c4SChris J Arges
add_new_ctl(struct usb_mixer_interface * mixer,const struct snd_kcontrol_new * ncontrol,usb_mixer_elem_resume_func_t resume,int index,int offset,int num,int val_type,int channels,const char * name,const struct scarlett_mixer_elem_enum_info * opt,struct usb_mixer_elem_info ** elem_ret)53676b188c4SChris J Arges static int add_new_ctl(struct usb_mixer_interface *mixer,
53776b188c4SChris J Arges const struct snd_kcontrol_new *ncontrol,
538b61f90eaSTakashi Iwai usb_mixer_elem_resume_func_t resume,
53976b188c4SChris J Arges int index, int offset, int num,
54076b188c4SChris J Arges int val_type, int channels, const char *name,
54176b188c4SChris J Arges const struct scarlett_mixer_elem_enum_info *opt,
54276b188c4SChris J Arges struct usb_mixer_elem_info **elem_ret
54376b188c4SChris J Arges )
54476b188c4SChris J Arges {
54576b188c4SChris J Arges struct snd_kcontrol *kctl;
54676b188c4SChris J Arges struct usb_mixer_elem_info *elem;
54776b188c4SChris J Arges int err;
54876b188c4SChris J Arges
54976b188c4SChris J Arges elem = kzalloc(sizeof(*elem), GFP_KERNEL);
55076b188c4SChris J Arges if (!elem)
55176b188c4SChris J Arges return -ENOMEM;
55276b188c4SChris J Arges
5533360b84bSTakashi Iwai elem->head.mixer = mixer;
554b61f90eaSTakashi Iwai elem->head.resume = resume;
55576b188c4SChris J Arges elem->control = offset;
55676b188c4SChris J Arges elem->idx_off = num;
5573360b84bSTakashi Iwai elem->head.id = index;
55876b188c4SChris J Arges elem->val_type = val_type;
55976b188c4SChris J Arges
56076b188c4SChris J Arges elem->channels = channels;
56176b188c4SChris J Arges
56276b188c4SChris J Arges /* add scarlett_mixer_elem_enum_info struct */
56376b188c4SChris J Arges elem->private_data = (void *)opt;
56476b188c4SChris J Arges
56576b188c4SChris J Arges kctl = snd_ctl_new1(ncontrol, elem);
56676b188c4SChris J Arges if (!kctl) {
56776b188c4SChris J Arges kfree(elem);
56876b188c4SChris J Arges return -ENOMEM;
56976b188c4SChris J Arges }
57076b188c4SChris J Arges kctl->private_free = snd_usb_mixer_elem_free;
57176b188c4SChris J Arges
57275b1a8f9SJoe Perches strscpy(kctl->id.name, name, sizeof(kctl->id.name));
57376b188c4SChris J Arges
574b61f90eaSTakashi Iwai err = snd_usb_mixer_add_control(&elem->head, kctl);
57576b188c4SChris J Arges if (err < 0)
57676b188c4SChris J Arges return err;
57776b188c4SChris J Arges
57876b188c4SChris J Arges if (elem_ret)
57976b188c4SChris J Arges *elem_ret = elem;
58076b188c4SChris J Arges
58176b188c4SChris J Arges return 0;
58276b188c4SChris J Arges }
58376b188c4SChris J Arges
add_output_ctls(struct usb_mixer_interface * mixer,int index,const char * name,const struct scarlett_device_info * info)58476b188c4SChris J Arges static int add_output_ctls(struct usb_mixer_interface *mixer,
58576b188c4SChris J Arges int index, const char *name,
58676b188c4SChris J Arges const struct scarlett_device_info *info)
58776b188c4SChris J Arges {
58876b188c4SChris J Arges int err;
58976b188c4SChris J Arges char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
59076b188c4SChris J Arges struct usb_mixer_elem_info *elem;
59176b188c4SChris J Arges
59276b188c4SChris J Arges /* Add mute switch */
59376b188c4SChris J Arges snprintf(mx, sizeof(mx), "Master %d (%s) Playback Switch",
59476b188c4SChris J Arges index + 1, name);
595b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_switch,
596b61f90eaSTakashi Iwai scarlett_ctl_resume, 0x0a, 0x01,
59776b188c4SChris J Arges 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem);
59876b188c4SChris J Arges if (err < 0)
59976b188c4SChris J Arges return err;
60076b188c4SChris J Arges
60176b188c4SChris J Arges /* Add volume control and initialize to 0 */
60276b188c4SChris J Arges snprintf(mx, sizeof(mx), "Master %d (%s) Playback Volume",
60376b188c4SChris J Arges index + 1, name);
604b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_master,
605b61f90eaSTakashi Iwai scarlett_ctl_resume, 0x0a, 0x02,
60676b188c4SChris J Arges 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem);
60776b188c4SChris J Arges if (err < 0)
60876b188c4SChris J Arges return err;
60976b188c4SChris J Arges
61076b188c4SChris J Arges /* Add L channel source playback enumeration */
61176b188c4SChris J Arges snprintf(mx, sizeof(mx), "Master %dL (%s) Source Playback Enum",
61276b188c4SChris J Arges index + 1, name);
613b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
614b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x33, 0x00,
61576b188c4SChris J Arges 2*index, USB_MIXER_S16, 1, mx, &info->opt_master,
61676b188c4SChris J Arges &elem);
61776b188c4SChris J Arges if (err < 0)
61876b188c4SChris J Arges return err;
61976b188c4SChris J Arges
62076b188c4SChris J Arges /* Add R channel source playback enumeration */
62176b188c4SChris J Arges snprintf(mx, sizeof(mx), "Master %dR (%s) Source Playback Enum",
62276b188c4SChris J Arges index + 1, name);
623b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
624b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x33, 0x00,
62576b188c4SChris J Arges 2*index+1, USB_MIXER_S16, 1, mx, &info->opt_master,
62676b188c4SChris J Arges &elem);
62776b188c4SChris J Arges if (err < 0)
62876b188c4SChris J Arges return err;
62976b188c4SChris J Arges
63076b188c4SChris J Arges return 0;
63176b188c4SChris J Arges }
63276b188c4SChris J Arges
63376b188c4SChris J Arges /********************** device-specific config *************************/
63476b188c4SChris J Arges
63576b188c4SChris J Arges /* untested... */
636a01df925STakashi Iwai static const struct scarlett_device_info s6i6_info = {
63776b188c4SChris J Arges .matrix_in = 18,
63876b188c4SChris J Arges .matrix_out = 8,
63976b188c4SChris J Arges .input_len = 6,
64076b188c4SChris J Arges .output_len = 6,
64176b188c4SChris J Arges
64276b188c4SChris J Arges .opt_master = {
64376b188c4SChris J Arges .start = -1,
64476b188c4SChris J Arges .len = 27,
64576b188c4SChris J Arges .offsets = {0, 12, 16, 18, 18},
64676b188c4SChris J Arges .names = NULL
64776b188c4SChris J Arges },
64876b188c4SChris J Arges
64976b188c4SChris J Arges .opt_matrix = {
65076b188c4SChris J Arges .start = -1,
65176b188c4SChris J Arges .len = 19,
65276b188c4SChris J Arges .offsets = {0, 12, 16, 18, 18},
65376b188c4SChris J Arges .names = NULL
65476b188c4SChris J Arges },
65576b188c4SChris J Arges
656c99b9e85SChris J Arges .num_controls = 9,
65776b188c4SChris J Arges .controls = {
65876b188c4SChris J Arges { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
65976b188c4SChris J Arges { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
66076b188c4SChris J Arges { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
66176b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
66276b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
66376b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
66476b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
665bf2aa5caSJens Verwiebe { .num = 3, .type = SCARLETT_SWITCH_GAIN, .name = NULL},
666bf2aa5caSJens Verwiebe { .num = 4, .type = SCARLETT_SWITCH_GAIN, .name = NULL},
66776b188c4SChris J Arges },
66876b188c4SChris J Arges
66976b188c4SChris J Arges .matrix_mux_init = {
67076b188c4SChris J Arges 12, 13, 14, 15, /* Analog -> 1..4 */
67176b188c4SChris J Arges 16, 17, /* SPDIF -> 5,6 */
67276b188c4SChris J Arges 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */
67376b188c4SChris J Arges 8, 9, 10, 11
67476b188c4SChris J Arges }
67576b188c4SChris J Arges };
67676b188c4SChris J Arges
67776b188c4SChris J Arges /* untested... */
678a01df925STakashi Iwai static const struct scarlett_device_info s8i6_info = {
67976b188c4SChris J Arges .matrix_in = 18,
68076b188c4SChris J Arges .matrix_out = 6,
68176b188c4SChris J Arges .input_len = 8,
68276b188c4SChris J Arges .output_len = 6,
68376b188c4SChris J Arges
68476b188c4SChris J Arges .opt_master = {
68576b188c4SChris J Arges .start = -1,
68676b188c4SChris J Arges .len = 25,
68776b188c4SChris J Arges .offsets = {0, 12, 16, 18, 18},
68876b188c4SChris J Arges .names = NULL
68976b188c4SChris J Arges },
69076b188c4SChris J Arges
69176b188c4SChris J Arges .opt_matrix = {
69276b188c4SChris J Arges .start = -1,
69376b188c4SChris J Arges .len = 19,
69476b188c4SChris J Arges .offsets = {0, 12, 16, 18, 18},
69576b188c4SChris J Arges .names = NULL
69676b188c4SChris J Arges },
69776b188c4SChris J Arges
69876b188c4SChris J Arges .num_controls = 7,
69976b188c4SChris J Arges .controls = {
70076b188c4SChris J Arges { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
70176b188c4SChris J Arges { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
70276b188c4SChris J Arges { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
70376b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
70476b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
70576b188c4SChris J Arges { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
70676b188c4SChris J Arges { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
70776b188c4SChris J Arges },
70876b188c4SChris J Arges
70976b188c4SChris J Arges .matrix_mux_init = {
71076b188c4SChris J Arges 12, 13, 14, 15, /* Analog -> 1..4 */
71176b188c4SChris J Arges 16, 17, /* SPDIF -> 5,6 */
71276b188c4SChris J Arges 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */
71376b188c4SChris J Arges 8, 9, 10, 11
71476b188c4SChris J Arges }
71576b188c4SChris J Arges };
71676b188c4SChris J Arges
717a01df925STakashi Iwai static const struct scarlett_device_info s18i6_info = {
71876b188c4SChris J Arges .matrix_in = 18,
71976b188c4SChris J Arges .matrix_out = 6,
72076b188c4SChris J Arges .input_len = 18,
72176b188c4SChris J Arges .output_len = 6,
72276b188c4SChris J Arges
72376b188c4SChris J Arges .opt_master = {
72476b188c4SChris J Arges .start = -1,
72576b188c4SChris J Arges .len = 31,
72676b188c4SChris J Arges .offsets = {0, 6, 14, 16, 24},
72776b188c4SChris J Arges .names = NULL,
72876b188c4SChris J Arges },
72976b188c4SChris J Arges
73076b188c4SChris J Arges .opt_matrix = {
73176b188c4SChris J Arges .start = -1,
73276b188c4SChris J Arges .len = 25,
73376b188c4SChris J Arges .offsets = {0, 6, 14, 16, 24},
73476b188c4SChris J Arges .names = NULL,
73576b188c4SChris J Arges },
73676b188c4SChris J Arges
73776b188c4SChris J Arges .num_controls = 5,
73876b188c4SChris J Arges .controls = {
73976b188c4SChris J Arges { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
74076b188c4SChris J Arges { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
74176b188c4SChris J Arges { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
74276b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
74376b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
74476b188c4SChris J Arges },
74576b188c4SChris J Arges
74676b188c4SChris J Arges .matrix_mux_init = {
74776b188c4SChris J Arges 6, 7, 8, 9, 10, 11, 12, 13, /* Analog -> 1..8 */
74876b188c4SChris J Arges 16, 17, 18, 19, 20, 21, /* ADAT[1..6] -> 9..14 */
74976b188c4SChris J Arges 14, 15, /* SPDIF -> 15,16 */
75076b188c4SChris J Arges 0, 1 /* PCM[1,2] -> 17,18 */
75176b188c4SChris J Arges }
75276b188c4SChris J Arges };
75376b188c4SChris J Arges
754a01df925STakashi Iwai static const struct scarlett_device_info s18i8_info = {
75576b188c4SChris J Arges .matrix_in = 18,
75676b188c4SChris J Arges .matrix_out = 8,
75776b188c4SChris J Arges .input_len = 18,
75876b188c4SChris J Arges .output_len = 8,
75976b188c4SChris J Arges
76076b188c4SChris J Arges .opt_master = {
76176b188c4SChris J Arges .start = -1,
76276b188c4SChris J Arges .len = 35,
76376b188c4SChris J Arges .offsets = {0, 8, 16, 18, 26},
76476b188c4SChris J Arges .names = NULL
76576b188c4SChris J Arges },
76676b188c4SChris J Arges
76776b188c4SChris J Arges .opt_matrix = {
76876b188c4SChris J Arges .start = -1,
76976b188c4SChris J Arges .len = 27,
77076b188c4SChris J Arges .offsets = {0, 8, 16, 18, 26},
77176b188c4SChris J Arges .names = NULL
77276b188c4SChris J Arges },
77376b188c4SChris J Arges
77476b188c4SChris J Arges .num_controls = 10,
77576b188c4SChris J Arges .controls = {
77676b188c4SChris J Arges { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
77776b188c4SChris J Arges { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone 1" },
77876b188c4SChris J Arges { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Headphone 2" },
77976b188c4SChris J Arges { .num = 3, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
78076b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
78176b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
78276b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
78376b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
78476b188c4SChris J Arges { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
78576b188c4SChris J Arges { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
78676b188c4SChris J Arges },
78776b188c4SChris J Arges
78876b188c4SChris J Arges .matrix_mux_init = {
78976b188c4SChris J Arges 8, 9, 10, 11, 12, 13, 14, 15, /* Analog -> 1..8 */
79076b188c4SChris J Arges 18, 19, 20, 21, 22, 23, /* ADAT[1..6] -> 9..14 */
79176b188c4SChris J Arges 16, 17, /* SPDIF -> 15,16 */
79276b188c4SChris J Arges 0, 1 /* PCM[1,2] -> 17,18 */
79376b188c4SChris J Arges }
79476b188c4SChris J Arges };
79576b188c4SChris J Arges
796a01df925STakashi Iwai static const struct scarlett_device_info s18i20_info = {
79776b188c4SChris J Arges .matrix_in = 18,
79876b188c4SChris J Arges .matrix_out = 8,
79976b188c4SChris J Arges .input_len = 18,
80076b188c4SChris J Arges .output_len = 20,
80176b188c4SChris J Arges
80276b188c4SChris J Arges .opt_master = {
80376b188c4SChris J Arges .start = -1,
80476b188c4SChris J Arges .len = 47,
80576b188c4SChris J Arges .offsets = {0, 20, 28, 30, 38},
80676b188c4SChris J Arges .names = NULL
80776b188c4SChris J Arges },
80876b188c4SChris J Arges
80976b188c4SChris J Arges .opt_matrix = {
81076b188c4SChris J Arges .start = -1,
81176b188c4SChris J Arges .len = 39,
81276b188c4SChris J Arges .offsets = {0, 20, 28, 30, 38},
81376b188c4SChris J Arges .names = NULL
81476b188c4SChris J Arges },
81576b188c4SChris J Arges
81676b188c4SChris J Arges .num_controls = 10,
81776b188c4SChris J Arges .controls = {
81876b188c4SChris J Arges { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
81976b188c4SChris J Arges { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Line 3/4" },
82076b188c4SChris J Arges { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Line 5/6" },
82176b188c4SChris J Arges { .num = 3, .type = SCARLETT_OUTPUTS, .name = "Line 7/8" },
82276b188c4SChris J Arges { .num = 4, .type = SCARLETT_OUTPUTS, .name = "Line 9/10" },
82376b188c4SChris J Arges { .num = 5, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
82476b188c4SChris J Arges { .num = 6, .type = SCARLETT_OUTPUTS, .name = "ADAT 1/2" },
82576b188c4SChris J Arges { .num = 7, .type = SCARLETT_OUTPUTS, .name = "ADAT 3/4" },
82676b188c4SChris J Arges { .num = 8, .type = SCARLETT_OUTPUTS, .name = "ADAT 5/6" },
82776b188c4SChris J Arges { .num = 9, .type = SCARLETT_OUTPUTS, .name = "ADAT 7/8" },
82876b188c4SChris J Arges /*{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
82976b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
83076b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
83176b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
83276b188c4SChris J Arges { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
83376b188c4SChris J Arges { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},*/
83476b188c4SChris J Arges },
83576b188c4SChris J Arges
83676b188c4SChris J Arges .matrix_mux_init = {
83776b188c4SChris J Arges 20, 21, 22, 23, 24, 25, 26, 27, /* Analog -> 1..8 */
83876b188c4SChris J Arges 30, 31, 32, 33, 34, 35, /* ADAT[1..6] -> 9..14 */
83976b188c4SChris J Arges 28, 29, /* SPDIF -> 15,16 */
84076b188c4SChris J Arges 0, 1 /* PCM[1,2] -> 17,18 */
84176b188c4SChris J Arges }
84276b188c4SChris J Arges };
84376b188c4SChris J Arges
84476b188c4SChris J Arges
scarlett_controls_create_generic(struct usb_mixer_interface * mixer,const struct scarlett_device_info * info)84576b188c4SChris J Arges static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer,
846a01df925STakashi Iwai const struct scarlett_device_info *info)
84776b188c4SChris J Arges {
84876b188c4SChris J Arges int i, err;
84976b188c4SChris J Arges char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
85076b188c4SChris J Arges const struct scarlett_mixer_control *ctl;
85176b188c4SChris J Arges struct usb_mixer_elem_info *elem;
85276b188c4SChris J Arges
85376b188c4SChris J Arges /* create master switch and playback volume */
854b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_switch,
855b61f90eaSTakashi Iwai scarlett_ctl_resume, 0x0a, 0x01, 0,
85676b188c4SChris J Arges USB_MIXER_S16, 1, "Master Playback Switch", NULL,
85776b188c4SChris J Arges &elem);
85876b188c4SChris J Arges if (err < 0)
85976b188c4SChris J Arges return err;
86076b188c4SChris J Arges
861b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_master,
862b61f90eaSTakashi Iwai scarlett_ctl_resume, 0x0a, 0x02, 0,
86376b188c4SChris J Arges USB_MIXER_S16, 1, "Master Playback Volume", NULL,
86476b188c4SChris J Arges &elem);
86576b188c4SChris J Arges if (err < 0)
86676b188c4SChris J Arges return err;
86776b188c4SChris J Arges
86876b188c4SChris J Arges /* iterate through controls in info struct and create each one */
86976b188c4SChris J Arges for (i = 0; i < info->num_controls; i++) {
87076b188c4SChris J Arges ctl = &info->controls[i];
87176b188c4SChris J Arges
87276b188c4SChris J Arges switch (ctl->type) {
87376b188c4SChris J Arges case SCARLETT_OUTPUTS:
87476b188c4SChris J Arges err = add_output_ctls(mixer, ctl->num, ctl->name, info);
87576b188c4SChris J Arges if (err < 0)
87676b188c4SChris J Arges return err;
87776b188c4SChris J Arges break;
87876b188c4SChris J Arges case SCARLETT_SWITCH_IMPEDANCE:
87976b188c4SChris J Arges sprintf(mx, "Input %d Impedance Switch", ctl->num);
880b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
881b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x01,
88276b188c4SChris J Arges 0x09, ctl->num, USB_MIXER_S16, 1, mx,
88376b188c4SChris J Arges &opt_impedance, &elem);
88476b188c4SChris J Arges if (err < 0)
88576b188c4SChris J Arges return err;
88676b188c4SChris J Arges break;
88776b188c4SChris J Arges case SCARLETT_SWITCH_PAD:
88876b188c4SChris J Arges sprintf(mx, "Input %d Pad Switch", ctl->num);
889b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
890b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x01,
89176b188c4SChris J Arges 0x0b, ctl->num, USB_MIXER_S16, 1, mx,
89276b188c4SChris J Arges &opt_pad, &elem);
89376b188c4SChris J Arges if (err < 0)
89476b188c4SChris J Arges return err;
89576b188c4SChris J Arges break;
896bf2aa5caSJens Verwiebe case SCARLETT_SWITCH_GAIN:
897bf2aa5caSJens Verwiebe sprintf(mx, "Input %d Gain Switch", ctl->num);
898bf2aa5caSJens Verwiebe err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
899bf2aa5caSJens Verwiebe scarlett_ctl_enum_resume, 0x01,
900bf2aa5caSJens Verwiebe 0x08, ctl->num, USB_MIXER_S16, 1, mx,
901bf2aa5caSJens Verwiebe &opt_gain, &elem);
902bf2aa5caSJens Verwiebe if (err < 0)
903bf2aa5caSJens Verwiebe return err;
904bf2aa5caSJens Verwiebe break;
90576b188c4SChris J Arges }
90676b188c4SChris J Arges }
90776b188c4SChris J Arges
90876b188c4SChris J Arges return 0;
90976b188c4SChris J Arges }
91076b188c4SChris J Arges
91176b188c4SChris J Arges /*
91276b188c4SChris J Arges * Create and initialize a mixer for the Focusrite(R) Scarlett
91376b188c4SChris J Arges */
snd_scarlett_controls_create(struct usb_mixer_interface * mixer)91476b188c4SChris J Arges int snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
91576b188c4SChris J Arges {
91676b188c4SChris J Arges int err, i, o;
91776b188c4SChris J Arges char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
918a01df925STakashi Iwai const struct scarlett_device_info *info;
91976b188c4SChris J Arges struct usb_mixer_elem_info *elem;
92076b188c4SChris J Arges static char sample_rate_buffer[4] = { '\x80', '\xbb', '\x00', '\x00' };
92176b188c4SChris J Arges
92276b188c4SChris J Arges /* only use UAC_VERSION_2 */
92376b188c4SChris J Arges if (!mixer->protocol)
92476b188c4SChris J Arges return 0;
92576b188c4SChris J Arges
92676b188c4SChris J Arges switch (mixer->chip->usb_id) {
92776b188c4SChris J Arges case USB_ID(0x1235, 0x8012):
92876b188c4SChris J Arges info = &s6i6_info;
92976b188c4SChris J Arges break;
93076b188c4SChris J Arges case USB_ID(0x1235, 0x8002):
93176b188c4SChris J Arges info = &s8i6_info;
93276b188c4SChris J Arges break;
93376b188c4SChris J Arges case USB_ID(0x1235, 0x8004):
93476b188c4SChris J Arges info = &s18i6_info;
93576b188c4SChris J Arges break;
93676b188c4SChris J Arges case USB_ID(0x1235, 0x8014):
93776b188c4SChris J Arges info = &s18i8_info;
93876b188c4SChris J Arges break;
93976b188c4SChris J Arges case USB_ID(0x1235, 0x800c):
94076b188c4SChris J Arges info = &s18i20_info;
94176b188c4SChris J Arges break;
94276b188c4SChris J Arges default: /* device not (yet) supported */
94376b188c4SChris J Arges return -EINVAL;
94476b188c4SChris J Arges }
94576b188c4SChris J Arges
94676b188c4SChris J Arges /* generic function to create controls */
94776b188c4SChris J Arges err = scarlett_controls_create_generic(mixer, info);
94876b188c4SChris J Arges if (err < 0)
94976b188c4SChris J Arges return err;
95076b188c4SChris J Arges
95176b188c4SChris J Arges /* setup matrix controls */
95276b188c4SChris J Arges for (i = 0; i < info->matrix_in; i++) {
95376b188c4SChris J Arges snprintf(mx, sizeof(mx), "Matrix %02d Input Playback Route",
95476b188c4SChris J Arges i+1);
955b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
956b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x32,
95776b188c4SChris J Arges 0x06, i, USB_MIXER_S16, 1, mx,
95876b188c4SChris J Arges &info->opt_matrix, &elem);
95976b188c4SChris J Arges if (err < 0)
96076b188c4SChris J Arges return err;
96176b188c4SChris J Arges
96276b188c4SChris J Arges for (o = 0; o < info->matrix_out; o++) {
96376b188c4SChris J Arges sprintf(mx, "Matrix %02d Mix %c Playback Volume", i+1,
96476b188c4SChris J Arges o+'A');
965b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl,
966b61f90eaSTakashi Iwai scarlett_ctl_resume, 0x3c, 0x00,
96776b188c4SChris J Arges (i << 3) + (o & 0x07), USB_MIXER_S16,
96876b188c4SChris J Arges 1, mx, NULL, &elem);
96976b188c4SChris J Arges if (err < 0)
97076b188c4SChris J Arges return err;
97176b188c4SChris J Arges
97276b188c4SChris J Arges }
97376b188c4SChris J Arges }
97476b188c4SChris J Arges
97576b188c4SChris J Arges for (i = 0; i < info->input_len; i++) {
97676b188c4SChris J Arges snprintf(mx, sizeof(mx), "Input Source %02d Capture Route",
97776b188c4SChris J Arges i+1);
978b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
979b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x34,
98076b188c4SChris J Arges 0x00, i, USB_MIXER_S16, 1, mx,
98176b188c4SChris J Arges &info->opt_master, &elem);
98276b188c4SChris J Arges if (err < 0)
98376b188c4SChris J Arges return err;
98476b188c4SChris J Arges }
98576b188c4SChris J Arges
98676b188c4SChris J Arges /* val_len == 1 needed here */
987b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
988b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x28, 0x01, 0,
98976b188c4SChris J Arges USB_MIXER_U8, 1, "Sample Clock Source",
99076b188c4SChris J Arges &opt_clock, &elem);
99176b188c4SChris J Arges if (err < 0)
99276b188c4SChris J Arges return err;
99376b188c4SChris J Arges
99476b188c4SChris J Arges /* val_len == 1 and UAC2_CS_MEM */
995b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_sync, NULL, 0x3c, 0x00, 2,
99676b188c4SChris J Arges USB_MIXER_U8, 1, "Sample Clock Sync Status",
99776b188c4SChris J Arges &opt_sync, &elem);
99876b188c4SChris J Arges if (err < 0)
99976b188c4SChris J Arges return err;
100076b188c4SChris J Arges
100176b188c4SChris J Arges /* initialize sampling rate to 48000 */
100276b188c4SChris J Arges err = snd_usb_ctl_msg(mixer->chip->dev,
100376b188c4SChris J Arges usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR,
100476b188c4SChris J Arges USB_RECIP_INTERFACE | USB_TYPE_CLASS |
100576b188c4SChris J Arges USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) |
100676b188c4SChris J Arges (0x29 << 8), sample_rate_buffer, 4);
100776b188c4SChris J Arges if (err < 0)
100876b188c4SChris J Arges return err;
100976b188c4SChris J Arges
101076b188c4SChris J Arges return err;
101176b188c4SChris J Arges }
1012