xref: /openbmc/linux/sound/usb/mixer_quirks.c (revision 76b188c4)
17b1eda22SDaniel Mack /*
27b1eda22SDaniel Mack  *   USB Audio Driver for ALSA
37b1eda22SDaniel Mack  *
47b1eda22SDaniel Mack  *   Quirks and vendor-specific extensions for mixer interfaces
57b1eda22SDaniel Mack  *
67b1eda22SDaniel Mack  *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
77b1eda22SDaniel Mack  *
87b1eda22SDaniel Mack  *   Many codes borrowed from audio.c by
97b1eda22SDaniel Mack  *	    Alan Cox (alan@lxorguk.ukuu.org.uk)
107b1eda22SDaniel Mack  *	    Thomas Sailer (sailer@ife.ee.ethz.ch)
117b1eda22SDaniel Mack  *
12066624c6SPrzemek Rudy  *   Audio Advantage Micro II support added by:
13066624c6SPrzemek Rudy  *	    Przemek Rudy (prudy1@o2.pl)
147b1eda22SDaniel Mack  *
157b1eda22SDaniel Mack  *   This program is free software; you can redistribute it and/or modify
167b1eda22SDaniel Mack  *   it under the terms of the GNU General Public License as published by
177b1eda22SDaniel Mack  *   the Free Software Foundation; either version 2 of the License, or
187b1eda22SDaniel Mack  *   (at your option) any later version.
197b1eda22SDaniel Mack  *
207b1eda22SDaniel Mack  *   This program is distributed in the hope that it will be useful,
217b1eda22SDaniel Mack  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
227b1eda22SDaniel Mack  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
237b1eda22SDaniel Mack  *   GNU General Public License for more details.
247b1eda22SDaniel Mack  *
257b1eda22SDaniel Mack  *   You should have received a copy of the GNU General Public License
267b1eda22SDaniel Mack  *   along with this program; if not, write to the Free Software
277b1eda22SDaniel Mack  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
287b1eda22SDaniel Mack  */
297b1eda22SDaniel Mack 
307b1eda22SDaniel Mack #include <linux/init.h>
3136db0456SStephen Rothwell #include <linux/slab.h>
327b1eda22SDaniel Mack #include <linux/usb.h>
337b1eda22SDaniel Mack #include <linux/usb/audio.h>
347b1eda22SDaniel Mack 
35066624c6SPrzemek Rudy #include <sound/asoundef.h>
367b1eda22SDaniel Mack #include <sound/core.h>
377b1eda22SDaniel Mack #include <sound/control.h>
387b1eda22SDaniel Mack #include <sound/hwdep.h>
397b1eda22SDaniel Mack #include <sound/info.h>
407b1eda22SDaniel Mack 
417b1eda22SDaniel Mack #include "usbaudio.h"
42f0b5e634SDaniel Mack #include "mixer.h"
437b1eda22SDaniel Mack #include "mixer_quirks.h"
4476b188c4SChris J Arges #include "mixer_scarlett.h"
457b1eda22SDaniel Mack #include "helper.h"
467b1eda22SDaniel Mack 
47d5a0bf6cSDaniel Mack extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
48d5a0bf6cSDaniel Mack 
49b71dad18SMark Hills struct std_mono_table {
50b71dad18SMark Hills 	unsigned int unitid, control, cmask;
51b71dad18SMark Hills 	int val_type;
52b71dad18SMark Hills 	const char *name;
53b71dad18SMark Hills 	snd_kcontrol_tlv_rw_t *tlv_callback;
54b71dad18SMark Hills };
55b71dad18SMark Hills 
568a4d1d39SFelix Homann /* This function allows for the creation of standard UAC controls.
578a4d1d39SFelix Homann  * See the quirks for M-Audio FTUs or Ebox-44.
588a4d1d39SFelix Homann  * If you don't want to set a TLV callback pass NULL.
598a4d1d39SFelix Homann  *
608a4d1d39SFelix Homann  * Since there doesn't seem to be a devices that needs a multichannel
618a4d1d39SFelix Homann  * version, we keep it mono for simplicity.
628a4d1d39SFelix Homann  */
639f814105SEldad Zack static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
648a4d1d39SFelix Homann 				unsigned int unitid,
658a4d1d39SFelix Homann 				unsigned int control,
668a4d1d39SFelix Homann 				unsigned int cmask,
678a4d1d39SFelix Homann 				int val_type,
689f814105SEldad Zack 				unsigned int idx_off,
698a4d1d39SFelix Homann 				const char *name,
708a4d1d39SFelix Homann 				snd_kcontrol_tlv_rw_t *tlv_callback)
718a4d1d39SFelix Homann {
728a4d1d39SFelix Homann 	int err;
738a4d1d39SFelix Homann 	struct usb_mixer_elem_info *cval;
748a4d1d39SFelix Homann 	struct snd_kcontrol *kctl;
758a4d1d39SFelix Homann 
768a4d1d39SFelix Homann 	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
778a4d1d39SFelix Homann 	if (!cval)
788a4d1d39SFelix Homann 		return -ENOMEM;
798a4d1d39SFelix Homann 
808a4d1d39SFelix Homann 	cval->id = unitid;
818a4d1d39SFelix Homann 	cval->mixer = mixer;
828a4d1d39SFelix Homann 	cval->val_type = val_type;
838a4d1d39SFelix Homann 	cval->channels = 1;
848a4d1d39SFelix Homann 	cval->control = control;
858a4d1d39SFelix Homann 	cval->cmask = cmask;
869f814105SEldad Zack 	cval->idx_off = idx_off;
878a4d1d39SFelix Homann 
887df4a691SMark Hills 	/* get_min_max() is called only for integer volumes later,
897df4a691SMark Hills 	 * so provide a short-cut for booleans */
908a4d1d39SFelix Homann 	cval->min = 0;
918a4d1d39SFelix Homann 	cval->max = 1;
928a4d1d39SFelix Homann 	cval->res = 0;
938a4d1d39SFelix Homann 	cval->dBmin = 0;
948a4d1d39SFelix Homann 	cval->dBmax = 0;
958a4d1d39SFelix Homann 
968a4d1d39SFelix Homann 	/* Create control */
978a4d1d39SFelix Homann 	kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
988a4d1d39SFelix Homann 	if (!kctl) {
998a4d1d39SFelix Homann 		kfree(cval);
1008a4d1d39SFelix Homann 		return -ENOMEM;
1018a4d1d39SFelix Homann 	}
1028a4d1d39SFelix Homann 
1038a4d1d39SFelix Homann 	/* Set name */
1048a4d1d39SFelix Homann 	snprintf(kctl->id.name, sizeof(kctl->id.name), name);
105eef90451SChris J Arges 	kctl->private_free = snd_usb_mixer_elem_free;
1068a4d1d39SFelix Homann 
1078a4d1d39SFelix Homann 	/* set TLV */
1088a4d1d39SFelix Homann 	if (tlv_callback) {
1098a4d1d39SFelix Homann 		kctl->tlv.c = tlv_callback;
1108a4d1d39SFelix Homann 		kctl->vd[0].access |=
1118a4d1d39SFelix Homann 			SNDRV_CTL_ELEM_ACCESS_TLV_READ |
1128a4d1d39SFelix Homann 			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
1138a4d1d39SFelix Homann 	}
1148a4d1d39SFelix Homann 	/* Add control to mixer */
1158a4d1d39SFelix Homann 	err = snd_usb_mixer_add_control(mixer, kctl);
1168a4d1d39SFelix Homann 	if (err < 0)
1178a4d1d39SFelix Homann 		return err;
1188a4d1d39SFelix Homann 
1198a4d1d39SFelix Homann 	return 0;
1208a4d1d39SFelix Homann }
1218a4d1d39SFelix Homann 
1229f814105SEldad Zack static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
1239f814105SEldad Zack 				unsigned int unitid,
1249f814105SEldad Zack 				unsigned int control,
1259f814105SEldad Zack 				unsigned int cmask,
1269f814105SEldad Zack 				int val_type,
1279f814105SEldad Zack 				const char *name,
1289f814105SEldad Zack 				snd_kcontrol_tlv_rw_t *tlv_callback)
1299f814105SEldad Zack {
1309f814105SEldad Zack 	return snd_create_std_mono_ctl_offset(mixer, unitid, control, cmask,
1319f814105SEldad Zack 		val_type, 0 /* Offset */, name, tlv_callback);
1329f814105SEldad Zack }
1339f814105SEldad Zack 
1347b1eda22SDaniel Mack /*
135b71dad18SMark Hills  * Create a set of standard UAC controls from a table
136b71dad18SMark Hills  */
137b71dad18SMark Hills static int snd_create_std_mono_table(struct usb_mixer_interface *mixer,
138b71dad18SMark Hills 				struct std_mono_table *t)
139b71dad18SMark Hills {
140b71dad18SMark Hills 	int err;
141b71dad18SMark Hills 
142b71dad18SMark Hills 	while (t->name != NULL) {
143b71dad18SMark Hills 		err = snd_create_std_mono_ctl(mixer, t->unitid, t->control,
144b71dad18SMark Hills 				t->cmask, t->val_type, t->name, t->tlv_callback);
145b71dad18SMark Hills 		if (err < 0)
146b71dad18SMark Hills 			return err;
147b71dad18SMark Hills 		t++;
148b71dad18SMark Hills 	}
149b71dad18SMark Hills 
150b71dad18SMark Hills 	return 0;
151b71dad18SMark Hills }
152b71dad18SMark Hills 
153b71dad18SMark Hills /*
1547b1eda22SDaniel Mack  * Sound Blaster remote control configuration
1557b1eda22SDaniel Mack  *
1567b1eda22SDaniel Mack  * format of remote control data:
1577b1eda22SDaniel Mack  * Extigy:       xx 00
1587b1eda22SDaniel Mack  * Audigy 2 NX:  06 80 xx 00 00 00
1597b1eda22SDaniel Mack  * Live! 24-bit: 06 80 xx yy 22 83
1607b1eda22SDaniel Mack  */
1617b1eda22SDaniel Mack static const struct rc_config {
1627b1eda22SDaniel Mack 	u32 usb_id;
1637b1eda22SDaniel Mack 	u8  offset;
1647b1eda22SDaniel Mack 	u8  length;
1657b1eda22SDaniel Mack 	u8  packet_length;
1667b1eda22SDaniel Mack 	u8  min_packet_length; /* minimum accepted length of the URB result */
1677b1eda22SDaniel Mack 	u8  mute_mixer_id;
1687b1eda22SDaniel Mack 	u32 mute_code;
1697b1eda22SDaniel Mack } rc_configs[] = {
1707b1eda22SDaniel Mack 	{ USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */
1717b1eda22SDaniel Mack 	{ USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */
1727b1eda22SDaniel Mack 	{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
173ca8dc34eSMandar Joshi 	{ USB_ID(0x041e, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 */
1747cdd8d73SMathieu Bouffard 	{ USB_ID(0x041e, 0x30df), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 Pro */
1757b1eda22SDaniel Mack 	{ USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
1767b1eda22SDaniel Mack };
1777b1eda22SDaniel Mack 
1787b1eda22SDaniel Mack static void snd_usb_soundblaster_remote_complete(struct urb *urb)
1797b1eda22SDaniel Mack {
1807b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = urb->context;
1817b1eda22SDaniel Mack 	const struct rc_config *rc = mixer->rc_cfg;
1827b1eda22SDaniel Mack 	u32 code;
1837b1eda22SDaniel Mack 
1847b1eda22SDaniel Mack 	if (urb->status < 0 || urb->actual_length < rc->min_packet_length)
1857b1eda22SDaniel Mack 		return;
1867b1eda22SDaniel Mack 
1877b1eda22SDaniel Mack 	code = mixer->rc_buffer[rc->offset];
1887b1eda22SDaniel Mack 	if (rc->length == 2)
1897b1eda22SDaniel Mack 		code |= mixer->rc_buffer[rc->offset + 1] << 8;
1907b1eda22SDaniel Mack 
1917b1eda22SDaniel Mack 	/* the Mute button actually changes the mixer control */
1927b1eda22SDaniel Mack 	if (code == rc->mute_code)
1937b1eda22SDaniel Mack 		snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id);
1947b1eda22SDaniel Mack 	mixer->rc_code = code;
1957b1eda22SDaniel Mack 	wmb();
1967b1eda22SDaniel Mack 	wake_up(&mixer->rc_waitq);
1977b1eda22SDaniel Mack }
1987b1eda22SDaniel Mack 
1997b1eda22SDaniel Mack static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf,
2007b1eda22SDaniel Mack 				     long count, loff_t *offset)
2017b1eda22SDaniel Mack {
2027b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = hw->private_data;
2037b1eda22SDaniel Mack 	int err;
2047b1eda22SDaniel Mack 	u32 rc_code;
2057b1eda22SDaniel Mack 
2067b1eda22SDaniel Mack 	if (count != 1 && count != 4)
2077b1eda22SDaniel Mack 		return -EINVAL;
2087b1eda22SDaniel Mack 	err = wait_event_interruptible(mixer->rc_waitq,
2097b1eda22SDaniel Mack 				       (rc_code = xchg(&mixer->rc_code, 0)) != 0);
2107b1eda22SDaniel Mack 	if (err == 0) {
2117b1eda22SDaniel Mack 		if (count == 1)
2127b1eda22SDaniel Mack 			err = put_user(rc_code, buf);
2137b1eda22SDaniel Mack 		else
2147b1eda22SDaniel Mack 			err = put_user(rc_code, (u32 __user *)buf);
2157b1eda22SDaniel Mack 	}
2167b1eda22SDaniel Mack 	return err < 0 ? err : count;
2177b1eda22SDaniel Mack }
2187b1eda22SDaniel Mack 
2197b1eda22SDaniel Mack static unsigned int snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *file,
2207b1eda22SDaniel Mack 					    poll_table *wait)
2217b1eda22SDaniel Mack {
2227b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = hw->private_data;
2237b1eda22SDaniel Mack 
2247b1eda22SDaniel Mack 	poll_wait(file, &mixer->rc_waitq, wait);
2257b1eda22SDaniel Mack 	return mixer->rc_code ? POLLIN | POLLRDNORM : 0;
2267b1eda22SDaniel Mack }
2277b1eda22SDaniel Mack 
2287b1eda22SDaniel Mack static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer)
2297b1eda22SDaniel Mack {
2307b1eda22SDaniel Mack 	struct snd_hwdep *hwdep;
2317b1eda22SDaniel Mack 	int err, len, i;
2327b1eda22SDaniel Mack 
2337b1eda22SDaniel Mack 	for (i = 0; i < ARRAY_SIZE(rc_configs); ++i)
2347b1eda22SDaniel Mack 		if (rc_configs[i].usb_id == mixer->chip->usb_id)
2357b1eda22SDaniel Mack 			break;
2367b1eda22SDaniel Mack 	if (i >= ARRAY_SIZE(rc_configs))
2377b1eda22SDaniel Mack 		return 0;
2387b1eda22SDaniel Mack 	mixer->rc_cfg = &rc_configs[i];
2397b1eda22SDaniel Mack 
2407b1eda22SDaniel Mack 	len = mixer->rc_cfg->packet_length;
2417b1eda22SDaniel Mack 
2427b1eda22SDaniel Mack 	init_waitqueue_head(&mixer->rc_waitq);
2437b1eda22SDaniel Mack 	err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep);
2447b1eda22SDaniel Mack 	if (err < 0)
2457b1eda22SDaniel Mack 		return err;
2467b1eda22SDaniel Mack 	snprintf(hwdep->name, sizeof(hwdep->name),
2477b1eda22SDaniel Mack 		 "%s remote control", mixer->chip->card->shortname);
2487b1eda22SDaniel Mack 	hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC;
2497b1eda22SDaniel Mack 	hwdep->private_data = mixer;
2507b1eda22SDaniel Mack 	hwdep->ops.read = snd_usb_sbrc_hwdep_read;
2517b1eda22SDaniel Mack 	hwdep->ops.poll = snd_usb_sbrc_hwdep_poll;
2527b1eda22SDaniel Mack 	hwdep->exclusive = 1;
2537b1eda22SDaniel Mack 
2547b1eda22SDaniel Mack 	mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL);
2557b1eda22SDaniel Mack 	if (!mixer->rc_urb)
2567b1eda22SDaniel Mack 		return -ENOMEM;
2577b1eda22SDaniel Mack 	mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL);
2587b1eda22SDaniel Mack 	if (!mixer->rc_setup_packet) {
2597b1eda22SDaniel Mack 		usb_free_urb(mixer->rc_urb);
2607b1eda22SDaniel Mack 		mixer->rc_urb = NULL;
2617b1eda22SDaniel Mack 		return -ENOMEM;
2627b1eda22SDaniel Mack 	}
2637b1eda22SDaniel Mack 	mixer->rc_setup_packet->bRequestType =
2647b1eda22SDaniel Mack 		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
2657b1eda22SDaniel Mack 	mixer->rc_setup_packet->bRequest = UAC_GET_MEM;
2667b1eda22SDaniel Mack 	mixer->rc_setup_packet->wValue = cpu_to_le16(0);
2677b1eda22SDaniel Mack 	mixer->rc_setup_packet->wIndex = cpu_to_le16(0);
2687b1eda22SDaniel Mack 	mixer->rc_setup_packet->wLength = cpu_to_le16(len);
2697b1eda22SDaniel Mack 	usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev,
2707b1eda22SDaniel Mack 			     usb_rcvctrlpipe(mixer->chip->dev, 0),
2717b1eda22SDaniel Mack 			     (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len,
2727b1eda22SDaniel Mack 			     snd_usb_soundblaster_remote_complete, mixer);
2737b1eda22SDaniel Mack 	return 0;
2747b1eda22SDaniel Mack }
2757b1eda22SDaniel Mack 
2767b1eda22SDaniel Mack #define snd_audigy2nx_led_info		snd_ctl_boolean_mono_info
2777b1eda22SDaniel Mack 
2787b1eda22SDaniel Mack static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2797b1eda22SDaniel Mack {
2807b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
2817b1eda22SDaniel Mack 	int index = kcontrol->private_value;
2827b1eda22SDaniel Mack 
2837b1eda22SDaniel Mack 	ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index];
2847b1eda22SDaniel Mack 	return 0;
2857b1eda22SDaniel Mack }
2867b1eda22SDaniel Mack 
2877b1eda22SDaniel Mack static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2887b1eda22SDaniel Mack {
2897b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
2907b1eda22SDaniel Mack 	int index = kcontrol->private_value;
2917b1eda22SDaniel Mack 	int value = ucontrol->value.integer.value[0];
2927b1eda22SDaniel Mack 	int err, changed;
2937b1eda22SDaniel Mack 
2947b1eda22SDaniel Mack 	if (value > 1)
2957b1eda22SDaniel Mack 		return -EINVAL;
2967b1eda22SDaniel Mack 	changed = value != mixer->audigy2nx_leds[index];
297888ea7d5STakashi Iwai 	down_read(&mixer->chip->shutdown_rwsem);
298888ea7d5STakashi Iwai 	if (mixer->chip->shutdown) {
299888ea7d5STakashi Iwai 		err = -ENODEV;
300888ea7d5STakashi Iwai 		goto out;
301888ea7d5STakashi Iwai 	}
302ca8dc34eSMandar Joshi 	if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042))
303ca8dc34eSMandar Joshi 		err = snd_usb_ctl_msg(mixer->chip->dev,
304ca8dc34eSMandar Joshi 			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
305ca8dc34eSMandar Joshi 			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
30617d900c4SClemens Ladisch 			      !value, 0, NULL, 0);
3077cdd8d73SMathieu Bouffard 	/* USB X-Fi S51 Pro */
3087cdd8d73SMathieu Bouffard 	if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df))
3097cdd8d73SMathieu Bouffard 		err = snd_usb_ctl_msg(mixer->chip->dev,
3107cdd8d73SMathieu Bouffard 			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
3117cdd8d73SMathieu Bouffard 			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
31217d900c4SClemens Ladisch 			      !value, 0, NULL, 0);
313ca8dc34eSMandar Joshi 	else
3147b1eda22SDaniel Mack 		err = snd_usb_ctl_msg(mixer->chip->dev,
3157b1eda22SDaniel Mack 			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
3167b1eda22SDaniel Mack 			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
31717d900c4SClemens Ladisch 			      value, index + 2, NULL, 0);
318888ea7d5STakashi Iwai  out:
319888ea7d5STakashi Iwai 	up_read(&mixer->chip->shutdown_rwsem);
3207b1eda22SDaniel Mack 	if (err < 0)
3217b1eda22SDaniel Mack 		return err;
3227b1eda22SDaniel Mack 	mixer->audigy2nx_leds[index] = value;
3237b1eda22SDaniel Mack 	return changed;
3247b1eda22SDaniel Mack }
3257b1eda22SDaniel Mack 
3267b1eda22SDaniel Mack static struct snd_kcontrol_new snd_audigy2nx_controls[] = {
3277b1eda22SDaniel Mack 	{
3287b1eda22SDaniel Mack 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3297b1eda22SDaniel Mack 		.name = "CMSS LED Switch",
3307b1eda22SDaniel Mack 		.info = snd_audigy2nx_led_info,
3317b1eda22SDaniel Mack 		.get = snd_audigy2nx_led_get,
3327b1eda22SDaniel Mack 		.put = snd_audigy2nx_led_put,
3337b1eda22SDaniel Mack 		.private_value = 0,
3347b1eda22SDaniel Mack 	},
3357b1eda22SDaniel Mack 	{
3367b1eda22SDaniel Mack 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3377b1eda22SDaniel Mack 		.name = "Power LED Switch",
3387b1eda22SDaniel Mack 		.info = snd_audigy2nx_led_info,
3397b1eda22SDaniel Mack 		.get = snd_audigy2nx_led_get,
3407b1eda22SDaniel Mack 		.put = snd_audigy2nx_led_put,
3417b1eda22SDaniel Mack 		.private_value = 1,
3427b1eda22SDaniel Mack 	},
3437b1eda22SDaniel Mack 	{
3447b1eda22SDaniel Mack 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3457b1eda22SDaniel Mack 		.name = "Dolby Digital LED Switch",
3467b1eda22SDaniel Mack 		.info = snd_audigy2nx_led_info,
3477b1eda22SDaniel Mack 		.get = snd_audigy2nx_led_get,
3487b1eda22SDaniel Mack 		.put = snd_audigy2nx_led_put,
3497b1eda22SDaniel Mack 		.private_value = 2,
3507b1eda22SDaniel Mack 	},
3517b1eda22SDaniel Mack };
3527b1eda22SDaniel Mack 
3537b1eda22SDaniel Mack static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
3547b1eda22SDaniel Mack {
3557b1eda22SDaniel Mack 	int i, err;
3567b1eda22SDaniel Mack 
3577b1eda22SDaniel Mack 	for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
358ca8dc34eSMandar Joshi 		/* USB X-Fi S51 doesn't have a CMSS LED */
359ca8dc34eSMandar Joshi 		if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0)
360ca8dc34eSMandar Joshi 			continue;
3617cdd8d73SMathieu Bouffard 		/* USB X-Fi S51 Pro doesn't have one either */
3627cdd8d73SMathieu Bouffard 		if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0)
3637cdd8d73SMathieu Bouffard 			continue;
3647b1eda22SDaniel Mack 		if (i > 1 && /* Live24ext has 2 LEDs only */
3657b1eda22SDaniel Mack 			(mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
366ca8dc34eSMandar Joshi 			 mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
3677cdd8d73SMathieu Bouffard 			 mixer->chip->usb_id == USB_ID(0x041e, 0x30df) ||
3687b1eda22SDaniel Mack 			 mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
3697b1eda22SDaniel Mack 			break;
3707b1eda22SDaniel Mack 		err = snd_ctl_add(mixer->chip->card,
3717b1eda22SDaniel Mack 				  snd_ctl_new1(&snd_audigy2nx_controls[i], mixer));
3727b1eda22SDaniel Mack 		if (err < 0)
3737b1eda22SDaniel Mack 			return err;
3747b1eda22SDaniel Mack 	}
3757b1eda22SDaniel Mack 	mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */
3767b1eda22SDaniel Mack 	return 0;
3777b1eda22SDaniel Mack }
3787b1eda22SDaniel Mack 
3797b1eda22SDaniel Mack static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
3807b1eda22SDaniel Mack 				    struct snd_info_buffer *buffer)
3817b1eda22SDaniel Mack {
3827b1eda22SDaniel Mack 	static const struct sb_jack {
3837b1eda22SDaniel Mack 		int unitid;
3847b1eda22SDaniel Mack 		const char *name;
3857b1eda22SDaniel Mack 	}  jacks_audigy2nx[] = {
3867b1eda22SDaniel Mack 		{4,  "dig in "},
3877b1eda22SDaniel Mack 		{7,  "line in"},
3887b1eda22SDaniel Mack 		{19, "spk out"},
3897b1eda22SDaniel Mack 		{20, "hph out"},
3907b1eda22SDaniel Mack 		{-1, NULL}
3917b1eda22SDaniel Mack 	}, jacks_live24ext[] = {
3927b1eda22SDaniel Mack 		{4,  "line in"}, /* &1=Line, &2=Mic*/
3937b1eda22SDaniel Mack 		{3,  "hph out"}, /* headphones */
3947b1eda22SDaniel Mack 		{0,  "RC     "}, /* last command, 6 bytes see rc_config above */
3957b1eda22SDaniel Mack 		{-1, NULL}
3967b1eda22SDaniel Mack 	};
3977b1eda22SDaniel Mack 	const struct sb_jack *jacks;
3987b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = entry->private_data;
3997b1eda22SDaniel Mack 	int i, err;
4007b1eda22SDaniel Mack 	u8 buf[3];
4017b1eda22SDaniel Mack 
4027b1eda22SDaniel Mack 	snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname);
4037b1eda22SDaniel Mack 	if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020))
4047b1eda22SDaniel Mack 		jacks = jacks_audigy2nx;
4057b1eda22SDaniel Mack 	else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
4067b1eda22SDaniel Mack 		 mixer->chip->usb_id == USB_ID(0x041e, 0x3048))
4077b1eda22SDaniel Mack 		jacks = jacks_live24ext;
4087b1eda22SDaniel Mack 	else
4097b1eda22SDaniel Mack 		return;
4107b1eda22SDaniel Mack 
4117b1eda22SDaniel Mack 	for (i = 0; jacks[i].name; ++i) {
4127b1eda22SDaniel Mack 		snd_iprintf(buffer, "%s: ", jacks[i].name);
413888ea7d5STakashi Iwai 		down_read(&mixer->chip->shutdown_rwsem);
414888ea7d5STakashi Iwai 		if (mixer->chip->shutdown)
415888ea7d5STakashi Iwai 			err = 0;
416888ea7d5STakashi Iwai 		else
4177b1eda22SDaniel Mack 			err = snd_usb_ctl_msg(mixer->chip->dev,
4187b1eda22SDaniel Mack 				      usb_rcvctrlpipe(mixer->chip->dev, 0),
4197b1eda22SDaniel Mack 				      UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS |
4207b1eda22SDaniel Mack 				      USB_RECIP_INTERFACE, 0,
42117d900c4SClemens Ladisch 				      jacks[i].unitid << 8, buf, 3);
422888ea7d5STakashi Iwai 		up_read(&mixer->chip->shutdown_rwsem);
4237b1eda22SDaniel Mack 		if (err == 3 && (buf[0] == 3 || buf[0] == 6))
4247b1eda22SDaniel Mack 			snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]);
4257b1eda22SDaniel Mack 		else
4267b1eda22SDaniel Mack 			snd_iprintf(buffer, "?\n");
4277b1eda22SDaniel Mack 	}
4287b1eda22SDaniel Mack }
4297b1eda22SDaniel Mack 
43044832a71SVasily Khoruzhick /* EMU0204 */
43144832a71SVasily Khoruzhick static int snd_emu0204_ch_switch_info(struct snd_kcontrol *kcontrol,
43244832a71SVasily Khoruzhick 				      struct snd_ctl_elem_info *uinfo)
43344832a71SVasily Khoruzhick {
4347bbd03e0STakashi Iwai 	static const char * const texts[2] = {"1/2", "3/4"};
43544832a71SVasily Khoruzhick 
4367bbd03e0STakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
43744832a71SVasily Khoruzhick }
43844832a71SVasily Khoruzhick 
43944832a71SVasily Khoruzhick static int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol,
44044832a71SVasily Khoruzhick 				     struct snd_ctl_elem_value *ucontrol)
44144832a71SVasily Khoruzhick {
44244832a71SVasily Khoruzhick 	ucontrol->value.enumerated.item[0] = kcontrol->private_value;
44344832a71SVasily Khoruzhick 	return 0;
44444832a71SVasily Khoruzhick }
44544832a71SVasily Khoruzhick 
44644832a71SVasily Khoruzhick static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol,
44744832a71SVasily Khoruzhick 				     struct snd_ctl_elem_value *ucontrol)
44844832a71SVasily Khoruzhick {
44944832a71SVasily Khoruzhick 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
45044832a71SVasily Khoruzhick 	unsigned int value = ucontrol->value.enumerated.item[0];
45144832a71SVasily Khoruzhick 	int err, changed;
45244832a71SVasily Khoruzhick 	unsigned char buf[2];
45344832a71SVasily Khoruzhick 
45444832a71SVasily Khoruzhick 	if (value > 1)
45544832a71SVasily Khoruzhick 		return -EINVAL;
45644832a71SVasily Khoruzhick 
45744832a71SVasily Khoruzhick 	buf[0] = 0x01;
45844832a71SVasily Khoruzhick 	buf[1] = value ? 0x02 : 0x01;
45944832a71SVasily Khoruzhick 
46044832a71SVasily Khoruzhick 	changed = value != kcontrol->private_value;
46144832a71SVasily Khoruzhick 	down_read(&mixer->chip->shutdown_rwsem);
46244832a71SVasily Khoruzhick 	if (mixer->chip->shutdown) {
46344832a71SVasily Khoruzhick 		err = -ENODEV;
46444832a71SVasily Khoruzhick 		goto out;
46544832a71SVasily Khoruzhick 	}
46644832a71SVasily Khoruzhick 	err = snd_usb_ctl_msg(mixer->chip->dev,
46744832a71SVasily Khoruzhick 		      usb_sndctrlpipe(mixer->chip->dev, 0), UAC_SET_CUR,
46844832a71SVasily Khoruzhick 		      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
46944832a71SVasily Khoruzhick 		      0x0400, 0x0e00, buf, 2);
47044832a71SVasily Khoruzhick  out:
47144832a71SVasily Khoruzhick 	up_read(&mixer->chip->shutdown_rwsem);
47244832a71SVasily Khoruzhick 	if (err < 0)
47344832a71SVasily Khoruzhick 		return err;
47444832a71SVasily Khoruzhick 	kcontrol->private_value = value;
47544832a71SVasily Khoruzhick 	return changed;
47644832a71SVasily Khoruzhick }
47744832a71SVasily Khoruzhick 
47844832a71SVasily Khoruzhick 
47944832a71SVasily Khoruzhick static struct snd_kcontrol_new snd_emu0204_controls[] = {
48044832a71SVasily Khoruzhick 	{
48144832a71SVasily Khoruzhick 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
48244832a71SVasily Khoruzhick 		.name = "Front Jack Channels",
48344832a71SVasily Khoruzhick 		.info = snd_emu0204_ch_switch_info,
48444832a71SVasily Khoruzhick 		.get = snd_emu0204_ch_switch_get,
48544832a71SVasily Khoruzhick 		.put = snd_emu0204_ch_switch_put,
48644832a71SVasily Khoruzhick 		.private_value = 0,
48744832a71SVasily Khoruzhick 	},
48844832a71SVasily Khoruzhick };
48944832a71SVasily Khoruzhick 
49044832a71SVasily Khoruzhick static int snd_emu0204_controls_create(struct usb_mixer_interface *mixer)
49144832a71SVasily Khoruzhick {
49244832a71SVasily Khoruzhick 	int i, err;
49344832a71SVasily Khoruzhick 
49444832a71SVasily Khoruzhick 	for (i = 0; i < ARRAY_SIZE(snd_emu0204_controls); ++i) {
49544832a71SVasily Khoruzhick 		err = snd_ctl_add(mixer->chip->card,
49644832a71SVasily Khoruzhick 			snd_ctl_new1(&snd_emu0204_controls[i], mixer));
49744832a71SVasily Khoruzhick 		if (err < 0)
49844832a71SVasily Khoruzhick 			return err;
49944832a71SVasily Khoruzhick 	}
50044832a71SVasily Khoruzhick 
50144832a71SVasily Khoruzhick 	return 0;
50244832a71SVasily Khoruzhick }
5031d31affbSDenis Washington /* ASUS Xonar U1 / U3 controls */
5041d31affbSDenis Washington 
5057b1eda22SDaniel Mack static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol,
5067b1eda22SDaniel Mack 				   struct snd_ctl_elem_value *ucontrol)
5077b1eda22SDaniel Mack {
5087b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
5097b1eda22SDaniel Mack 
5107b1eda22SDaniel Mack 	ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02);
5117b1eda22SDaniel Mack 	return 0;
5127b1eda22SDaniel Mack }
5137b1eda22SDaniel Mack 
5147b1eda22SDaniel Mack static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
5157b1eda22SDaniel Mack 				   struct snd_ctl_elem_value *ucontrol)
5167b1eda22SDaniel Mack {
5177b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
5187b1eda22SDaniel Mack 	u8 old_status, new_status;
5197b1eda22SDaniel Mack 	int err, changed;
5207b1eda22SDaniel Mack 
5217b1eda22SDaniel Mack 	old_status = mixer->xonar_u1_status;
5227b1eda22SDaniel Mack 	if (ucontrol->value.integer.value[0])
5237b1eda22SDaniel Mack 		new_status = old_status | 0x02;
5247b1eda22SDaniel Mack 	else
5257b1eda22SDaniel Mack 		new_status = old_status & ~0x02;
5267b1eda22SDaniel Mack 	changed = new_status != old_status;
527888ea7d5STakashi Iwai 	down_read(&mixer->chip->shutdown_rwsem);
528888ea7d5STakashi Iwai 	if (mixer->chip->shutdown)
529888ea7d5STakashi Iwai 		err = -ENODEV;
530888ea7d5STakashi Iwai 	else
5317b1eda22SDaniel Mack 		err = snd_usb_ctl_msg(mixer->chip->dev,
5327b1eda22SDaniel Mack 			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x08,
5337b1eda22SDaniel Mack 			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
53417d900c4SClemens Ladisch 			      50, 0, &new_status, 1);
535888ea7d5STakashi Iwai 	up_read(&mixer->chip->shutdown_rwsem);
5367b1eda22SDaniel Mack 	if (err < 0)
5377b1eda22SDaniel Mack 		return err;
5387b1eda22SDaniel Mack 	mixer->xonar_u1_status = new_status;
5397b1eda22SDaniel Mack 	return changed;
5407b1eda22SDaniel Mack }
5417b1eda22SDaniel Mack 
5427b1eda22SDaniel Mack static struct snd_kcontrol_new snd_xonar_u1_output_switch = {
5437b1eda22SDaniel Mack 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5447b1eda22SDaniel Mack 	.name = "Digital Playback Switch",
5457b1eda22SDaniel Mack 	.info = snd_ctl_boolean_mono_info,
5467b1eda22SDaniel Mack 	.get = snd_xonar_u1_switch_get,
5477b1eda22SDaniel Mack 	.put = snd_xonar_u1_switch_put,
5487b1eda22SDaniel Mack };
5497b1eda22SDaniel Mack 
5507b1eda22SDaniel Mack static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)
5517b1eda22SDaniel Mack {
5527b1eda22SDaniel Mack 	int err;
5537b1eda22SDaniel Mack 
5547b1eda22SDaniel Mack 	err = snd_ctl_add(mixer->chip->card,
5557b1eda22SDaniel Mack 			  snd_ctl_new1(&snd_xonar_u1_output_switch, mixer));
5567b1eda22SDaniel Mack 	if (err < 0)
5577b1eda22SDaniel Mack 		return err;
5587b1eda22SDaniel Mack 	mixer->xonar_u1_status = 0x05;
5597b1eda22SDaniel Mack 	return 0;
5607b1eda22SDaniel Mack }
5617b1eda22SDaniel Mack 
562d497a82fSDamien Zammit /* Digidesign Mbox 1 clock source switch (internal/spdif) */
563d497a82fSDamien Zammit 
564d497a82fSDamien Zammit static int snd_mbox1_switch_get(struct snd_kcontrol *kctl,
565d497a82fSDamien Zammit 				struct snd_ctl_elem_value *ucontrol)
566d497a82fSDamien Zammit {
567d497a82fSDamien Zammit 	ucontrol->value.enumerated.item[0] = kctl->private_value;
568d497a82fSDamien Zammit 	return 0;
569d497a82fSDamien Zammit }
570d497a82fSDamien Zammit 
571d497a82fSDamien Zammit static int snd_mbox1_switch_put(struct snd_kcontrol *kctl,
572d497a82fSDamien Zammit 				struct snd_ctl_elem_value *ucontrol)
573d497a82fSDamien Zammit {
574d497a82fSDamien Zammit 	struct snd_usb_audio *chip;
575d497a82fSDamien Zammit 	struct usb_mixer_interface *mixer;
576d497a82fSDamien Zammit 	int err;
577d497a82fSDamien Zammit 	bool cur_val, new_val;
578d497a82fSDamien Zammit 	unsigned char buff[3];
579d497a82fSDamien Zammit 
580d497a82fSDamien Zammit 	cur_val = kctl->private_value;
581d497a82fSDamien Zammit 	new_val = ucontrol->value.enumerated.item[0];
582d497a82fSDamien Zammit 
583d497a82fSDamien Zammit 	mixer = snd_kcontrol_chip(kctl);
584d497a82fSDamien Zammit 	if (snd_BUG_ON(!mixer))
585d497a82fSDamien Zammit 		return -EINVAL;
586d497a82fSDamien Zammit 
587d497a82fSDamien Zammit 	chip = mixer->chip;
588d497a82fSDamien Zammit 	if (snd_BUG_ON(!chip))
589d497a82fSDamien Zammit 		return -EINVAL;
590d497a82fSDamien Zammit 
591d497a82fSDamien Zammit 	if (cur_val == new_val)
592d497a82fSDamien Zammit 		return 0;
593d497a82fSDamien Zammit 
594d497a82fSDamien Zammit 	down_read(&chip->shutdown_rwsem);
595d497a82fSDamien Zammit 	if (chip->shutdown) {
596d497a82fSDamien Zammit 		err = -ENODEV;
597d497a82fSDamien Zammit 		goto err;
598d497a82fSDamien Zammit 	}
599d497a82fSDamien Zammit 
600d497a82fSDamien Zammit 	/* Prepare for magic command to toggle clock source */
601d497a82fSDamien Zammit 	err = snd_usb_ctl_msg(chip->dev,
602d497a82fSDamien Zammit 				usb_rcvctrlpipe(chip->dev, 0), 0x81,
603d497a82fSDamien Zammit 				USB_DIR_IN |
604d497a82fSDamien Zammit 				USB_TYPE_CLASS |
605d497a82fSDamien Zammit 				USB_RECIP_INTERFACE, 0x00, 0x500, buff, 1);
606d497a82fSDamien Zammit 	if (err < 0)
607d497a82fSDamien Zammit 		goto err;
608d497a82fSDamien Zammit 	err = snd_usb_ctl_msg(chip->dev,
609d497a82fSDamien Zammit 				usb_rcvctrlpipe(chip->dev, 0), 0x81,
610d497a82fSDamien Zammit 				USB_DIR_IN |
611d497a82fSDamien Zammit 				USB_TYPE_CLASS |
612d497a82fSDamien Zammit 				USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
613d497a82fSDamien Zammit 	if (err < 0)
614d497a82fSDamien Zammit 		goto err;
615d497a82fSDamien Zammit 
616d497a82fSDamien Zammit 	/* 2 possibilities:	Internal    -> send sample rate
617d497a82fSDamien Zammit 	 *			S/PDIF sync -> send zeroes
618d497a82fSDamien Zammit 	 * NB: Sample rate locked to 48kHz on purpose to
619d497a82fSDamien Zammit 	 *     prevent user from resetting the sample rate
620d497a82fSDamien Zammit 	 *     while S/PDIF sync is enabled and confusing
621d497a82fSDamien Zammit 	 *     this configuration.
622d497a82fSDamien Zammit 	 */
623d497a82fSDamien Zammit 	if (new_val == 0) {
624d497a82fSDamien Zammit 		buff[0] = 0x80;
625d497a82fSDamien Zammit 		buff[1] = 0xbb;
626d497a82fSDamien Zammit 		buff[2] = 0x00;
627d497a82fSDamien Zammit 	} else {
628d497a82fSDamien Zammit 		buff[0] = buff[1] = buff[2] = 0x00;
629d497a82fSDamien Zammit 	}
630d497a82fSDamien Zammit 
631d497a82fSDamien Zammit 	/* Send the magic command to toggle the clock source */
632d497a82fSDamien Zammit 	err = snd_usb_ctl_msg(chip->dev,
633d497a82fSDamien Zammit 				usb_sndctrlpipe(chip->dev, 0), 0x1,
634d497a82fSDamien Zammit 				USB_TYPE_CLASS |
635d497a82fSDamien Zammit 				USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
636d497a82fSDamien Zammit 	if (err < 0)
637d497a82fSDamien Zammit 		goto err;
638d497a82fSDamien Zammit 	err = snd_usb_ctl_msg(chip->dev,
639d497a82fSDamien Zammit 				usb_rcvctrlpipe(chip->dev, 0), 0x81,
640d497a82fSDamien Zammit 				USB_DIR_IN |
641d497a82fSDamien Zammit 				USB_TYPE_CLASS |
642d497a82fSDamien Zammit 				USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
643d497a82fSDamien Zammit 	if (err < 0)
644d497a82fSDamien Zammit 		goto err;
645d497a82fSDamien Zammit 	err = snd_usb_ctl_msg(chip->dev,
646d497a82fSDamien Zammit 				usb_rcvctrlpipe(chip->dev, 0), 0x81,
647d497a82fSDamien Zammit 				USB_DIR_IN |
648d497a82fSDamien Zammit 				USB_TYPE_CLASS |
649d497a82fSDamien Zammit 				USB_RECIP_ENDPOINT, 0x100, 0x2, buff, 3);
650d497a82fSDamien Zammit 	if (err < 0)
651d497a82fSDamien Zammit 		goto err;
652d497a82fSDamien Zammit 	kctl->private_value = new_val;
653d497a82fSDamien Zammit 
654d497a82fSDamien Zammit err:
655d497a82fSDamien Zammit 	up_read(&chip->shutdown_rwsem);
656d497a82fSDamien Zammit 	return err < 0 ? err : 1;
657d497a82fSDamien Zammit }
658d497a82fSDamien Zammit 
659d497a82fSDamien Zammit static int snd_mbox1_switch_info(struct snd_kcontrol *kcontrol,
660d497a82fSDamien Zammit 				 struct snd_ctl_elem_info *uinfo)
661d497a82fSDamien Zammit {
662d497a82fSDamien Zammit 	static const char *const texts[2] = {
663d497a82fSDamien Zammit 		"Internal",
664d497a82fSDamien Zammit 		"S/PDIF"
665d497a82fSDamien Zammit 	};
666d497a82fSDamien Zammit 
667d497a82fSDamien Zammit 	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
668d497a82fSDamien Zammit }
669d497a82fSDamien Zammit 
670d497a82fSDamien Zammit static struct snd_kcontrol_new snd_mbox1_switch = {
671d497a82fSDamien Zammit 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
672d497a82fSDamien Zammit 	.name = "Clock Source",
673d497a82fSDamien Zammit 	.index = 0,
674d497a82fSDamien Zammit 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
675d497a82fSDamien Zammit 	.info = snd_mbox1_switch_info,
676d497a82fSDamien Zammit 	.get = snd_mbox1_switch_get,
677d497a82fSDamien Zammit 	.put = snd_mbox1_switch_put,
678d497a82fSDamien Zammit 	.private_value = 0
679d497a82fSDamien Zammit };
680d497a82fSDamien Zammit 
681d497a82fSDamien Zammit static int snd_mbox1_create_sync_switch(struct usb_mixer_interface *mixer)
682d497a82fSDamien Zammit {
683d497a82fSDamien Zammit 	return snd_ctl_add(mixer->chip->card,
684d497a82fSDamien Zammit 			snd_ctl_new1(&snd_mbox1_switch, mixer));
685d497a82fSDamien Zammit }
686d497a82fSDamien Zammit 
68754a8c500SDaniel Mack /* Native Instruments device quirks */
68854a8c500SDaniel Mack 
68954a8c500SDaniel Mack #define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex))
69054a8c500SDaniel Mack 
69154a8c500SDaniel Mack static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
69254a8c500SDaniel Mack 					     struct snd_ctl_elem_value *ucontrol)
69354a8c500SDaniel Mack {
69454a8c500SDaniel Mack 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
69554a8c500SDaniel Mack 	struct usb_device *dev = mixer->chip->dev;
69654a8c500SDaniel Mack 	u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
69754a8c500SDaniel Mack 	u16 wIndex = kcontrol->private_value & 0xffff;
69854a8c500SDaniel Mack 	u8 tmp;
699888ea7d5STakashi Iwai 	int ret;
70054a8c500SDaniel Mack 
701888ea7d5STakashi Iwai 	down_read(&mixer->chip->shutdown_rwsem);
702888ea7d5STakashi Iwai 	if (mixer->chip->shutdown)
703888ea7d5STakashi Iwai 		ret = -ENODEV;
704888ea7d5STakashi Iwai 	else
705888ea7d5STakashi Iwai 		ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
70654a8c500SDaniel Mack 				  USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
707889d6684SEldad Zack 				  0, wIndex,
70854a8c500SDaniel Mack 				  &tmp, sizeof(tmp), 1000);
709888ea7d5STakashi Iwai 	up_read(&mixer->chip->shutdown_rwsem);
71054a8c500SDaniel Mack 
71154a8c500SDaniel Mack 	if (ret < 0) {
7120ba41d91STakashi Iwai 		dev_err(&dev->dev,
71354a8c500SDaniel Mack 			"unable to issue vendor read request (ret = %d)", ret);
71454a8c500SDaniel Mack 		return ret;
71554a8c500SDaniel Mack 	}
71654a8c500SDaniel Mack 
71754a8c500SDaniel Mack 	ucontrol->value.integer.value[0] = tmp;
71854a8c500SDaniel Mack 
71954a8c500SDaniel Mack 	return 0;
72054a8c500SDaniel Mack }
72154a8c500SDaniel Mack 
72254a8c500SDaniel Mack static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
72354a8c500SDaniel Mack 					     struct snd_ctl_elem_value *ucontrol)
72454a8c500SDaniel Mack {
72554a8c500SDaniel Mack 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
72654a8c500SDaniel Mack 	struct usb_device *dev = mixer->chip->dev;
72754a8c500SDaniel Mack 	u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
72854a8c500SDaniel Mack 	u16 wIndex = kcontrol->private_value & 0xffff;
72954a8c500SDaniel Mack 	u16 wValue = ucontrol->value.integer.value[0];
730888ea7d5STakashi Iwai 	int ret;
73154a8c500SDaniel Mack 
732888ea7d5STakashi Iwai 	down_read(&mixer->chip->shutdown_rwsem);
733888ea7d5STakashi Iwai 	if (mixer->chip->shutdown)
734888ea7d5STakashi Iwai 		ret = -ENODEV;
735888ea7d5STakashi Iwai 	else
736888ea7d5STakashi Iwai 		ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
73754a8c500SDaniel Mack 				  USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
738889d6684SEldad Zack 				  wValue, wIndex,
73954a8c500SDaniel Mack 				  NULL, 0, 1000);
740888ea7d5STakashi Iwai 	up_read(&mixer->chip->shutdown_rwsem);
74154a8c500SDaniel Mack 
74254a8c500SDaniel Mack 	if (ret < 0) {
7430ba41d91STakashi Iwai 		dev_err(&dev->dev,
74454a8c500SDaniel Mack 			"unable to issue vendor write request (ret = %d)", ret);
74554a8c500SDaniel Mack 		return ret;
74654a8c500SDaniel Mack 	}
74754a8c500SDaniel Mack 
74854a8c500SDaniel Mack 	return 0;
74954a8c500SDaniel Mack }
75054a8c500SDaniel Mack 
75154a8c500SDaniel Mack static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = {
75254a8c500SDaniel Mack 	{
75354a8c500SDaniel Mack 		.name = "Direct Thru Channel A",
75454a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x01, 0x03),
75554a8c500SDaniel Mack 	},
75654a8c500SDaniel Mack 	{
75754a8c500SDaniel Mack 		.name = "Direct Thru Channel B",
75854a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x01, 0x05),
75954a8c500SDaniel Mack 	},
76054a8c500SDaniel Mack 	{
76154a8c500SDaniel Mack 		.name = "Phono Input Channel A",
76254a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x02, 0x03),
76354a8c500SDaniel Mack 	},
76454a8c500SDaniel Mack 	{
76554a8c500SDaniel Mack 		.name = "Phono Input Channel B",
76654a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x02, 0x05),
76754a8c500SDaniel Mack 	},
76854a8c500SDaniel Mack };
76954a8c500SDaniel Mack 
77054a8c500SDaniel Mack static struct snd_kcontrol_new snd_nativeinstruments_ta10_mixers[] = {
77154a8c500SDaniel Mack 	{
77254a8c500SDaniel Mack 		.name = "Direct Thru Channel A",
77354a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x01, 0x03),
77454a8c500SDaniel Mack 	},
77554a8c500SDaniel Mack 	{
77654a8c500SDaniel Mack 		.name = "Direct Thru Channel B",
77754a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x01, 0x05),
77854a8c500SDaniel Mack 	},
77954a8c500SDaniel Mack 	{
78054a8c500SDaniel Mack 		.name = "Direct Thru Channel C",
78154a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x01, 0x07),
78254a8c500SDaniel Mack 	},
78354a8c500SDaniel Mack 	{
78454a8c500SDaniel Mack 		.name = "Direct Thru Channel D",
78554a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x01, 0x09),
78654a8c500SDaniel Mack 	},
78754a8c500SDaniel Mack 	{
78854a8c500SDaniel Mack 		.name = "Phono Input Channel A",
78954a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x02, 0x03),
79054a8c500SDaniel Mack 	},
79154a8c500SDaniel Mack 	{
79254a8c500SDaniel Mack 		.name = "Phono Input Channel B",
79354a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x02, 0x05),
79454a8c500SDaniel Mack 	},
79554a8c500SDaniel Mack 	{
79654a8c500SDaniel Mack 		.name = "Phono Input Channel C",
79754a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x02, 0x07),
79854a8c500SDaniel Mack 	},
79954a8c500SDaniel Mack 	{
80054a8c500SDaniel Mack 		.name = "Phono Input Channel D",
80154a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x02, 0x09),
80254a8c500SDaniel Mack 	},
80354a8c500SDaniel Mack };
80454a8c500SDaniel Mack 
80554a8c500SDaniel Mack static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
80654a8c500SDaniel Mack 					      const struct snd_kcontrol_new *kc,
80754a8c500SDaniel Mack 					      unsigned int count)
80854a8c500SDaniel Mack {
80954a8c500SDaniel Mack 	int i, err = 0;
81054a8c500SDaniel Mack 	struct snd_kcontrol_new template = {
81154a8c500SDaniel Mack 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
81254a8c500SDaniel Mack 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
81354a8c500SDaniel Mack 		.get = snd_nativeinstruments_control_get,
81454a8c500SDaniel Mack 		.put = snd_nativeinstruments_control_put,
81554a8c500SDaniel Mack 		.info = snd_ctl_boolean_mono_info,
81654a8c500SDaniel Mack 	};
81754a8c500SDaniel Mack 
81854a8c500SDaniel Mack 	for (i = 0; i < count; i++) {
81954a8c500SDaniel Mack 		struct snd_kcontrol *c;
82054a8c500SDaniel Mack 
82154a8c500SDaniel Mack 		template.name = kc[i].name;
82254a8c500SDaniel Mack 		template.private_value = kc[i].private_value;
82354a8c500SDaniel Mack 
82454a8c500SDaniel Mack 		c = snd_ctl_new1(&template, mixer);
82554a8c500SDaniel Mack 		err = snd_ctl_add(mixer->chip->card, c);
82654a8c500SDaniel Mack 
82754a8c500SDaniel Mack 		if (err < 0)
82854a8c500SDaniel Mack 			break;
82954a8c500SDaniel Mack 	}
83054a8c500SDaniel Mack 
83154a8c500SDaniel Mack 	return err;
83254a8c500SDaniel Mack }
83354a8c500SDaniel Mack 
834d5a0bf6cSDaniel Mack /* M-Audio FastTrack Ultra quirks */
835e9a25e04SMatt Gruskin /* FTU Effect switch (also used by C400/C600) */
836d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val {
837d34bf148SFelix Homann 	struct usb_mixer_interface *mixer;
838d34bf148SFelix Homann 	int cached_value;
839d34bf148SFelix Homann 	int is_cached;
840d847ce0eSEldad Zack 	int bUnitID;
841d847ce0eSEldad Zack 	int validx;
842d34bf148SFelix Homann };
843d34bf148SFelix Homann 
844d34bf148SFelix Homann static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol,
845d34bf148SFelix Homann 					struct snd_ctl_elem_info *uinfo)
846d34bf148SFelix Homann {
8477bbd03e0STakashi Iwai 	static const char *const texts[8] = {
8487bbd03e0STakashi Iwai 		"Room 1", "Room 2", "Room 3", "Hall 1",
8497bbd03e0STakashi Iwai 		"Hall 2", "Plate", "Delay", "Echo"
850d34bf148SFelix Homann 	};
851d34bf148SFelix Homann 
8527bbd03e0STakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
853d34bf148SFelix Homann }
854d34bf148SFelix Homann 
855d34bf148SFelix Homann static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
856d34bf148SFelix Homann 					struct snd_ctl_elem_value *ucontrol)
857d34bf148SFelix Homann {
858d34bf148SFelix Homann 	struct snd_usb_audio *chip;
859d34bf148SFelix Homann 	struct usb_mixer_interface *mixer;
860d34bf148SFelix Homann 	struct snd_ftu_eff_switch_priv_val *pval;
861d34bf148SFelix Homann 	int err;
862d34bf148SFelix Homann 	unsigned char value[2];
863d847ce0eSEldad Zack 	int id, validx;
864d34bf148SFelix Homann 
865d34bf148SFelix Homann 	const int val_len = 2;
866d34bf148SFelix Homann 
867d34bf148SFelix Homann 	value[0] = 0x00;
868d34bf148SFelix Homann 	value[1] = 0x00;
869d34bf148SFelix Homann 
870d34bf148SFelix Homann 	pval = (struct snd_ftu_eff_switch_priv_val *)
871d34bf148SFelix Homann 		kctl->private_value;
872d34bf148SFelix Homann 
873d34bf148SFelix Homann 	if (pval->is_cached) {
874d34bf148SFelix Homann 		ucontrol->value.enumerated.item[0] = pval->cached_value;
875d34bf148SFelix Homann 		return 0;
876d34bf148SFelix Homann 	}
877d34bf148SFelix Homann 
878d34bf148SFelix Homann 	mixer = (struct usb_mixer_interface *) pval->mixer;
879d34bf148SFelix Homann 	if (snd_BUG_ON(!mixer))
880d34bf148SFelix Homann 		return -EINVAL;
881d34bf148SFelix Homann 
882d34bf148SFelix Homann 	chip = (struct snd_usb_audio *) mixer->chip;
883d34bf148SFelix Homann 	if (snd_BUG_ON(!chip))
884d34bf148SFelix Homann 		return -EINVAL;
885d34bf148SFelix Homann 
886d847ce0eSEldad Zack 	id = pval->bUnitID;
887d847ce0eSEldad Zack 	validx = pval->validx;
888d34bf148SFelix Homann 
889888ea7d5STakashi Iwai 	down_read(&mixer->chip->shutdown_rwsem);
890888ea7d5STakashi Iwai 	if (mixer->chip->shutdown)
891888ea7d5STakashi Iwai 		err = -ENODEV;
892888ea7d5STakashi Iwai 	else
893d34bf148SFelix Homann 		err = snd_usb_ctl_msg(chip->dev,
894d34bf148SFelix Homann 			usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
895d34bf148SFelix Homann 			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
896d34bf148SFelix Homann 			validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
897d34bf148SFelix Homann 			value, val_len);
898888ea7d5STakashi Iwai 	up_read(&mixer->chip->shutdown_rwsem);
899d34bf148SFelix Homann 	if (err < 0)
900d34bf148SFelix Homann 		return err;
901d34bf148SFelix Homann 
902d34bf148SFelix Homann 	ucontrol->value.enumerated.item[0] = value[0];
903d34bf148SFelix Homann 	pval->cached_value = value[0];
904d34bf148SFelix Homann 	pval->is_cached = 1;
905d34bf148SFelix Homann 
906d34bf148SFelix Homann 	return 0;
907d34bf148SFelix Homann }
908d34bf148SFelix Homann 
909d34bf148SFelix Homann static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
910d34bf148SFelix Homann 					struct snd_ctl_elem_value *ucontrol)
911d34bf148SFelix Homann {
912d34bf148SFelix Homann 	struct snd_usb_audio *chip;
913d34bf148SFelix Homann 	struct snd_ftu_eff_switch_priv_val *pval;
914d34bf148SFelix Homann 
915d34bf148SFelix Homann 	struct usb_mixer_interface *mixer;
916d34bf148SFelix Homann 	int changed, cur_val, err, new_val;
917d34bf148SFelix Homann 	unsigned char value[2];
918d847ce0eSEldad Zack 	int id, validx;
919d34bf148SFelix Homann 
920d34bf148SFelix Homann 	const int val_len = 2;
921d34bf148SFelix Homann 
922d34bf148SFelix Homann 	changed = 0;
923d34bf148SFelix Homann 
924d34bf148SFelix Homann 	pval = (struct snd_ftu_eff_switch_priv_val *)
925d34bf148SFelix Homann 		kctl->private_value;
926d34bf148SFelix Homann 	cur_val = pval->cached_value;
927d34bf148SFelix Homann 	new_val = ucontrol->value.enumerated.item[0];
928d34bf148SFelix Homann 
929d34bf148SFelix Homann 	mixer = (struct usb_mixer_interface *) pval->mixer;
930d34bf148SFelix Homann 	if (snd_BUG_ON(!mixer))
931d34bf148SFelix Homann 		return -EINVAL;
932d34bf148SFelix Homann 
933d34bf148SFelix Homann 	chip = (struct snd_usb_audio *) mixer->chip;
934d34bf148SFelix Homann 	if (snd_BUG_ON(!chip))
935d34bf148SFelix Homann 		return -EINVAL;
936d34bf148SFelix Homann 
937d847ce0eSEldad Zack 	id = pval->bUnitID;
938d847ce0eSEldad Zack 	validx = pval->validx;
939d847ce0eSEldad Zack 
940d34bf148SFelix Homann 	if (!pval->is_cached) {
941d34bf148SFelix Homann 		/* Read current value */
942888ea7d5STakashi Iwai 		down_read(&mixer->chip->shutdown_rwsem);
943888ea7d5STakashi Iwai 		if (mixer->chip->shutdown)
944888ea7d5STakashi Iwai 			err = -ENODEV;
945888ea7d5STakashi Iwai 		else
946d34bf148SFelix Homann 			err = snd_usb_ctl_msg(chip->dev,
947d34bf148SFelix Homann 				usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
948d34bf148SFelix Homann 				USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
949d34bf148SFelix Homann 				validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
950d34bf148SFelix Homann 				value, val_len);
951888ea7d5STakashi Iwai 		up_read(&mixer->chip->shutdown_rwsem);
952d34bf148SFelix Homann 		if (err < 0)
953d34bf148SFelix Homann 			return err;
954d34bf148SFelix Homann 
955d34bf148SFelix Homann 		cur_val = value[0];
956d34bf148SFelix Homann 		pval->cached_value = cur_val;
957d34bf148SFelix Homann 		pval->is_cached = 1;
958d34bf148SFelix Homann 	}
959d34bf148SFelix Homann 	/* update value if needed */
960d34bf148SFelix Homann 	if (cur_val != new_val) {
961d34bf148SFelix Homann 		value[0] = new_val;
962d34bf148SFelix Homann 		value[1] = 0;
963888ea7d5STakashi Iwai 		down_read(&mixer->chip->shutdown_rwsem);
964888ea7d5STakashi Iwai 		if (mixer->chip->shutdown)
965888ea7d5STakashi Iwai 			err = -ENODEV;
966888ea7d5STakashi Iwai 		else
967d34bf148SFelix Homann 			err = snd_usb_ctl_msg(chip->dev,
968d34bf148SFelix Homann 				usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
969d34bf148SFelix Homann 				USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
970d34bf148SFelix Homann 				validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
971d34bf148SFelix Homann 				value, val_len);
972888ea7d5STakashi Iwai 		up_read(&mixer->chip->shutdown_rwsem);
973d34bf148SFelix Homann 		if (err < 0)
974d34bf148SFelix Homann 			return err;
975d34bf148SFelix Homann 
976d34bf148SFelix Homann 		pval->cached_value = new_val;
977d34bf148SFelix Homann 		pval->is_cached = 1;
978d34bf148SFelix Homann 		changed = 1;
979d34bf148SFelix Homann 	}
980d34bf148SFelix Homann 
981d34bf148SFelix Homann 	return changed;
982d34bf148SFelix Homann }
983d34bf148SFelix Homann 
984d847ce0eSEldad Zack static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer,
985d847ce0eSEldad Zack 	int validx, int bUnitID)
986d34bf148SFelix Homann {
987d34bf148SFelix Homann 	static struct snd_kcontrol_new template = {
988d34bf148SFelix Homann 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
989d34bf148SFelix Homann 		.name = "Effect Program Switch",
990d34bf148SFelix Homann 		.index = 0,
991d34bf148SFelix Homann 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
992d34bf148SFelix Homann 		.info = snd_ftu_eff_switch_info,
993d34bf148SFelix Homann 		.get = snd_ftu_eff_switch_get,
994d34bf148SFelix Homann 		.put = snd_ftu_eff_switch_put
995d34bf148SFelix Homann 	};
996d34bf148SFelix Homann 
997d34bf148SFelix Homann 	int err;
998d34bf148SFelix Homann 	struct snd_kcontrol *kctl;
999d34bf148SFelix Homann 	struct snd_ftu_eff_switch_priv_val *pval;
1000d34bf148SFelix Homann 
1001d34bf148SFelix Homann 	pval = kzalloc(sizeof(*pval), GFP_KERNEL);
1002d34bf148SFelix Homann 	if (!pval)
1003d34bf148SFelix Homann 		return -ENOMEM;
1004d34bf148SFelix Homann 
1005d34bf148SFelix Homann 	pval->cached_value = 0;
1006d34bf148SFelix Homann 	pval->is_cached = 0;
1007d34bf148SFelix Homann 	pval->mixer = mixer;
1008d847ce0eSEldad Zack 	pval->bUnitID = bUnitID;
1009d847ce0eSEldad Zack 	pval->validx = validx;
1010d34bf148SFelix Homann 
1011d34bf148SFelix Homann 	template.private_value = (unsigned long) pval;
1012d34bf148SFelix Homann 	kctl = snd_ctl_new1(&template, mixer->chip);
1013d34bf148SFelix Homann 	if (!kctl) {
1014d34bf148SFelix Homann 		kfree(pval);
1015d34bf148SFelix Homann 		return -ENOMEM;
1016d34bf148SFelix Homann 	}
1017d34bf148SFelix Homann 
1018d34bf148SFelix Homann 	err = snd_ctl_add(mixer->chip->card, kctl);
1019d34bf148SFelix Homann 	if (err < 0)
1020d34bf148SFelix Homann 		return err;
1021d34bf148SFelix Homann 
1022d34bf148SFelix Homann 	return 0;
1023d34bf148SFelix Homann }
1024d5a0bf6cSDaniel Mack 
1025cfe8f97cSFelix Homann /* Create volume controls for FTU devices*/
1026cfe8f97cSFelix Homann static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
1027d5a0bf6cSDaniel Mack {
1028d5a0bf6cSDaniel Mack 	char name[64];
10298a4d1d39SFelix Homann 	unsigned int control, cmask;
1030d5a0bf6cSDaniel Mack 	int in, out, err;
1031d5a0bf6cSDaniel Mack 
10328a4d1d39SFelix Homann 	const unsigned int id = 5;
10338a4d1d39SFelix Homann 	const int val_type = USB_MIXER_S16;
10348a4d1d39SFelix Homann 
1035d5a0bf6cSDaniel Mack 	for (out = 0; out < 8; out++) {
10368a4d1d39SFelix Homann 		control = out + 1;
1037d5a0bf6cSDaniel Mack 		for (in = 0; in < 8; in++) {
10388a4d1d39SFelix Homann 			cmask = 1 << in;
1039d5a0bf6cSDaniel Mack 			snprintf(name, sizeof(name),
10408a4d1d39SFelix Homann 				"AIn%d - Out%d Capture Volume",
10418a4d1d39SFelix Homann 				in  + 1, out + 1);
10428a4d1d39SFelix Homann 			err = snd_create_std_mono_ctl(mixer, id, control,
10438a4d1d39SFelix Homann 							cmask, val_type, name,
104425ee7ef8SFelix Homann 							&snd_usb_mixer_vol_tlv);
1045d5a0bf6cSDaniel Mack 			if (err < 0)
1046d5a0bf6cSDaniel Mack 				return err;
1047d5a0bf6cSDaniel Mack 		}
1048d5a0bf6cSDaniel Mack 		for (in = 8; in < 16; in++) {
10498a4d1d39SFelix Homann 			cmask = 1 << in;
1050d5a0bf6cSDaniel Mack 			snprintf(name, sizeof(name),
10518a4d1d39SFelix Homann 				"DIn%d - Out%d Playback Volume",
10528a4d1d39SFelix Homann 				in - 7, out + 1);
10538a4d1d39SFelix Homann 			err = snd_create_std_mono_ctl(mixer, id, control,
10548a4d1d39SFelix Homann 							cmask, val_type, name,
105525ee7ef8SFelix Homann 							&snd_usb_mixer_vol_tlv);
1056d5a0bf6cSDaniel Mack 			if (err < 0)
1057d5a0bf6cSDaniel Mack 				return err;
1058d5a0bf6cSDaniel Mack 		}
1059d5a0bf6cSDaniel Mack 	}
1060d5a0bf6cSDaniel Mack 
1061d5a0bf6cSDaniel Mack 	return 0;
1062d5a0bf6cSDaniel Mack }
1063d5a0bf6cSDaniel Mack 
1064d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */
1065d34bf148SFelix Homann static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
1066d34bf148SFelix Homann {
1067d34bf148SFelix Homann 	static const char name[] = "Effect Volume";
1068d34bf148SFelix Homann 	const unsigned int id = 6;
1069d34bf148SFelix Homann 	const int val_type = USB_MIXER_U8;
1070d34bf148SFelix Homann 	const unsigned int control = 2;
1071d34bf148SFelix Homann 	const unsigned int cmask = 0;
1072d34bf148SFelix Homann 
1073d34bf148SFelix Homann 	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
1074d34bf148SFelix Homann 					name, snd_usb_mixer_vol_tlv);
1075d34bf148SFelix Homann }
1076d34bf148SFelix Homann 
1077d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */
1078d34bf148SFelix Homann static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
1079d34bf148SFelix Homann {
1080d34bf148SFelix Homann 	static const char name[] = "Effect Duration";
1081d34bf148SFelix Homann 	const unsigned int id = 6;
1082d34bf148SFelix Homann 	const int val_type = USB_MIXER_S16;
1083d34bf148SFelix Homann 	const unsigned int control = 3;
1084d34bf148SFelix Homann 	const unsigned int cmask = 0;
1085d34bf148SFelix Homann 
1086d34bf148SFelix Homann 	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
1087d34bf148SFelix Homann 					name, snd_usb_mixer_vol_tlv);
1088d34bf148SFelix Homann }
1089d34bf148SFelix Homann 
1090d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */
1091d34bf148SFelix Homann static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
1092d34bf148SFelix Homann {
1093d34bf148SFelix Homann 	static const char name[] = "Effect Feedback Volume";
1094d34bf148SFelix Homann 	const unsigned int id = 6;
1095d34bf148SFelix Homann 	const int val_type = USB_MIXER_U8;
1096d34bf148SFelix Homann 	const unsigned int control = 4;
1097d34bf148SFelix Homann 	const unsigned int cmask = 0;
1098d34bf148SFelix Homann 
1099d34bf148SFelix Homann 	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
1100d34bf148SFelix Homann 					name, NULL);
1101d34bf148SFelix Homann }
1102d34bf148SFelix Homann 
1103d34bf148SFelix Homann static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer)
1104d34bf148SFelix Homann {
1105d34bf148SFelix Homann 	unsigned int cmask;
1106d34bf148SFelix Homann 	int err, ch;
1107d34bf148SFelix Homann 	char name[48];
1108d34bf148SFelix Homann 
1109d34bf148SFelix Homann 	const unsigned int id = 7;
1110d34bf148SFelix Homann 	const int val_type = USB_MIXER_S16;
1111d34bf148SFelix Homann 	const unsigned int control = 7;
1112d34bf148SFelix Homann 
1113d34bf148SFelix Homann 	for (ch = 0; ch < 4; ++ch) {
1114d34bf148SFelix Homann 		cmask = 1 << ch;
1115d34bf148SFelix Homann 		snprintf(name, sizeof(name),
1116d34bf148SFelix Homann 			"Effect Return %d Volume", ch + 1);
1117d34bf148SFelix Homann 		err = snd_create_std_mono_ctl(mixer, id, control,
1118d34bf148SFelix Homann 						cmask, val_type, name,
1119d34bf148SFelix Homann 						snd_usb_mixer_vol_tlv);
1120d34bf148SFelix Homann 		if (err < 0)
1121d34bf148SFelix Homann 			return err;
1122d34bf148SFelix Homann 	}
1123d34bf148SFelix Homann 
1124d34bf148SFelix Homann 	return 0;
1125d34bf148SFelix Homann }
1126d34bf148SFelix Homann 
1127d34bf148SFelix Homann static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer)
1128d34bf148SFelix Homann {
1129d34bf148SFelix Homann 	unsigned int  cmask;
1130d34bf148SFelix Homann 	int err, ch;
1131d34bf148SFelix Homann 	char name[48];
1132d34bf148SFelix Homann 
1133d34bf148SFelix Homann 	const unsigned int id = 5;
1134d34bf148SFelix Homann 	const int val_type = USB_MIXER_S16;
1135d34bf148SFelix Homann 	const unsigned int control = 9;
1136d34bf148SFelix Homann 
1137d34bf148SFelix Homann 	for (ch = 0; ch < 8; ++ch) {
1138d34bf148SFelix Homann 		cmask = 1 << ch;
1139d34bf148SFelix Homann 		snprintf(name, sizeof(name),
1140d34bf148SFelix Homann 			"Effect Send AIn%d Volume", ch + 1);
1141d34bf148SFelix Homann 		err = snd_create_std_mono_ctl(mixer, id, control, cmask,
1142d34bf148SFelix Homann 						val_type, name,
1143d34bf148SFelix Homann 						snd_usb_mixer_vol_tlv);
1144d34bf148SFelix Homann 		if (err < 0)
1145d34bf148SFelix Homann 			return err;
1146d34bf148SFelix Homann 	}
1147d34bf148SFelix Homann 	for (ch = 8; ch < 16; ++ch) {
1148d34bf148SFelix Homann 		cmask = 1 << ch;
1149d34bf148SFelix Homann 		snprintf(name, sizeof(name),
1150d34bf148SFelix Homann 			"Effect Send DIn%d Volume", ch - 7);
1151d34bf148SFelix Homann 		err = snd_create_std_mono_ctl(mixer, id, control, cmask,
1152d34bf148SFelix Homann 						val_type, name,
1153d34bf148SFelix Homann 						snd_usb_mixer_vol_tlv);
1154d34bf148SFelix Homann 		if (err < 0)
1155d34bf148SFelix Homann 			return err;
1156d34bf148SFelix Homann 	}
1157d34bf148SFelix Homann 	return 0;
1158d34bf148SFelix Homann }
1159d34bf148SFelix Homann 
1160cfe8f97cSFelix Homann static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer)
11617536c301SMark Hills {
11628a4d1d39SFelix Homann 	int err;
11637536c301SMark Hills 
1164cfe8f97cSFelix Homann 	err = snd_ftu_create_volume_ctls(mixer);
11658a4d1d39SFelix Homann 	if (err < 0)
11668a4d1d39SFelix Homann 		return err;
11677536c301SMark Hills 
1168d847ce0eSEldad Zack 	err = snd_ftu_create_effect_switch(mixer, 1, 6);
1169d34bf148SFelix Homann 	if (err < 0)
1170d34bf148SFelix Homann 		return err;
1171d847ce0eSEldad Zack 
1172d34bf148SFelix Homann 	err = snd_ftu_create_effect_volume_ctl(mixer);
1173d34bf148SFelix Homann 	if (err < 0)
1174d34bf148SFelix Homann 		return err;
1175d34bf148SFelix Homann 
1176d34bf148SFelix Homann 	err = snd_ftu_create_effect_duration_ctl(mixer);
1177d34bf148SFelix Homann 	if (err < 0)
1178d34bf148SFelix Homann 		return err;
1179d34bf148SFelix Homann 
1180d34bf148SFelix Homann 	err = snd_ftu_create_effect_feedback_ctl(mixer);
1181d34bf148SFelix Homann 	if (err < 0)
1182d34bf148SFelix Homann 		return err;
1183d34bf148SFelix Homann 
1184d34bf148SFelix Homann 	err = snd_ftu_create_effect_return_ctls(mixer);
1185d34bf148SFelix Homann 	if (err < 0)
1186d34bf148SFelix Homann 		return err;
1187d34bf148SFelix Homann 
1188d34bf148SFelix Homann 	err = snd_ftu_create_effect_send_ctls(mixer);
1189d34bf148SFelix Homann 	if (err < 0)
1190d34bf148SFelix Homann 		return err;
1191d34bf148SFelix Homann 
11928a4d1d39SFelix Homann 	return 0;
11937536c301SMark Hills }
11947536c301SMark Hills 
11957b1eda22SDaniel Mack void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
11967b1eda22SDaniel Mack 			       unsigned char samplerate_id)
11977b1eda22SDaniel Mack {
11987b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer;
11997b1eda22SDaniel Mack 	struct usb_mixer_elem_info *cval;
12007b1eda22SDaniel Mack 	int unitid = 12; /* SamleRate ExtensionUnit ID */
12017b1eda22SDaniel Mack 
12027b1eda22SDaniel Mack 	list_for_each_entry(mixer, &chip->mixer_list, list) {
12037b1eda22SDaniel Mack 		cval = mixer->id_elems[unitid];
12047b1eda22SDaniel Mack 		if (cval) {
12057b1eda22SDaniel Mack 			snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
12067b1eda22SDaniel Mack 						    cval->control << 8,
12077b1eda22SDaniel Mack 						    samplerate_id);
12087b1eda22SDaniel Mack 			snd_usb_mixer_notify_id(mixer, unitid);
12097b1eda22SDaniel Mack 		}
12107b1eda22SDaniel Mack 		break;
12117b1eda22SDaniel Mack 	}
12127b1eda22SDaniel Mack }
12137b1eda22SDaniel Mack 
1214e9a25e04SMatt Gruskin /* M-Audio Fast Track C400/C600 */
1215e9a25e04SMatt Gruskin /* C400/C600 volume controls, this control needs a volume quirk, see mixer.c */
121609d8e3a7SEldad Zack static int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer)
121709d8e3a7SEldad Zack {
121809d8e3a7SEldad Zack 	char name[64];
121909d8e3a7SEldad Zack 	unsigned int cmask, offset;
122009d8e3a7SEldad Zack 	int out, chan, err;
1221e9a25e04SMatt Gruskin 	int num_outs = 0;
1222e9a25e04SMatt Gruskin 	int num_ins = 0;
122309d8e3a7SEldad Zack 
122409d8e3a7SEldad Zack 	const unsigned int id = 0x40;
122509d8e3a7SEldad Zack 	const int val_type = USB_MIXER_S16;
122609d8e3a7SEldad Zack 	const int control = 1;
122709d8e3a7SEldad Zack 
1228e9a25e04SMatt Gruskin 	switch (mixer->chip->usb_id) {
1229e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2030):
1230e9a25e04SMatt Gruskin 		num_outs = 6;
1231e9a25e04SMatt Gruskin 		num_ins = 4;
1232e9a25e04SMatt Gruskin 		break;
1233e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2031):
1234e9a25e04SMatt Gruskin 		num_outs = 8;
1235e9a25e04SMatt Gruskin 		num_ins = 6;
1236e9a25e04SMatt Gruskin 		break;
1237e9a25e04SMatt Gruskin 	}
1238e9a25e04SMatt Gruskin 
1239e9a25e04SMatt Gruskin 	for (chan = 0; chan < num_outs + num_ins; chan++) {
1240e9a25e04SMatt Gruskin 		for (out = 0; out < num_outs; out++) {
1241e9a25e04SMatt Gruskin 			if (chan < num_outs) {
124209d8e3a7SEldad Zack 				snprintf(name, sizeof(name),
124309d8e3a7SEldad Zack 					"PCM%d-Out%d Playback Volume",
124409d8e3a7SEldad Zack 					chan + 1, out + 1);
124509d8e3a7SEldad Zack 			} else {
124609d8e3a7SEldad Zack 				snprintf(name, sizeof(name),
124709d8e3a7SEldad Zack 					"In%d-Out%d Playback Volume",
1248e9a25e04SMatt Gruskin 					chan - num_outs + 1, out + 1);
124909d8e3a7SEldad Zack 			}
125009d8e3a7SEldad Zack 
125109d8e3a7SEldad Zack 			cmask = (out == 0) ? 0 : 1 << (out - 1);
1252e9a25e04SMatt Gruskin 			offset = chan * num_outs;
125309d8e3a7SEldad Zack 			err = snd_create_std_mono_ctl_offset(mixer, id, control,
125409d8e3a7SEldad Zack 						cmask, val_type, offset, name,
125509d8e3a7SEldad Zack 						&snd_usb_mixer_vol_tlv);
125609d8e3a7SEldad Zack 			if (err < 0)
125709d8e3a7SEldad Zack 				return err;
125809d8e3a7SEldad Zack 		}
125909d8e3a7SEldad Zack 	}
126009d8e3a7SEldad Zack 
126109d8e3a7SEldad Zack 	return 0;
126209d8e3a7SEldad Zack }
126309d8e3a7SEldad Zack 
126409d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */
126509d8e3a7SEldad Zack static int snd_c400_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
126609d8e3a7SEldad Zack {
126709d8e3a7SEldad Zack 	static const char name[] = "Effect Volume";
126809d8e3a7SEldad Zack 	const unsigned int id = 0x43;
126909d8e3a7SEldad Zack 	const int val_type = USB_MIXER_U8;
127009d8e3a7SEldad Zack 	const unsigned int control = 3;
127109d8e3a7SEldad Zack 	const unsigned int cmask = 0;
127209d8e3a7SEldad Zack 
127309d8e3a7SEldad Zack 	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
127409d8e3a7SEldad Zack 					name, snd_usb_mixer_vol_tlv);
127509d8e3a7SEldad Zack }
127609d8e3a7SEldad Zack 
127709d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */
127809d8e3a7SEldad Zack static int snd_c400_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
127909d8e3a7SEldad Zack {
128009d8e3a7SEldad Zack 	static const char name[] = "Effect Duration";
128109d8e3a7SEldad Zack 	const unsigned int id = 0x43;
128209d8e3a7SEldad Zack 	const int val_type = USB_MIXER_S16;
128309d8e3a7SEldad Zack 	const unsigned int control = 4;
128409d8e3a7SEldad Zack 	const unsigned int cmask = 0;
128509d8e3a7SEldad Zack 
128609d8e3a7SEldad Zack 	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
128709d8e3a7SEldad Zack 					name, snd_usb_mixer_vol_tlv);
128809d8e3a7SEldad Zack }
128909d8e3a7SEldad Zack 
129009d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */
129109d8e3a7SEldad Zack static int snd_c400_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
129209d8e3a7SEldad Zack {
129309d8e3a7SEldad Zack 	static const char name[] = "Effect Feedback Volume";
129409d8e3a7SEldad Zack 	const unsigned int id = 0x43;
129509d8e3a7SEldad Zack 	const int val_type = USB_MIXER_U8;
129609d8e3a7SEldad Zack 	const unsigned int control = 5;
129709d8e3a7SEldad Zack 	const unsigned int cmask = 0;
129809d8e3a7SEldad Zack 
129909d8e3a7SEldad Zack 	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
130009d8e3a7SEldad Zack 					name, NULL);
130109d8e3a7SEldad Zack }
130209d8e3a7SEldad Zack 
130309d8e3a7SEldad Zack static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer)
130409d8e3a7SEldad Zack {
130509d8e3a7SEldad Zack 	char name[64];
130609d8e3a7SEldad Zack 	unsigned int cmask;
130709d8e3a7SEldad Zack 	int chan, err;
1308e9a25e04SMatt Gruskin 	int num_outs = 0;
1309e9a25e04SMatt Gruskin 	int num_ins = 0;
131009d8e3a7SEldad Zack 
131109d8e3a7SEldad Zack 	const unsigned int id = 0x42;
131209d8e3a7SEldad Zack 	const int val_type = USB_MIXER_S16;
131309d8e3a7SEldad Zack 	const int control = 1;
131409d8e3a7SEldad Zack 
1315e9a25e04SMatt Gruskin 	switch (mixer->chip->usb_id) {
1316e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2030):
1317e9a25e04SMatt Gruskin 		num_outs = 6;
1318e9a25e04SMatt Gruskin 		num_ins = 4;
1319e9a25e04SMatt Gruskin 		break;
1320e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2031):
1321e9a25e04SMatt Gruskin 		num_outs = 8;
1322e9a25e04SMatt Gruskin 		num_ins = 6;
1323e9a25e04SMatt Gruskin 		break;
1324e9a25e04SMatt Gruskin 	}
1325e9a25e04SMatt Gruskin 
1326e9a25e04SMatt Gruskin 	for (chan = 0; chan < num_outs + num_ins; chan++) {
1327e9a25e04SMatt Gruskin 		if (chan < num_outs) {
132809d8e3a7SEldad Zack 			snprintf(name, sizeof(name),
132909d8e3a7SEldad Zack 				"Effect Send DOut%d",
133009d8e3a7SEldad Zack 				chan + 1);
133109d8e3a7SEldad Zack 		} else {
133209d8e3a7SEldad Zack 			snprintf(name, sizeof(name),
133309d8e3a7SEldad Zack 				"Effect Send AIn%d",
1334e9a25e04SMatt Gruskin 				chan - num_outs + 1);
133509d8e3a7SEldad Zack 		}
133609d8e3a7SEldad Zack 
133709d8e3a7SEldad Zack 		cmask = (chan == 0) ? 0 : 1 << (chan - 1);
133809d8e3a7SEldad Zack 		err = snd_create_std_mono_ctl(mixer, id, control,
133909d8e3a7SEldad Zack 						cmask, val_type, name,
134009d8e3a7SEldad Zack 						&snd_usb_mixer_vol_tlv);
134109d8e3a7SEldad Zack 		if (err < 0)
134209d8e3a7SEldad Zack 			return err;
134309d8e3a7SEldad Zack 	}
134409d8e3a7SEldad Zack 
134509d8e3a7SEldad Zack 	return 0;
134609d8e3a7SEldad Zack }
134709d8e3a7SEldad Zack 
134809d8e3a7SEldad Zack static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer)
134909d8e3a7SEldad Zack {
135009d8e3a7SEldad Zack 	char name[64];
135109d8e3a7SEldad Zack 	unsigned int cmask;
135209d8e3a7SEldad Zack 	int chan, err;
1353e9a25e04SMatt Gruskin 	int num_outs = 0;
1354e9a25e04SMatt Gruskin 	int offset = 0;
135509d8e3a7SEldad Zack 
135609d8e3a7SEldad Zack 	const unsigned int id = 0x40;
135709d8e3a7SEldad Zack 	const int val_type = USB_MIXER_S16;
135809d8e3a7SEldad Zack 	const int control = 1;
135909d8e3a7SEldad Zack 
1360e9a25e04SMatt Gruskin 	switch (mixer->chip->usb_id) {
1361e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2030):
1362e9a25e04SMatt Gruskin 		num_outs = 6;
1363e9a25e04SMatt Gruskin 		offset = 0x3c;
1364e9a25e04SMatt Gruskin 		/* { 0x3c, 0x43, 0x3e, 0x45, 0x40, 0x47 } */
1365e9a25e04SMatt Gruskin 		break;
1366e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2031):
1367e9a25e04SMatt Gruskin 		num_outs = 8;
1368e9a25e04SMatt Gruskin 		offset = 0x70;
1369e9a25e04SMatt Gruskin 		/* { 0x70, 0x79, 0x72, 0x7b, 0x74, 0x7d, 0x76, 0x7f } */
1370e9a25e04SMatt Gruskin 		break;
1371e9a25e04SMatt Gruskin 	}
1372e9a25e04SMatt Gruskin 
1373e9a25e04SMatt Gruskin 	for (chan = 0; chan < num_outs; chan++) {
137409d8e3a7SEldad Zack 		snprintf(name, sizeof(name),
137509d8e3a7SEldad Zack 			"Effect Return %d",
137609d8e3a7SEldad Zack 			chan + 1);
137709d8e3a7SEldad Zack 
1378e9a25e04SMatt Gruskin 		cmask = (chan == 0) ? 0 :
1379e9a25e04SMatt Gruskin 			1 << (chan + (chan % 2) * num_outs - 1);
138009d8e3a7SEldad Zack 		err = snd_create_std_mono_ctl_offset(mixer, id, control,
138109d8e3a7SEldad Zack 						cmask, val_type, offset, name,
138209d8e3a7SEldad Zack 						&snd_usb_mixer_vol_tlv);
138309d8e3a7SEldad Zack 		if (err < 0)
138409d8e3a7SEldad Zack 			return err;
138509d8e3a7SEldad Zack 	}
138609d8e3a7SEldad Zack 
138709d8e3a7SEldad Zack 	return 0;
138809d8e3a7SEldad Zack }
138909d8e3a7SEldad Zack 
139009d8e3a7SEldad Zack static int snd_c400_create_mixer(struct usb_mixer_interface *mixer)
139109d8e3a7SEldad Zack {
139209d8e3a7SEldad Zack 	int err;
139309d8e3a7SEldad Zack 
139409d8e3a7SEldad Zack 	err = snd_c400_create_vol_ctls(mixer);
139509d8e3a7SEldad Zack 	if (err < 0)
139609d8e3a7SEldad Zack 		return err;
139709d8e3a7SEldad Zack 
139809d8e3a7SEldad Zack 	err = snd_c400_create_effect_vol_ctls(mixer);
139909d8e3a7SEldad Zack 	if (err < 0)
140009d8e3a7SEldad Zack 		return err;
140109d8e3a7SEldad Zack 
140209d8e3a7SEldad Zack 	err = snd_c400_create_effect_ret_vol_ctls(mixer);
140309d8e3a7SEldad Zack 	if (err < 0)
140409d8e3a7SEldad Zack 		return err;
140509d8e3a7SEldad Zack 
140609d8e3a7SEldad Zack 	err = snd_ftu_create_effect_switch(mixer, 2, 0x43);
140709d8e3a7SEldad Zack 	if (err < 0)
140809d8e3a7SEldad Zack 		return err;
140909d8e3a7SEldad Zack 
141009d8e3a7SEldad Zack 	err = snd_c400_create_effect_volume_ctl(mixer);
141109d8e3a7SEldad Zack 	if (err < 0)
141209d8e3a7SEldad Zack 		return err;
141309d8e3a7SEldad Zack 
141409d8e3a7SEldad Zack 	err = snd_c400_create_effect_duration_ctl(mixer);
141509d8e3a7SEldad Zack 	if (err < 0)
141609d8e3a7SEldad Zack 		return err;
141709d8e3a7SEldad Zack 
141809d8e3a7SEldad Zack 	err = snd_c400_create_effect_feedback_ctl(mixer);
141909d8e3a7SEldad Zack 	if (err < 0)
142009d8e3a7SEldad Zack 		return err;
142109d8e3a7SEldad Zack 
142209d8e3a7SEldad Zack 	return 0;
142309d8e3a7SEldad Zack }
142409d8e3a7SEldad Zack 
1425b71dad18SMark Hills /*
1426b71dad18SMark Hills  * The mixer units for Ebox-44 are corrupt, and even where they
1427b71dad18SMark Hills  * are valid they presents mono controls as L and R channels of
1428b71dad18SMark Hills  * stereo. So we provide a good mixer here.
1429b71dad18SMark Hills  */
1430e8e7da23SSachin Kamat static struct std_mono_table ebox44_table[] = {
1431989b0138SMark Hills 	{
1432989b0138SMark Hills 		.unitid = 4,
1433989b0138SMark Hills 		.control = 1,
1434989b0138SMark Hills 		.cmask = 0x0,
1435989b0138SMark Hills 		.val_type = USB_MIXER_INV_BOOLEAN,
1436989b0138SMark Hills 		.name = "Headphone Playback Switch"
1437989b0138SMark Hills 	},
1438989b0138SMark Hills 	{
1439989b0138SMark Hills 		.unitid = 4,
1440989b0138SMark Hills 		.control = 2,
1441989b0138SMark Hills 		.cmask = 0x1,
1442989b0138SMark Hills 		.val_type = USB_MIXER_S16,
1443989b0138SMark Hills 		.name = "Headphone A Mix Playback Volume"
1444989b0138SMark Hills 	},
1445989b0138SMark Hills 	{
1446989b0138SMark Hills 		.unitid = 4,
1447989b0138SMark Hills 		.control = 2,
1448989b0138SMark Hills 		.cmask = 0x2,
1449989b0138SMark Hills 		.val_type = USB_MIXER_S16,
1450989b0138SMark Hills 		.name = "Headphone B Mix Playback Volume"
1451989b0138SMark Hills 	},
1452b71dad18SMark Hills 
1453989b0138SMark Hills 	{
1454989b0138SMark Hills 		.unitid = 7,
1455989b0138SMark Hills 		.control = 1,
1456989b0138SMark Hills 		.cmask = 0x0,
1457989b0138SMark Hills 		.val_type = USB_MIXER_INV_BOOLEAN,
1458989b0138SMark Hills 		.name = "Output Playback Switch"
1459989b0138SMark Hills 	},
1460989b0138SMark Hills 	{
1461989b0138SMark Hills 		.unitid = 7,
1462989b0138SMark Hills 		.control = 2,
1463989b0138SMark Hills 		.cmask = 0x1,
1464989b0138SMark Hills 		.val_type = USB_MIXER_S16,
1465989b0138SMark Hills 		.name = "Output A Playback Volume"
1466989b0138SMark Hills 	},
1467989b0138SMark Hills 	{
1468989b0138SMark Hills 		.unitid = 7,
1469989b0138SMark Hills 		.control = 2,
1470989b0138SMark Hills 		.cmask = 0x2,
1471989b0138SMark Hills 		.val_type = USB_MIXER_S16,
1472989b0138SMark Hills 		.name = "Output B Playback Volume"
1473989b0138SMark Hills 	},
1474b71dad18SMark Hills 
1475989b0138SMark Hills 	{
1476989b0138SMark Hills 		.unitid = 10,
1477989b0138SMark Hills 		.control = 1,
1478989b0138SMark Hills 		.cmask = 0x0,
1479989b0138SMark Hills 		.val_type = USB_MIXER_INV_BOOLEAN,
1480989b0138SMark Hills 		.name = "Input Capture Switch"
1481989b0138SMark Hills 	},
1482989b0138SMark Hills 	{
1483989b0138SMark Hills 		.unitid = 10,
1484989b0138SMark Hills 		.control = 2,
1485989b0138SMark Hills 		.cmask = 0x1,
1486989b0138SMark Hills 		.val_type = USB_MIXER_S16,
1487989b0138SMark Hills 		.name = "Input A Capture Volume"
1488989b0138SMark Hills 	},
1489989b0138SMark Hills 	{
1490989b0138SMark Hills 		.unitid = 10,
1491989b0138SMark Hills 		.control = 2,
1492989b0138SMark Hills 		.cmask = 0x2,
1493989b0138SMark Hills 		.val_type = USB_MIXER_S16,
1494989b0138SMark Hills 		.name = "Input B Capture Volume"
1495989b0138SMark Hills 	},
1496b71dad18SMark Hills 
1497b71dad18SMark Hills 	{}
1498b71dad18SMark Hills };
1499b71dad18SMark Hills 
1500066624c6SPrzemek Rudy /* Audio Advantage Micro II findings:
1501066624c6SPrzemek Rudy  *
1502066624c6SPrzemek Rudy  * Mapping spdif AES bits to vendor register.bit:
1503066624c6SPrzemek Rudy  * AES0: [0 0 0 0 2.3 2.2 2.1 2.0] - default 0x00
1504066624c6SPrzemek Rudy  * AES1: [3.3 3.2.3.1.3.0 2.7 2.6 2.5 2.4] - default: 0x01
1505066624c6SPrzemek Rudy  * AES2: [0 0 0 0 0 0 0 0]
1506066624c6SPrzemek Rudy  * AES3: [0 0 0 0 0 0 x 0] - 'x' bit is set basing on standard usb request
1507066624c6SPrzemek Rudy  *                           (UAC_EP_CS_ATTR_SAMPLE_RATE) for Audio Devices
1508066624c6SPrzemek Rudy  *
1509066624c6SPrzemek Rudy  * power on values:
1510066624c6SPrzemek Rudy  * r2: 0x10
1511066624c6SPrzemek Rudy  * r3: 0x20 (b7 is zeroed just before playback (except IEC61937) and set
1512066624c6SPrzemek Rudy  *           just after it to 0xa0, presumably it disables/mutes some analog
1513066624c6SPrzemek Rudy  *           parts when there is no audio.)
1514066624c6SPrzemek Rudy  * r9: 0x28
1515066624c6SPrzemek Rudy  *
1516066624c6SPrzemek Rudy  * Optical transmitter on/off:
1517066624c6SPrzemek Rudy  * vendor register.bit: 9.1
1518066624c6SPrzemek Rudy  * 0 - on (0x28 register value)
1519066624c6SPrzemek Rudy  * 1 - off (0x2a register value)
1520066624c6SPrzemek Rudy  *
1521066624c6SPrzemek Rudy  */
1522066624c6SPrzemek Rudy static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol,
1523066624c6SPrzemek Rudy 	struct snd_ctl_elem_info *uinfo)
1524066624c6SPrzemek Rudy {
1525066624c6SPrzemek Rudy 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1526066624c6SPrzemek Rudy 	uinfo->count = 1;
1527066624c6SPrzemek Rudy 	return 0;
1528066624c6SPrzemek Rudy }
1529066624c6SPrzemek Rudy 
1530066624c6SPrzemek Rudy static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
1531066624c6SPrzemek Rudy 	struct snd_ctl_elem_value *ucontrol)
1532066624c6SPrzemek Rudy {
1533066624c6SPrzemek Rudy 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
1534066624c6SPrzemek Rudy 	int err;
1535066624c6SPrzemek Rudy 	struct usb_interface *iface;
1536066624c6SPrzemek Rudy 	struct usb_host_interface *alts;
1537066624c6SPrzemek Rudy 	unsigned int ep;
1538066624c6SPrzemek Rudy 	unsigned char data[3];
1539066624c6SPrzemek Rudy 	int rate;
1540066624c6SPrzemek Rudy 
1541066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff;
1542066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff;
1543066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[2] = 0x00;
1544066624c6SPrzemek Rudy 
1545066624c6SPrzemek Rudy 	/* use known values for that card: interface#1 altsetting#1 */
1546066624c6SPrzemek Rudy 	iface = usb_ifnum_to_if(mixer->chip->dev, 1);
1547066624c6SPrzemek Rudy 	alts = &iface->altsetting[1];
1548066624c6SPrzemek Rudy 	ep = get_endpoint(alts, 0)->bEndpointAddress;
1549066624c6SPrzemek Rudy 
1550066624c6SPrzemek Rudy 	err = snd_usb_ctl_msg(mixer->chip->dev,
1551066624c6SPrzemek Rudy 			usb_rcvctrlpipe(mixer->chip->dev, 0),
1552066624c6SPrzemek Rudy 			UAC_GET_CUR,
1553066624c6SPrzemek Rudy 			USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
1554066624c6SPrzemek Rudy 			UAC_EP_CS_ATTR_SAMPLE_RATE << 8,
1555066624c6SPrzemek Rudy 			ep,
1556066624c6SPrzemek Rudy 			data,
1557066624c6SPrzemek Rudy 			sizeof(data));
1558066624c6SPrzemek Rudy 	if (err < 0)
1559066624c6SPrzemek Rudy 		goto end;
1560066624c6SPrzemek Rudy 
1561066624c6SPrzemek Rudy 	rate = data[0] | (data[1] << 8) | (data[2] << 16);
1562066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[3] = (rate == 48000) ?
1563066624c6SPrzemek Rudy 			IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100;
1564066624c6SPrzemek Rudy 
1565066624c6SPrzemek Rudy 	err = 0;
1566066624c6SPrzemek Rudy end:
1567066624c6SPrzemek Rudy 	return err;
1568066624c6SPrzemek Rudy }
1569066624c6SPrzemek Rudy 
1570066624c6SPrzemek Rudy static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
1571066624c6SPrzemek Rudy 	struct snd_ctl_elem_value *ucontrol)
1572066624c6SPrzemek Rudy {
1573066624c6SPrzemek Rudy 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
1574066624c6SPrzemek Rudy 	int err;
1575066624c6SPrzemek Rudy 	u8 reg;
1576066624c6SPrzemek Rudy 	unsigned long priv_backup = kcontrol->private_value;
1577066624c6SPrzemek Rudy 
1578066624c6SPrzemek Rudy 	reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) |
1579066624c6SPrzemek Rudy 			(ucontrol->value.iec958.status[0] & 0x0f);
1580066624c6SPrzemek Rudy 	err = snd_usb_ctl_msg(mixer->chip->dev,
1581066624c6SPrzemek Rudy 			usb_sndctrlpipe(mixer->chip->dev, 0),
1582066624c6SPrzemek Rudy 			UAC_SET_CUR,
1583066624c6SPrzemek Rudy 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
1584066624c6SPrzemek Rudy 			reg,
1585066624c6SPrzemek Rudy 			2,
1586066624c6SPrzemek Rudy 			NULL,
1587066624c6SPrzemek Rudy 			0);
1588066624c6SPrzemek Rudy 	if (err < 0)
1589066624c6SPrzemek Rudy 		goto end;
1590066624c6SPrzemek Rudy 
1591066624c6SPrzemek Rudy 	kcontrol->private_value &= 0xfffff0f0;
1592066624c6SPrzemek Rudy 	kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8;
1593066624c6SPrzemek Rudy 	kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f);
1594066624c6SPrzemek Rudy 
1595066624c6SPrzemek Rudy 	reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ?
1596066624c6SPrzemek Rudy 			0xa0 : 0x20;
1597066624c6SPrzemek Rudy 	reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f;
1598066624c6SPrzemek Rudy 	err = snd_usb_ctl_msg(mixer->chip->dev,
1599066624c6SPrzemek Rudy 			usb_sndctrlpipe(mixer->chip->dev, 0),
1600066624c6SPrzemek Rudy 			UAC_SET_CUR,
1601066624c6SPrzemek Rudy 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
1602066624c6SPrzemek Rudy 			reg,
1603066624c6SPrzemek Rudy 			3,
1604066624c6SPrzemek Rudy 			NULL,
1605066624c6SPrzemek Rudy 			0);
1606066624c6SPrzemek Rudy 	if (err < 0)
1607066624c6SPrzemek Rudy 		goto end;
1608066624c6SPrzemek Rudy 
1609066624c6SPrzemek Rudy 	kcontrol->private_value &= 0xffff0fff;
1610066624c6SPrzemek Rudy 	kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8;
1611066624c6SPrzemek Rudy 
1612066624c6SPrzemek Rudy 	/* The frequency bits in AES3 cannot be set via register access. */
1613066624c6SPrzemek Rudy 
1614066624c6SPrzemek Rudy 	/* Silently ignore any bits from the request that cannot be set. */
1615066624c6SPrzemek Rudy 
1616066624c6SPrzemek Rudy 	err = (priv_backup != kcontrol->private_value);
1617066624c6SPrzemek Rudy end:
1618066624c6SPrzemek Rudy 	return err;
1619066624c6SPrzemek Rudy }
1620066624c6SPrzemek Rudy 
1621066624c6SPrzemek Rudy static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol,
1622066624c6SPrzemek Rudy 	struct snd_ctl_elem_value *ucontrol)
1623066624c6SPrzemek Rudy {
1624066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[0] = 0x0f;
1625066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[1] = 0xff;
1626066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[2] = 0x00;
1627066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[3] = 0x00;
1628066624c6SPrzemek Rudy 
1629066624c6SPrzemek Rudy 	return 0;
1630066624c6SPrzemek Rudy }
1631066624c6SPrzemek Rudy 
1632066624c6SPrzemek Rudy static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol,
1633066624c6SPrzemek Rudy 	struct snd_ctl_elem_value *ucontrol)
1634066624c6SPrzemek Rudy {
1635066624c6SPrzemek Rudy 	ucontrol->value.integer.value[0] = !(kcontrol->private_value & 0x02);
1636066624c6SPrzemek Rudy 
1637066624c6SPrzemek Rudy 	return 0;
1638066624c6SPrzemek Rudy }
1639066624c6SPrzemek Rudy 
1640066624c6SPrzemek Rudy static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
1641066624c6SPrzemek Rudy 	struct snd_ctl_elem_value *ucontrol)
1642066624c6SPrzemek Rudy {
1643066624c6SPrzemek Rudy 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
1644066624c6SPrzemek Rudy 	int err;
1645066624c6SPrzemek Rudy 	u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
1646066624c6SPrzemek Rudy 
1647066624c6SPrzemek Rudy 	err = snd_usb_ctl_msg(mixer->chip->dev,
1648066624c6SPrzemek Rudy 			usb_sndctrlpipe(mixer->chip->dev, 0),
1649066624c6SPrzemek Rudy 			UAC_SET_CUR,
1650066624c6SPrzemek Rudy 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
1651066624c6SPrzemek Rudy 			reg,
1652066624c6SPrzemek Rudy 			9,
1653066624c6SPrzemek Rudy 			NULL,
1654066624c6SPrzemek Rudy 			0);
1655066624c6SPrzemek Rudy 
1656066624c6SPrzemek Rudy 	if (!err) {
1657066624c6SPrzemek Rudy 		err = (reg != (kcontrol->private_value & 0x0ff));
1658066624c6SPrzemek Rudy 		if (err)
1659066624c6SPrzemek Rudy 			kcontrol->private_value = reg;
1660066624c6SPrzemek Rudy 	}
1661066624c6SPrzemek Rudy 
1662066624c6SPrzemek Rudy 	return err;
1663066624c6SPrzemek Rudy }
1664066624c6SPrzemek Rudy 
1665066624c6SPrzemek Rudy static struct snd_kcontrol_new snd_microii_mixer_spdif[] = {
1666066624c6SPrzemek Rudy 	{
1667066624c6SPrzemek Rudy 		.iface =    SNDRV_CTL_ELEM_IFACE_PCM,
1668066624c6SPrzemek Rudy 		.name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
1669066624c6SPrzemek Rudy 		.info =     snd_microii_spdif_info,
1670066624c6SPrzemek Rudy 		.get =      snd_microii_spdif_default_get,
1671066624c6SPrzemek Rudy 		.put =      snd_microii_spdif_default_put,
1672066624c6SPrzemek Rudy 		.private_value = 0x00000100UL,/* reset value */
1673066624c6SPrzemek Rudy 	},
1674066624c6SPrzemek Rudy 	{
1675066624c6SPrzemek Rudy 		.access =   SNDRV_CTL_ELEM_ACCESS_READ,
1676066624c6SPrzemek Rudy 		.iface =    SNDRV_CTL_ELEM_IFACE_PCM,
1677066624c6SPrzemek Rudy 		.name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
1678066624c6SPrzemek Rudy 		.info =     snd_microii_spdif_info,
1679066624c6SPrzemek Rudy 		.get =      snd_microii_spdif_mask_get,
1680066624c6SPrzemek Rudy 	},
1681066624c6SPrzemek Rudy 	{
1682066624c6SPrzemek Rudy 		.iface =    SNDRV_CTL_ELEM_IFACE_MIXER,
1683066624c6SPrzemek Rudy 		.name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
1684066624c6SPrzemek Rudy 		.info =     snd_ctl_boolean_mono_info,
1685066624c6SPrzemek Rudy 		.get =      snd_microii_spdif_switch_get,
1686066624c6SPrzemek Rudy 		.put =      snd_microii_spdif_switch_put,
1687066624c6SPrzemek Rudy 		.private_value = 0x00000028UL,/* reset value */
1688066624c6SPrzemek Rudy 	}
1689066624c6SPrzemek Rudy };
1690066624c6SPrzemek Rudy 
1691066624c6SPrzemek Rudy static int snd_microii_controls_create(struct usb_mixer_interface *mixer)
1692066624c6SPrzemek Rudy {
1693066624c6SPrzemek Rudy 	int err, i;
1694066624c6SPrzemek Rudy 
1695066624c6SPrzemek Rudy 	for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) {
1696066624c6SPrzemek Rudy 		err = snd_ctl_add(mixer->chip->card,
1697066624c6SPrzemek Rudy 			snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer));
1698066624c6SPrzemek Rudy 		if (err < 0)
1699066624c6SPrzemek Rudy 			return err;
1700066624c6SPrzemek Rudy 	}
1701066624c6SPrzemek Rudy 
170218e4753fSMikulas Patocka 	return 0;
1703066624c6SPrzemek Rudy }
1704066624c6SPrzemek Rudy 
17057b1eda22SDaniel Mack int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
17067b1eda22SDaniel Mack {
17073347b26cSDaniel Mack 	int err = 0;
17087b1eda22SDaniel Mack 	struct snd_info_entry *entry;
17097b1eda22SDaniel Mack 
17107b1eda22SDaniel Mack 	if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0)
17117b1eda22SDaniel Mack 		return err;
17127b1eda22SDaniel Mack 
17133347b26cSDaniel Mack 	switch (mixer->chip->usb_id) {
17143347b26cSDaniel Mack 	case USB_ID(0x041e, 0x3020):
17153347b26cSDaniel Mack 	case USB_ID(0x041e, 0x3040):
17163347b26cSDaniel Mack 	case USB_ID(0x041e, 0x3042):
17177cdd8d73SMathieu Bouffard 	case USB_ID(0x041e, 0x30df):
17183347b26cSDaniel Mack 	case USB_ID(0x041e, 0x3048):
17193347b26cSDaniel Mack 		err = snd_audigy2nx_controls_create(mixer);
17203347b26cSDaniel Mack 		if (err < 0)
17213347b26cSDaniel Mack 			break;
17227b1eda22SDaniel Mack 		if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry))
17237b1eda22SDaniel Mack 			snd_info_set_text_ops(entry, mixer,
17247b1eda22SDaniel Mack 					      snd_audigy2nx_proc_read);
17253347b26cSDaniel Mack 		break;
17267b1eda22SDaniel Mack 
172744832a71SVasily Khoruzhick 	/* EMU0204 */
172844832a71SVasily Khoruzhick 	case USB_ID(0x041e, 0x3f19):
172944832a71SVasily Khoruzhick 		err = snd_emu0204_controls_create(mixer);
173044832a71SVasily Khoruzhick 		if (err < 0)
173144832a71SVasily Khoruzhick 			break;
173244832a71SVasily Khoruzhick 		break;
173344832a71SVasily Khoruzhick 
173409d8e3a7SEldad Zack 	case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
1735e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C400 */
173609d8e3a7SEldad Zack 		err = snd_c400_create_mixer(mixer);
173709d8e3a7SEldad Zack 		break;
173809d8e3a7SEldad Zack 
1739d5a0bf6cSDaniel Mack 	case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
1740d5a0bf6cSDaniel Mack 	case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
1741cfe8f97cSFelix Homann 		err = snd_ftu_create_mixer(mixer);
1742d5a0bf6cSDaniel Mack 		break;
1743d5a0bf6cSDaniel Mack 
17441d31affbSDenis Washington 	case USB_ID(0x0b05, 0x1739): /* ASUS Xonar U1 */
17451d31affbSDenis Washington 	case USB_ID(0x0b05, 0x1743): /* ASUS Xonar U1 (2) */
17461d31affbSDenis Washington 	case USB_ID(0x0b05, 0x17a0): /* ASUS Xonar U3 */
17477b1eda22SDaniel Mack 		err = snd_xonar_u1_controls_create(mixer);
17483347b26cSDaniel Mack 		break;
17497b1eda22SDaniel Mack 
1750066624c6SPrzemek Rudy 	case USB_ID(0x0d8c, 0x0103): /* Audio Advantage Micro II */
1751066624c6SPrzemek Rudy 		err = snd_microii_controls_create(mixer);
1752066624c6SPrzemek Rudy 		break;
1753066624c6SPrzemek Rudy 
1754d497a82fSDamien Zammit 	case USB_ID(0x0dba, 0x1000): /* Digidesign Mbox 1 */
1755d497a82fSDamien Zammit 		err = snd_mbox1_create_sync_switch(mixer);
1756d497a82fSDamien Zammit 		break;
1757d497a82fSDamien Zammit 
17583347b26cSDaniel Mack 	case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */
175954a8c500SDaniel Mack 		err = snd_nativeinstruments_create_mixer(mixer,
176054a8c500SDaniel Mack 				snd_nativeinstruments_ta6_mixers,
176154a8c500SDaniel Mack 				ARRAY_SIZE(snd_nativeinstruments_ta6_mixers));
17623347b26cSDaniel Mack 		break;
176354a8c500SDaniel Mack 
17643347b26cSDaniel Mack 	case USB_ID(0x17cc, 0x1021): /* Traktor Audio 10 */
176554a8c500SDaniel Mack 		err = snd_nativeinstruments_create_mixer(mixer,
176654a8c500SDaniel Mack 				snd_nativeinstruments_ta10_mixers,
176754a8c500SDaniel Mack 				ARRAY_SIZE(snd_nativeinstruments_ta10_mixers));
17683347b26cSDaniel Mack 		break;
17697536c301SMark Hills 
17707536c301SMark Hills 	case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */
1771b71dad18SMark Hills 		/* detection is disabled in mixer_maps.c */
1772b71dad18SMark Hills 		err = snd_create_std_mono_table(mixer, ebox44_table);
17737536c301SMark Hills 		break;
177476b188c4SChris J Arges 
177576b188c4SChris J Arges 	case USB_ID(0x1235, 0x8012): /* Focusrite Scarlett 6i6 */
177676b188c4SChris J Arges 	case USB_ID(0x1235, 0x8002): /* Focusrite Scarlett 8i6 */
177776b188c4SChris J Arges 	case USB_ID(0x1235, 0x8004): /* Focusrite Scarlett 18i6 */
177876b188c4SChris J Arges 	case USB_ID(0x1235, 0x8014): /* Focusrite Scarlett 18i8 */
177976b188c4SChris J Arges 	case USB_ID(0x1235, 0x800c): /* Focusrite Scarlett 18i20 */
178076b188c4SChris J Arges 		err = snd_scarlett_controls_create(mixer);
178176b188c4SChris J Arges 		break;
178254a8c500SDaniel Mack 	}
178354a8c500SDaniel Mack 
17843347b26cSDaniel Mack 	return err;
17857b1eda22SDaniel Mack }
17867b1eda22SDaniel Mack 
17877b1eda22SDaniel Mack void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
17887b1eda22SDaniel Mack 				    int unitid)
17897b1eda22SDaniel Mack {
17907b1eda22SDaniel Mack 	if (!mixer->rc_cfg)
17917b1eda22SDaniel Mack 		return;
17927b1eda22SDaniel Mack 	/* unit ids specific to Extigy/Audigy 2 NX: */
17937b1eda22SDaniel Mack 	switch (unitid) {
17947b1eda22SDaniel Mack 	case 0: /* remote control */
17957b1eda22SDaniel Mack 		mixer->rc_urb->dev = mixer->chip->dev;
17967b1eda22SDaniel Mack 		usb_submit_urb(mixer->rc_urb, GFP_ATOMIC);
17977b1eda22SDaniel Mack 		break;
17987b1eda22SDaniel Mack 	case 4: /* digital in jack */
17997b1eda22SDaniel Mack 	case 7: /* line in jacks */
18007b1eda22SDaniel Mack 	case 19: /* speaker out jacks */
18017b1eda22SDaniel Mack 	case 20: /* headphones out jack */
18027b1eda22SDaniel Mack 		break;
18037b1eda22SDaniel Mack 	/* live24ext: 4 = line-in jack */
18047b1eda22SDaniel Mack 	case 3:	/* hp-out jack (may actuate Mute) */
18057b1eda22SDaniel Mack 		if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
18067b1eda22SDaniel Mack 		    mixer->chip->usb_id == USB_ID(0x041e, 0x3048))
18077b1eda22SDaniel Mack 			snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id);
18087b1eda22SDaniel Mack 		break;
18097b1eda22SDaniel Mack 	default:
18100ba41d91STakashi Iwai 		usb_audio_dbg(mixer->chip, "memory change in unknown unit %d\n", unitid);
18117b1eda22SDaniel Mack 		break;
18127b1eda22SDaniel Mack 	}
18137b1eda22SDaniel Mack }
18147b1eda22SDaniel Mack 
1815