xref: /OK3568_Linux_fs/kernel/sound/usb/mixer_us16x08.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *   Tascam US-16x08 ALSA driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *   Copyright (c) 2016 by Detlef Urban (onkel@paraair.de)
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/slab.h>
9*4882a593Smuzhiyun #include <linux/usb.h>
10*4882a593Smuzhiyun #include <linux/usb/audio-v2.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <sound/core.h>
13*4882a593Smuzhiyun #include <sound/control.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "usbaudio.h"
16*4882a593Smuzhiyun #include "mixer.h"
17*4882a593Smuzhiyun #include "helper.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include "mixer_us16x08.h"
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun /* USB control message templates */
22*4882a593Smuzhiyun static const char route_msg[] = {
23*4882a593Smuzhiyun 	0x61,
24*4882a593Smuzhiyun 	0x02,
25*4882a593Smuzhiyun 	0x03, /* input from master (0x02) or input from computer bus (0x03) */
26*4882a593Smuzhiyun 	0x62,
27*4882a593Smuzhiyun 	0x02,
28*4882a593Smuzhiyun 	0x01, /* input index (0x01/0x02 eq. left/right) or bus (0x01-0x08) */
29*4882a593Smuzhiyun 	0x41,
30*4882a593Smuzhiyun 	0x01,
31*4882a593Smuzhiyun 	0x61,
32*4882a593Smuzhiyun 	0x02,
33*4882a593Smuzhiyun 	0x01,
34*4882a593Smuzhiyun 	0x62,
35*4882a593Smuzhiyun 	0x02,
36*4882a593Smuzhiyun 	0x01, /* output index (0x01-0x08) */
37*4882a593Smuzhiyun 	0x42,
38*4882a593Smuzhiyun 	0x01,
39*4882a593Smuzhiyun 	0x43,
40*4882a593Smuzhiyun 	0x01,
41*4882a593Smuzhiyun 	0x00,
42*4882a593Smuzhiyun 	0x00
43*4882a593Smuzhiyun };
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun static const char mix_init_msg1[] = {
46*4882a593Smuzhiyun 	0x71, 0x01, 0x00, 0x00
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun static const char mix_init_msg2[] = {
50*4882a593Smuzhiyun 	0x62, 0x02, 0x00, 0x61, 0x02, 0x04, 0xb1, 0x01, 0x00, 0x00
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun static const char mix_msg_in[] = {
54*4882a593Smuzhiyun 	/* default message head, equal to all mixers */
55*4882a593Smuzhiyun 	0x61, 0x02, 0x04, 0x62, 0x02, 0x01,
56*4882a593Smuzhiyun 	0x81, /* 0x06: Controller ID */
57*4882a593Smuzhiyun 	0x02, /* 0x07:  */
58*4882a593Smuzhiyun 	0x00, /* 0x08: Value of common mixer */
59*4882a593Smuzhiyun 	0x00,
60*4882a593Smuzhiyun 	0x00
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun static const char mix_msg_out[] = {
64*4882a593Smuzhiyun 	/* default message head, equal to all mixers */
65*4882a593Smuzhiyun 	0x61, 0x02, 0x02, 0x62, 0x02, 0x01,
66*4882a593Smuzhiyun 	0x81, /* 0x06: Controller ID */
67*4882a593Smuzhiyun 	0x02, /*                    0x07:  */
68*4882a593Smuzhiyun 	0x00, /*                    0x08: Value of common mixer */
69*4882a593Smuzhiyun 	0x00,
70*4882a593Smuzhiyun 	0x00
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun static const char bypass_msg_out[] = {
74*4882a593Smuzhiyun 	0x45,
75*4882a593Smuzhiyun 	0x02,
76*4882a593Smuzhiyun 	0x01, /* on/off flag */
77*4882a593Smuzhiyun 	0x00,
78*4882a593Smuzhiyun 	0x00
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun static const char bus_msg_out[] = {
82*4882a593Smuzhiyun 	0x44,
83*4882a593Smuzhiyun 	0x02,
84*4882a593Smuzhiyun 	0x01, /* on/off flag */
85*4882a593Smuzhiyun 	0x00,
86*4882a593Smuzhiyun 	0x00
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun static const char comp_msg[] = {
90*4882a593Smuzhiyun 	/* default message head, equal to all mixers */
91*4882a593Smuzhiyun 	0x61, 0x02, 0x04, 0x62, 0x02, 0x01,
92*4882a593Smuzhiyun 	0x91,
93*4882a593Smuzhiyun 	0x02,
94*4882a593Smuzhiyun 	0xf0, /* 0x08: Threshold db (8) (e0 ... 00) (+-0dB -- -32dB) x-32 */
95*4882a593Smuzhiyun 	0x92,
96*4882a593Smuzhiyun 	0x02,
97*4882a593Smuzhiyun 	0x0a, /* 0x0b: Ratio (0a,0b,0d,0f,11,14,19,1e,23,28,32,3c,50,a0,ff)  */
98*4882a593Smuzhiyun 	0x93,
99*4882a593Smuzhiyun 	0x02,
100*4882a593Smuzhiyun 	0x02, /* 0x0e: Attack (0x02 ... 0xc0) (2ms ... 200ms) */
101*4882a593Smuzhiyun 	0x94,
102*4882a593Smuzhiyun 	0x02,
103*4882a593Smuzhiyun 	0x01, /* 0x11: Release (0x01 ... 0x64) (10ms ... 1000ms) x*10  */
104*4882a593Smuzhiyun 	0x95,
105*4882a593Smuzhiyun 	0x02,
106*4882a593Smuzhiyun 	0x03, /* 0x14: gain (0 ... 20) (0dB .. 20dB) */
107*4882a593Smuzhiyun 	0x96,
108*4882a593Smuzhiyun 	0x02,
109*4882a593Smuzhiyun 	0x01,
110*4882a593Smuzhiyun 	0x97,
111*4882a593Smuzhiyun 	0x02,
112*4882a593Smuzhiyun 	0x01, /* 0x1a: main Comp switch (0 ... 1) (off ... on)) */
113*4882a593Smuzhiyun 	0x00,
114*4882a593Smuzhiyun 	0x00
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun static const char eqs_msq[] = {
118*4882a593Smuzhiyun 	/* default message head, equal to all mixers */
119*4882a593Smuzhiyun 	0x61, 0x02, 0x04, 0x62, 0x02, 0x01,
120*4882a593Smuzhiyun 	0x51, /*                0x06: Controller ID  */
121*4882a593Smuzhiyun 	0x02,
122*4882a593Smuzhiyun 	0x04, /* 0x08: EQ set num (0x01..0x04) (LOW, LOWMID, HIGHMID, HIGH)) */
123*4882a593Smuzhiyun 	0x52,
124*4882a593Smuzhiyun 	0x02,
125*4882a593Smuzhiyun 	0x0c, /* 0x0b: value dB (0 ... 12) (-12db .. +12db)  x-6 */
126*4882a593Smuzhiyun 	0x53,
127*4882a593Smuzhiyun 	0x02,
128*4882a593Smuzhiyun 	0x0f, /* 0x0e: value freq (32-47) (1.7kHz..18kHz) */
129*4882a593Smuzhiyun 	0x54,
130*4882a593Smuzhiyun 	0x02,
131*4882a593Smuzhiyun 	0x02, /* 0x11: band width (0-6) (Q16-Q0.25)  2^x/4 (EQ xxMID only) */
132*4882a593Smuzhiyun 	0x55,
133*4882a593Smuzhiyun 	0x02,
134*4882a593Smuzhiyun 	0x01, /* 0x14: main EQ switch (0 ... 1) (off ... on)) */
135*4882a593Smuzhiyun 	0x00,
136*4882a593Smuzhiyun 	0x00
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun /* compressor ratio map */
140*4882a593Smuzhiyun static const char ratio_map[] = {
141*4882a593Smuzhiyun 	0x0a, 0x0b, 0x0d, 0x0f, 0x11, 0x14, 0x19, 0x1e,
142*4882a593Smuzhiyun 	0x23, 0x28, 0x32, 0x3c, 0x50, 0xa0, 0xff
143*4882a593Smuzhiyun };
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun /* route enumeration names */
146*4882a593Smuzhiyun static const char *const route_names[] = {
147*4882a593Smuzhiyun 	"Master Left", "Master Right", "Output 1", "Output 2", "Output 3",
148*4882a593Smuzhiyun 	"Output 4", "Output 5", "Output 6", "Output 7", "Output 8",
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun 
snd_us16x08_recv_urb(struct snd_usb_audio * chip,unsigned char * buf,int size)151*4882a593Smuzhiyun static int snd_us16x08_recv_urb(struct snd_usb_audio *chip,
152*4882a593Smuzhiyun 	unsigned char *buf, int size)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	mutex_lock(&chip->mutex);
156*4882a593Smuzhiyun 	snd_usb_ctl_msg(chip->dev,
157*4882a593Smuzhiyun 		usb_rcvctrlpipe(chip->dev, 0),
158*4882a593Smuzhiyun 		SND_US16X08_URB_METER_REQUEST,
159*4882a593Smuzhiyun 		SND_US16X08_URB_METER_REQUESTTYPE, 0, 0, buf, size);
160*4882a593Smuzhiyun 	mutex_unlock(&chip->mutex);
161*4882a593Smuzhiyun 	return 0;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun /* wrapper function to send prepared URB buffer to usb device. Return an error
165*4882a593Smuzhiyun  * code if something went wrong
166*4882a593Smuzhiyun  */
snd_us16x08_send_urb(struct snd_usb_audio * chip,char * buf,int size)167*4882a593Smuzhiyun static int snd_us16x08_send_urb(struct snd_usb_audio *chip, char *buf, int size)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	return snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
170*4882a593Smuzhiyun 			SND_US16X08_URB_REQUEST, SND_US16X08_URB_REQUESTTYPE,
171*4882a593Smuzhiyun 			0, 0, buf, size);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
snd_us16x08_route_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)174*4882a593Smuzhiyun static int snd_us16x08_route_info(struct snd_kcontrol *kcontrol,
175*4882a593Smuzhiyun 	struct snd_ctl_elem_info *uinfo)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	return snd_ctl_enum_info(uinfo, 1, 10, route_names);
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
snd_us16x08_route_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)180*4882a593Smuzhiyun static int snd_us16x08_route_get(struct snd_kcontrol *kcontrol,
181*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
184*4882a593Smuzhiyun 	int index = ucontrol->id.index;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	/* route has no bias */
187*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = elem->cache_val[index];
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	return 0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
snd_us16x08_route_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)192*4882a593Smuzhiyun static int snd_us16x08_route_put(struct snd_kcontrol *kcontrol,
193*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
196*4882a593Smuzhiyun 	struct snd_usb_audio *chip = elem->head.mixer->chip;
197*4882a593Smuzhiyun 	int index = ucontrol->id.index;
198*4882a593Smuzhiyun 	char buf[sizeof(route_msg)];
199*4882a593Smuzhiyun 	int val, val_org, err;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	/*  get the new value (no bias for routes) */
202*4882a593Smuzhiyun 	val = ucontrol->value.enumerated.item[0];
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	/* sanity check */
205*4882a593Smuzhiyun 	if (val < 0 || val > 9)
206*4882a593Smuzhiyun 		return -EINVAL;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	/* prepare the message buffer from template */
209*4882a593Smuzhiyun 	memcpy(buf, route_msg, sizeof(route_msg));
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	if (val < 2) {
212*4882a593Smuzhiyun 		/* input comes from a master channel */
213*4882a593Smuzhiyun 		val_org = val;
214*4882a593Smuzhiyun 		buf[2] = 0x02;
215*4882a593Smuzhiyun 	} else {
216*4882a593Smuzhiyun 		/* input comes from a computer channel */
217*4882a593Smuzhiyun 		buf[2] = 0x03;
218*4882a593Smuzhiyun 		val_org = val - 2;
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	/* place new route selection in URB message */
222*4882a593Smuzhiyun 	buf[5] = (unsigned char) (val_org & 0x0f) + 1;
223*4882a593Smuzhiyun 	/* place route selector in URB message */
224*4882a593Smuzhiyun 	buf[13] = index + 1;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	err = snd_us16x08_send_urb(chip, buf, sizeof(route_msg));
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	if (err > 0) {
229*4882a593Smuzhiyun 		elem->cached |= 1 << index;
230*4882a593Smuzhiyun 		elem->cache_val[index] = val;
231*4882a593Smuzhiyun 	} else {
232*4882a593Smuzhiyun 		usb_audio_dbg(chip, "Failed to set routing, err:%d\n", err);
233*4882a593Smuzhiyun 	}
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	return err > 0 ? 1 : 0;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
snd_us16x08_master_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)238*4882a593Smuzhiyun static int snd_us16x08_master_info(struct snd_kcontrol *kcontrol,
239*4882a593Smuzhiyun 	struct snd_ctl_elem_info *uinfo)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	uinfo->count = 1;
242*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
243*4882a593Smuzhiyun 	uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol);
244*4882a593Smuzhiyun 	uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol);
245*4882a593Smuzhiyun 	uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol);
246*4882a593Smuzhiyun 	return 0;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
snd_us16x08_master_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)249*4882a593Smuzhiyun static int snd_us16x08_master_get(struct snd_kcontrol *kcontrol,
250*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
253*4882a593Smuzhiyun 	int index = ucontrol->id.index;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = elem->cache_val[index];
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	return 0;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
snd_us16x08_master_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)260*4882a593Smuzhiyun static int snd_us16x08_master_put(struct snd_kcontrol *kcontrol,
261*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
264*4882a593Smuzhiyun 	struct snd_usb_audio *chip = elem->head.mixer->chip;
265*4882a593Smuzhiyun 	char buf[sizeof(mix_msg_out)];
266*4882a593Smuzhiyun 	int val, err;
267*4882a593Smuzhiyun 	int index = ucontrol->id.index;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	/* new control value incl. bias*/
270*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0];
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	/* sanity check */
273*4882a593Smuzhiyun 	if (val < SND_US16X08_KCMIN(kcontrol)
274*4882a593Smuzhiyun 		|| val > SND_US16X08_KCMAX(kcontrol))
275*4882a593Smuzhiyun 		return -EINVAL;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	/* prepare the message buffer from template */
278*4882a593Smuzhiyun 	memcpy(buf, mix_msg_out, sizeof(mix_msg_out));
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	buf[8] = val - SND_US16X08_KCBIAS(kcontrol);
281*4882a593Smuzhiyun 	buf[6] = elem->head.id;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	/* place channel selector in URB message */
284*4882a593Smuzhiyun 	buf[5] = index + 1;
285*4882a593Smuzhiyun 	err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_out));
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	if (err > 0) {
288*4882a593Smuzhiyun 		elem->cached |= 1 << index;
289*4882a593Smuzhiyun 		elem->cache_val[index] = val;
290*4882a593Smuzhiyun 	} else {
291*4882a593Smuzhiyun 		usb_audio_dbg(chip, "Failed to set master, err:%d\n", err);
292*4882a593Smuzhiyun 	}
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	return err > 0 ? 1 : 0;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun 
snd_us16x08_bus_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)297*4882a593Smuzhiyun static int snd_us16x08_bus_put(struct snd_kcontrol *kcontrol,
298*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
301*4882a593Smuzhiyun 	struct snd_usb_audio *chip = elem->head.mixer->chip;
302*4882a593Smuzhiyun 	char buf[sizeof(mix_msg_out)];
303*4882a593Smuzhiyun 	int val, err = 0;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0];
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	/* prepare the message buffer from template */
308*4882a593Smuzhiyun 	switch (elem->head.id) {
309*4882a593Smuzhiyun 	case SND_US16X08_ID_BYPASS:
310*4882a593Smuzhiyun 		memcpy(buf, bypass_msg_out, sizeof(bypass_msg_out));
311*4882a593Smuzhiyun 		buf[2] = val;
312*4882a593Smuzhiyun 		err = snd_us16x08_send_urb(chip, buf, sizeof(bypass_msg_out));
313*4882a593Smuzhiyun 		break;
314*4882a593Smuzhiyun 	case SND_US16X08_ID_BUSS_OUT:
315*4882a593Smuzhiyun 		memcpy(buf, bus_msg_out, sizeof(bus_msg_out));
316*4882a593Smuzhiyun 		buf[2] = val;
317*4882a593Smuzhiyun 		err = snd_us16x08_send_urb(chip, buf, sizeof(bus_msg_out));
318*4882a593Smuzhiyun 		break;
319*4882a593Smuzhiyun 	case SND_US16X08_ID_MUTE:
320*4882a593Smuzhiyun 		memcpy(buf, mix_msg_out, sizeof(mix_msg_out));
321*4882a593Smuzhiyun 		buf[8] = val;
322*4882a593Smuzhiyun 		buf[6] = elem->head.id;
323*4882a593Smuzhiyun 		buf[5] = 1;
324*4882a593Smuzhiyun 		err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_out));
325*4882a593Smuzhiyun 		break;
326*4882a593Smuzhiyun 	}
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	if (err > 0) {
329*4882a593Smuzhiyun 		elem->cached |= 1;
330*4882a593Smuzhiyun 		elem->cache_val[0] = val;
331*4882a593Smuzhiyun 	} else {
332*4882a593Smuzhiyun 		usb_audio_dbg(chip, "Failed to set bus parameter, err:%d\n", err);
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	return err > 0 ? 1 : 0;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun 
snd_us16x08_bus_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)338*4882a593Smuzhiyun static int snd_us16x08_bus_get(struct snd_kcontrol *kcontrol,
339*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	switch (elem->head.id) {
344*4882a593Smuzhiyun 	case SND_US16X08_ID_BUSS_OUT:
345*4882a593Smuzhiyun 		ucontrol->value.integer.value[0] = elem->cache_val[0];
346*4882a593Smuzhiyun 		break;
347*4882a593Smuzhiyun 	case SND_US16X08_ID_BYPASS:
348*4882a593Smuzhiyun 		ucontrol->value.integer.value[0] = elem->cache_val[0];
349*4882a593Smuzhiyun 		break;
350*4882a593Smuzhiyun 	case SND_US16X08_ID_MUTE:
351*4882a593Smuzhiyun 		ucontrol->value.integer.value[0] = elem->cache_val[0];
352*4882a593Smuzhiyun 		break;
353*4882a593Smuzhiyun 	}
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	return 0;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun /* gets a current mixer value from common store */
snd_us16x08_channel_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)359*4882a593Smuzhiyun static int snd_us16x08_channel_get(struct snd_kcontrol *kcontrol,
360*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
363*4882a593Smuzhiyun 	int index = ucontrol->id.index;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = elem->cache_val[index];
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	return 0;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
snd_us16x08_channel_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)370*4882a593Smuzhiyun static int snd_us16x08_channel_put(struct snd_kcontrol *kcontrol,
371*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
374*4882a593Smuzhiyun 	struct snd_usb_audio *chip = elem->head.mixer->chip;
375*4882a593Smuzhiyun 	char buf[sizeof(mix_msg_in)];
376*4882a593Smuzhiyun 	int val, err;
377*4882a593Smuzhiyun 	int index = ucontrol->id.index;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0];
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	/* sanity check */
382*4882a593Smuzhiyun 	if (val < SND_US16X08_KCMIN(kcontrol)
383*4882a593Smuzhiyun 		|| val > SND_US16X08_KCMAX(kcontrol))
384*4882a593Smuzhiyun 		return -EINVAL;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	/* prepare URB message from template */
387*4882a593Smuzhiyun 	memcpy(buf, mix_msg_in, sizeof(mix_msg_in));
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	/* add the bias to the new value */
390*4882a593Smuzhiyun 	buf[8] = val - SND_US16X08_KCBIAS(kcontrol);
391*4882a593Smuzhiyun 	buf[6] = elem->head.id;
392*4882a593Smuzhiyun 	buf[5] = index + 1;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_in));
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	if (err > 0) {
397*4882a593Smuzhiyun 		elem->cached |= 1 << index;
398*4882a593Smuzhiyun 		elem->cache_val[index] = val;
399*4882a593Smuzhiyun 	} else {
400*4882a593Smuzhiyun 		usb_audio_dbg(chip, "Failed to set channel, err:%d\n", err);
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	return err > 0 ? 1 : 0;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun 
snd_us16x08_mix_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)406*4882a593Smuzhiyun static int snd_us16x08_mix_info(struct snd_kcontrol *kcontrol,
407*4882a593Smuzhiyun 	struct snd_ctl_elem_info *uinfo)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	uinfo->count = 1;
410*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
411*4882a593Smuzhiyun 	uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol);
412*4882a593Smuzhiyun 	uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol);
413*4882a593Smuzhiyun 	uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol);
414*4882a593Smuzhiyun 	return 0;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
snd_us16x08_comp_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)417*4882a593Smuzhiyun static int snd_us16x08_comp_get(struct snd_kcontrol *kcontrol,
418*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
421*4882a593Smuzhiyun 	struct snd_us16x08_comp_store *store = elem->private_data;
422*4882a593Smuzhiyun 	int index = ucontrol->id.index;
423*4882a593Smuzhiyun 	int val_idx = COMP_STORE_IDX(elem->head.id);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = store->val[val_idx][index];
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	return 0;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun 
snd_us16x08_comp_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)430*4882a593Smuzhiyun static int snd_us16x08_comp_put(struct snd_kcontrol *kcontrol,
431*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
434*4882a593Smuzhiyun 	struct snd_usb_audio *chip = elem->head.mixer->chip;
435*4882a593Smuzhiyun 	struct snd_us16x08_comp_store *store = elem->private_data;
436*4882a593Smuzhiyun 	int index = ucontrol->id.index;
437*4882a593Smuzhiyun 	char buf[sizeof(comp_msg)];
438*4882a593Smuzhiyun 	int val_idx, val;
439*4882a593Smuzhiyun 	int err;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0];
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	/* sanity check */
444*4882a593Smuzhiyun 	if (val < SND_US16X08_KCMIN(kcontrol)
445*4882a593Smuzhiyun 		|| val > SND_US16X08_KCMAX(kcontrol))
446*4882a593Smuzhiyun 		return -EINVAL;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	/* new control value incl. bias*/
449*4882a593Smuzhiyun 	val_idx = elem->head.id - SND_US16X08_ID_COMP_BASE;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	store->val[val_idx][index] = ucontrol->value.integer.value[0];
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	/* prepare compressor URB message from template  */
454*4882a593Smuzhiyun 	memcpy(buf, comp_msg, sizeof(comp_msg));
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	/* place comp values in message buffer watch bias! */
457*4882a593Smuzhiyun 	buf[8] = store->val[
458*4882a593Smuzhiyun 		COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD)][index]
459*4882a593Smuzhiyun 		- SND_US16X08_COMP_THRESHOLD_BIAS;
460*4882a593Smuzhiyun 	buf[11] = ratio_map[store->val[
461*4882a593Smuzhiyun 		COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO)][index]];
462*4882a593Smuzhiyun 	buf[14] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK)][index]
463*4882a593Smuzhiyun 		+ SND_US16X08_COMP_ATTACK_BIAS;
464*4882a593Smuzhiyun 	buf[17] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE)][index]
465*4882a593Smuzhiyun 		+ SND_US16X08_COMP_RELEASE_BIAS;
466*4882a593Smuzhiyun 	buf[20] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN)][index];
467*4882a593Smuzhiyun 	buf[26] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)][index];
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	/* place channel selector in message buffer */
470*4882a593Smuzhiyun 	buf[5] = index + 1;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	err = snd_us16x08_send_urb(chip, buf, sizeof(comp_msg));
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	if (err > 0) {
475*4882a593Smuzhiyun 		elem->cached |= 1 << index;
476*4882a593Smuzhiyun 		elem->cache_val[index] = val;
477*4882a593Smuzhiyun 	} else {
478*4882a593Smuzhiyun 		usb_audio_dbg(chip, "Failed to set compressor, err:%d\n", err);
479*4882a593Smuzhiyun 	}
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	return 1;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun 
snd_us16x08_eqswitch_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)484*4882a593Smuzhiyun static int snd_us16x08_eqswitch_get(struct snd_kcontrol *kcontrol,
485*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun 	int val;
488*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
489*4882a593Smuzhiyun 	struct snd_us16x08_eq_store *store = elem->private_data;
490*4882a593Smuzhiyun 	int index = ucontrol->id.index;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	/* get low switch from cache is enough, cause all bands are together */
493*4882a593Smuzhiyun 	val = store->val[EQ_STORE_BAND_IDX(elem->head.id)]
494*4882a593Smuzhiyun 		[EQ_STORE_PARAM_IDX(elem->head.id)][index];
495*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = val;
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	return 0;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun 
snd_us16x08_eqswitch_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)500*4882a593Smuzhiyun static int snd_us16x08_eqswitch_put(struct snd_kcontrol *kcontrol,
501*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
504*4882a593Smuzhiyun 	struct snd_usb_audio *chip = elem->head.mixer->chip;
505*4882a593Smuzhiyun 	struct snd_us16x08_eq_store *store = elem->private_data;
506*4882a593Smuzhiyun 	int index = ucontrol->id.index;
507*4882a593Smuzhiyun 	char buf[sizeof(eqs_msq)];
508*4882a593Smuzhiyun 	int val, err = 0;
509*4882a593Smuzhiyun 	int b_idx;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	/* new control value incl. bias*/
512*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0] + SND_US16X08_KCBIAS(kcontrol);
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	/* prepare URB message from EQ template */
515*4882a593Smuzhiyun 	memcpy(buf, eqs_msq, sizeof(eqs_msq));
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	/* place channel index in URB message */
518*4882a593Smuzhiyun 	buf[5] = index + 1;
519*4882a593Smuzhiyun 	for (b_idx = 0; b_idx < SND_US16X08_ID_EQ_BAND_COUNT; b_idx++) {
520*4882a593Smuzhiyun 		/* all four EQ bands have to be enabled/disabled in once */
521*4882a593Smuzhiyun 		buf[20] = val;
522*4882a593Smuzhiyun 		buf[17] = store->val[b_idx][2][index];
523*4882a593Smuzhiyun 		buf[14] = store->val[b_idx][1][index];
524*4882a593Smuzhiyun 		buf[11] = store->val[b_idx][0][index];
525*4882a593Smuzhiyun 		buf[8] = b_idx + 1;
526*4882a593Smuzhiyun 		err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
527*4882a593Smuzhiyun 		if (err < 0)
528*4882a593Smuzhiyun 			break;
529*4882a593Smuzhiyun 		store->val[b_idx][3][index] = val;
530*4882a593Smuzhiyun 		msleep(15);
531*4882a593Smuzhiyun 	}
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	if (err > 0) {
534*4882a593Smuzhiyun 		elem->cached |= 1 << index;
535*4882a593Smuzhiyun 		elem->cache_val[index] = val;
536*4882a593Smuzhiyun 	} else {
537*4882a593Smuzhiyun 		usb_audio_dbg(chip, "Failed to set eq switch, err:%d\n", err);
538*4882a593Smuzhiyun 	}
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	return 1;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun 
snd_us16x08_eq_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)543*4882a593Smuzhiyun static int snd_us16x08_eq_get(struct snd_kcontrol *kcontrol,
544*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun 	int val;
547*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
548*4882a593Smuzhiyun 	struct snd_us16x08_eq_store *store = elem->private_data;
549*4882a593Smuzhiyun 	int index = ucontrol->id.index;
550*4882a593Smuzhiyun 	int b_idx = EQ_STORE_BAND_IDX(elem->head.id) - 1;
551*4882a593Smuzhiyun 	int p_idx = EQ_STORE_PARAM_IDX(elem->head.id);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	val = store->val[b_idx][p_idx][index];
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = val;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	return 0;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun 
snd_us16x08_eq_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)560*4882a593Smuzhiyun static int snd_us16x08_eq_put(struct snd_kcontrol *kcontrol,
561*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
564*4882a593Smuzhiyun 	struct snd_usb_audio *chip = elem->head.mixer->chip;
565*4882a593Smuzhiyun 	struct snd_us16x08_eq_store *store = elem->private_data;
566*4882a593Smuzhiyun 	int index = ucontrol->id.index;
567*4882a593Smuzhiyun 	char buf[sizeof(eqs_msq)];
568*4882a593Smuzhiyun 	int val, err;
569*4882a593Smuzhiyun 	int b_idx = EQ_STORE_BAND_IDX(elem->head.id) - 1;
570*4882a593Smuzhiyun 	int p_idx = EQ_STORE_PARAM_IDX(elem->head.id);
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0];
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	/* sanity check */
575*4882a593Smuzhiyun 	if (val < SND_US16X08_KCMIN(kcontrol)
576*4882a593Smuzhiyun 		|| val > SND_US16X08_KCMAX(kcontrol))
577*4882a593Smuzhiyun 		return -EINVAL;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	/* copy URB buffer from EQ template */
580*4882a593Smuzhiyun 	memcpy(buf, eqs_msq, sizeof(eqs_msq));
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	store->val[b_idx][p_idx][index] = val;
583*4882a593Smuzhiyun 	buf[20] = store->val[b_idx][3][index];
584*4882a593Smuzhiyun 	buf[17] = store->val[b_idx][2][index];
585*4882a593Smuzhiyun 	buf[14] = store->val[b_idx][1][index];
586*4882a593Smuzhiyun 	buf[11] = store->val[b_idx][0][index];
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	/* place channel index in URB buffer */
589*4882a593Smuzhiyun 	buf[5] = index + 1;
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	/* place EQ band in URB buffer */
592*4882a593Smuzhiyun 	buf[8] = b_idx + 1;
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	if (err > 0) {
597*4882a593Smuzhiyun 		/* store new value in EQ band cache */
598*4882a593Smuzhiyun 		elem->cached |= 1 << index;
599*4882a593Smuzhiyun 		elem->cache_val[index] = val;
600*4882a593Smuzhiyun 	} else {
601*4882a593Smuzhiyun 		usb_audio_dbg(chip, "Failed to set eq param, err:%d\n", err);
602*4882a593Smuzhiyun 	}
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	return 1;
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun 
snd_us16x08_meter_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)607*4882a593Smuzhiyun static int snd_us16x08_meter_info(struct snd_kcontrol *kcontrol,
608*4882a593Smuzhiyun 	struct snd_ctl_elem_info *uinfo)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun 	uinfo->count = 34;
611*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
612*4882a593Smuzhiyun 	uinfo->value.integer.max = 0x7FFF;
613*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	return 0;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun /* calculate compressor index for reduction level request */
snd_get_meter_comp_index(struct snd_us16x08_meter_store * store)619*4882a593Smuzhiyun static int snd_get_meter_comp_index(struct snd_us16x08_meter_store *store)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun 	int ret;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	/* any channel active */
624*4882a593Smuzhiyun 	if (store->comp_active_index) {
625*4882a593Smuzhiyun 		/* check for stereo link */
626*4882a593Smuzhiyun 		if (store->comp_active_index & 0x20) {
627*4882a593Smuzhiyun 			/* reset comp_index to left channel*/
628*4882a593Smuzhiyun 			if (store->comp_index -
629*4882a593Smuzhiyun 				store->comp_active_index > 1)
630*4882a593Smuzhiyun 				store->comp_index =
631*4882a593Smuzhiyun 				store->comp_active_index;
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 			ret = store->comp_index++ & 0x1F;
634*4882a593Smuzhiyun 		} else {
635*4882a593Smuzhiyun 			/* no stereo link */
636*4882a593Smuzhiyun 			ret = store->comp_active_index;
637*4882a593Smuzhiyun 		}
638*4882a593Smuzhiyun 	} else {
639*4882a593Smuzhiyun 		/* skip channels with no compressor active */
640*4882a593Smuzhiyun 		while (!store->comp_store->val[
641*4882a593Smuzhiyun 			COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)]
642*4882a593Smuzhiyun 			[store->comp_index - 1]
643*4882a593Smuzhiyun 			&& store->comp_index <= SND_US16X08_MAX_CHANNELS) {
644*4882a593Smuzhiyun 			store->comp_index++;
645*4882a593Smuzhiyun 		}
646*4882a593Smuzhiyun 		ret = store->comp_index++;
647*4882a593Smuzhiyun 		if (store->comp_index > SND_US16X08_MAX_CHANNELS)
648*4882a593Smuzhiyun 			store->comp_index = 1;
649*4882a593Smuzhiyun 	}
650*4882a593Smuzhiyun 	return ret;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun /* retrieve the meter level values from URB message */
get_meter_levels_from_urb(int s,struct snd_us16x08_meter_store * store,u8 * meter_urb)654*4882a593Smuzhiyun static void get_meter_levels_from_urb(int s,
655*4882a593Smuzhiyun 	struct snd_us16x08_meter_store *store,
656*4882a593Smuzhiyun 	u8 *meter_urb)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun 	int val = MUC2(meter_urb, s) + (MUC3(meter_urb, s) << 8);
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 &&
661*4882a593Smuzhiyun 		MUA2(meter_urb, s) == 0x04 && MUB0(meter_urb, s) == 0x62) {
662*4882a593Smuzhiyun 		if (MUC0(meter_urb, s) == 0x72)
663*4882a593Smuzhiyun 			store->meter_level[MUB2(meter_urb, s) - 1] = val;
664*4882a593Smuzhiyun 		if (MUC0(meter_urb, s) == 0xb2)
665*4882a593Smuzhiyun 			store->comp_level[MUB2(meter_urb, s) - 1] = val;
666*4882a593Smuzhiyun 	}
667*4882a593Smuzhiyun 	if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 &&
668*4882a593Smuzhiyun 		MUA2(meter_urb, s) == 0x02 && MUB0(meter_urb, s) == 0x62)
669*4882a593Smuzhiyun 		store->master_level[MUB2(meter_urb, s) - 1] = val;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun /* Function to retrieve current meter values from the device.
673*4882a593Smuzhiyun  *
674*4882a593Smuzhiyun  * The device needs to be polled for meter values with an initial
675*4882a593Smuzhiyun  * requests. It will return with a sequence of different meter value
676*4882a593Smuzhiyun  * packages. The first request (case 0:) initiate this meter response sequence.
677*4882a593Smuzhiyun  * After the third response, an additional request can be placed,
678*4882a593Smuzhiyun  * to retrieve compressor reduction level value for given channel. This round
679*4882a593Smuzhiyun  * trip channel selector will skip all inactive compressors.
680*4882a593Smuzhiyun  * A mixer can interrupt this round-trip by selecting one ore two (stereo-link)
681*4882a593Smuzhiyun  * specific channels.
682*4882a593Smuzhiyun  */
snd_us16x08_meter_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)683*4882a593Smuzhiyun static int snd_us16x08_meter_get(struct snd_kcontrol *kcontrol,
684*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun 	int i, set;
687*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
688*4882a593Smuzhiyun 	struct snd_usb_audio *chip = elem->head.mixer->chip;
689*4882a593Smuzhiyun 	struct snd_us16x08_meter_store *store = elem->private_data;
690*4882a593Smuzhiyun 	u8 meter_urb[64];
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	switch (kcontrol->private_value) {
693*4882a593Smuzhiyun 	case 0: {
694*4882a593Smuzhiyun 		char tmp[sizeof(mix_init_msg1)];
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 		memcpy(tmp, mix_init_msg1, sizeof(mix_init_msg1));
697*4882a593Smuzhiyun 		snd_us16x08_send_urb(chip, tmp, 4);
698*4882a593Smuzhiyun 		snd_us16x08_recv_urb(chip, meter_urb,
699*4882a593Smuzhiyun 			sizeof(meter_urb));
700*4882a593Smuzhiyun 		kcontrol->private_value++;
701*4882a593Smuzhiyun 		break;
702*4882a593Smuzhiyun 	}
703*4882a593Smuzhiyun 	case 1:
704*4882a593Smuzhiyun 		snd_us16x08_recv_urb(chip, meter_urb,
705*4882a593Smuzhiyun 			sizeof(meter_urb));
706*4882a593Smuzhiyun 		kcontrol->private_value++;
707*4882a593Smuzhiyun 		break;
708*4882a593Smuzhiyun 	case 2:
709*4882a593Smuzhiyun 		snd_us16x08_recv_urb(chip, meter_urb,
710*4882a593Smuzhiyun 			sizeof(meter_urb));
711*4882a593Smuzhiyun 		kcontrol->private_value++;
712*4882a593Smuzhiyun 		break;
713*4882a593Smuzhiyun 	case 3: {
714*4882a593Smuzhiyun 		char tmp[sizeof(mix_init_msg2)];
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 		memcpy(tmp, mix_init_msg2, sizeof(mix_init_msg2));
717*4882a593Smuzhiyun 		tmp[2] = snd_get_meter_comp_index(store);
718*4882a593Smuzhiyun 		snd_us16x08_send_urb(chip, tmp, 10);
719*4882a593Smuzhiyun 		snd_us16x08_recv_urb(chip, meter_urb,
720*4882a593Smuzhiyun 			sizeof(meter_urb));
721*4882a593Smuzhiyun 		kcontrol->private_value = 0;
722*4882a593Smuzhiyun 		break;
723*4882a593Smuzhiyun 	}
724*4882a593Smuzhiyun 	}
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	for (set = 0; set < 6; set++)
727*4882a593Smuzhiyun 		get_meter_levels_from_urb(set, store, meter_urb);
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
730*4882a593Smuzhiyun 		ucontrol->value.integer.value[i] =
731*4882a593Smuzhiyun 			store ? store->meter_level[i] : 0;
732*4882a593Smuzhiyun 	}
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	ucontrol->value.integer.value[i++] = store ? store->master_level[0] : 0;
735*4882a593Smuzhiyun 	ucontrol->value.integer.value[i++] = store ? store->master_level[1] : 0;
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 	for (i = 2; i < SND_US16X08_MAX_CHANNELS + 2; i++)
738*4882a593Smuzhiyun 		ucontrol->value.integer.value[i + SND_US16X08_MAX_CHANNELS] =
739*4882a593Smuzhiyun 		store ? store->comp_level[i - 2] : 0;
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	return 1;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun 
snd_us16x08_meter_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)744*4882a593Smuzhiyun static int snd_us16x08_meter_put(struct snd_kcontrol *kcontrol,
745*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
746*4882a593Smuzhiyun {
747*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kcontrol->private_data;
748*4882a593Smuzhiyun 	struct snd_us16x08_meter_store *store = elem->private_data;
749*4882a593Smuzhiyun 	int val;
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0];
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	/* sanity check */
754*4882a593Smuzhiyun 	if (val < 0 || val >= SND_US16X08_MAX_CHANNELS)
755*4882a593Smuzhiyun 		return -EINVAL;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	store->comp_active_index = val;
758*4882a593Smuzhiyun 	store->comp_index = val;
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 	return 1;
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_ch_boolean_ctl = {
764*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
765*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
766*4882a593Smuzhiyun 	.count = 16,
767*4882a593Smuzhiyun 	.info = snd_us16x08_switch_info,
768*4882a593Smuzhiyun 	.get = snd_us16x08_channel_get,
769*4882a593Smuzhiyun 	.put = snd_us16x08_channel_put,
770*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
771*4882a593Smuzhiyun };
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_ch_int_ctl = {
774*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
775*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
776*4882a593Smuzhiyun 	.count = 16,
777*4882a593Smuzhiyun 	.info = snd_us16x08_mix_info,
778*4882a593Smuzhiyun 	.get = snd_us16x08_channel_get,
779*4882a593Smuzhiyun 	.put = snd_us16x08_channel_put,
780*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 133)
781*4882a593Smuzhiyun };
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_pan_int_ctl = {
784*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
785*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
786*4882a593Smuzhiyun 	.count = 16,
787*4882a593Smuzhiyun 	.info = snd_us16x08_mix_info,
788*4882a593Smuzhiyun 	.get = snd_us16x08_channel_get,
789*4882a593Smuzhiyun 	.put = snd_us16x08_channel_put,
790*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 255)
791*4882a593Smuzhiyun };
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_master_ctl = {
794*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
795*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
796*4882a593Smuzhiyun 	.count = 1,
797*4882a593Smuzhiyun 	.info = snd_us16x08_master_info,
798*4882a593Smuzhiyun 	.get = snd_us16x08_master_get,
799*4882a593Smuzhiyun 	.put = snd_us16x08_master_put,
800*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 133)
801*4882a593Smuzhiyun };
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_route_ctl = {
804*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
805*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
806*4882a593Smuzhiyun 	.count = 8,
807*4882a593Smuzhiyun 	.info = snd_us16x08_route_info,
808*4882a593Smuzhiyun 	.get = snd_us16x08_route_get,
809*4882a593Smuzhiyun 	.put = snd_us16x08_route_put,
810*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 9)
811*4882a593Smuzhiyun };
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_bus_ctl = {
814*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
815*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
816*4882a593Smuzhiyun 	.count = 1,
817*4882a593Smuzhiyun 	.info = snd_us16x08_switch_info,
818*4882a593Smuzhiyun 	.get = snd_us16x08_bus_get,
819*4882a593Smuzhiyun 	.put = snd_us16x08_bus_put,
820*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
821*4882a593Smuzhiyun };
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_compswitch_ctl = {
824*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
825*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
826*4882a593Smuzhiyun 	.count = 16,
827*4882a593Smuzhiyun 	.info = snd_us16x08_switch_info,
828*4882a593Smuzhiyun 	.get = snd_us16x08_comp_get,
829*4882a593Smuzhiyun 	.put = snd_us16x08_comp_put,
830*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
831*4882a593Smuzhiyun };
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_comp_threshold_ctl = {
834*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
835*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
836*4882a593Smuzhiyun 	.count = 16,
837*4882a593Smuzhiyun 	.info = snd_us16x08_mix_info,
838*4882a593Smuzhiyun 	.get = snd_us16x08_comp_get,
839*4882a593Smuzhiyun 	.put = snd_us16x08_comp_put,
840*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_COMP_THRESHOLD_BIAS, 1,
841*4882a593Smuzhiyun 	0, 0x20)
842*4882a593Smuzhiyun };
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_comp_ratio_ctl = {
845*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
846*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
847*4882a593Smuzhiyun 	.count = 16,
848*4882a593Smuzhiyun 	.info = snd_us16x08_mix_info,
849*4882a593Smuzhiyun 	.get = snd_us16x08_comp_get,
850*4882a593Smuzhiyun 	.put = snd_us16x08_comp_put,
851*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0,
852*4882a593Smuzhiyun 	sizeof(ratio_map) - 1), /*max*/
853*4882a593Smuzhiyun };
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_comp_gain_ctl = {
856*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
857*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
858*4882a593Smuzhiyun 	.count = 16,
859*4882a593Smuzhiyun 	.info = snd_us16x08_mix_info,
860*4882a593Smuzhiyun 	.get = snd_us16x08_comp_get,
861*4882a593Smuzhiyun 	.put = snd_us16x08_comp_put,
862*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x14)
863*4882a593Smuzhiyun };
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_comp_attack_ctl = {
866*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
867*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
868*4882a593Smuzhiyun 	.count = 16,
869*4882a593Smuzhiyun 	.info = snd_us16x08_mix_info,
870*4882a593Smuzhiyun 	.get = snd_us16x08_comp_get,
871*4882a593Smuzhiyun 	.put = snd_us16x08_comp_put,
872*4882a593Smuzhiyun 	.private_value =
873*4882a593Smuzhiyun 	SND_US16X08_KCSET(SND_US16X08_COMP_ATTACK_BIAS, 1, 0, 0xc6),
874*4882a593Smuzhiyun };
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_comp_release_ctl = {
877*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
878*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
879*4882a593Smuzhiyun 	.count = 16,
880*4882a593Smuzhiyun 	.info = snd_us16x08_mix_info,
881*4882a593Smuzhiyun 	.get = snd_us16x08_comp_get,
882*4882a593Smuzhiyun 	.put = snd_us16x08_comp_put,
883*4882a593Smuzhiyun 	.private_value =
884*4882a593Smuzhiyun 	SND_US16X08_KCSET(SND_US16X08_COMP_RELEASE_BIAS, 1, 0, 0x63),
885*4882a593Smuzhiyun };
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_eq_gain_ctl = {
888*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
889*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
890*4882a593Smuzhiyun 	.count = 16,
891*4882a593Smuzhiyun 	.info = snd_us16x08_mix_info,
892*4882a593Smuzhiyun 	.get = snd_us16x08_eq_get,
893*4882a593Smuzhiyun 	.put = snd_us16x08_eq_put,
894*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 24),
895*4882a593Smuzhiyun };
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_eq_low_freq_ctl = {
898*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
899*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
900*4882a593Smuzhiyun 	.count = 16,
901*4882a593Smuzhiyun 	.info = snd_us16x08_mix_info,
902*4882a593Smuzhiyun 	.get = snd_us16x08_eq_get,
903*4882a593Smuzhiyun 	.put = snd_us16x08_eq_put,
904*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x1F),
905*4882a593Smuzhiyun };
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_eq_mid_freq_ctl = {
908*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
909*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
910*4882a593Smuzhiyun 	.count = 16,
911*4882a593Smuzhiyun 	.info = snd_us16x08_mix_info,
912*4882a593Smuzhiyun 	.get = snd_us16x08_eq_get,
913*4882a593Smuzhiyun 	.put = snd_us16x08_eq_put,
914*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x3F)
915*4882a593Smuzhiyun };
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_eq_mid_width_ctl = {
918*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
919*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
920*4882a593Smuzhiyun 	.count = 16,
921*4882a593Smuzhiyun 	.info = snd_us16x08_mix_info,
922*4882a593Smuzhiyun 	.get = snd_us16x08_eq_get,
923*4882a593Smuzhiyun 	.put = snd_us16x08_eq_put,
924*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x06)
925*4882a593Smuzhiyun };
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_eq_high_freq_ctl = {
928*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
929*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
930*4882a593Smuzhiyun 	.count = 16,
931*4882a593Smuzhiyun 	.info = snd_us16x08_mix_info,
932*4882a593Smuzhiyun 	.get = snd_us16x08_eq_get,
933*4882a593Smuzhiyun 	.put = snd_us16x08_eq_put,
934*4882a593Smuzhiyun 	.private_value =
935*4882a593Smuzhiyun 	SND_US16X08_KCSET(SND_US16X08_EQ_HIGHFREQ_BIAS, 1, 0, 0x1F)
936*4882a593Smuzhiyun };
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_eq_switch_ctl = {
939*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
940*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
941*4882a593Smuzhiyun 	.count = 16,
942*4882a593Smuzhiyun 	.info = snd_us16x08_switch_info,
943*4882a593Smuzhiyun 	.get = snd_us16x08_eqswitch_get,
944*4882a593Smuzhiyun 	.put = snd_us16x08_eqswitch_put,
945*4882a593Smuzhiyun 	.private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
946*4882a593Smuzhiyun };
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_us16x08_meter_ctl = {
949*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
950*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
951*4882a593Smuzhiyun 	.count = 1,
952*4882a593Smuzhiyun 	.info = snd_us16x08_meter_info,
953*4882a593Smuzhiyun 	.get = snd_us16x08_meter_get,
954*4882a593Smuzhiyun 	.put = snd_us16x08_meter_put
955*4882a593Smuzhiyun };
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun /* control store preparation */
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun /* setup compressor store and assign default value */
snd_us16x08_create_comp_store(void)960*4882a593Smuzhiyun static struct snd_us16x08_comp_store *snd_us16x08_create_comp_store(void)
961*4882a593Smuzhiyun {
962*4882a593Smuzhiyun 	int i;
963*4882a593Smuzhiyun 	struct snd_us16x08_comp_store *tmp;
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
966*4882a593Smuzhiyun 	if (!tmp)
967*4882a593Smuzhiyun 		return NULL;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
970*4882a593Smuzhiyun 		tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD)][i]
971*4882a593Smuzhiyun 			= 0x20;
972*4882a593Smuzhiyun 		tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO)][i] = 0x00;
973*4882a593Smuzhiyun 		tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN)][i] = 0x00;
974*4882a593Smuzhiyun 		tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)][i] = 0x00;
975*4882a593Smuzhiyun 		tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK)][i] = 0x00;
976*4882a593Smuzhiyun 		tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE)][i] = 0x00;
977*4882a593Smuzhiyun 	}
978*4882a593Smuzhiyun 	return tmp;
979*4882a593Smuzhiyun }
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun /* setup EQ store and assign default values */
snd_us16x08_create_eq_store(void)982*4882a593Smuzhiyun static struct snd_us16x08_eq_store *snd_us16x08_create_eq_store(void)
983*4882a593Smuzhiyun {
984*4882a593Smuzhiyun 	int i, b_idx;
985*4882a593Smuzhiyun 	struct snd_us16x08_eq_store *tmp;
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 	tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
988*4882a593Smuzhiyun 	if (!tmp)
989*4882a593Smuzhiyun 		return NULL;
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun 	for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
992*4882a593Smuzhiyun 		for (b_idx = 0; b_idx < SND_US16X08_ID_EQ_BAND_COUNT; b_idx++) {
993*4882a593Smuzhiyun 			tmp->val[b_idx][0][i] = 0x0c;
994*4882a593Smuzhiyun 			tmp->val[b_idx][3][i] = 0x00;
995*4882a593Smuzhiyun 			switch (b_idx) {
996*4882a593Smuzhiyun 			case 0: /* EQ Low */
997*4882a593Smuzhiyun 				tmp->val[b_idx][1][i] = 0x05;
998*4882a593Smuzhiyun 				tmp->val[b_idx][2][i] = 0xff;
999*4882a593Smuzhiyun 				break;
1000*4882a593Smuzhiyun 			case 1: /* EQ Mid low */
1001*4882a593Smuzhiyun 				tmp->val[b_idx][1][i] = 0x0e;
1002*4882a593Smuzhiyun 				tmp->val[b_idx][2][i] = 0x02;
1003*4882a593Smuzhiyun 				break;
1004*4882a593Smuzhiyun 			case 2: /* EQ Mid High */
1005*4882a593Smuzhiyun 				tmp->val[b_idx][1][i] = 0x1b;
1006*4882a593Smuzhiyun 				tmp->val[b_idx][2][i] = 0x02;
1007*4882a593Smuzhiyun 				break;
1008*4882a593Smuzhiyun 			case 3: /* EQ High */
1009*4882a593Smuzhiyun 				tmp->val[b_idx][1][i] = 0x2f
1010*4882a593Smuzhiyun 					- SND_US16X08_EQ_HIGHFREQ_BIAS;
1011*4882a593Smuzhiyun 				tmp->val[b_idx][2][i] = 0xff;
1012*4882a593Smuzhiyun 				break;
1013*4882a593Smuzhiyun 			}
1014*4882a593Smuzhiyun 		}
1015*4882a593Smuzhiyun 	}
1016*4882a593Smuzhiyun 	return tmp;
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun 
snd_us16x08_create_meter_store(void)1019*4882a593Smuzhiyun static struct snd_us16x08_meter_store *snd_us16x08_create_meter_store(void)
1020*4882a593Smuzhiyun {
1021*4882a593Smuzhiyun 	struct snd_us16x08_meter_store *tmp;
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
1024*4882a593Smuzhiyun 	if (!tmp)
1025*4882a593Smuzhiyun 		return NULL;
1026*4882a593Smuzhiyun 	tmp->comp_index = 1;
1027*4882a593Smuzhiyun 	tmp->comp_active_index = 0;
1028*4882a593Smuzhiyun 	return tmp;
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun /* release elem->private_free as well; called only once for each *_store */
elem_private_free(struct snd_kcontrol * kctl)1032*4882a593Smuzhiyun static void elem_private_free(struct snd_kcontrol *kctl)
1033*4882a593Smuzhiyun {
1034*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem = kctl->private_data;
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	if (elem)
1037*4882a593Smuzhiyun 		kfree(elem->private_data);
1038*4882a593Smuzhiyun 	kfree(elem);
1039*4882a593Smuzhiyun 	kctl->private_data = NULL;
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun 
add_new_ctl(struct usb_mixer_interface * mixer,const struct snd_kcontrol_new * ncontrol,int index,int val_type,int channels,const char * name,void * opt,bool do_private_free,struct usb_mixer_elem_info ** elem_ret)1042*4882a593Smuzhiyun static int add_new_ctl(struct usb_mixer_interface *mixer,
1043*4882a593Smuzhiyun 	const struct snd_kcontrol_new *ncontrol,
1044*4882a593Smuzhiyun 	int index, int val_type, int channels,
1045*4882a593Smuzhiyun 	const char *name, void *opt,
1046*4882a593Smuzhiyun 	bool do_private_free,
1047*4882a593Smuzhiyun 	struct usb_mixer_elem_info **elem_ret)
1048*4882a593Smuzhiyun {
1049*4882a593Smuzhiyun 	struct snd_kcontrol *kctl;
1050*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem;
1051*4882a593Smuzhiyun 	int err;
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun 	usb_audio_dbg(mixer->chip, "us16x08 add mixer %s\n", name);
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun 	elem = kzalloc(sizeof(*elem), GFP_KERNEL);
1056*4882a593Smuzhiyun 	if (!elem)
1057*4882a593Smuzhiyun 		return -ENOMEM;
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun 	elem->head.mixer = mixer;
1060*4882a593Smuzhiyun 	elem->head.resume = NULL;
1061*4882a593Smuzhiyun 	elem->control = 0;
1062*4882a593Smuzhiyun 	elem->idx_off = 0;
1063*4882a593Smuzhiyun 	elem->head.id = index;
1064*4882a593Smuzhiyun 	elem->val_type = val_type;
1065*4882a593Smuzhiyun 	elem->channels = channels;
1066*4882a593Smuzhiyun 	elem->private_data = opt;
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	kctl = snd_ctl_new1(ncontrol, elem);
1069*4882a593Smuzhiyun 	if (!kctl) {
1070*4882a593Smuzhiyun 		kfree(elem);
1071*4882a593Smuzhiyun 		return -ENOMEM;
1072*4882a593Smuzhiyun 	}
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	if (do_private_free)
1075*4882a593Smuzhiyun 		kctl->private_free = elem_private_free;
1076*4882a593Smuzhiyun 	else
1077*4882a593Smuzhiyun 		kctl->private_free = snd_usb_mixer_elem_free;
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 	strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
1080*4882a593Smuzhiyun 
1081*4882a593Smuzhiyun 	err = snd_usb_mixer_add_control(&elem->head, kctl);
1082*4882a593Smuzhiyun 	if (err < 0)
1083*4882a593Smuzhiyun 		return err;
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	if (elem_ret)
1086*4882a593Smuzhiyun 		*elem_ret = elem;
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun 	return 0;
1089*4882a593Smuzhiyun }
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun /* table of EQ controls */
1092*4882a593Smuzhiyun static const struct snd_us16x08_control_params eq_controls[] = {
1093*4882a593Smuzhiyun 	{ /* EQ switch */
1094*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_eq_switch_ctl,
1095*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_EQENABLE,
1096*4882a593Smuzhiyun 		.type = USB_MIXER_BOOLEAN,
1097*4882a593Smuzhiyun 		.num_channels = 16,
1098*4882a593Smuzhiyun 		.name = "EQ Switch",
1099*4882a593Smuzhiyun 	},
1100*4882a593Smuzhiyun 	{ /* EQ low gain */
1101*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_eq_gain_ctl,
1102*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_EQLOWLEVEL,
1103*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1104*4882a593Smuzhiyun 		.num_channels = 16,
1105*4882a593Smuzhiyun 		.name = "EQ Low Volume",
1106*4882a593Smuzhiyun 	},
1107*4882a593Smuzhiyun 	{ /* EQ low freq */
1108*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_eq_low_freq_ctl,
1109*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_EQLOWFREQ,
1110*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1111*4882a593Smuzhiyun 		.num_channels = 16,
1112*4882a593Smuzhiyun 		.name = "EQ Low Frequency",
1113*4882a593Smuzhiyun 	},
1114*4882a593Smuzhiyun 	{ /* EQ mid low gain */
1115*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_eq_gain_ctl,
1116*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_EQLOWMIDLEVEL,
1117*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1118*4882a593Smuzhiyun 		.num_channels = 16,
1119*4882a593Smuzhiyun 		.name = "EQ MidLow Volume",
1120*4882a593Smuzhiyun 	},
1121*4882a593Smuzhiyun 	{ /* EQ mid low freq */
1122*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_eq_mid_freq_ctl,
1123*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_EQLOWMIDFREQ,
1124*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1125*4882a593Smuzhiyun 		.num_channels = 16,
1126*4882a593Smuzhiyun 		.name = "EQ MidLow Frequency",
1127*4882a593Smuzhiyun 	},
1128*4882a593Smuzhiyun 	{ /* EQ mid low Q */
1129*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
1130*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_EQLOWMIDWIDTH,
1131*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1132*4882a593Smuzhiyun 		.num_channels = 16,
1133*4882a593Smuzhiyun 		.name = "EQ MidLow Q",
1134*4882a593Smuzhiyun 	},
1135*4882a593Smuzhiyun 	{ /* EQ mid high gain */
1136*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_eq_gain_ctl,
1137*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_EQHIGHMIDLEVEL,
1138*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1139*4882a593Smuzhiyun 		.num_channels = 16,
1140*4882a593Smuzhiyun 		.name = "EQ MidHigh Volume",
1141*4882a593Smuzhiyun 	},
1142*4882a593Smuzhiyun 	{ /* EQ mid high freq */
1143*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_eq_mid_freq_ctl,
1144*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_EQHIGHMIDFREQ,
1145*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1146*4882a593Smuzhiyun 		.num_channels = 16,
1147*4882a593Smuzhiyun 		.name = "EQ MidHigh Frequency",
1148*4882a593Smuzhiyun 	},
1149*4882a593Smuzhiyun 	{ /* EQ mid high Q */
1150*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
1151*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_EQHIGHMIDWIDTH,
1152*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1153*4882a593Smuzhiyun 		.num_channels = 16,
1154*4882a593Smuzhiyun 		.name = "EQ MidHigh Q",
1155*4882a593Smuzhiyun 	},
1156*4882a593Smuzhiyun 	{ /* EQ high gain */
1157*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_eq_gain_ctl,
1158*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_EQHIGHLEVEL,
1159*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1160*4882a593Smuzhiyun 		.num_channels = 16,
1161*4882a593Smuzhiyun 		.name = "EQ High Volume",
1162*4882a593Smuzhiyun 	},
1163*4882a593Smuzhiyun 	{ /* EQ low freq */
1164*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_eq_high_freq_ctl,
1165*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_EQHIGHFREQ,
1166*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1167*4882a593Smuzhiyun 		.num_channels = 16,
1168*4882a593Smuzhiyun 		.name = "EQ High Frequency",
1169*4882a593Smuzhiyun 	},
1170*4882a593Smuzhiyun };
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun /* table of compressor controls */
1173*4882a593Smuzhiyun static const struct snd_us16x08_control_params comp_controls[] = {
1174*4882a593Smuzhiyun 	{ /* Comp enable */
1175*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_compswitch_ctl,
1176*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_COMP_SWITCH,
1177*4882a593Smuzhiyun 		.type = USB_MIXER_BOOLEAN,
1178*4882a593Smuzhiyun 		.num_channels = 16,
1179*4882a593Smuzhiyun 		.name = "Compressor Switch",
1180*4882a593Smuzhiyun 	},
1181*4882a593Smuzhiyun 	{ /* Comp threshold */
1182*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_comp_threshold_ctl,
1183*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_COMP_THRESHOLD,
1184*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1185*4882a593Smuzhiyun 		.num_channels = 16,
1186*4882a593Smuzhiyun 		.name = "Compressor Threshold Volume",
1187*4882a593Smuzhiyun 	},
1188*4882a593Smuzhiyun 	{ /* Comp ratio */
1189*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_comp_ratio_ctl,
1190*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_COMP_RATIO,
1191*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1192*4882a593Smuzhiyun 		.num_channels = 16,
1193*4882a593Smuzhiyun 		.name = "Compressor Ratio",
1194*4882a593Smuzhiyun 	},
1195*4882a593Smuzhiyun 	{ /* Comp attack */
1196*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_comp_attack_ctl,
1197*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_COMP_ATTACK,
1198*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1199*4882a593Smuzhiyun 		.num_channels = 16,
1200*4882a593Smuzhiyun 		.name = "Compressor Attack",
1201*4882a593Smuzhiyun 	},
1202*4882a593Smuzhiyun 	{ /* Comp release */
1203*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_comp_release_ctl,
1204*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_COMP_RELEASE,
1205*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1206*4882a593Smuzhiyun 		.num_channels = 16,
1207*4882a593Smuzhiyun 		.name = "Compressor Release",
1208*4882a593Smuzhiyun 	},
1209*4882a593Smuzhiyun 	{ /* Comp gain */
1210*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_comp_gain_ctl,
1211*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_COMP_GAIN,
1212*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1213*4882a593Smuzhiyun 		.num_channels = 16,
1214*4882a593Smuzhiyun 		.name = "Compressor Volume",
1215*4882a593Smuzhiyun 	},
1216*4882a593Smuzhiyun };
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun /* table of channel controls */
1219*4882a593Smuzhiyun static const struct snd_us16x08_control_params channel_controls[] = {
1220*4882a593Smuzhiyun 	{ /* Phase */
1221*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_ch_boolean_ctl,
1222*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_PHASE,
1223*4882a593Smuzhiyun 		.type = USB_MIXER_BOOLEAN,
1224*4882a593Smuzhiyun 		.num_channels = 16,
1225*4882a593Smuzhiyun 		.name = "Phase Switch",
1226*4882a593Smuzhiyun 		.default_val = 0
1227*4882a593Smuzhiyun 	},
1228*4882a593Smuzhiyun 	{ /* Fader */
1229*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_ch_int_ctl,
1230*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_FADER,
1231*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1232*4882a593Smuzhiyun 		.num_channels = 16,
1233*4882a593Smuzhiyun 		.name = "Line Volume",
1234*4882a593Smuzhiyun 		.default_val = 127
1235*4882a593Smuzhiyun 	},
1236*4882a593Smuzhiyun 	{ /* Mute */
1237*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_ch_boolean_ctl,
1238*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_MUTE,
1239*4882a593Smuzhiyun 		.type = USB_MIXER_BOOLEAN,
1240*4882a593Smuzhiyun 		.num_channels = 16,
1241*4882a593Smuzhiyun 		.name = "Mute Switch",
1242*4882a593Smuzhiyun 		.default_val = 0
1243*4882a593Smuzhiyun 	},
1244*4882a593Smuzhiyun 	{ /* Pan */
1245*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_pan_int_ctl,
1246*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_PAN,
1247*4882a593Smuzhiyun 		.type = USB_MIXER_U16,
1248*4882a593Smuzhiyun 		.num_channels = 16,
1249*4882a593Smuzhiyun 		.name = "Pan Left-Right Volume",
1250*4882a593Smuzhiyun 		.default_val = 127
1251*4882a593Smuzhiyun 	},
1252*4882a593Smuzhiyun };
1253*4882a593Smuzhiyun 
1254*4882a593Smuzhiyun /* table of master controls */
1255*4882a593Smuzhiyun static const struct snd_us16x08_control_params master_controls[] = {
1256*4882a593Smuzhiyun 	{ /* Master */
1257*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_master_ctl,
1258*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_FADER,
1259*4882a593Smuzhiyun 		.type = USB_MIXER_U8,
1260*4882a593Smuzhiyun 		.num_channels = 16,
1261*4882a593Smuzhiyun 		.name = "Master Volume",
1262*4882a593Smuzhiyun 		.default_val = 127
1263*4882a593Smuzhiyun 	},
1264*4882a593Smuzhiyun 	{ /* Bypass */
1265*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_bus_ctl,
1266*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_BYPASS,
1267*4882a593Smuzhiyun 		.type = USB_MIXER_BOOLEAN,
1268*4882a593Smuzhiyun 		.num_channels = 16,
1269*4882a593Smuzhiyun 		.name = "DSP Bypass Switch",
1270*4882a593Smuzhiyun 		.default_val = 0
1271*4882a593Smuzhiyun 	},
1272*4882a593Smuzhiyun 	{ /* Buss out */
1273*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_bus_ctl,
1274*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_BUSS_OUT,
1275*4882a593Smuzhiyun 		.type = USB_MIXER_BOOLEAN,
1276*4882a593Smuzhiyun 		.num_channels = 16,
1277*4882a593Smuzhiyun 		.name = "Buss Out Switch",
1278*4882a593Smuzhiyun 		.default_val = 0
1279*4882a593Smuzhiyun 	},
1280*4882a593Smuzhiyun 	{ /* Master mute */
1281*4882a593Smuzhiyun 		.kcontrol_new = &snd_us16x08_bus_ctl,
1282*4882a593Smuzhiyun 		.control_id = SND_US16X08_ID_MUTE,
1283*4882a593Smuzhiyun 		.type = USB_MIXER_BOOLEAN,
1284*4882a593Smuzhiyun 		.num_channels = 16,
1285*4882a593Smuzhiyun 		.name = "Master Mute Switch",
1286*4882a593Smuzhiyun 		.default_val = 0
1287*4882a593Smuzhiyun 	},
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun };
1290*4882a593Smuzhiyun 
snd_us16x08_controls_create(struct usb_mixer_interface * mixer)1291*4882a593Smuzhiyun int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
1292*4882a593Smuzhiyun {
1293*4882a593Smuzhiyun 	int i, j;
1294*4882a593Smuzhiyun 	int err;
1295*4882a593Smuzhiyun 	struct usb_mixer_elem_info *elem;
1296*4882a593Smuzhiyun 	struct snd_us16x08_comp_store *comp_store;
1297*4882a593Smuzhiyun 	struct snd_us16x08_meter_store *meter_store;
1298*4882a593Smuzhiyun 	struct snd_us16x08_eq_store *eq_store;
1299*4882a593Smuzhiyun 
1300*4882a593Smuzhiyun 	/* just check for non-MIDI interface */
1301*4882a593Smuzhiyun 	if (mixer->hostif->desc.bInterfaceNumber == 3) {
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun 		/* add routing control */
1304*4882a593Smuzhiyun 		err = add_new_ctl(mixer, &snd_us16x08_route_ctl,
1305*4882a593Smuzhiyun 			SND_US16X08_ID_ROUTE, USB_MIXER_U8, 8, "Line Out Route",
1306*4882a593Smuzhiyun 			NULL, false, &elem);
1307*4882a593Smuzhiyun 		if (err < 0) {
1308*4882a593Smuzhiyun 			usb_audio_dbg(mixer->chip,
1309*4882a593Smuzhiyun 				"Failed to create route control, err:%d\n",
1310*4882a593Smuzhiyun 				err);
1311*4882a593Smuzhiyun 			return err;
1312*4882a593Smuzhiyun 		}
1313*4882a593Smuzhiyun 		for (i = 0; i < 8; i++)
1314*4882a593Smuzhiyun 			elem->cache_val[i] = i < 2 ? i : i + 2;
1315*4882a593Smuzhiyun 		elem->cached = 0xff;
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun 		/* create compressor mixer elements */
1318*4882a593Smuzhiyun 		comp_store = snd_us16x08_create_comp_store();
1319*4882a593Smuzhiyun 		if (!comp_store)
1320*4882a593Smuzhiyun 			return -ENOMEM;
1321*4882a593Smuzhiyun 
1322*4882a593Smuzhiyun 		/* add master controls */
1323*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(master_controls); i++) {
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 			err = add_new_ctl(mixer,
1326*4882a593Smuzhiyun 				master_controls[i].kcontrol_new,
1327*4882a593Smuzhiyun 				master_controls[i].control_id,
1328*4882a593Smuzhiyun 				master_controls[i].type,
1329*4882a593Smuzhiyun 				master_controls[i].num_channels,
1330*4882a593Smuzhiyun 				master_controls[i].name,
1331*4882a593Smuzhiyun 				comp_store,
1332*4882a593Smuzhiyun 				i == 0, /* release comp_store only once */
1333*4882a593Smuzhiyun 				&elem);
1334*4882a593Smuzhiyun 			if (err < 0)
1335*4882a593Smuzhiyun 				return err;
1336*4882a593Smuzhiyun 			elem->cache_val[0] = master_controls[i].default_val;
1337*4882a593Smuzhiyun 			elem->cached = 1;
1338*4882a593Smuzhiyun 		}
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun 		/* add channel controls */
1341*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(channel_controls); i++) {
1342*4882a593Smuzhiyun 
1343*4882a593Smuzhiyun 			err = add_new_ctl(mixer,
1344*4882a593Smuzhiyun 				channel_controls[i].kcontrol_new,
1345*4882a593Smuzhiyun 				channel_controls[i].control_id,
1346*4882a593Smuzhiyun 				channel_controls[i].type,
1347*4882a593Smuzhiyun 				channel_controls[i].num_channels,
1348*4882a593Smuzhiyun 				channel_controls[i].name,
1349*4882a593Smuzhiyun 				comp_store,
1350*4882a593Smuzhiyun 				false, &elem);
1351*4882a593Smuzhiyun 			if (err < 0)
1352*4882a593Smuzhiyun 				return err;
1353*4882a593Smuzhiyun 			for (j = 0; j < SND_US16X08_MAX_CHANNELS; j++) {
1354*4882a593Smuzhiyun 				elem->cache_val[j] =
1355*4882a593Smuzhiyun 					channel_controls[i].default_val;
1356*4882a593Smuzhiyun 			}
1357*4882a593Smuzhiyun 			elem->cached = 0xffff;
1358*4882a593Smuzhiyun 		}
1359*4882a593Smuzhiyun 
1360*4882a593Smuzhiyun 		/* create eq store */
1361*4882a593Smuzhiyun 		eq_store = snd_us16x08_create_eq_store();
1362*4882a593Smuzhiyun 		if (!eq_store)
1363*4882a593Smuzhiyun 			return -ENOMEM;
1364*4882a593Smuzhiyun 
1365*4882a593Smuzhiyun 		/* add EQ controls */
1366*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(eq_controls); i++) {
1367*4882a593Smuzhiyun 
1368*4882a593Smuzhiyun 			err = add_new_ctl(mixer,
1369*4882a593Smuzhiyun 				eq_controls[i].kcontrol_new,
1370*4882a593Smuzhiyun 				eq_controls[i].control_id,
1371*4882a593Smuzhiyun 				eq_controls[i].type,
1372*4882a593Smuzhiyun 				eq_controls[i].num_channels,
1373*4882a593Smuzhiyun 				eq_controls[i].name,
1374*4882a593Smuzhiyun 				eq_store,
1375*4882a593Smuzhiyun 				i == 0, /* release eq_store only once */
1376*4882a593Smuzhiyun 				NULL);
1377*4882a593Smuzhiyun 			if (err < 0)
1378*4882a593Smuzhiyun 				return err;
1379*4882a593Smuzhiyun 		}
1380*4882a593Smuzhiyun 
1381*4882a593Smuzhiyun 		/* add compressor controls */
1382*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(comp_controls); i++) {
1383*4882a593Smuzhiyun 
1384*4882a593Smuzhiyun 			err = add_new_ctl(mixer,
1385*4882a593Smuzhiyun 				comp_controls[i].kcontrol_new,
1386*4882a593Smuzhiyun 				comp_controls[i].control_id,
1387*4882a593Smuzhiyun 				comp_controls[i].type,
1388*4882a593Smuzhiyun 				comp_controls[i].num_channels,
1389*4882a593Smuzhiyun 				comp_controls[i].name,
1390*4882a593Smuzhiyun 				comp_store,
1391*4882a593Smuzhiyun 				false, NULL);
1392*4882a593Smuzhiyun 			if (err < 0)
1393*4882a593Smuzhiyun 				return err;
1394*4882a593Smuzhiyun 		}
1395*4882a593Smuzhiyun 
1396*4882a593Smuzhiyun 		/* create meters store */
1397*4882a593Smuzhiyun 		meter_store = snd_us16x08_create_meter_store();
1398*4882a593Smuzhiyun 		if (!meter_store)
1399*4882a593Smuzhiyun 			return -ENOMEM;
1400*4882a593Smuzhiyun 
1401*4882a593Smuzhiyun 		/* meter function 'get' must access to compressor store
1402*4882a593Smuzhiyun 		 * so place a reference here
1403*4882a593Smuzhiyun 		 */
1404*4882a593Smuzhiyun 		meter_store->comp_store = comp_store;
1405*4882a593Smuzhiyun 		err = add_new_ctl(mixer, &snd_us16x08_meter_ctl,
1406*4882a593Smuzhiyun 			SND_US16X08_ID_METER, USB_MIXER_U16, 0, "Level Meter",
1407*4882a593Smuzhiyun 			meter_store, true, NULL);
1408*4882a593Smuzhiyun 		if (err < 0)
1409*4882a593Smuzhiyun 			return err;
1410*4882a593Smuzhiyun 	}
1411*4882a593Smuzhiyun 
1412*4882a593Smuzhiyun 	return 0;
1413*4882a593Smuzhiyun }
1414*4882a593Smuzhiyun 
1415