18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Focusrite Scarlett 6i6/18i8/18i20 Gen 2 Driver for ALSA 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2018-2019 by Geoffrey D. Bennett <g at b4.vu> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on the Scarlett (Gen 1) Driver for ALSA: 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (c) 2013 by Tobias Hoffmann 108c2ecf20Sopenharmony_ci * Copyright (c) 2013 by Robin Gareus <robin at gareus.org> 118c2ecf20Sopenharmony_ci * Copyright (c) 2002 by Takashi Iwai <tiwai at suse.de> 128c2ecf20Sopenharmony_ci * Copyright (c) 2014 by Chris J Arges <chris.j.arges at canonical.com> 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Many codes borrowed from audio.c by 158c2ecf20Sopenharmony_ci * Alan Cox (alan at lxorguk.ukuu.org.uk) 168c2ecf20Sopenharmony_ci * Thomas Sailer (sailer at ife.ee.ethz.ch) 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Code cleanup: 198c2ecf20Sopenharmony_ci * David Henningsson <david.henningsson at canonical.com> 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Mixer Interface for the Focusrite Scarlett 6i6/18i8/18i20 Gen 2 audio 238c2ecf20Sopenharmony_ci * interface. Based on the Gen 1 driver and rewritten. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* The protocol was reverse engineered by looking at the communication 278c2ecf20Sopenharmony_ci * between Focusrite Control 2.3.4 and the Focusrite(R) Scarlett 18i20 288c2ecf20Sopenharmony_ci * (firmware 1083) using usbmon in July-August 2018. 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * Scarlett 18i8 support added in April 2019. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * Scarlett 6i6 support added in June 2019 (thanks to Martin Wittmann 338c2ecf20Sopenharmony_ci * for providing usbmon output and testing). 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * This ALSA mixer gives access to: 368c2ecf20Sopenharmony_ci * - input, output, mixer-matrix muxes 378c2ecf20Sopenharmony_ci * - 18x10 mixer-matrix gain stages 388c2ecf20Sopenharmony_ci * - gain/volume controls 398c2ecf20Sopenharmony_ci * - level meters 408c2ecf20Sopenharmony_ci * - line/inst level and pad controls 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * <ditaa> 438c2ecf20Sopenharmony_ci * /--------------\ 18chn 20chn /--------------\ 448c2ecf20Sopenharmony_ci * | Hardware in +--+------\ /-------------+--+ ALSA PCM out | 458c2ecf20Sopenharmony_ci * \--------------/ | | | | \--------------/ 468c2ecf20Sopenharmony_ci * | | | /-----\ | 478c2ecf20Sopenharmony_ci * | | | | | | 488c2ecf20Sopenharmony_ci * | v v v | | 498c2ecf20Sopenharmony_ci * | +---------------+ | | 508c2ecf20Sopenharmony_ci * | \ Matrix Mux / | | 518c2ecf20Sopenharmony_ci * | +-----+-----+ | | 528c2ecf20Sopenharmony_ci * | | | | 538c2ecf20Sopenharmony_ci * | |18chn | | 548c2ecf20Sopenharmony_ci * | | | | 558c2ecf20Sopenharmony_ci * | | 10chn| | 568c2ecf20Sopenharmony_ci * | v | | 578c2ecf20Sopenharmony_ci * | +------------+ | | 588c2ecf20Sopenharmony_ci * | | Mixer | | | 598c2ecf20Sopenharmony_ci * | | Matrix | | | 608c2ecf20Sopenharmony_ci * | | | | | 618c2ecf20Sopenharmony_ci * | | 18x10 Gain | | | 628c2ecf20Sopenharmony_ci * | | stages | | | 638c2ecf20Sopenharmony_ci * | +-----+------+ | | 648c2ecf20Sopenharmony_ci * | | | | 658c2ecf20Sopenharmony_ci * |18chn |10chn | |20chn 668c2ecf20Sopenharmony_ci * | | | | 678c2ecf20Sopenharmony_ci * | +----------/ | 688c2ecf20Sopenharmony_ci * | | | 698c2ecf20Sopenharmony_ci * v v v 708c2ecf20Sopenharmony_ci * =========================== 718c2ecf20Sopenharmony_ci * +---------------+ +--—------------+ 728c2ecf20Sopenharmony_ci * \ Output Mux / \ Capture Mux / 738c2ecf20Sopenharmony_ci * +---+---+---+ +-----+-----+ 748c2ecf20Sopenharmony_ci * | | | 758c2ecf20Sopenharmony_ci * 10chn| | |18chn 768c2ecf20Sopenharmony_ci * | | | 778c2ecf20Sopenharmony_ci * /--------------\ | | | /--------------\ 788c2ecf20Sopenharmony_ci * | S/PDIF, ADAT |<--/ |10chn \-->| ALSA PCM in | 798c2ecf20Sopenharmony_ci * | Hardware out | | \--------------/ 808c2ecf20Sopenharmony_ci * \--------------/ | 818c2ecf20Sopenharmony_ci * v 828c2ecf20Sopenharmony_ci * +-------------+ Software gain per channel. 838c2ecf20Sopenharmony_ci * | Master Gain |<-- 18i20 only: Switch per channel 848c2ecf20Sopenharmony_ci * +------+------+ to select HW or SW gain control. 858c2ecf20Sopenharmony_ci * | 868c2ecf20Sopenharmony_ci * |10chn 878c2ecf20Sopenharmony_ci * /--------------\ | 888c2ecf20Sopenharmony_ci * | Analogue |<------/ 898c2ecf20Sopenharmony_ci * | Hardware out | 908c2ecf20Sopenharmony_ci * \--------------/ 918c2ecf20Sopenharmony_ci * </ditaa> 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci#include <linux/slab.h> 968c2ecf20Sopenharmony_ci#include <linux/usb.h> 978c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci#include <sound/control.h> 1008c2ecf20Sopenharmony_ci#include <sound/tlv.h> 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#include "usbaudio.h" 1038c2ecf20Sopenharmony_ci#include "mixer.h" 1048c2ecf20Sopenharmony_ci#include "helper.h" 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#include "mixer_scarlett_gen2.h" 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* device_setup value to enable */ 1098c2ecf20Sopenharmony_ci#define SCARLETT2_ENABLE 0x01 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* some gui mixers can't handle negative ctl values */ 1128c2ecf20Sopenharmony_ci#define SCARLETT2_VOLUME_BIAS 127 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* mixer range from -80dB to +6dB in 0.5dB steps */ 1158c2ecf20Sopenharmony_ci#define SCARLETT2_MIXER_MIN_DB -80 1168c2ecf20Sopenharmony_ci#define SCARLETT2_MIXER_BIAS (-SCARLETT2_MIXER_MIN_DB * 2) 1178c2ecf20Sopenharmony_ci#define SCARLETT2_MIXER_MAX_DB 6 1188c2ecf20Sopenharmony_ci#define SCARLETT2_MIXER_MAX_VALUE \ 1198c2ecf20Sopenharmony_ci ((SCARLETT2_MIXER_MAX_DB - SCARLETT2_MIXER_MIN_DB) * 2) 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* map from (dB + 80) * 2 to mixer value 1228c2ecf20Sopenharmony_ci * for dB in 0 .. 172: int(8192 * pow(10, ((dB - 160) / 2 / 20))) 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_cistatic const u16 scarlett2_mixer_values[173] = { 1258c2ecf20Sopenharmony_ci 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1268c2ecf20Sopenharmony_ci 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 1278c2ecf20Sopenharmony_ci 9, 9, 10, 10, 11, 12, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 1288c2ecf20Sopenharmony_ci 23, 24, 25, 27, 29, 30, 32, 34, 36, 38, 41, 43, 46, 48, 51, 1298c2ecf20Sopenharmony_ci 54, 57, 61, 65, 68, 73, 77, 81, 86, 91, 97, 103, 109, 115, 1308c2ecf20Sopenharmony_ci 122, 129, 137, 145, 154, 163, 173, 183, 194, 205, 217, 230, 1318c2ecf20Sopenharmony_ci 244, 259, 274, 290, 307, 326, 345, 365, 387, 410, 434, 460, 1328c2ecf20Sopenharmony_ci 487, 516, 547, 579, 614, 650, 689, 730, 773, 819, 867, 919, 1338c2ecf20Sopenharmony_ci 973, 1031, 1092, 1157, 1225, 1298, 1375, 1456, 1543, 1634, 1348c2ecf20Sopenharmony_ci 1731, 1833, 1942, 2057, 2179, 2308, 2445, 2590, 2744, 2906, 1358c2ecf20Sopenharmony_ci 3078, 3261, 3454, 3659, 3876, 4105, 4349, 4606, 4879, 5168, 1368c2ecf20Sopenharmony_ci 5475, 5799, 6143, 6507, 6892, 7301, 7733, 8192, 8677, 9191, 1378c2ecf20Sopenharmony_ci 9736, 10313, 10924, 11571, 12257, 12983, 13752, 14567, 15430, 1388c2ecf20Sopenharmony_ci 16345 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/* Maximum number of analogue outputs */ 1428c2ecf20Sopenharmony_ci#define SCARLETT2_ANALOGUE_MAX 10 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* Maximum number of level and pad switches */ 1458c2ecf20Sopenharmony_ci#define SCARLETT2_LEVEL_SWITCH_MAX 2 1468c2ecf20Sopenharmony_ci#define SCARLETT2_PAD_SWITCH_MAX 4 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* Maximum number of inputs to the mixer */ 1498c2ecf20Sopenharmony_ci#define SCARLETT2_INPUT_MIX_MAX 18 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* Maximum number of outputs from the mixer */ 1528c2ecf20Sopenharmony_ci#define SCARLETT2_OUTPUT_MIX_MAX 10 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* Maximum size of the data in the USB mux assignment message: 1558c2ecf20Sopenharmony_ci * 18 inputs, 20 outputs, 18 matrix inputs, 8 spare 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci#define SCARLETT2_MUX_MAX 64 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* Number of meters: 1608c2ecf20Sopenharmony_ci * 18 inputs, 20 outputs, 18 matrix inputs 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_ci#define SCARLETT2_NUM_METERS 56 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* Hardware port types: 1658c2ecf20Sopenharmony_ci * - None (no input to mux) 1668c2ecf20Sopenharmony_ci * - Analogue I/O 1678c2ecf20Sopenharmony_ci * - S/PDIF I/O 1688c2ecf20Sopenharmony_ci * - ADAT I/O 1698c2ecf20Sopenharmony_ci * - Mixer I/O 1708c2ecf20Sopenharmony_ci * - PCM I/O 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_cienum { 1738c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_NONE = 0, 1748c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_ANALOGUE = 1, 1758c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_SPDIF = 2, 1768c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_ADAT = 3, 1778c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_MIX = 4, 1788c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_PCM = 5, 1798c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_COUNT = 6, 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* Count of total I/O and number available at each sample rate */ 1838c2ecf20Sopenharmony_cienum { 1848c2ecf20Sopenharmony_ci SCARLETT2_PORT_IN = 0, 1858c2ecf20Sopenharmony_ci SCARLETT2_PORT_OUT = 1, 1868c2ecf20Sopenharmony_ci SCARLETT2_PORT_OUT_44 = 2, 1878c2ecf20Sopenharmony_ci SCARLETT2_PORT_OUT_88 = 3, 1888c2ecf20Sopenharmony_ci SCARLETT2_PORT_OUT_176 = 4, 1898c2ecf20Sopenharmony_ci SCARLETT2_PORT_DIRECTIONS = 5, 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* Hardware buttons on the 18i20 */ 1938c2ecf20Sopenharmony_ci#define SCARLETT2_BUTTON_MAX 2 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic const char *const scarlett2_button_names[SCARLETT2_BUTTON_MAX] = { 1968c2ecf20Sopenharmony_ci "Mute", "Dim" 1978c2ecf20Sopenharmony_ci}; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* Description of each hardware port type: 2008c2ecf20Sopenharmony_ci * - id: hardware ID for this port type 2018c2ecf20Sopenharmony_ci * - num: number of sources/destinations of this port type 2028c2ecf20Sopenharmony_ci * - src_descr: printf format string for mux input selections 2038c2ecf20Sopenharmony_ci * - src_num_offset: added to channel number for the fprintf 2048c2ecf20Sopenharmony_ci * - dst_descr: printf format string for mixer controls 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_cistruct scarlett2_ports { 2078c2ecf20Sopenharmony_ci u16 id; 2088c2ecf20Sopenharmony_ci int num[SCARLETT2_PORT_DIRECTIONS]; 2098c2ecf20Sopenharmony_ci const char * const src_descr; 2108c2ecf20Sopenharmony_ci int src_num_offset; 2118c2ecf20Sopenharmony_ci const char * const dst_descr; 2128c2ecf20Sopenharmony_ci}; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistruct scarlett2_device_info { 2158c2ecf20Sopenharmony_ci u8 line_out_hw_vol; /* line out hw volume is sw controlled */ 2168c2ecf20Sopenharmony_ci u8 button_count; /* number of buttons */ 2178c2ecf20Sopenharmony_ci u8 level_input_count; /* inputs with level selectable */ 2188c2ecf20Sopenharmony_ci u8 pad_input_count; /* inputs with pad selectable */ 2198c2ecf20Sopenharmony_ci const char * const line_out_descrs[SCARLETT2_ANALOGUE_MAX]; 2208c2ecf20Sopenharmony_ci struct scarlett2_ports ports[SCARLETT2_PORT_TYPE_COUNT]; 2218c2ecf20Sopenharmony_ci}; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistruct scarlett2_mixer_data { 2248c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer; 2258c2ecf20Sopenharmony_ci struct mutex usb_mutex; /* prevent sending concurrent USB requests */ 2268c2ecf20Sopenharmony_ci struct mutex data_mutex; /* lock access to this data */ 2278c2ecf20Sopenharmony_ci struct delayed_work work; 2288c2ecf20Sopenharmony_ci const struct scarlett2_device_info *info; 2298c2ecf20Sopenharmony_ci int num_mux_srcs; 2308c2ecf20Sopenharmony_ci u16 scarlett2_seq; 2318c2ecf20Sopenharmony_ci u8 vol_updated; 2328c2ecf20Sopenharmony_ci u8 master_vol; 2338c2ecf20Sopenharmony_ci u8 vol[SCARLETT2_ANALOGUE_MAX]; 2348c2ecf20Sopenharmony_ci u8 vol_sw_hw_switch[SCARLETT2_ANALOGUE_MAX]; 2358c2ecf20Sopenharmony_ci u8 level_switch[SCARLETT2_LEVEL_SWITCH_MAX]; 2368c2ecf20Sopenharmony_ci u8 pad_switch[SCARLETT2_PAD_SWITCH_MAX]; 2378c2ecf20Sopenharmony_ci u8 buttons[SCARLETT2_BUTTON_MAX]; 2388c2ecf20Sopenharmony_ci struct snd_kcontrol *master_vol_ctl; 2398c2ecf20Sopenharmony_ci struct snd_kcontrol *vol_ctls[SCARLETT2_ANALOGUE_MAX]; 2408c2ecf20Sopenharmony_ci struct snd_kcontrol *button_ctls[SCARLETT2_BUTTON_MAX]; 2418c2ecf20Sopenharmony_ci u8 mux[SCARLETT2_MUX_MAX]; 2428c2ecf20Sopenharmony_ci u8 mix[SCARLETT2_INPUT_MIX_MAX * SCARLETT2_OUTPUT_MIX_MAX]; 2438c2ecf20Sopenharmony_ci}; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci/*** Model-specific data ***/ 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic const struct scarlett2_device_info s6i6_gen2_info = { 2488c2ecf20Sopenharmony_ci /* The first two analogue inputs can be switched between line 2498c2ecf20Sopenharmony_ci * and instrument levels. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci .level_input_count = 2, 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* The first two analogue inputs have an optional pad. */ 2548c2ecf20Sopenharmony_ci .pad_input_count = 2, 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci .line_out_descrs = { 2578c2ecf20Sopenharmony_ci "Headphones 1 L", 2588c2ecf20Sopenharmony_ci "Headphones 1 R", 2598c2ecf20Sopenharmony_ci "Headphones 2 L", 2608c2ecf20Sopenharmony_ci "Headphones 2 R", 2618c2ecf20Sopenharmony_ci }, 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci .ports = { 2648c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_NONE] = { 2658c2ecf20Sopenharmony_ci .id = 0x000, 2668c2ecf20Sopenharmony_ci .num = { 1, 0, 8, 8, 8 }, 2678c2ecf20Sopenharmony_ci .src_descr = "Off", 2688c2ecf20Sopenharmony_ci .src_num_offset = 0, 2698c2ecf20Sopenharmony_ci }, 2708c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_ANALOGUE] = { 2718c2ecf20Sopenharmony_ci .id = 0x080, 2728c2ecf20Sopenharmony_ci .num = { 4, 4, 4, 4, 4 }, 2738c2ecf20Sopenharmony_ci .src_descr = "Analogue %d", 2748c2ecf20Sopenharmony_ci .src_num_offset = 1, 2758c2ecf20Sopenharmony_ci .dst_descr = "Analogue Output %02d Playback" 2768c2ecf20Sopenharmony_ci }, 2778c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_SPDIF] = { 2788c2ecf20Sopenharmony_ci .id = 0x180, 2798c2ecf20Sopenharmony_ci .num = { 2, 2, 2, 2, 2 }, 2808c2ecf20Sopenharmony_ci .src_descr = "S/PDIF %d", 2818c2ecf20Sopenharmony_ci .src_num_offset = 1, 2828c2ecf20Sopenharmony_ci .dst_descr = "S/PDIF Output %d Playback" 2838c2ecf20Sopenharmony_ci }, 2848c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_MIX] = { 2858c2ecf20Sopenharmony_ci .id = 0x300, 2868c2ecf20Sopenharmony_ci .num = { 10, 18, 18, 18, 18 }, 2878c2ecf20Sopenharmony_ci .src_descr = "Mix %c", 2888c2ecf20Sopenharmony_ci .src_num_offset = 65, 2898c2ecf20Sopenharmony_ci .dst_descr = "Mixer Input %02d Capture" 2908c2ecf20Sopenharmony_ci }, 2918c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_PCM] = { 2928c2ecf20Sopenharmony_ci .id = 0x600, 2938c2ecf20Sopenharmony_ci .num = { 6, 6, 6, 6, 6 }, 2948c2ecf20Sopenharmony_ci .src_descr = "PCM %d", 2958c2ecf20Sopenharmony_ci .src_num_offset = 1, 2968c2ecf20Sopenharmony_ci .dst_descr = "PCM %02d Capture" 2978c2ecf20Sopenharmony_ci }, 2988c2ecf20Sopenharmony_ci }, 2998c2ecf20Sopenharmony_ci}; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic const struct scarlett2_device_info s18i8_gen2_info = { 3028c2ecf20Sopenharmony_ci /* The first two analogue inputs can be switched between line 3038c2ecf20Sopenharmony_ci * and instrument levels. 3048c2ecf20Sopenharmony_ci */ 3058c2ecf20Sopenharmony_ci .level_input_count = 2, 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* The first four analogue inputs have an optional pad. */ 3088c2ecf20Sopenharmony_ci .pad_input_count = 4, 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci .line_out_descrs = { 3118c2ecf20Sopenharmony_ci "Monitor L", 3128c2ecf20Sopenharmony_ci "Monitor R", 3138c2ecf20Sopenharmony_ci "Headphones 1 L", 3148c2ecf20Sopenharmony_ci "Headphones 1 R", 3158c2ecf20Sopenharmony_ci "Headphones 2 L", 3168c2ecf20Sopenharmony_ci "Headphones 2 R", 3178c2ecf20Sopenharmony_ci }, 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci .ports = { 3208c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_NONE] = { 3218c2ecf20Sopenharmony_ci .id = 0x000, 3228c2ecf20Sopenharmony_ci .num = { 1, 0, 8, 8, 4 }, 3238c2ecf20Sopenharmony_ci .src_descr = "Off", 3248c2ecf20Sopenharmony_ci .src_num_offset = 0, 3258c2ecf20Sopenharmony_ci }, 3268c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_ANALOGUE] = { 3278c2ecf20Sopenharmony_ci .id = 0x080, 3288c2ecf20Sopenharmony_ci .num = { 8, 6, 6, 6, 6 }, 3298c2ecf20Sopenharmony_ci .src_descr = "Analogue %d", 3308c2ecf20Sopenharmony_ci .src_num_offset = 1, 3318c2ecf20Sopenharmony_ci .dst_descr = "Analogue Output %02d Playback" 3328c2ecf20Sopenharmony_ci }, 3338c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_SPDIF] = { 3348c2ecf20Sopenharmony_ci .id = 0x180, 3358c2ecf20Sopenharmony_ci /* S/PDIF outputs aren't available at 192kHz 3368c2ecf20Sopenharmony_ci * but are included in the USB mux I/O 3378c2ecf20Sopenharmony_ci * assignment message anyway 3388c2ecf20Sopenharmony_ci */ 3398c2ecf20Sopenharmony_ci .num = { 2, 2, 2, 2, 2 }, 3408c2ecf20Sopenharmony_ci .src_descr = "S/PDIF %d", 3418c2ecf20Sopenharmony_ci .src_num_offset = 1, 3428c2ecf20Sopenharmony_ci .dst_descr = "S/PDIF Output %d Playback" 3438c2ecf20Sopenharmony_ci }, 3448c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_ADAT] = { 3458c2ecf20Sopenharmony_ci .id = 0x200, 3468c2ecf20Sopenharmony_ci .num = { 8, 0, 0, 0, 0 }, 3478c2ecf20Sopenharmony_ci .src_descr = "ADAT %d", 3488c2ecf20Sopenharmony_ci .src_num_offset = 1, 3498c2ecf20Sopenharmony_ci }, 3508c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_MIX] = { 3518c2ecf20Sopenharmony_ci .id = 0x300, 3528c2ecf20Sopenharmony_ci .num = { 10, 18, 18, 18, 18 }, 3538c2ecf20Sopenharmony_ci .src_descr = "Mix %c", 3548c2ecf20Sopenharmony_ci .src_num_offset = 65, 3558c2ecf20Sopenharmony_ci .dst_descr = "Mixer Input %02d Capture" 3568c2ecf20Sopenharmony_ci }, 3578c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_PCM] = { 3588c2ecf20Sopenharmony_ci .id = 0x600, 3598c2ecf20Sopenharmony_ci .num = { 8, 18, 18, 14, 10 }, 3608c2ecf20Sopenharmony_ci .src_descr = "PCM %d", 3618c2ecf20Sopenharmony_ci .src_num_offset = 1, 3628c2ecf20Sopenharmony_ci .dst_descr = "PCM %02d Capture" 3638c2ecf20Sopenharmony_ci }, 3648c2ecf20Sopenharmony_ci }, 3658c2ecf20Sopenharmony_ci}; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic const struct scarlett2_device_info s18i20_gen2_info = { 3688c2ecf20Sopenharmony_ci /* The analogue line outputs on the 18i20 can be switched 3698c2ecf20Sopenharmony_ci * between software and hardware volume control 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_ci .line_out_hw_vol = 1, 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* Mute and dim buttons */ 3748c2ecf20Sopenharmony_ci .button_count = 2, 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci .line_out_descrs = { 3778c2ecf20Sopenharmony_ci "Monitor L", 3788c2ecf20Sopenharmony_ci "Monitor R", 3798c2ecf20Sopenharmony_ci NULL, 3808c2ecf20Sopenharmony_ci NULL, 3818c2ecf20Sopenharmony_ci NULL, 3828c2ecf20Sopenharmony_ci NULL, 3838c2ecf20Sopenharmony_ci "Headphones 1 L", 3848c2ecf20Sopenharmony_ci "Headphones 1 R", 3858c2ecf20Sopenharmony_ci "Headphones 2 L", 3868c2ecf20Sopenharmony_ci "Headphones 2 R", 3878c2ecf20Sopenharmony_ci }, 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci .ports = { 3908c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_NONE] = { 3918c2ecf20Sopenharmony_ci .id = 0x000, 3928c2ecf20Sopenharmony_ci .num = { 1, 0, 8, 8, 6 }, 3938c2ecf20Sopenharmony_ci .src_descr = "Off", 3948c2ecf20Sopenharmony_ci .src_num_offset = 0, 3958c2ecf20Sopenharmony_ci }, 3968c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_ANALOGUE] = { 3978c2ecf20Sopenharmony_ci .id = 0x080, 3988c2ecf20Sopenharmony_ci .num = { 8, 10, 10, 10, 10 }, 3998c2ecf20Sopenharmony_ci .src_descr = "Analogue %d", 4008c2ecf20Sopenharmony_ci .src_num_offset = 1, 4018c2ecf20Sopenharmony_ci .dst_descr = "Analogue Output %02d Playback" 4028c2ecf20Sopenharmony_ci }, 4038c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_SPDIF] = { 4048c2ecf20Sopenharmony_ci /* S/PDIF outputs aren't available at 192kHz 4058c2ecf20Sopenharmony_ci * but are included in the USB mux I/O 4068c2ecf20Sopenharmony_ci * assignment message anyway 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_ci .id = 0x180, 4098c2ecf20Sopenharmony_ci .num = { 2, 2, 2, 2, 2 }, 4108c2ecf20Sopenharmony_ci .src_descr = "S/PDIF %d", 4118c2ecf20Sopenharmony_ci .src_num_offset = 1, 4128c2ecf20Sopenharmony_ci .dst_descr = "S/PDIF Output %d Playback" 4138c2ecf20Sopenharmony_ci }, 4148c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_ADAT] = { 4158c2ecf20Sopenharmony_ci .id = 0x200, 4168c2ecf20Sopenharmony_ci .num = { 8, 8, 8, 4, 0 }, 4178c2ecf20Sopenharmony_ci .src_descr = "ADAT %d", 4188c2ecf20Sopenharmony_ci .src_num_offset = 1, 4198c2ecf20Sopenharmony_ci .dst_descr = "ADAT Output %d Playback" 4208c2ecf20Sopenharmony_ci }, 4218c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_MIX] = { 4228c2ecf20Sopenharmony_ci .id = 0x300, 4238c2ecf20Sopenharmony_ci .num = { 10, 18, 18, 18, 18 }, 4248c2ecf20Sopenharmony_ci .src_descr = "Mix %c", 4258c2ecf20Sopenharmony_ci .src_num_offset = 65, 4268c2ecf20Sopenharmony_ci .dst_descr = "Mixer Input %02d Capture" 4278c2ecf20Sopenharmony_ci }, 4288c2ecf20Sopenharmony_ci [SCARLETT2_PORT_TYPE_PCM] = { 4298c2ecf20Sopenharmony_ci .id = 0x600, 4308c2ecf20Sopenharmony_ci .num = { 20, 18, 18, 14, 10 }, 4318c2ecf20Sopenharmony_ci .src_descr = "PCM %d", 4328c2ecf20Sopenharmony_ci .src_num_offset = 1, 4338c2ecf20Sopenharmony_ci .dst_descr = "PCM %02d Capture" 4348c2ecf20Sopenharmony_ci }, 4358c2ecf20Sopenharmony_ci }, 4368c2ecf20Sopenharmony_ci}; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci/* get the starting port index number for a given port type/direction */ 4398c2ecf20Sopenharmony_cistatic int scarlett2_get_port_start_num(const struct scarlett2_ports *ports, 4408c2ecf20Sopenharmony_ci int direction, int port_type) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci int i, num = 0; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci for (i = 0; i < port_type; i++) 4458c2ecf20Sopenharmony_ci num += ports[i].num[direction]; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return num; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci/*** USB Interactions ***/ 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci/* Vendor-Specific Interface, Endpoint, MaxPacketSize, Interval */ 4538c2ecf20Sopenharmony_ci#define SCARLETT2_USB_VENDOR_SPECIFIC_INTERFACE 5 4548c2ecf20Sopenharmony_ci#define SCARLETT2_USB_INTERRUPT_ENDPOINT 4 4558c2ecf20Sopenharmony_ci#define SCARLETT2_USB_INTERRUPT_MAX_DATA 64 4568c2ecf20Sopenharmony_ci#define SCARLETT2_USB_INTERRUPT_INTERVAL 3 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci/* Interrupt flags for volume and mute/dim button changes */ 4598c2ecf20Sopenharmony_ci#define SCARLETT2_USB_INTERRUPT_VOL_CHANGE 0x400000 4608c2ecf20Sopenharmony_ci#define SCARLETT2_USB_INTERRUPT_BUTTON_CHANGE 0x200000 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci/* Commands for sending/receiving requests/responses */ 4638c2ecf20Sopenharmony_ci#define SCARLETT2_USB_VENDOR_SPECIFIC_CMD_REQ 2 4648c2ecf20Sopenharmony_ci#define SCARLETT2_USB_VENDOR_SPECIFIC_CMD_RESP 3 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci#define SCARLETT2_USB_INIT_SEQ 0x00000000 4678c2ecf20Sopenharmony_ci#define SCARLETT2_USB_GET_METER_LEVELS 0x00001001 4688c2ecf20Sopenharmony_ci#define SCARLETT2_USB_SET_MIX 0x00002002 4698c2ecf20Sopenharmony_ci#define SCARLETT2_USB_SET_MUX 0x00003002 4708c2ecf20Sopenharmony_ci#define SCARLETT2_USB_GET_DATA 0x00800000 4718c2ecf20Sopenharmony_ci#define SCARLETT2_USB_SET_DATA 0x00800001 4728c2ecf20Sopenharmony_ci#define SCARLETT2_USB_DATA_CMD 0x00800002 4738c2ecf20Sopenharmony_ci#define SCARLETT2_USB_CONFIG_SAVE 6 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci#define SCARLETT2_USB_VOLUME_STATUS_OFFSET 0x31 4768c2ecf20Sopenharmony_ci#define SCARLETT2_USB_METER_LEVELS_GET_MAGIC 1 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/* volume status is read together (matches scarlett2_config_items[]) */ 4798c2ecf20Sopenharmony_cistruct scarlett2_usb_volume_status { 4808c2ecf20Sopenharmony_ci /* mute & dim buttons */ 4818c2ecf20Sopenharmony_ci u8 buttons[SCARLETT2_BUTTON_MAX]; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci u8 pad1; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* software volume setting */ 4868c2ecf20Sopenharmony_ci s16 sw_vol[SCARLETT2_ANALOGUE_MAX]; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* actual volume of output inc. dim (-18dB) */ 4898c2ecf20Sopenharmony_ci s16 hw_vol[SCARLETT2_ANALOGUE_MAX]; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci u8 pad2[SCARLETT2_ANALOGUE_MAX]; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* sw (0) or hw (1) controlled */ 4948c2ecf20Sopenharmony_ci u8 sw_hw_switch[SCARLETT2_ANALOGUE_MAX]; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci u8 pad3[6]; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci /* front panel volume knob */ 4998c2ecf20Sopenharmony_ci s16 master_vol; 5008c2ecf20Sopenharmony_ci} __packed; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci/* Configuration parameters that can be read and written */ 5038c2ecf20Sopenharmony_cienum { 5048c2ecf20Sopenharmony_ci SCARLETT2_CONFIG_BUTTONS = 0, 5058c2ecf20Sopenharmony_ci SCARLETT2_CONFIG_LINE_OUT_VOLUME = 1, 5068c2ecf20Sopenharmony_ci SCARLETT2_CONFIG_SW_HW_SWITCH = 2, 5078c2ecf20Sopenharmony_ci SCARLETT2_CONFIG_LEVEL_SWITCH = 3, 5088c2ecf20Sopenharmony_ci SCARLETT2_CONFIG_PAD_SWITCH = 4, 5098c2ecf20Sopenharmony_ci SCARLETT2_CONFIG_COUNT = 5 5108c2ecf20Sopenharmony_ci}; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci/* Location, size, and activation command number for the configuration 5138c2ecf20Sopenharmony_ci * parameters 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_cistruct scarlett2_config { 5168c2ecf20Sopenharmony_ci u8 offset; 5178c2ecf20Sopenharmony_ci u8 size; 5188c2ecf20Sopenharmony_ci u8 activate; 5198c2ecf20Sopenharmony_ci}; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic const struct scarlett2_config 5228c2ecf20Sopenharmony_ci scarlett2_config_items[SCARLETT2_CONFIG_COUNT] = { 5238c2ecf20Sopenharmony_ci /* Mute/Dim Buttons */ 5248c2ecf20Sopenharmony_ci { 5258c2ecf20Sopenharmony_ci .offset = 0x31, 5268c2ecf20Sopenharmony_ci .size = 1, 5278c2ecf20Sopenharmony_ci .activate = 2 5288c2ecf20Sopenharmony_ci }, 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* Line Out Volume */ 5318c2ecf20Sopenharmony_ci { 5328c2ecf20Sopenharmony_ci .offset = 0x34, 5338c2ecf20Sopenharmony_ci .size = 2, 5348c2ecf20Sopenharmony_ci .activate = 1 5358c2ecf20Sopenharmony_ci }, 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* SW/HW Volume Switch */ 5388c2ecf20Sopenharmony_ci { 5398c2ecf20Sopenharmony_ci .offset = 0x66, 5408c2ecf20Sopenharmony_ci .size = 1, 5418c2ecf20Sopenharmony_ci .activate = 3 5428c2ecf20Sopenharmony_ci }, 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* Level Switch */ 5458c2ecf20Sopenharmony_ci { 5468c2ecf20Sopenharmony_ci .offset = 0x7c, 5478c2ecf20Sopenharmony_ci .size = 1, 5488c2ecf20Sopenharmony_ci .activate = 7 5498c2ecf20Sopenharmony_ci }, 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci /* Pad Switch */ 5528c2ecf20Sopenharmony_ci { 5538c2ecf20Sopenharmony_ci .offset = 0x84, 5548c2ecf20Sopenharmony_ci .size = 1, 5558c2ecf20Sopenharmony_ci .activate = 8 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci}; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/* proprietary request/response format */ 5608c2ecf20Sopenharmony_cistruct scarlett2_usb_packet { 5618c2ecf20Sopenharmony_ci __le32 cmd; 5628c2ecf20Sopenharmony_ci __le16 size; 5638c2ecf20Sopenharmony_ci __le16 seq; 5648c2ecf20Sopenharmony_ci __le32 error; 5658c2ecf20Sopenharmony_ci __le32 pad; 5668c2ecf20Sopenharmony_ci u8 data[]; 5678c2ecf20Sopenharmony_ci}; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci#define SCARLETT2_USB_PACKET_LEN (sizeof(struct scarlett2_usb_packet)) 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic void scarlett2_fill_request_header(struct scarlett2_mixer_data *private, 5728c2ecf20Sopenharmony_ci struct scarlett2_usb_packet *req, 5738c2ecf20Sopenharmony_ci u32 cmd, u16 req_size) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci /* sequence must go up by 1 for each request */ 5768c2ecf20Sopenharmony_ci u16 seq = private->scarlett2_seq++; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci req->cmd = cpu_to_le32(cmd); 5798c2ecf20Sopenharmony_ci req->size = cpu_to_le16(req_size); 5808c2ecf20Sopenharmony_ci req->seq = cpu_to_le16(seq); 5818c2ecf20Sopenharmony_ci req->error = 0; 5828c2ecf20Sopenharmony_ci req->pad = 0; 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci/* Send a proprietary format request to the Scarlett interface */ 5868c2ecf20Sopenharmony_cistatic int scarlett2_usb( 5878c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer, u32 cmd, 5888c2ecf20Sopenharmony_ci void *req_data, u16 req_size, void *resp_data, u16 resp_size) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 5918c2ecf20Sopenharmony_ci u16 req_buf_size = sizeof(struct scarlett2_usb_packet) + req_size; 5928c2ecf20Sopenharmony_ci u16 resp_buf_size = sizeof(struct scarlett2_usb_packet) + resp_size; 5938c2ecf20Sopenharmony_ci struct scarlett2_usb_packet *req = NULL, *resp = NULL; 5948c2ecf20Sopenharmony_ci int err = 0; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci req = kmalloc(req_buf_size, GFP_KERNEL); 5978c2ecf20Sopenharmony_ci if (!req) { 5988c2ecf20Sopenharmony_ci err = -ENOMEM; 5998c2ecf20Sopenharmony_ci goto error; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci resp = kmalloc(resp_buf_size, GFP_KERNEL); 6038c2ecf20Sopenharmony_ci if (!resp) { 6048c2ecf20Sopenharmony_ci err = -ENOMEM; 6058c2ecf20Sopenharmony_ci goto error; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci mutex_lock(&private->usb_mutex); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* build request message and send it */ 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci scarlett2_fill_request_header(private, req, cmd, req_size); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (req_size) 6158c2ecf20Sopenharmony_ci memcpy(req->data, req_data, req_size); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci err = snd_usb_ctl_msg(mixer->chip->dev, 6188c2ecf20Sopenharmony_ci usb_sndctrlpipe(mixer->chip->dev, 0), 6198c2ecf20Sopenharmony_ci SCARLETT2_USB_VENDOR_SPECIFIC_CMD_REQ, 6208c2ecf20Sopenharmony_ci USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 6218c2ecf20Sopenharmony_ci 0, 6228c2ecf20Sopenharmony_ci SCARLETT2_USB_VENDOR_SPECIFIC_INTERFACE, 6238c2ecf20Sopenharmony_ci req, 6248c2ecf20Sopenharmony_ci req_buf_size); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (err != req_buf_size) { 6278c2ecf20Sopenharmony_ci usb_audio_err( 6288c2ecf20Sopenharmony_ci mixer->chip, 6298c2ecf20Sopenharmony_ci "Scarlett Gen 2 USB request result cmd %x was %d\n", 6308c2ecf20Sopenharmony_ci cmd, err); 6318c2ecf20Sopenharmony_ci err = -EINVAL; 6328c2ecf20Sopenharmony_ci goto unlock; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* send a second message to get the response */ 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci err = snd_usb_ctl_msg(mixer->chip->dev, 6388c2ecf20Sopenharmony_ci usb_rcvctrlpipe(mixer->chip->dev, 0), 6398c2ecf20Sopenharmony_ci SCARLETT2_USB_VENDOR_SPECIFIC_CMD_RESP, 6408c2ecf20Sopenharmony_ci USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 6418c2ecf20Sopenharmony_ci 0, 6428c2ecf20Sopenharmony_ci SCARLETT2_USB_VENDOR_SPECIFIC_INTERFACE, 6438c2ecf20Sopenharmony_ci resp, 6448c2ecf20Sopenharmony_ci resp_buf_size); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci /* validate the response */ 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (err != resp_buf_size) { 6498c2ecf20Sopenharmony_ci usb_audio_err( 6508c2ecf20Sopenharmony_ci mixer->chip, 6518c2ecf20Sopenharmony_ci "Scarlett Gen 2 USB response result cmd %x was %d\n", 6528c2ecf20Sopenharmony_ci cmd, err); 6538c2ecf20Sopenharmony_ci err = -EINVAL; 6548c2ecf20Sopenharmony_ci goto unlock; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (resp->cmd != req->cmd || 6588c2ecf20Sopenharmony_ci resp->seq != req->seq || 6598c2ecf20Sopenharmony_ci resp_size != le16_to_cpu(resp->size) || 6608c2ecf20Sopenharmony_ci resp->error || 6618c2ecf20Sopenharmony_ci resp->pad) { 6628c2ecf20Sopenharmony_ci usb_audio_err( 6638c2ecf20Sopenharmony_ci mixer->chip, 6648c2ecf20Sopenharmony_ci "Scarlett Gen 2 USB invalid response; " 6658c2ecf20Sopenharmony_ci "cmd tx/rx %d/%d seq %d/%d size %d/%d " 6668c2ecf20Sopenharmony_ci "error %d pad %d\n", 6678c2ecf20Sopenharmony_ci le32_to_cpu(req->cmd), le32_to_cpu(resp->cmd), 6688c2ecf20Sopenharmony_ci le16_to_cpu(req->seq), le16_to_cpu(resp->seq), 6698c2ecf20Sopenharmony_ci resp_size, le16_to_cpu(resp->size), 6708c2ecf20Sopenharmony_ci le32_to_cpu(resp->error), 6718c2ecf20Sopenharmony_ci le32_to_cpu(resp->pad)); 6728c2ecf20Sopenharmony_ci err = -EINVAL; 6738c2ecf20Sopenharmony_ci goto unlock; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (resp_size > 0) 6778c2ecf20Sopenharmony_ci memcpy(resp_data, resp->data, resp_size); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ciunlock: 6808c2ecf20Sopenharmony_ci mutex_unlock(&private->usb_mutex); 6818c2ecf20Sopenharmony_cierror: 6828c2ecf20Sopenharmony_ci kfree(req); 6838c2ecf20Sopenharmony_ci kfree(resp); 6848c2ecf20Sopenharmony_ci return err; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci/* Send SCARLETT2_USB_DATA_CMD SCARLETT2_USB_CONFIG_SAVE */ 6888c2ecf20Sopenharmony_cistatic void scarlett2_config_save(struct usb_mixer_interface *mixer) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci __le32 req = cpu_to_le32(SCARLETT2_USB_CONFIG_SAVE); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci scarlett2_usb(mixer, SCARLETT2_USB_DATA_CMD, 6938c2ecf20Sopenharmony_ci &req, sizeof(u32), 6948c2ecf20Sopenharmony_ci NULL, 0); 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci/* Delayed work to save config */ 6988c2ecf20Sopenharmony_cistatic void scarlett2_config_save_work(struct work_struct *work) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = 7018c2ecf20Sopenharmony_ci container_of(work, struct scarlett2_mixer_data, work.work); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci scarlett2_config_save(private->mixer); 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci/* Send a USB message to set a configuration parameter (volume level, 7078c2ecf20Sopenharmony_ci * sw/hw volume switch, line/inst level switch, or pad switch) 7088c2ecf20Sopenharmony_ci */ 7098c2ecf20Sopenharmony_cistatic int scarlett2_usb_set_config( 7108c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer, 7118c2ecf20Sopenharmony_ci int config_item_num, int index, int value) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci const struct scarlett2_config config_item = 7148c2ecf20Sopenharmony_ci scarlett2_config_items[config_item_num]; 7158c2ecf20Sopenharmony_ci struct { 7168c2ecf20Sopenharmony_ci __le32 offset; 7178c2ecf20Sopenharmony_ci __le32 bytes; 7188c2ecf20Sopenharmony_ci __le32 value; 7198c2ecf20Sopenharmony_ci } __packed req; 7208c2ecf20Sopenharmony_ci __le32 req2; 7218c2ecf20Sopenharmony_ci int err; 7228c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* Cancel any pending NVRAM save */ 7258c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&private->work); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* Send the configuration parameter data */ 7288c2ecf20Sopenharmony_ci req.offset = cpu_to_le32(config_item.offset + index * config_item.size); 7298c2ecf20Sopenharmony_ci req.bytes = cpu_to_le32(config_item.size); 7308c2ecf20Sopenharmony_ci req.value = cpu_to_le32(value); 7318c2ecf20Sopenharmony_ci err = scarlett2_usb(mixer, SCARLETT2_USB_SET_DATA, 7328c2ecf20Sopenharmony_ci &req, sizeof(u32) * 2 + config_item.size, 7338c2ecf20Sopenharmony_ci NULL, 0); 7348c2ecf20Sopenharmony_ci if (err < 0) 7358c2ecf20Sopenharmony_ci return err; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* Activate the change */ 7388c2ecf20Sopenharmony_ci req2 = cpu_to_le32(config_item.activate); 7398c2ecf20Sopenharmony_ci err = scarlett2_usb(mixer, SCARLETT2_USB_DATA_CMD, 7408c2ecf20Sopenharmony_ci &req2, sizeof(req2), NULL, 0); 7418c2ecf20Sopenharmony_ci if (err < 0) 7428c2ecf20Sopenharmony_ci return err; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* Schedule the change to be written to NVRAM */ 7458c2ecf20Sopenharmony_ci schedule_delayed_work(&private->work, msecs_to_jiffies(2000)); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci return 0; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci/* Send a USB message to get data; result placed in *buf */ 7518c2ecf20Sopenharmony_cistatic int scarlett2_usb_get( 7528c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer, 7538c2ecf20Sopenharmony_ci int offset, void *buf, int size) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct { 7568c2ecf20Sopenharmony_ci __le32 offset; 7578c2ecf20Sopenharmony_ci __le32 size; 7588c2ecf20Sopenharmony_ci } __packed req; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci req.offset = cpu_to_le32(offset); 7618c2ecf20Sopenharmony_ci req.size = cpu_to_le32(size); 7628c2ecf20Sopenharmony_ci return scarlett2_usb(mixer, SCARLETT2_USB_GET_DATA, 7638c2ecf20Sopenharmony_ci &req, sizeof(req), buf, size); 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci/* Send a USB message to get configuration parameters; result placed in *buf */ 7678c2ecf20Sopenharmony_cistatic int scarlett2_usb_get_config( 7688c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer, 7698c2ecf20Sopenharmony_ci int config_item_num, int count, void *buf) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci const struct scarlett2_config config_item = 7728c2ecf20Sopenharmony_ci scarlett2_config_items[config_item_num]; 7738c2ecf20Sopenharmony_ci int size = config_item.size * count; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci return scarlett2_usb_get(mixer, config_item.offset, buf, size); 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci/* Send a USB message to get volume status; result placed in *buf */ 7798c2ecf20Sopenharmony_cistatic int scarlett2_usb_get_volume_status( 7808c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer, 7818c2ecf20Sopenharmony_ci struct scarlett2_usb_volume_status *buf) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci return scarlett2_usb_get(mixer, SCARLETT2_USB_VOLUME_STATUS_OFFSET, 7848c2ecf20Sopenharmony_ci buf, sizeof(*buf)); 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci/* Send a USB message to set the volumes for all inputs of one mix 7888c2ecf20Sopenharmony_ci * (values obtained from private->mix[]) 7898c2ecf20Sopenharmony_ci */ 7908c2ecf20Sopenharmony_cistatic int scarlett2_usb_set_mix(struct usb_mixer_interface *mixer, 7918c2ecf20Sopenharmony_ci int mix_num) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 7948c2ecf20Sopenharmony_ci const struct scarlett2_device_info *info = private->info; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci struct { 7978c2ecf20Sopenharmony_ci __le16 mix_num; 7988c2ecf20Sopenharmony_ci __le16 data[SCARLETT2_INPUT_MIX_MAX]; 7998c2ecf20Sopenharmony_ci } __packed req; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci int i, j; 8028c2ecf20Sopenharmony_ci int num_mixer_in = 8038c2ecf20Sopenharmony_ci info->ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT]; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci req.mix_num = cpu_to_le16(mix_num); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci for (i = 0, j = mix_num * num_mixer_in; i < num_mixer_in; i++, j++) 8088c2ecf20Sopenharmony_ci req.data[i] = cpu_to_le16( 8098c2ecf20Sopenharmony_ci scarlett2_mixer_values[private->mix[j]] 8108c2ecf20Sopenharmony_ci ); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return scarlett2_usb(mixer, SCARLETT2_USB_SET_MIX, 8138c2ecf20Sopenharmony_ci &req, (num_mixer_in + 1) * sizeof(u16), 8148c2ecf20Sopenharmony_ci NULL, 0); 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci/* Convert a port number index (per info->ports) to a hardware ID */ 8188c2ecf20Sopenharmony_cistatic u32 scarlett2_mux_src_num_to_id(const struct scarlett2_ports *ports, 8198c2ecf20Sopenharmony_ci int num) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci int port_type; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci for (port_type = 0; 8248c2ecf20Sopenharmony_ci port_type < SCARLETT2_PORT_TYPE_COUNT; 8258c2ecf20Sopenharmony_ci port_type++) { 8268c2ecf20Sopenharmony_ci if (num < ports[port_type].num[SCARLETT2_PORT_IN]) 8278c2ecf20Sopenharmony_ci return ports[port_type].id | num; 8288c2ecf20Sopenharmony_ci num -= ports[port_type].num[SCARLETT2_PORT_IN]; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci /* Oops */ 8328c2ecf20Sopenharmony_ci return 0; 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci/* Send USB messages to set mux inputs */ 8368c2ecf20Sopenharmony_cistatic int scarlett2_usb_set_mux(struct usb_mixer_interface *mixer) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 8398c2ecf20Sopenharmony_ci const struct scarlett2_device_info *info = private->info; 8408c2ecf20Sopenharmony_ci const struct scarlett2_ports *ports = info->ports; 8418c2ecf20Sopenharmony_ci int rate, port_dir_rate; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci static const int assignment_order[SCARLETT2_PORT_TYPE_COUNT] = { 8448c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_PCM, 8458c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_ANALOGUE, 8468c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_SPDIF, 8478c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_ADAT, 8488c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_MIX, 8498c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_NONE, 8508c2ecf20Sopenharmony_ci }; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci struct { 8538c2ecf20Sopenharmony_ci __le16 pad; 8548c2ecf20Sopenharmony_ci __le16 num; 8558c2ecf20Sopenharmony_ci __le32 data[SCARLETT2_MUX_MAX]; 8568c2ecf20Sopenharmony_ci } __packed req; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci req.pad = 0; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* mux settings for each rate */ 8618c2ecf20Sopenharmony_ci for (rate = 0, port_dir_rate = SCARLETT2_PORT_OUT_44; 8628c2ecf20Sopenharmony_ci port_dir_rate <= SCARLETT2_PORT_OUT_176; 8638c2ecf20Sopenharmony_ci rate++, port_dir_rate++) { 8648c2ecf20Sopenharmony_ci int order_num, i, err; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci req.num = cpu_to_le16(rate); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci for (order_num = 0, i = 0; 8698c2ecf20Sopenharmony_ci order_num < SCARLETT2_PORT_TYPE_COUNT; 8708c2ecf20Sopenharmony_ci order_num++) { 8718c2ecf20Sopenharmony_ci int port_type = assignment_order[order_num]; 8728c2ecf20Sopenharmony_ci int j = scarlett2_get_port_start_num(ports, 8738c2ecf20Sopenharmony_ci SCARLETT2_PORT_OUT, 8748c2ecf20Sopenharmony_ci port_type); 8758c2ecf20Sopenharmony_ci int port_id = ports[port_type].id; 8768c2ecf20Sopenharmony_ci int channel; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci for (channel = 0; 8798c2ecf20Sopenharmony_ci channel < ports[port_type].num[port_dir_rate]; 8808c2ecf20Sopenharmony_ci channel++, i++, j++) 8818c2ecf20Sopenharmony_ci /* lower 12 bits for the destination and 8828c2ecf20Sopenharmony_ci * next 12 bits for the source 8838c2ecf20Sopenharmony_ci */ 8848c2ecf20Sopenharmony_ci req.data[i] = !port_id 8858c2ecf20Sopenharmony_ci ? 0 8868c2ecf20Sopenharmony_ci : cpu_to_le32( 8878c2ecf20Sopenharmony_ci port_id | 8888c2ecf20Sopenharmony_ci channel | 8898c2ecf20Sopenharmony_ci scarlett2_mux_src_num_to_id( 8908c2ecf20Sopenharmony_ci ports, private->mux[j] 8918c2ecf20Sopenharmony_ci ) << 12 8928c2ecf20Sopenharmony_ci ); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* skip private->mux[j] entries not output */ 8958c2ecf20Sopenharmony_ci j += ports[port_type].num[SCARLETT2_PORT_OUT] - 8968c2ecf20Sopenharmony_ci ports[port_type].num[port_dir_rate]; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci err = scarlett2_usb(mixer, SCARLETT2_USB_SET_MUX, 9008c2ecf20Sopenharmony_ci &req, (i + 1) * sizeof(u32), 9018c2ecf20Sopenharmony_ci NULL, 0); 9028c2ecf20Sopenharmony_ci if (err < 0) 9038c2ecf20Sopenharmony_ci return err; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci return 0; 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci/* Send USB message to get meter levels */ 9108c2ecf20Sopenharmony_cistatic int scarlett2_usb_get_meter_levels(struct usb_mixer_interface *mixer, 9118c2ecf20Sopenharmony_ci u16 *levels) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci struct { 9148c2ecf20Sopenharmony_ci __le16 pad; 9158c2ecf20Sopenharmony_ci __le16 num_meters; 9168c2ecf20Sopenharmony_ci __le32 magic; 9178c2ecf20Sopenharmony_ci } __packed req; 9188c2ecf20Sopenharmony_ci u32 resp[SCARLETT2_NUM_METERS]; 9198c2ecf20Sopenharmony_ci int i, err; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci req.pad = 0; 9228c2ecf20Sopenharmony_ci req.num_meters = cpu_to_le16(SCARLETT2_NUM_METERS); 9238c2ecf20Sopenharmony_ci req.magic = cpu_to_le32(SCARLETT2_USB_METER_LEVELS_GET_MAGIC); 9248c2ecf20Sopenharmony_ci err = scarlett2_usb(mixer, SCARLETT2_USB_GET_METER_LEVELS, 9258c2ecf20Sopenharmony_ci &req, sizeof(req), resp, sizeof(resp)); 9268c2ecf20Sopenharmony_ci if (err < 0) 9278c2ecf20Sopenharmony_ci return err; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* copy, convert to u16 */ 9308c2ecf20Sopenharmony_ci for (i = 0; i < SCARLETT2_NUM_METERS; i++) 9318c2ecf20Sopenharmony_ci levels[i] = resp[i]; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci return 0; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci/*** Control Functions ***/ 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci/* helper function to create a new control */ 9398c2ecf20Sopenharmony_cistatic int scarlett2_add_new_ctl(struct usb_mixer_interface *mixer, 9408c2ecf20Sopenharmony_ci const struct snd_kcontrol_new *ncontrol, 9418c2ecf20Sopenharmony_ci int index, int channels, const char *name, 9428c2ecf20Sopenharmony_ci struct snd_kcontrol **kctl_return) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl; 9458c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem; 9468c2ecf20Sopenharmony_ci int err; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci elem = kzalloc(sizeof(*elem), GFP_KERNEL); 9498c2ecf20Sopenharmony_ci if (!elem) 9508c2ecf20Sopenharmony_ci return -ENOMEM; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* We set USB_MIXER_BESPOKEN type, so that the core USB mixer code 9538c2ecf20Sopenharmony_ci * ignores them for resume and other operations. 9548c2ecf20Sopenharmony_ci * Also, the head.id field is set to 0, as we don't use this field. 9558c2ecf20Sopenharmony_ci */ 9568c2ecf20Sopenharmony_ci elem->head.mixer = mixer; 9578c2ecf20Sopenharmony_ci elem->control = index; 9588c2ecf20Sopenharmony_ci elem->head.id = 0; 9598c2ecf20Sopenharmony_ci elem->channels = channels; 9608c2ecf20Sopenharmony_ci elem->val_type = USB_MIXER_BESPOKEN; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci kctl = snd_ctl_new1(ncontrol, elem); 9638c2ecf20Sopenharmony_ci if (!kctl) { 9648c2ecf20Sopenharmony_ci kfree(elem); 9658c2ecf20Sopenharmony_ci return -ENOMEM; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci kctl->private_free = snd_usb_mixer_elem_free; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci strlcpy(kctl->id.name, name, sizeof(kctl->id.name)); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci err = snd_usb_mixer_add_control(&elem->head, kctl); 9728c2ecf20Sopenharmony_ci if (err < 0) 9738c2ecf20Sopenharmony_ci return err; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (kctl_return) 9768c2ecf20Sopenharmony_ci *kctl_return = kctl; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci return 0; 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci/*** Analogue Line Out Volume Controls ***/ 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci/* Update hardware volume controls after receiving notification that 9848c2ecf20Sopenharmony_ci * they have changed 9858c2ecf20Sopenharmony_ci */ 9868c2ecf20Sopenharmony_cistatic int scarlett2_update_volumes(struct usb_mixer_interface *mixer) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 9898c2ecf20Sopenharmony_ci const struct scarlett2_ports *ports = private->info->ports; 9908c2ecf20Sopenharmony_ci struct scarlett2_usb_volume_status volume_status; 9918c2ecf20Sopenharmony_ci int num_line_out = 9928c2ecf20Sopenharmony_ci ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT]; 9938c2ecf20Sopenharmony_ci int err, i; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci private->vol_updated = 0; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci err = scarlett2_usb_get_volume_status(mixer, &volume_status); 9988c2ecf20Sopenharmony_ci if (err < 0) 9998c2ecf20Sopenharmony_ci return err; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci private->master_vol = clamp( 10028c2ecf20Sopenharmony_ci volume_status.master_vol + SCARLETT2_VOLUME_BIAS, 10038c2ecf20Sopenharmony_ci 0, SCARLETT2_VOLUME_BIAS); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci for (i = 0; i < num_line_out; i++) { 10068c2ecf20Sopenharmony_ci if (private->vol_sw_hw_switch[i]) 10078c2ecf20Sopenharmony_ci private->vol[i] = private->master_vol; 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci for (i = 0; i < private->info->button_count; i++) 10118c2ecf20Sopenharmony_ci private->buttons[i] = !!volume_status.buttons[i]; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci return 0; 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_cistatic int scarlett2_volume_ctl_info(struct snd_kcontrol *kctl, 10178c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 10188c2ecf20Sopenharmony_ci{ 10198c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 10228c2ecf20Sopenharmony_ci uinfo->count = elem->channels; 10238c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 10248c2ecf20Sopenharmony_ci uinfo->value.integer.max = SCARLETT2_VOLUME_BIAS; 10258c2ecf20Sopenharmony_ci uinfo->value.integer.step = 1; 10268c2ecf20Sopenharmony_ci return 0; 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic int scarlett2_master_volume_ctl_get(struct snd_kcontrol *kctl, 10308c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 10338c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = elem->head.mixer; 10348c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci mutex_lock(&private->data_mutex); 10378c2ecf20Sopenharmony_ci if (private->vol_updated) 10388c2ecf20Sopenharmony_ci scarlett2_update_volumes(mixer); 10398c2ecf20Sopenharmony_ci mutex_unlock(&private->data_mutex); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = private->master_vol; 10428c2ecf20Sopenharmony_ci return 0; 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic int scarlett2_volume_ctl_get(struct snd_kcontrol *kctl, 10468c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 10498c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = elem->head.mixer; 10508c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 10518c2ecf20Sopenharmony_ci int index = elem->control; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci mutex_lock(&private->data_mutex); 10548c2ecf20Sopenharmony_ci if (private->vol_updated) 10558c2ecf20Sopenharmony_ci scarlett2_update_volumes(mixer); 10568c2ecf20Sopenharmony_ci mutex_unlock(&private->data_mutex); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = private->vol[index]; 10598c2ecf20Sopenharmony_ci return 0; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_cistatic int scarlett2_volume_ctl_put(struct snd_kcontrol *kctl, 10638c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 10648c2ecf20Sopenharmony_ci{ 10658c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 10668c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = elem->head.mixer; 10678c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 10688c2ecf20Sopenharmony_ci int index = elem->control; 10698c2ecf20Sopenharmony_ci int oval, val, err = 0; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci mutex_lock(&private->data_mutex); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci oval = private->vol[index]; 10748c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (oval == val) 10778c2ecf20Sopenharmony_ci goto unlock; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci private->vol[index] = val; 10808c2ecf20Sopenharmony_ci err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME, 10818c2ecf20Sopenharmony_ci index, val - SCARLETT2_VOLUME_BIAS); 10828c2ecf20Sopenharmony_ci if (err == 0) 10838c2ecf20Sopenharmony_ci err = 1; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ciunlock: 10868c2ecf20Sopenharmony_ci mutex_unlock(&private->data_mutex); 10878c2ecf20Sopenharmony_ci return err; 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_MINMAX( 10918c2ecf20Sopenharmony_ci db_scale_scarlett2_gain, -SCARLETT2_VOLUME_BIAS * 100, 0 10928c2ecf20Sopenharmony_ci); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new scarlett2_master_volume_ctl = { 10958c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 10968c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 10978c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 10988c2ecf20Sopenharmony_ci .name = "", 10998c2ecf20Sopenharmony_ci .info = scarlett2_volume_ctl_info, 11008c2ecf20Sopenharmony_ci .get = scarlett2_master_volume_ctl_get, 11018c2ecf20Sopenharmony_ci .private_value = 0, /* max value */ 11028c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_scarlett2_gain } 11038c2ecf20Sopenharmony_ci}; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new scarlett2_line_out_volume_ctl = { 11068c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 11078c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 11088c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 11098c2ecf20Sopenharmony_ci .name = "", 11108c2ecf20Sopenharmony_ci .info = scarlett2_volume_ctl_info, 11118c2ecf20Sopenharmony_ci .get = scarlett2_volume_ctl_get, 11128c2ecf20Sopenharmony_ci .put = scarlett2_volume_ctl_put, 11138c2ecf20Sopenharmony_ci .private_value = 0, /* max value */ 11148c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_scarlett2_gain } 11158c2ecf20Sopenharmony_ci}; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci/*** HW/SW Volume Switch Controls ***/ 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_cistatic int scarlett2_sw_hw_enum_ctl_info(struct snd_kcontrol *kctl, 11208c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci static const char *const values[2] = { 11238c2ecf20Sopenharmony_ci "SW", "HW" 11248c2ecf20Sopenharmony_ci }; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, values); 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cistatic int scarlett2_sw_hw_enum_ctl_get(struct snd_kcontrol *kctl, 11308c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 11338c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = elem->head.mixer->private_data; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 11368c2ecf20Sopenharmony_ci private->vol_sw_hw_switch[elem->control]; 11378c2ecf20Sopenharmony_ci return 0; 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_cistatic int scarlett2_sw_hw_enum_ctl_put(struct snd_kcontrol *kctl, 11418c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 11448c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = elem->head.mixer; 11458c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci int index = elem->control; 11488c2ecf20Sopenharmony_ci int oval, val, err = 0; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci mutex_lock(&private->data_mutex); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci oval = private->vol_sw_hw_switch[index]; 11538c2ecf20Sopenharmony_ci val = !!ucontrol->value.integer.value[0]; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci if (oval == val) 11568c2ecf20Sopenharmony_ci goto unlock; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci private->vol_sw_hw_switch[index] = val; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci /* Change access mode to RO (hardware controlled volume) 11618c2ecf20Sopenharmony_ci * or RW (software controlled volume) 11628c2ecf20Sopenharmony_ci */ 11638c2ecf20Sopenharmony_ci if (val) 11648c2ecf20Sopenharmony_ci private->vol_ctls[index]->vd[0].access &= 11658c2ecf20Sopenharmony_ci ~SNDRV_CTL_ELEM_ACCESS_WRITE; 11668c2ecf20Sopenharmony_ci else 11678c2ecf20Sopenharmony_ci private->vol_ctls[index]->vd[0].access |= 11688c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_WRITE; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci /* Reset volume to master volume */ 11718c2ecf20Sopenharmony_ci private->vol[index] = private->master_vol; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci /* Set SW volume to current HW volume */ 11748c2ecf20Sopenharmony_ci err = scarlett2_usb_set_config( 11758c2ecf20Sopenharmony_ci mixer, SCARLETT2_CONFIG_LINE_OUT_VOLUME, 11768c2ecf20Sopenharmony_ci index, private->master_vol - SCARLETT2_VOLUME_BIAS); 11778c2ecf20Sopenharmony_ci if (err < 0) 11788c2ecf20Sopenharmony_ci goto unlock; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci /* Notify of RO/RW change */ 11818c2ecf20Sopenharmony_ci snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_INFO, 11828c2ecf20Sopenharmony_ci &private->vol_ctls[index]->id); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci /* Send SW/HW switch change to the device */ 11858c2ecf20Sopenharmony_ci err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_SW_HW_SWITCH, 11868c2ecf20Sopenharmony_ci index, val); 11878c2ecf20Sopenharmony_ci if (err == 0) 11888c2ecf20Sopenharmony_ci err = 1; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ciunlock: 11918c2ecf20Sopenharmony_ci mutex_unlock(&private->data_mutex); 11928c2ecf20Sopenharmony_ci return err; 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new scarlett2_sw_hw_enum_ctl = { 11968c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 11978c2ecf20Sopenharmony_ci .name = "", 11988c2ecf20Sopenharmony_ci .info = scarlett2_sw_hw_enum_ctl_info, 11998c2ecf20Sopenharmony_ci .get = scarlett2_sw_hw_enum_ctl_get, 12008c2ecf20Sopenharmony_ci .put = scarlett2_sw_hw_enum_ctl_put, 12018c2ecf20Sopenharmony_ci}; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci/*** Line Level/Instrument Level Switch Controls ***/ 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_cistatic int scarlett2_level_enum_ctl_info(struct snd_kcontrol *kctl, 12068c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 12078c2ecf20Sopenharmony_ci{ 12088c2ecf20Sopenharmony_ci static const char *const values[2] = { 12098c2ecf20Sopenharmony_ci "Line", "Inst" 12108c2ecf20Sopenharmony_ci }; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, values); 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic int scarlett2_level_enum_ctl_get(struct snd_kcontrol *kctl, 12168c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 12198c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = elem->head.mixer->private_data; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 12228c2ecf20Sopenharmony_ci private->level_switch[elem->control]; 12238c2ecf20Sopenharmony_ci return 0; 12248c2ecf20Sopenharmony_ci} 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_cistatic int scarlett2_level_enum_ctl_put(struct snd_kcontrol *kctl, 12278c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 12288c2ecf20Sopenharmony_ci{ 12298c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 12308c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = elem->head.mixer; 12318c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci int index = elem->control; 12348c2ecf20Sopenharmony_ci int oval, val, err = 0; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci mutex_lock(&private->data_mutex); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci oval = private->level_switch[index]; 12398c2ecf20Sopenharmony_ci val = !!ucontrol->value.integer.value[0]; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci if (oval == val) 12428c2ecf20Sopenharmony_ci goto unlock; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci private->level_switch[index] = val; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci /* Send switch change to the device */ 12478c2ecf20Sopenharmony_ci err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_LEVEL_SWITCH, 12488c2ecf20Sopenharmony_ci index, val); 12498c2ecf20Sopenharmony_ci if (err == 0) 12508c2ecf20Sopenharmony_ci err = 1; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ciunlock: 12538c2ecf20Sopenharmony_ci mutex_unlock(&private->data_mutex); 12548c2ecf20Sopenharmony_ci return err; 12558c2ecf20Sopenharmony_ci} 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new scarlett2_level_enum_ctl = { 12588c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 12598c2ecf20Sopenharmony_ci .name = "", 12608c2ecf20Sopenharmony_ci .info = scarlett2_level_enum_ctl_info, 12618c2ecf20Sopenharmony_ci .get = scarlett2_level_enum_ctl_get, 12628c2ecf20Sopenharmony_ci .put = scarlett2_level_enum_ctl_put, 12638c2ecf20Sopenharmony_ci}; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci/*** Pad Switch Controls ***/ 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_cistatic int scarlett2_pad_ctl_get(struct snd_kcontrol *kctl, 12688c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 12698c2ecf20Sopenharmony_ci{ 12708c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 12718c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = elem->head.mixer->private_data; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 12748c2ecf20Sopenharmony_ci private->pad_switch[elem->control]; 12758c2ecf20Sopenharmony_ci return 0; 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic int scarlett2_pad_ctl_put(struct snd_kcontrol *kctl, 12798c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 12828c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = elem->head.mixer; 12838c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci int index = elem->control; 12868c2ecf20Sopenharmony_ci int oval, val, err = 0; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci mutex_lock(&private->data_mutex); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci oval = private->pad_switch[index]; 12918c2ecf20Sopenharmony_ci val = !!ucontrol->value.integer.value[0]; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if (oval == val) 12948c2ecf20Sopenharmony_ci goto unlock; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci private->pad_switch[index] = val; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci /* Send switch change to the device */ 12998c2ecf20Sopenharmony_ci err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_PAD_SWITCH, 13008c2ecf20Sopenharmony_ci index, val); 13018c2ecf20Sopenharmony_ci if (err == 0) 13028c2ecf20Sopenharmony_ci err = 1; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ciunlock: 13058c2ecf20Sopenharmony_ci mutex_unlock(&private->data_mutex); 13068c2ecf20Sopenharmony_ci return err; 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new scarlett2_pad_ctl = { 13108c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 13118c2ecf20Sopenharmony_ci .name = "", 13128c2ecf20Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 13138c2ecf20Sopenharmony_ci .get = scarlett2_pad_ctl_get, 13148c2ecf20Sopenharmony_ci .put = scarlett2_pad_ctl_put, 13158c2ecf20Sopenharmony_ci}; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci/*** Mute/Dim Controls ***/ 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cistatic int scarlett2_button_ctl_get(struct snd_kcontrol *kctl, 13208c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 13218c2ecf20Sopenharmony_ci{ 13228c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 13238c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = elem->head.mixer; 13248c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci mutex_lock(&private->data_mutex); 13278c2ecf20Sopenharmony_ci if (private->vol_updated) 13288c2ecf20Sopenharmony_ci scarlett2_update_volumes(mixer); 13298c2ecf20Sopenharmony_ci mutex_unlock(&private->data_mutex); 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = private->buttons[elem->control]; 13328c2ecf20Sopenharmony_ci return 0; 13338c2ecf20Sopenharmony_ci} 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_cistatic int scarlett2_button_ctl_put(struct snd_kcontrol *kctl, 13368c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 13398c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = elem->head.mixer; 13408c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci int index = elem->control; 13438c2ecf20Sopenharmony_ci int oval, val, err = 0; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci mutex_lock(&private->data_mutex); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci oval = private->buttons[index]; 13488c2ecf20Sopenharmony_ci val = !!ucontrol->value.integer.value[0]; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci if (oval == val) 13518c2ecf20Sopenharmony_ci goto unlock; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci private->buttons[index] = val; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci /* Send switch change to the device */ 13568c2ecf20Sopenharmony_ci err = scarlett2_usb_set_config(mixer, SCARLETT2_CONFIG_BUTTONS, 13578c2ecf20Sopenharmony_ci index, val); 13588c2ecf20Sopenharmony_ci if (err == 0) 13598c2ecf20Sopenharmony_ci err = 1; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ciunlock: 13628c2ecf20Sopenharmony_ci mutex_unlock(&private->data_mutex); 13638c2ecf20Sopenharmony_ci return err; 13648c2ecf20Sopenharmony_ci} 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new scarlett2_button_ctl = { 13678c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 13688c2ecf20Sopenharmony_ci .name = "", 13698c2ecf20Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 13708c2ecf20Sopenharmony_ci .get = scarlett2_button_ctl_get, 13718c2ecf20Sopenharmony_ci .put = scarlett2_button_ctl_put 13728c2ecf20Sopenharmony_ci}; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci/*** Create the analogue output controls ***/ 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_cistatic int scarlett2_add_line_out_ctls(struct usb_mixer_interface *mixer) 13778c2ecf20Sopenharmony_ci{ 13788c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 13798c2ecf20Sopenharmony_ci const struct scarlett2_device_info *info = private->info; 13808c2ecf20Sopenharmony_ci const struct scarlett2_ports *ports = info->ports; 13818c2ecf20Sopenharmony_ci int num_line_out = 13828c2ecf20Sopenharmony_ci ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT]; 13838c2ecf20Sopenharmony_ci int err, i; 13848c2ecf20Sopenharmony_ci char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci /* Add R/O HW volume control */ 13878c2ecf20Sopenharmony_ci if (info->line_out_hw_vol) { 13888c2ecf20Sopenharmony_ci snprintf(s, sizeof(s), "Master HW Playback Volume"); 13898c2ecf20Sopenharmony_ci err = scarlett2_add_new_ctl(mixer, 13908c2ecf20Sopenharmony_ci &scarlett2_master_volume_ctl, 13918c2ecf20Sopenharmony_ci 0, 1, s, &private->master_vol_ctl); 13928c2ecf20Sopenharmony_ci if (err < 0) 13938c2ecf20Sopenharmony_ci return err; 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci /* Add volume controls */ 13978c2ecf20Sopenharmony_ci for (i = 0; i < num_line_out; i++) { 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci /* Fader */ 14008c2ecf20Sopenharmony_ci if (info->line_out_descrs[i]) 14018c2ecf20Sopenharmony_ci snprintf(s, sizeof(s), 14028c2ecf20Sopenharmony_ci "Line %02d (%s) Playback Volume", 14038c2ecf20Sopenharmony_ci i + 1, info->line_out_descrs[i]); 14048c2ecf20Sopenharmony_ci else 14058c2ecf20Sopenharmony_ci snprintf(s, sizeof(s), 14068c2ecf20Sopenharmony_ci "Line %02d Playback Volume", 14078c2ecf20Sopenharmony_ci i + 1); 14088c2ecf20Sopenharmony_ci err = scarlett2_add_new_ctl(mixer, 14098c2ecf20Sopenharmony_ci &scarlett2_line_out_volume_ctl, 14108c2ecf20Sopenharmony_ci i, 1, s, &private->vol_ctls[i]); 14118c2ecf20Sopenharmony_ci if (err < 0) 14128c2ecf20Sopenharmony_ci return err; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci /* Make the fader read-only if the SW/HW switch is set to HW */ 14158c2ecf20Sopenharmony_ci if (private->vol_sw_hw_switch[i]) 14168c2ecf20Sopenharmony_ci private->vol_ctls[i]->vd[0].access &= 14178c2ecf20Sopenharmony_ci ~SNDRV_CTL_ELEM_ACCESS_WRITE; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci /* SW/HW Switch */ 14208c2ecf20Sopenharmony_ci if (info->line_out_hw_vol) { 14218c2ecf20Sopenharmony_ci snprintf(s, sizeof(s), 14228c2ecf20Sopenharmony_ci "Line Out %02d Volume Control Playback Enum", 14238c2ecf20Sopenharmony_ci i + 1); 14248c2ecf20Sopenharmony_ci err = scarlett2_add_new_ctl(mixer, 14258c2ecf20Sopenharmony_ci &scarlett2_sw_hw_enum_ctl, 14268c2ecf20Sopenharmony_ci i, 1, s, NULL); 14278c2ecf20Sopenharmony_ci if (err < 0) 14288c2ecf20Sopenharmony_ci return err; 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci /* Add HW button controls */ 14338c2ecf20Sopenharmony_ci for (i = 0; i < private->info->button_count; i++) { 14348c2ecf20Sopenharmony_ci err = scarlett2_add_new_ctl(mixer, &scarlett2_button_ctl, 14358c2ecf20Sopenharmony_ci i, 1, scarlett2_button_names[i], 14368c2ecf20Sopenharmony_ci &private->button_ctls[i]); 14378c2ecf20Sopenharmony_ci if (err < 0) 14388c2ecf20Sopenharmony_ci return err; 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci return 0; 14428c2ecf20Sopenharmony_ci} 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci/*** Create the analogue input controls ***/ 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 14498c2ecf20Sopenharmony_ci const struct scarlett2_device_info *info = private->info; 14508c2ecf20Sopenharmony_ci int err, i; 14518c2ecf20Sopenharmony_ci char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci /* Add input level (line/inst) controls */ 14548c2ecf20Sopenharmony_ci for (i = 0; i < info->level_input_count; i++) { 14558c2ecf20Sopenharmony_ci snprintf(s, sizeof(s), "Line In %d Level Capture Enum", i + 1); 14568c2ecf20Sopenharmony_ci err = scarlett2_add_new_ctl(mixer, &scarlett2_level_enum_ctl, 14578c2ecf20Sopenharmony_ci i, 1, s, NULL); 14588c2ecf20Sopenharmony_ci if (err < 0) 14598c2ecf20Sopenharmony_ci return err; 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci /* Add input pad controls */ 14638c2ecf20Sopenharmony_ci for (i = 0; i < info->pad_input_count; i++) { 14648c2ecf20Sopenharmony_ci snprintf(s, sizeof(s), "Line In %d Pad Capture Switch", i + 1); 14658c2ecf20Sopenharmony_ci err = scarlett2_add_new_ctl(mixer, &scarlett2_pad_ctl, 14668c2ecf20Sopenharmony_ci i, 1, s, NULL); 14678c2ecf20Sopenharmony_ci if (err < 0) 14688c2ecf20Sopenharmony_ci return err; 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci return 0; 14728c2ecf20Sopenharmony_ci} 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci/*** Mixer Volume Controls ***/ 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_cistatic int scarlett2_mixer_ctl_info(struct snd_kcontrol *kctl, 14778c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 14788c2ecf20Sopenharmony_ci{ 14798c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 14828c2ecf20Sopenharmony_ci uinfo->count = elem->channels; 14838c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 14848c2ecf20Sopenharmony_ci uinfo->value.integer.max = SCARLETT2_MIXER_MAX_VALUE; 14858c2ecf20Sopenharmony_ci uinfo->value.integer.step = 1; 14868c2ecf20Sopenharmony_ci return 0; 14878c2ecf20Sopenharmony_ci} 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_cistatic int scarlett2_mixer_ctl_get(struct snd_kcontrol *kctl, 14908c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 14918c2ecf20Sopenharmony_ci{ 14928c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 14938c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = elem->head.mixer->private_data; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = private->mix[elem->control]; 14968c2ecf20Sopenharmony_ci return 0; 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_cistatic int scarlett2_mixer_ctl_put(struct snd_kcontrol *kctl, 15008c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 15038c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = elem->head.mixer; 15048c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 15058c2ecf20Sopenharmony_ci const struct scarlett2_device_info *info = private->info; 15068c2ecf20Sopenharmony_ci const struct scarlett2_ports *ports = info->ports; 15078c2ecf20Sopenharmony_ci int oval, val, num_mixer_in, mix_num, err = 0; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci mutex_lock(&private->data_mutex); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci oval = private->mix[elem->control]; 15128c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 15138c2ecf20Sopenharmony_ci num_mixer_in = ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT]; 15148c2ecf20Sopenharmony_ci mix_num = elem->control / num_mixer_in; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (oval == val) 15178c2ecf20Sopenharmony_ci goto unlock; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci private->mix[elem->control] = val; 15208c2ecf20Sopenharmony_ci err = scarlett2_usb_set_mix(mixer, mix_num); 15218c2ecf20Sopenharmony_ci if (err == 0) 15228c2ecf20Sopenharmony_ci err = 1; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ciunlock: 15258c2ecf20Sopenharmony_ci mutex_unlock(&private->data_mutex); 15268c2ecf20Sopenharmony_ci return err; 15278c2ecf20Sopenharmony_ci} 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_MINMAX( 15308c2ecf20Sopenharmony_ci db_scale_scarlett2_mixer, 15318c2ecf20Sopenharmony_ci SCARLETT2_MIXER_MIN_DB * 100, 15328c2ecf20Sopenharmony_ci SCARLETT2_MIXER_MAX_DB * 100 15338c2ecf20Sopenharmony_ci); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new scarlett2_mixer_ctl = { 15368c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 15378c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 15388c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 15398c2ecf20Sopenharmony_ci .name = "", 15408c2ecf20Sopenharmony_ci .info = scarlett2_mixer_ctl_info, 15418c2ecf20Sopenharmony_ci .get = scarlett2_mixer_ctl_get, 15428c2ecf20Sopenharmony_ci .put = scarlett2_mixer_ctl_put, 15438c2ecf20Sopenharmony_ci .private_value = SCARLETT2_MIXER_MAX_DB, /* max value */ 15448c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_scarlett2_mixer } 15458c2ecf20Sopenharmony_ci}; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_cistatic int scarlett2_add_mixer_ctls(struct usb_mixer_interface *mixer) 15488c2ecf20Sopenharmony_ci{ 15498c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 15508c2ecf20Sopenharmony_ci const struct scarlett2_ports *ports = private->info->ports; 15518c2ecf20Sopenharmony_ci int err, i, j; 15528c2ecf20Sopenharmony_ci int index; 15538c2ecf20Sopenharmony_ci char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci int num_inputs = ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_OUT]; 15568c2ecf20Sopenharmony_ci int num_outputs = ports[SCARLETT2_PORT_TYPE_MIX].num[SCARLETT2_PORT_IN]; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci for (i = 0, index = 0; i < num_outputs; i++) { 15598c2ecf20Sopenharmony_ci for (j = 0; j < num_inputs; j++, index++) { 15608c2ecf20Sopenharmony_ci snprintf(s, sizeof(s), 15618c2ecf20Sopenharmony_ci "Mix %c Input %02d Playback Volume", 15628c2ecf20Sopenharmony_ci 'A' + i, j + 1); 15638c2ecf20Sopenharmony_ci err = scarlett2_add_new_ctl(mixer, &scarlett2_mixer_ctl, 15648c2ecf20Sopenharmony_ci index, 1, s, NULL); 15658c2ecf20Sopenharmony_ci if (err < 0) 15668c2ecf20Sopenharmony_ci return err; 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci } 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci return 0; 15718c2ecf20Sopenharmony_ci} 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci/*** Mux Source Selection Controls ***/ 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_cistatic int scarlett2_mux_src_enum_ctl_info(struct snd_kcontrol *kctl, 15768c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 15778c2ecf20Sopenharmony_ci{ 15788c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 15798c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = elem->head.mixer->private_data; 15808c2ecf20Sopenharmony_ci const struct scarlett2_ports *ports = private->info->ports; 15818c2ecf20Sopenharmony_ci unsigned int item = uinfo->value.enumerated.item; 15828c2ecf20Sopenharmony_ci int items = private->num_mux_srcs; 15838c2ecf20Sopenharmony_ci int port_type; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 15868c2ecf20Sopenharmony_ci uinfo->count = elem->channels; 15878c2ecf20Sopenharmony_ci uinfo->value.enumerated.items = items; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci if (item >= items) 15908c2ecf20Sopenharmony_ci item = uinfo->value.enumerated.item = items - 1; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci for (port_type = 0; 15938c2ecf20Sopenharmony_ci port_type < SCARLETT2_PORT_TYPE_COUNT; 15948c2ecf20Sopenharmony_ci port_type++) { 15958c2ecf20Sopenharmony_ci if (item < ports[port_type].num[SCARLETT2_PORT_IN]) { 15968c2ecf20Sopenharmony_ci sprintf(uinfo->value.enumerated.name, 15978c2ecf20Sopenharmony_ci ports[port_type].src_descr, 15988c2ecf20Sopenharmony_ci item + ports[port_type].src_num_offset); 15998c2ecf20Sopenharmony_ci return 0; 16008c2ecf20Sopenharmony_ci } 16018c2ecf20Sopenharmony_ci item -= ports[port_type].num[SCARLETT2_PORT_IN]; 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci return -EINVAL; 16058c2ecf20Sopenharmony_ci} 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_cistatic int scarlett2_mux_src_enum_ctl_get(struct snd_kcontrol *kctl, 16088c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 16098c2ecf20Sopenharmony_ci{ 16108c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 16118c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = elem->head.mixer->private_data; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = private->mux[elem->control]; 16148c2ecf20Sopenharmony_ci return 0; 16158c2ecf20Sopenharmony_ci} 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_cistatic int scarlett2_mux_src_enum_ctl_put(struct snd_kcontrol *kctl, 16188c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 16198c2ecf20Sopenharmony_ci{ 16208c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 16218c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = elem->head.mixer; 16228c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 16238c2ecf20Sopenharmony_ci int index = elem->control; 16248c2ecf20Sopenharmony_ci int oval, val, err = 0; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci mutex_lock(&private->data_mutex); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci oval = private->mux[index]; 16298c2ecf20Sopenharmony_ci val = clamp(ucontrol->value.integer.value[0], 16308c2ecf20Sopenharmony_ci 0L, private->num_mux_srcs - 1L); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci if (oval == val) 16338c2ecf20Sopenharmony_ci goto unlock; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci private->mux[index] = val; 16368c2ecf20Sopenharmony_ci err = scarlett2_usb_set_mux(mixer); 16378c2ecf20Sopenharmony_ci if (err == 0) 16388c2ecf20Sopenharmony_ci err = 1; 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ciunlock: 16418c2ecf20Sopenharmony_ci mutex_unlock(&private->data_mutex); 16428c2ecf20Sopenharmony_ci return err; 16438c2ecf20Sopenharmony_ci} 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new scarlett2_mux_src_enum_ctl = { 16468c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 16478c2ecf20Sopenharmony_ci .name = "", 16488c2ecf20Sopenharmony_ci .info = scarlett2_mux_src_enum_ctl_info, 16498c2ecf20Sopenharmony_ci .get = scarlett2_mux_src_enum_ctl_get, 16508c2ecf20Sopenharmony_ci .put = scarlett2_mux_src_enum_ctl_put, 16518c2ecf20Sopenharmony_ci}; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_cistatic int scarlett2_add_mux_enums(struct usb_mixer_interface *mixer) 16548c2ecf20Sopenharmony_ci{ 16558c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 16568c2ecf20Sopenharmony_ci const struct scarlett2_ports *ports = private->info->ports; 16578c2ecf20Sopenharmony_ci int port_type, channel, i; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci for (i = 0, port_type = 0; 16608c2ecf20Sopenharmony_ci port_type < SCARLETT2_PORT_TYPE_COUNT; 16618c2ecf20Sopenharmony_ci port_type++) { 16628c2ecf20Sopenharmony_ci for (channel = 0; 16638c2ecf20Sopenharmony_ci channel < ports[port_type].num[SCARLETT2_PORT_OUT]; 16648c2ecf20Sopenharmony_ci channel++, i++) { 16658c2ecf20Sopenharmony_ci int err; 16668c2ecf20Sopenharmony_ci char s[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 16678c2ecf20Sopenharmony_ci const char *const descr = ports[port_type].dst_descr; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci snprintf(s, sizeof(s) - 5, descr, channel + 1); 16708c2ecf20Sopenharmony_ci strcat(s, " Enum"); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci err = scarlett2_add_new_ctl(mixer, 16738c2ecf20Sopenharmony_ci &scarlett2_mux_src_enum_ctl, 16748c2ecf20Sopenharmony_ci i, 1, s, NULL); 16758c2ecf20Sopenharmony_ci if (err < 0) 16768c2ecf20Sopenharmony_ci return err; 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci } 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci return 0; 16818c2ecf20Sopenharmony_ci} 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci/*** Meter Controls ***/ 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_cistatic int scarlett2_meter_ctl_info(struct snd_kcontrol *kctl, 16868c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 16878c2ecf20Sopenharmony_ci{ 16888c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 16918c2ecf20Sopenharmony_ci uinfo->count = elem->channels; 16928c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 16938c2ecf20Sopenharmony_ci uinfo->value.integer.max = 4095; 16948c2ecf20Sopenharmony_ci uinfo->value.integer.step = 1; 16958c2ecf20Sopenharmony_ci return 0; 16968c2ecf20Sopenharmony_ci} 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_cistatic int scarlett2_meter_ctl_get(struct snd_kcontrol *kctl, 16998c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 17028c2ecf20Sopenharmony_ci u16 meter_levels[SCARLETT2_NUM_METERS]; 17038c2ecf20Sopenharmony_ci int i, err; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci err = scarlett2_usb_get_meter_levels(elem->head.mixer, meter_levels); 17068c2ecf20Sopenharmony_ci if (err < 0) 17078c2ecf20Sopenharmony_ci return err; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci for (i = 0; i < elem->channels; i++) 17108c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i] = meter_levels[i]; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci return 0; 17138c2ecf20Sopenharmony_ci} 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new scarlett2_meter_ctl = { 17168c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 17178c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 17188c2ecf20Sopenharmony_ci .name = "", 17198c2ecf20Sopenharmony_ci .info = scarlett2_meter_ctl_info, 17208c2ecf20Sopenharmony_ci .get = scarlett2_meter_ctl_get 17218c2ecf20Sopenharmony_ci}; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_cistatic int scarlett2_add_meter_ctl(struct usb_mixer_interface *mixer) 17248c2ecf20Sopenharmony_ci{ 17258c2ecf20Sopenharmony_ci return scarlett2_add_new_ctl(mixer, &scarlett2_meter_ctl, 17268c2ecf20Sopenharmony_ci 0, SCARLETT2_NUM_METERS, 17278c2ecf20Sopenharmony_ci "Level Meter", NULL); 17288c2ecf20Sopenharmony_ci} 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci/*** Cleanup/Suspend Callbacks ***/ 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_cistatic void scarlett2_private_free(struct usb_mixer_interface *mixer) 17338c2ecf20Sopenharmony_ci{ 17348c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&private->work); 17378c2ecf20Sopenharmony_ci kfree(private); 17388c2ecf20Sopenharmony_ci mixer->private_data = NULL; 17398c2ecf20Sopenharmony_ci} 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_cistatic void scarlett2_private_suspend(struct usb_mixer_interface *mixer) 17428c2ecf20Sopenharmony_ci{ 17438c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci if (cancel_delayed_work_sync(&private->work)) 17468c2ecf20Sopenharmony_ci scarlett2_config_save(private->mixer); 17478c2ecf20Sopenharmony_ci} 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci/*** Initialisation ***/ 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_cistatic int scarlett2_count_mux_srcs(const struct scarlett2_ports *ports) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci int port_type, count = 0; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci for (port_type = 0; 17568c2ecf20Sopenharmony_ci port_type < SCARLETT2_PORT_TYPE_COUNT; 17578c2ecf20Sopenharmony_ci port_type++) 17588c2ecf20Sopenharmony_ci count += ports[port_type].num[SCARLETT2_PORT_IN]; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci return count; 17618c2ecf20Sopenharmony_ci} 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci/* Default routing connects PCM outputs and inputs to Analogue, 17648c2ecf20Sopenharmony_ci * S/PDIF, then ADAT 17658c2ecf20Sopenharmony_ci */ 17668c2ecf20Sopenharmony_cistatic void scarlett2_init_routing(u8 *mux, 17678c2ecf20Sopenharmony_ci const struct scarlett2_ports *ports) 17688c2ecf20Sopenharmony_ci{ 17698c2ecf20Sopenharmony_ci int i, input_num, input_count, port_type; 17708c2ecf20Sopenharmony_ci int output_num, output_count, port_type_connect_num; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci static const int connect_order[] = { 17738c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_ANALOGUE, 17748c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_SPDIF, 17758c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_ADAT, 17768c2ecf20Sopenharmony_ci -1 17778c2ecf20Sopenharmony_ci }; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci /* Assign PCM inputs (routing outputs) */ 17808c2ecf20Sopenharmony_ci output_num = scarlett2_get_port_start_num(ports, 17818c2ecf20Sopenharmony_ci SCARLETT2_PORT_OUT, 17828c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_PCM); 17838c2ecf20Sopenharmony_ci output_count = ports[SCARLETT2_PORT_TYPE_PCM].num[SCARLETT2_PORT_OUT]; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci for (port_type = connect_order[port_type_connect_num = 0]; 17868c2ecf20Sopenharmony_ci port_type >= 0; 17878c2ecf20Sopenharmony_ci port_type = connect_order[++port_type_connect_num]) { 17888c2ecf20Sopenharmony_ci input_num = scarlett2_get_port_start_num( 17898c2ecf20Sopenharmony_ci ports, SCARLETT2_PORT_IN, port_type); 17908c2ecf20Sopenharmony_ci input_count = ports[port_type].num[SCARLETT2_PORT_IN]; 17918c2ecf20Sopenharmony_ci for (i = 0; 17928c2ecf20Sopenharmony_ci i < input_count && output_count; 17938c2ecf20Sopenharmony_ci i++, output_count--) 17948c2ecf20Sopenharmony_ci mux[output_num++] = input_num++; 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci /* Assign PCM outputs (routing inputs) */ 17988c2ecf20Sopenharmony_ci input_num = scarlett2_get_port_start_num(ports, 17998c2ecf20Sopenharmony_ci SCARLETT2_PORT_IN, 18008c2ecf20Sopenharmony_ci SCARLETT2_PORT_TYPE_PCM); 18018c2ecf20Sopenharmony_ci input_count = ports[SCARLETT2_PORT_TYPE_PCM].num[SCARLETT2_PORT_IN]; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci for (port_type = connect_order[port_type_connect_num = 0]; 18048c2ecf20Sopenharmony_ci port_type >= 0; 18058c2ecf20Sopenharmony_ci port_type = connect_order[++port_type_connect_num]) { 18068c2ecf20Sopenharmony_ci output_num = scarlett2_get_port_start_num( 18078c2ecf20Sopenharmony_ci ports, SCARLETT2_PORT_OUT, port_type); 18088c2ecf20Sopenharmony_ci output_count = ports[port_type].num[SCARLETT2_PORT_OUT]; 18098c2ecf20Sopenharmony_ci for (i = 0; 18108c2ecf20Sopenharmony_ci i < output_count && input_count; 18118c2ecf20Sopenharmony_ci i++, input_count--) 18128c2ecf20Sopenharmony_ci mux[output_num++] = input_num++; 18138c2ecf20Sopenharmony_ci } 18148c2ecf20Sopenharmony_ci} 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci/* Initialise private data, routing, sequence number */ 18178c2ecf20Sopenharmony_cistatic int scarlett2_init_private(struct usb_mixer_interface *mixer, 18188c2ecf20Sopenharmony_ci const struct scarlett2_device_info *info) 18198c2ecf20Sopenharmony_ci{ 18208c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = 18218c2ecf20Sopenharmony_ci kzalloc(sizeof(struct scarlett2_mixer_data), GFP_KERNEL); 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci if (!private) 18248c2ecf20Sopenharmony_ci return -ENOMEM; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci mutex_init(&private->usb_mutex); 18278c2ecf20Sopenharmony_ci mutex_init(&private->data_mutex); 18288c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work); 18298c2ecf20Sopenharmony_ci private->info = info; 18308c2ecf20Sopenharmony_ci private->num_mux_srcs = scarlett2_count_mux_srcs(info->ports); 18318c2ecf20Sopenharmony_ci private->scarlett2_seq = 0; 18328c2ecf20Sopenharmony_ci private->mixer = mixer; 18338c2ecf20Sopenharmony_ci mixer->private_data = private; 18348c2ecf20Sopenharmony_ci mixer->private_free = scarlett2_private_free; 18358c2ecf20Sopenharmony_ci mixer->private_suspend = scarlett2_private_suspend; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci /* Setup default routing */ 18388c2ecf20Sopenharmony_ci scarlett2_init_routing(private->mux, info->ports); 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci /* Initialise the sequence number used for the proprietary commands */ 18418c2ecf20Sopenharmony_ci return scarlett2_usb(mixer, SCARLETT2_USB_INIT_SEQ, NULL, 0, NULL, 0); 18428c2ecf20Sopenharmony_ci} 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci/* Read line-in config and line-out volume settings on start */ 18458c2ecf20Sopenharmony_cistatic int scarlett2_read_configs(struct usb_mixer_interface *mixer) 18468c2ecf20Sopenharmony_ci{ 18478c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 18488c2ecf20Sopenharmony_ci const struct scarlett2_device_info *info = private->info; 18498c2ecf20Sopenharmony_ci const struct scarlett2_ports *ports = info->ports; 18508c2ecf20Sopenharmony_ci int num_line_out = 18518c2ecf20Sopenharmony_ci ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT]; 18528c2ecf20Sopenharmony_ci u8 level_switches[SCARLETT2_LEVEL_SWITCH_MAX]; 18538c2ecf20Sopenharmony_ci u8 pad_switches[SCARLETT2_PAD_SWITCH_MAX]; 18548c2ecf20Sopenharmony_ci struct scarlett2_usb_volume_status volume_status; 18558c2ecf20Sopenharmony_ci int err, i; 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci if (info->level_input_count) { 18588c2ecf20Sopenharmony_ci err = scarlett2_usb_get_config( 18598c2ecf20Sopenharmony_ci mixer, 18608c2ecf20Sopenharmony_ci SCARLETT2_CONFIG_LEVEL_SWITCH, 18618c2ecf20Sopenharmony_ci info->level_input_count, 18628c2ecf20Sopenharmony_ci level_switches); 18638c2ecf20Sopenharmony_ci if (err < 0) 18648c2ecf20Sopenharmony_ci return err; 18658c2ecf20Sopenharmony_ci for (i = 0; i < info->level_input_count; i++) 18668c2ecf20Sopenharmony_ci private->level_switch[i] = level_switches[i]; 18678c2ecf20Sopenharmony_ci } 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci if (info->pad_input_count) { 18708c2ecf20Sopenharmony_ci err = scarlett2_usb_get_config( 18718c2ecf20Sopenharmony_ci mixer, 18728c2ecf20Sopenharmony_ci SCARLETT2_CONFIG_PAD_SWITCH, 18738c2ecf20Sopenharmony_ci info->pad_input_count, 18748c2ecf20Sopenharmony_ci pad_switches); 18758c2ecf20Sopenharmony_ci if (err < 0) 18768c2ecf20Sopenharmony_ci return err; 18778c2ecf20Sopenharmony_ci for (i = 0; i < info->pad_input_count; i++) 18788c2ecf20Sopenharmony_ci private->pad_switch[i] = pad_switches[i]; 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci err = scarlett2_usb_get_volume_status(mixer, &volume_status); 18828c2ecf20Sopenharmony_ci if (err < 0) 18838c2ecf20Sopenharmony_ci return err; 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci private->master_vol = clamp( 18868c2ecf20Sopenharmony_ci volume_status.master_vol + SCARLETT2_VOLUME_BIAS, 18878c2ecf20Sopenharmony_ci 0, SCARLETT2_VOLUME_BIAS); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci for (i = 0; i < num_line_out; i++) { 18908c2ecf20Sopenharmony_ci int volume; 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci private->vol_sw_hw_switch[i] = 18938c2ecf20Sopenharmony_ci info->line_out_hw_vol 18948c2ecf20Sopenharmony_ci && volume_status.sw_hw_switch[i]; 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci volume = private->vol_sw_hw_switch[i] 18978c2ecf20Sopenharmony_ci ? volume_status.master_vol 18988c2ecf20Sopenharmony_ci : volume_status.sw_vol[i]; 18998c2ecf20Sopenharmony_ci volume = clamp(volume + SCARLETT2_VOLUME_BIAS, 19008c2ecf20Sopenharmony_ci 0, SCARLETT2_VOLUME_BIAS); 19018c2ecf20Sopenharmony_ci private->vol[i] = volume; 19028c2ecf20Sopenharmony_ci } 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci for (i = 0; i < info->button_count; i++) 19058c2ecf20Sopenharmony_ci private->buttons[i] = !!volume_status.buttons[i]; 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci return 0; 19088c2ecf20Sopenharmony_ci} 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci/* Notify on volume change */ 19118c2ecf20Sopenharmony_cistatic void scarlett2_mixer_interrupt_vol_change( 19128c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer) 19138c2ecf20Sopenharmony_ci{ 19148c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 19158c2ecf20Sopenharmony_ci const struct scarlett2_ports *ports = private->info->ports; 19168c2ecf20Sopenharmony_ci int num_line_out = 19178c2ecf20Sopenharmony_ci ports[SCARLETT2_PORT_TYPE_ANALOGUE].num[SCARLETT2_PORT_OUT]; 19188c2ecf20Sopenharmony_ci int i; 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci private->vol_updated = 1; 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, 19238c2ecf20Sopenharmony_ci &private->master_vol_ctl->id); 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci for (i = 0; i < num_line_out; i++) { 19268c2ecf20Sopenharmony_ci if (!private->vol_sw_hw_switch[i]) 19278c2ecf20Sopenharmony_ci continue; 19288c2ecf20Sopenharmony_ci snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, 19298c2ecf20Sopenharmony_ci &private->vol_ctls[i]->id); 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci} 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci/* Notify on button change */ 19348c2ecf20Sopenharmony_cistatic void scarlett2_mixer_interrupt_button_change( 19358c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer) 19368c2ecf20Sopenharmony_ci{ 19378c2ecf20Sopenharmony_ci struct scarlett2_mixer_data *private = mixer->private_data; 19388c2ecf20Sopenharmony_ci int i; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci private->vol_updated = 1; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci for (i = 0; i < private->info->button_count; i++) 19438c2ecf20Sopenharmony_ci snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, 19448c2ecf20Sopenharmony_ci &private->button_ctls[i]->id); 19458c2ecf20Sopenharmony_ci} 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci/* Interrupt callback */ 19488c2ecf20Sopenharmony_cistatic void scarlett2_mixer_interrupt(struct urb *urb) 19498c2ecf20Sopenharmony_ci{ 19508c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = urb->context; 19518c2ecf20Sopenharmony_ci int len = urb->actual_length; 19528c2ecf20Sopenharmony_ci int ustatus = urb->status; 19538c2ecf20Sopenharmony_ci u32 data; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci if (ustatus != 0) 19568c2ecf20Sopenharmony_ci goto requeue; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci if (len == 8) { 19598c2ecf20Sopenharmony_ci data = le32_to_cpu(*(__le32 *)urb->transfer_buffer); 19608c2ecf20Sopenharmony_ci if (data & SCARLETT2_USB_INTERRUPT_VOL_CHANGE) 19618c2ecf20Sopenharmony_ci scarlett2_mixer_interrupt_vol_change(mixer); 19628c2ecf20Sopenharmony_ci if (data & SCARLETT2_USB_INTERRUPT_BUTTON_CHANGE) 19638c2ecf20Sopenharmony_ci scarlett2_mixer_interrupt_button_change(mixer); 19648c2ecf20Sopenharmony_ci } else { 19658c2ecf20Sopenharmony_ci usb_audio_err(mixer->chip, 19668c2ecf20Sopenharmony_ci "scarlett mixer interrupt length %d\n", len); 19678c2ecf20Sopenharmony_ci } 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_cirequeue: 19708c2ecf20Sopenharmony_ci if (ustatus != -ENOENT && 19718c2ecf20Sopenharmony_ci ustatus != -ECONNRESET && 19728c2ecf20Sopenharmony_ci ustatus != -ESHUTDOWN) { 19738c2ecf20Sopenharmony_ci urb->dev = mixer->chip->dev; 19748c2ecf20Sopenharmony_ci usb_submit_urb(urb, GFP_ATOMIC); 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci} 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_cistatic int scarlett2_mixer_status_create(struct usb_mixer_interface *mixer) 19798c2ecf20Sopenharmony_ci{ 19808c2ecf20Sopenharmony_ci struct usb_device *dev = mixer->chip->dev; 19818c2ecf20Sopenharmony_ci unsigned int pipe = usb_rcvintpipe(dev, 19828c2ecf20Sopenharmony_ci SCARLETT2_USB_INTERRUPT_ENDPOINT); 19838c2ecf20Sopenharmony_ci void *transfer_buffer; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci if (mixer->urb) { 19868c2ecf20Sopenharmony_ci usb_audio_err(mixer->chip, 19878c2ecf20Sopenharmony_ci "%s: mixer urb already in use!\n", __func__); 19888c2ecf20Sopenharmony_ci return 0; 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci if (usb_pipe_type_check(dev, pipe)) 19928c2ecf20Sopenharmony_ci return -EINVAL; 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci mixer->urb = usb_alloc_urb(0, GFP_KERNEL); 19958c2ecf20Sopenharmony_ci if (!mixer->urb) 19968c2ecf20Sopenharmony_ci return -ENOMEM; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci transfer_buffer = kmalloc(SCARLETT2_USB_INTERRUPT_MAX_DATA, GFP_KERNEL); 19998c2ecf20Sopenharmony_ci if (!transfer_buffer) 20008c2ecf20Sopenharmony_ci return -ENOMEM; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci usb_fill_int_urb(mixer->urb, dev, pipe, 20038c2ecf20Sopenharmony_ci transfer_buffer, SCARLETT2_USB_INTERRUPT_MAX_DATA, 20048c2ecf20Sopenharmony_ci scarlett2_mixer_interrupt, mixer, 20058c2ecf20Sopenharmony_ci SCARLETT2_USB_INTERRUPT_INTERVAL); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci return usb_submit_urb(mixer->urb, GFP_KERNEL); 20088c2ecf20Sopenharmony_ci} 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_cistatic int snd_scarlett_gen2_controls_create(struct usb_mixer_interface *mixer, 20118c2ecf20Sopenharmony_ci const struct scarlett2_device_info *info) 20128c2ecf20Sopenharmony_ci{ 20138c2ecf20Sopenharmony_ci int err; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci /* Initialise private data, routing, sequence number */ 20168c2ecf20Sopenharmony_ci err = scarlett2_init_private(mixer, info); 20178c2ecf20Sopenharmony_ci if (err < 0) 20188c2ecf20Sopenharmony_ci return err; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci /* Read volume levels and controls from the interface */ 20218c2ecf20Sopenharmony_ci err = scarlett2_read_configs(mixer); 20228c2ecf20Sopenharmony_ci if (err < 0) 20238c2ecf20Sopenharmony_ci return err; 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci /* Create the analogue output controls */ 20268c2ecf20Sopenharmony_ci err = scarlett2_add_line_out_ctls(mixer); 20278c2ecf20Sopenharmony_ci if (err < 0) 20288c2ecf20Sopenharmony_ci return err; 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci /* Create the analogue input controls */ 20318c2ecf20Sopenharmony_ci err = scarlett2_add_line_in_ctls(mixer); 20328c2ecf20Sopenharmony_ci if (err < 0) 20338c2ecf20Sopenharmony_ci return err; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci /* Create the input, output, and mixer mux input selections */ 20368c2ecf20Sopenharmony_ci err = scarlett2_add_mux_enums(mixer); 20378c2ecf20Sopenharmony_ci if (err < 0) 20388c2ecf20Sopenharmony_ci return err; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci /* Create the matrix mixer controls */ 20418c2ecf20Sopenharmony_ci err = scarlett2_add_mixer_ctls(mixer); 20428c2ecf20Sopenharmony_ci if (err < 0) 20438c2ecf20Sopenharmony_ci return err; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci /* Create the level meter controls */ 20468c2ecf20Sopenharmony_ci err = scarlett2_add_meter_ctl(mixer); 20478c2ecf20Sopenharmony_ci if (err < 0) 20488c2ecf20Sopenharmony_ci return err; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci /* Set up the interrupt polling if there are hardware buttons */ 20518c2ecf20Sopenharmony_ci if (info->button_count) { 20528c2ecf20Sopenharmony_ci err = scarlett2_mixer_status_create(mixer); 20538c2ecf20Sopenharmony_ci if (err < 0) 20548c2ecf20Sopenharmony_ci return err; 20558c2ecf20Sopenharmony_ci } 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci return 0; 20588c2ecf20Sopenharmony_ci} 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ciint snd_scarlett_gen2_init(struct usb_mixer_interface *mixer) 20618c2ecf20Sopenharmony_ci{ 20628c2ecf20Sopenharmony_ci struct snd_usb_audio *chip = mixer->chip; 20638c2ecf20Sopenharmony_ci const struct scarlett2_device_info *info; 20648c2ecf20Sopenharmony_ci int err; 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci /* only use UAC_VERSION_2 */ 20678c2ecf20Sopenharmony_ci if (!mixer->protocol) 20688c2ecf20Sopenharmony_ci return 0; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci switch (chip->usb_id) { 20718c2ecf20Sopenharmony_ci case USB_ID(0x1235, 0x8203): 20728c2ecf20Sopenharmony_ci info = &s6i6_gen2_info; 20738c2ecf20Sopenharmony_ci break; 20748c2ecf20Sopenharmony_ci case USB_ID(0x1235, 0x8204): 20758c2ecf20Sopenharmony_ci info = &s18i8_gen2_info; 20768c2ecf20Sopenharmony_ci break; 20778c2ecf20Sopenharmony_ci case USB_ID(0x1235, 0x8201): 20788c2ecf20Sopenharmony_ci info = &s18i20_gen2_info; 20798c2ecf20Sopenharmony_ci break; 20808c2ecf20Sopenharmony_ci default: /* device not (yet) supported */ 20818c2ecf20Sopenharmony_ci return -EINVAL; 20828c2ecf20Sopenharmony_ci } 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci if (!(chip->setup & SCARLETT2_ENABLE)) { 20858c2ecf20Sopenharmony_ci usb_audio_info(chip, 20868c2ecf20Sopenharmony_ci "Focusrite Scarlett Gen 2 Mixer Driver disabled; " 20878c2ecf20Sopenharmony_ci "use options snd_usb_audio vid=0x%04x pid=0x%04x " 20888c2ecf20Sopenharmony_ci "device_setup=1 to enable and report any issues " 20898c2ecf20Sopenharmony_ci "to g@b4.vu", 20908c2ecf20Sopenharmony_ci USB_ID_VENDOR(chip->usb_id), 20918c2ecf20Sopenharmony_ci USB_ID_PRODUCT(chip->usb_id)); 20928c2ecf20Sopenharmony_ci return 0; 20938c2ecf20Sopenharmony_ci } 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci usb_audio_info(chip, 20968c2ecf20Sopenharmony_ci "Focusrite Scarlett Gen 2 Mixer Driver enabled pid=0x%04x", 20978c2ecf20Sopenharmony_ci USB_ID_PRODUCT(chip->usb_id)); 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci err = snd_scarlett_gen2_controls_create(mixer, info); 21008c2ecf20Sopenharmony_ci if (err < 0) 21018c2ecf20Sopenharmony_ci usb_audio_err(mixer->chip, 21028c2ecf20Sopenharmony_ci "Error initialising Scarlett Mixer Driver: %d", 21038c2ecf20Sopenharmony_ci err); 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci return err; 21068c2ecf20Sopenharmony_ci} 2107