18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *   Tascam US-16x08 ALSA driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *   Copyright (c) 2016 by Detlef Urban (onkel@paraair.de)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/slab.h>
98c2ecf20Sopenharmony_ci#include <linux/usb.h>
108c2ecf20Sopenharmony_ci#include <linux/usb/audio-v2.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <sound/core.h>
138c2ecf20Sopenharmony_ci#include <sound/control.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "usbaudio.h"
168c2ecf20Sopenharmony_ci#include "mixer.h"
178c2ecf20Sopenharmony_ci#include "helper.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "mixer_us16x08.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* USB control message templates */
228c2ecf20Sopenharmony_cistatic const char route_msg[] = {
238c2ecf20Sopenharmony_ci	0x61,
248c2ecf20Sopenharmony_ci	0x02,
258c2ecf20Sopenharmony_ci	0x03, /* input from master (0x02) or input from computer bus (0x03) */
268c2ecf20Sopenharmony_ci	0x62,
278c2ecf20Sopenharmony_ci	0x02,
288c2ecf20Sopenharmony_ci	0x01, /* input index (0x01/0x02 eq. left/right) or bus (0x01-0x08) */
298c2ecf20Sopenharmony_ci	0x41,
308c2ecf20Sopenharmony_ci	0x01,
318c2ecf20Sopenharmony_ci	0x61,
328c2ecf20Sopenharmony_ci	0x02,
338c2ecf20Sopenharmony_ci	0x01,
348c2ecf20Sopenharmony_ci	0x62,
358c2ecf20Sopenharmony_ci	0x02,
368c2ecf20Sopenharmony_ci	0x01, /* output index (0x01-0x08) */
378c2ecf20Sopenharmony_ci	0x42,
388c2ecf20Sopenharmony_ci	0x01,
398c2ecf20Sopenharmony_ci	0x43,
408c2ecf20Sopenharmony_ci	0x01,
418c2ecf20Sopenharmony_ci	0x00,
428c2ecf20Sopenharmony_ci	0x00
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic const char mix_init_msg1[] = {
468c2ecf20Sopenharmony_ci	0x71, 0x01, 0x00, 0x00
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic const char mix_init_msg2[] = {
508c2ecf20Sopenharmony_ci	0x62, 0x02, 0x00, 0x61, 0x02, 0x04, 0xb1, 0x01, 0x00, 0x00
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic const char mix_msg_in[] = {
548c2ecf20Sopenharmony_ci	/* default message head, equal to all mixers */
558c2ecf20Sopenharmony_ci	0x61, 0x02, 0x04, 0x62, 0x02, 0x01,
568c2ecf20Sopenharmony_ci	0x81, /* 0x06: Controller ID */
578c2ecf20Sopenharmony_ci	0x02, /* 0x07:  */
588c2ecf20Sopenharmony_ci	0x00, /* 0x08: Value of common mixer */
598c2ecf20Sopenharmony_ci	0x00,
608c2ecf20Sopenharmony_ci	0x00
618c2ecf20Sopenharmony_ci};
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic const char mix_msg_out[] = {
648c2ecf20Sopenharmony_ci	/* default message head, equal to all mixers */
658c2ecf20Sopenharmony_ci	0x61, 0x02, 0x02, 0x62, 0x02, 0x01,
668c2ecf20Sopenharmony_ci	0x81, /* 0x06: Controller ID */
678c2ecf20Sopenharmony_ci	0x02, /*                    0x07:  */
688c2ecf20Sopenharmony_ci	0x00, /*                    0x08: Value of common mixer */
698c2ecf20Sopenharmony_ci	0x00,
708c2ecf20Sopenharmony_ci	0x00
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic const char bypass_msg_out[] = {
748c2ecf20Sopenharmony_ci	0x45,
758c2ecf20Sopenharmony_ci	0x02,
768c2ecf20Sopenharmony_ci	0x01, /* on/off flag */
778c2ecf20Sopenharmony_ci	0x00,
788c2ecf20Sopenharmony_ci	0x00
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic const char bus_msg_out[] = {
828c2ecf20Sopenharmony_ci	0x44,
838c2ecf20Sopenharmony_ci	0x02,
848c2ecf20Sopenharmony_ci	0x01, /* on/off flag */
858c2ecf20Sopenharmony_ci	0x00,
868c2ecf20Sopenharmony_ci	0x00
878c2ecf20Sopenharmony_ci};
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic const char comp_msg[] = {
908c2ecf20Sopenharmony_ci	/* default message head, equal to all mixers */
918c2ecf20Sopenharmony_ci	0x61, 0x02, 0x04, 0x62, 0x02, 0x01,
928c2ecf20Sopenharmony_ci	0x91,
938c2ecf20Sopenharmony_ci	0x02,
948c2ecf20Sopenharmony_ci	0xf0, /* 0x08: Threshold db (8) (e0 ... 00) (+-0dB -- -32dB) x-32 */
958c2ecf20Sopenharmony_ci	0x92,
968c2ecf20Sopenharmony_ci	0x02,
978c2ecf20Sopenharmony_ci	0x0a, /* 0x0b: Ratio (0a,0b,0d,0f,11,14,19,1e,23,28,32,3c,50,a0,ff)  */
988c2ecf20Sopenharmony_ci	0x93,
998c2ecf20Sopenharmony_ci	0x02,
1008c2ecf20Sopenharmony_ci	0x02, /* 0x0e: Attack (0x02 ... 0xc0) (2ms ... 200ms) */
1018c2ecf20Sopenharmony_ci	0x94,
1028c2ecf20Sopenharmony_ci	0x02,
1038c2ecf20Sopenharmony_ci	0x01, /* 0x11: Release (0x01 ... 0x64) (10ms ... 1000ms) x*10  */
1048c2ecf20Sopenharmony_ci	0x95,
1058c2ecf20Sopenharmony_ci	0x02,
1068c2ecf20Sopenharmony_ci	0x03, /* 0x14: gain (0 ... 20) (0dB .. 20dB) */
1078c2ecf20Sopenharmony_ci	0x96,
1088c2ecf20Sopenharmony_ci	0x02,
1098c2ecf20Sopenharmony_ci	0x01,
1108c2ecf20Sopenharmony_ci	0x97,
1118c2ecf20Sopenharmony_ci	0x02,
1128c2ecf20Sopenharmony_ci	0x01, /* 0x1a: main Comp switch (0 ... 1) (off ... on)) */
1138c2ecf20Sopenharmony_ci	0x00,
1148c2ecf20Sopenharmony_ci	0x00
1158c2ecf20Sopenharmony_ci};
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic const char eqs_msq[] = {
1188c2ecf20Sopenharmony_ci	/* default message head, equal to all mixers */
1198c2ecf20Sopenharmony_ci	0x61, 0x02, 0x04, 0x62, 0x02, 0x01,
1208c2ecf20Sopenharmony_ci	0x51, /*                0x06: Controller ID  */
1218c2ecf20Sopenharmony_ci	0x02,
1228c2ecf20Sopenharmony_ci	0x04, /* 0x08: EQ set num (0x01..0x04) (LOW, LOWMID, HIGHMID, HIGH)) */
1238c2ecf20Sopenharmony_ci	0x52,
1248c2ecf20Sopenharmony_ci	0x02,
1258c2ecf20Sopenharmony_ci	0x0c, /* 0x0b: value dB (0 ... 12) (-12db .. +12db)  x-6 */
1268c2ecf20Sopenharmony_ci	0x53,
1278c2ecf20Sopenharmony_ci	0x02,
1288c2ecf20Sopenharmony_ci	0x0f, /* 0x0e: value freq (32-47) (1.7kHz..18kHz) */
1298c2ecf20Sopenharmony_ci	0x54,
1308c2ecf20Sopenharmony_ci	0x02,
1318c2ecf20Sopenharmony_ci	0x02, /* 0x11: band width (0-6) (Q16-Q0.25)  2^x/4 (EQ xxMID only) */
1328c2ecf20Sopenharmony_ci	0x55,
1338c2ecf20Sopenharmony_ci	0x02,
1348c2ecf20Sopenharmony_ci	0x01, /* 0x14: main EQ switch (0 ... 1) (off ... on)) */
1358c2ecf20Sopenharmony_ci	0x00,
1368c2ecf20Sopenharmony_ci	0x00
1378c2ecf20Sopenharmony_ci};
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci/* compressor ratio map */
1408c2ecf20Sopenharmony_cistatic const char ratio_map[] = {
1418c2ecf20Sopenharmony_ci	0x0a, 0x0b, 0x0d, 0x0f, 0x11, 0x14, 0x19, 0x1e,
1428c2ecf20Sopenharmony_ci	0x23, 0x28, 0x32, 0x3c, 0x50, 0xa0, 0xff
1438c2ecf20Sopenharmony_ci};
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/* route enumeration names */
1468c2ecf20Sopenharmony_cistatic const char *const route_names[] = {
1478c2ecf20Sopenharmony_ci	"Master Left", "Master Right", "Output 1", "Output 2", "Output 3",
1488c2ecf20Sopenharmony_ci	"Output 4", "Output 5", "Output 6", "Output 7", "Output 8",
1498c2ecf20Sopenharmony_ci};
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic int snd_us16x08_recv_urb(struct snd_usb_audio *chip,
1528c2ecf20Sopenharmony_ci	unsigned char *buf, int size)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
1568c2ecf20Sopenharmony_ci	snd_usb_ctl_msg(chip->dev,
1578c2ecf20Sopenharmony_ci		usb_rcvctrlpipe(chip->dev, 0),
1588c2ecf20Sopenharmony_ci		SND_US16X08_URB_METER_REQUEST,
1598c2ecf20Sopenharmony_ci		SND_US16X08_URB_METER_REQUESTTYPE, 0, 0, buf, size);
1608c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
1618c2ecf20Sopenharmony_ci	return 0;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/* wrapper function to send prepared URB buffer to usb device. Return an error
1658c2ecf20Sopenharmony_ci * code if something went wrong
1668c2ecf20Sopenharmony_ci */
1678c2ecf20Sopenharmony_cistatic int snd_us16x08_send_urb(struct snd_usb_audio *chip, char *buf, int size)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	return snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
1708c2ecf20Sopenharmony_ci			SND_US16X08_URB_REQUEST, SND_US16X08_URB_REQUESTTYPE,
1718c2ecf20Sopenharmony_ci			0, 0, buf, size);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int snd_us16x08_route_info(struct snd_kcontrol *kcontrol,
1758c2ecf20Sopenharmony_ci	struct snd_ctl_elem_info *uinfo)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 10, route_names);
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic int snd_us16x08_route_get(struct snd_kcontrol *kcontrol,
1818c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
1848c2ecf20Sopenharmony_ci	int index = ucontrol->id.index;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* route has no bias */
1878c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = elem->cache_val[index];
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	return 0;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic int snd_us16x08_route_put(struct snd_kcontrol *kcontrol,
1938c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
1968c2ecf20Sopenharmony_ci	struct snd_usb_audio *chip = elem->head.mixer->chip;
1978c2ecf20Sopenharmony_ci	int index = ucontrol->id.index;
1988c2ecf20Sopenharmony_ci	char buf[sizeof(route_msg)];
1998c2ecf20Sopenharmony_ci	int val, val_org, err;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/*  get the new value (no bias for routes) */
2028c2ecf20Sopenharmony_ci	val = ucontrol->value.enumerated.item[0];
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/* sanity check */
2058c2ecf20Sopenharmony_ci	if (val < 0 || val > 9)
2068c2ecf20Sopenharmony_ci		return -EINVAL;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* prepare the message buffer from template */
2098c2ecf20Sopenharmony_ci	memcpy(buf, route_msg, sizeof(route_msg));
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (val < 2) {
2128c2ecf20Sopenharmony_ci		/* input comes from a master channel */
2138c2ecf20Sopenharmony_ci		val_org = val;
2148c2ecf20Sopenharmony_ci		buf[2] = 0x02;
2158c2ecf20Sopenharmony_ci	} else {
2168c2ecf20Sopenharmony_ci		/* input comes from a computer channel */
2178c2ecf20Sopenharmony_ci		buf[2] = 0x03;
2188c2ecf20Sopenharmony_ci		val_org = val - 2;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	/* place new route selection in URB message */
2228c2ecf20Sopenharmony_ci	buf[5] = (unsigned char) (val_org & 0x0f) + 1;
2238c2ecf20Sopenharmony_ci	/* place route selector in URB message */
2248c2ecf20Sopenharmony_ci	buf[13] = index + 1;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	err = snd_us16x08_send_urb(chip, buf, sizeof(route_msg));
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (err > 0) {
2298c2ecf20Sopenharmony_ci		elem->cached |= 1 << index;
2308c2ecf20Sopenharmony_ci		elem->cache_val[index] = val;
2318c2ecf20Sopenharmony_ci	} else {
2328c2ecf20Sopenharmony_ci		usb_audio_dbg(chip, "Failed to set routing, err:%d\n", err);
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	return err > 0 ? 1 : 0;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic int snd_us16x08_master_info(struct snd_kcontrol *kcontrol,
2398c2ecf20Sopenharmony_ci	struct snd_ctl_elem_info *uinfo)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	uinfo->count = 1;
2428c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2438c2ecf20Sopenharmony_ci	uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol);
2448c2ecf20Sopenharmony_ci	uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol);
2458c2ecf20Sopenharmony_ci	uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol);
2468c2ecf20Sopenharmony_ci	return 0;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic int snd_us16x08_master_get(struct snd_kcontrol *kcontrol,
2508c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
2538c2ecf20Sopenharmony_ci	int index = ucontrol->id.index;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = elem->cache_val[index];
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return 0;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic int snd_us16x08_master_put(struct snd_kcontrol *kcontrol,
2618c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
2648c2ecf20Sopenharmony_ci	struct snd_usb_audio *chip = elem->head.mixer->chip;
2658c2ecf20Sopenharmony_ci	char buf[sizeof(mix_msg_out)];
2668c2ecf20Sopenharmony_ci	int val, err;
2678c2ecf20Sopenharmony_ci	int index = ucontrol->id.index;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	/* new control value incl. bias*/
2708c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0];
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	/* sanity check */
2738c2ecf20Sopenharmony_ci	if (val < SND_US16X08_KCMIN(kcontrol)
2748c2ecf20Sopenharmony_ci		|| val > SND_US16X08_KCMAX(kcontrol))
2758c2ecf20Sopenharmony_ci		return -EINVAL;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/* prepare the message buffer from template */
2788c2ecf20Sopenharmony_ci	memcpy(buf, mix_msg_out, sizeof(mix_msg_out));
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	buf[8] = val - SND_US16X08_KCBIAS(kcontrol);
2818c2ecf20Sopenharmony_ci	buf[6] = elem->head.id;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	/* place channel selector in URB message */
2848c2ecf20Sopenharmony_ci	buf[5] = index + 1;
2858c2ecf20Sopenharmony_ci	err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_out));
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (err > 0) {
2888c2ecf20Sopenharmony_ci		elem->cached |= 1 << index;
2898c2ecf20Sopenharmony_ci		elem->cache_val[index] = val;
2908c2ecf20Sopenharmony_ci	} else {
2918c2ecf20Sopenharmony_ci		usb_audio_dbg(chip, "Failed to set master, err:%d\n", err);
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	return err > 0 ? 1 : 0;
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic int snd_us16x08_bus_put(struct snd_kcontrol *kcontrol,
2988c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
3018c2ecf20Sopenharmony_ci	struct snd_usb_audio *chip = elem->head.mixer->chip;
3028c2ecf20Sopenharmony_ci	char buf[sizeof(mix_msg_out)];
3038c2ecf20Sopenharmony_ci	int val, err = 0;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0];
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	/* prepare the message buffer from template */
3088c2ecf20Sopenharmony_ci	switch (elem->head.id) {
3098c2ecf20Sopenharmony_ci	case SND_US16X08_ID_BYPASS:
3108c2ecf20Sopenharmony_ci		memcpy(buf, bypass_msg_out, sizeof(bypass_msg_out));
3118c2ecf20Sopenharmony_ci		buf[2] = val;
3128c2ecf20Sopenharmony_ci		err = snd_us16x08_send_urb(chip, buf, sizeof(bypass_msg_out));
3138c2ecf20Sopenharmony_ci		break;
3148c2ecf20Sopenharmony_ci	case SND_US16X08_ID_BUSS_OUT:
3158c2ecf20Sopenharmony_ci		memcpy(buf, bus_msg_out, sizeof(bus_msg_out));
3168c2ecf20Sopenharmony_ci		buf[2] = val;
3178c2ecf20Sopenharmony_ci		err = snd_us16x08_send_urb(chip, buf, sizeof(bus_msg_out));
3188c2ecf20Sopenharmony_ci		break;
3198c2ecf20Sopenharmony_ci	case SND_US16X08_ID_MUTE:
3208c2ecf20Sopenharmony_ci		memcpy(buf, mix_msg_out, sizeof(mix_msg_out));
3218c2ecf20Sopenharmony_ci		buf[8] = val;
3228c2ecf20Sopenharmony_ci		buf[6] = elem->head.id;
3238c2ecf20Sopenharmony_ci		buf[5] = 1;
3248c2ecf20Sopenharmony_ci		err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_out));
3258c2ecf20Sopenharmony_ci		break;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (err > 0) {
3298c2ecf20Sopenharmony_ci		elem->cached |= 1;
3308c2ecf20Sopenharmony_ci		elem->cache_val[0] = val;
3318c2ecf20Sopenharmony_ci	} else {
3328c2ecf20Sopenharmony_ci		usb_audio_dbg(chip, "Failed to set bus parameter, err:%d\n", err);
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	return err > 0 ? 1 : 0;
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic int snd_us16x08_bus_get(struct snd_kcontrol *kcontrol,
3398c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	switch (elem->head.id) {
3448c2ecf20Sopenharmony_ci	case SND_US16X08_ID_BUSS_OUT:
3458c2ecf20Sopenharmony_ci		ucontrol->value.integer.value[0] = elem->cache_val[0];
3468c2ecf20Sopenharmony_ci		break;
3478c2ecf20Sopenharmony_ci	case SND_US16X08_ID_BYPASS:
3488c2ecf20Sopenharmony_ci		ucontrol->value.integer.value[0] = elem->cache_val[0];
3498c2ecf20Sopenharmony_ci		break;
3508c2ecf20Sopenharmony_ci	case SND_US16X08_ID_MUTE:
3518c2ecf20Sopenharmony_ci		ucontrol->value.integer.value[0] = elem->cache_val[0];
3528c2ecf20Sopenharmony_ci		break;
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	return 0;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci/* gets a current mixer value from common store */
3598c2ecf20Sopenharmony_cistatic int snd_us16x08_channel_get(struct snd_kcontrol *kcontrol,
3608c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
3638c2ecf20Sopenharmony_ci	int index = ucontrol->id.index;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = elem->cache_val[index];
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	return 0;
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic int snd_us16x08_channel_put(struct snd_kcontrol *kcontrol,
3718c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
3748c2ecf20Sopenharmony_ci	struct snd_usb_audio *chip = elem->head.mixer->chip;
3758c2ecf20Sopenharmony_ci	char buf[sizeof(mix_msg_in)];
3768c2ecf20Sopenharmony_ci	int val, err;
3778c2ecf20Sopenharmony_ci	int index = ucontrol->id.index;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0];
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	/* sanity check */
3828c2ecf20Sopenharmony_ci	if (val < SND_US16X08_KCMIN(kcontrol)
3838c2ecf20Sopenharmony_ci		|| val > SND_US16X08_KCMAX(kcontrol))
3848c2ecf20Sopenharmony_ci		return -EINVAL;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	/* prepare URB message from template */
3878c2ecf20Sopenharmony_ci	memcpy(buf, mix_msg_in, sizeof(mix_msg_in));
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	/* add the bias to the new value */
3908c2ecf20Sopenharmony_ci	buf[8] = val - SND_US16X08_KCBIAS(kcontrol);
3918c2ecf20Sopenharmony_ci	buf[6] = elem->head.id;
3928c2ecf20Sopenharmony_ci	buf[5] = index + 1;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_in));
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (err > 0) {
3978c2ecf20Sopenharmony_ci		elem->cached |= 1 << index;
3988c2ecf20Sopenharmony_ci		elem->cache_val[index] = val;
3998c2ecf20Sopenharmony_ci	} else {
4008c2ecf20Sopenharmony_ci		usb_audio_dbg(chip, "Failed to set channel, err:%d\n", err);
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	return err > 0 ? 1 : 0;
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic int snd_us16x08_mix_info(struct snd_kcontrol *kcontrol,
4078c2ecf20Sopenharmony_ci	struct snd_ctl_elem_info *uinfo)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	uinfo->count = 1;
4108c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
4118c2ecf20Sopenharmony_ci	uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol);
4128c2ecf20Sopenharmony_ci	uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol);
4138c2ecf20Sopenharmony_ci	uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol);
4148c2ecf20Sopenharmony_ci	return 0;
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cistatic int snd_us16x08_comp_get(struct snd_kcontrol *kcontrol,
4188c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
4218c2ecf20Sopenharmony_ci	struct snd_us16x08_comp_store *store = elem->private_data;
4228c2ecf20Sopenharmony_ci	int index = ucontrol->id.index;
4238c2ecf20Sopenharmony_ci	int val_idx = COMP_STORE_IDX(elem->head.id);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = store->val[val_idx][index];
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	return 0;
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic int snd_us16x08_comp_put(struct snd_kcontrol *kcontrol,
4318c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
4348c2ecf20Sopenharmony_ci	struct snd_usb_audio *chip = elem->head.mixer->chip;
4358c2ecf20Sopenharmony_ci	struct snd_us16x08_comp_store *store = elem->private_data;
4368c2ecf20Sopenharmony_ci	int index = ucontrol->id.index;
4378c2ecf20Sopenharmony_ci	char buf[sizeof(comp_msg)];
4388c2ecf20Sopenharmony_ci	int val_idx, val;
4398c2ecf20Sopenharmony_ci	int err;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0];
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	/* sanity check */
4448c2ecf20Sopenharmony_ci	if (val < SND_US16X08_KCMIN(kcontrol)
4458c2ecf20Sopenharmony_ci		|| val > SND_US16X08_KCMAX(kcontrol))
4468c2ecf20Sopenharmony_ci		return -EINVAL;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	/* new control value incl. bias*/
4498c2ecf20Sopenharmony_ci	val_idx = elem->head.id - SND_US16X08_ID_COMP_BASE;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	store->val[val_idx][index] = ucontrol->value.integer.value[0];
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* prepare compressor URB message from template  */
4548c2ecf20Sopenharmony_ci	memcpy(buf, comp_msg, sizeof(comp_msg));
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/* place comp values in message buffer watch bias! */
4578c2ecf20Sopenharmony_ci	buf[8] = store->val[
4588c2ecf20Sopenharmony_ci		COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD)][index]
4598c2ecf20Sopenharmony_ci		- SND_US16X08_COMP_THRESHOLD_BIAS;
4608c2ecf20Sopenharmony_ci	buf[11] = ratio_map[store->val[
4618c2ecf20Sopenharmony_ci		COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO)][index]];
4628c2ecf20Sopenharmony_ci	buf[14] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK)][index]
4638c2ecf20Sopenharmony_ci		+ SND_US16X08_COMP_ATTACK_BIAS;
4648c2ecf20Sopenharmony_ci	buf[17] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE)][index]
4658c2ecf20Sopenharmony_ci		+ SND_US16X08_COMP_RELEASE_BIAS;
4668c2ecf20Sopenharmony_ci	buf[20] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN)][index];
4678c2ecf20Sopenharmony_ci	buf[26] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)][index];
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	/* place channel selector in message buffer */
4708c2ecf20Sopenharmony_ci	buf[5] = index + 1;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	err = snd_us16x08_send_urb(chip, buf, sizeof(comp_msg));
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if (err > 0) {
4758c2ecf20Sopenharmony_ci		elem->cached |= 1 << index;
4768c2ecf20Sopenharmony_ci		elem->cache_val[index] = val;
4778c2ecf20Sopenharmony_ci	} else {
4788c2ecf20Sopenharmony_ci		usb_audio_dbg(chip, "Failed to set compressor, err:%d\n", err);
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	return 1;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic int snd_us16x08_eqswitch_get(struct snd_kcontrol *kcontrol,
4858c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	int val;
4888c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
4898c2ecf20Sopenharmony_ci	struct snd_us16x08_eq_store *store = elem->private_data;
4908c2ecf20Sopenharmony_ci	int index = ucontrol->id.index;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	/* get low switch from cache is enough, cause all bands are together */
4938c2ecf20Sopenharmony_ci	val = store->val[EQ_STORE_BAND_IDX(elem->head.id)]
4948c2ecf20Sopenharmony_ci		[EQ_STORE_PARAM_IDX(elem->head.id)][index];
4958c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = val;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	return 0;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic int snd_us16x08_eqswitch_put(struct snd_kcontrol *kcontrol,
5018c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
5048c2ecf20Sopenharmony_ci	struct snd_usb_audio *chip = elem->head.mixer->chip;
5058c2ecf20Sopenharmony_ci	struct snd_us16x08_eq_store *store = elem->private_data;
5068c2ecf20Sopenharmony_ci	int index = ucontrol->id.index;
5078c2ecf20Sopenharmony_ci	char buf[sizeof(eqs_msq)];
5088c2ecf20Sopenharmony_ci	int val, err = 0;
5098c2ecf20Sopenharmony_ci	int b_idx;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	/* new control value incl. bias*/
5128c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0] + SND_US16X08_KCBIAS(kcontrol);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	/* prepare URB message from EQ template */
5158c2ecf20Sopenharmony_ci	memcpy(buf, eqs_msq, sizeof(eqs_msq));
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/* place channel index in URB message */
5188c2ecf20Sopenharmony_ci	buf[5] = index + 1;
5198c2ecf20Sopenharmony_ci	for (b_idx = 0; b_idx < SND_US16X08_ID_EQ_BAND_COUNT; b_idx++) {
5208c2ecf20Sopenharmony_ci		/* all four EQ bands have to be enabled/disabled in once */
5218c2ecf20Sopenharmony_ci		buf[20] = val;
5228c2ecf20Sopenharmony_ci		buf[17] = store->val[b_idx][2][index];
5238c2ecf20Sopenharmony_ci		buf[14] = store->val[b_idx][1][index];
5248c2ecf20Sopenharmony_ci		buf[11] = store->val[b_idx][0][index];
5258c2ecf20Sopenharmony_ci		buf[8] = b_idx + 1;
5268c2ecf20Sopenharmony_ci		err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
5278c2ecf20Sopenharmony_ci		if (err < 0)
5288c2ecf20Sopenharmony_ci			break;
5298c2ecf20Sopenharmony_ci		store->val[b_idx][3][index] = val;
5308c2ecf20Sopenharmony_ci		msleep(15);
5318c2ecf20Sopenharmony_ci	}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (err > 0) {
5348c2ecf20Sopenharmony_ci		elem->cached |= 1 << index;
5358c2ecf20Sopenharmony_ci		elem->cache_val[index] = val;
5368c2ecf20Sopenharmony_ci	} else {
5378c2ecf20Sopenharmony_ci		usb_audio_dbg(chip, "Failed to set eq switch, err:%d\n", err);
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	return 1;
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistatic int snd_us16x08_eq_get(struct snd_kcontrol *kcontrol,
5448c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	int val;
5478c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
5488c2ecf20Sopenharmony_ci	struct snd_us16x08_eq_store *store = elem->private_data;
5498c2ecf20Sopenharmony_ci	int index = ucontrol->id.index;
5508c2ecf20Sopenharmony_ci	int b_idx = EQ_STORE_BAND_IDX(elem->head.id) - 1;
5518c2ecf20Sopenharmony_ci	int p_idx = EQ_STORE_PARAM_IDX(elem->head.id);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	val = store->val[b_idx][p_idx][index];
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = val;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	return 0;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic int snd_us16x08_eq_put(struct snd_kcontrol *kcontrol,
5618c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
5648c2ecf20Sopenharmony_ci	struct snd_usb_audio *chip = elem->head.mixer->chip;
5658c2ecf20Sopenharmony_ci	struct snd_us16x08_eq_store *store = elem->private_data;
5668c2ecf20Sopenharmony_ci	int index = ucontrol->id.index;
5678c2ecf20Sopenharmony_ci	char buf[sizeof(eqs_msq)];
5688c2ecf20Sopenharmony_ci	int val, err;
5698c2ecf20Sopenharmony_ci	int b_idx = EQ_STORE_BAND_IDX(elem->head.id) - 1;
5708c2ecf20Sopenharmony_ci	int p_idx = EQ_STORE_PARAM_IDX(elem->head.id);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0];
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	/* sanity check */
5758c2ecf20Sopenharmony_ci	if (val < SND_US16X08_KCMIN(kcontrol)
5768c2ecf20Sopenharmony_ci		|| val > SND_US16X08_KCMAX(kcontrol))
5778c2ecf20Sopenharmony_ci		return -EINVAL;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	/* copy URB buffer from EQ template */
5808c2ecf20Sopenharmony_ci	memcpy(buf, eqs_msq, sizeof(eqs_msq));
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	store->val[b_idx][p_idx][index] = val;
5838c2ecf20Sopenharmony_ci	buf[20] = store->val[b_idx][3][index];
5848c2ecf20Sopenharmony_ci	buf[17] = store->val[b_idx][2][index];
5858c2ecf20Sopenharmony_ci	buf[14] = store->val[b_idx][1][index];
5868c2ecf20Sopenharmony_ci	buf[11] = store->val[b_idx][0][index];
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	/* place channel index in URB buffer */
5898c2ecf20Sopenharmony_ci	buf[5] = index + 1;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	/* place EQ band in URB buffer */
5928c2ecf20Sopenharmony_ci	buf[8] = b_idx + 1;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	if (err > 0) {
5978c2ecf20Sopenharmony_ci		/* store new value in EQ band cache */
5988c2ecf20Sopenharmony_ci		elem->cached |= 1 << index;
5998c2ecf20Sopenharmony_ci		elem->cache_val[index] = val;
6008c2ecf20Sopenharmony_ci	} else {
6018c2ecf20Sopenharmony_ci		usb_audio_dbg(chip, "Failed to set eq param, err:%d\n", err);
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	return 1;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic int snd_us16x08_meter_info(struct snd_kcontrol *kcontrol,
6088c2ecf20Sopenharmony_ci	struct snd_ctl_elem_info *uinfo)
6098c2ecf20Sopenharmony_ci{
6108c2ecf20Sopenharmony_ci	uinfo->count = 34;
6118c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
6128c2ecf20Sopenharmony_ci	uinfo->value.integer.max = 0x7FFF;
6138c2ecf20Sopenharmony_ci	uinfo->value.integer.min = 0;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	return 0;
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci/* calculate compressor index for reduction level request */
6198c2ecf20Sopenharmony_cistatic int snd_get_meter_comp_index(struct snd_us16x08_meter_store *store)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	int ret;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	/* any channel active */
6248c2ecf20Sopenharmony_ci	if (store->comp_active_index) {
6258c2ecf20Sopenharmony_ci		/* check for stereo link */
6268c2ecf20Sopenharmony_ci		if (store->comp_active_index & 0x20) {
6278c2ecf20Sopenharmony_ci			/* reset comp_index to left channel*/
6288c2ecf20Sopenharmony_ci			if (store->comp_index -
6298c2ecf20Sopenharmony_ci				store->comp_active_index > 1)
6308c2ecf20Sopenharmony_ci				store->comp_index =
6318c2ecf20Sopenharmony_ci				store->comp_active_index;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci			ret = store->comp_index++ & 0x1F;
6348c2ecf20Sopenharmony_ci		} else {
6358c2ecf20Sopenharmony_ci			/* no stereo link */
6368c2ecf20Sopenharmony_ci			ret = store->comp_active_index;
6378c2ecf20Sopenharmony_ci		}
6388c2ecf20Sopenharmony_ci	} else {
6398c2ecf20Sopenharmony_ci		/* skip channels with no compressor active */
6408c2ecf20Sopenharmony_ci		while (!store->comp_store->val[
6418c2ecf20Sopenharmony_ci			COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)]
6428c2ecf20Sopenharmony_ci			[store->comp_index - 1]
6438c2ecf20Sopenharmony_ci			&& store->comp_index <= SND_US16X08_MAX_CHANNELS) {
6448c2ecf20Sopenharmony_ci			store->comp_index++;
6458c2ecf20Sopenharmony_ci		}
6468c2ecf20Sopenharmony_ci		ret = store->comp_index++;
6478c2ecf20Sopenharmony_ci		if (store->comp_index > SND_US16X08_MAX_CHANNELS)
6488c2ecf20Sopenharmony_ci			store->comp_index = 1;
6498c2ecf20Sopenharmony_ci	}
6508c2ecf20Sopenharmony_ci	return ret;
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci/* retrieve the meter level values from URB message */
6548c2ecf20Sopenharmony_cistatic void get_meter_levels_from_urb(int s,
6558c2ecf20Sopenharmony_ci	struct snd_us16x08_meter_store *store,
6568c2ecf20Sopenharmony_ci	u8 *meter_urb)
6578c2ecf20Sopenharmony_ci{
6588c2ecf20Sopenharmony_ci	int val = MUC2(meter_urb, s) + (MUC3(meter_urb, s) << 8);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 &&
6618c2ecf20Sopenharmony_ci		MUA2(meter_urb, s) == 0x04 && MUB0(meter_urb, s) == 0x62) {
6628c2ecf20Sopenharmony_ci		if (MUC0(meter_urb, s) == 0x72)
6638c2ecf20Sopenharmony_ci			store->meter_level[MUB2(meter_urb, s) - 1] = val;
6648c2ecf20Sopenharmony_ci		if (MUC0(meter_urb, s) == 0xb2)
6658c2ecf20Sopenharmony_ci			store->comp_level[MUB2(meter_urb, s) - 1] = val;
6668c2ecf20Sopenharmony_ci	}
6678c2ecf20Sopenharmony_ci	if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 &&
6688c2ecf20Sopenharmony_ci		MUA2(meter_urb, s) == 0x02 && MUB0(meter_urb, s) == 0x62)
6698c2ecf20Sopenharmony_ci		store->master_level[MUB2(meter_urb, s) - 1] = val;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci/* Function to retrieve current meter values from the device.
6738c2ecf20Sopenharmony_ci *
6748c2ecf20Sopenharmony_ci * The device needs to be polled for meter values with an initial
6758c2ecf20Sopenharmony_ci * requests. It will return with a sequence of different meter value
6768c2ecf20Sopenharmony_ci * packages. The first request (case 0:) initiate this meter response sequence.
6778c2ecf20Sopenharmony_ci * After the third response, an additional request can be placed,
6788c2ecf20Sopenharmony_ci * to retrieve compressor reduction level value for given channel. This round
6798c2ecf20Sopenharmony_ci * trip channel selector will skip all inactive compressors.
6808c2ecf20Sopenharmony_ci * A mixer can interrupt this round-trip by selecting one ore two (stereo-link)
6818c2ecf20Sopenharmony_ci * specific channels.
6828c2ecf20Sopenharmony_ci */
6838c2ecf20Sopenharmony_cistatic int snd_us16x08_meter_get(struct snd_kcontrol *kcontrol,
6848c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci	int i, set;
6878c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
6888c2ecf20Sopenharmony_ci	struct snd_usb_audio *chip = elem->head.mixer->chip;
6898c2ecf20Sopenharmony_ci	struct snd_us16x08_meter_store *store = elem->private_data;
6908c2ecf20Sopenharmony_ci	u8 meter_urb[64];
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	switch (kcontrol->private_value) {
6938c2ecf20Sopenharmony_ci	case 0: {
6948c2ecf20Sopenharmony_ci		char tmp[sizeof(mix_init_msg1)];
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci		memcpy(tmp, mix_init_msg1, sizeof(mix_init_msg1));
6978c2ecf20Sopenharmony_ci		snd_us16x08_send_urb(chip, tmp, 4);
6988c2ecf20Sopenharmony_ci		snd_us16x08_recv_urb(chip, meter_urb,
6998c2ecf20Sopenharmony_ci			sizeof(meter_urb));
7008c2ecf20Sopenharmony_ci		kcontrol->private_value++;
7018c2ecf20Sopenharmony_ci		break;
7028c2ecf20Sopenharmony_ci	}
7038c2ecf20Sopenharmony_ci	case 1:
7048c2ecf20Sopenharmony_ci		snd_us16x08_recv_urb(chip, meter_urb,
7058c2ecf20Sopenharmony_ci			sizeof(meter_urb));
7068c2ecf20Sopenharmony_ci		kcontrol->private_value++;
7078c2ecf20Sopenharmony_ci		break;
7088c2ecf20Sopenharmony_ci	case 2:
7098c2ecf20Sopenharmony_ci		snd_us16x08_recv_urb(chip, meter_urb,
7108c2ecf20Sopenharmony_ci			sizeof(meter_urb));
7118c2ecf20Sopenharmony_ci		kcontrol->private_value++;
7128c2ecf20Sopenharmony_ci		break;
7138c2ecf20Sopenharmony_ci	case 3: {
7148c2ecf20Sopenharmony_ci		char tmp[sizeof(mix_init_msg2)];
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci		memcpy(tmp, mix_init_msg2, sizeof(mix_init_msg2));
7178c2ecf20Sopenharmony_ci		tmp[2] = snd_get_meter_comp_index(store);
7188c2ecf20Sopenharmony_ci		snd_us16x08_send_urb(chip, tmp, 10);
7198c2ecf20Sopenharmony_ci		snd_us16x08_recv_urb(chip, meter_urb,
7208c2ecf20Sopenharmony_ci			sizeof(meter_urb));
7218c2ecf20Sopenharmony_ci		kcontrol->private_value = 0;
7228c2ecf20Sopenharmony_ci		break;
7238c2ecf20Sopenharmony_ci	}
7248c2ecf20Sopenharmony_ci	}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	for (set = 0; set < 6; set++)
7278c2ecf20Sopenharmony_ci		get_meter_levels_from_urb(set, store, meter_urb);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
7308c2ecf20Sopenharmony_ci		ucontrol->value.integer.value[i] =
7318c2ecf20Sopenharmony_ci			store ? store->meter_level[i] : 0;
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[i++] = store ? store->master_level[0] : 0;
7358c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[i++] = store ? store->master_level[1] : 0;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	for (i = 2; i < SND_US16X08_MAX_CHANNELS + 2; i++)
7388c2ecf20Sopenharmony_ci		ucontrol->value.integer.value[i + SND_US16X08_MAX_CHANNELS] =
7398c2ecf20Sopenharmony_ci		store ? store->comp_level[i - 2] : 0;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	return 1;
7428c2ecf20Sopenharmony_ci}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_cistatic int snd_us16x08_meter_put(struct snd_kcontrol *kcontrol,
7458c2ecf20Sopenharmony_ci	struct snd_ctl_elem_value *ucontrol)
7468c2ecf20Sopenharmony_ci{
7478c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kcontrol->private_data;
7488c2ecf20Sopenharmony_ci	struct snd_us16x08_meter_store *store = elem->private_data;
7498c2ecf20Sopenharmony_ci	int val;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	val = ucontrol->value.integer.value[0];
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	/* sanity check */
7548c2ecf20Sopenharmony_ci	if (val < 0 || val >= SND_US16X08_MAX_CHANNELS)
7558c2ecf20Sopenharmony_ci		return -EINVAL;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	store->comp_active_index = val;
7588c2ecf20Sopenharmony_ci	store->comp_index = val;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	return 1;
7618c2ecf20Sopenharmony_ci}
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_ch_boolean_ctl = {
7648c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7658c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
7668c2ecf20Sopenharmony_ci	.count = 16,
7678c2ecf20Sopenharmony_ci	.info = snd_us16x08_switch_info,
7688c2ecf20Sopenharmony_ci	.get = snd_us16x08_channel_get,
7698c2ecf20Sopenharmony_ci	.put = snd_us16x08_channel_put,
7708c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
7718c2ecf20Sopenharmony_ci};
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_ch_int_ctl = {
7748c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7758c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
7768c2ecf20Sopenharmony_ci	.count = 16,
7778c2ecf20Sopenharmony_ci	.info = snd_us16x08_mix_info,
7788c2ecf20Sopenharmony_ci	.get = snd_us16x08_channel_get,
7798c2ecf20Sopenharmony_ci	.put = snd_us16x08_channel_put,
7808c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 133)
7818c2ecf20Sopenharmony_ci};
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_pan_int_ctl = {
7848c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7858c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
7868c2ecf20Sopenharmony_ci	.count = 16,
7878c2ecf20Sopenharmony_ci	.info = snd_us16x08_mix_info,
7888c2ecf20Sopenharmony_ci	.get = snd_us16x08_channel_get,
7898c2ecf20Sopenharmony_ci	.put = snd_us16x08_channel_put,
7908c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 255)
7918c2ecf20Sopenharmony_ci};
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_master_ctl = {
7948c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7958c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
7968c2ecf20Sopenharmony_ci	.count = 1,
7978c2ecf20Sopenharmony_ci	.info = snd_us16x08_master_info,
7988c2ecf20Sopenharmony_ci	.get = snd_us16x08_master_get,
7998c2ecf20Sopenharmony_ci	.put = snd_us16x08_master_put,
8008c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 133)
8018c2ecf20Sopenharmony_ci};
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_route_ctl = {
8048c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8058c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
8068c2ecf20Sopenharmony_ci	.count = 8,
8078c2ecf20Sopenharmony_ci	.info = snd_us16x08_route_info,
8088c2ecf20Sopenharmony_ci	.get = snd_us16x08_route_get,
8098c2ecf20Sopenharmony_ci	.put = snd_us16x08_route_put,
8108c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 9)
8118c2ecf20Sopenharmony_ci};
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_bus_ctl = {
8148c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8158c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
8168c2ecf20Sopenharmony_ci	.count = 1,
8178c2ecf20Sopenharmony_ci	.info = snd_us16x08_switch_info,
8188c2ecf20Sopenharmony_ci	.get = snd_us16x08_bus_get,
8198c2ecf20Sopenharmony_ci	.put = snd_us16x08_bus_put,
8208c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
8218c2ecf20Sopenharmony_ci};
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_compswitch_ctl = {
8248c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8258c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
8268c2ecf20Sopenharmony_ci	.count = 16,
8278c2ecf20Sopenharmony_ci	.info = snd_us16x08_switch_info,
8288c2ecf20Sopenharmony_ci	.get = snd_us16x08_comp_get,
8298c2ecf20Sopenharmony_ci	.put = snd_us16x08_comp_put,
8308c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
8318c2ecf20Sopenharmony_ci};
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_comp_threshold_ctl = {
8348c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8358c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
8368c2ecf20Sopenharmony_ci	.count = 16,
8378c2ecf20Sopenharmony_ci	.info = snd_us16x08_mix_info,
8388c2ecf20Sopenharmony_ci	.get = snd_us16x08_comp_get,
8398c2ecf20Sopenharmony_ci	.put = snd_us16x08_comp_put,
8408c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_COMP_THRESHOLD_BIAS, 1,
8418c2ecf20Sopenharmony_ci	0, 0x20)
8428c2ecf20Sopenharmony_ci};
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_comp_ratio_ctl = {
8458c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8468c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
8478c2ecf20Sopenharmony_ci	.count = 16,
8488c2ecf20Sopenharmony_ci	.info = snd_us16x08_mix_info,
8498c2ecf20Sopenharmony_ci	.get = snd_us16x08_comp_get,
8508c2ecf20Sopenharmony_ci	.put = snd_us16x08_comp_put,
8518c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0,
8528c2ecf20Sopenharmony_ci	sizeof(ratio_map) - 1), /*max*/
8538c2ecf20Sopenharmony_ci};
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_comp_gain_ctl = {
8568c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8578c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
8588c2ecf20Sopenharmony_ci	.count = 16,
8598c2ecf20Sopenharmony_ci	.info = snd_us16x08_mix_info,
8608c2ecf20Sopenharmony_ci	.get = snd_us16x08_comp_get,
8618c2ecf20Sopenharmony_ci	.put = snd_us16x08_comp_put,
8628c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x14)
8638c2ecf20Sopenharmony_ci};
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_comp_attack_ctl = {
8668c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8678c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
8688c2ecf20Sopenharmony_ci	.count = 16,
8698c2ecf20Sopenharmony_ci	.info = snd_us16x08_mix_info,
8708c2ecf20Sopenharmony_ci	.get = snd_us16x08_comp_get,
8718c2ecf20Sopenharmony_ci	.put = snd_us16x08_comp_put,
8728c2ecf20Sopenharmony_ci	.private_value =
8738c2ecf20Sopenharmony_ci	SND_US16X08_KCSET(SND_US16X08_COMP_ATTACK_BIAS, 1, 0, 0xc6),
8748c2ecf20Sopenharmony_ci};
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_comp_release_ctl = {
8778c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8788c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
8798c2ecf20Sopenharmony_ci	.count = 16,
8808c2ecf20Sopenharmony_ci	.info = snd_us16x08_mix_info,
8818c2ecf20Sopenharmony_ci	.get = snd_us16x08_comp_get,
8828c2ecf20Sopenharmony_ci	.put = snd_us16x08_comp_put,
8838c2ecf20Sopenharmony_ci	.private_value =
8848c2ecf20Sopenharmony_ci	SND_US16X08_KCSET(SND_US16X08_COMP_RELEASE_BIAS, 1, 0, 0x63),
8858c2ecf20Sopenharmony_ci};
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_eq_gain_ctl = {
8888c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8898c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
8908c2ecf20Sopenharmony_ci	.count = 16,
8918c2ecf20Sopenharmony_ci	.info = snd_us16x08_mix_info,
8928c2ecf20Sopenharmony_ci	.get = snd_us16x08_eq_get,
8938c2ecf20Sopenharmony_ci	.put = snd_us16x08_eq_put,
8948c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 24),
8958c2ecf20Sopenharmony_ci};
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_eq_low_freq_ctl = {
8988c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8998c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
9008c2ecf20Sopenharmony_ci	.count = 16,
9018c2ecf20Sopenharmony_ci	.info = snd_us16x08_mix_info,
9028c2ecf20Sopenharmony_ci	.get = snd_us16x08_eq_get,
9038c2ecf20Sopenharmony_ci	.put = snd_us16x08_eq_put,
9048c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x1F),
9058c2ecf20Sopenharmony_ci};
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_eq_mid_freq_ctl = {
9088c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9098c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
9108c2ecf20Sopenharmony_ci	.count = 16,
9118c2ecf20Sopenharmony_ci	.info = snd_us16x08_mix_info,
9128c2ecf20Sopenharmony_ci	.get = snd_us16x08_eq_get,
9138c2ecf20Sopenharmony_ci	.put = snd_us16x08_eq_put,
9148c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x3F)
9158c2ecf20Sopenharmony_ci};
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_eq_mid_width_ctl = {
9188c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9198c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
9208c2ecf20Sopenharmony_ci	.count = 16,
9218c2ecf20Sopenharmony_ci	.info = snd_us16x08_mix_info,
9228c2ecf20Sopenharmony_ci	.get = snd_us16x08_eq_get,
9238c2ecf20Sopenharmony_ci	.put = snd_us16x08_eq_put,
9248c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x06)
9258c2ecf20Sopenharmony_ci};
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_eq_high_freq_ctl = {
9288c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9298c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
9308c2ecf20Sopenharmony_ci	.count = 16,
9318c2ecf20Sopenharmony_ci	.info = snd_us16x08_mix_info,
9328c2ecf20Sopenharmony_ci	.get = snd_us16x08_eq_get,
9338c2ecf20Sopenharmony_ci	.put = snd_us16x08_eq_put,
9348c2ecf20Sopenharmony_ci	.private_value =
9358c2ecf20Sopenharmony_ci	SND_US16X08_KCSET(SND_US16X08_EQ_HIGHFREQ_BIAS, 1, 0, 0x1F)
9368c2ecf20Sopenharmony_ci};
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_eq_switch_ctl = {
9398c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9408c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
9418c2ecf20Sopenharmony_ci	.count = 16,
9428c2ecf20Sopenharmony_ci	.info = snd_us16x08_switch_info,
9438c2ecf20Sopenharmony_ci	.get = snd_us16x08_eqswitch_get,
9448c2ecf20Sopenharmony_ci	.put = snd_us16x08_eqswitch_put,
9458c2ecf20Sopenharmony_ci	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
9468c2ecf20Sopenharmony_ci};
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_meter_ctl = {
9498c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9508c2ecf20Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
9518c2ecf20Sopenharmony_ci	.count = 1,
9528c2ecf20Sopenharmony_ci	.info = snd_us16x08_meter_info,
9538c2ecf20Sopenharmony_ci	.get = snd_us16x08_meter_get,
9548c2ecf20Sopenharmony_ci	.put = snd_us16x08_meter_put
9558c2ecf20Sopenharmony_ci};
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci/* control store preparation */
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci/* setup compressor store and assign default value */
9608c2ecf20Sopenharmony_cistatic struct snd_us16x08_comp_store *snd_us16x08_create_comp_store(void)
9618c2ecf20Sopenharmony_ci{
9628c2ecf20Sopenharmony_ci	int i;
9638c2ecf20Sopenharmony_ci	struct snd_us16x08_comp_store *tmp;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
9668c2ecf20Sopenharmony_ci	if (!tmp)
9678c2ecf20Sopenharmony_ci		return NULL;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
9708c2ecf20Sopenharmony_ci		tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD)][i]
9718c2ecf20Sopenharmony_ci			= 0x20;
9728c2ecf20Sopenharmony_ci		tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO)][i] = 0x00;
9738c2ecf20Sopenharmony_ci		tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN)][i] = 0x00;
9748c2ecf20Sopenharmony_ci		tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)][i] = 0x00;
9758c2ecf20Sopenharmony_ci		tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK)][i] = 0x00;
9768c2ecf20Sopenharmony_ci		tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE)][i] = 0x00;
9778c2ecf20Sopenharmony_ci	}
9788c2ecf20Sopenharmony_ci	return tmp;
9798c2ecf20Sopenharmony_ci}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci/* setup EQ store and assign default values */
9828c2ecf20Sopenharmony_cistatic struct snd_us16x08_eq_store *snd_us16x08_create_eq_store(void)
9838c2ecf20Sopenharmony_ci{
9848c2ecf20Sopenharmony_ci	int i, b_idx;
9858c2ecf20Sopenharmony_ci	struct snd_us16x08_eq_store *tmp;
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
9888c2ecf20Sopenharmony_ci	if (!tmp)
9898c2ecf20Sopenharmony_ci		return NULL;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
9928c2ecf20Sopenharmony_ci		for (b_idx = 0; b_idx < SND_US16X08_ID_EQ_BAND_COUNT; b_idx++) {
9938c2ecf20Sopenharmony_ci			tmp->val[b_idx][0][i] = 0x0c;
9948c2ecf20Sopenharmony_ci			tmp->val[b_idx][3][i] = 0x00;
9958c2ecf20Sopenharmony_ci			switch (b_idx) {
9968c2ecf20Sopenharmony_ci			case 0: /* EQ Low */
9978c2ecf20Sopenharmony_ci				tmp->val[b_idx][1][i] = 0x05;
9988c2ecf20Sopenharmony_ci				tmp->val[b_idx][2][i] = 0xff;
9998c2ecf20Sopenharmony_ci				break;
10008c2ecf20Sopenharmony_ci			case 1: /* EQ Mid low */
10018c2ecf20Sopenharmony_ci				tmp->val[b_idx][1][i] = 0x0e;
10028c2ecf20Sopenharmony_ci				tmp->val[b_idx][2][i] = 0x02;
10038c2ecf20Sopenharmony_ci				break;
10048c2ecf20Sopenharmony_ci			case 2: /* EQ Mid High */
10058c2ecf20Sopenharmony_ci				tmp->val[b_idx][1][i] = 0x1b;
10068c2ecf20Sopenharmony_ci				tmp->val[b_idx][2][i] = 0x02;
10078c2ecf20Sopenharmony_ci				break;
10088c2ecf20Sopenharmony_ci			case 3: /* EQ High */
10098c2ecf20Sopenharmony_ci				tmp->val[b_idx][1][i] = 0x2f
10108c2ecf20Sopenharmony_ci					- SND_US16X08_EQ_HIGHFREQ_BIAS;
10118c2ecf20Sopenharmony_ci				tmp->val[b_idx][2][i] = 0xff;
10128c2ecf20Sopenharmony_ci				break;
10138c2ecf20Sopenharmony_ci			}
10148c2ecf20Sopenharmony_ci		}
10158c2ecf20Sopenharmony_ci	}
10168c2ecf20Sopenharmony_ci	return tmp;
10178c2ecf20Sopenharmony_ci}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_cistatic struct snd_us16x08_meter_store *snd_us16x08_create_meter_store(void)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	struct snd_us16x08_meter_store *tmp;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
10248c2ecf20Sopenharmony_ci	if (!tmp)
10258c2ecf20Sopenharmony_ci		return NULL;
10268c2ecf20Sopenharmony_ci	tmp->comp_index = 1;
10278c2ecf20Sopenharmony_ci	tmp->comp_active_index = 0;
10288c2ecf20Sopenharmony_ci	return tmp;
10298c2ecf20Sopenharmony_ci}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci/* release elem->private_free as well; called only once for each *_store */
10328c2ecf20Sopenharmony_cistatic void elem_private_free(struct snd_kcontrol *kctl)
10338c2ecf20Sopenharmony_ci{
10348c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem = kctl->private_data;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	if (elem)
10378c2ecf20Sopenharmony_ci		kfree(elem->private_data);
10388c2ecf20Sopenharmony_ci	kfree(elem);
10398c2ecf20Sopenharmony_ci	kctl->private_data = NULL;
10408c2ecf20Sopenharmony_ci}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_cistatic int add_new_ctl(struct usb_mixer_interface *mixer,
10438c2ecf20Sopenharmony_ci	const struct snd_kcontrol_new *ncontrol,
10448c2ecf20Sopenharmony_ci	int index, int val_type, int channels,
10458c2ecf20Sopenharmony_ci	const char *name, void *opt,
10468c2ecf20Sopenharmony_ci	bool do_private_free,
10478c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info **elem_ret)
10488c2ecf20Sopenharmony_ci{
10498c2ecf20Sopenharmony_ci	struct snd_kcontrol *kctl;
10508c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem;
10518c2ecf20Sopenharmony_ci	int err;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	usb_audio_dbg(mixer->chip, "us16x08 add mixer %s\n", name);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	elem = kzalloc(sizeof(*elem), GFP_KERNEL);
10568c2ecf20Sopenharmony_ci	if (!elem)
10578c2ecf20Sopenharmony_ci		return -ENOMEM;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	elem->head.mixer = mixer;
10608c2ecf20Sopenharmony_ci	elem->head.resume = NULL;
10618c2ecf20Sopenharmony_ci	elem->control = 0;
10628c2ecf20Sopenharmony_ci	elem->idx_off = 0;
10638c2ecf20Sopenharmony_ci	elem->head.id = index;
10648c2ecf20Sopenharmony_ci	elem->val_type = val_type;
10658c2ecf20Sopenharmony_ci	elem->channels = channels;
10668c2ecf20Sopenharmony_ci	elem->private_data = opt;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	kctl = snd_ctl_new1(ncontrol, elem);
10698c2ecf20Sopenharmony_ci	if (!kctl) {
10708c2ecf20Sopenharmony_ci		kfree(elem);
10718c2ecf20Sopenharmony_ci		return -ENOMEM;
10728c2ecf20Sopenharmony_ci	}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	if (do_private_free)
10758c2ecf20Sopenharmony_ci		kctl->private_free = elem_private_free;
10768c2ecf20Sopenharmony_ci	else
10778c2ecf20Sopenharmony_ci		kctl->private_free = snd_usb_mixer_elem_free;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	err = snd_usb_mixer_add_control(&elem->head, kctl);
10828c2ecf20Sopenharmony_ci	if (err < 0)
10838c2ecf20Sopenharmony_ci		return err;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	if (elem_ret)
10868c2ecf20Sopenharmony_ci		*elem_ret = elem;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	return 0;
10898c2ecf20Sopenharmony_ci}
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci/* table of EQ controls */
10928c2ecf20Sopenharmony_cistatic const struct snd_us16x08_control_params eq_controls[] = {
10938c2ecf20Sopenharmony_ci	{ /* EQ switch */
10948c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_eq_switch_ctl,
10958c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_EQENABLE,
10968c2ecf20Sopenharmony_ci		.type = USB_MIXER_BOOLEAN,
10978c2ecf20Sopenharmony_ci		.num_channels = 16,
10988c2ecf20Sopenharmony_ci		.name = "EQ Switch",
10998c2ecf20Sopenharmony_ci	},
11008c2ecf20Sopenharmony_ci	{ /* EQ low gain */
11018c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_eq_gain_ctl,
11028c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_EQLOWLEVEL,
11038c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11048c2ecf20Sopenharmony_ci		.num_channels = 16,
11058c2ecf20Sopenharmony_ci		.name = "EQ Low Volume",
11068c2ecf20Sopenharmony_ci	},
11078c2ecf20Sopenharmony_ci	{ /* EQ low freq */
11088c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_eq_low_freq_ctl,
11098c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_EQLOWFREQ,
11108c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11118c2ecf20Sopenharmony_ci		.num_channels = 16,
11128c2ecf20Sopenharmony_ci		.name = "EQ Low Frequency",
11138c2ecf20Sopenharmony_ci	},
11148c2ecf20Sopenharmony_ci	{ /* EQ mid low gain */
11158c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_eq_gain_ctl,
11168c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_EQLOWMIDLEVEL,
11178c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11188c2ecf20Sopenharmony_ci		.num_channels = 16,
11198c2ecf20Sopenharmony_ci		.name = "EQ MidLow Volume",
11208c2ecf20Sopenharmony_ci	},
11218c2ecf20Sopenharmony_ci	{ /* EQ mid low freq */
11228c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_eq_mid_freq_ctl,
11238c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_EQLOWMIDFREQ,
11248c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11258c2ecf20Sopenharmony_ci		.num_channels = 16,
11268c2ecf20Sopenharmony_ci		.name = "EQ MidLow Frequency",
11278c2ecf20Sopenharmony_ci	},
11288c2ecf20Sopenharmony_ci	{ /* EQ mid low Q */
11298c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
11308c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_EQLOWMIDWIDTH,
11318c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11328c2ecf20Sopenharmony_ci		.num_channels = 16,
11338c2ecf20Sopenharmony_ci		.name = "EQ MidLow Q",
11348c2ecf20Sopenharmony_ci	},
11358c2ecf20Sopenharmony_ci	{ /* EQ mid high gain */
11368c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_eq_gain_ctl,
11378c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_EQHIGHMIDLEVEL,
11388c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11398c2ecf20Sopenharmony_ci		.num_channels = 16,
11408c2ecf20Sopenharmony_ci		.name = "EQ MidHigh Volume",
11418c2ecf20Sopenharmony_ci	},
11428c2ecf20Sopenharmony_ci	{ /* EQ mid high freq */
11438c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_eq_mid_freq_ctl,
11448c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_EQHIGHMIDFREQ,
11458c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11468c2ecf20Sopenharmony_ci		.num_channels = 16,
11478c2ecf20Sopenharmony_ci		.name = "EQ MidHigh Frequency",
11488c2ecf20Sopenharmony_ci	},
11498c2ecf20Sopenharmony_ci	{ /* EQ mid high Q */
11508c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
11518c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_EQHIGHMIDWIDTH,
11528c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11538c2ecf20Sopenharmony_ci		.num_channels = 16,
11548c2ecf20Sopenharmony_ci		.name = "EQ MidHigh Q",
11558c2ecf20Sopenharmony_ci	},
11568c2ecf20Sopenharmony_ci	{ /* EQ high gain */
11578c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_eq_gain_ctl,
11588c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_EQHIGHLEVEL,
11598c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11608c2ecf20Sopenharmony_ci		.num_channels = 16,
11618c2ecf20Sopenharmony_ci		.name = "EQ High Volume",
11628c2ecf20Sopenharmony_ci	},
11638c2ecf20Sopenharmony_ci	{ /* EQ low freq */
11648c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_eq_high_freq_ctl,
11658c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_EQHIGHFREQ,
11668c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11678c2ecf20Sopenharmony_ci		.num_channels = 16,
11688c2ecf20Sopenharmony_ci		.name = "EQ High Frequency",
11698c2ecf20Sopenharmony_ci	},
11708c2ecf20Sopenharmony_ci};
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci/* table of compressor controls */
11738c2ecf20Sopenharmony_cistatic const struct snd_us16x08_control_params comp_controls[] = {
11748c2ecf20Sopenharmony_ci	{ /* Comp enable */
11758c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_compswitch_ctl,
11768c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_COMP_SWITCH,
11778c2ecf20Sopenharmony_ci		.type = USB_MIXER_BOOLEAN,
11788c2ecf20Sopenharmony_ci		.num_channels = 16,
11798c2ecf20Sopenharmony_ci		.name = "Compressor Switch",
11808c2ecf20Sopenharmony_ci	},
11818c2ecf20Sopenharmony_ci	{ /* Comp threshold */
11828c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_comp_threshold_ctl,
11838c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_COMP_THRESHOLD,
11848c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11858c2ecf20Sopenharmony_ci		.num_channels = 16,
11868c2ecf20Sopenharmony_ci		.name = "Compressor Threshold Volume",
11878c2ecf20Sopenharmony_ci	},
11888c2ecf20Sopenharmony_ci	{ /* Comp ratio */
11898c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_comp_ratio_ctl,
11908c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_COMP_RATIO,
11918c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11928c2ecf20Sopenharmony_ci		.num_channels = 16,
11938c2ecf20Sopenharmony_ci		.name = "Compressor Ratio",
11948c2ecf20Sopenharmony_ci	},
11958c2ecf20Sopenharmony_ci	{ /* Comp attack */
11968c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_comp_attack_ctl,
11978c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_COMP_ATTACK,
11988c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
11998c2ecf20Sopenharmony_ci		.num_channels = 16,
12008c2ecf20Sopenharmony_ci		.name = "Compressor Attack",
12018c2ecf20Sopenharmony_ci	},
12028c2ecf20Sopenharmony_ci	{ /* Comp release */
12038c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_comp_release_ctl,
12048c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_COMP_RELEASE,
12058c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
12068c2ecf20Sopenharmony_ci		.num_channels = 16,
12078c2ecf20Sopenharmony_ci		.name = "Compressor Release",
12088c2ecf20Sopenharmony_ci	},
12098c2ecf20Sopenharmony_ci	{ /* Comp gain */
12108c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_comp_gain_ctl,
12118c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_COMP_GAIN,
12128c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
12138c2ecf20Sopenharmony_ci		.num_channels = 16,
12148c2ecf20Sopenharmony_ci		.name = "Compressor Volume",
12158c2ecf20Sopenharmony_ci	},
12168c2ecf20Sopenharmony_ci};
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci/* table of channel controls */
12198c2ecf20Sopenharmony_cistatic const struct snd_us16x08_control_params channel_controls[] = {
12208c2ecf20Sopenharmony_ci	{ /* Phase */
12218c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_ch_boolean_ctl,
12228c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_PHASE,
12238c2ecf20Sopenharmony_ci		.type = USB_MIXER_BOOLEAN,
12248c2ecf20Sopenharmony_ci		.num_channels = 16,
12258c2ecf20Sopenharmony_ci		.name = "Phase Switch",
12268c2ecf20Sopenharmony_ci		.default_val = 0
12278c2ecf20Sopenharmony_ci	},
12288c2ecf20Sopenharmony_ci	{ /* Fader */
12298c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_ch_int_ctl,
12308c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_FADER,
12318c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
12328c2ecf20Sopenharmony_ci		.num_channels = 16,
12338c2ecf20Sopenharmony_ci		.name = "Line Volume",
12348c2ecf20Sopenharmony_ci		.default_val = 127
12358c2ecf20Sopenharmony_ci	},
12368c2ecf20Sopenharmony_ci	{ /* Mute */
12378c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_ch_boolean_ctl,
12388c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_MUTE,
12398c2ecf20Sopenharmony_ci		.type = USB_MIXER_BOOLEAN,
12408c2ecf20Sopenharmony_ci		.num_channels = 16,
12418c2ecf20Sopenharmony_ci		.name = "Mute Switch",
12428c2ecf20Sopenharmony_ci		.default_val = 0
12438c2ecf20Sopenharmony_ci	},
12448c2ecf20Sopenharmony_ci	{ /* Pan */
12458c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_pan_int_ctl,
12468c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_PAN,
12478c2ecf20Sopenharmony_ci		.type = USB_MIXER_U16,
12488c2ecf20Sopenharmony_ci		.num_channels = 16,
12498c2ecf20Sopenharmony_ci		.name = "Pan Left-Right Volume",
12508c2ecf20Sopenharmony_ci		.default_val = 127
12518c2ecf20Sopenharmony_ci	},
12528c2ecf20Sopenharmony_ci};
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci/* table of master controls */
12558c2ecf20Sopenharmony_cistatic const struct snd_us16x08_control_params master_controls[] = {
12568c2ecf20Sopenharmony_ci	{ /* Master */
12578c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_master_ctl,
12588c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_FADER,
12598c2ecf20Sopenharmony_ci		.type = USB_MIXER_U8,
12608c2ecf20Sopenharmony_ci		.num_channels = 16,
12618c2ecf20Sopenharmony_ci		.name = "Master Volume",
12628c2ecf20Sopenharmony_ci		.default_val = 127
12638c2ecf20Sopenharmony_ci	},
12648c2ecf20Sopenharmony_ci	{ /* Bypass */
12658c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_bus_ctl,
12668c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_BYPASS,
12678c2ecf20Sopenharmony_ci		.type = USB_MIXER_BOOLEAN,
12688c2ecf20Sopenharmony_ci		.num_channels = 16,
12698c2ecf20Sopenharmony_ci		.name = "DSP Bypass Switch",
12708c2ecf20Sopenharmony_ci		.default_val = 0
12718c2ecf20Sopenharmony_ci	},
12728c2ecf20Sopenharmony_ci	{ /* Buss out */
12738c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_bus_ctl,
12748c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_BUSS_OUT,
12758c2ecf20Sopenharmony_ci		.type = USB_MIXER_BOOLEAN,
12768c2ecf20Sopenharmony_ci		.num_channels = 16,
12778c2ecf20Sopenharmony_ci		.name = "Buss Out Switch",
12788c2ecf20Sopenharmony_ci		.default_val = 0
12798c2ecf20Sopenharmony_ci	},
12808c2ecf20Sopenharmony_ci	{ /* Master mute */
12818c2ecf20Sopenharmony_ci		.kcontrol_new = &snd_us16x08_bus_ctl,
12828c2ecf20Sopenharmony_ci		.control_id = SND_US16X08_ID_MUTE,
12838c2ecf20Sopenharmony_ci		.type = USB_MIXER_BOOLEAN,
12848c2ecf20Sopenharmony_ci		.num_channels = 16,
12858c2ecf20Sopenharmony_ci		.name = "Master Mute Switch",
12868c2ecf20Sopenharmony_ci		.default_val = 0
12878c2ecf20Sopenharmony_ci	},
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci};
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ciint snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
12928c2ecf20Sopenharmony_ci{
12938c2ecf20Sopenharmony_ci	int i, j;
12948c2ecf20Sopenharmony_ci	int err;
12958c2ecf20Sopenharmony_ci	struct usb_mixer_elem_info *elem;
12968c2ecf20Sopenharmony_ci	struct snd_us16x08_comp_store *comp_store;
12978c2ecf20Sopenharmony_ci	struct snd_us16x08_meter_store *meter_store;
12988c2ecf20Sopenharmony_ci	struct snd_us16x08_eq_store *eq_store;
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	/* just check for non-MIDI interface */
13018c2ecf20Sopenharmony_ci	if (mixer->hostif->desc.bInterfaceNumber == 3) {
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci		/* add routing control */
13048c2ecf20Sopenharmony_ci		err = add_new_ctl(mixer, &snd_us16x08_route_ctl,
13058c2ecf20Sopenharmony_ci			SND_US16X08_ID_ROUTE, USB_MIXER_U8, 8, "Line Out Route",
13068c2ecf20Sopenharmony_ci			NULL, false, &elem);
13078c2ecf20Sopenharmony_ci		if (err < 0) {
13088c2ecf20Sopenharmony_ci			usb_audio_dbg(mixer->chip,
13098c2ecf20Sopenharmony_ci				"Failed to create route control, err:%d\n",
13108c2ecf20Sopenharmony_ci				err);
13118c2ecf20Sopenharmony_ci			return err;
13128c2ecf20Sopenharmony_ci		}
13138c2ecf20Sopenharmony_ci		for (i = 0; i < 8; i++)
13148c2ecf20Sopenharmony_ci			elem->cache_val[i] = i < 2 ? i : i + 2;
13158c2ecf20Sopenharmony_ci		elem->cached = 0xff;
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci		/* create compressor mixer elements */
13188c2ecf20Sopenharmony_ci		comp_store = snd_us16x08_create_comp_store();
13198c2ecf20Sopenharmony_ci		if (!comp_store)
13208c2ecf20Sopenharmony_ci			return -ENOMEM;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci		/* add master controls */
13238c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(master_controls); i++) {
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci			err = add_new_ctl(mixer,
13268c2ecf20Sopenharmony_ci				master_controls[i].kcontrol_new,
13278c2ecf20Sopenharmony_ci				master_controls[i].control_id,
13288c2ecf20Sopenharmony_ci				master_controls[i].type,
13298c2ecf20Sopenharmony_ci				master_controls[i].num_channels,
13308c2ecf20Sopenharmony_ci				master_controls[i].name,
13318c2ecf20Sopenharmony_ci				comp_store,
13328c2ecf20Sopenharmony_ci				i == 0, /* release comp_store only once */
13338c2ecf20Sopenharmony_ci				&elem);
13348c2ecf20Sopenharmony_ci			if (err < 0)
13358c2ecf20Sopenharmony_ci				return err;
13368c2ecf20Sopenharmony_ci			elem->cache_val[0] = master_controls[i].default_val;
13378c2ecf20Sopenharmony_ci			elem->cached = 1;
13388c2ecf20Sopenharmony_ci		}
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci		/* add channel controls */
13418c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(channel_controls); i++) {
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci			err = add_new_ctl(mixer,
13448c2ecf20Sopenharmony_ci				channel_controls[i].kcontrol_new,
13458c2ecf20Sopenharmony_ci				channel_controls[i].control_id,
13468c2ecf20Sopenharmony_ci				channel_controls[i].type,
13478c2ecf20Sopenharmony_ci				channel_controls[i].num_channels,
13488c2ecf20Sopenharmony_ci				channel_controls[i].name,
13498c2ecf20Sopenharmony_ci				comp_store,
13508c2ecf20Sopenharmony_ci				false, &elem);
13518c2ecf20Sopenharmony_ci			if (err < 0)
13528c2ecf20Sopenharmony_ci				return err;
13538c2ecf20Sopenharmony_ci			for (j = 0; j < SND_US16X08_MAX_CHANNELS; j++) {
13548c2ecf20Sopenharmony_ci				elem->cache_val[j] =
13558c2ecf20Sopenharmony_ci					channel_controls[i].default_val;
13568c2ecf20Sopenharmony_ci			}
13578c2ecf20Sopenharmony_ci			elem->cached = 0xffff;
13588c2ecf20Sopenharmony_ci		}
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci		/* create eq store */
13618c2ecf20Sopenharmony_ci		eq_store = snd_us16x08_create_eq_store();
13628c2ecf20Sopenharmony_ci		if (!eq_store)
13638c2ecf20Sopenharmony_ci			return -ENOMEM;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci		/* add EQ controls */
13668c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(eq_controls); i++) {
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci			err = add_new_ctl(mixer,
13698c2ecf20Sopenharmony_ci				eq_controls[i].kcontrol_new,
13708c2ecf20Sopenharmony_ci				eq_controls[i].control_id,
13718c2ecf20Sopenharmony_ci				eq_controls[i].type,
13728c2ecf20Sopenharmony_ci				eq_controls[i].num_channels,
13738c2ecf20Sopenharmony_ci				eq_controls[i].name,
13748c2ecf20Sopenharmony_ci				eq_store,
13758c2ecf20Sopenharmony_ci				i == 0, /* release eq_store only once */
13768c2ecf20Sopenharmony_ci				NULL);
13778c2ecf20Sopenharmony_ci			if (err < 0)
13788c2ecf20Sopenharmony_ci				return err;
13798c2ecf20Sopenharmony_ci		}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci		/* add compressor controls */
13828c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(comp_controls); i++) {
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci			err = add_new_ctl(mixer,
13858c2ecf20Sopenharmony_ci				comp_controls[i].kcontrol_new,
13868c2ecf20Sopenharmony_ci				comp_controls[i].control_id,
13878c2ecf20Sopenharmony_ci				comp_controls[i].type,
13888c2ecf20Sopenharmony_ci				comp_controls[i].num_channels,
13898c2ecf20Sopenharmony_ci				comp_controls[i].name,
13908c2ecf20Sopenharmony_ci				comp_store,
13918c2ecf20Sopenharmony_ci				false, NULL);
13928c2ecf20Sopenharmony_ci			if (err < 0)
13938c2ecf20Sopenharmony_ci				return err;
13948c2ecf20Sopenharmony_ci		}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci		/* create meters store */
13978c2ecf20Sopenharmony_ci		meter_store = snd_us16x08_create_meter_store();
13988c2ecf20Sopenharmony_ci		if (!meter_store)
13998c2ecf20Sopenharmony_ci			return -ENOMEM;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci		/* meter function 'get' must access to compressor store
14028c2ecf20Sopenharmony_ci		 * so place a reference here
14038c2ecf20Sopenharmony_ci		 */
14048c2ecf20Sopenharmony_ci		meter_store->comp_store = comp_store;
14058c2ecf20Sopenharmony_ci		err = add_new_ctl(mixer, &snd_us16x08_meter_ctl,
14068c2ecf20Sopenharmony_ci			SND_US16X08_ID_METER, USB_MIXER_U16, 0, "Level Meter",
14078c2ecf20Sopenharmony_ci			meter_store, true, NULL);
14088c2ecf20Sopenharmony_ci		if (err < 0)
14098c2ecf20Sopenharmony_ci			return err;
14108c2ecf20Sopenharmony_ci	}
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	return 0;
14138c2ecf20Sopenharmony_ci}
14148c2ecf20Sopenharmony_ci
1415