Blame view

sound/usb/mixer.c 61.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  /*
   *   (Tentative) USB Audio Driver for ALSA
   *
   *   Mixer control part
   *
   *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
   *
   *   Many codes borrowed from audio.c by
   *	    Alan Cox (alan@lxorguk.ukuu.org.uk)
   *	    Thomas Sailer (sailer@ife.ee.ethz.ch)
   *
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
   *   along with this program; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   *
   */
157a57b6f   Daniel Mack   ALSA: usb-audio: ...
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  /*
   * TODOs, for both the mixer and the streaming interfaces:
   *
   *  - support for UAC2 effect units
   *  - support for graphical equalizers
   *  - RANGE and MEM set commands (UAC2)
   *  - RANGE and MEM interrupt dispatchers (UAC2)
   *  - audio channel clustering (UAC2)
   *  - audio sample rate converter units (UAC2)
   *  - proper handling of clock multipliers (UAC2)
   *  - dispatch clock change notifications (UAC2)
   *  	- stop PCM streams which use a clock that became invalid
   *  	- stop PCM streams which use a clock selector that has changed
   *  	- parse available sample rates again when clock sources changed
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
48
  #include <linux/bitops.h>
  #include <linux/init.h>
  #include <linux/list.h>
  #include <linux/slab.h>
  #include <linux/string.h>
  #include <linux/usb.h>
28e1b7730   Daniel Mack   ALSA: usbaudio: p...
49
  #include <linux/usb/audio.h>
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
50
  #include <linux/usb/audio-v2.h>
28e1b7730   Daniel Mack   ALSA: usbaudio: p...
51

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
  #include <sound/core.h>
  #include <sound/control.h>
b259b10c4   Clemens Ladisch   [ALSA] usb-audio ...
54
  #include <sound/hwdep.h>
aafad5629   Clemens Ladisch   [ALSA] usb-audio ...
55
  #include <sound/info.h>
7bc5ba7e0   Takashi Iwai   [ALSA] Add TLV su...
56
  #include <sound/tlv.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
  
  #include "usbaudio.h"
f0b5e634f   Daniel Mack   ALSA: usbmixer: r...
59
  #include "mixer.h"
e5779998b   Daniel Mack   ALSA: usb-audio: ...
60
  #include "helper.h"
7b1eda223   Daniel Mack   ALSA: usb-mixer: ...
61
  #include "mixer_quirks.h"
88a8516a2   Oliver Neukum   ALSA: usbaudio: i...
62
  #include "power.h"
4d1a70dad   Raimonds Cicans   [ALSA] add suppor...
63

ebfdeea3d   Jaroslav Kysela   ALSA: usbmixer - ...
64
  #define MAX_ID_ELEMS	256
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
69
70
71
72
73
  struct usb_audio_term {
  	int id;
  	int type;
  	int channels;
  	unsigned int chconfig;
  	int name;
  };
  
  struct usbmix_name_map;
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
74
75
  struct mixer_build {
  	struct snd_usb_audio *chip;
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
76
  	struct usb_mixer_interface *mixer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
  	unsigned char *buffer;
  	unsigned int buflen;
291186e04   Jaroslav Kysela   ALSA: usbmixer - ...
79
  	DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS);
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
80
  	struct usb_audio_term oterm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  	const struct usbmix_name_map *map;
8e062ec71   Clemens Ladisch   [ALSA] usb-audio ...
82
  	const struct usbmix_selector_map *selector_map;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
  };
1cdfa9f34   Joseph Teichman   ALSA: usbaudio - ...
84
  /*E-mu 0202/0404/0204 eXtension Unit(XU) control*/
