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 2476b188c4SChris J Arges * right now it's a major headache to work arount 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, 14576b188c4SChris J Arges }; 14676b188c4SChris J Arges 14776b188c4SChris J Arges enum { 14876b188c4SChris J Arges SCARLETT_OFFSET_PCM = 0, 14976b188c4SChris J Arges SCARLETT_OFFSET_ANALOG = 1, 15076b188c4SChris J Arges SCARLETT_OFFSET_SPDIF = 2, 15176b188c4SChris J Arges SCARLETT_OFFSET_ADAT = 3, 15276b188c4SChris J Arges SCARLETT_OFFSET_MIX = 4, 15376b188c4SChris J Arges }; 15476b188c4SChris J Arges 15576b188c4SChris J Arges struct scarlett_mixer_elem_enum_info { 15676b188c4SChris J Arges int start; 15776b188c4SChris J Arges int len; 15876b188c4SChris J Arges int offsets[SND_SCARLETT_OFFSETS_MAX]; 15976b188c4SChris J Arges char const * const *names; 16076b188c4SChris J Arges }; 16176b188c4SChris J Arges 16276b188c4SChris J Arges struct scarlett_mixer_control { 16376b188c4SChris J Arges unsigned char num; 16476b188c4SChris J Arges unsigned char type; 16576b188c4SChris J Arges const char *name; 16676b188c4SChris J Arges }; 16776b188c4SChris J Arges 16876b188c4SChris J Arges struct scarlett_device_info { 16976b188c4SChris J Arges int matrix_in; 17076b188c4SChris J Arges int matrix_out; 17176b188c4SChris J Arges int input_len; 17276b188c4SChris J Arges int output_len; 17376b188c4SChris J Arges 17476b188c4SChris J Arges struct scarlett_mixer_elem_enum_info opt_master; 17576b188c4SChris J Arges struct scarlett_mixer_elem_enum_info opt_matrix; 17676b188c4SChris J Arges 17776b188c4SChris J Arges /* initial values for matrix mux */ 17876b188c4SChris J Arges int matrix_mux_init[SND_SCARLETT_MATRIX_IN_MAX]; 17976b188c4SChris J Arges 18076b188c4SChris J Arges int num_controls; /* number of items in controls */ 18176b188c4SChris J Arges const struct scarlett_mixer_control controls[SND_SCARLETT_CONTROLS_MAX]; 18276b188c4SChris J Arges }; 18376b188c4SChris J Arges 18476b188c4SChris J Arges /********************** Enum Strings *************************/ 18576b188c4SChris J Arges 18676b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_pad = { 18776b188c4SChris J Arges .start = 0, 18876b188c4SChris J Arges .len = 2, 18976b188c4SChris J Arges .offsets = {}, 19076b188c4SChris J Arges .names = (char const * const []){ 19176b188c4SChris J Arges "0dB", "-10dB" 19276b188c4SChris J Arges } 19376b188c4SChris J Arges }; 19476b188c4SChris J Arges 19576b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_impedance = { 19676b188c4SChris J Arges .start = 0, 19776b188c4SChris J Arges .len = 2, 19876b188c4SChris J Arges .offsets = {}, 19976b188c4SChris J Arges .names = (char const * const []){ 20076b188c4SChris J Arges "Line", "Hi-Z" 20176b188c4SChris J Arges } 20276b188c4SChris J Arges }; 20376b188c4SChris J Arges 20476b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_clock = { 20576b188c4SChris J Arges .start = 1, 20676b188c4SChris J Arges .len = 3, 20776b188c4SChris J Arges .offsets = {}, 20876b188c4SChris J Arges .names = (char const * const []){ 20976b188c4SChris J Arges "Internal", "SPDIF", "ADAT" 21076b188c4SChris J Arges } 21176b188c4SChris J Arges }; 21276b188c4SChris J Arges 21376b188c4SChris J Arges static const struct scarlett_mixer_elem_enum_info opt_sync = { 21476b188c4SChris J Arges .start = 0, 21576b188c4SChris J Arges .len = 2, 21676b188c4SChris J Arges .offsets = {}, 21776b188c4SChris J Arges .names = (char const * const []){ 21876b188c4SChris J Arges "No Lock", "Locked" 21976b188c4SChris J Arges } 22076b188c4SChris J Arges }; 22176b188c4SChris J Arges 22276b188c4SChris J Arges static int scarlett_ctl_switch_info(struct snd_kcontrol *kctl, 22376b188c4SChris J Arges struct snd_ctl_elem_info *uinfo) 22476b188c4SChris J Arges { 22576b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data; 22676b188c4SChris J Arges 22776b188c4SChris J Arges uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 22876b188c4SChris J Arges uinfo->count = elem->channels; 22976b188c4SChris J Arges uinfo->value.integer.min = 0; 23076b188c4SChris J Arges uinfo->value.integer.max = 1; 23176b188c4SChris J Arges return 0; 23276b188c4SChris J Arges } 23376b188c4SChris J Arges 23476b188c4SChris J Arges static int scarlett_ctl_switch_get(struct snd_kcontrol *kctl, 23576b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol) 23676b188c4SChris J Arges { 23776b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data; 23876b188c4SChris J Arges int i, err, val; 23976b188c4SChris J Arges 24076b188c4SChris J Arges for (i = 0; i < elem->channels; i++) { 24176b188c4SChris J Arges err = snd_usb_get_cur_mix_value(elem, i, i, &val); 24276b188c4SChris J Arges if (err < 0) 24376b188c4SChris J Arges return err; 24476b188c4SChris J Arges 24576b188c4SChris J Arges val = !val; /* invert mute logic for mixer */ 24676b188c4SChris J Arges ucontrol->value.integer.value[i] = val; 24776b188c4SChris J Arges } 24876b188c4SChris J Arges 24976b188c4SChris J Arges return 0; 25076b188c4SChris J Arges } 25176b188c4SChris J Arges 25276b188c4SChris J Arges static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl, 25376b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol) 25476b188c4SChris J Arges { 25576b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data; 25676b188c4SChris J Arges int i, changed = 0; 25776b188c4SChris J Arges int err, oval, val; 25876b188c4SChris J Arges 25976b188c4SChris J Arges for (i = 0; i < elem->channels; i++) { 26076b188c4SChris J Arges err = snd_usb_get_cur_mix_value(elem, i, i, &oval); 26176b188c4SChris J Arges if (err < 0) 26276b188c4SChris J Arges return err; 26376b188c4SChris J Arges 26476b188c4SChris J Arges val = ucontrol->value.integer.value[i]; 26576b188c4SChris J Arges val = !val; 26676b188c4SChris J Arges if (oval != val) { 26776b188c4SChris J Arges err = snd_usb_set_cur_mix_value(elem, i, i, val); 26876b188c4SChris J Arges if (err < 0) 26976b188c4SChris J Arges return err; 27076b188c4SChris J Arges 27176b188c4SChris J Arges changed = 1; 27276b188c4SChris J Arges } 27376b188c4SChris J Arges } 27476b188c4SChris J Arges 27576b188c4SChris J Arges return changed; 27676b188c4SChris J Arges } 27776b188c4SChris J Arges 278b61f90eaSTakashi Iwai static int scarlett_ctl_resume(struct usb_mixer_elem_list *list) 279b61f90eaSTakashi Iwai { 2808c558076STakashi Iwai struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list); 281b61f90eaSTakashi Iwai int i; 282b61f90eaSTakashi Iwai 283b61f90eaSTakashi Iwai for (i = 0; i < elem->channels; i++) 284b61f90eaSTakashi Iwai if (elem->cached & (1 << i)) 285b61f90eaSTakashi Iwai snd_usb_set_cur_mix_value(elem, i, i, 286b61f90eaSTakashi Iwai elem->cache_val[i]); 287b61f90eaSTakashi Iwai return 0; 288b61f90eaSTakashi Iwai } 289b61f90eaSTakashi Iwai 29076b188c4SChris J Arges static int scarlett_ctl_info(struct snd_kcontrol *kctl, 29176b188c4SChris J Arges struct snd_ctl_elem_info *uinfo) 29276b188c4SChris J Arges { 29376b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data; 29476b188c4SChris J Arges 29576b188c4SChris J Arges uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 29676b188c4SChris J Arges uinfo->count = elem->channels; 29776b188c4SChris J Arges uinfo->value.integer.min = 0; 29876b188c4SChris J Arges uinfo->value.integer.max = (int)kctl->private_value + 29976b188c4SChris J Arges SND_SCARLETT_LEVEL_BIAS; 30076b188c4SChris J Arges uinfo->value.integer.step = 1; 30176b188c4SChris J Arges return 0; 30276b188c4SChris J Arges } 30376b188c4SChris J Arges 30476b188c4SChris J Arges static int scarlett_ctl_get(struct snd_kcontrol *kctl, 30576b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol) 30676b188c4SChris J Arges { 30776b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data; 30876b188c4SChris J Arges int i, err, val; 30976b188c4SChris J Arges 31076b188c4SChris J Arges for (i = 0; i < elem->channels; i++) { 31176b188c4SChris J Arges err = snd_usb_get_cur_mix_value(elem, i, i, &val); 31276b188c4SChris J Arges if (err < 0) 31376b188c4SChris J Arges return err; 31476b188c4SChris J Arges 31576b188c4SChris J Arges val = clamp(val / 256, -128, (int)kctl->private_value) + 31676b188c4SChris J Arges SND_SCARLETT_LEVEL_BIAS; 31776b188c4SChris J Arges ucontrol->value.integer.value[i] = val; 31876b188c4SChris J Arges } 31976b188c4SChris J Arges 32076b188c4SChris J Arges return 0; 32176b188c4SChris J Arges } 32276b188c4SChris J Arges 32376b188c4SChris J Arges static int scarlett_ctl_put(struct snd_kcontrol *kctl, 32476b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol) 32576b188c4SChris J Arges { 32676b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data; 32776b188c4SChris J Arges int i, changed = 0; 32876b188c4SChris J Arges int err, oval, val; 32976b188c4SChris J Arges 33076b188c4SChris J Arges for (i = 0; i < elem->channels; i++) { 33176b188c4SChris J Arges err = snd_usb_get_cur_mix_value(elem, i, i, &oval); 33276b188c4SChris J Arges if (err < 0) 33376b188c4SChris J Arges return err; 33476b188c4SChris J Arges 33576b188c4SChris J Arges val = ucontrol->value.integer.value[i] - 33676b188c4SChris J Arges SND_SCARLETT_LEVEL_BIAS; 33776b188c4SChris J Arges val = val * 256; 33876b188c4SChris J Arges if (oval != val) { 33976b188c4SChris J Arges err = snd_usb_set_cur_mix_value(elem, i, i, val); 34076b188c4SChris J Arges if (err < 0) 34176b188c4SChris J Arges return err; 34276b188c4SChris J Arges 34376b188c4SChris J Arges changed = 1; 34476b188c4SChris J Arges } 34576b188c4SChris J Arges } 34676b188c4SChris J Arges 34776b188c4SChris J Arges return changed; 34876b188c4SChris J Arges } 34976b188c4SChris J Arges 35076b188c4SChris J Arges static void scarlett_generate_name(int i, char *dst, int offsets[]) 35176b188c4SChris J Arges { 35276b188c4SChris J Arges if (i > offsets[SCARLETT_OFFSET_MIX]) 35376b188c4SChris J Arges sprintf(dst, "Mix %c", 35476b188c4SChris J Arges 'A'+(i - offsets[SCARLETT_OFFSET_MIX] - 1)); 35576b188c4SChris J Arges else if (i > offsets[SCARLETT_OFFSET_ADAT]) 35676b188c4SChris J Arges sprintf(dst, "ADAT %d", i - offsets[SCARLETT_OFFSET_ADAT]); 35776b188c4SChris J Arges else if (i > offsets[SCARLETT_OFFSET_SPDIF]) 35876b188c4SChris J Arges sprintf(dst, "SPDIF %d", i - offsets[SCARLETT_OFFSET_SPDIF]); 35976b188c4SChris J Arges else if (i > offsets[SCARLETT_OFFSET_ANALOG]) 36076b188c4SChris J Arges sprintf(dst, "Analog %d", i - offsets[SCARLETT_OFFSET_ANALOG]); 36176b188c4SChris J Arges else if (i > offsets[SCARLETT_OFFSET_PCM]) 36276b188c4SChris J Arges sprintf(dst, "PCM %d", i - offsets[SCARLETT_OFFSET_PCM]); 36376b188c4SChris J Arges else 36476b188c4SChris J Arges sprintf(dst, "Off"); 36576b188c4SChris J Arges } 36676b188c4SChris J Arges 36776b188c4SChris J Arges static int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl, 36876b188c4SChris J Arges struct snd_ctl_elem_info *uinfo) 36976b188c4SChris J Arges { 37076b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data; 37176b188c4SChris J Arges struct scarlett_mixer_elem_enum_info *opt = elem->private_data; 37276b188c4SChris J Arges unsigned int items = opt->len; 37376b188c4SChris J Arges 37476b188c4SChris J Arges uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 37576b188c4SChris J Arges uinfo->count = elem->channels; 37676b188c4SChris J Arges uinfo->value.enumerated.items = items; 37776b188c4SChris J Arges 37876b188c4SChris J Arges if (uinfo->value.enumerated.item >= items) 37976b188c4SChris J Arges uinfo->value.enumerated.item = items - 1; 38076b188c4SChris J Arges 38176b188c4SChris J Arges /* generate name dynamically based on item number and offset info */ 38276b188c4SChris J Arges scarlett_generate_name(uinfo->value.enumerated.item, 38376b188c4SChris J Arges uinfo->value.enumerated.name, 38476b188c4SChris J Arges opt->offsets); 38576b188c4SChris J Arges 38676b188c4SChris J Arges return 0; 38776b188c4SChris J Arges } 38876b188c4SChris J Arges 38976b188c4SChris J Arges static int scarlett_ctl_enum_info(struct snd_kcontrol *kctl, 39076b188c4SChris J Arges struct snd_ctl_elem_info *uinfo) 39176b188c4SChris J Arges { 39276b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data; 39376b188c4SChris J Arges struct scarlett_mixer_elem_enum_info *opt = elem->private_data; 39476b188c4SChris J Arges 39576b188c4SChris J Arges return snd_ctl_enum_info(uinfo, elem->channels, opt->len, 39676b188c4SChris J Arges (const char * const *)opt->names); 39776b188c4SChris J Arges } 39876b188c4SChris J Arges 39976b188c4SChris J Arges static int scarlett_ctl_enum_get(struct snd_kcontrol *kctl, 40076b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol) 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 int err, val; 40576b188c4SChris J Arges 40676b188c4SChris J Arges err = snd_usb_get_cur_mix_value(elem, 0, 0, &val); 40776b188c4SChris J Arges if (err < 0) 40876b188c4SChris J Arges return err; 40976b188c4SChris J Arges 41076b188c4SChris J Arges val = clamp(val - opt->start, 0, opt->len-1); 41176b188c4SChris J Arges 41276b188c4SChris J Arges ucontrol->value.enumerated.item[0] = val; 41376b188c4SChris J Arges 41476b188c4SChris J Arges return 0; 41576b188c4SChris J Arges } 41676b188c4SChris J Arges 41776b188c4SChris J Arges static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl, 41876b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol) 41976b188c4SChris J Arges { 42076b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data; 42176b188c4SChris J Arges struct scarlett_mixer_elem_enum_info *opt = elem->private_data; 42276b188c4SChris J Arges int err, oval, val; 42376b188c4SChris J Arges 42476b188c4SChris J Arges err = snd_usb_get_cur_mix_value(elem, 0, 0, &oval); 42576b188c4SChris J Arges if (err < 0) 42676b188c4SChris J Arges return err; 42776b188c4SChris J Arges 42876b188c4SChris J Arges val = ucontrol->value.integer.value[0]; 42976b188c4SChris J Arges val = val + opt->start; 43076b188c4SChris J Arges if (val != oval) { 43176b188c4SChris J Arges snd_usb_set_cur_mix_value(elem, 0, 0, val); 43276b188c4SChris J Arges return 1; 43376b188c4SChris J Arges } 43476b188c4SChris J Arges return 0; 43576b188c4SChris J Arges } 43676b188c4SChris J Arges 437b61f90eaSTakashi Iwai static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list) 438b61f90eaSTakashi Iwai { 4398c558076STakashi Iwai struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list); 440b61f90eaSTakashi Iwai 441b61f90eaSTakashi Iwai if (elem->cached) 442b61f90eaSTakashi Iwai snd_usb_set_cur_mix_value(elem, 0, 0, *elem->cache_val); 443b61f90eaSTakashi Iwai return 0; 444b61f90eaSTakashi Iwai } 445b61f90eaSTakashi Iwai 44676b188c4SChris J Arges static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl, 44776b188c4SChris J Arges struct snd_ctl_elem_value *ucontrol) 44876b188c4SChris J Arges { 44976b188c4SChris J Arges struct usb_mixer_elem_info *elem = kctl->private_data; 4503360b84bSTakashi Iwai struct snd_usb_audio *chip = elem->head.mixer->chip; 45176b188c4SChris J Arges unsigned char buf[2 * MAX_CHANNELS] = {0, }; 45276b188c4SChris J Arges int wValue = (elem->control << 8) | elem->idx_off; 4533360b84bSTakashi Iwai int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8); 45476b188c4SChris J Arges int err; 45576b188c4SChris J Arges 45676b188c4SChris J Arges err = snd_usb_ctl_msg(chip->dev, 45776b188c4SChris J Arges usb_rcvctrlpipe(chip->dev, 0), 45876b188c4SChris J Arges UAC2_CS_MEM, 45976b188c4SChris J Arges USB_RECIP_INTERFACE | USB_TYPE_CLASS | 46076b188c4SChris J Arges USB_DIR_IN, wValue, idx, buf, elem->channels); 46176b188c4SChris J Arges if (err < 0) 46276b188c4SChris J Arges return err; 46376b188c4SChris J Arges 46476b188c4SChris J Arges ucontrol->value.enumerated.item[0] = clamp((int)buf[0], 0, 1); 46576b188c4SChris J Arges return 0; 46676b188c4SChris J Arges } 46776b188c4SChris J Arges 46804bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_switch = { 46976b188c4SChris J Arges .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 47076b188c4SChris J Arges .name = "", 47176b188c4SChris J Arges .info = scarlett_ctl_switch_info, 47276b188c4SChris J Arges .get = scarlett_ctl_switch_get, 47376b188c4SChris J Arges .put = scarlett_ctl_switch_put, 47476b188c4SChris J Arges }; 47576b188c4SChris J Arges 47676b188c4SChris J Arges static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0); 47776b188c4SChris J Arges 47804bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl = { 47976b188c4SChris J Arges .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 48076b188c4SChris J Arges .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 48176b188c4SChris J Arges SNDRV_CTL_ELEM_ACCESS_TLV_READ, 48276b188c4SChris J Arges .name = "", 48376b188c4SChris J Arges .info = scarlett_ctl_info, 48476b188c4SChris J Arges .get = scarlett_ctl_get, 48576b188c4SChris J Arges .put = scarlett_ctl_put, 48676b188c4SChris J Arges .private_value = 6, /* max value */ 48776b188c4SChris J Arges .tlv = { .p = db_scale_scarlett_gain } 48876b188c4SChris J Arges }; 48976b188c4SChris J Arges 49004bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_master = { 49176b188c4SChris J Arges .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 49276b188c4SChris J Arges .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 49376b188c4SChris J Arges SNDRV_CTL_ELEM_ACCESS_TLV_READ, 49476b188c4SChris J Arges .name = "", 49576b188c4SChris J Arges .info = scarlett_ctl_info, 49676b188c4SChris J Arges .get = scarlett_ctl_get, 49776b188c4SChris J Arges .put = scarlett_ctl_put, 49876b188c4SChris J Arges .private_value = 6, /* max value */ 49976b188c4SChris J Arges .tlv = { .p = db_scale_scarlett_gain } 50076b188c4SChris J Arges }; 50176b188c4SChris J Arges 50204bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_enum = { 50376b188c4SChris J Arges .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 50476b188c4SChris J Arges .name = "", 50576b188c4SChris J Arges .info = scarlett_ctl_enum_info, 50676b188c4SChris J Arges .get = scarlett_ctl_enum_get, 50776b188c4SChris J Arges .put = scarlett_ctl_enum_put, 50876b188c4SChris J Arges }; 50976b188c4SChris J Arges 51004bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = { 51176b188c4SChris J Arges .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 51276b188c4SChris J Arges .name = "", 51376b188c4SChris J Arges .info = scarlett_ctl_enum_dynamic_info, 51476b188c4SChris J Arges .get = scarlett_ctl_enum_get, 51576b188c4SChris J Arges .put = scarlett_ctl_enum_put, 51676b188c4SChris J Arges }; 51776b188c4SChris J Arges 51804bab350SBhumika Goyal static const struct snd_kcontrol_new usb_scarlett_ctl_sync = { 51976b188c4SChris J Arges .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 52076b188c4SChris J Arges .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 52176b188c4SChris J Arges .name = "", 52276b188c4SChris J Arges .info = scarlett_ctl_enum_info, 52376b188c4SChris J Arges .get = scarlett_ctl_meter_get, 52476b188c4SChris J Arges }; 52576b188c4SChris J Arges 52676b188c4SChris J Arges static int add_new_ctl(struct usb_mixer_interface *mixer, 52776b188c4SChris J Arges const struct snd_kcontrol_new *ncontrol, 528b61f90eaSTakashi Iwai usb_mixer_elem_resume_func_t resume, 52976b188c4SChris J Arges int index, int offset, int num, 53076b188c4SChris J Arges int val_type, int channels, const char *name, 53176b188c4SChris J Arges const struct scarlett_mixer_elem_enum_info *opt, 53276b188c4SChris J Arges struct usb_mixer_elem_info **elem_ret 53376b188c4SChris J Arges ) 53476b188c4SChris J Arges { 53576b188c4SChris J Arges struct snd_kcontrol *kctl; 53676b188c4SChris J Arges struct usb_mixer_elem_info *elem; 53776b188c4SChris J Arges int err; 53876b188c4SChris J Arges 53976b188c4SChris J Arges elem = kzalloc(sizeof(*elem), GFP_KERNEL); 54076b188c4SChris J Arges if (!elem) 54176b188c4SChris J Arges return -ENOMEM; 54276b188c4SChris J Arges 5433360b84bSTakashi Iwai elem->head.mixer = mixer; 544b61f90eaSTakashi Iwai elem->head.resume = resume; 54576b188c4SChris J Arges elem->control = offset; 54676b188c4SChris J Arges elem->idx_off = num; 5473360b84bSTakashi Iwai elem->head.id = index; 54876b188c4SChris J Arges elem->val_type = val_type; 54976b188c4SChris J Arges 55076b188c4SChris J Arges elem->channels = channels; 55176b188c4SChris J Arges 55276b188c4SChris J Arges /* add scarlett_mixer_elem_enum_info struct */ 55376b188c4SChris J Arges elem->private_data = (void *)opt; 55476b188c4SChris J Arges 55576b188c4SChris J Arges kctl = snd_ctl_new1(ncontrol, elem); 55676b188c4SChris J Arges if (!kctl) { 55776b188c4SChris J Arges kfree(elem); 55876b188c4SChris J Arges return -ENOMEM; 55976b188c4SChris J Arges } 56076b188c4SChris J Arges kctl->private_free = snd_usb_mixer_elem_free; 56176b188c4SChris J Arges 56276b188c4SChris J Arges strlcpy(kctl->id.name, name, sizeof(kctl->id.name)); 56376b188c4SChris J Arges 564b61f90eaSTakashi Iwai err = snd_usb_mixer_add_control(&elem->head, kctl); 56576b188c4SChris J Arges if (err < 0) 56676b188c4SChris J Arges return err; 56776b188c4SChris J Arges 56876b188c4SChris J Arges if (elem_ret) 56976b188c4SChris J Arges *elem_ret = elem; 57076b188c4SChris J Arges 57176b188c4SChris J Arges return 0; 57276b188c4SChris J Arges } 57376b188c4SChris J Arges 57476b188c4SChris J Arges static int add_output_ctls(struct usb_mixer_interface *mixer, 57576b188c4SChris J Arges int index, const char *name, 57676b188c4SChris J Arges const struct scarlett_device_info *info) 57776b188c4SChris J Arges { 57876b188c4SChris J Arges int err; 57976b188c4SChris J Arges char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 58076b188c4SChris J Arges struct usb_mixer_elem_info *elem; 58176b188c4SChris J Arges 58276b188c4SChris J Arges /* Add mute switch */ 58376b188c4SChris J Arges snprintf(mx, sizeof(mx), "Master %d (%s) Playback Switch", 58476b188c4SChris J Arges index + 1, name); 585b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_switch, 586b61f90eaSTakashi Iwai scarlett_ctl_resume, 0x0a, 0x01, 58776b188c4SChris J Arges 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem); 58876b188c4SChris J Arges if (err < 0) 58976b188c4SChris J Arges return err; 59076b188c4SChris J Arges 59176b188c4SChris J Arges /* Add volume control and initialize to 0 */ 59276b188c4SChris J Arges snprintf(mx, sizeof(mx), "Master %d (%s) Playback Volume", 59376b188c4SChris J Arges index + 1, name); 594b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_master, 595b61f90eaSTakashi Iwai scarlett_ctl_resume, 0x0a, 0x02, 59676b188c4SChris J Arges 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem); 59776b188c4SChris J Arges if (err < 0) 59876b188c4SChris J Arges return err; 59976b188c4SChris J Arges 60076b188c4SChris J Arges /* Add L channel source playback enumeration */ 60176b188c4SChris J Arges snprintf(mx, sizeof(mx), "Master %dL (%s) Source Playback Enum", 60276b188c4SChris J Arges index + 1, name); 603b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, 604b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x33, 0x00, 60576b188c4SChris J Arges 2*index, USB_MIXER_S16, 1, mx, &info->opt_master, 60676b188c4SChris J Arges &elem); 60776b188c4SChris J Arges if (err < 0) 60876b188c4SChris J Arges return err; 60976b188c4SChris J Arges 61076b188c4SChris J Arges /* Add R channel source playback enumeration */ 61176b188c4SChris J Arges snprintf(mx, sizeof(mx), "Master %dR (%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+1, 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 return 0; 62176b188c4SChris J Arges } 62276b188c4SChris J Arges 62376b188c4SChris J Arges /********************** device-specific config *************************/ 62476b188c4SChris J Arges 62576b188c4SChris J Arges /* untested... */ 62676b188c4SChris J Arges static struct scarlett_device_info s6i6_info = { 62776b188c4SChris J Arges .matrix_in = 18, 62876b188c4SChris J Arges .matrix_out = 8, 62976b188c4SChris J Arges .input_len = 6, 63076b188c4SChris J Arges .output_len = 6, 63176b188c4SChris J Arges 63276b188c4SChris J Arges .opt_master = { 63376b188c4SChris J Arges .start = -1, 63476b188c4SChris J Arges .len = 27, 63576b188c4SChris J Arges .offsets = {0, 12, 16, 18, 18}, 63676b188c4SChris J Arges .names = NULL 63776b188c4SChris J Arges }, 63876b188c4SChris J Arges 63976b188c4SChris J Arges .opt_matrix = { 64076b188c4SChris J Arges .start = -1, 64176b188c4SChris J Arges .len = 19, 64276b188c4SChris J Arges .offsets = {0, 12, 16, 18, 18}, 64376b188c4SChris J Arges .names = NULL 64476b188c4SChris J Arges }, 64576b188c4SChris J Arges 646c99b9e85SChris J Arges .num_controls = 9, 64776b188c4SChris J Arges .controls = { 64876b188c4SChris J Arges { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, 64976b188c4SChris J Arges { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" }, 65076b188c4SChris J Arges { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, 65176b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, 65276b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 65376b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, 65476b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 65576b188c4SChris J Arges { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 65676b188c4SChris J Arges { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 65776b188c4SChris J Arges }, 65876b188c4SChris J Arges 65976b188c4SChris J Arges .matrix_mux_init = { 66076b188c4SChris J Arges 12, 13, 14, 15, /* Analog -> 1..4 */ 66176b188c4SChris J Arges 16, 17, /* SPDIF -> 5,6 */ 66276b188c4SChris J Arges 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */ 66376b188c4SChris J Arges 8, 9, 10, 11 66476b188c4SChris J Arges } 66576b188c4SChris J Arges }; 66676b188c4SChris J Arges 66776b188c4SChris J Arges /* untested... */ 66876b188c4SChris J Arges static struct scarlett_device_info s8i6_info = { 66976b188c4SChris J Arges .matrix_in = 18, 67076b188c4SChris J Arges .matrix_out = 6, 67176b188c4SChris J Arges .input_len = 8, 67276b188c4SChris J Arges .output_len = 6, 67376b188c4SChris J Arges 67476b188c4SChris J Arges .opt_master = { 67576b188c4SChris J Arges .start = -1, 67676b188c4SChris J Arges .len = 25, 67776b188c4SChris J Arges .offsets = {0, 12, 16, 18, 18}, 67876b188c4SChris J Arges .names = NULL 67976b188c4SChris J Arges }, 68076b188c4SChris J Arges 68176b188c4SChris J Arges .opt_matrix = { 68276b188c4SChris J Arges .start = -1, 68376b188c4SChris J Arges .len = 19, 68476b188c4SChris J Arges .offsets = {0, 12, 16, 18, 18}, 68576b188c4SChris J Arges .names = NULL 68676b188c4SChris J Arges }, 68776b188c4SChris J Arges 68876b188c4SChris J Arges .num_controls = 7, 68976b188c4SChris J Arges .controls = { 69076b188c4SChris J Arges { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, 69176b188c4SChris J Arges { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" }, 69276b188c4SChris J Arges { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, 69376b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, 69476b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, 69576b188c4SChris J Arges { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 69676b188c4SChris J Arges { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 69776b188c4SChris J Arges }, 69876b188c4SChris J Arges 69976b188c4SChris J Arges .matrix_mux_init = { 70076b188c4SChris J Arges 12, 13, 14, 15, /* Analog -> 1..4 */ 70176b188c4SChris J Arges 16, 17, /* SPDIF -> 5,6 */ 70276b188c4SChris J Arges 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */ 70376b188c4SChris J Arges 8, 9, 10, 11 70476b188c4SChris J Arges } 70576b188c4SChris J Arges }; 70676b188c4SChris J Arges 70776b188c4SChris J Arges static struct scarlett_device_info s18i6_info = { 70876b188c4SChris J Arges .matrix_in = 18, 70976b188c4SChris J Arges .matrix_out = 6, 71076b188c4SChris J Arges .input_len = 18, 71176b188c4SChris J Arges .output_len = 6, 71276b188c4SChris J Arges 71376b188c4SChris J Arges .opt_master = { 71476b188c4SChris J Arges .start = -1, 71576b188c4SChris J Arges .len = 31, 71676b188c4SChris J Arges .offsets = {0, 6, 14, 16, 24}, 71776b188c4SChris J Arges .names = NULL, 71876b188c4SChris J Arges }, 71976b188c4SChris J Arges 72076b188c4SChris J Arges .opt_matrix = { 72176b188c4SChris J Arges .start = -1, 72276b188c4SChris J Arges .len = 25, 72376b188c4SChris J Arges .offsets = {0, 6, 14, 16, 24}, 72476b188c4SChris J Arges .names = NULL, 72576b188c4SChris J Arges }, 72676b188c4SChris J Arges 72776b188c4SChris J Arges .num_controls = 5, 72876b188c4SChris J Arges .controls = { 72976b188c4SChris J Arges { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, 73076b188c4SChris J Arges { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" }, 73176b188c4SChris J Arges { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, 73276b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, 73376b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, 73476b188c4SChris J Arges }, 73576b188c4SChris J Arges 73676b188c4SChris J Arges .matrix_mux_init = { 73776b188c4SChris J Arges 6, 7, 8, 9, 10, 11, 12, 13, /* Analog -> 1..8 */ 73876b188c4SChris J Arges 16, 17, 18, 19, 20, 21, /* ADAT[1..6] -> 9..14 */ 73976b188c4SChris J Arges 14, 15, /* SPDIF -> 15,16 */ 74076b188c4SChris J Arges 0, 1 /* PCM[1,2] -> 17,18 */ 74176b188c4SChris J Arges } 74276b188c4SChris J Arges }; 74376b188c4SChris J Arges 74476b188c4SChris J Arges static struct scarlett_device_info s18i8_info = { 74576b188c4SChris J Arges .matrix_in = 18, 74676b188c4SChris J Arges .matrix_out = 8, 74776b188c4SChris J Arges .input_len = 18, 74876b188c4SChris J Arges .output_len = 8, 74976b188c4SChris J Arges 75076b188c4SChris J Arges .opt_master = { 75176b188c4SChris J Arges .start = -1, 75276b188c4SChris J Arges .len = 35, 75376b188c4SChris J Arges .offsets = {0, 8, 16, 18, 26}, 75476b188c4SChris J Arges .names = NULL 75576b188c4SChris J Arges }, 75676b188c4SChris J Arges 75776b188c4SChris J Arges .opt_matrix = { 75876b188c4SChris J Arges .start = -1, 75976b188c4SChris J Arges .len = 27, 76076b188c4SChris J Arges .offsets = {0, 8, 16, 18, 26}, 76176b188c4SChris J Arges .names = NULL 76276b188c4SChris J Arges }, 76376b188c4SChris J Arges 76476b188c4SChris J Arges .num_controls = 10, 76576b188c4SChris J Arges .controls = { 76676b188c4SChris J Arges { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, 76776b188c4SChris J Arges { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone 1" }, 76876b188c4SChris J Arges { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Headphone 2" }, 76976b188c4SChris J Arges { .num = 3, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, 77076b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, 77176b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 77276b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, 77376b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 77476b188c4SChris J Arges { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 77576b188c4SChris J Arges { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 77676b188c4SChris J Arges }, 77776b188c4SChris J Arges 77876b188c4SChris J Arges .matrix_mux_init = { 77976b188c4SChris J Arges 8, 9, 10, 11, 12, 13, 14, 15, /* Analog -> 1..8 */ 78076b188c4SChris J Arges 18, 19, 20, 21, 22, 23, /* ADAT[1..6] -> 9..14 */ 78176b188c4SChris J Arges 16, 17, /* SPDIF -> 15,16 */ 78276b188c4SChris J Arges 0, 1 /* PCM[1,2] -> 17,18 */ 78376b188c4SChris J Arges } 78476b188c4SChris J Arges }; 78576b188c4SChris J Arges 78676b188c4SChris J Arges static struct scarlett_device_info s18i20_info = { 78776b188c4SChris J Arges .matrix_in = 18, 78876b188c4SChris J Arges .matrix_out = 8, 78976b188c4SChris J Arges .input_len = 18, 79076b188c4SChris J Arges .output_len = 20, 79176b188c4SChris J Arges 79276b188c4SChris J Arges .opt_master = { 79376b188c4SChris J Arges .start = -1, 79476b188c4SChris J Arges .len = 47, 79576b188c4SChris J Arges .offsets = {0, 20, 28, 30, 38}, 79676b188c4SChris J Arges .names = NULL 79776b188c4SChris J Arges }, 79876b188c4SChris J Arges 79976b188c4SChris J Arges .opt_matrix = { 80076b188c4SChris J Arges .start = -1, 80176b188c4SChris J Arges .len = 39, 80276b188c4SChris J Arges .offsets = {0, 20, 28, 30, 38}, 80376b188c4SChris J Arges .names = NULL 80476b188c4SChris J Arges }, 80576b188c4SChris J Arges 80676b188c4SChris J Arges .num_controls = 10, 80776b188c4SChris J Arges .controls = { 80876b188c4SChris J Arges { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" }, 80976b188c4SChris J Arges { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Line 3/4" }, 81076b188c4SChris J Arges { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Line 5/6" }, 81176b188c4SChris J Arges { .num = 3, .type = SCARLETT_OUTPUTS, .name = "Line 7/8" }, 81276b188c4SChris J Arges { .num = 4, .type = SCARLETT_OUTPUTS, .name = "Line 9/10" }, 81376b188c4SChris J Arges { .num = 5, .type = SCARLETT_OUTPUTS, .name = "SPDIF" }, 81476b188c4SChris J Arges { .num = 6, .type = SCARLETT_OUTPUTS, .name = "ADAT 1/2" }, 81576b188c4SChris J Arges { .num = 7, .type = SCARLETT_OUTPUTS, .name = "ADAT 3/4" }, 81676b188c4SChris J Arges { .num = 8, .type = SCARLETT_OUTPUTS, .name = "ADAT 5/6" }, 81776b188c4SChris J Arges { .num = 9, .type = SCARLETT_OUTPUTS, .name = "ADAT 7/8" }, 81876b188c4SChris J Arges /*{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, 81976b188c4SChris J Arges { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 82076b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL}, 82176b188c4SChris J Arges { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 82276b188c4SChris J Arges { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL}, 82376b188c4SChris J Arges { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},*/ 82476b188c4SChris J Arges }, 82576b188c4SChris J Arges 82676b188c4SChris J Arges .matrix_mux_init = { 82776b188c4SChris J Arges 20, 21, 22, 23, 24, 25, 26, 27, /* Analog -> 1..8 */ 82876b188c4SChris J Arges 30, 31, 32, 33, 34, 35, /* ADAT[1..6] -> 9..14 */ 82976b188c4SChris J Arges 28, 29, /* SPDIF -> 15,16 */ 83076b188c4SChris J Arges 0, 1 /* PCM[1,2] -> 17,18 */ 83176b188c4SChris J Arges } 83276b188c4SChris J Arges }; 83376b188c4SChris J Arges 83476b188c4SChris J Arges 83576b188c4SChris J Arges static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer, 83676b188c4SChris J Arges struct scarlett_device_info *info) 83776b188c4SChris J Arges { 83876b188c4SChris J Arges int i, err; 83976b188c4SChris J Arges char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 84076b188c4SChris J Arges const struct scarlett_mixer_control *ctl; 84176b188c4SChris J Arges struct usb_mixer_elem_info *elem; 84276b188c4SChris J Arges 84376b188c4SChris J Arges /* create master switch and playback volume */ 844b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_switch, 845b61f90eaSTakashi Iwai scarlett_ctl_resume, 0x0a, 0x01, 0, 84676b188c4SChris J Arges USB_MIXER_S16, 1, "Master Playback Switch", NULL, 84776b188c4SChris J Arges &elem); 84876b188c4SChris J Arges if (err < 0) 84976b188c4SChris J Arges return err; 85076b188c4SChris J Arges 851b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_master, 852b61f90eaSTakashi Iwai scarlett_ctl_resume, 0x0a, 0x02, 0, 85376b188c4SChris J Arges USB_MIXER_S16, 1, "Master Playback Volume", NULL, 85476b188c4SChris J Arges &elem); 85576b188c4SChris J Arges if (err < 0) 85676b188c4SChris J Arges return err; 85776b188c4SChris J Arges 85876b188c4SChris J Arges /* iterate through controls in info struct and create each one */ 85976b188c4SChris J Arges for (i = 0; i < info->num_controls; i++) { 86076b188c4SChris J Arges ctl = &info->controls[i]; 86176b188c4SChris J Arges 86276b188c4SChris J Arges switch (ctl->type) { 86376b188c4SChris J Arges case SCARLETT_OUTPUTS: 86476b188c4SChris J Arges err = add_output_ctls(mixer, ctl->num, ctl->name, info); 86576b188c4SChris J Arges if (err < 0) 86676b188c4SChris J Arges return err; 86776b188c4SChris J Arges break; 86876b188c4SChris J Arges case SCARLETT_SWITCH_IMPEDANCE: 86976b188c4SChris J Arges sprintf(mx, "Input %d Impedance Switch", ctl->num); 870b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, 871b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x01, 87276b188c4SChris J Arges 0x09, ctl->num, USB_MIXER_S16, 1, mx, 87376b188c4SChris J Arges &opt_impedance, &elem); 87476b188c4SChris J Arges if (err < 0) 87576b188c4SChris J Arges return err; 87676b188c4SChris J Arges break; 87776b188c4SChris J Arges case SCARLETT_SWITCH_PAD: 87876b188c4SChris J Arges sprintf(mx, "Input %d Pad Switch", ctl->num); 879b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, 880b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x01, 88176b188c4SChris J Arges 0x0b, ctl->num, USB_MIXER_S16, 1, mx, 88276b188c4SChris J Arges &opt_pad, &elem); 88376b188c4SChris J Arges if (err < 0) 88476b188c4SChris J Arges return err; 88576b188c4SChris J Arges break; 88676b188c4SChris J Arges } 88776b188c4SChris J Arges } 88876b188c4SChris J Arges 88976b188c4SChris J Arges return 0; 89076b188c4SChris J Arges } 89176b188c4SChris J Arges 89276b188c4SChris J Arges /* 89376b188c4SChris J Arges * Create and initialize a mixer for the Focusrite(R) Scarlett 89476b188c4SChris J Arges */ 89576b188c4SChris J Arges int snd_scarlett_controls_create(struct usb_mixer_interface *mixer) 89676b188c4SChris J Arges { 89776b188c4SChris J Arges int err, i, o; 89876b188c4SChris J Arges char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 89976b188c4SChris J Arges struct scarlett_device_info *info; 90076b188c4SChris J Arges struct usb_mixer_elem_info *elem; 90176b188c4SChris J Arges static char sample_rate_buffer[4] = { '\x80', '\xbb', '\x00', '\x00' }; 90276b188c4SChris J Arges 90376b188c4SChris J Arges /* only use UAC_VERSION_2 */ 90476b188c4SChris J Arges if (!mixer->protocol) 90576b188c4SChris J Arges return 0; 90676b188c4SChris J Arges 90776b188c4SChris J Arges switch (mixer->chip->usb_id) { 90876b188c4SChris J Arges case USB_ID(0x1235, 0x8012): 90976b188c4SChris J Arges info = &s6i6_info; 91076b188c4SChris J Arges break; 91176b188c4SChris J Arges case USB_ID(0x1235, 0x8002): 91276b188c4SChris J Arges info = &s8i6_info; 91376b188c4SChris J Arges break; 91476b188c4SChris J Arges case USB_ID(0x1235, 0x8004): 91576b188c4SChris J Arges info = &s18i6_info; 91676b188c4SChris J Arges break; 91776b188c4SChris J Arges case USB_ID(0x1235, 0x8014): 91876b188c4SChris J Arges info = &s18i8_info; 91976b188c4SChris J Arges break; 92076b188c4SChris J Arges case USB_ID(0x1235, 0x800c): 92176b188c4SChris J Arges info = &s18i20_info; 92276b188c4SChris J Arges break; 92376b188c4SChris J Arges default: /* device not (yet) supported */ 92476b188c4SChris J Arges return -EINVAL; 92576b188c4SChris J Arges } 92676b188c4SChris J Arges 92776b188c4SChris J Arges /* generic function to create controls */ 92876b188c4SChris J Arges err = scarlett_controls_create_generic(mixer, info); 92976b188c4SChris J Arges if (err < 0) 93076b188c4SChris J Arges return err; 93176b188c4SChris J Arges 93276b188c4SChris J Arges /* setup matrix controls */ 93376b188c4SChris J Arges for (i = 0; i < info->matrix_in; i++) { 93476b188c4SChris J Arges snprintf(mx, sizeof(mx), "Matrix %02d Input Playback Route", 93576b188c4SChris J Arges i+1); 936b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, 937b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x32, 93876b188c4SChris J Arges 0x06, i, USB_MIXER_S16, 1, mx, 93976b188c4SChris J Arges &info->opt_matrix, &elem); 94076b188c4SChris J Arges if (err < 0) 94176b188c4SChris J Arges return err; 94276b188c4SChris J Arges 94376b188c4SChris J Arges for (o = 0; o < info->matrix_out; o++) { 94476b188c4SChris J Arges sprintf(mx, "Matrix %02d Mix %c Playback Volume", i+1, 94576b188c4SChris J Arges o+'A'); 946b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl, 947b61f90eaSTakashi Iwai scarlett_ctl_resume, 0x3c, 0x00, 94876b188c4SChris J Arges (i << 3) + (o & 0x07), USB_MIXER_S16, 94976b188c4SChris J Arges 1, mx, NULL, &elem); 95076b188c4SChris J Arges if (err < 0) 95176b188c4SChris J Arges return err; 95276b188c4SChris J Arges 95376b188c4SChris J Arges } 95476b188c4SChris J Arges } 95576b188c4SChris J Arges 95676b188c4SChris J Arges for (i = 0; i < info->input_len; i++) { 95776b188c4SChris J Arges snprintf(mx, sizeof(mx), "Input Source %02d Capture Route", 95876b188c4SChris J Arges i+1); 959b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum, 960b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x34, 96176b188c4SChris J Arges 0x00, i, USB_MIXER_S16, 1, mx, 96276b188c4SChris J Arges &info->opt_master, &elem); 96376b188c4SChris J Arges if (err < 0) 96476b188c4SChris J Arges return err; 96576b188c4SChris J Arges } 96676b188c4SChris J Arges 96776b188c4SChris J Arges /* val_len == 1 needed here */ 968b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_enum, 969b61f90eaSTakashi Iwai scarlett_ctl_enum_resume, 0x28, 0x01, 0, 97076b188c4SChris J Arges USB_MIXER_U8, 1, "Sample Clock Source", 97176b188c4SChris J Arges &opt_clock, &elem); 97276b188c4SChris J Arges if (err < 0) 97376b188c4SChris J Arges return err; 97476b188c4SChris J Arges 97576b188c4SChris J Arges /* val_len == 1 and UAC2_CS_MEM */ 976b61f90eaSTakashi Iwai err = add_new_ctl(mixer, &usb_scarlett_ctl_sync, NULL, 0x3c, 0x00, 2, 97776b188c4SChris J Arges USB_MIXER_U8, 1, "Sample Clock Sync Status", 97876b188c4SChris J Arges &opt_sync, &elem); 97976b188c4SChris J Arges if (err < 0) 98076b188c4SChris J Arges return err; 98176b188c4SChris J Arges 98276b188c4SChris J Arges /* initialize sampling rate to 48000 */ 98376b188c4SChris J Arges err = snd_usb_ctl_msg(mixer->chip->dev, 98476b188c4SChris J Arges usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR, 98576b188c4SChris J Arges USB_RECIP_INTERFACE | USB_TYPE_CLASS | 98676b188c4SChris J Arges USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) | 98776b188c4SChris J Arges (0x29 << 8), sample_rate_buffer, 4); 98876b188c4SChris J Arges if (err < 0) 98976b188c4SChris J Arges return err; 99076b188c4SChris J Arges 99176b188c4SChris J Arges return err; 99276b188c4SChris J Arges } 993