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