7d2b451e6   Sergiy Kovalchuk   ALSA: usb-audio -...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  enum {
  	USB_XU_CLOCK_RATE 		= 0xe301,
  	USB_XU_CLOCK_SOURCE		= 0xe302,
  	USB_XU_DIGITAL_IO_STATUS	= 0xe303,
  	USB_XU_DEVICE_OPTIONS		= 0xe304,
  	USB_XU_DIRECT_MONITORING	= 0xe305,
  	USB_XU_METERING			= 0xe306
  };
  enum {
  	USB_XU_CLOCK_SOURCE_SELECTOR = 0x02,	/* clock source*/
  	USB_XU_CLOCK_RATE_SELECTOR = 0x03,	/* clock rate */
  	USB_XU_DIGITAL_FORMAT_SELECTOR = 0x01,	/* the spdif format */
  	USB_XU_SOFT_LIMIT_SELECTOR = 0x03	/* soft limiter */
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
103
104
  
  /*
   * manual mapping of mixer names
   * if the mixer topology is too complicated and the parsed names are
   * ambiguous, add the entries in usbmixer_maps.c.
   */
f0b5e634f   Daniel Mack   ALSA: usbmixer: r...
105
  #include "mixer_maps.c"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106

c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
107
108
  static const struct usbmix_name_map *
  find_map(struct mixer_build *state, int unitid, int control)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  {
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
110
  	const struct usbmix_name_map *p = state->map;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111

c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
112
113
  	if (!p)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
  
  	for (p = state->map; p->id; p++) {
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
116
117
118
  		if (p->id == unitid &&
  		    (!control || !p->control || control == p->control))
  			return p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  	}
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
120
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  }
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
122
123
124
  /* get the mapped name if the unit matches */
  static int
  check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  {
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
126
127
  	if (!p || !p->name)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128

c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
129
130
131
132
133
134
135
136
137
  	buflen--;
  	return strlcpy(buf, p->name, buflen);
  }
  
  /* check whether the control should be ignored */
  static inline int
  check_ignored_ctl(const struct usbmix_name_map *p)
  {
  	if (!p || p->name || p->dB)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
  		return 0;
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
139
140
141
142
143
144
145
146
147
148
  	return 1;
  }
  
  /* dB mapping */
  static inline void check_mapped_dB(const struct usbmix_name_map *p,
  				   struct usb_mixer_elem_info *cval)
  {
  	if (p && p->dB) {
  		cval->dBmin = p->dB->min;
  		cval->dBmax = p->dB->max;
38b65190c   Takashi Iwai   ALSA: usb-audio -...
149
  		cval->initialized = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  }
8e062ec71   Clemens Ladisch   [ALSA] usb-audio ...
152
  /* get the mapped selector source name */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
153
  static int check_mapped_selector_name(struct mixer_build *state, int unitid,
8e062ec71   Clemens Ladisch   [ALSA] usb-audio ...
154
155
156
157
158
159
160
161
162
163
164
165
  				      int index, char *buf, int buflen)
  {
  	const struct usbmix_selector_map *p;
  
  	if (! state->selector_map)
  		return 0;
  	for (p = state->selector_map; p->id; p++) {
  		if (p->id == unitid && index < p->count)
  			return strlcpy(buf, p->names[index], buflen);
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
168
  /*
   * find an audio control unit with the given unit id
   */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
169
  static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  {
67e1daa0b   Daniel Mack   ALSA: usb-audio: ...
171
172
173
174
175
176
177
178
179
180
  	/* we just parse the header */
  	struct uac_feature_unit_descriptor *hdr = NULL;
  
  	while ((hdr = snd_usb_find_desc(state->buffer, state->buflen, hdr,
  					USB_DT_CS_INTERFACE)) != NULL) {
  		if (hdr->bLength >= 4 &&
  		    hdr->bDescriptorSubtype >= UAC_INPUT_TERMINAL &&
  		    hdr->bDescriptorSubtype <= UAC2_SAMPLE_RATE_CONVERTER &&
  		    hdr->bUnitID == unit)
  			return hdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  	}
67e1daa0b   Daniel Mack   ALSA: usb-audio: ...
182

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
  /*
   * copy a string with the given id
   */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
188
  static int snd_usb_copy_string_desc(struct mixer_build *state, int index, char *buf, int maxlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
194
195
196
197
  {
  	int len = usb_string(state->chip->dev, index, buf, maxlen - 1);
  	buf[len] = 0;
  	return len;
  }
  
  /*
   * convert from the byte/word on usb descriptor to the zero-based integer
   */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
198
  static int convert_signed_value(struct usb_mixer_elem_info *cval, int val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  {
  	switch (cval->val_type) {
  	case USB_MIXER_BOOLEAN:
  		return !!val;
  	case USB_MIXER_INV_BOOLEAN:
  		return !val;
  	case USB_MIXER_U8:
  		val &= 0xff;
  		break;
  	case USB_MIXER_S8:
  		val &= 0xff;
  		if (val >= 0x80)
  			val -= 0x100;
  		break;
  	case USB_MIXER_U16:
  		val &= 0xffff;
  		break;
  	case USB_MIXER_S16:
  		val &= 0xffff;
  		if (val >= 0x8000)
  			val -= 0x10000;
  		break;
  	}
  	return val;
  }
  
  /*
   * convert from the zero-based int to the byte/word for usb descriptor
   */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
228
  static int convert_bytes_value(struct usb_mixer_elem_info *cval, int val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  {
  	switch (cval->val_type) {
  	case USB_MIXER_BOOLEAN:
  		return !!val;
  	case USB_MIXER_INV_BOOLEAN:
  		return !val;
  	case USB_MIXER_S8:
  	case USB_MIXER_U8:
  		return val & 0xff;
  	case USB_MIXER_S16:
  	case USB_MIXER_U16:
  		return val & 0xffff;
  	}
  	return 0; /* not reached */
  }
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
244
  static int get_relative_value(struct usb_mixer_elem_info *cval, int val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
247
248
249
  {
  	if (! cval->res)
  		cval->res = 1;
  	if (val < cval->min)
  		return 0;
14790f1c7   Takashi Iwai   [ALSA] Test volum...
250
251
  	else if (val >= cval->max)
  		return (cval->max - cval->min + cval->res - 1) / cval->res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
  	else
  		return (val - cval->min) / cval->res;
  }
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
255
  static int get_abs_value(struct usb_mixer_elem_info *cval, int val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
  {
  	if (val < 0)
  		return cval->min;
  	if (! cval->res)
  		cval->res = 1;
  	val *= cval->res;
  	val += cval->min;
  	if (val > cval->max)
  		return cval->max;
  	return val;
  }
  
  
  /*
   * retrieve a mixer value
   */
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
272
  static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
  {
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
274
  	struct snd_usb_audio *chip = cval->mixer->chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
277
  	unsigned char buf[2];
  	int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
  	int timeout = 10;
88a8516a2   Oliver Neukum   ALSA: usbaudio: i...
278
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279

88a8516a2   Oliver Neukum   ALSA: usbaudio: i...
280
281
282
  	err = snd_usb_autoresume(cval->mixer->chip);
  	if (err < 0)
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  	while (timeout-- > 0) {
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
284
  		if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  				    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
286
  				    validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
17d900c4a   Clemens Ladisch   ALSA: usb-audio: ...
287
  				    buf, val_len) >= val_len) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
  			*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
88a8516a2   Oliver Neukum   ALSA: usbaudio: i...
289
  			snd_usb_autosuspend(cval->mixer->chip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
292
  			return 0;
  		}
  	}
88a8516a2   Oliver Neukum   ALSA: usbaudio: i...
293
  	snd_usb_autosuspend(cval->mixer->chip);
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
294
295
  	snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d
  ",
b415ec704   Takashi Iwai   ALSA: usb - Fix c...
296
  		    request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
  	return -EINVAL;
  }
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
299
300
  static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret)
  {
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
301
  	struct snd_usb_audio *chip = cval->mixer->chip;
e8bdb6bba   Daniel Mack   ALSA: usb-audio: ...
302
  	unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
303
  	unsigned char *val;
e8bdb6bba   Daniel Mack   ALSA: usb-audio: ...
304
  	int ret, size;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
305
  	__u8 bRequest;
e8bdb6bba   Daniel Mack   ALSA: usb-audio: ...
306
307
308
309
310
311
312
313
314
  	if (request == UAC_GET_CUR) {
  		bRequest = UAC2_CS_CUR;
  		size = sizeof(__u16);
  	} else {
  		bRequest = UAC2_CS_RANGE;
  		size = sizeof(buf);
  	}
  
  	memset(buf, 0, sizeof(buf));
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
315

88a8516a2   Oliver Neukum   ALSA: usbaudio: i...
316
317
318
  	ret = snd_usb_autoresume(chip) ? -EIO : 0;
  	if (ret)
  		goto error;
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
319
  	ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
320
  			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
321
  			      validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
17d900c4a   Clemens Ladisch   ALSA: usb-audio: ...
322
  			      buf, size);
88a8516a2   Oliver Neukum   ALSA: usbaudio: i...
323
  	snd_usb_autosuspend(chip);
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
324
325
  
  	if (ret < 0) {
88a8516a2   Oliver Neukum   ALSA: usbaudio: i...
326
  error:
09414207d   Daniel Mack   ALSA: usb-audio: ...
327
328
  		snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d
  ",
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
329
  			   request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
330
331
  		return ret;
  	}
e8bdb6bba   Daniel Mack   ALSA: usb-audio: ...
332
  	/* FIXME: how should we handle multiple triplets here? */
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
  	switch (request) {
  	case UAC_GET_CUR:
  		val = buf;
  		break;
  	case UAC_GET_MIN:
  		val = buf + sizeof(__u16);
  		break;
  	case UAC_GET_MAX:
  		val = buf + sizeof(__u16) * 2;
  		break;
  	case UAC_GET_RES:
  		val = buf + sizeof(__u16) * 3;
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(val, sizeof(__u16)));
  
  	return 0;
  }
  
  static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret)
  {
  	return (cval->mixer->protocol == UAC_VERSION_1) ?
  		get_ctl_value_v1(cval, request, validx, value_ret) :
  		get_ctl_value_v2(cval, request, validx, value_ret);
  }
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
361
  static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
  {
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
363
  	return get_ctl_value(cval, UAC_GET_CUR, validx, value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
  }
  
  /* channel = 0: master, 1 = first channel */
641b48794   Takashi Iwai   ALSA: usb-audio -...
367
368
  static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval,
  				  int channel, int *value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  {
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
370
  	return get_ctl_value(cval, UAC_GET_CUR, (cval->control << 8) | channel, value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  }
641b48794   Takashi Iwai   ALSA: usb-audio -...
372
373
374
375
376
377
378
379
380
381
382
383
  static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
  			     int channel, int index, int *value)
  {
  	int err;
  
  	if (cval->cached & (1 << channel)) {
  		*value = cval->cache_val[index];
  		return 0;
  	}
  	err = get_cur_mix_raw(cval, channel, value);
  	if (err < 0) {
  		if (!cval->mixer->ignore_ctl_error)
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
384
385
  			snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d
  ",
641b48794   Takashi Iwai   ALSA: usb-audio -...
386
387
388
389
390
391
392
  				   cval->control, channel, err);
  		return err;
  	}
  	cval->cached |= 1 << channel;
  	cval->cache_val[index] = *value;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
  /*
   * set a mixer value
   */
7b1eda223   Daniel Mack   ALSA: usb-mixer: ...
396
397
  int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
  				int request, int validx, int value_set)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  {
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
399
  	struct snd_usb_audio *chip = cval->mixer->chip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
  	unsigned char buf[2];
88a8516a2   Oliver Neukum   ALSA: usbaudio: i...
401
  	int val_len, err, timeout = 10;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
  
  	if (cval->mixer->protocol == UAC_VERSION_1) {
  		val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
  	} else { /* UAC_VERSION_2 */
  		/* audio class v2 controls are always 2 bytes in size */
  		val_len = sizeof(__u16);
  
  		/* FIXME */
  		if (request != UAC_SET_CUR) {
  			snd_printdd(KERN_WARNING "RANGE setting not yet supported
  ");
  			return -EINVAL;
  		}
  
  		request = UAC2_CS_CUR;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
421
  
  	value_set = convert_bytes_value(cval, value_set);
  	buf[0] = value_set & 0xff;
  	buf[1] = (value_set >> 8) & 0xff;
88a8516a2   Oliver Neukum   ALSA: usbaudio: i...
422
423
424
  	err = snd_usb_autoresume(chip);
  	if (err < 0)
  		return -EIO;
cf3f9130f   Viral Mehta   trivial: remove e...
425
  	while (timeout-- > 0)
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
426
427
  		if (snd_usb_ctl_msg(chip->dev,
  				    usb_sndctrlpipe(chip->dev, 0), request,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  				    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
429
  				    validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
17d900c4a   Clemens Ladisch   ALSA: usb-audio: ...
430
  				    buf, val_len) >= 0) {
88a8516a2   Oliver Neukum   ALSA: usbaudio: i...
431
  			snd_usb_autosuspend(chip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
  			return 0;
88a8516a2   Oliver Neukum   ALSA: usbaudio: i...
433
434
  		}
  	snd_usb_autosuspend(chip);
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
435
436
  	snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x
  ",
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
437
  		    request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
  	return -EINVAL;
  }
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
440
  static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
  {
7b1eda223   Daniel Mack   ALSA: usb-mixer: ...
442
  	return snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, validx, value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
  }
641b48794   Takashi Iwai   ALSA: usb-audio -...
444
445
  static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
  			     int index, int value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  {
641b48794   Takashi Iwai   ALSA: usb-audio -...
447
  	int err;
a6a332591   Daniel Mack   ALSA: usb-audio: ...
448
449
450
451
452
453
454
455
456
457
  	unsigned int read_only = (channel == 0) ?
  		cval->master_readonly :
  		cval->ch_readonly & (1 << (channel - 1));
  
  	if (read_only) {
  		snd_printdd(KERN_INFO "%s(): channel %d of control %d is read_only
  ",
  			    __func__, channel, cval->control);
  		return 0;
  	}
7b1eda223   Daniel Mack   ALSA: usb-mixer: ...
458
  	err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel,
641b48794   Takashi Iwai   ALSA: usb-audio -...
459
460
461
462
463
464
  			    value);
  	if (err < 0)
  		return err;
  	cval->cached |= 1 << channel;
  	cval->cache_val[index] = value;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  }
7bc5ba7e0   Takashi Iwai   [ALSA] Add TLV su...
466
467
468
469
470
471
472
  /*
   * TLV callback for mixer volume controls
   */
  static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
  			 unsigned int size, unsigned int __user *_tlv)
  {
  	struct usb_mixer_elem_info *cval = kcontrol->private_data;
b8e1c73f4   Takashi Iwai   ALSA: usb-audio -...
473
  	DECLARE_TLV_DB_MINMAX(scale, 0, 0);
7bc5ba7e0   Takashi Iwai   [ALSA] Add TLV su...
474
475
476
  
  	if (size < sizeof(scale))
  		return -ENOMEM;
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
477
478
  	scale[2] = cval->dBmin;
  	scale[3] = cval->dBmax;
7bc5ba7e0   Takashi Iwai   [ALSA] Add TLV su...
479
480
481
482
  	if (copy_to_user(_tlv, scale, sizeof(scale)))
  		return -EFAULT;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
486
  
  /*
   * parser routines begin here...
   */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
487
  static int parse_audio_unit(struct mixer_build *state, int unitid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
  
  
  /*
   * check if the input/output channel routing is enabled on the given bitmap.
   * used for mixer unit parser
   */
  static int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_outs)
  {
  	int idx = ich * num_outs + och;
  	return bmap[idx >> 3] & (0x80 >> (idx & 7));
  }
  
  
  /*
   * add an alsa control element
   * search and increment the index until an empty slot is found.
   *
   * if failed, give up and free the control instance.
   */
ef9d59708   Daniel Mack   ALSA: usb-audio: ...
507
508
  int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
  			      struct snd_kcontrol *kctl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
510
  	struct usb_mixer_elem_info *cval = kctl->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
  	int err;
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
512

ef9d59708   Daniel Mack   ALSA: usb-audio: ...
513
  	while (snd_ctl_find_id(mixer->chip->card, &kctl->id))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
  		kctl->id.index++;
ef9d59708   Daniel Mack   ALSA: usb-audio: ...
515
  	if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
  		snd_printd(KERN_ERR "cannot add control (err = %d)
  ", err);
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
518
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  	}
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
520
  	cval->elem_id = &kctl->id;
ef9d59708   Daniel Mack   ALSA: usb-audio: ...
521
522
  	cval->next_id_elem = mixer->id_elems[cval->id];
  	mixer->id_elems[cval->id] = cval;
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
523
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
  }
  
  
  /*
   * get a terminal name string
   */
  
  static struct iterm_name_combo {
  	int type;
  	char *name;
  } iterm_names[] = {
  	{ 0x0300, "Output" },
  	{ 0x0301, "Speaker" },
  	{ 0x0302, "Headphone" },
  	{ 0x0303, "HMD Audio" },
  	{ 0x0304, "Desktop Speaker" },
  	{ 0x0305, "Room Speaker" },
  	{ 0x0306, "Com Speaker" },
  	{ 0x0307, "LFE" },
  	{ 0x0600, "External In" },
  	{ 0x0601, "Analog In" },
  	{ 0x0602, "Digital In" },
  	{ 0x0603, "Line" },
  	{ 0x0604, "Legacy In" },
  	{ 0x0605, "IEC958 In" },
  	{ 0x0606, "1394 DA Stream" },
  	{ 0x0607, "1394 DV Stream" },
  	{ 0x0700, "Embedded" },
  	{ 0x0701, "Noise Source" },
  	{ 0x0702, "Equalization Noise" },
  	{ 0x0703, "CD" },
  	{ 0x0704, "DAT" },
  	{ 0x0705, "DCC" },
  	{ 0x0706, "MiniDisk" },
  	{ 0x0707, "Analog Tape" },
  	{ 0x0708, "Phonograph" },
  	{ 0x0709, "VCR Audio" },
  	{ 0x070a, "Video Disk Audio" },
  	{ 0x070b, "DVD Audio" },
  	{ 0x070c, "TV Tuner Audio" },
  	{ 0x070d, "Satellite Rec Audio" },
  	{ 0x070e, "Cable Tuner Audio" },
  	{ 0x070f, "DSS Audio" },
  	{ 0x0710, "Radio Receiver" },
  	{ 0x0711, "Radio Transmitter" },
  	{ 0x0712, "Multi-Track Recorder" },
  	{ 0x0713, "Synthesizer" },
  	{ 0 },
  };
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
573
  static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
576
577
578
579
580
581
582
583
584
585
  			 unsigned char *name, int maxlen, int term_only)
  {
  	struct iterm_name_combo *names;
  
  	if (iterm->name)
  		return snd_usb_copy_string_desc(state, iterm->name, name, maxlen);
  
  	/* virtual type - not a real terminal */
  	if (iterm->type >> 16) {
  		if (term_only)
  			return 0;
  		switch (iterm->type >> 16) {
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
586
  		case UAC_SELECTOR_UNIT:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
  			strcpy(name, "Selector"); return 8;
69da9bcb9   Daniel Mack   ALSA: usb-audio: ...
588
  		case UAC1_PROCESSING_UNIT:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  			strcpy(name, "Process Unit"); return 12;
69da9bcb9   Daniel Mack   ALSA: usb-audio: ...
590
  		case UAC1_EXTENSION_UNIT:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
  			strcpy(name, "Ext Unit"); return 8;
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
592
  		case UAC_MIXER_UNIT:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
  			strcpy(name, "Mixer"); return 5;
  		default:
  			return sprintf(name, "Unit %d", iterm->id);
  		}
  	}
  
  	switch (iterm->type & 0xff00) {
  	case 0x0100:
  		strcpy(name, "PCM"); return 3;
  	case 0x0200:
  		strcpy(name, "Mic"); return 3;
  	case 0x0400:
  		strcpy(name, "Headset"); return 7;
  	case 0x0500:
  		strcpy(name, "Phone"); return 5;
  	}
  
  	for (names = iterm_names; names->type; names++)
  		if (names->type == iterm->type) {
  			strcpy(name, names->name);
  			return strlen(names->name);
  		}
  	return 0;
  }
  
  
  /*
   * parse the source unit recursively until it reaches to a terminal
   * or a branched unit.
   */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
623
  static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
  {
09414207d   Daniel Mack   ALSA: usb-audio: ...
625
  	int err;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
626
  	void *p1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
  
  	memset(term, 0, sizeof(*term));
  	while ((p1 = find_audio_control_unit(state, id)) != NULL) {
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
630
  		unsigned char *hdr = p1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
  		term->id = id;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
632
  		switch (hdr[2]) {
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
633
  		case UAC_INPUT_TERMINAL:
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
634
635
636
637
638
639
640
641
642
643
644
645
  			if (state->mixer->protocol == UAC_VERSION_1) {
  				struct uac_input_terminal_descriptor *d = p1;
  				term->type = le16_to_cpu(d->wTerminalType);
  				term->channels = d->bNrChannels;
  				term->chconfig = le16_to_cpu(d->wChannelConfig);
  				term->name = d->iTerminal;
  			} else { /* UAC_VERSION_2 */
  				struct uac2_input_terminal_descriptor *d = p1;
  				term->type = le16_to_cpu(d->wTerminalType);
  				term->channels = d->bNrChannels;
  				term->chconfig = le32_to_cpu(d->bmChannelConfig);
  				term->name = d->iTerminal;
09414207d   Daniel Mack   ALSA: usb-audio: ...
646
647
648
649
650
  
  				/* call recursively to get the clock selectors */
  				err = check_input_term(state, d->bCSourceID, term);
  				if (err < 0)
  					return err;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
651
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
  			return 0;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
653
654
655
  		case UAC_FEATURE_UNIT: {
  			/* the header is the same for v1 and v2 */
  			struct uac_feature_unit_descriptor *d = p1;
5e6888835   Daniel Mack   ALSA: sound/usb: ...
656
  			id = d->bSourceID;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  			break; /* continue to parse */
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
658
659
660
661
662
663
664
  		}
  		case UAC_MIXER_UNIT: {
  			struct uac_mixer_unit_descriptor *d = p1;
  			term->type = d->bDescriptorSubtype << 16; /* virtual type */
  			term->channels = uac_mixer_unit_bNrChannels(d);
  			term->chconfig = uac_mixer_unit_wChannelConfig(d, state->mixer->protocol);
  			term->name = uac_mixer_unit_iMixer(d);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  			return 0;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
666
  		}
09414207d   Daniel Mack   ALSA: usb-audio: ...
667
668
  		case UAC_SELECTOR_UNIT:
  		case UAC2_CLOCK_SELECTOR: {
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
669
  			struct uac_selector_unit_descriptor *d = p1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
  			/* call recursively to retrieve the channel info */
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
671
  			if (check_input_term(state, d->baSourceID[0], term) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
  				return -ENODEV;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
673
  			term->type = d->bDescriptorSubtype << 16; /* virtual type */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
  			term->id = id;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
675
  			term->name = uac_selector_unit_iSelector(d);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
  			return 0;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
677
  		}
69da9bcb9   Daniel Mack   ALSA: usb-audio: ...
678
679
  		case UAC1_PROCESSING_UNIT:
  		case UAC1_EXTENSION_UNIT: {
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
680
681
682
  			struct uac_processing_unit_descriptor *d = p1;
  			if (d->bNrInPins) {
  				id = d->baSourceID[0];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
  				break; /* continue to parse */
  			}
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
685
686
687
688
  			term->type = d->bDescriptorSubtype << 16; /* virtual type */
  			term->channels = uac_processing_unit_bNrChannels(d);
  			term->chconfig = uac_processing_unit_wChannelConfig(d, state->mixer->protocol);
  			term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
  			return 0;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
690
  		}
09414207d   Daniel Mack   ALSA: usb-audio: ...
691
692
693
694
695
696
697
  		case UAC2_CLOCK_SOURCE: {
  			struct uac_clock_source_descriptor *d = p1;
  			term->type = d->bDescriptorSubtype << 16; /* virtual type */
  			term->id = id;
  			term->name = d->iClockSource;
  			return 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
  		default:
  			return -ENODEV;
  		}
  	}
  	return -ENODEV;
  }
  
  
  /*
   * Feature Unit
   */
  
  /* feature unit control information */
  struct usb_feature_control_info {
  	const char *name;
  	unsigned int type;	/* control type (mute, volume, etc.) */
  };
  
  static struct usb_feature_control_info audio_feature_info[] = {
2e0281d15   Daniel Mack   ALSA: usb-audio: ...
717
718
  	{ "Mute",			USB_MIXER_INV_BOOLEAN },
  	{ "Volume",			USB_MIXER_S16 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
721
722
  	{ "Tone Control - Bass",	USB_MIXER_S8 },
  	{ "Tone Control - Mid",		USB_MIXER_S8 },
  	{ "Tone Control - Treble",	USB_MIXER_S8 },
  	{ "Graphic Equalizer",		USB_MIXER_S8 }, /* FIXME: not implemeted yet */
2e0281d15   Daniel Mack   ALSA: usb-audio: ...
723
724
725
726
727
728
729
730
  	{ "Auto Gain Control",		USB_MIXER_BOOLEAN },
  	{ "Delay Control",		USB_MIXER_U16 },
  	{ "Bass Boost",			USB_MIXER_BOOLEAN },
  	{ "Loudness",			USB_MIXER_BOOLEAN },
  	/* UAC2 specific */
  	{ "Input Gain Control",		USB_MIXER_U16 },
  	{ "Input Gain Pad Control",	USB_MIXER_BOOLEAN },
  	{ "Phase Inverter Control",	USB_MIXER_BOOLEAN },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
  };
  
  
  /* private_free callback */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
735
  static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
  {
4d572776d   Jesper Juhl   [ALSA] Remove red...
737
738
  	kfree(kctl->private_data);
  	kctl->private_data = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
740
741
742
743
744
  }
  
  
  /*
   * interface to ALSA control for feature/mixer units
   */
dcaaf9f2c   Takashi Iwai   ALSA: usb-audio -...
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
  /* volume control quirks */
  static void volume_control_quirks(struct usb_mixer_elem_info *cval,
  				  struct snd_kcontrol *kctl)
  {
  	switch (cval->mixer->chip->usb_id) {
  	case USB_ID(0x0471, 0x0101):
  	case USB_ID(0x0471, 0x0104):
  	case USB_ID(0x0471, 0x0105):
  	case USB_ID(0x0672, 0x1041):
  	/* quirk for UDA1321/N101.
  	 * note that detection between firmware 2.1.1.7 (N101)
  	 * and later 2.1.1.21 is not very clear from datasheets.
  	 * I hope that the min value is -15360 for newer firmware --jk
  	 */
  		if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
  		    cval->min == -15616) {
  			snd_printk(KERN_INFO
  				 "set volume quirk for UDA1321/N101 chip
  ");
  			cval->max = -256;
  		}
  		break;
  
  	case USB_ID(0x046d, 0x09a4):
  		if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
  			snd_printk(KERN_INFO
  				"set volume quirk for QuickCam E3500
  ");
  			cval->min = 6080;
  			cval->max = 8768;
  			cval->res = 192;
  		}
  		break;
  
  	case USB_ID(0x046d, 0x0808):
  	case USB_ID(0x046d, 0x0809):
55c0008be   Alexey Fisher   ALSA: snd_usb_aud...
781
  	case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */
dcaaf9f2c   Takashi Iwai   ALSA: usb-audio -...
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
  	case USB_ID(0x046d, 0x0991):
  	/* Most audio usb devices lie about volume resolution.
  	 * Most Logitech webcams have res = 384.
  	 * Proboly there is some logitech magic behind this number --fishor
  	 */
  		if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
  			snd_printk(KERN_INFO
  				"set resolution quirk: cval->res = 384
  ");
  			cval->res = 384;
  		}
  		break;
  
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
798
799
  /*
   * retrieve the minimum and maximum values for the specified control
   */
dcaaf9f2c   Takashi Iwai   ALSA: usb-audio -...
800
801
  static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
  				   int default_min, struct snd_kcontrol *kctl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
804
805
806
  {
  	/* for failsafe */
  	cval->min = default_min;
  	cval->max = cval->min + 1;
  	cval->res = 1;
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
807
  	cval->dBmin = cval->dBmax = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
811
812
813
814
815
816
817
818
819
820
821
  
  	if (cval->val_type == USB_MIXER_BOOLEAN ||
  	    cval->val_type == USB_MIXER_INV_BOOLEAN) {
  		cval->initialized = 1;
  	} else {
  		int minchn = 0;
  		if (cval->cmask) {
  			int i;
  			for (i = 0; i < MAX_CHANNELS; i++)
  				if (cval->cmask & (1 << i)) {
  					minchn = i + 1;
  					break;
  				}
  		}
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
822
823
  		if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
  		    get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
824
825
  			snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)
  ",
1a4e34e67   Takashi Iwai   ALSA: usb-audio -...
826
  				   cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
  			return -EINVAL;
  		}
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
829
  		if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830
831
832
833
834
  			cval->res = 1;
  		} else {
  			int last_valid_res = cval->res;
  
  			while (cval->res > 1) {
7b1eda223   Daniel Mack   ALSA: usb-mixer: ...
835
836
  				if (snd_usb_mixer_set_ctl_value(cval, UAC_SET_RES,
  								(cval->control << 8) | minchn, cval->res / 2) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
839
  					break;
  				cval->res /= 2;
  			}
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
840
  			if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
843
844
  				cval->res = last_valid_res;
  		}
  		if (cval->res == 0)
  			cval->res = 1;
14790f1c7   Takashi Iwai   [ALSA] Test volum...
845
846
847
848
849
850
851
852
853
854
  
  		/* Additional checks for the proper resolution
  		 *
  		 * Some devices report smaller resolutions than actually
  		 * reacting.  They don't return errors but simply clip
  		 * to the lower aligned value.
  		 */
  		if (cval->min + cval->res < cval->max) {
  			int last_valid_res = cval->res;
  			int saved, test, check;
641b48794   Takashi Iwai   ALSA: usb-audio -...
855
  			get_cur_mix_raw(cval, minchn, &saved);
14790f1c7   Takashi Iwai   [ALSA] Test volum...
856
857
858
859
860
861
862
  			for (;;) {
  				test = saved;
  				if (test < cval->max)
  					test += cval->res;
  				else
  					test -= cval->res;
  				if (test < cval->min || test > cval->max ||
641b48794   Takashi Iwai   ALSA: usb-audio -...
863
864
  				    set_cur_mix_value(cval, minchn, 0, test) ||
  				    get_cur_mix_raw(cval, minchn, &check)) {
14790f1c7   Takashi Iwai   [ALSA] Test volum...
865
866
867
868
869
870
871
  					cval->res = last_valid_res;
  					break;
  				}
  				if (test == check)
  					break;
  				cval->res *= 2;
  			}
641b48794   Takashi Iwai   ALSA: usb-audio -...
872
  			set_cur_mix_value(cval, minchn, 0, saved);
14790f1c7   Takashi Iwai   [ALSA] Test volum...
873
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
  		cval->initialized = 1;
  	}
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
876

dcaaf9f2c   Takashi Iwai   ALSA: usb-audio -...
877
878
  	if (kctl)
  		volume_control_quirks(cval, kctl);
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
  	/* USB descriptions contain the dB scale in 1/256 dB unit
  	 * while ALSA TLV contains in 1/100 dB unit
  	 */
  	cval->dBmin = (convert_signed_value(cval, cval->min) * 100) / 256;
  	cval->dBmax = (convert_signed_value(cval, cval->max) * 100) / 256;
  	if (cval->dBmin > cval->dBmax) {
  		/* something is wrong; assume it's either from/to 0dB */
  		if (cval->dBmin < 0)
  			cval->dBmax = 0;
  		else if (cval->dBmin > 0)
  			cval->dBmin = 0;
  		if (cval->dBmin > cval->dBmax) {
  			/* totally crap, return an error */
  			return -EINVAL;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
  	return 0;
  }
dcaaf9f2c   Takashi Iwai   ALSA: usb-audio -...
897
  #define get_min_max(cval, def)	get_min_max_with_quirks(cval, def, NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
  
  /* get a feature/mixer unit info */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
900
  static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
902
  	struct usb_mixer_elem_info *cval = kcontrol->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
904
905
906
907
908
909
910
911
912
913
914
  
  	if (cval->val_type == USB_MIXER_BOOLEAN ||
  	    cval->val_type == USB_MIXER_INV_BOOLEAN)
  		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  	else
  		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = cval->channels;
  	if (cval->val_type == USB_MIXER_BOOLEAN ||
  	    cval->val_type == USB_MIXER_INV_BOOLEAN) {
  		uinfo->value.integer.min = 0;
  		uinfo->value.integer.max = 1;
  	} else {
9fcd0ab13   Takashi Iwai   ALSA: usb-audio -...
915
  		if (!cval->initialized) {
dcaaf9f2c   Takashi Iwai   ALSA: usb-audio -...
916
  			get_min_max_with_quirks(cval, 0, kcontrol);
9fcd0ab13   Takashi Iwai   ALSA: usb-audio -...
917
918
919
920
921
922
923
924
925
  			if (cval->initialized && cval->dBmin >= cval->dBmax) {
  				kcontrol->vd[0].access &= 
  					~(SNDRV_CTL_ELEM_ACCESS_TLV_READ |
  					  SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
  				snd_ctl_notify(cval->mixer->chip->card,
  					       SNDRV_CTL_EVENT_MASK_INFO,
  					       &kcontrol->id);
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
  		uinfo->value.integer.min = 0;
14790f1c7   Takashi Iwai   [ALSA] Test volum...
927
928
  		uinfo->value.integer.max =
  			(cval->max - cval->min + cval->res - 1) / cval->res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
931
932
933
  	}
  	return 0;
  }
  
  /* get the current value from feature/mixer unit */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
934
  static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
936
  	struct usb_mixer_elem_info *cval = kcontrol->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
  	int c, cnt, val, err;
641b48794   Takashi Iwai   ALSA: usb-audio -...
938
  	ucontrol->value.integer.value[0] = cval->min;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
941
  	if (cval->cmask) {
  		cnt = 0;
  		for (c = 0; c < MAX_CHANNELS; c++) {
641b48794   Takashi Iwai   ALSA: usb-audio -...
942
943
944
945
946
947
948
949
  			if (!(cval->cmask & (1 << c)))
  				continue;
  			err = get_cur_mix_value(cval, c + 1, cnt, &val);
  			if (err < 0)
  				return cval->mixer->ignore_ctl_error ? 0 : err;
  			val = get_relative_value(cval, val);
  			ucontrol->value.integer.value[cnt] = val;
  			cnt++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
  		}
641b48794   Takashi Iwai   ALSA: usb-audio -...
951
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
  	} else {
  		/* master channel */
641b48794   Takashi Iwai   ALSA: usb-audio -...
954
955
956
  		err = get_cur_mix_value(cval, 0, 0, &val);
  		if (err < 0)
  			return cval->mixer->ignore_ctl_error ? 0 : err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
959
960
961
962
963
  		val = get_relative_value(cval, val);
  		ucontrol->value.integer.value[0] = val;
  	}
  	return 0;
  }
  
  /* put the current value to feature/mixer unit */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
964
  static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
966
  	struct usb_mixer_elem_info *cval = kcontrol->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
969
970
971
972
  	int c, cnt, val, oval, err;
  	int changed = 0;
  
  	if (cval->cmask) {
  		cnt = 0;
  		for (c = 0; c < MAX_CHANNELS; c++) {
641b48794   Takashi Iwai   ALSA: usb-audio -...
973
974
975
976
977
978
979
980
981
982
  			if (!(cval->cmask & (1 << c)))
  				continue;
  			err = get_cur_mix_value(cval, c + 1, cnt, &oval);
  			if (err < 0)
  				return cval->mixer->ignore_ctl_error ? 0 : err;
  			val = ucontrol->value.integer.value[cnt];
  			val = get_abs_value(cval, val);
  			if (oval != val) {
  				set_cur_mix_value(cval, c + 1, cnt, val);
  				changed = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
  			}
641b48794   Takashi Iwai   ALSA: usb-audio -...
984
  			cnt++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
986
987
  		}
  	} else {
  		/* master channel */
641b48794   Takashi Iwai   ALSA: usb-audio -...
988
  		err = get_cur_mix_value(cval, 0, 0, &oval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
  		if (err < 0)
641b48794   Takashi Iwai   ALSA: usb-audio -...
990
  			return cval->mixer->ignore_ctl_error ? 0 : err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
992
993
  		val = ucontrol->value.integer.value[0];
  		val = get_abs_value(cval, val);
  		if (val != oval) {
641b48794   Takashi Iwai   ALSA: usb-audio -...
994
  			set_cur_mix_value(cval, 0, 0, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
996
997
998
999
  			changed = 1;
  		}
  	}
  	return changed;
  }
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1000
  static struct snd_kcontrol_new usb_feature_unit_ctl = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
1002
1003
1004
1005
1006
  	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	.name = "", /* will be filled later manually */
  	.info = mixer_ctl_feature_info,
  	.get = mixer_ctl_feature_get,
  	.put = mixer_ctl_feature_put,
  };
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1007
1008
1009
1010
1011
1012
1013
1014
  /* the read-only variant */
  static struct snd_kcontrol_new usb_feature_unit_ctl_ro = {
  	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	.name = "", /* will be filled later manually */
  	.info = mixer_ctl_feature_info,
  	.get = mixer_ctl_feature_get,
  	.put = NULL,
  };
9e38658f7   Daniel Mack   ALSA: usb-audio: ...
1015
1016
1017
  /* This symbol is exported in order to allow the mixer quirks to
   * hook up to the standard feature unit control mechanism */
  struct snd_kcontrol_new *snd_usb_feature_unit_ctl = &usb_feature_unit_ctl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
1019
1020
1021
  
  /*
   * build a feature control
   */
08d1e6350   Takashi Iwai   ALSA: usb - Use s...
1022
1023
1024
1025
  static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str)
  {
  	return strlcat(kctl->id.name, str, sizeof(kctl->id.name));
  }
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1026
  static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027
  			      unsigned int ctl_mask, int control,
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1028
  			      struct usb_audio_term *iterm, int unitid,
a6a332591   Daniel Mack   ALSA: usb-audio: ...
1029
  			      int readonly_mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
  {
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1031
  	struct uac_feature_unit_descriptor *desc = raw_desc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
1033
  	unsigned int len = 0;
  	int mapped_name = 0;
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1034
  	int nameid = uac_feature_unit_iFeature(desc);
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1035
1036
  	struct snd_kcontrol *kctl;
  	struct usb_mixer_elem_info *cval;
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1037
  	const struct usbmix_name_map *map;
80acefff3   Alexey Fisher   ALSA: usb-audio -...
1038
  	unsigned int range;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
1040
  
  	control++; /* change from zero-based to 1-based value */
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1041
  	if (control == UAC_FU_GRAPHIC_EQUALIZER) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
1043
1044
  		/* FIXME: not supported yet */
  		return;
  	}
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1045
1046
  	map = find_map(state, unitid, control);
  	if (check_ignored_ctl(map))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1047
  		return;
561b220a4   Takashi Iwai   [ALSA] Replace wi...
1048
  	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049
1050
1051
1052
1053
  	if (! cval) {
  		snd_printk(KERN_ERR "cannot malloc kcontrol
  ");
  		return;
  	}
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1054
  	cval->mixer = state->mixer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055
1056
1057
1058
  	cval->id = unitid;
  	cval->control = control;
  	cval->cmask = ctl_mask;
  	cval->val_type = audio_feature_info[control-1].type;
a6a332591   Daniel Mack   ALSA: usb-audio: ...
1059
  	if (ctl_mask == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
  		cval->channels = 1;	/* master channel */
a6a332591   Daniel Mack   ALSA: usb-audio: ...
1061
1062
  		cval->master_readonly = readonly_mask;
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
1065
1066
1067
  		int i, c = 0;
  		for (i = 0; i < 16; i++)
  			if (ctl_mask & (1 << i))
  				c++;
  		cval->channels = c;
a6a332591   Daniel Mack   ALSA: usb-audio: ...
1068
  		cval->ch_readonly = readonly_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
  	}
a6a332591   Daniel Mack   ALSA: usb-audio: ...
1070
1071
1072
1073
  	/* if all channels in the mask are marked read-only, make the control
  	 * read-only. set_cur_mix_value() will check the mask again and won't
  	 * issue write commands to read-only channels. */
  	if (cval->channels == readonly_mask)
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1074
1075
1076
  		kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval);
  	else
  		kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
1078
1079
1080
1081
1082
1083
  	if (! kctl) {
  		snd_printk(KERN_ERR "cannot malloc kcontrol
  ");
  		kfree(cval);
  		return;
  	}
  	kctl->private_free = usb_mixer_elem_free;
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1084
  	len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
1086
  	mapped_name = len != 0;
  	if (! len && nameid)
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1087
1088
  		len = snd_usb_copy_string_desc(state, nameid,
  				kctl->id.name, sizeof(kctl->id.name));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089

dcaaf9f2c   Takashi Iwai   ALSA: usb-audio -...
1090
1091
  	/* get min/max values */
  	get_min_max_with_quirks(cval, 0, kctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
  	switch (control) {
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1093
1094
  	case UAC_FU_MUTE:
  	case UAC_FU_VOLUME:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
  		/* determine the control name.  the rule is:
  		 * - if a name id is given in descriptor, use it.
  		 * - if the connected input can be determined, then use the name
  		 *   of terminal type.
  		 * - if the connected output can be determined, use it.
  		 * - otherwise, anonymous name.
  		 */
  		if (! len) {
  			len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 1);
  			if (! len)
  				len = get_term_name(state, &state->oterm, kctl->id.name, sizeof(kctl->id.name), 1);
  			if (! len)
  				len = snprintf(kctl->id.name, sizeof(kctl->id.name),
  					       "Feature %d", unitid);
  		}
  		/* determine the stream direction:
  		 * if the connected output is USB stream, then it's likely a
  		 * capture stream.  otherwise it should be playback (hopefully :)
  		 */
  		if (! mapped_name && ! (state->oterm.type >> 16)) {
  			if ((state->oterm.type & 0xff00) == 0x0100) {
08d1e6350   Takashi Iwai   ALSA: usb - Use s...
1116
  				len = append_ctl_name(kctl, " Capture");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
  			} else {
08d1e6350   Takashi Iwai   ALSA: usb - Use s...
1118
  				len = append_ctl_name(kctl, " Playback");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
1120
  			}
  		}
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1121
  		append_ctl_name(kctl, control == UAC_FU_MUTE ?
08d1e6350   Takashi Iwai   ALSA: usb - Use s...
1122
  				" Switch" : " Volume");
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1123
  		if (control == UAC_FU_VOLUME) {
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1124
  			check_mapped_dB(map, cval);
38b65190c   Takashi Iwai   ALSA: usb-audio -...
1125
  			if (cval->dBmin < cval->dBmax || !cval->initialized) {
59bb7f0ee   Takashi Iwai   ALSA: usb-audio -...
1126
1127
1128
1129
1130
  				kctl->tlv.c = mixer_vol_tlv;
  				kctl->vd[0].access |= 
  					SNDRV_CTL_ELEM_ACCESS_TLV_READ |
  					SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
  			}
7bc5ba7e0   Takashi Iwai   [ALSA] Add TLV su...
1131
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
1133
1134
1135
1136
1137
1138
1139
  		break;
  
  	default:
  		if (! len)
  			strlcpy(kctl->id.name, audio_feature_info[control-1].name,
  				sizeof(kctl->id.name));
  		break;
  	}
80acefff3   Alexey Fisher   ALSA: usb-audio -...
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
  	range = (cval->max - cval->min) / cval->res;
  	/* Are there devices with volume range more than 255? I use a bit more
  	 * to be sure. 384 is a resolution magic number found on Logitech
  	 * devices. It will definitively catch all buggy Logitech devices.
  	 */
  	if (range > 384) {
  		snd_printk(KERN_WARNING "usb_audio: Warning! Unlikely big "
  			   "volume range (=%u), cval->res is probably wrong.",
  			   range);
  		snd_printk(KERN_WARNING "usb_audio: [%d] FU [%s] ch = %d, "
  			   "val = %d/%d/%d", cval->id,
  			   kctl->id.name, cval->channels,
  			   cval->min, cval->max, cval->res);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
1155
1156
  	snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d
  ",
  		    cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res);
ef9d59708   Daniel Mack   ALSA: usb-audio: ...
1157
  	snd_usb_mixer_add_control(state->mixer, kctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
1159
1160
1161
1162
1163
1164
  }
  
  
  
  /*
   * parse a feature unit
   *
25985edce   Lucas De Marchi   Fix common misspe...
1165
   * most of controls are defined here.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
   */
28e1b7730   Daniel Mack   ALSA: usbaudio: p...
1167
  static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void *_ftr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
1169
  {
  	int channels, i, j;
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1170
  	struct usb_audio_term iterm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
1172
  	unsigned int master_bits, first_ch_bits;
  	int err, csize;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1173
1174
1175
1176
1177
  	struct uac_feature_unit_descriptor *hdr = _ftr;
  	__u8 *bmaControls;
  
  	if (state->mixer->protocol == UAC_VERSION_1) {
  		csize = hdr->bControlSize;
60c961a9e   Nicolai Krakowiak   ALSA: snd-usb: av...
1178
1179
1180
1181
1182
1183
  		if (!csize) {
  			snd_printdd(KERN_ERR "usbaudio: unit %u: "
  				    "invalid bControlSize == 0
  ", unitid);
  			return -EINVAL;
  		}
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1184
1185
1186
1187
1188
  		channels = (hdr->bLength - 7) / csize - 1;
  		bmaControls = hdr->bmaControls;
  	} else {
  		struct uac2_feature_unit_descriptor *ftr = _ftr;
  		csize = 4;
e8d0fee70   Daniel Mack   ALSA: usb-audio: ...
1189
  		channels = (hdr->bLength - 6) / 4 - 1;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1190
1191
  		bmaControls = ftr->bmaControls;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192

23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1193
  	if (hdr->bLength < 7 || !csize || hdr->bLength < 7 + csize) {
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
1194
1195
  		snd_printk(KERN_ERR "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor
  ", unitid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
1197
1198
1199
  		return -EINVAL;
  	}
  
  	/* parse the source unit */
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1200
  	if ((err = parse_audio_unit(state, hdr->bSourceID)) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201
1202
1203
  		return err;
  
  	/* determine the input source type and name */
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1204
  	if (check_input_term(state, hdr->bSourceID, &iterm) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1205
  		return -EINVAL;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1206
  	master_bits = snd_usb_combine_bytes(bmaControls, csize);
0c3cee57e   Javier Kohen   ALSA: usb - Quirk...
1207
1208
1209
1210
1211
1212
1213
  	/* master configuration quirks */
  	switch (state->chip->usb_id) {
  	case USB_ID(0x08bb, 0x2702):
  		snd_printk(KERN_INFO
  			   "usbmixer: master volume quirk for PCM2702 chip
  ");
  		/* disable non-functional volume control */
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1214
  		master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME);
0c3cee57e   Javier Kohen   ALSA: usb - Quirk...
1215
1216
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
  	if (channels > 0)
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1218
  		first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1219
1220
  	else
  		first_ch_bits = 0;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
  
  	if (state->mixer->protocol == UAC_VERSION_1) {
  		/* check all control types */
  		for (i = 0; i < 10; i++) {
  			unsigned int ch_bits = 0;
  			for (j = 0; j < channels; j++) {
  				unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize);
  				if (mask & (1 << i))
  					ch_bits |= (1 << j);
  			}
  			/* audio class v1 controls are never read-only */
  			if (ch_bits & 1) /* the first channel must be set (for ease of programming) */
  				build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, 0);
  			if (master_bits & (1 << i))
  				build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, 0);
  		}
  	} else { /* UAC_VERSION_2 */
d09c06c6f   Takashi Iwai   ALSA: usb-audio -...
1238
  		for (i = 0; i < ARRAY_SIZE(audio_feature_info); i++) {
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1239
1240
1241
1242
1243
  			unsigned int ch_bits = 0;
  			unsigned int ch_read_only = 0;
  
  			for (j = 0; j < channels; j++) {
  				unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize);
dcbe7bcfa   Daniel Mack   ALSA: usb-audio: ...
1244
  				if (uac2_control_is_readable(mask, i)) {
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1245
  					ch_bits |= (1 << j);
dcbe7bcfa   Daniel Mack   ALSA: usb-audio: ...
1246
  					if (!uac2_control_is_writeable(mask, i))
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1247
1248
1249
  						ch_read_only |= (1 << j);
  				}
  			}
a6a332591   Daniel Mack   ALSA: usb-audio: ...
1250
1251
1252
1253
  			/* NOTE: build_feature_ctl() will mark the control read-only if all channels
  			 * are marked read-only in the descriptors. Otherwise, the control will be
  			 * reported as writeable, but the driver will not actually issue a write
  			 * command for read-only channels */
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1254
  			if (ch_bits & 1) /* the first channel must be set (for ease of programming) */
a6a332591   Daniel Mack   ALSA: usb-audio: ...
1255
  				build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, ch_read_only);
dcbe7bcfa   Daniel Mack   ALSA: usb-audio: ...
1256
  			if (uac2_control_is_readable(master_bits, i))
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1257
  				build_feature_ctl(state, _ftr, 0, i, &iterm, unitid,
dcbe7bcfa   Daniel Mack   ALSA: usb-audio: ...
1258
  						  !uac2_control_is_writeable(master_bits, i));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1259
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
  	}
  
  	return 0;
  }
  
  
  /*
   * Mixer Unit
   */
  
  /*
   * build a mixer unit control
   *
   * the callbacks are identical with feature unit.
   * input channel number (zero based) is given in control field instead.
   */
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1276
1277
  static void build_mixer_unit_ctl(struct mixer_build *state,
  				 struct uac_mixer_unit_descriptor *desc,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
  				 int in_pin, int in_ch, int unitid,
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1279
  				 struct usb_audio_term *iterm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1281
  	struct usb_mixer_elem_info *cval;
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1282
  	unsigned int num_outs = uac_mixer_unit_bNrChannels(desc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
  	unsigned int i, len;
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1284
  	struct snd_kcontrol *kctl;
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1285
  	const struct usbmix_name_map *map;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1286

c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1287
1288
  	map = find_map(state, unitid, 0);
  	if (check_ignored_ctl(map))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1289
  		return;
561b220a4   Takashi Iwai   [ALSA] Replace wi...
1290
  	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1291
1292
  	if (! cval)
  		return;
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1293
  	cval->mixer = state->mixer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
1295
1296
1297
  	cval->id = unitid;
  	cval->control = in_ch + 1; /* based on 1 */
  	cval->val_type = USB_MIXER_S16;
  	for (i = 0; i < num_outs; i++) {
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1298
  		if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc, state->mixer->protocol), in_ch, i, num_outs)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
  			cval->cmask |= (1 << i);
  			cval->channels++;
  		}
  	}
  
  	/* get min/max values */
  	get_min_max(cval, 0);
  
  	kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
  	if (! kctl) {
  		snd_printk(KERN_ERR "cannot malloc kcontrol
  ");
  		kfree(cval);
  		return;
  	}
  	kctl->private_free = usb_mixer_elem_free;
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1315
  	len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1316
1317
1318
1319
  	if (! len)
  		len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0);
  	if (! len)
  		len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1);
08d1e6350   Takashi Iwai   ALSA: usb - Use s...
1320
  	append_ctl_name(kctl, " Volume");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321
1322
1323
1324
  
  	snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d
  ",
  		    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
ef9d59708   Daniel Mack   ALSA: usb-audio: ...
1325
  	snd_usb_mixer_add_control(state->mixer, kctl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326
1327
1328
1329
1330
1331
  }
  
  
  /*
   * parse a mixer unit
   */
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1332
  static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *raw_desc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1333
  {
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1334
  	struct uac_mixer_unit_descriptor *desc = raw_desc;
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1335
  	struct usb_audio_term iterm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1336
1337
  	int input_pins, num_ins, num_outs;
  	int pin, ich, err;
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1338
  	if (desc->bLength < 11 || ! (input_pins = desc->bNrInPins) || ! (num_outs = uac_mixer_unit_bNrChannels(desc))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
1340
1341
1342
1343
  		snd_printk(KERN_ERR "invalid MIXER UNIT descriptor %d
  ", unitid);
  		return -EINVAL;
  	}
  	/* no bmControls field (e.g. Maya44) -> ignore */
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1344
  	if (desc->bLength <= 10 + input_pins) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1345
1346
1347
1348
1349
1350
1351
1352
  		snd_printdd(KERN_INFO "MU %d has no bmControls field
  ", unitid);
  		return 0;
  	}
  
  	num_ins = 0;
  	ich = 0;
  	for (pin = 0; pin < input_pins; pin++) {
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1353
  		err = parse_audio_unit(state, desc->baSourceID[pin]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1354
1355
  		if (err < 0)
  			return err;
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1356
  		err = check_input_term(state, desc->baSourceID[pin], &iterm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1357
1358
1359
1360
1361
1362
1363
  		if (err < 0)
  			return err;
  		num_ins += iterm.channels;
  		for (; ich < num_ins; ++ich) {
  			int och, ich_has_controls = 0;
  
  			for (och = 0; och < num_outs; ++och) {
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1364
  				if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc, state->mixer->protocol),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
  							ich, och, num_outs)) {
  					ich_has_controls = 1;
  					break;
  				}
  			}
  			if (ich_has_controls)
  				build_mixer_unit_ctl(state, desc, pin, ich,
  						     unitid, &iterm);
  		}
  	}
  	return 0;
  }
  
  
  /*
   * Processing Unit / Extension Unit
   */
  
  /* get callback for processing/extension unit */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1384
  static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1386
  	struct usb_mixer_elem_info *cval = kcontrol->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1387
1388
1389
  	int err, val;
  
  	err = get_cur_ctl_value(cval, cval->control << 8, &val);
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1390
  	if (err < 0 && cval->mixer->ignore_ctl_error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
  		ucontrol->value.integer.value[0] = cval->min;
  		return 0;
  	}
  	if (err < 0)
  		return err;
  	val = get_relative_value(cval, val);
  	ucontrol->value.integer.value[0] = val;
  	return 0;
  }
  
  /* put callback for processing/extension unit */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1402
  static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1404
  	struct usb_mixer_elem_info *cval = kcontrol->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405
1406
1407
1408
  	int val, oval, err;
  
  	err = get_cur_ctl_value(cval, cval->control << 8, &oval);
  	if (err < 0) {
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1409
  		if (cval->mixer->ignore_ctl_error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
  			return 0;
  		return err;
  	}
  	val = ucontrol->value.integer.value[0];
  	val = get_abs_value(cval, val);
  	if (val != oval) {
  		set_cur_ctl_value(cval, cval->control << 8, val);
  		return 1;
  	}
  	return 0;
  }
  
  /* alsa control interface for processing/extension unit */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1423
  static struct snd_kcontrol_new mixer_procunit_ctl = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
  	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	.name = "", /* will be filled later */
  	.info = mixer_ctl_feature_info,
  	.get = mixer_ctl_procunit_get,
  	.put = mixer_ctl_procunit_put,
  };
  
  
  /*
   * predefined data for processing units
   */
  struct procunit_value_info {
  	int control;
  	char *suffix;
  	int val_type;
  	int min_value;
  };
  
  struct procunit_info {
  	int type;
  	char *name;
  	struct procunit_value_info *values;
  };
  
  static struct procunit_value_info updown_proc_info[] = {
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1449
1450
  	{ UAC_UD_ENABLE, "Switch", USB_MIXER_BOOLEAN },
  	{ UAC_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1451
1452
1453
  	{ 0 }
  };
  static struct procunit_value_info prologic_proc_info[] = {
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1454
1455
  	{ UAC_DP_ENABLE, "Switch", USB_MIXER_BOOLEAN },
  	{ UAC_DP_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
1457
1458
  	{ 0 }
  };
  static struct procunit_value_info threed_enh_proc_info[] = {
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1459
1460
  	{ UAC_3D_ENABLE, "Switch", USB_MIXER_BOOLEAN },
  	{ UAC_3D_SPACE, "Spaciousness", USB_MIXER_U8 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1461
1462
1463
  	{ 0 }
  };
  static struct procunit_value_info reverb_proc_info[] = {
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1464
1465
1466
1467
  	{ UAC_REVERB_ENABLE, "Switch", USB_MIXER_BOOLEAN },
  	{ UAC_REVERB_LEVEL, "Level", USB_MIXER_U8 },
  	{ UAC_REVERB_TIME, "Time", USB_MIXER_U16 },
  	{ UAC_REVERB_FEEDBACK, "Feedback", USB_MIXER_U8 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1468
1469
1470
  	{ 0 }
  };
  static struct procunit_value_info chorus_proc_info[] = {
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1471
1472
1473
1474
  	{ UAC_CHORUS_ENABLE, "Switch", USB_MIXER_BOOLEAN },
  	{ UAC_CHORUS_LEVEL, "Level", USB_MIXER_U8 },
  	{ UAC_CHORUS_RATE, "Rate", USB_MIXER_U16 },
  	{ UAC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1475
1476
1477
  	{ 0 }
  };
  static struct procunit_value_info dcr_proc_info[] = {
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1478
1479
1480
1481
1482
1483
  	{ UAC_DCR_ENABLE, "Switch", USB_MIXER_BOOLEAN },
  	{ UAC_DCR_RATE, "Ratio", USB_MIXER_U16 },
  	{ UAC_DCR_MAXAMPL, "Max Amp", USB_MIXER_S16 },
  	{ UAC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 },
  	{ UAC_DCR_ATTACK_TIME, "Attack Time", USB_MIXER_U16 },
  	{ UAC_DCR_RELEASE_TIME, "Release Time", USB_MIXER_U16 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1484
1485
1486
1487
  	{ 0 }
  };
  
  static struct procunit_info procunits[] = {
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1488
1489
1490
1491
1492
1493
  	{ UAC_PROCESS_UP_DOWNMIX, "Up Down", updown_proc_info },
  	{ UAC_PROCESS_DOLBY_PROLOGIC, "Dolby Prologic", prologic_proc_info },
  	{ UAC_PROCESS_STEREO_EXTENDER, "3D Stereo Extender", threed_enh_proc_info },
  	{ UAC_PROCESS_REVERB, "Reverb", reverb_proc_info },
  	{ UAC_PROCESS_CHORUS, "Chorus", chorus_proc_info },
  	{ UAC_PROCESS_DYN_RANGE_COMP, "DCR", dcr_proc_info },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1494
1495
  	{ 0 },
  };
7d2b451e6   Sergiy Kovalchuk   ALSA: usb-audio -...
1496
1497
1498
1499
  /*
   * predefined data for extension units
   */
  static struct procunit_value_info clock_rate_xu_info[] = {
e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
1500
1501
  	{ USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0 },
  	{ 0 }
7d2b451e6   Sergiy Kovalchuk   ALSA: usb-audio -...
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
  };
  static struct procunit_value_info clock_source_xu_info[] = {
  	{ USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN },
  	{ 0 }
  };
  static struct procunit_value_info spdif_format_xu_info[] = {
  	{ USB_XU_DIGITAL_FORMAT_SELECTOR, "SPDIF/AC3", USB_MIXER_BOOLEAN },
  	{ 0 }
  };
  static struct procunit_value_info soft_limit_xu_info[] = {
  	{ USB_XU_SOFT_LIMIT_SELECTOR, " ", USB_MIXER_BOOLEAN },
  	{ 0 }
  };
  static struct procunit_info extunits[] = {
  	{ USB_XU_CLOCK_RATE, "Clock rate", clock_rate_xu_info },
  	{ USB_XU_CLOCK_SOURCE, "DigitalIn CLK source", clock_source_xu_info },
  	{ USB_XU_DIGITAL_IO_STATUS, "DigitalOut format:", spdif_format_xu_info },
  	{ USB_XU_DEVICE_OPTIONS, "AnalogueIn Soft Limit", soft_limit_xu_info },
  	{ 0 }
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1522
1523
1524
  /*
   * build a processing/extension unit
   */
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1525
  static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw_desc, struct procunit_info *list, char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1526
  {
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1527
1528
  	struct uac_processing_unit_descriptor *desc = raw_desc;
  	int num_ins = desc->bNrInPins;
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1529
1530
  	struct usb_mixer_elem_info *cval;
  	struct snd_kcontrol *kctl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1531
1532
1533
  	int i, err, nameid, type, len;
  	struct procunit_info *info;
  	struct procunit_value_info *valinfo;
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1534
  	const struct usbmix_name_map *map;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
1536
1537
1538
1539
1540
1541
  	static struct procunit_value_info default_value_info[] = {
  		{ 0x01, "Switch", USB_MIXER_BOOLEAN },
  		{ 0 }
  	};
  	static struct procunit_info default_info = {
  		0, NULL, default_value_info
  	};
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1542
1543
  	if (desc->bLength < 13 || desc->bLength < 13 + num_ins ||
  	    desc->bLength < num_ins + uac_processing_unit_bControlSize(desc, state->mixer->protocol)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1544
1545
1546
1547
1548
1549
  		snd_printk(KERN_ERR "invalid %s descriptor (id %d)
  ", name, unitid);
  		return -EINVAL;
  	}
  
  	for (i = 0; i < num_ins; i++) {
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1550
  		if ((err = parse_audio_unit(state, desc->baSourceID[i])) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1551
1552
  			return err;
  	}
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1553
  	type = le16_to_cpu(desc->wProcessType);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1554
1555
1556
1557
1558
1559
1560
  	for (info = list; info && info->type; info++)
  		if (info->type == type)
  			break;
  	if (! info || ! info->type)
  		info = &default_info;
  
  	for (valinfo = info->values; valinfo->control; valinfo++) {
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1561
  		__u8 *controls = uac_processing_unit_bmControls(desc, state->mixer->protocol);
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1562
1563
  
  		if (! (controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1))))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1564
  			continue;
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1565
1566
  		map = find_map(state, unitid, valinfo->control);
  		if (check_ignored_ctl(map))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1567
  			continue;
561b220a4   Takashi Iwai   [ALSA] Replace wi...
1568
  		cval = kzalloc(sizeof(*cval), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1569
1570
1571
1572
1573
  		if (! cval) {
  			snd_printk(KERN_ERR "cannot malloc kcontrol
  ");
  			return -ENOMEM;
  		}
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1574
  		cval->mixer = state->mixer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1575
1576
1577
1578
1579
1580
  		cval->id = unitid;
  		cval->control = valinfo->control;
  		cval->val_type = valinfo->val_type;
  		cval->channels = 1;
  
  		/* get min/max values */
65f25da44   Daniel Mack   ALSA: usb-audio: ...
1581
  		if (type == UAC_PROCESS_UP_DOWNMIX && cval->control == UAC_UD_MODE_SELECT) {
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1582
  			__u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1583
1584
  			/* FIXME: hard-coded */
  			cval->min = 1;
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1585
  			cval->max = control_spec[0];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1586
1587
  			cval->res = 1;
  			cval->initialized = 1;
7d2b451e6   Sergiy Kovalchuk   ALSA: usb-audio -...
1588
1589
  		} else {
  			if (type == USB_XU_CLOCK_RATE) {
1cdfa9f34   Joseph Teichman   ALSA: usbaudio - ...
1590
  				/* E-Mu USB 0404/0202/TrackerPre/0204
7d2b451e6   Sergiy Kovalchuk   ALSA: usb-audio -...
1591
1592
1593
1594
1595
1596
1597
1598
1599
  				 * samplerate control quirk
  				 */
  				cval->min = 0;
  				cval->max = 5;
  				cval->res = 1;
  				cval->initialized = 1;
  			} else
  				get_min_max(cval, valinfo->min_value);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1600
1601
1602
1603
1604
1605
1606
1607
1608
  
  		kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
  		if (! kctl) {
  			snd_printk(KERN_ERR "cannot malloc kcontrol
  ");
  			kfree(cval);
  			return -ENOMEM;
  		}
  		kctl->private_free = usb_mixer_elem_free;
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1609
1610
1611
  		if (check_mapped_name(map, kctl->id.name,
  						sizeof(kctl->id.name)))
  			/* nothing */ ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1612
1613
1614
  		else if (info->name)
  			strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
  		else {
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1615
  			nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1616
1617
1618
1619
1620
1621
  			len = 0;
  			if (nameid)
  				len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
  			if (! len)
  				strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
  		}
08d1e6350   Takashi Iwai   ALSA: usb - Use s...
1622
1623
  		append_ctl_name(kctl, " ");
  		append_ctl_name(kctl, valinfo->suffix);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1624
1625
1626
1627
  
  		snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d
  ",
  			    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
ef9d59708   Daniel Mack   ALSA: usb-audio: ...
1628
  		if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1629
1630
1631
1632
  			return err;
  	}
  	return 0;
  }
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1633
  static int parse_audio_processing_unit(struct mixer_build *state, int unitid, void *raw_desc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1634
  {
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1635
  	return build_audio_procunit(state, unitid, raw_desc, procunits, "Processing Unit");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1636
  }
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1637
  static int parse_audio_extension_unit(struct mixer_build *state, int unitid, void *raw_desc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1638
  {
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1639
1640
1641
  	/* Note that we parse extension units with processing unit descriptors.
  	 * That's ok as the layout is the same */
  	return build_audio_procunit(state, unitid, raw_desc, extunits, "Extension Unit");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
  }
  
  
  /*
   * Selector Unit
   */
  
  /* info callback for selector unit
   * use an enumerator type for routing
   */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1652
  static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1653
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1654
  	struct usb_mixer_elem_info *cval = kcontrol->private_data;
2a1803a72   Clemens Ladisch   ALSA: usb-audio: ...
1655
  	const char **itemlist = (const char **)kcontrol->private_value;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1656

5e246b850   Takashi Iwai   ALSA: Kill snd_as...
1657
1658
  	if (snd_BUG_ON(!itemlist))
  		return -EINVAL;
2a1803a72   Clemens Ladisch   ALSA: usb-audio: ...
1659
  	return snd_ctl_enum_info(uinfo, 1, cval->max, itemlist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1660
1661
1662
  }
  
  /* get callback for selector unit */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1663
  static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1664
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1665
  	struct usb_mixer_elem_info *cval = kcontrol->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1666
  	int val, err;
09414207d   Daniel Mack   ALSA: usb-audio: ...
1667
  	err = get_cur_ctl_value(cval, cval->control << 8, &val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1668
  	if (err < 0) {
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1669
  		if (cval->mixer->ignore_ctl_error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
  			ucontrol->value.enumerated.item[0] = 0;
  			return 0;
  		}
  		return err;
  	}
  	val = get_relative_value(cval, val);
  	ucontrol->value.enumerated.item[0] = val;
  	return 0;
  }
  
  /* put callback for selector unit */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1681
  static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1682
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1683
  	struct usb_mixer_elem_info *cval = kcontrol->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1684
  	int val, oval, err;
09414207d   Daniel Mack   ALSA: usb-audio: ...
1685
  	err = get_cur_ctl_value(cval, cval->control << 8, &oval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1686
  	if (err < 0) {
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1687
  		if (cval->mixer->ignore_ctl_error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688
1689
1690
1691
1692
1693
  			return 0;
  		return err;
  	}
  	val = ucontrol->value.enumerated.item[0];
  	val = get_abs_value(cval, val);
  	if (val != oval) {
09414207d   Daniel Mack   ALSA: usb-audio: ...
1694
  		set_cur_ctl_value(cval, cval->control << 8, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1695
1696
1697
1698
1699
1700
  		return 1;
  	}
  	return 0;
  }
  
  /* alsa control interface for selector unit */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1701
  static struct snd_kcontrol_new mixer_selectunit_ctl = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
  	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	.name = "", /* will be filled later */
  	.info = mixer_ctl_selector_info,
  	.get = mixer_ctl_selector_get,
  	.put = mixer_ctl_selector_put,
  };
  
  
  /* private free callback.
   * free both private_data and private_value
   */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1713
  static void usb_mixer_selector_elem_free(struct snd_kcontrol *kctl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1714
1715
1716
1717
  {
  	int i, num_ins = 0;
  
  	if (kctl->private_data) {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1718
  		struct usb_mixer_elem_info *cval = kctl->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
  		num_ins = cval->max;
  		kfree(cval);
  		kctl->private_data = NULL;
  	}
  	if (kctl->private_value) {
  		char **itemlist = (char **)kctl->private_value;
  		for (i = 0; i < num_ins; i++)
  			kfree(itemlist[i]);
  		kfree(itemlist);
  		kctl->private_value = 0;
  	}
  }
  
  /*
   * parse a selector unit
   */
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1735
  static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void *raw_desc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1736
  {
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1737
  	struct uac_selector_unit_descriptor *desc = raw_desc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1738
1739
  	unsigned int i, nameid, len;
  	int err;
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1740
1741
  	struct usb_mixer_elem_info *cval;
  	struct snd_kcontrol *kctl;
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1742
  	const struct usbmix_name_map *map;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1743
  	char **namelist;
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1744
  	if (!desc->bNrInPins || desc->bLength < 5 + desc->bNrInPins) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1745
1746
1747
1748
  		snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d
  ", unitid);
  		return -EINVAL;
  	}
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1749
1750
  	for (i = 0; i < desc->bNrInPins; i++) {
  		if ((err = parse_audio_unit(state, desc->baSourceID[i])) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1751
1752
  			return err;
  	}
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1753
  	if (desc->bNrInPins == 1) /* only one ? nonsense! */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1754
  		return 0;
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1755
1756
  	map = find_map(state, unitid, 0);
  	if (check_ignored_ctl(map))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1757
  		return 0;
561b220a4   Takashi Iwai   [ALSA] Replace wi...
1758
  	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1759
1760
1761
1762
1763
  	if (! cval) {
  		snd_printk(KERN_ERR "cannot malloc kcontrol
  ");
  		return -ENOMEM;
  	}
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1764
  	cval->mixer = state->mixer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1765
1766
1767
1768
  	cval->id = unitid;
  	cval->val_type = USB_MIXER_U8;
  	cval->channels = 1;
  	cval->min = 1;
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1769
  	cval->max = desc->bNrInPins;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1770
1771
  	cval->res = 1;
  	cval->initialized = 1;
09414207d   Daniel Mack   ALSA: usb-audio: ...
1772
1773
1774
1775
  	if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR)
  		cval->control = UAC2_CX_CLOCK_SELECTOR;
  	else
  		cval->control = 0;
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1776
  	namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1777
1778
1779
1780
1781
1782
1783
  	if (! namelist) {
  		snd_printk(KERN_ERR "cannot malloc
  ");
  		kfree(cval);
  		return -ENOMEM;
  	}
  #define MAX_ITEM_NAME_LEN	64
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1784
  	for (i = 0; i < desc->bNrInPins; i++) {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1785
  		struct usb_audio_term iterm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1786
1787
1788
1789
1790
  		len = 0;
  		namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL);
  		if (! namelist[i]) {
  			snd_printk(KERN_ERR "cannot malloc
  ");
7fbe3ca57   Mariusz Kozlowski   [ALSA] usb: usbmi...
1791
  			while (i--)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1792
1793
1794
1795
1796
  				kfree(namelist[i]);
  			kfree(namelist);
  			kfree(cval);
  			return -ENOMEM;
  		}
8e062ec71   Clemens Ladisch   [ALSA] usb-audio ...
1797
1798
  		len = check_mapped_selector_name(state, unitid, i, namelist[i],
  						 MAX_ITEM_NAME_LEN);
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1799
  		if (! len && check_input_term(state, desc->baSourceID[i], &iterm) >= 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1800
1801
1802
1803
1804
1805
1806
1807
1808
  			len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0);
  		if (! len)
  			sprintf(namelist[i], "Input %d", i);
  	}
  
  	kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
  	if (! kctl) {
  		snd_printk(KERN_ERR "cannot malloc kcontrol
  ");
878b47891   Jesper Juhl   [ALSA] fix resour...
1809
  		kfree(namelist);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1810
1811
1812
1813
1814
  		kfree(cval);
  		return -ENOMEM;
  	}
  	kctl->private_value = (unsigned long)namelist;
  	kctl->private_free = usb_mixer_selector_elem_free;
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1815
  	nameid = uac_selector_unit_iSelector(desc);
c3a3e040f   Jaroslav Kysela   ALSA: usbmixer - ...
1816
  	len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1817
1818
1819
1820
1821
1822
1823
1824
1825
  	if (len)
  		;
  	else if (nameid)
  		snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
  	else {
  		len = get_term_name(state, &state->oterm,
  				    kctl->id.name, sizeof(kctl->id.name), 0);
  		if (! len)
  			strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));
09414207d   Daniel Mack   ALSA: usb-audio: ...
1826
1827
1828
  		if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR)
  			append_ctl_name(kctl, " Clock Source");
  		else if ((state->oterm.type & 0xff00) == 0x0100)
08d1e6350   Takashi Iwai   ALSA: usb - Use s...
1829
  			append_ctl_name(kctl, " Capture Source");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1830
  		else
08d1e6350   Takashi Iwai   ALSA: usb - Use s...
1831
  			append_ctl_name(kctl, " Playback Source");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1832
1833
1834
1835
  	}
  
  	snd_printdd(KERN_INFO "[%d] SU [%s] items = %d
  ",
99fc86450   Daniel Mack   ALSA: usb-mixer: ...
1836
  		    cval->id, kctl->id.name, desc->bNrInPins);
ef9d59708   Daniel Mack   ALSA: usb-audio: ...
1837
  	if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1838
1839
1840
1841
1842
1843
1844
1845
1846
  		return err;
  
  	return 0;
  }
  
  
  /*
   * parse an audio unit recursively
   */
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1847
  static int parse_audio_unit(struct mixer_build *state, int unitid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
  {
  	unsigned char *p1;
  
  	if (test_and_set_bit(unitid, state->unitbitmap))
  		return 0; /* the unit already visited */
  
  	p1 = find_audio_control_unit(state, unitid);
  	if (!p1) {
  		snd_printk(KERN_ERR "usbaudio: unit %d not found!
  ", unitid);
  		return -EINVAL;
  	}
  
  	switch (p1[2]) {
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
1862
  	case UAC_INPUT_TERMINAL:
09414207d   Daniel Mack   ALSA: usb-audio: ...
1863
  	case UAC2_CLOCK_SOURCE:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1864
  		return 0; /* NOP */
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
1865
  	case UAC_MIXER_UNIT:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1866
  		return parse_audio_mixer_unit(state, unitid, p1);
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
1867
  	case UAC_SELECTOR_UNIT:
09414207d   Daniel Mack   ALSA: usb-audio: ...
1868
  	case UAC2_CLOCK_SELECTOR:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1869
  		return parse_audio_selector_unit(state, unitid, p1);
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
1870
  	case UAC_FEATURE_UNIT:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1871
  		return parse_audio_feature_unit(state, unitid, p1);
69da9bcb9   Daniel Mack   ALSA: usb-audio: ...
1872
  	case UAC1_PROCESSING_UNIT:
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1873
1874
1875
1876
1877
  	/*   UAC2_EFFECT_UNIT has the same value */
  		if (state->mixer->protocol == UAC_VERSION_1)
  			return parse_audio_processing_unit(state, unitid, p1);
  		else
  			return 0; /* FIXME - effect units not implemented yet */
69da9bcb9   Daniel Mack   ALSA: usb-audio: ...
1878
  	case UAC1_EXTENSION_UNIT:
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1879
1880
1881
1882
1883
  	/*   UAC2_PROCESSING_UNIT_V2 has the same value */
  		if (state->mixer->protocol == UAC_VERSION_1)
  			return parse_audio_extension_unit(state, unitid, p1);
  		else /* UAC_VERSION_2 */
  			return parse_audio_processing_unit(state, unitid, p1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1884
1885
1886
1887
1888
1889
  	default:
  		snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x
  ", unitid, p1[2]);
  		return -EINVAL;
  	}
  }
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1890
1891
  static void snd_usb_mixer_free(struct usb_mixer_interface *mixer)
  {
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
1892
1893
1894
1895
1896
  	kfree(mixer->id_elems);
  	if (mixer->urb) {
  		kfree(mixer->urb->transfer_buffer);
  		usb_free_urb(mixer->urb);
  	}
68df9de1d   Mariusz Kozlowski   usb: usbmixer fre...
1897
  	usb_free_urb(mixer->rc_urb);
b259b10c4   Clemens Ladisch   [ALSA] usb-audio ...
1898
  	kfree(mixer->rc_setup_packet);
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1899
1900
  	kfree(mixer);
  }
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1901
  static int snd_usb_mixer_dev_free(struct snd_device *device)
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1902
1903
1904
1905
1906
  {
  	struct usb_mixer_interface *mixer = device->device_data;
  	snd_usb_mixer_free(mixer);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1907
1908
1909
  /*
   * create mixer controls
   *
de48c7bc6   Daniel Mack   ALSA: usbaudio: c...
1910
   * walk through all UAC_OUTPUT_TERMINAL descriptors to search for mixers
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1911
   */
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1912
  static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1913
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1914
  	struct mixer_build state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1915
1916
  	int err;
  	const struct usbmix_ctl_map *map;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1917
  	void *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1918
1919
  
  	memset(&state, 0, sizeof(state));
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1920
1921
  	state.chip = mixer->chip;
  	state.mixer = mixer;
1faa5d07a   Daniel Mack   ALSA: snd-usb: op...
1922
1923
  	state.buffer = mixer->hostif->extra;
  	state.buflen = mixer->hostif->extralen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1924
1925
  
  	/* check the mapping table */
27d10f566   Clemens Ladisch   [ALSA] usb-audio ...
1926
1927
  	for (map = usbmix_ctl_maps; map->id; map++) {
  		if (map->id == state.chip->usb_id) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1928
  			state.map = map->map;
8e062ec71   Clemens Ladisch   [ALSA] usb-audio ...
1929
  			state.selector_map = map->selector_map;
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1930
  			mixer->ignore_ctl_error = map->ignore_ctl_error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1931
1932
1933
  			break;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1934

23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1935
  	p = NULL;
1faa5d07a   Daniel Mack   ALSA: snd-usb: op...
1936
1937
  	while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, mixer->hostif->extralen,
  					    p, UAC_OUTPUT_TERMINAL)) != NULL) {
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1938
  		if (mixer->protocol == UAC_VERSION_1) {
69da9bcb9   Daniel Mack   ALSA: usb-audio: ...
1939
  			struct uac1_output_terminal_descriptor *desc = p;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
  
  			if (desc->bLength < sizeof(*desc))
  				continue; /* invalid descriptor? */
  			set_bit(desc->bTerminalID, state.unitbitmap);  /* mark terminal ID as visited */
  			state.oterm.id = desc->bTerminalID;
  			state.oterm.type = le16_to_cpu(desc->wTerminalType);
  			state.oterm.name = desc->iTerminal;
  			err = parse_audio_unit(&state, desc->bSourceID);
  			if (err < 0)
  				return err;
  		} else { /* UAC_VERSION_2 */
  			struct uac2_output_terminal_descriptor *desc = p;
  
  			if (desc->bLength < sizeof(*desc))
  				continue; /* invalid descriptor? */
  			set_bit(desc->bTerminalID, state.unitbitmap);  /* mark terminal ID as visited */
  			state.oterm.id = desc->bTerminalID;
  			state.oterm.type = le16_to_cpu(desc->wTerminalType);
  			state.oterm.name = desc->iTerminal;
  			err = parse_audio_unit(&state, desc->bSourceID);
  			if (err < 0)
  				return err;
09414207d   Daniel Mack   ALSA: usb-audio: ...
1962
1963
1964
1965
1966
  
  			/* for UAC2, use the same approach to also add the clock selectors */
  			err = parse_audio_unit(&state, desc->bCSourceID);
  			if (err < 0)
  				return err;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1967
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1968
  	}
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
1969

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1970
1971
  	return 0;
  }
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
1972

7b1eda223   Daniel Mack   ALSA: usb-mixer: ...
1973
  void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid)
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
1974
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
1975
  	struct usb_mixer_elem_info *info;
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
1976
1977
1978
1979
1980
  
  	for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem)
  		snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
  			       info->elem_id);
  }
ebfdeea3d   Jaroslav Kysela   ALSA: usbmixer - ...
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
  static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer,
  				    int unitid,
  				    struct usb_mixer_elem_info *cval)
  {
  	static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN",
  				    "S8", "U8", "S16", "U16"};
  	snd_iprintf(buffer, "  Unit: %i
  ", unitid);
  	if (cval->elem_id)
  		snd_iprintf(buffer, "    Control: name=\"%s\", index=%i
  ",
  				cval->elem_id->name, cval->elem_id->index);
  	snd_iprintf(buffer, "    Info: id=%i, control=%i, cmask=0x%x, "
  			    "channels=%i, type=\"%s\"
  ", cval->id,
  			    cval->control, cval->cmask, cval->channels,
  			    val_types[cval->val_type]);
  	snd_iprintf(buffer, "    Volume: min=%i, max=%i, dBmin=%i, dBmax=%i
  ",
  			    cval->min, cval->max, cval->dBmin, cval->dBmax);
  }
  
  static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
  				    struct snd_info_buffer *buffer)
  {
  	struct snd_usb_audio *chip = entry->private_data;
  	struct usb_mixer_interface *mixer;
  	struct usb_mixer_elem_info *cval;
  	int unitid;
  
  	list_for_each_entry(mixer, &chip->mixer_list, list) {
  		snd_iprintf(buffer,
7affdc17d   Jaroslav Kysela   ALSA: usbmixer - ...
2013
2014
  			"USB Mixer: usb_id=0x%08x, ctrlif=%i, ctlerr=%i
  ",
3d8d4dcfd   Daniel Mack   ALSA: usb-audio: ...
2015
  				chip->usb_id, snd_usb_ctrl_intf(chip),
7affdc17d   Jaroslav Kysela   ALSA: usbmixer - ...
2016
  				mixer->ignore_ctl_error);
ebfdeea3d   Jaroslav Kysela   ALSA: usbmixer - ...
2017
2018
2019
2020
2021
2022
2023
2024
2025
  		snd_iprintf(buffer, "Card: %s
  ", chip->card->longname);
  		for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) {
  			for (cval = mixer->id_elems[unitid]; cval;
  						cval = cval->next_id_elem)
  				snd_usb_mixer_dump_cval(buffer, unitid, cval);
  		}
  	}
  }
e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
  static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
  				       int attribute, int value, int index)
  {
  	struct usb_mixer_elem_info *info;
  	__u8 unitid = (index >> 8) & 0xff;
  	__u8 control = (value >> 8) & 0xff;
  	__u8 channel = value & 0xff;
  
  	if (channel >= MAX_CHANNELS) {
  		snd_printk(KERN_DEBUG "%s(): bogus channel number %d
  ",
  				__func__, channel);
  		return;
  	}
  
  	for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) {
  		if (info->control != control)
  			continue;
  
  		switch (attribute) {
  		case UAC2_CS_CUR:
  			/* invalidate cache, so the value is read from the device */
  			if (channel)
  				info->cached &= ~(1 << channel);
  			else /* master channel */
  				info->cached = 0;
  
  			snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
  					info->elem_id);
  			break;
  
  		case UAC2_CS_RANGE:
  			/* TODO */
  			break;
  
  		case UAC2_CS_MEM:
  			/* TODO */
  			break;
  
  		default:
  			snd_printk(KERN_DEBUG "unknown attribute %d in interrupt
  ",
  						attribute);
  			break;
  		} /* switch */
  	}
  }
  
  static void snd_usb_mixer_interrupt(struct urb *urb)
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2075
2076
  {
  	struct usb_mixer_interface *mixer = urb->context;
e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
2077
  	int len = urb->actual_length;
edf7de31c   Oliver Neukum   ALSA: usbaudio: f...
2078
  	int ustatus = urb->status;
e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
2079

edf7de31c   Oliver Neukum   ALSA: usbaudio: f...
2080
  	if (ustatus != 0)
e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
2081
  		goto requeue;
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2082

e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
2083
2084
  	if (mixer->protocol == UAC_VERSION_1) {
  		struct uac1_status_word *status;
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2085

e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
2086
2087
2088
  		for (status = urb->transfer_buffer;
  		     len >= sizeof(*status);
  		     len -= sizeof(*status), status++) {
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2089
2090
  			snd_printd(KERN_DEBUG "status interrupt: %02x %02x
  ",
e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
2091
2092
  						status->bStatusType,
  						status->bOriginator);
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2093
  			/* ignore any notifications not from the control interface */
e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
2094
2095
  			if ((status->bStatusType & UAC1_STATUS_TYPE_ORIG_MASK) !=
  				UAC1_STATUS_TYPE_ORIG_AUDIO_CONTROL_IF)
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2096
  				continue;
e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
2097
2098
2099
  
  			if (status->bStatusType & UAC1_STATUS_TYPE_MEM_CHANGED)
  				snd_usb_mixer_rc_memory_change(mixer, status->bOriginator);
b259b10c4   Clemens Ladisch   [ALSA] usb-audio ...
2100
  			else
e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
  				snd_usb_mixer_notify_id(mixer, status->bOriginator);
  		}
  	} else { /* UAC_VERSION_2 */
  		struct uac2_interrupt_data_msg *msg;
  
  		for (msg = urb->transfer_buffer;
  		     len >= sizeof(*msg);
  		     len -= sizeof(*msg), msg++) {
  			/* drop vendor specific and endpoint requests */
  			if ((msg->bInfo & UAC2_INTERRUPT_DATA_MSG_VENDOR) ||
  			    (msg->bInfo & UAC2_INTERRUPT_DATA_MSG_EP))
  				continue;
  
  			snd_usb_mixer_interrupt_v2(mixer, msg->bAttribute,
  						   le16_to_cpu(msg->wValue),
  						   le16_to_cpu(msg->wIndex));
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2117
2118
  		}
  	}
e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
2119
2120
  
  requeue:
edf7de31c   Oliver Neukum   ALSA: usbaudio: f...
2121
  	if (ustatus != -ENOENT && ustatus != -ECONNRESET && ustatus != -ESHUTDOWN) {
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2122
2123
2124
2125
  		urb->dev = mixer->chip->dev;
  		usb_submit_urb(urb, GFP_ATOMIC);
  	}
  }
edf7de31c   Oliver Neukum   ALSA: usbaudio: f...
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
  /* stop any bus activity of a mixer */
  void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer)
  {
  	usb_kill_urb(mixer->urb);
  	usb_kill_urb(mixer->rc_urb);
  }
  
  int snd_usb_mixer_activate(struct usb_mixer_interface *mixer)
  {
  	int err;
  
  	if (mixer->urb) {
  		err = usb_submit_urb(mixer->urb, GFP_NOIO);
  		if (err < 0)
  			return err;
  	}
  
  	return 0;
  }
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2145
2146
2147
  /* create the handler for the optional status interrupt endpoint */
  static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
  {
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2148
2149
2150
2151
  	struct usb_endpoint_descriptor *ep;
  	void *transfer_buffer;
  	int buffer_length;
  	unsigned int epnum;
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2152
  	/* we need one interrupt input endpoint */
1faa5d07a   Daniel Mack   ALSA: snd-usb: op...
2153
  	if (get_iface_desc(mixer->hostif)->bNumEndpoints < 1)
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2154
  		return 0;
1faa5d07a   Daniel Mack   ALSA: snd-usb: op...
2155
  	ep = get_endpoint(mixer->hostif, 0);
913ae5a24   Julia Lawall   ALSA: sound/usb: ...
2156
  	if (!usb_endpoint_dir_in(ep) || !usb_endpoint_xfer_int(ep))
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2157
  		return 0;
42a6e66f1   Julia Lawall   ALSA: sound/usb: ...
2158
  	epnum = usb_endpoint_num(ep);
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
  	buffer_length = le16_to_cpu(ep->wMaxPacketSize);
  	transfer_buffer = kmalloc(buffer_length, GFP_KERNEL);
  	if (!transfer_buffer)
  		return -ENOMEM;
  	mixer->urb = usb_alloc_urb(0, GFP_KERNEL);
  	if (!mixer->urb) {
  		kfree(transfer_buffer);
  		return -ENOMEM;
  	}
  	usb_fill_int_urb(mixer->urb, mixer->chip->dev,
  			 usb_rcvintpipe(mixer->chip->dev, epnum),
  			 transfer_buffer, buffer_length,
e213e9cf7   Daniel Mack   ALSA: sound/usb: ...
2171
  			 snd_usb_mixer_interrupt, mixer, ep->bInterval);
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2172
2173
2174
  	usb_submit_urb(mixer->urb, GFP_KERNEL);
  	return 0;
  }
7a9b8063c   Takashi Iwai   ALSA: usb-audio -...
2175
2176
  int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
  			 int ignore_error)
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
2177
  {
86e07d346   Takashi Iwai   [ALSA] Remove xxx...
2178
  	static struct snd_device_ops dev_ops = {
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
2179
2180
2181
  		.dev_free = snd_usb_mixer_dev_free
  	};
  	struct usb_mixer_interface *mixer;
ebfdeea3d   Jaroslav Kysela   ALSA: usbmixer - ...
2182
  	struct snd_info_entry *entry;
23caaf19b   Daniel Mack   ALSA: usb-mixer: ...
2183
  	int err;
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
2184
2185
  
  	strcpy(chip->card->mixername, "USB Mixer");
561b220a4   Takashi Iwai   [ALSA] Replace wi...
2186
  	mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
2187
2188
2189
  	if (!mixer)
  		return -ENOMEM;
  	mixer->chip = chip;
7a9b8063c   Takashi Iwai   ALSA: usb-audio -...
2190
  	mixer->ignore_ctl_error = ignore_error;
291186e04   Jaroslav Kysela   ALSA: usbmixer - ...
2191
2192
  	mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems),
  				  GFP_KERNEL);
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2193
2194
2195
2196
  	if (!mixer->id_elems) {
  		kfree(mixer);
  		return -ENOMEM;
  	}
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
2197

1faa5d07a   Daniel Mack   ALSA: snd-usb: op...
2198
2199
  	mixer->hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
  	switch (get_iface_desc(mixer->hostif)->bInterfaceProtocol) {
a2acad829   Clemens Ladisch   ALSA: usb-audio: ...
2200
2201
2202
2203
2204
2205
2206
2207
  	case UAC_VERSION_1:
  	default:
  		mixer->protocol = UAC_VERSION_1;
  		break;
  	case UAC_VERSION_2:
  		mixer->protocol = UAC_VERSION_2;
  		break;
  	}
7b8a043f2   Daniel Mack   ALSA: usbmixer: b...
2208

6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2209
  	if ((err = snd_usb_mixer_controls(mixer)) < 0 ||
93446edcd   Clemens Ladisch   [ALSA] usb-audio ...
2210
2211
  	    (err = snd_usb_mixer_status_create(mixer)) < 0)
  		goto _error;
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
2212

7b1eda223   Daniel Mack   ALSA: usb-mixer: ...
2213
  	snd_usb_mixer_apply_create_quirk(mixer);
468b8fde2   Clemens Ladisch   sound: usb-audio:...
2214

84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
2215
  	err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops);
93446edcd   Clemens Ladisch   [ALSA] usb-audio ...
2216
2217
  	if (err < 0)
  		goto _error;
ebfdeea3d   Jaroslav Kysela   ALSA: usbmixer - ...
2218
2219
2220
2221
  
  	if (list_empty(&chip->mixer_list) &&
  	    !snd_card_proc_new(chip->card, "usbmixer", &entry))
  		snd_info_set_text_ops(entry, chip, snd_usb_mixer_proc_read);
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
2222
2223
  	list_add(&mixer->list, &chip->mixer_list);
  	return 0;
93446edcd   Clemens Ladisch   [ALSA] usb-audio ...
2224
2225
2226
2227
  
  _error:
  	snd_usb_mixer_free(mixer);
  	return err;
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
2228
2229
2230
2231
  }
  
  void snd_usb_mixer_disconnect(struct list_head *p)
  {
6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2232
  	struct usb_mixer_interface *mixer;
7b1eda223   Daniel Mack   ALSA: usb-mixer: ...
2233

6639b6c23   Clemens Ladisch   [ALSA] usb-audio ...
2234
  	mixer = list_entry(p, struct usb_mixer_interface, list);
68df9de1d   Mariusz Kozlowski   usb: usbmixer fre...
2235
2236
  	usb_kill_urb(mixer->urb);
  	usb_kill_urb(mixer->rc_urb);
84957a8ab   Clemens Ladisch   [ALSA] usb-audio ...
2237
  }