mixer.c revision 7b1eda223debcba706ab989a09c4eecb327aebdf
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   (Tentative) USB Audio Driver for ALSA
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   Mixer control part
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   Many codes borrowed from audio.c by
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    Alan Cox (alan@lxorguk.ukuu.org.uk)
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	    Thomas Sailer (sailer@ife.ee.ethz.ch)
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   This program is free software; you can redistribute it and/or modify
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   it under the terms of the GNU General Public License as published by
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   the Free Software Foundation; either version 2 of the License, or
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   (at your option) any later version.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   This program is distributed in the hope that it will be useful,
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   but WITHOUT ANY WARRANTY; without even the implied warranty of
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   GNU General Public License for more details.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   You should have received a copy of the GNU General Public License
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   along with this program; if not, write to the Free Software
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h>
3528e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack#include <linux/usb/audio.h>
3628e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sound/core.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sound/control.h>
39b259b10c420a59a2fdbcf5a3498253ebcbdffa1eClemens Ladisch#include <sound/hwdep.h>
40aafad5629a949d0ad41180f8a746b6cd7654e317Clemens Ladisch#include <sound/info.h>
417bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai#include <sound/tlv.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "usbaudio.h"
443e1aebef6fb55e35668d2d7cf608cf03f30c904fDaniel Mack#include "usbmixer.h"
45e5779998bf8b70e48a6cc208c8b61b33bd6117eaDaniel Mack#include "helper.h"
467b1eda223debcba706ab989a09c4eecb327aebdfDaniel Mack#include "mixer_quirks.h"
474d1a70dad0e1c44dc0725de6de25aceead48599eRaimonds Cicans
48ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela#define MAX_ID_ELEMS	256
49ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct usb_audio_term {
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int id;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int type;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int channels;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int chconfig;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int name;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct usbmix_name_map;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6086e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistruct mixer_build {
6186e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct snd_usb_audio *chip;
6284957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	struct usb_mixer_interface *mixer;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buffer;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int buflen;
65291186e049d7f8178ad31d43c38a53889f25d79eJaroslav Kysela	DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS);
6686e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_audio_term oterm;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct usbmix_name_map *map;
688e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch	const struct usbmix_selector_map *selector_map;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_MIXER_BOOLEAN,
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_MIXER_INV_BOOLEAN,
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_MIXER_S8,
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_MIXER_U8,
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_MIXER_S16,
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_MIXER_U16,
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_UPDOWN = 1,
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_UPDOWN_SWITCH = 1,
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_UPDOWN_MODE_SEL = 2,
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_PROLOGIC = 2,
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_PROLOGIC_SWITCH = 1,
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_PROLOGIC_MODE_SEL = 2,
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_3DENH = 3,
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_3DENH_SWITCH = 1,
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_3DENH_SPACE = 2,
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_REVERB = 4,
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_REVERB_SWITCH = 1,
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_REVERB_LEVEL = 2,
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_REVERB_TIME = 3,
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_REVERB_DELAY = 4,
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_CHORUS = 5,
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_CHORUS_SWITCH = 1,
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_CHORUS_LEVEL = 2,
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_CHORUS_RATE = 3,
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_CHORUS_DEPTH = 4,
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_DCR = 6,
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_DCR_SWITCH = 1,
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_DCR_RATIO = 2,
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_DCR_MAX_AMP = 3,
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_DCR_THRESHOLD = 4,
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_DCR_ATTACK = 5,
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	USB_PROC_DCR_RELEASE = 6,
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1147d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk/*E-mu 0202(0404) eXtension Unit(XU) control*/
1157d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchukenum {
1167d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	USB_XU_CLOCK_RATE 		= 0xe301,
1177d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	USB_XU_CLOCK_SOURCE		= 0xe302,
1187d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	USB_XU_DIGITAL_IO_STATUS	= 0xe303,
1197d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	USB_XU_DEVICE_OPTIONS		= 0xe304,
1207d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	USB_XU_DIRECT_MONITORING	= 0xe305,
1217d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	USB_XU_METERING			= 0xe306
1227d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk};
1237d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchukenum {
1247d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	USB_XU_CLOCK_SOURCE_SELECTOR = 0x02,	/* clock source*/
1257d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	USB_XU_CLOCK_RATE_SELECTOR = 0x03,	/* clock rate */
1267d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	USB_XU_DIGITAL_FORMAT_SELECTOR = 0x01,	/* the spdif format */
1277d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	USB_XU_SOFT_LIMIT_SELECTOR = 0x03	/* soft limiter */
1287d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk};
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * manual mapping of mixer names
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if the mixer topology is too complicated and the parsed names are
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ambiguous, add the entries in usbmixer_maps.c.
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "usbmixer_maps.c"
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
137c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kyselastatic const struct usbmix_name_map *
138c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kyselafind_map(struct mixer_build *state, int unitid, int control)
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
140c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	const struct usbmix_name_map *p = state->map;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
142c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	if (!p)
143c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		return NULL;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (p = state->map; p->id; p++) {
146c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		if (p->id == unitid &&
147c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		    (!control || !p->control || control == p->control))
148c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela			return p;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
150c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	return NULL;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
153c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela/* get the mapped name if the unit matches */
154c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kyselastatic int
155c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kyselacheck_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen)
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
157c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	if (!p || !p->name)
158c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		return 0;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
160c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	buflen--;
161c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	return strlcpy(buf, p->name, buflen);
162c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela}
163c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela
164c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela/* check whether the control should be ignored */
165c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kyselastatic inline int
166c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kyselacheck_ignored_ctl(const struct usbmix_name_map *p)
167c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela{
168c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	if (!p || p->name || p->dB)
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
170c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	return 1;
171c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela}
172c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela
173c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela/* dB mapping */
174c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kyselastatic inline void check_mapped_dB(const struct usbmix_name_map *p,
175c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela				   struct usb_mixer_elem_info *cval)
176c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela{
177c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	if (p && p->dB) {
178c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		cval->dBmin = p->dB->min;
179c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		cval->dBmax = p->dB->max;
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1838e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch/* get the mapped selector source name */
18486e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int check_mapped_selector_name(struct mixer_build *state, int unitid,
1858e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch				      int index, char *buf, int buflen)
1868e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch{
1878e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch	const struct usbmix_selector_map *p;
1888e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch
1898e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch	if (! state->selector_map)
1908e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch		return 0;
1918e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch	for (p = state->selector_map; p->id; p++) {
1928e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch		if (p->id == unitid && index < p->count)
1938e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch			return strlcpy(buf, p->names[index], buflen);
1948e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch	}
1958e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch	return 0;
1968e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch}
1978e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * find an audio control unit with the given unit id
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
20186e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic void *find_audio_control_unit(struct mixer_build *state, unsigned char unit)
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *p;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p = NULL;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((p = snd_usb_find_desc(state->buffer, state->buflen, p,
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      USB_DT_CS_INTERFACE)) != NULL) {
208de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC_EXTENSION_UNIT_V1 && p[3] == unit)
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return p;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * copy a string with the given id
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
21886e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int snd_usb_copy_string_desc(struct mixer_build *state, int index, char *buf, int maxlen)
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len = usb_string(state->chip->dev, index, buf, maxlen - 1);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[len] = 0;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * convert from the byte/word on usb descriptor to the zero-based integer
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
22886e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int convert_signed_value(struct usb_mixer_elem_info *cval, int val)
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cval->val_type) {
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_MIXER_BOOLEAN:
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return !!val;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_MIXER_INV_BOOLEAN:
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return !val;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_MIXER_U8:
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val &= 0xff;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_MIXER_S8:
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val &= 0xff;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (val >= 0x80)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			val -= 0x100;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_MIXER_U16:
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val &= 0xffff;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_MIXER_S16:
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val &= 0xffff;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (val >= 0x8000)
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			val -= 0x10000;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return val;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * convert from the zero-based int to the byte/word for usb descriptor
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
25886e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int convert_bytes_value(struct usb_mixer_elem_info *cval, int val)
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cval->val_type) {
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_MIXER_BOOLEAN:
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return !!val;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_MIXER_INV_BOOLEAN:
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return !val;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_MIXER_S8:
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_MIXER_U8:
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return val & 0xff;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_MIXER_S16:
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case USB_MIXER_U16:
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return val & 0xffff;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0; /* not reached */
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27586e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int get_relative_value(struct usb_mixer_elem_info *cval, int val)
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! cval->res)
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cval->res = 1;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val < cval->min)
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
28114790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai	else if (val >= cval->max)
28214790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai		return (cval->max - cval->min + cval->res - 1) / cval->res;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (val - cval->min) / cval->res;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28786e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int get_abs_value(struct usb_mixer_elem_info *cval, int val)
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val < 0)
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return cval->min;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! cval->res)
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cval->res = 1;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val *= cval->res;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val += cval->min;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val > cval->max)
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return cval->max;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return val;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * retrieve a mixer value
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30586e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret)
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char buf[2];
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int timeout = 10;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (timeout-- > 0) {
31284957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch		if (snd_usb_ctl_msg(cval->mixer->chip->dev,
31384957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch				    usb_rcvctrlpipe(cval->mixer->chip->dev, 0),
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    request,
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
31684957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch				    validx, cval->mixer->ctrlif | (cval->id << 8),
317a04395ead6d17c83da64264b6fe78f852a648202Thomas Reitmayr				    buf, val_len, 100) >= val_len) {
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
32284957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
32384957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch		    request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type);
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32786e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *value)
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
329de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack	return get_ctl_value(cval, UAC_GET_CUR, validx, value);
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* channel = 0: master, 1 = first channel */
333641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwaistatic inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval,
334641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai				  int channel, int *value)
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
336de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack	return get_ctl_value(cval, UAC_GET_CUR, (cval->control << 8) | channel, value);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
339641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwaistatic int get_cur_mix_value(struct usb_mixer_elem_info *cval,
340641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			     int channel, int index, int *value)
341641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai{
342641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	int err;
343641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai
344641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	if (cval->cached & (1 << channel)) {
345641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai		*value = cval->cache_val[index];
346641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai		return 0;
347641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	}
348641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	err = get_cur_mix_raw(cval, channel, value);
349641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	if (err < 0) {
350641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai		if (!cval->mixer->ignore_ctl_error)
351641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			snd_printd(KERN_ERR "cannot get current value for "
352641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai				   "control %d ch %d: err = %d\n",
353641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai				   cval->control, channel, err);
354641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai		return err;
355641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	}
356641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	cval->cached |= 1 << channel;
357641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	cval->cache_val[index] = *value;
358641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	return 0;
359641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai}
360641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai
361641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set a mixer value
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3667b1eda223debcba706ab989a09c4eecb327aebdfDaniel Mackint snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
3677b1eda223debcba706ab989a09c4eecb327aebdfDaniel Mack				int request, int validx, int value_set)
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char buf[2];
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int timeout = 10;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	value_set = convert_bytes_value(cval, value_set);
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = value_set & 0xff;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[1] = (value_set >> 8) & 0xff;
376cf3f9130f48ed04f32a31cfad21f576d45b8788bViral Mehta	while (timeout-- > 0)
37784957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch		if (snd_usb_ctl_msg(cval->mixer->chip->dev,
37884957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch				    usb_sndctrlpipe(cval->mixer->chip->dev, 0),
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    request,
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
38184957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch				    validx, cval->mixer->ctrlif | (cval->id << 8),
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    buf, val_len, 100) >= 0)
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
38484957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
38584957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch		    request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type, buf[0], buf[1]);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
38986e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value)
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3917b1eda223debcba706ab989a09c4eecb327aebdfDaniel Mack	return snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, validx, value);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
394641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwaistatic int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
395641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			     int index, int value)
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
397641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	int err;
3987b1eda223debcba706ab989a09c4eecb327aebdfDaniel Mack	err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel,
399641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			    value);
400641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	if (err < 0)
401641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai		return err;
402641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	cval->cached |= 1 << channel;
403641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	cval->cache_val[index] = value;
404641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	return 0;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4077bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai/*
4087bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai * TLV callback for mixer volume controls
4097bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai */
4107bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwaistatic int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
4117bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai			 unsigned int size, unsigned int __user *_tlv)
4127bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai{
4137bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai	struct usb_mixer_elem_info *cval = kcontrol->private_data;
414b8e1c73f4608b8b9ca1e8f1a09f9fd8684e78071Takashi Iwai	DECLARE_TLV_DB_MINMAX(scale, 0, 0);
4157bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai
4167bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai	if (size < sizeof(scale))
4177bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai		return -ENOMEM;
418c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	scale[2] = cval->dBmin;
419c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	scale[3] = cval->dBmax;
4207bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai	if (copy_to_user(_tlv, scale, sizeof(scale)))
4217bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai		return -EFAULT;
4227bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai	return 0;
4237bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai}
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parser routines begin here...
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42986e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int parse_audio_unit(struct mixer_build *state, int unitid);
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * check if the input/output channel routing is enabled on the given bitmap.
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * used for mixer unit parser
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_matrix_bitmap(unsigned char *bmap, int ich, int och, int num_outs)
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int idx = ich * num_outs + och;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return bmap[idx >> 3] & (0x80 >> (idx & 7));
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * add an alsa control element
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * search and increment the index until an empty slot is found.
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if failed, give up and free the control instance.
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45086e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int add_control_to_empty(struct mixer_build *state, struct snd_kcontrol *kctl)
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
45286e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval = kctl->private_data;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
45484957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch
45584957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	while (snd_ctl_find_id(state->chip->card, &kctl->id))
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kctl->id.index++;
45784957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) {
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printd(KERN_ERR "cannot add control (err = %d)\n", err);
4596639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		return err;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4616639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	cval->elem_id = &kctl->id;
4626639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	cval->next_id_elem = state->mixer->id_elems[cval->id];
4636639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	state->mixer->id_elems[cval->id] = cval;
4646639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	return 0;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get a terminal name string
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct iterm_name_combo {
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int type;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *name;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} iterm_names[] = {
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0300, "Output" },
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0301, "Speaker" },
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0302, "Headphone" },
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0303, "HMD Audio" },
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0304, "Desktop Speaker" },
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0305, "Room Speaker" },
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0306, "Com Speaker" },
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0307, "LFE" },
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0600, "External In" },
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0601, "Analog In" },
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0602, "Digital In" },
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0603, "Line" },
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0604, "Legacy In" },
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0605, "IEC958 In" },
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0606, "1394 DA Stream" },
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0607, "1394 DV Stream" },
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0700, "Embedded" },
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0701, "Noise Source" },
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0702, "Equalization Noise" },
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0703, "CD" },
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0704, "DAT" },
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0705, "DCC" },
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0706, "MiniDisk" },
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0707, "Analog Tape" },
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0708, "Phonograph" },
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0709, "VCR Audio" },
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x070a, "Video Disk Audio" },
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x070b, "DVD Audio" },
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x070c, "TV Tuner Audio" },
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x070d, "Satellite Rec Audio" },
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x070e, "Cable Tuner Audio" },
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x070f, "DSS Audio" },
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0710, "Radio Receiver" },
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0711, "Radio Transmitter" },
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0712, "Multi-Track Recorder" },
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0x0713, "Synthesizer" },
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0 },
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51586e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm,
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 unsigned char *name, int maxlen, int term_only)
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct iterm_name_combo *names;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (iterm->name)
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return snd_usb_copy_string_desc(state, iterm->name, name, maxlen);
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* virtual type - not a real terminal */
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (iterm->type >> 16) {
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (term_only)
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (iterm->type >> 16) {
528de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		case UAC_SELECTOR_UNIT:
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strcpy(name, "Selector"); return 8;
530de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		case UAC_PROCESSING_UNIT_V1:
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strcpy(name, "Process Unit"); return 12;
532de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		case UAC_EXTENSION_UNIT_V1:
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strcpy(name, "Ext Unit"); return 8;
534de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		case UAC_MIXER_UNIT:
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strcpy(name, "Mixer"); return 5;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return sprintf(name, "Unit %d", iterm->id);
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (iterm->type & 0xff00) {
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0100:
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(name, "PCM"); return 3;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0200:
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(name, "Mic"); return 3;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0400:
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(name, "Headset"); return 7;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0500:
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(name, "Phone"); return 5;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (names = iterm_names; names->type; names++)
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (names->type == iterm->type) {
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strcpy(name, names->name);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return strlen(names->name);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parse the source unit recursively until it reaches to a terminal
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or a branched unit.
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
56586e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term)
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *p1;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(term, 0, sizeof(*term));
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while ((p1 = find_audio_control_unit(state, id)) != NULL) {
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		term->id = id;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (p1[2]) {
573de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		case UAC_INPUT_TERMINAL:
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->type = combine_word(p1 + 4);
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->channels = p1[7];
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->chconfig = combine_word(p1 + 8);
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->name = p1[11];
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
579de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		case UAC_FEATURE_UNIT:
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			id = p1[4];
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break; /* continue to parse */
582de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		case UAC_MIXER_UNIT:
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->type = p1[2] << 16; /* virtual type */
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->channels = p1[5 + p1[4]];
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->chconfig = combine_word(p1 + 6 + p1[4]);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->name = p1[p1[0] - 1];
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
588de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		case UAC_SELECTOR_UNIT:
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* call recursively to retrieve the channel info */
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (check_input_term(state, p1[5], term) < 0)
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -ENODEV;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->type = p1[2] << 16; /* virtual type */
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->id = id;
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->name = p1[9 + p1[0] - 1];
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
596de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		case UAC_PROCESSING_UNIT_V1:
597de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		case UAC_EXTENSION_UNIT_V1:
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (p1[6] == 1) {
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				id = p1[7];
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break; /* continue to parse */
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->type = p1[2] << 16; /* virtual type */
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->channels = p1[7 + p1[6]];
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->chconfig = combine_word(p1 + 8 + p1[6]);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			term->name = p1[12 + p1[6] + p1[11 + p1[6]]];
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENODEV;
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Feature Unit
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* feature unit control information */
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct usb_feature_control_info {
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const char *name;
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int type;	/* control type (mute, volume, etc.) */
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_feature_control_info audio_feature_info[] = {
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "Mute",		USB_MIXER_INV_BOOLEAN },
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "Volume",		USB_MIXER_S16 },
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "Tone Control - Bass",	USB_MIXER_S8 },
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "Tone Control - Mid",		USB_MIXER_S8 },
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "Tone Control - Treble",	USB_MIXER_S8 },
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "Graphic Equalizer",		USB_MIXER_S8 }, /* FIXME: not implemeted yet */
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "Auto Gain Control",	USB_MIXER_BOOLEAN },
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "Delay Control",	USB_MIXER_U16 },
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "Bass Boost",		USB_MIXER_BOOLEAN },
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "Loudness",		USB_MIXER_BOOLEAN },
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* private_free callback */
64086e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic void usb_mixer_elem_free(struct snd_kcontrol *kctl)
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6424d572776d4dfa2d5385a2ec3acec3cc059149e13Jesper Juhl	kfree(kctl->private_data);
6434d572776d4dfa2d5385a2ec3acec3cc059149e13Jesper Juhl	kctl->private_data = NULL;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interface to ALSA control for feature/mixer units
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * retrieve the minimum and maximum values for the specified control
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
65486e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* for failsafe */
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->min = default_min;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->max = cval->min + 1;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->res = 1;
660c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	cval->dBmin = cval->dBmax = 0;
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cval->val_type == USB_MIXER_BOOLEAN ||
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    cval->val_type == USB_MIXER_INV_BOOLEAN) {
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cval->initialized = 1;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int minchn = 0;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cval->cmask) {
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int i;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 0; i < MAX_CHANNELS; i++)
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (cval->cmask & (1 << i)) {
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					minchn = i + 1;
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
675de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
676de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		    get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
67784957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch			snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n",
67884957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch				   cval->id, cval->mixer->ctrlif, cval->control, cval->id);
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
681de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) {
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cval->res = 1;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int last_valid_res = cval->res;
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			while (cval->res > 1) {
6877b1eda223debcba706ab989a09c4eecb327aebdfDaniel Mack				if (snd_usb_mixer_set_ctl_value(cval, UAC_SET_RES,
6887b1eda223debcba706ab989a09c4eecb327aebdfDaniel Mack								(cval->control << 8) | minchn, cval->res / 2) < 0)
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cval->res /= 2;
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
692de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack			if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0)
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				cval->res = last_valid_res;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cval->res == 0)
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cval->res = 1;
69714790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai
69814790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai		/* Additional checks for the proper resolution
69914790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai		 *
70014790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai		 * Some devices report smaller resolutions than actually
70114790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai		 * reacting.  They don't return errors but simply clip
70214790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai		 * to the lower aligned value.
70314790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai		 */
70414790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai		if (cval->min + cval->res < cval->max) {
70514790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai			int last_valid_res = cval->res;
70614790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai			int saved, test, check;
707641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			get_cur_mix_raw(cval, minchn, &saved);
70814790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai			for (;;) {
70914790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai				test = saved;
71014790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai				if (test < cval->max)
71114790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai					test += cval->res;
71214790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai				else
71314790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai					test -= cval->res;
71414790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai				if (test < cval->min || test > cval->max ||
715641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai				    set_cur_mix_value(cval, minchn, 0, test) ||
716641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai				    get_cur_mix_raw(cval, minchn, &check)) {
71714790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai					cval->res = last_valid_res;
71814790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai					break;
71914790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai				}
72014790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai				if (test == check)
72114790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai					break;
72214790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai				cval->res *= 2;
72314790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai			}
724641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			set_cur_mix_value(cval, minchn, 0, saved);
72514790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai		}
72614790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cval->initialized = 1;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
729c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela
730c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	/* USB descriptions contain the dB scale in 1/256 dB unit
731c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	 * while ALSA TLV contains in 1/100 dB unit
732c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	 */
733c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	cval->dBmin = (convert_signed_value(cval, cval->min) * 100) / 256;
734c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	cval->dBmax = (convert_signed_value(cval, cval->max) * 100) / 256;
735c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	if (cval->dBmin > cval->dBmax) {
736c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		/* something is wrong; assume it's either from/to 0dB */
737c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		if (cval->dBmin < 0)
738c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela			cval->dBmax = 0;
739c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		else if (cval->dBmin > 0)
740c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela			cval->dBmin = 0;
741c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		if (cval->dBmin > cval->dBmax) {
742c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela			/* totally crap, return an error */
743c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela			return -EINVAL;
744c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		}
745c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	}
746c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get a feature/mixer unit info */
75286e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
75486e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval = kcontrol->private_data;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cval->val_type == USB_MIXER_BOOLEAN ||
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    cval->val_type == USB_MIXER_INV_BOOLEAN)
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uinfo->count = cval->channels;
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cval->val_type == USB_MIXER_BOOLEAN ||
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    cval->val_type == USB_MIXER_INV_BOOLEAN) {
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uinfo->value.integer.min = 0;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uinfo->value.integer.max = 1;
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (! cval->initialized)
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			get_min_max(cval,  0);
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uinfo->value.integer.min = 0;
77014790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai		uinfo->value.integer.max =
77114790f1c73cfa4d4a22ac10b4501b4831380683cTakashi Iwai			(cval->max - cval->min + cval->res - 1) / cval->res;
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get the current value from feature/mixer unit */
77786e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
77986e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval = kcontrol->private_data;
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int c, cnt, val, err;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
782641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai	ucontrol->value.integer.value[0] = cval->min;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cval->cmask) {
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cnt = 0;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (c = 0; c < MAX_CHANNELS; c++) {
786641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			if (!(cval->cmask & (1 << c)))
787641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai				continue;
788641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			err = get_cur_mix_value(cval, c + 1, cnt, &val);
789641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			if (err < 0)
790641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai				return cval->mixer->ignore_ctl_error ? 0 : err;
791641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			val = get_relative_value(cval, val);
792641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			ucontrol->value.integer.value[cnt] = val;
793641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			cnt++;
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
795641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai		return 0;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* master channel */
798641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai		err = get_cur_mix_value(cval, 0, 0, &val);
799641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai		if (err < 0)
800641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			return cval->mixer->ignore_ctl_error ? 0 : err;
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = get_relative_value(cval, val);
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucontrol->value.integer.value[0] = val;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* put the current value to feature/mixer unit */
80886e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
81086e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval = kcontrol->private_data;
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int c, cnt, val, oval, err;
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int changed = 0;
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cval->cmask) {
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cnt = 0;
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (c = 0; c < MAX_CHANNELS; c++) {
817641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			if (!(cval->cmask & (1 << c)))
818641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai				continue;
819641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			err = get_cur_mix_value(cval, c + 1, cnt, &oval);
820641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			if (err < 0)
821641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai				return cval->mixer->ignore_ctl_error ? 0 : err;
822641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			val = ucontrol->value.integer.value[cnt];
823641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			val = get_abs_value(cval, val);
824641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			if (oval != val) {
825641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai				set_cur_mix_value(cval, c + 1, cnt, val);
826641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai				changed = 1;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
828641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			cnt++;
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* master channel */
832641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai		err = get_cur_mix_value(cval, 0, 0, &oval);
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err < 0)
834641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			return cval->mixer->ignore_ctl_error ? 0 : err;
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = ucontrol->value.integer.value[0];
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = get_abs_value(cval, val);
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (val != oval) {
838641b4879444c0edb276fedca5c2fcbd2e5c70044Takashi Iwai			set_cur_mix_value(cval, 0, 0, val);
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			changed = 1;
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return changed;
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
84586e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic struct snd_kcontrol_new usb_feature_unit_ctl = {
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name = "", /* will be filled later manually */
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.info = mixer_ctl_feature_info,
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get = mixer_ctl_feature_get,
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.put = mixer_ctl_feature_put,
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * build a feature control
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
85808d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwaistatic size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str)
85908d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwai{
86008d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwai	return strlcat(kctl->id.name, str, sizeof(kctl->id.name));
86108d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwai}
86208d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwai
86386e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      unsigned int ctl_mask, int control,
86586e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai			      struct usb_audio_term *iterm, int unitid)
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int len = 0;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int mapped_name = 0;
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int nameid = desc[desc[0] - 1];
87086e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct snd_kcontrol *kctl;
87186e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval;
872c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	const struct usbmix_name_map *map;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	control++; /* change from zero-based to 1-based value */
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
87645d760567a7d773237b8996584a4ae0440d5e369Daniel Mack	if (control == UAC_GRAPHIC_EQUALIZER_CONTROL) {
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME: not supported yet */
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	map = find_map(state, unitid, control);
882c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	if (check_ignored_ctl(map))
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
885561b220a4dece18d67177413e6fa21b49aa4acceTakashi Iwai	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! cval) {
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printk(KERN_ERR "cannot malloc kcontrol\n");
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
89084957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	cval->mixer = state->mixer;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->id = unitid;
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->control = control;
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->cmask = ctl_mask;
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->val_type = audio_feature_info[control-1].type;
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ctl_mask == 0)
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cval->channels = 1;	/* master channel */
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int i, c = 0;
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < 16; i++)
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ctl_mask & (1 << i))
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				c++;
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cval->channels = c;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get min/max values */
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	get_min_max(cval, 0);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! kctl) {
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printk(KERN_ERR "cannot malloc kcontrol\n");
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(cval);
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kctl->private_free = usb_mixer_elem_free;
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
916c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mapped_name = len != 0;
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! len && nameid)
919c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		len = snd_usb_copy_string_desc(state, nameid,
920c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela				kctl->id.name, sizeof(kctl->id.name));
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (control) {
92345d760567a7d773237b8996584a4ae0440d5e369Daniel Mack	case UAC_MUTE_CONTROL:
92445d760567a7d773237b8996584a4ae0440d5e369Daniel Mack	case UAC_VOLUME_CONTROL:
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* determine the control name.  the rule is:
9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * - if a name id is given in descriptor, use it.
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * - if the connected input can be determined, then use the name
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *   of terminal type.
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * - if the connected output can be determined, use it.
9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * - otherwise, anonymous name.
9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (! len) {
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 1);
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (! len)
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = get_term_name(state, &state->oterm, kctl->id.name, sizeof(kctl->id.name), 1);
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (! len)
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = snprintf(kctl->id.name, sizeof(kctl->id.name),
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       "Feature %d", unitid);
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* determine the stream direction:
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * if the connected output is USB stream, then it's likely a
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * capture stream.  otherwise it should be playback (hopefully :)
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (! mapped_name && ! (state->oterm.type >> 16)) {
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((state->oterm.type & 0xff00) == 0x0100) {
94608d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwai				len = append_ctl_name(kctl, " Capture");
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
94808d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwai				len = append_ctl_name(kctl, " Playback");
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
95145d760567a7d773237b8996584a4ae0440d5e369Daniel Mack		append_ctl_name(kctl, control == UAC_MUTE_CONTROL ?
95208d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwai				" Switch" : " Volume");
95345d760567a7d773237b8996584a4ae0440d5e369Daniel Mack		if (control == UAC_VOLUME_CONTROL) {
9547bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai			kctl->tlv.c = mixer_vol_tlv;
9557bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai			kctl->vd[0].access |=
9567bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai				SNDRV_CTL_ELEM_ACCESS_TLV_READ |
9577bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai				SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
958c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela			check_mapped_dB(map, cval);
9597bc5ba7e02f63a5732fdf99e7471f54738f6f918Takashi Iwai		}
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (! len)
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strlcpy(kctl->id.name, audio_feature_info[control-1].name,
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sizeof(kctl->id.name));
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9692cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher	/* volume control quirks */
97027d10f5664c7650af3b2ffadfefaf19b36dc7bd8Clemens Ladisch	switch (state->chip->usb_id) {
97127d10f5664c7650af3b2ffadfefaf19b36dc7bd8Clemens Ladisch	case USB_ID(0x0471, 0x0101):
97227d10f5664c7650af3b2ffadfefaf19b36dc7bd8Clemens Ladisch	case USB_ID(0x0471, 0x0104):
97327d10f5664c7650af3b2ffadfefaf19b36dc7bd8Clemens Ladisch	case USB_ID(0x0471, 0x0105):
97427d10f5664c7650af3b2ffadfefaf19b36dc7bd8Clemens Ladisch	case USB_ID(0x0672, 0x1041):
9752cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher	/* quirk for UDA1321/N101.
9762cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher	 * note that detection between firmware 2.1.1.7 (N101)
9772cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher	 * and later 2.1.1.21 is not very clear from datasheets.
9782cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher	 * I hope that the min value is -15360 for newer firmware --jk
9792cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher	 */
98027d10f5664c7650af3b2ffadfefaf19b36dc7bd8Clemens Ladisch		if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
98127d10f5664c7650af3b2ffadfefaf19b36dc7bd8Clemens Ladisch		    cval->min == -15616) {
9822cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher			snd_printk(KERN_INFO
9832cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher				 "set volume quirk for UDA1321/N101 chip\n");
98427d10f5664c7650af3b2ffadfefaf19b36dc7bd8Clemens Ladisch			cval->max = -256;
98527d10f5664c7650af3b2ffadfefaf19b36dc7bd8Clemens Ladisch		}
9862cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher		break;
9872cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher
9882cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher	case USB_ID(0x046d, 0x09a4):
9892cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher		if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
9902cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher			snd_printk(KERN_INFO
9912cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher				"set volume quirk for QuickCam E3500\n");
9922cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher			cval->min = 6080;
9932cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher			cval->max = 8768;
9942cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher			cval->res = 192;
9952cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher		}
9962cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher		break;
9972cf313ee75ddf6220b5d623b749b1bb79458307fAlexey Fisher
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res);
100284957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	add_control_to_empty(state, kctl);
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parse a feature unit
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * most of controlls are defined here.
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
101228e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mackstatic int parse_audio_feature_unit(struct mixer_build *state, int unitid, void *_ftr)
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int channels, i, j;
101586e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_audio_term iterm;
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int master_bits, first_ch_bits;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err, csize;
101828e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack	struct uac_feature_unit_descriptor *ftr = _ftr;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
102028e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack	if (ftr->bLength < 7 || ! (csize = ftr->bControlSize) || ftr->bLength < 7 + csize) {
1021de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack		snd_printk(KERN_ERR "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n", unitid);
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* parse the source unit */
102628e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack	if ((err = parse_audio_unit(state, ftr->bSourceID)) < 0)
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* determine the input source type and name */
103028e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack	if (check_input_term(state, ftr->bSourceID, &iterm) < 0)
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
103328e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack	channels = (ftr->bLength - 7) / csize - 1;
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
103528e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack	master_bits = snd_usb_combine_bytes(ftr->controls, csize);
10360c3cee57efcb1c79d62b1238c0d22afef4599247Javier Kohen	/* master configuration quirks */
10370c3cee57efcb1c79d62b1238c0d22afef4599247Javier Kohen	switch (state->chip->usb_id) {
10380c3cee57efcb1c79d62b1238c0d22afef4599247Javier Kohen	case USB_ID(0x08bb, 0x2702):
10390c3cee57efcb1c79d62b1238c0d22afef4599247Javier Kohen		snd_printk(KERN_INFO
10400c3cee57efcb1c79d62b1238c0d22afef4599247Javier Kohen			   "usbmixer: master volume quirk for PCM2702 chip\n");
10410c3cee57efcb1c79d62b1238c0d22afef4599247Javier Kohen		/* disable non-functional volume control */
104245d760567a7d773237b8996584a4ae0440d5e369Daniel Mack		master_bits &= ~UAC_FU_VOLUME;
10430c3cee57efcb1c79d62b1238c0d22afef4599247Javier Kohen		break;
10440c3cee57efcb1c79d62b1238c0d22afef4599247Javier Kohen	}
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (channels > 0)
104628e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack		first_ch_bits = snd_usb_combine_bytes(ftr->controls + csize, csize);
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		first_ch_bits = 0;
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check all control types */
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 10; i++) {
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned int ch_bits = 0;
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = 0; j < channels; j++) {
105328e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack			unsigned int mask = snd_usb_combine_bytes(ftr->controls + csize * (j+1), csize);
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (mask & (1 << i))
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ch_bits |= (1 << j);
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ch_bits & 1) /* the first channel must be set (for ease of programming) */
105828e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack			build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid);
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (master_bits & (1 << i))
106028e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack			build_feature_ctl(state, _ftr, 0, i, &iterm, unitid);
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Mixer Unit
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * build a mixer unit control
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the callbacks are identical with feature unit.
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * input channel number (zero based) is given in control field instead.
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
107886e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc,
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 int in_pin, int in_ch, int unitid,
108086e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai				 struct usb_audio_term *iterm)
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
108286e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval;
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int input_pins = desc[4];
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int num_outs = desc[5 + input_pins];
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i, len;
108686e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct snd_kcontrol *kctl;
1087c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	const struct usbmix_name_map *map;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1089c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	map = find_map(state, unitid, 0);
1090c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	if (check_ignored_ctl(map))
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1093561b220a4dece18d67177413e6fa21b49aa4acceTakashi Iwai	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! cval)
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
109784957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	cval->mixer = state->mixer;
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->id = unitid;
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->control = in_ch + 1; /* based on 1 */
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->val_type = USB_MIXER_S16;
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < num_outs; i++) {
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (check_matrix_bitmap(desc + 9 + input_pins, in_ch, i, num_outs)) {
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cval->cmask |= (1 << i);
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cval->channels++;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get min/max values */
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	get_min_max(cval, 0);
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! kctl) {
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printk(KERN_ERR "cannot malloc kcontrol\n");
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(cval);
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kctl->private_free = usb_mixer_elem_free;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1119c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! len)
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0);
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! len)
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1);
112408d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwai	append_ctl_name(kctl, " Volume");
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
112884957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	add_control_to_empty(state, kctl);
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parse a mixer unit
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
113586e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int parse_audio_mixer_unit(struct mixer_build *state, int unitid, unsigned char *desc)
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
113786e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_audio_term iterm;
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int input_pins, num_ins, num_outs;
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pin, ich, err;
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (desc[0] < 11 || ! (input_pins = desc[4]) || ! (num_outs = desc[5 + input_pins])) {
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printk(KERN_ERR "invalid MIXER UNIT descriptor %d\n", unitid);
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* no bmControls field (e.g. Maya44) -> ignore */
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (desc[0] <= 10 + input_pins) {
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printdd(KERN_INFO "MU %d has no bmControls field\n", unitid);
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	num_ins = 0;
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ich = 0;
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (pin = 0; pin < input_pins; pin++) {
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = parse_audio_unit(state, desc[5 + pin]);
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err < 0)
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = check_input_term(state, desc[5 + pin], &iterm);
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err < 0)
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		num_ins += iterm.channels;
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (; ich < num_ins; ++ich) {
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int och, ich_has_controls = 0;
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (och = 0; och < num_outs; ++och) {
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (check_matrix_bitmap(desc + 9 + input_pins,
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							ich, och, num_outs)) {
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					ich_has_controls = 1;
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					break;
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ich_has_controls)
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				build_mixer_unit_ctl(state, desc, pin, ich,
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						     unitid, &iterm);
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Processing Unit / Extension Unit
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get callback for processing/extension unit */
118586e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
118786e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval = kcontrol->private_data;
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err, val;
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = get_cur_ctl_value(cval, cval->control << 8, &val);
119184957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	if (err < 0 && cval->mixer->ignore_ctl_error) {
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ucontrol->value.integer.value[0] = cval->min;
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err < 0)
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = get_relative_value(cval, val);
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ucontrol->value.integer.value[0] = val;
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* put callback for processing/extension unit */
120386e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
120586e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval = kcontrol->private_data;
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val, oval, err;
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = get_cur_ctl_value(cval, cval->control << 8, &oval);
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err < 0) {
121084957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch		if (cval->mixer->ignore_ctl_error)
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = ucontrol->value.integer.value[0];
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = get_abs_value(cval, val);
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val != oval) {
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_cur_ctl_value(cval, cval->control << 8, val);
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* alsa control interface for processing/extension unit */
122486e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic struct snd_kcontrol_new mixer_procunit_ctl = {
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name = "", /* will be filled later */
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.info = mixer_ctl_feature_info,
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get = mixer_ctl_procunit_get,
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.put = mixer_ctl_procunit_put,
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * predefined data for processing units
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct procunit_value_info {
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int control;
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *suffix;
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val_type;
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int min_value;
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct procunit_info {
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int type;
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *name;
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct procunit_value_info *values;
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct procunit_value_info updown_proc_info[] = {
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_UPDOWN_SWITCH, "Switch", USB_MIXER_BOOLEAN },
12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_UPDOWN_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 },
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0 }
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct procunit_value_info prologic_proc_info[] = {
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_PROLOGIC_SWITCH, "Switch", USB_MIXER_BOOLEAN },
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_PROLOGIC_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 },
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0 }
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct procunit_value_info threed_enh_proc_info[] = {
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_3DENH_SWITCH, "Switch", USB_MIXER_BOOLEAN },
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_3DENH_SPACE, "Spaciousness", USB_MIXER_U8 },
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0 }
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct procunit_value_info reverb_proc_info[] = {
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_REVERB_SWITCH, "Switch", USB_MIXER_BOOLEAN },
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_REVERB_LEVEL, "Level", USB_MIXER_U8 },
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_REVERB_TIME, "Time", USB_MIXER_U16 },
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_REVERB_DELAY, "Delay", USB_MIXER_U8 },
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0 }
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct procunit_value_info chorus_proc_info[] = {
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_CHORUS_SWITCH, "Switch", USB_MIXER_BOOLEAN },
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_CHORUS_LEVEL, "Level", USB_MIXER_U8 },
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_CHORUS_RATE, "Rate", USB_MIXER_U16 },
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 },
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0 }
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct procunit_value_info dcr_proc_info[] = {
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_DCR_SWITCH, "Switch", USB_MIXER_BOOLEAN },
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_DCR_RATIO, "Ratio", USB_MIXER_U16 },
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_DCR_MAX_AMP, "Max Amp", USB_MIXER_S16 },
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 },
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_DCR_ATTACK, "Attack Time", USB_MIXER_U16 },
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_DCR_RELEASE, "Release Time", USB_MIXER_U16 },
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0 }
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct procunit_info procunits[] = {
12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_UPDOWN, "Up Down", updown_proc_info },
12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_PROLOGIC, "Dolby Prologic", prologic_proc_info },
12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_3DENH, "3D Stereo Extender", threed_enh_proc_info },
12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_REVERB, "Reverb", reverb_proc_info },
12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_CHORUS, "Chorus", chorus_proc_info },
12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_PROC_DCR, "DCR", dcr_proc_info },
12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0 },
12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
12977d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk/*
12987d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk * predefined data for extension units
12997d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk */
13007d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchukstatic struct procunit_value_info clock_rate_xu_info[] = {
13017d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk       { USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0 },
13027d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk       { 0 }
13037d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk};
13047d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchukstatic struct procunit_value_info clock_source_xu_info[] = {
13057d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	{ USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN },
13067d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	{ 0 }
13077d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk};
13087d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchukstatic struct procunit_value_info spdif_format_xu_info[] = {
13097d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	{ USB_XU_DIGITAL_FORMAT_SELECTOR, "SPDIF/AC3", USB_MIXER_BOOLEAN },
13107d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	{ 0 }
13117d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk};
13127d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchukstatic struct procunit_value_info soft_limit_xu_info[] = {
13137d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	{ USB_XU_SOFT_LIMIT_SELECTOR, " ", USB_MIXER_BOOLEAN },
13147d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	{ 0 }
13157d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk};
13167d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchukstatic struct procunit_info extunits[] = {
13177d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	{ USB_XU_CLOCK_RATE, "Clock rate", clock_rate_xu_info },
13187d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	{ USB_XU_CLOCK_SOURCE, "DigitalIn CLK source", clock_source_xu_info },
13197d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	{ USB_XU_DIGITAL_IO_STATUS, "DigitalOut format:", spdif_format_xu_info },
13207d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	{ USB_XU_DEVICE_OPTIONS, "AnalogueIn Soft Limit", soft_limit_xu_info },
13217d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	{ 0 }
13227d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk};
13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * build a processing/extension unit
13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
132686e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int build_audio_procunit(struct mixer_build *state, int unitid, unsigned char *dsc, struct procunit_info *list, char *name)
13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int num_ins = dsc[6];
132986e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval;
133086e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct snd_kcontrol *kctl;
13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, err, nameid, type, len;
13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct procunit_info *info;
13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct procunit_value_info *valinfo;
1334c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	const struct usbmix_name_map *map;
13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static struct procunit_value_info default_value_info[] = {
13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ 0x01, "Switch", USB_MIXER_BOOLEAN },
13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{ 0 }
13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static struct procunit_info default_info = {
13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		0, NULL, default_value_info
13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	};
13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dsc[0] < 13 || dsc[0] < 13 + num_ins || dsc[0] < num_ins + dsc[11 + num_ins]) {
13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printk(KERN_ERR "invalid %s descriptor (id %d)\n", name, unitid);
13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < num_ins; i++) {
13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((err = parse_audio_unit(state, dsc[7 + i])) < 0)
13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	type = combine_word(&dsc[4]);
13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (info = list; info && info->type; info++)
13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (info->type == type)
13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! info || ! info->type)
13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		info = &default_info;
13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (valinfo = info->values; valinfo->control; valinfo++) {
13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* FIXME: bitmap might be longer than 8bit */
13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1))))
13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
1364c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		map = find_map(state, unitid, valinfo->control);
1365c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		if (check_ignored_ctl(map))
13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
1367561b220a4dece18d67177413e6fa21b49aa4acceTakashi Iwai		cval = kzalloc(sizeof(*cval), GFP_KERNEL);
13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (! cval) {
13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			snd_printk(KERN_ERR "cannot malloc kcontrol\n");
13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOMEM;
13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
137284957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch		cval->mixer = state->mixer;
13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cval->id = unitid;
13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cval->control = valinfo->control;
13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cval->val_type = valinfo->val_type;
13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cval->channels = 1;
13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* get min/max values */
13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) {
13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* FIXME: hard-coded */
13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cval->min = 1;
13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cval->max = dsc[15];
13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cval->res = 1;
13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cval->initialized = 1;
13857d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk		} else {
13867d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk			if (type == USB_XU_CLOCK_RATE) {
13877d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk				/* E-Mu USB 0404/0202/TrackerPre
13887d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk				 * samplerate control quirk
13897d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk				 */
13907d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk				cval->min = 0;
13917d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk				cval->max = 5;
13927d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk				cval->res = 1;
13937d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk				cval->initialized = 1;
13947d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk			} else
13957d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk				get_min_max(cval, valinfo->min_value);
13967d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk		}
13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (! kctl) {
14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			snd_printk(KERN_ERR "cannot malloc kcontrol\n");
14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(cval);
14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOMEM;
14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kctl->private_free = usb_mixer_elem_free;
14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1406c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela		if (check_mapped_name(map, kctl->id.name,
1407c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela						sizeof(kctl->id.name)))
1408c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela			/* nothing */ ;
14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (info->name)
14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nameid = dsc[12 + num_ins + dsc[11 + num_ins]];
14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = 0;
14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (nameid)
14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (! len)
14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
141908d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwai		append_ctl_name(kctl, " ");
142008d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwai		append_ctl_name(kctl, valinfo->suffix);
14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
142484957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch		if ((err = add_control_to_empty(state, kctl)) < 0)
14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
143186e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int parse_audio_processing_unit(struct mixer_build *state, int unitid, unsigned char *desc)
14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return build_audio_procunit(state, unitid, desc, procunits, "Processing Unit");
14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
143686e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc)
14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14387d2b451e65d255427c108e990507964ac39c13eeSergiy Kovalchuk	return build_audio_procunit(state, unitid, desc, extunits, "Extension Unit");
14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Selector Unit
14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* info callback for selector unit
14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * use an enumerator type for routing
14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
144986e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
145186e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval = kcontrol->private_data;
14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char **itemlist = (char **)kcontrol->private_value;
14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14545e246b850df563224be26f1d409cf66fd6c968dfTakashi Iwai	if (snd_BUG_ON(!itemlist))
14555e246b850df563224be26f1d409cf66fd6c968dfTakashi Iwai		return -EINVAL;
14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uinfo->count = 1;
14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uinfo->value.enumerated.items = cval->max;
14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((int)uinfo->value.enumerated.item >= cval->max)
14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uinfo->value.enumerated.item = cval->max - 1;
14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	strcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item]);
14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get callback for selector unit */
146686e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
146886e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval = kcontrol->private_data;
14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val, err;
14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = get_cur_ctl_value(cval, 0, &val);
14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err < 0) {
147384957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch		if (cval->mixer->ignore_ctl_error) {
14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ucontrol->value.enumerated.item[0] = 0;
14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = get_relative_value(cval, val);
14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ucontrol->value.enumerated.item[0] = val;
14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* put callback for selector unit */
148586e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
148786e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval = kcontrol->private_data;
14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val, oval, err;
14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = get_cur_ctl_value(cval, 0, &oval);
14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err < 0) {
149284957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch		if (cval->mixer->ignore_ctl_error)
14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = ucontrol->value.enumerated.item[0];
14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = get_abs_value(cval, val);
14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val != oval) {
14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_cur_ctl_value(cval, 0, val);
15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 1;
15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* alsa control interface for selector unit */
150686e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic struct snd_kcontrol_new mixer_selectunit_ctl = {
15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name = "", /* will be filled later */
15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.info = mixer_ctl_selector_info,
15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get = mixer_ctl_selector_get,
15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.put = mixer_ctl_selector_put,
15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* private free callback.
15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * free both private_data and private_value
15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
151886e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic void usb_mixer_selector_elem_free(struct snd_kcontrol *kctl)
15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, num_ins = 0;
15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kctl->private_data) {
152386e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai		struct usb_mixer_elem_info *cval = kctl->private_data;
15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		num_ins = cval->max;
15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(cval);
15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kctl->private_data = NULL;
15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kctl->private_value) {
15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char **itemlist = (char **)kctl->private_value;
15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < num_ins; i++)
15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(itemlist[i]);
15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(itemlist);
15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kctl->private_value = 0;
15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parse a selector unit
15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
154086e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsigned char *desc)
15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int num_ins = desc[4];
15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i, nameid, len;
15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
154586e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *cval;
154686e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct snd_kcontrol *kctl;
1547c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	const struct usbmix_name_map *map;
15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char **namelist;
15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
155038977e96cb32e658716e11a05ec7f1fc4618e0f3Russ Cox	if (! num_ins || desc[0] < 5 + num_ins) {
15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid);
15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < num_ins; i++) {
15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((err = parse_audio_unit(state, desc[5 + i])) < 0)
15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (num_ins == 1) /* only one ? nonsense! */
15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1563c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	map = find_map(state, unitid, 0);
1564c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	if (check_ignored_ctl(map))
15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1567561b220a4dece18d67177413e6fa21b49aa4acceTakashi Iwai	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! cval) {
15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printk(KERN_ERR "cannot malloc kcontrol\n");
15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
157284957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	cval->mixer = state->mixer;
15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->id = unitid;
15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->val_type = USB_MIXER_U8;
15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->channels = 1;
15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->min = 1;
15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->max = num_ins;
15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->res = 1;
15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cval->initialized = 1;
15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	namelist = kmalloc(sizeof(char *) * num_ins, GFP_KERNEL);
15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! namelist) {
15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printk(KERN_ERR "cannot malloc\n");
15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(cval);
15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_ITEM_NAME_LEN	64
15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < num_ins; i++) {
158986e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai		struct usb_audio_term iterm;
15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = 0;
15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL);
15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (! namelist[i]) {
15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			snd_printk(KERN_ERR "cannot malloc\n");
15947fbe3ca571e4b0795b729658e3d76824be54cb18Mariusz Kozlowski			while (i--)
15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				kfree(namelist[i]);
15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(namelist);
15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(cval);
15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENOMEM;
15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16008e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch		len = check_mapped_selector_name(state, unitid, i, namelist[i],
16018e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch						 MAX_ITEM_NAME_LEN);
16028e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch		if (! len && check_input_term(state, desc[5 + i], &iterm) >= 0)
16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0);
16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (! len)
16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sprintf(namelist[i], "Input %d", i);
16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (! kctl) {
16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printk(KERN_ERR "cannot malloc kcontrol\n");
1611878b4789196e3cd470f843854b6b09d963214659Jesper Juhl		kfree(namelist);
16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(cval);
16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kctl->private_value = (unsigned long)namelist;
16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kctl->private_free = usb_mixer_selector_elem_free;
16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nameid = desc[desc[0] - 1];
1619c3a3e040f01457d2ea4f199f75ca205401001a3bJaroslav Kysela	len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len)
16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		;
16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (nameid)
16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else {
16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = get_term_name(state, &state->oterm,
16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    kctl->id.name, sizeof(kctl->id.name), 0);
16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (! len)
16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));
16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((state->oterm.type & 0xff00) == 0x0100)
163108d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwai			append_ctl_name(kctl, " Capture Source");
16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
163308d1e635089f41e28fec644a8620a0e8d66b1235Takashi Iwai			append_ctl_name(kctl, " Playback Source");
16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",
16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    cval->id, kctl->id.name, num_ins);
163884957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	if ((err = add_control_to_empty(state, kctl)) < 0)
16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return err;
16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parse an audio unit recursively
16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
164986e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int parse_audio_unit(struct mixer_build *state, int unitid)
16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *p1;
16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (test_and_set_bit(unitid, state->unitbitmap))
16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0; /* the unit already visited */
16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p1 = find_audio_control_unit(state, unitid);
16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!p1) {
16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printk(KERN_ERR "usbaudio: unit %d not found!\n", unitid);
16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (p1[2]) {
1663de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack	case UAC_INPUT_TERMINAL:
16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0; /* NOP */
1665de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack	case UAC_MIXER_UNIT:
16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return parse_audio_mixer_unit(state, unitid, p1);
1667de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack	case UAC_SELECTOR_UNIT:
16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return parse_audio_selector_unit(state, unitid, p1);
1669de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack	case UAC_FEATURE_UNIT:
16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return parse_audio_feature_unit(state, unitid, p1);
1671de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack	case UAC_PROCESSING_UNIT_V1:
16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return parse_audio_processing_unit(state, unitid, p1);
1673de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack	case UAC_EXTENSION_UNIT_V1:
16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return parse_audio_extension_unit(state, unitid, p1);
16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
168184957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladischstatic void snd_usb_mixer_free(struct usb_mixer_interface *mixer)
168284957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch{
16836639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	kfree(mixer->id_elems);
16846639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	if (mixer->urb) {
16856639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		kfree(mixer->urb->transfer_buffer);
16866639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		usb_free_urb(mixer->urb);
16876639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	}
168868df9de1d0e95034355283dc12056f93de8e0a79Mariusz Kozlowski	usb_free_urb(mixer->rc_urb);
1689b259b10c420a59a2fdbcf5a3498253ebcbdffa1eClemens Ladisch	kfree(mixer->rc_setup_packet);
169084957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	kfree(mixer);
169184957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch}
169284957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch
169386e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwaistatic int snd_usb_mixer_dev_free(struct snd_device *device)
169484957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch{
169584957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	struct usb_mixer_interface *mixer = device->device_data;
169684957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	snd_usb_mixer_free(mixer);
169784957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	return 0;
169884957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch}
169984957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch
17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * create mixer controls
17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1703de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack * walk through all UAC_OUTPUT_TERMINAL descriptors to search for mixers
17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
170584957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladischstatic int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
170728e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack	struct uac_output_terminal_descriptor_v1 *desc;
170886e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct mixer_build state;
17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct usbmix_ctl_map *map;
171184957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	struct usb_host_interface *hostif;
17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171384957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0];
17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&state, 0, sizeof(state));
171584957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	state.chip = mixer->chip;
171684957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	state.mixer = mixer;
17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state.buffer = hostif->extra;
17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state.buflen = hostif->extralen;
17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check the mapping table */
172127d10f5664c7650af3b2ffadfefaf19b36dc7bd8Clemens Ladisch	for (map = usbmix_ctl_maps; map->id; map++) {
172227d10f5664c7650af3b2ffadfefaf19b36dc7bd8Clemens Ladisch		if (map->id == state.chip->usb_id) {
17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			state.map = map->map;
17248e062ec7108f8a91149e6bccddc3b7341e406274Clemens Ladisch			state.selector_map = map->selector_map;
172584957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch			mixer->ignore_ctl_error = map->ignore_ctl_error;
17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	desc = NULL;
1731de48c7bc6f93c6c8e0be8612c9d72a2dc92eaa01Daniel Mack	while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, UAC_OUTPUT_TERMINAL)) != NULL) {
173228e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack		if (desc->bLength < 9)
17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue; /* invalid descriptor? */
173428e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack		set_bit(desc->bTerminalID, state.unitbitmap);  /* mark terminal ID as visited */
173528e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack		state.oterm.id = desc->bTerminalID;
173628e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack		state.oterm.type = le16_to_cpu(desc->wTerminalType);
173728e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack		state.oterm.name = desc->iTerminal;
173828e1b773083d349d5223f586a39fa30f5d0f1c36Daniel Mack		err = parse_audio_unit(&state, desc->bSourceID);
17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err < 0)
17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return err;
17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
174484957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch
17457b1eda223debcba706ab989a09c4eecb327aebdfDaniel Mackvoid snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid)
17466639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch{
174786e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	struct usb_mixer_elem_info *info;
17486639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch
17496639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem)
17506639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
17516639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch			       info->elem_id);
17526639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch}
17536639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch
1754ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kyselastatic void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer,
1755ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela				    int unitid,
1756ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela				    struct usb_mixer_elem_info *cval)
1757ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela{
1758ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN",
1759ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela				    "S8", "U8", "S16", "U16"};
1760ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	snd_iprintf(buffer, "  Unit: %i\n", unitid);
1761ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	if (cval->elem_id)
1762ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela		snd_iprintf(buffer, "    Control: name=\"%s\", index=%i\n",
1763ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela				cval->elem_id->name, cval->elem_id->index);
1764ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	snd_iprintf(buffer, "    Info: id=%i, control=%i, cmask=0x%x, "
1765ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela			    "channels=%i, type=\"%s\"\n", cval->id,
1766ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela			    cval->control, cval->cmask, cval->channels,
1767ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela			    val_types[cval->val_type]);
1768ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	snd_iprintf(buffer, "    Volume: min=%i, max=%i, dBmin=%i, dBmax=%i\n",
1769ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela			    cval->min, cval->max, cval->dBmin, cval->dBmax);
1770ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela}
1771ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela
1772ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kyselastatic void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
1773ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela				    struct snd_info_buffer *buffer)
1774ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela{
1775ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	struct snd_usb_audio *chip = entry->private_data;
1776ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	struct usb_mixer_interface *mixer;
1777ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	struct usb_mixer_elem_info *cval;
1778ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	int unitid;
1779ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela
1780ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	list_for_each_entry(mixer, &chip->mixer_list, list) {
1781ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela		snd_iprintf(buffer,
17827affdc17d49b5d9e9c350d5d99ee34ab8655c7b4Jaroslav Kysela			"USB Mixer: usb_id=0x%08x, ctrlif=%i, ctlerr=%i\n",
17837affdc17d49b5d9e9c350d5d99ee34ab8655c7b4Jaroslav Kysela				chip->usb_id, mixer->ctrlif,
17847affdc17d49b5d9e9c350d5d99ee34ab8655c7b4Jaroslav Kysela				mixer->ignore_ctl_error);
1785ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela		snd_iprintf(buffer, "Card: %s\n", chip->card->longname);
1786ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela		for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) {
1787ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela			for (cval = mixer->id_elems[unitid]; cval;
1788ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela						cval = cval->next_id_elem)
1789ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela				snd_usb_mixer_dump_cval(buffer, unitid, cval);
1790ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela		}
1791ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	}
1792ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela}
1793ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela
17947d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void snd_usb_mixer_status_complete(struct urb *urb)
17956639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch{
17966639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	struct usb_mixer_interface *mixer = urb->context;
17976639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch
17986639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	if (urb->status == 0) {
17996639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		u8 *buf = urb->transfer_buffer;
18006639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		int i;
18016639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch
18026639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		for (i = urb->actual_length; i >= 2; buf += 2, i -= 2) {
18036639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch			snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n",
18046639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch				   buf[0], buf[1]);
18056639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch			/* ignore any notifications not from the control interface */
18066639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch			if ((buf[0] & 0x0f) != 0)
18076639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch				continue;
18086639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch			if (!(buf[0] & 0x40))
18096639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch				snd_usb_mixer_notify_id(mixer, buf[1]);
1810b259b10c420a59a2fdbcf5a3498253ebcbdffa1eClemens Ladisch			else
18117b1eda223debcba706ab989a09c4eecb327aebdfDaniel Mack				snd_usb_mixer_rc_memory_change(mixer, buf[1]);
18126639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		}
18136639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	}
18146639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	if (urb->status != -ENOENT && urb->status != -ECONNRESET) {
18156639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		urb->dev = mixer->chip->dev;
18166639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		usb_submit_urb(urb, GFP_ATOMIC);
18176639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	}
18186639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch}
18196639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch
18206639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch/* create the handler for the optional status interrupt endpoint */
18216639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladischstatic int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
18226639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch{
18236639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	struct usb_host_interface *hostif;
18246639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	struct usb_endpoint_descriptor *ep;
18256639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	void *transfer_buffer;
18266639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	int buffer_length;
18276639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	unsigned int epnum;
18286639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch
18296639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0];
18306639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	/* we need one interrupt input endpoint */
18316639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	if (get_iface_desc(hostif)->bNumEndpoints < 1)
18326639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		return 0;
18336639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	ep = get_endpoint(hostif, 0);
1834913ae5a24efd27deef4fc154953871b62d0d99cdJulia Lawall	if (!usb_endpoint_dir_in(ep) || !usb_endpoint_xfer_int(ep))
18356639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		return 0;
18366639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch
183742a6e66f1e40a930d093c33ba0bb9d8d8e4555edJulia Lawall	epnum = usb_endpoint_num(ep);
18386639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	buffer_length = le16_to_cpu(ep->wMaxPacketSize);
18396639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	transfer_buffer = kmalloc(buffer_length, GFP_KERNEL);
18406639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	if (!transfer_buffer)
18416639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		return -ENOMEM;
18426639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	mixer->urb = usb_alloc_urb(0, GFP_KERNEL);
18436639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	if (!mixer->urb) {
18446639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		kfree(transfer_buffer);
18456639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		return -ENOMEM;
18466639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	}
18476639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	usb_fill_int_urb(mixer->urb, mixer->chip->dev,
18486639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch			 usb_rcvintpipe(mixer->chip->dev, epnum),
18496639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch			 transfer_buffer, buffer_length,
18506639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch			 snd_usb_mixer_status_complete, mixer, ep->bInterval);
18516639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	usb_submit_urb(mixer->urb, GFP_KERNEL);
18526639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	return 0;
18536639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch}
18546639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch
18557a9b8063cf7d78d7de4f2555357101087548c699Takashi Iwaiint snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
18567a9b8063cf7d78d7de4f2555357101087548c699Takashi Iwai			 int ignore_error)
185784957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch{
185886e07d34658bb85b3424f4db64fa28f884edbe8dTakashi Iwai	static struct snd_device_ops dev_ops = {
185984957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch		.dev_free = snd_usb_mixer_dev_free
186084957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	};
186184957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	struct usb_mixer_interface *mixer;
1862ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	struct snd_info_entry *entry;
18637b8a043f2686af9f41e313a78ed5e98233e5fdedDaniel Mack	struct usb_host_interface *host_iface;
18647b8a043f2686af9f41e313a78ed5e98233e5fdedDaniel Mack	int err, protocol;
186584957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch
186684957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	strcpy(chip->card->mixername, "USB Mixer");
186784957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch
1868561b220a4dece18d67177413e6fa21b49aa4acceTakashi Iwai	mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
186984957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	if (!mixer)
187084957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch		return -ENOMEM;
187184957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	mixer->chip = chip;
187284957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	mixer->ctrlif = ctrlif;
18737a9b8063cf7d78d7de4f2555357101087548c699Takashi Iwai	mixer->ignore_ctl_error = ignore_error;
1874291186e049d7f8178ad31d43c38a53889f25d79eJaroslav Kysela	mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems),
1875291186e049d7f8178ad31d43c38a53889f25d79eJaroslav Kysela				  GFP_KERNEL);
18766639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	if (!mixer->id_elems) {
18776639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		kfree(mixer);
18786639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch		return -ENOMEM;
18796639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	}
188084957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch
18817b8a043f2686af9f41e313a78ed5e98233e5fdedDaniel Mack	host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
18827b8a043f2686af9f41e313a78ed5e98233e5fdedDaniel Mack	protocol = host_iface->desc.bInterfaceProtocol;
18837b8a043f2686af9f41e313a78ed5e98233e5fdedDaniel Mack
18847b8a043f2686af9f41e313a78ed5e98233e5fdedDaniel Mack	/* FIXME! */
18857b8a043f2686af9f41e313a78ed5e98233e5fdedDaniel Mack	if (protocol != UAC_VERSION_1) {
18867b8a043f2686af9f41e313a78ed5e98233e5fdedDaniel Mack		snd_printk(KERN_WARNING "mixer interface protocol 0x%02x not yet supported\n",
18877b8a043f2686af9f41e313a78ed5e98233e5fdedDaniel Mack					protocol);
18887b8a043f2686af9f41e313a78ed5e98233e5fdedDaniel Mack		return 0;
18897b8a043f2686af9f41e313a78ed5e98233e5fdedDaniel Mack	}
18907b8a043f2686af9f41e313a78ed5e98233e5fdedDaniel Mack
18916639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	if ((err = snd_usb_mixer_controls(mixer)) < 0 ||
189293446edcd05589201f20cf8843e8c4f990c18ae4Clemens Ladisch	    (err = snd_usb_mixer_status_create(mixer)) < 0)
189393446edcd05589201f20cf8843e8c4f990c18ae4Clemens Ladisch		goto _error;
189484957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch
18957b1eda223debcba706ab989a09c4eecb327aebdfDaniel Mack	snd_usb_mixer_apply_create_quirk(mixer);
1896468b8fde24d49f5b34e9152981824b9d4ecd1a2eClemens Ladisch
189784957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops);
189893446edcd05589201f20cf8843e8c4f990c18ae4Clemens Ladisch	if (err < 0)
189993446edcd05589201f20cf8843e8c4f990c18ae4Clemens Ladisch		goto _error;
1900ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela
1901ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	if (list_empty(&chip->mixer_list) &&
1902ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela	    !snd_card_proc_new(chip->card, "usbmixer", &entry))
1903ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela		snd_info_set_text_ops(entry, chip, snd_usb_mixer_proc_read);
1904ebfdeea3df2b8c265975b6acc47996a0b7c507e8Jaroslav Kysela
190584957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	list_add(&mixer->list, &chip->mixer_list);
190684957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch	return 0;
190793446edcd05589201f20cf8843e8c4f990c18ae4Clemens Ladisch
190893446edcd05589201f20cf8843e8c4f990c18ae4Clemens Ladisch_error:
190993446edcd05589201f20cf8843e8c4f990c18ae4Clemens Ladisch	snd_usb_mixer_free(mixer);
191093446edcd05589201f20cf8843e8c4f990c18ae4Clemens Ladisch	return err;
191184957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch}
191284957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch
191384957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladischvoid snd_usb_mixer_disconnect(struct list_head *p)
191484957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch{
19156639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	struct usb_mixer_interface *mixer;
19167b1eda223debcba706ab989a09c4eecb327aebdfDaniel Mack
19176639b6c2367f884ca172b78d69f7da17bfab2e5eClemens Ladisch	mixer = list_entry(p, struct usb_mixer_interface, list);
191868df9de1d0e95034355283dc12056f93de8e0a79Mariusz Kozlowski	usb_kill_urb(mixer->urb);
191968df9de1d0e95034355283dc12056f93de8e0a79Mariusz Kozlowski	usb_kill_urb(mixer->rc_urb);
192084957a8ab086377a025e0448fa716ed5983f3c3aClemens Ladisch}
1921