18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Presonus Studio 1810c driver for ALSA 48c2ecf20Sopenharmony_ci * Copyright (C) 2019 Nick Kossifidis <mickflemm@gmail.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Based on reverse engineering of the communication protocol 78c2ecf20Sopenharmony_ci * between the windows driver / Univeral Control (UC) program 88c2ecf20Sopenharmony_ci * and the device, through usbmon. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * For now this bypasses the mixer, with all channels split, 118c2ecf20Sopenharmony_ci * so that the software can mix with greater flexibility. 128c2ecf20Sopenharmony_ci * It also adds controls for the 4 buttons on the front of 138c2ecf20Sopenharmony_ci * the device. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/usb.h> 178c2ecf20Sopenharmony_ci#include <linux/usb/audio-v2.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <sound/core.h> 208c2ecf20Sopenharmony_ci#include <sound/control.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "usbaudio.h" 238c2ecf20Sopenharmony_ci#include "mixer.h" 248c2ecf20Sopenharmony_ci#include "mixer_quirks.h" 258c2ecf20Sopenharmony_ci#include "helper.h" 268c2ecf20Sopenharmony_ci#include "mixer_s1810c.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define SC1810C_CMD_REQ 160 298c2ecf20Sopenharmony_ci#define SC1810C_CMD_REQTYPE \ 308c2ecf20Sopenharmony_ci (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT) 318c2ecf20Sopenharmony_ci#define SC1810C_CMD_F1 0x50617269 328c2ecf20Sopenharmony_ci#define SC1810C_CMD_F2 0x14 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * DISCLAIMER: These are just guesses based on the 368c2ecf20Sopenharmony_ci * dumps I got. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * It seems like a selects between 398c2ecf20Sopenharmony_ci * device (0), mixer (0x64) and output (0x65) 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * For mixer (0x64): 428c2ecf20Sopenharmony_ci * * b selects an input channel (see below). 438c2ecf20Sopenharmony_ci * * c selects an output channel pair (see below). 448c2ecf20Sopenharmony_ci * * d selects left (0) or right (1) of that pair. 458c2ecf20Sopenharmony_ci * * e 0-> disconnect, 0x01000000-> connect, 468c2ecf20Sopenharmony_ci * 0x0109-> used for stereo-linking channels, 478c2ecf20Sopenharmony_ci * e is also used for setting volume levels 488c2ecf20Sopenharmony_ci * in which case b is also set so I guess 498c2ecf20Sopenharmony_ci * this way it is possible to set the volume 508c2ecf20Sopenharmony_ci * level from the specified input to the 518c2ecf20Sopenharmony_ci * specified output. 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * IN Channels: 548c2ecf20Sopenharmony_ci * 0 - 7 Mic/Inst/Line (Analog inputs) 558c2ecf20Sopenharmony_ci * 8 - 9 S/PDIF 568c2ecf20Sopenharmony_ci * 10 - 17 ADAT 578c2ecf20Sopenharmony_ci * 18 - 35 DAW (Inputs from the host) 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * OUT Channels (pairs): 608c2ecf20Sopenharmony_ci * 0 -> Main out 618c2ecf20Sopenharmony_ci * 1 -> Line1/2 628c2ecf20Sopenharmony_ci * 2 -> Line3/4 638c2ecf20Sopenharmony_ci * 3 -> S/PDIF 648c2ecf20Sopenharmony_ci * 4 -> ADAT? 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * For device (0): 678c2ecf20Sopenharmony_ci * * b and c are not used, at least not on the 688c2ecf20Sopenharmony_ci * dumps I got. 698c2ecf20Sopenharmony_ci * * d sets the control id to be modified 708c2ecf20Sopenharmony_ci * (see below). 718c2ecf20Sopenharmony_ci * * e sets the setting for that control. 728c2ecf20Sopenharmony_ci * (so for the switches I was interested 738c2ecf20Sopenharmony_ci * in it's 0/1) 748c2ecf20Sopenharmony_ci * 758c2ecf20Sopenharmony_ci * For output (0x65): 768c2ecf20Sopenharmony_ci * * b is the output channel (see above). 778c2ecf20Sopenharmony_ci * * c is zero. 788c2ecf20Sopenharmony_ci * * e I guess the same as with mixer except 0x0109 798c2ecf20Sopenharmony_ci * which I didn't see in my dumps. 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * The two fixed fields have the same values for 828c2ecf20Sopenharmony_ci * mixer and output but a different set for device. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_cistruct s1810c_ctl_packet { 858c2ecf20Sopenharmony_ci u32 a; 868c2ecf20Sopenharmony_ci u32 b; 878c2ecf20Sopenharmony_ci u32 fixed1; 888c2ecf20Sopenharmony_ci u32 fixed2; 898c2ecf20Sopenharmony_ci u32 c; 908c2ecf20Sopenharmony_ci u32 d; 918c2ecf20Sopenharmony_ci u32 e; 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define SC1810C_CTL_LINE_SW 0 958c2ecf20Sopenharmony_ci#define SC1810C_CTL_MUTE_SW 1 968c2ecf20Sopenharmony_ci#define SC1810C_CTL_AB_SW 3 978c2ecf20Sopenharmony_ci#define SC1810C_CTL_48V_SW 4 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci#define SC1810C_SET_STATE_REQ 161 1008c2ecf20Sopenharmony_ci#define SC1810C_SET_STATE_REQTYPE SC1810C_CMD_REQTYPE 1018c2ecf20Sopenharmony_ci#define SC1810C_SET_STATE_F1 0x64656D73 1028c2ecf20Sopenharmony_ci#define SC1810C_SET_STATE_F2 0xF4 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#define SC1810C_GET_STATE_REQ 162 1058c2ecf20Sopenharmony_ci#define SC1810C_GET_STATE_REQTYPE \ 1068c2ecf20Sopenharmony_ci (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN) 1078c2ecf20Sopenharmony_ci#define SC1810C_GET_STATE_F1 SC1810C_SET_STATE_F1 1088c2ecf20Sopenharmony_ci#define SC1810C_GET_STATE_F2 SC1810C_SET_STATE_F2 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci#define SC1810C_STATE_F1_IDX 2 1118c2ecf20Sopenharmony_ci#define SC1810C_STATE_F2_IDX 3 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* 1148c2ecf20Sopenharmony_ci * This packet includes mixer volumes and 1158c2ecf20Sopenharmony_ci * various other fields, it's an extended 1168c2ecf20Sopenharmony_ci * version of ctl_packet, with a and b 1178c2ecf20Sopenharmony_ci * being zero and different f1/f2. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistruct s1810c_state_packet { 1208c2ecf20Sopenharmony_ci u32 fields[63]; 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci#define SC1810C_STATE_48V_SW 58 1248c2ecf20Sopenharmony_ci#define SC1810C_STATE_LINE_SW 59 1258c2ecf20Sopenharmony_ci#define SC1810C_STATE_MUTE_SW 60 1268c2ecf20Sopenharmony_ci#define SC1810C_STATE_AB_SW 62 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistruct s1810_mixer_state { 1298c2ecf20Sopenharmony_ci uint16_t seqnum; 1308c2ecf20Sopenharmony_ci struct mutex usb_mutex; 1318c2ecf20Sopenharmony_ci struct mutex data_mutex; 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int 1358c2ecf20Sopenharmony_cisnd_s1810c_send_ctl_packet(struct usb_device *dev, u32 a, 1368c2ecf20Sopenharmony_ci u32 b, u32 c, u32 d, u32 e) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct s1810c_ctl_packet pkt = { 0 }; 1398c2ecf20Sopenharmony_ci int ret = 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci pkt.fixed1 = SC1810C_CMD_F1; 1428c2ecf20Sopenharmony_ci pkt.fixed2 = SC1810C_CMD_F2; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci pkt.a = a; 1458c2ecf20Sopenharmony_ci pkt.b = b; 1468c2ecf20Sopenharmony_ci pkt.c = c; 1478c2ecf20Sopenharmony_ci pkt.d = d; 1488c2ecf20Sopenharmony_ci /* 1498c2ecf20Sopenharmony_ci * Value for settings 0/1 for this 1508c2ecf20Sopenharmony_ci * output channel is always 0 (probably because 1518c2ecf20Sopenharmony_ci * there is no ADAT output on 1810c) 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci pkt.e = (c == 4) ? 0 : e; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci ret = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 1568c2ecf20Sopenharmony_ci SC1810C_CMD_REQ, 1578c2ecf20Sopenharmony_ci SC1810C_CMD_REQTYPE, 0, 0, &pkt, sizeof(pkt)); 1588c2ecf20Sopenharmony_ci if (ret < 0) { 1598c2ecf20Sopenharmony_ci dev_warn(&dev->dev, "could not send ctl packet\n"); 1608c2ecf20Sopenharmony_ci return ret; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* 1668c2ecf20Sopenharmony_ci * When opening Universal Control the program periodicaly 1678c2ecf20Sopenharmony_ci * sends and receives state packets for syncinc state between 1688c2ecf20Sopenharmony_ci * the device and the host. 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * Note that if we send only the request to get data back we'll 1718c2ecf20Sopenharmony_ci * get an error, we need to first send an empty state packet and 1728c2ecf20Sopenharmony_ci * then ask to receive a filled. Their seqnumbers must also match. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_cistatic int 1758c2ecf20Sopenharmony_cisnd_sc1810c_get_status_field(struct usb_device *dev, 1768c2ecf20Sopenharmony_ci u32 *field, int field_idx, uint16_t *seqnum) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct s1810c_state_packet pkt_out = { { 0 } }; 1798c2ecf20Sopenharmony_ci struct s1810c_state_packet pkt_in = { { 0 } }; 1808c2ecf20Sopenharmony_ci int ret = 0; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci pkt_out.fields[SC1810C_STATE_F1_IDX] = SC1810C_SET_STATE_F1; 1838c2ecf20Sopenharmony_ci pkt_out.fields[SC1810C_STATE_F2_IDX] = SC1810C_SET_STATE_F2; 1848c2ecf20Sopenharmony_ci ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 1858c2ecf20Sopenharmony_ci SC1810C_SET_STATE_REQ, 1868c2ecf20Sopenharmony_ci SC1810C_SET_STATE_REQTYPE, 1878c2ecf20Sopenharmony_ci (*seqnum), 0, &pkt_out, sizeof(pkt_out)); 1888c2ecf20Sopenharmony_ci if (ret < 0) { 1898c2ecf20Sopenharmony_ci dev_warn(&dev->dev, "could not send state packet (%d)\n", ret); 1908c2ecf20Sopenharmony_ci return ret; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 1948c2ecf20Sopenharmony_ci SC1810C_GET_STATE_REQ, 1958c2ecf20Sopenharmony_ci SC1810C_GET_STATE_REQTYPE, 1968c2ecf20Sopenharmony_ci (*seqnum), 0, &pkt_in, sizeof(pkt_in)); 1978c2ecf20Sopenharmony_ci if (ret < 0) { 1988c2ecf20Sopenharmony_ci dev_warn(&dev->dev, "could not get state field %u (%d)\n", 1998c2ecf20Sopenharmony_ci field_idx, ret); 2008c2ecf20Sopenharmony_ci return ret; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci (*field) = pkt_in.fields[field_idx]; 2048c2ecf20Sopenharmony_ci (*seqnum)++; 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/* 2098c2ecf20Sopenharmony_ci * This is what I got when bypassing the mixer with 2108c2ecf20Sopenharmony_ci * all channels split. I'm not 100% sure of what's going 2118c2ecf20Sopenharmony_ci * on, I could probably clean this up based on my observations 2128c2ecf20Sopenharmony_ci * but I prefer to keep the same behavior as the windows driver. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_cistatic int snd_s1810c_init_mixer_maps(struct snd_usb_audio *chip) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci u32 a, b, c, e, n, off; 2178c2ecf20Sopenharmony_ci struct usb_device *dev = chip->dev; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Set initial volume levels ? */ 2208c2ecf20Sopenharmony_ci a = 0x64; 2218c2ecf20Sopenharmony_ci e = 0xbc; 2228c2ecf20Sopenharmony_ci for (n = 0; n < 2; n++) { 2238c2ecf20Sopenharmony_ci off = n * 18; 2248c2ecf20Sopenharmony_ci for (b = off, c = 0; b < 18 + off; b++) { 2258c2ecf20Sopenharmony_ci /* This channel to all outputs ? */ 2268c2ecf20Sopenharmony_ci for (c = 0; c <= 8; c++) { 2278c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); 2288c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci /* This channel to main output (again) */ 2318c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e); 2328c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e); 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci /* 2358c2ecf20Sopenharmony_ci * I noticed on UC that DAW channels have different 2368c2ecf20Sopenharmony_ci * initial volumes, so this makes sense. 2378c2ecf20Sopenharmony_ci */ 2388c2ecf20Sopenharmony_ci e = 0xb53bf0; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* Connect analog outputs ? */ 2428c2ecf20Sopenharmony_ci a = 0x65; 2438c2ecf20Sopenharmony_ci e = 0x01000000; 2448c2ecf20Sopenharmony_ci for (b = 1; b < 3; b++) { 2458c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e); 2468c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, 0, 0, 0, e); 2498c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, 0, 0, 1, e); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* Set initial volume levels for S/PDIF mappings ? */ 2528c2ecf20Sopenharmony_ci a = 0x64; 2538c2ecf20Sopenharmony_ci e = 0xbc; 2548c2ecf20Sopenharmony_ci c = 3; 2558c2ecf20Sopenharmony_ci for (n = 0; n < 2; n++) { 2568c2ecf20Sopenharmony_ci off = n * 18; 2578c2ecf20Sopenharmony_ci for (b = off; b < 18 + off; b++) { 2588c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); 2598c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci e = 0xb53bf0; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* Connect S/PDIF output ? */ 2658c2ecf20Sopenharmony_ci a = 0x65; 2668c2ecf20Sopenharmony_ci e = 0x01000000; 2678c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e); 2688c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* Connect all outputs (again) ? */ 2718c2ecf20Sopenharmony_ci a = 0x65; 2728c2ecf20Sopenharmony_ci e = 0x01000000; 2738c2ecf20Sopenharmony_ci for (b = 0; b < 4; b++) { 2748c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, 0, 0, e); 2758c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, 0, 1, e); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Basic routing to get sound out of the device */ 2798c2ecf20Sopenharmony_ci a = 0x64; 2808c2ecf20Sopenharmony_ci e = 0x01000000; 2818c2ecf20Sopenharmony_ci for (c = 0; c < 4; c++) { 2828c2ecf20Sopenharmony_ci for (b = 0; b < 36; b++) { 2838c2ecf20Sopenharmony_ci if ((c == 0 && b == 18) || /* DAW1/2 -> Main */ 2848c2ecf20Sopenharmony_ci (c == 1 && b == 20) || /* DAW3/4 -> Line3/4 */ 2858c2ecf20Sopenharmony_ci (c == 2 && b == 22) || /* DAW4/5 -> Line5/6 */ 2868c2ecf20Sopenharmony_ci (c == 3 && b == 24)) { /* DAW5/6 -> S/PDIF */ 2878c2ecf20Sopenharmony_ci /* Left */ 2888c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); 2898c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0); 2908c2ecf20Sopenharmony_ci b++; 2918c2ecf20Sopenharmony_ci /* Right */ 2928c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0); 2938c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); 2948c2ecf20Sopenharmony_ci } else { 2958c2ecf20Sopenharmony_ci /* Leave the rest disconnected */ 2968c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, c, 0, 0); 2978c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, c, 1, 0); 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* Set initial volume levels for S/PDIF (again) ? */ 3038c2ecf20Sopenharmony_ci a = 0x64; 3048c2ecf20Sopenharmony_ci e = 0xbc; 3058c2ecf20Sopenharmony_ci c = 3; 3068c2ecf20Sopenharmony_ci for (n = 0; n < 2; n++) { 3078c2ecf20Sopenharmony_ci off = n * 18; 3088c2ecf20Sopenharmony_ci for (b = off; b < 18 + off; b++) { 3098c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, c, 0, e); 3108c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, b, c, 1, e); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci e = 0xb53bf0; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* Connect S/PDIF outputs (again) ? */ 3168c2ecf20Sopenharmony_ci a = 0x65; 3178c2ecf20Sopenharmony_ci e = 0x01000000; 3188c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e); 3198c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* Again ? */ 3228c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, 3, 0, 0, e); 3238c2ecf20Sopenharmony_ci snd_s1810c_send_ctl_packet(dev, a, 3, 0, 1, e); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci/* 3298c2ecf20Sopenharmony_ci * Sync state with the device and retrieve the requested field, 3308c2ecf20Sopenharmony_ci * whose index is specified in (kctl->private_value & 0xFF), 3318c2ecf20Sopenharmony_ci * from the received fields array. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_cistatic int 3348c2ecf20Sopenharmony_cisnd_s1810c_get_switch_state(struct usb_mixer_interface *mixer, 3358c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl, u32 *state) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci struct snd_usb_audio *chip = mixer->chip; 3388c2ecf20Sopenharmony_ci struct s1810_mixer_state *private = mixer->private_data; 3398c2ecf20Sopenharmony_ci u32 field = 0; 3408c2ecf20Sopenharmony_ci u32 ctl_idx = (u32) (kctl->private_value & 0xFF); 3418c2ecf20Sopenharmony_ci int ret = 0; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci mutex_lock(&private->usb_mutex); 3448c2ecf20Sopenharmony_ci ret = snd_sc1810c_get_status_field(chip->dev, &field, 3458c2ecf20Sopenharmony_ci ctl_idx, &private->seqnum); 3468c2ecf20Sopenharmony_ci if (ret < 0) 3478c2ecf20Sopenharmony_ci goto unlock; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci *state = field; 3508c2ecf20Sopenharmony_ci unlock: 3518c2ecf20Sopenharmony_ci mutex_unlock(&private->usb_mutex); 3528c2ecf20Sopenharmony_ci return ret ? ret : 0; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci/* 3568c2ecf20Sopenharmony_ci * Send a control packet to the device for the control id 3578c2ecf20Sopenharmony_ci * specified in (kctl->private_value >> 8) with value 3588c2ecf20Sopenharmony_ci * specified in (kctl->private_value >> 16). 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_cistatic int 3618c2ecf20Sopenharmony_cisnd_s1810c_set_switch_state(struct usb_mixer_interface *mixer, 3628c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct snd_usb_audio *chip = mixer->chip; 3658c2ecf20Sopenharmony_ci struct s1810_mixer_state *private = mixer->private_data; 3668c2ecf20Sopenharmony_ci u32 pval = (u32) kctl->private_value; 3678c2ecf20Sopenharmony_ci u32 ctl_id = (pval >> 8) & 0xFF; 3688c2ecf20Sopenharmony_ci u32 ctl_val = (pval >> 16) & 0x1; 3698c2ecf20Sopenharmony_ci int ret = 0; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci mutex_lock(&private->usb_mutex); 3728c2ecf20Sopenharmony_ci ret = snd_s1810c_send_ctl_packet(chip->dev, 0, 0, 0, ctl_id, ctl_val); 3738c2ecf20Sopenharmony_ci mutex_unlock(&private->usb_mutex); 3748c2ecf20Sopenharmony_ci return ret; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci/* Generic get/set/init functions for switch controls */ 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int 3808c2ecf20Sopenharmony_cisnd_s1810c_switch_get(struct snd_kcontrol *kctl, 3818c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ctl_elem) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); 3848c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = list->mixer; 3858c2ecf20Sopenharmony_ci struct s1810_mixer_state *private = mixer->private_data; 3868c2ecf20Sopenharmony_ci u32 pval = (u32) kctl->private_value; 3878c2ecf20Sopenharmony_ci u32 ctl_idx = pval & 0xFF; 3888c2ecf20Sopenharmony_ci u32 state = 0; 3898c2ecf20Sopenharmony_ci int ret = 0; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci mutex_lock(&private->data_mutex); 3928c2ecf20Sopenharmony_ci ret = snd_s1810c_get_switch_state(mixer, kctl, &state); 3938c2ecf20Sopenharmony_ci if (ret < 0) 3948c2ecf20Sopenharmony_ci goto unlock; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci switch (ctl_idx) { 3978c2ecf20Sopenharmony_ci case SC1810C_STATE_LINE_SW: 3988c2ecf20Sopenharmony_ci case SC1810C_STATE_AB_SW: 3998c2ecf20Sopenharmony_ci ctl_elem->value.enumerated.item[0] = (int)state; 4008c2ecf20Sopenharmony_ci break; 4018c2ecf20Sopenharmony_ci default: 4028c2ecf20Sopenharmony_ci ctl_elem->value.integer.value[0] = (long)state; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci unlock: 4068c2ecf20Sopenharmony_ci mutex_unlock(&private->data_mutex); 4078c2ecf20Sopenharmony_ci return (ret < 0) ? ret : 0; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic int 4118c2ecf20Sopenharmony_cisnd_s1810c_switch_set(struct snd_kcontrol *kctl, 4128c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ctl_elem) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); 4158c2ecf20Sopenharmony_ci struct usb_mixer_interface *mixer = list->mixer; 4168c2ecf20Sopenharmony_ci struct s1810_mixer_state *private = mixer->private_data; 4178c2ecf20Sopenharmony_ci u32 pval = (u32) kctl->private_value; 4188c2ecf20Sopenharmony_ci u32 ctl_idx = pval & 0xFF; 4198c2ecf20Sopenharmony_ci u32 curval = 0; 4208c2ecf20Sopenharmony_ci u32 newval = 0; 4218c2ecf20Sopenharmony_ci int ret = 0; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci mutex_lock(&private->data_mutex); 4248c2ecf20Sopenharmony_ci ret = snd_s1810c_get_switch_state(mixer, kctl, &curval); 4258c2ecf20Sopenharmony_ci if (ret < 0) 4268c2ecf20Sopenharmony_ci goto unlock; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci switch (ctl_idx) { 4298c2ecf20Sopenharmony_ci case SC1810C_STATE_LINE_SW: 4308c2ecf20Sopenharmony_ci case SC1810C_STATE_AB_SW: 4318c2ecf20Sopenharmony_ci newval = (u32) ctl_elem->value.enumerated.item[0]; 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci default: 4348c2ecf20Sopenharmony_ci newval = (u32) ctl_elem->value.integer.value[0]; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (curval == newval) 4388c2ecf20Sopenharmony_ci goto unlock; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci kctl->private_value &= ~(0x1 << 16); 4418c2ecf20Sopenharmony_ci kctl->private_value |= (unsigned int)(newval & 0x1) << 16; 4428c2ecf20Sopenharmony_ci ret = snd_s1810c_set_switch_state(mixer, kctl); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci unlock: 4458c2ecf20Sopenharmony_ci mutex_unlock(&private->data_mutex); 4468c2ecf20Sopenharmony_ci return (ret < 0) ? 0 : 1; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int 4508c2ecf20Sopenharmony_cisnd_s1810c_switch_init(struct usb_mixer_interface *mixer, 4518c2ecf20Sopenharmony_ci const struct snd_kcontrol_new *new_kctl) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl; 4548c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci elem = kzalloc(sizeof(struct usb_mixer_elem_info), GFP_KERNEL); 4578c2ecf20Sopenharmony_ci if (!elem) 4588c2ecf20Sopenharmony_ci return -ENOMEM; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci elem->head.mixer = mixer; 4618c2ecf20Sopenharmony_ci elem->control = 0; 4628c2ecf20Sopenharmony_ci elem->head.id = 0; 4638c2ecf20Sopenharmony_ci elem->channels = 1; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci kctl = snd_ctl_new1(new_kctl, elem); 4668c2ecf20Sopenharmony_ci if (!kctl) { 4678c2ecf20Sopenharmony_ci kfree(elem); 4688c2ecf20Sopenharmony_ci return -ENOMEM; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci kctl->private_free = snd_usb_mixer_elem_free; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return snd_usb_mixer_add_control(&elem->head, kctl); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int 4768c2ecf20Sopenharmony_cisnd_s1810c_line_sw_info(struct snd_kcontrol *kctl, 4778c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci static const char *const texts[2] = { 4808c2ecf20Sopenharmony_ci "Preamp On (Mic/Inst)", 4818c2ecf20Sopenharmony_ci "Preamp Off (Line in)" 4828c2ecf20Sopenharmony_ci }; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_s1810c_line_sw = { 4888c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4898c2ecf20Sopenharmony_ci .name = "Line 1/2 Source Type", 4908c2ecf20Sopenharmony_ci .info = snd_s1810c_line_sw_info, 4918c2ecf20Sopenharmony_ci .get = snd_s1810c_switch_get, 4928c2ecf20Sopenharmony_ci .put = snd_s1810c_switch_set, 4938c2ecf20Sopenharmony_ci .private_value = (SC1810C_STATE_LINE_SW | SC1810C_CTL_LINE_SW << 8) 4948c2ecf20Sopenharmony_ci}; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_s1810c_mute_sw = { 4978c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4988c2ecf20Sopenharmony_ci .name = "Mute Main Out Switch", 4998c2ecf20Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 5008c2ecf20Sopenharmony_ci .get = snd_s1810c_switch_get, 5018c2ecf20Sopenharmony_ci .put = snd_s1810c_switch_set, 5028c2ecf20Sopenharmony_ci .private_value = (SC1810C_STATE_MUTE_SW | SC1810C_CTL_MUTE_SW << 8) 5038c2ecf20Sopenharmony_ci}; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_s1810c_48v_sw = { 5068c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5078c2ecf20Sopenharmony_ci .name = "48V Phantom Power On Mic Inputs Switch", 5088c2ecf20Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 5098c2ecf20Sopenharmony_ci .get = snd_s1810c_switch_get, 5108c2ecf20Sopenharmony_ci .put = snd_s1810c_switch_set, 5118c2ecf20Sopenharmony_ci .private_value = (SC1810C_STATE_48V_SW | SC1810C_CTL_48V_SW << 8) 5128c2ecf20Sopenharmony_ci}; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic int 5158c2ecf20Sopenharmony_cisnd_s1810c_ab_sw_info(struct snd_kcontrol *kctl, 5168c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci static const char *const texts[2] = { 5198c2ecf20Sopenharmony_ci "1/2", 5208c2ecf20Sopenharmony_ci "3/4" 5218c2ecf20Sopenharmony_ci }; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_s1810c_ab_sw = { 5278c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5288c2ecf20Sopenharmony_ci .name = "Headphone 1 Source Route", 5298c2ecf20Sopenharmony_ci .info = snd_s1810c_ab_sw_info, 5308c2ecf20Sopenharmony_ci .get = snd_s1810c_switch_get, 5318c2ecf20Sopenharmony_ci .put = snd_s1810c_switch_set, 5328c2ecf20Sopenharmony_ci .private_value = (SC1810C_STATE_AB_SW | SC1810C_CTL_AB_SW << 8) 5338c2ecf20Sopenharmony_ci}; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic void snd_sc1810_mixer_state_free(struct usb_mixer_interface *mixer) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci struct s1810_mixer_state *private = mixer->private_data; 5388c2ecf20Sopenharmony_ci kfree(private); 5398c2ecf20Sopenharmony_ci mixer->private_data = NULL; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci/* Entry point, called from mixer_quirks.c */ 5438c2ecf20Sopenharmony_ciint snd_sc1810_init_mixer(struct usb_mixer_interface *mixer) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct s1810_mixer_state *private = NULL; 5468c2ecf20Sopenharmony_ci struct snd_usb_audio *chip = mixer->chip; 5478c2ecf20Sopenharmony_ci struct usb_device *dev = chip->dev; 5488c2ecf20Sopenharmony_ci int ret = 0; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* Run this only once */ 5518c2ecf20Sopenharmony_ci if (!list_empty(&chip->mixer_list)) 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci dev_info(&dev->dev, 5558c2ecf20Sopenharmony_ci "Presonus Studio 1810c, device_setup: %u\n", chip->setup); 5568c2ecf20Sopenharmony_ci if (chip->setup == 1) 5578c2ecf20Sopenharmony_ci dev_info(&dev->dev, "(8out/18in @ 48kHz)\n"); 5588c2ecf20Sopenharmony_ci else if (chip->setup == 2) 5598c2ecf20Sopenharmony_ci dev_info(&dev->dev, "(6out/8in @ 192kHz)\n"); 5608c2ecf20Sopenharmony_ci else 5618c2ecf20Sopenharmony_ci dev_info(&dev->dev, "(8out/14in @ 96kHz)\n"); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci ret = snd_s1810c_init_mixer_maps(chip); 5648c2ecf20Sopenharmony_ci if (ret < 0) 5658c2ecf20Sopenharmony_ci return ret; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci private = kzalloc(sizeof(struct s1810_mixer_state), GFP_KERNEL); 5688c2ecf20Sopenharmony_ci if (!private) 5698c2ecf20Sopenharmony_ci return -ENOMEM; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci mutex_init(&private->usb_mutex); 5728c2ecf20Sopenharmony_ci mutex_init(&private->data_mutex); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci mixer->private_data = private; 5758c2ecf20Sopenharmony_ci mixer->private_free = snd_sc1810_mixer_state_free; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci private->seqnum = 1; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci ret = snd_s1810c_switch_init(mixer, &snd_s1810c_line_sw); 5808c2ecf20Sopenharmony_ci if (ret < 0) 5818c2ecf20Sopenharmony_ci return ret; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci ret = snd_s1810c_switch_init(mixer, &snd_s1810c_mute_sw); 5848c2ecf20Sopenharmony_ci if (ret < 0) 5858c2ecf20Sopenharmony_ci return ret; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci ret = snd_s1810c_switch_init(mixer, &snd_s1810c_48v_sw); 5888c2ecf20Sopenharmony_ci if (ret < 0) 5898c2ecf20Sopenharmony_ci return ret; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci ret = snd_s1810c_switch_init(mixer, &snd_s1810c_ab_sw); 5928c2ecf20Sopenharmony_ci if (ret < 0) 5938c2ecf20Sopenharmony_ci return ret; 5948c2ecf20Sopenharmony_ci return ret; 5958c2ecf20Sopenharmony_ci} 596