xref: /openbmc/linux/sound/usb/mixer_quirks.c (revision 5f503ee9)
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 	struct usb_mixer_elem_info *cval;
738a4d1d39SFelix Homann 	struct snd_kcontrol *kctl;
748a4d1d39SFelix Homann 
758a4d1d39SFelix Homann 	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
768a4d1d39SFelix Homann 	if (!cval)
778a4d1d39SFelix Homann 		return -ENOMEM;
788a4d1d39SFelix Homann 
793360b84bSTakashi Iwai 	snd_usb_mixer_elem_init_std(&cval->head, mixer, unitid);
808a4d1d39SFelix Homann 	cval->val_type = val_type;
818a4d1d39SFelix Homann 	cval->channels = 1;
828a4d1d39SFelix Homann 	cval->control = control;
838a4d1d39SFelix Homann 	cval->cmask = cmask;
849f814105SEldad Zack 	cval->idx_off = idx_off;
858a4d1d39SFelix Homann 
867df4a691SMark Hills 	/* get_min_max() is called only for integer volumes later,
877df4a691SMark Hills 	 * so provide a short-cut for booleans */
888a4d1d39SFelix Homann 	cval->min = 0;
898a4d1d39SFelix Homann 	cval->max = 1;
908a4d1d39SFelix Homann 	cval->res = 0;
918a4d1d39SFelix Homann 	cval->dBmin = 0;
928a4d1d39SFelix Homann 	cval->dBmax = 0;
938a4d1d39SFelix Homann 
948a4d1d39SFelix Homann 	/* Create control */
958a4d1d39SFelix Homann 	kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
968a4d1d39SFelix Homann 	if (!kctl) {
978a4d1d39SFelix Homann 		kfree(cval);
988a4d1d39SFelix Homann 		return -ENOMEM;
998a4d1d39SFelix Homann 	}
1008a4d1d39SFelix Homann 
1018a4d1d39SFelix Homann 	/* Set name */
1028a4d1d39SFelix Homann 	snprintf(kctl->id.name, sizeof(kctl->id.name), name);
103eef90451SChris J Arges 	kctl->private_free = snd_usb_mixer_elem_free;
1048a4d1d39SFelix Homann 
1058a4d1d39SFelix Homann 	/* set TLV */
1068a4d1d39SFelix Homann 	if (tlv_callback) {
1078a4d1d39SFelix Homann 		kctl->tlv.c = tlv_callback;
1088a4d1d39SFelix Homann 		kctl->vd[0].access |=
1098a4d1d39SFelix Homann 			SNDRV_CTL_ELEM_ACCESS_TLV_READ |
1108a4d1d39SFelix Homann 			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
1118a4d1d39SFelix Homann 	}
1128a4d1d39SFelix Homann 	/* Add control to mixer */
1133360b84bSTakashi Iwai 	return snd_usb_mixer_add_control(&cval->head, kctl);
1148a4d1d39SFelix Homann }
1158a4d1d39SFelix Homann 
1169f814105SEldad Zack static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
1179f814105SEldad Zack 				unsigned int unitid,
1189f814105SEldad Zack 				unsigned int control,
1199f814105SEldad Zack 				unsigned int cmask,
1209f814105SEldad Zack 				int val_type,
1219f814105SEldad Zack 				const char *name,
1229f814105SEldad Zack 				snd_kcontrol_tlv_rw_t *tlv_callback)
1239f814105SEldad Zack {
1249f814105SEldad Zack 	return snd_create_std_mono_ctl_offset(mixer, unitid, control, cmask,
1259f814105SEldad Zack 		val_type, 0 /* Offset */, name, tlv_callback);
1269f814105SEldad Zack }
1279f814105SEldad Zack 
1287b1eda22SDaniel Mack /*
129b71dad18SMark Hills  * Create a set of standard UAC controls from a table
130b71dad18SMark Hills  */
131b71dad18SMark Hills static int snd_create_std_mono_table(struct usb_mixer_interface *mixer,
132b71dad18SMark Hills 				struct std_mono_table *t)
133b71dad18SMark Hills {
134b71dad18SMark Hills 	int err;
135b71dad18SMark Hills 
136b71dad18SMark Hills 	while (t->name != NULL) {
137b71dad18SMark Hills 		err = snd_create_std_mono_ctl(mixer, t->unitid, t->control,
138b71dad18SMark Hills 				t->cmask, t->val_type, t->name, t->tlv_callback);
139b71dad18SMark Hills 		if (err < 0)
140b71dad18SMark Hills 			return err;
141b71dad18SMark Hills 		t++;
142b71dad18SMark Hills 	}
143b71dad18SMark Hills 
144b71dad18SMark Hills 	return 0;
145b71dad18SMark Hills }
146b71dad18SMark Hills 
1479cf3689bSTakashi Iwai static int add_single_ctl_with_resume(struct usb_mixer_interface *mixer,
1489cf3689bSTakashi Iwai 				      int id,
1499cf3689bSTakashi Iwai 				      usb_mixer_elem_resume_func_t resume,
1509cf3689bSTakashi Iwai 				      const struct snd_kcontrol_new *knew,
1519cf3689bSTakashi Iwai 				      struct usb_mixer_elem_list **listp)
1529cf3689bSTakashi Iwai {
1539cf3689bSTakashi Iwai 	struct usb_mixer_elem_list *list;
1549cf3689bSTakashi Iwai 	struct snd_kcontrol *kctl;
1559cf3689bSTakashi Iwai 
1569cf3689bSTakashi Iwai 	list = kzalloc(sizeof(*list), GFP_KERNEL);
1579cf3689bSTakashi Iwai 	if (!list)
1589cf3689bSTakashi Iwai 		return -ENOMEM;
1599cf3689bSTakashi Iwai 	if (listp)
1609cf3689bSTakashi Iwai 		*listp = list;
1619cf3689bSTakashi Iwai 	list->mixer = mixer;
1629cf3689bSTakashi Iwai 	list->id = id;
1639cf3689bSTakashi Iwai 	list->resume = resume;
1649cf3689bSTakashi Iwai 	kctl = snd_ctl_new1(knew, list);
1659cf3689bSTakashi Iwai 	if (!kctl) {
1669cf3689bSTakashi Iwai 		kfree(list);
1679cf3689bSTakashi Iwai 		return -ENOMEM;
1689cf3689bSTakashi Iwai 	}
1699cf3689bSTakashi Iwai 	kctl->private_free = snd_usb_mixer_elem_free;
1709cf3689bSTakashi Iwai 	return snd_usb_mixer_add_control(list, kctl);
1719cf3689bSTakashi Iwai }
1729cf3689bSTakashi Iwai 
173b71dad18SMark Hills /*
1747b1eda22SDaniel Mack  * Sound Blaster remote control configuration
1757b1eda22SDaniel Mack  *
1767b1eda22SDaniel Mack  * format of remote control data:
1777b1eda22SDaniel Mack  * Extigy:       xx 00
1787b1eda22SDaniel Mack  * Audigy 2 NX:  06 80 xx 00 00 00
1797b1eda22SDaniel Mack  * Live! 24-bit: 06 80 xx yy 22 83
1807b1eda22SDaniel Mack  */
1817b1eda22SDaniel Mack static const struct rc_config {
1827b1eda22SDaniel Mack 	u32 usb_id;
1837b1eda22SDaniel Mack 	u8  offset;
1847b1eda22SDaniel Mack 	u8  length;
1857b1eda22SDaniel Mack 	u8  packet_length;
1867b1eda22SDaniel Mack 	u8  min_packet_length; /* minimum accepted length of the URB result */
1877b1eda22SDaniel Mack 	u8  mute_mixer_id;
1887b1eda22SDaniel Mack 	u32 mute_code;
1897b1eda22SDaniel Mack } rc_configs[] = {
1907b1eda22SDaniel Mack 	{ USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */
1917b1eda22SDaniel Mack 	{ USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */
1927b1eda22SDaniel Mack 	{ USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
193ca8dc34eSMandar Joshi 	{ USB_ID(0x041e, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 */
1947cdd8d73SMathieu Bouffard 	{ USB_ID(0x041e, 0x30df), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 Pro */
1957b1eda22SDaniel Mack 	{ USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
1967b1eda22SDaniel Mack };
1977b1eda22SDaniel Mack 
1987b1eda22SDaniel Mack static void snd_usb_soundblaster_remote_complete(struct urb *urb)
1997b1eda22SDaniel Mack {
2007b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = urb->context;
2017b1eda22SDaniel Mack 	const struct rc_config *rc = mixer->rc_cfg;
2027b1eda22SDaniel Mack 	u32 code;
2037b1eda22SDaniel Mack 
2047b1eda22SDaniel Mack 	if (urb->status < 0 || urb->actual_length < rc->min_packet_length)
2057b1eda22SDaniel Mack 		return;
2067b1eda22SDaniel Mack 
2077b1eda22SDaniel Mack 	code = mixer->rc_buffer[rc->offset];
2087b1eda22SDaniel Mack 	if (rc->length == 2)
2097b1eda22SDaniel Mack 		code |= mixer->rc_buffer[rc->offset + 1] << 8;
2107b1eda22SDaniel Mack 
2117b1eda22SDaniel Mack 	/* the Mute button actually changes the mixer control */
2127b1eda22SDaniel Mack 	if (code == rc->mute_code)
2137b1eda22SDaniel Mack 		snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id);
2147b1eda22SDaniel Mack 	mixer->rc_code = code;
2157b1eda22SDaniel Mack 	wmb();
2167b1eda22SDaniel Mack 	wake_up(&mixer->rc_waitq);
2177b1eda22SDaniel Mack }
2187b1eda22SDaniel Mack 
2197b1eda22SDaniel Mack static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf,
2207b1eda22SDaniel Mack 				     long count, loff_t *offset)
2217b1eda22SDaniel Mack {
2227b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = hw->private_data;
2237b1eda22SDaniel Mack 	int err;
2247b1eda22SDaniel Mack 	u32 rc_code;
2257b1eda22SDaniel Mack 
2267b1eda22SDaniel Mack 	if (count != 1 && count != 4)
2277b1eda22SDaniel Mack 		return -EINVAL;
2287b1eda22SDaniel Mack 	err = wait_event_interruptible(mixer->rc_waitq,
2297b1eda22SDaniel Mack 				       (rc_code = xchg(&mixer->rc_code, 0)) != 0);
2307b1eda22SDaniel Mack 	if (err == 0) {
2317b1eda22SDaniel Mack 		if (count == 1)
2327b1eda22SDaniel Mack 			err = put_user(rc_code, buf);
2337b1eda22SDaniel Mack 		else
2347b1eda22SDaniel Mack 			err = put_user(rc_code, (u32 __user *)buf);
2357b1eda22SDaniel Mack 	}
2367b1eda22SDaniel Mack 	return err < 0 ? err : count;
2377b1eda22SDaniel Mack }
2387b1eda22SDaniel Mack 
2397b1eda22SDaniel Mack static unsigned int snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *file,
2407b1eda22SDaniel Mack 					    poll_table *wait)
2417b1eda22SDaniel Mack {
2427b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = hw->private_data;
2437b1eda22SDaniel Mack 
2447b1eda22SDaniel Mack 	poll_wait(file, &mixer->rc_waitq, wait);
2457b1eda22SDaniel Mack 	return mixer->rc_code ? POLLIN | POLLRDNORM : 0;
2467b1eda22SDaniel Mack }
2477b1eda22SDaniel Mack 
2487b1eda22SDaniel Mack static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer)
2497b1eda22SDaniel Mack {
2507b1eda22SDaniel Mack 	struct snd_hwdep *hwdep;
2517b1eda22SDaniel Mack 	int err, len, i;
2527b1eda22SDaniel Mack 
2537b1eda22SDaniel Mack 	for (i = 0; i < ARRAY_SIZE(rc_configs); ++i)
2547b1eda22SDaniel Mack 		if (rc_configs[i].usb_id == mixer->chip->usb_id)
2557b1eda22SDaniel Mack 			break;
2567b1eda22SDaniel Mack 	if (i >= ARRAY_SIZE(rc_configs))
2577b1eda22SDaniel Mack 		return 0;
2587b1eda22SDaniel Mack 	mixer->rc_cfg = &rc_configs[i];
2597b1eda22SDaniel Mack 
2607b1eda22SDaniel Mack 	len = mixer->rc_cfg->packet_length;
2617b1eda22SDaniel Mack 
2627b1eda22SDaniel Mack 	init_waitqueue_head(&mixer->rc_waitq);
2637b1eda22SDaniel Mack 	err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep);
2647b1eda22SDaniel Mack 	if (err < 0)
2657b1eda22SDaniel Mack 		return err;
2667b1eda22SDaniel Mack 	snprintf(hwdep->name, sizeof(hwdep->name),
2677b1eda22SDaniel Mack 		 "%s remote control", mixer->chip->card->shortname);
2687b1eda22SDaniel Mack 	hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC;
2697b1eda22SDaniel Mack 	hwdep->private_data = mixer;
2707b1eda22SDaniel Mack 	hwdep->ops.read = snd_usb_sbrc_hwdep_read;
2717b1eda22SDaniel Mack 	hwdep->ops.poll = snd_usb_sbrc_hwdep_poll;
2727b1eda22SDaniel Mack 	hwdep->exclusive = 1;
2737b1eda22SDaniel Mack 
2747b1eda22SDaniel Mack 	mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL);
2757b1eda22SDaniel Mack 	if (!mixer->rc_urb)
2767b1eda22SDaniel Mack 		return -ENOMEM;
2777b1eda22SDaniel Mack 	mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL);
2787b1eda22SDaniel Mack 	if (!mixer->rc_setup_packet) {
2797b1eda22SDaniel Mack 		usb_free_urb(mixer->rc_urb);
2807b1eda22SDaniel Mack 		mixer->rc_urb = NULL;
2817b1eda22SDaniel Mack 		return -ENOMEM;
2827b1eda22SDaniel Mack 	}
2837b1eda22SDaniel Mack 	mixer->rc_setup_packet->bRequestType =
2847b1eda22SDaniel Mack 		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
2857b1eda22SDaniel Mack 	mixer->rc_setup_packet->bRequest = UAC_GET_MEM;
2867b1eda22SDaniel Mack 	mixer->rc_setup_packet->wValue = cpu_to_le16(0);
2877b1eda22SDaniel Mack 	mixer->rc_setup_packet->wIndex = cpu_to_le16(0);
2887b1eda22SDaniel Mack 	mixer->rc_setup_packet->wLength = cpu_to_le16(len);
2897b1eda22SDaniel Mack 	usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev,
2907b1eda22SDaniel Mack 			     usb_rcvctrlpipe(mixer->chip->dev, 0),
2917b1eda22SDaniel Mack 			     (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len,
2927b1eda22SDaniel Mack 			     snd_usb_soundblaster_remote_complete, mixer);
2937b1eda22SDaniel Mack 	return 0;
2947b1eda22SDaniel Mack }
2957b1eda22SDaniel Mack 
2967b1eda22SDaniel Mack #define snd_audigy2nx_led_info		snd_ctl_boolean_mono_info
2977b1eda22SDaniel Mack 
2987b1eda22SDaniel Mack static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2997b1eda22SDaniel Mack {
3009cf3689bSTakashi Iwai 	ucontrol->value.integer.value[0] = kcontrol->private_value >> 8;
3017b1eda22SDaniel Mack 	return 0;
3027b1eda22SDaniel Mack }
3037b1eda22SDaniel Mack 
3049cf3689bSTakashi Iwai static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer,
3059cf3689bSTakashi Iwai 				    int value, int index)
3067b1eda22SDaniel Mack {
3079cf3689bSTakashi Iwai 	struct snd_usb_audio *chip = mixer->chip;
3089cf3689bSTakashi Iwai 	int err;
3097b1eda22SDaniel Mack 
3109cf3689bSTakashi Iwai 	down_read(&chip->shutdown_rwsem);
3119cf3689bSTakashi Iwai 	if (chip->shutdown) {
312888ea7d5STakashi Iwai 		err = -ENODEV;
313888ea7d5STakashi Iwai 		goto out;
314888ea7d5STakashi Iwai 	}
3159cf3689bSTakashi Iwai 	if (chip->usb_id == USB_ID(0x041e, 0x3042))
3169cf3689bSTakashi Iwai 		err = snd_usb_ctl_msg(chip->dev,
3179cf3689bSTakashi Iwai 			      usb_sndctrlpipe(chip->dev, 0), 0x24,
318ca8dc34eSMandar Joshi 			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
31917d900c4SClemens Ladisch 			      !value, 0, NULL, 0);
3207cdd8d73SMathieu Bouffard 	/* USB X-Fi S51 Pro */
3219cf3689bSTakashi Iwai 	if (chip->usb_id == USB_ID(0x041e, 0x30df))
3229cf3689bSTakashi Iwai 		err = snd_usb_ctl_msg(chip->dev,
3239cf3689bSTakashi Iwai 			      usb_sndctrlpipe(chip->dev, 0), 0x24,
3247cdd8d73SMathieu Bouffard 			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
32517d900c4SClemens Ladisch 			      !value, 0, NULL, 0);
326ca8dc34eSMandar Joshi 	else
3279cf3689bSTakashi Iwai 		err = snd_usb_ctl_msg(chip->dev,
3289cf3689bSTakashi Iwai 			      usb_sndctrlpipe(chip->dev, 0), 0x24,
3297b1eda22SDaniel Mack 			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
33017d900c4SClemens Ladisch 			      value, index + 2, NULL, 0);
331888ea7d5STakashi Iwai  out:
3329cf3689bSTakashi Iwai 	up_read(&chip->shutdown_rwsem);
3337b1eda22SDaniel Mack 	return err;
3347b1eda22SDaniel Mack }
3357b1eda22SDaniel Mack 
3369cf3689bSTakashi Iwai static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol,
3379cf3689bSTakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
3387b1eda22SDaniel Mack {
3399cf3689bSTakashi Iwai 	struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
3409cf3689bSTakashi Iwai 	struct usb_mixer_interface *mixer = list->mixer;
3419cf3689bSTakashi Iwai 	int index = kcontrol->private_value & 0xff;
3429cf3689bSTakashi Iwai 	int value = ucontrol->value.integer.value[0];
3439cf3689bSTakashi Iwai 	int old_value = kcontrol->private_value >> 8;
3449cf3689bSTakashi Iwai 	int err;
3459cf3689bSTakashi Iwai 
3469cf3689bSTakashi Iwai 	if (value > 1)
3479cf3689bSTakashi Iwai 		return -EINVAL;
3489cf3689bSTakashi Iwai 	if (value == old_value)
3499cf3689bSTakashi Iwai 		return 0;
3509cf3689bSTakashi Iwai 	kcontrol->private_value = (value << 8) | index;
3519cf3689bSTakashi Iwai 	err = snd_audigy2nx_led_update(mixer, value, index);
3529cf3689bSTakashi Iwai 	return err < 0 ? err : 1;
3539cf3689bSTakashi Iwai }
3549cf3689bSTakashi Iwai 
3559cf3689bSTakashi Iwai static int snd_audigy2nx_led_resume(struct usb_mixer_elem_list *list)
3569cf3689bSTakashi Iwai {
3579cf3689bSTakashi Iwai 	int priv_value = list->kctl->private_value;
3589cf3689bSTakashi Iwai 
3599cf3689bSTakashi Iwai 	return snd_audigy2nx_led_update(list->mixer, priv_value >> 8,
3609cf3689bSTakashi Iwai 					priv_value & 0xff);
3619cf3689bSTakashi Iwai }
3629cf3689bSTakashi Iwai 
3639cf3689bSTakashi Iwai /* name and private_value are set dynamically */
3649cf3689bSTakashi Iwai static struct snd_kcontrol_new snd_audigy2nx_control = {
3657b1eda22SDaniel Mack 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3667b1eda22SDaniel Mack 	.info = snd_audigy2nx_led_info,
3677b1eda22SDaniel Mack 	.get = snd_audigy2nx_led_get,
3687b1eda22SDaniel Mack 	.put = snd_audigy2nx_led_put,
3699cf3689bSTakashi Iwai };
3709cf3689bSTakashi Iwai 
3719cf3689bSTakashi Iwai static const char * const snd_audigy2nx_led_names[] = {
3729cf3689bSTakashi Iwai 	"CMSS LED Switch",
3739cf3689bSTakashi Iwai 	"Power LED Switch",
3749cf3689bSTakashi Iwai 	"Dolby Digital LED Switch",
3757b1eda22SDaniel Mack };
3767b1eda22SDaniel Mack 
3777b1eda22SDaniel Mack static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
3787b1eda22SDaniel Mack {
3797b1eda22SDaniel Mack 	int i, err;
3807b1eda22SDaniel Mack 
3819cf3689bSTakashi Iwai 	for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_led_names); ++i) {
3829cf3689bSTakashi Iwai 		struct snd_kcontrol_new knew;
3839cf3689bSTakashi Iwai 
384ca8dc34eSMandar Joshi 		/* USB X-Fi S51 doesn't have a CMSS LED */
385ca8dc34eSMandar Joshi 		if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0)
386ca8dc34eSMandar Joshi 			continue;
3877cdd8d73SMathieu Bouffard 		/* USB X-Fi S51 Pro doesn't have one either */
3887cdd8d73SMathieu Bouffard 		if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0)
3897cdd8d73SMathieu Bouffard 			continue;
3907b1eda22SDaniel Mack 		if (i > 1 && /* Live24ext has 2 LEDs only */
3917b1eda22SDaniel Mack 			(mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
392ca8dc34eSMandar Joshi 			 mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
3937cdd8d73SMathieu Bouffard 			 mixer->chip->usb_id == USB_ID(0x041e, 0x30df) ||
3947b1eda22SDaniel Mack 			 mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
3957b1eda22SDaniel Mack 			break;
3969cf3689bSTakashi Iwai 
3979cf3689bSTakashi Iwai 		knew = snd_audigy2nx_control;
3989cf3689bSTakashi Iwai 		knew.name = snd_audigy2nx_led_names[i];
3999cf3689bSTakashi Iwai 		knew.private_value = (1 << 8) | i; /* LED on as default */
4009cf3689bSTakashi Iwai 		err = add_single_ctl_with_resume(mixer, 0,
4019cf3689bSTakashi Iwai 						 snd_audigy2nx_led_resume,
4029cf3689bSTakashi Iwai 						 &knew, NULL);
4037b1eda22SDaniel Mack 		if (err < 0)
4047b1eda22SDaniel Mack 			return err;
4057b1eda22SDaniel Mack 	}
4067b1eda22SDaniel Mack 	return 0;
4077b1eda22SDaniel Mack }
4087b1eda22SDaniel Mack 
4097b1eda22SDaniel Mack static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
4107b1eda22SDaniel Mack 				    struct snd_info_buffer *buffer)
4117b1eda22SDaniel Mack {
4127b1eda22SDaniel Mack 	static const struct sb_jack {
4137b1eda22SDaniel Mack 		int unitid;
4147b1eda22SDaniel Mack 		const char *name;
4157b1eda22SDaniel Mack 	}  jacks_audigy2nx[] = {
4167b1eda22SDaniel Mack 		{4,  "dig in "},
4177b1eda22SDaniel Mack 		{7,  "line in"},
4187b1eda22SDaniel Mack 		{19, "spk out"},
4197b1eda22SDaniel Mack 		{20, "hph out"},
4207b1eda22SDaniel Mack 		{-1, NULL}
4217b1eda22SDaniel Mack 	}, jacks_live24ext[] = {
4227b1eda22SDaniel Mack 		{4,  "line in"}, /* &1=Line, &2=Mic*/
4237b1eda22SDaniel Mack 		{3,  "hph out"}, /* headphones */
4247b1eda22SDaniel Mack 		{0,  "RC     "}, /* last command, 6 bytes see rc_config above */
4257b1eda22SDaniel Mack 		{-1, NULL}
4267b1eda22SDaniel Mack 	};
4277b1eda22SDaniel Mack 	const struct sb_jack *jacks;
4287b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = entry->private_data;
4297b1eda22SDaniel Mack 	int i, err;
4307b1eda22SDaniel Mack 	u8 buf[3];
4317b1eda22SDaniel Mack 
4327b1eda22SDaniel Mack 	snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname);
4337b1eda22SDaniel Mack 	if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020))
4347b1eda22SDaniel Mack 		jacks = jacks_audigy2nx;
4357b1eda22SDaniel Mack 	else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
4367b1eda22SDaniel Mack 		 mixer->chip->usb_id == USB_ID(0x041e, 0x3048))
4377b1eda22SDaniel Mack 		jacks = jacks_live24ext;
4387b1eda22SDaniel Mack 	else
4397b1eda22SDaniel Mack 		return;
4407b1eda22SDaniel Mack 
4417b1eda22SDaniel Mack 	for (i = 0; jacks[i].name; ++i) {
4427b1eda22SDaniel Mack 		snd_iprintf(buffer, "%s: ", jacks[i].name);
443888ea7d5STakashi Iwai 		down_read(&mixer->chip->shutdown_rwsem);
444888ea7d5STakashi Iwai 		if (mixer->chip->shutdown)
445888ea7d5STakashi Iwai 			err = 0;
446888ea7d5STakashi Iwai 		else
4477b1eda22SDaniel Mack 			err = snd_usb_ctl_msg(mixer->chip->dev,
4487b1eda22SDaniel Mack 				      usb_rcvctrlpipe(mixer->chip->dev, 0),
4497b1eda22SDaniel Mack 				      UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS |
4507b1eda22SDaniel Mack 				      USB_RECIP_INTERFACE, 0,
45117d900c4SClemens Ladisch 				      jacks[i].unitid << 8, buf, 3);
452888ea7d5STakashi Iwai 		up_read(&mixer->chip->shutdown_rwsem);
4537b1eda22SDaniel Mack 		if (err == 3 && (buf[0] == 3 || buf[0] == 6))
4547b1eda22SDaniel Mack 			snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]);
4557b1eda22SDaniel Mack 		else
4567b1eda22SDaniel Mack 			snd_iprintf(buffer, "?\n");
4577b1eda22SDaniel Mack 	}
4587b1eda22SDaniel Mack }
4597b1eda22SDaniel Mack 
46044832a71SVasily Khoruzhick /* EMU0204 */
46144832a71SVasily Khoruzhick static int snd_emu0204_ch_switch_info(struct snd_kcontrol *kcontrol,
46244832a71SVasily Khoruzhick 				      struct snd_ctl_elem_info *uinfo)
46344832a71SVasily Khoruzhick {
4647bbd03e0STakashi Iwai 	static const char * const texts[2] = {"1/2", "3/4"};
46544832a71SVasily Khoruzhick 
4667bbd03e0STakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
46744832a71SVasily Khoruzhick }
46844832a71SVasily Khoruzhick 
46944832a71SVasily Khoruzhick static int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol,
47044832a71SVasily Khoruzhick 				     struct snd_ctl_elem_value *ucontrol)
47144832a71SVasily Khoruzhick {
47244832a71SVasily Khoruzhick 	ucontrol->value.enumerated.item[0] = kcontrol->private_value;
47344832a71SVasily Khoruzhick 	return 0;
47444832a71SVasily Khoruzhick }
47544832a71SVasily Khoruzhick 
4765f503ee9STakashi Iwai static int snd_emu0204_ch_switch_update(struct usb_mixer_interface *mixer,
4775f503ee9STakashi Iwai 					int value)
47844832a71SVasily Khoruzhick {
4795f503ee9STakashi Iwai 	struct snd_usb_audio *chip = mixer->chip;
4805f503ee9STakashi Iwai 	int err;
48144832a71SVasily Khoruzhick 	unsigned char buf[2];
48244832a71SVasily Khoruzhick 
4835f503ee9STakashi Iwai 	down_read(&chip->shutdown_rwsem);
48444832a71SVasily Khoruzhick 	if (mixer->chip->shutdown) {
48544832a71SVasily Khoruzhick 		err = -ENODEV;
48644832a71SVasily Khoruzhick 		goto out;
48744832a71SVasily Khoruzhick 	}
4885f503ee9STakashi Iwai 
4895f503ee9STakashi Iwai 	buf[0] = 0x01;
4905f503ee9STakashi Iwai 	buf[1] = value ? 0x02 : 0x01;
4915f503ee9STakashi Iwai 	err = snd_usb_ctl_msg(chip->dev,
4925f503ee9STakashi Iwai 		      usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
49344832a71SVasily Khoruzhick 		      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
49444832a71SVasily Khoruzhick 		      0x0400, 0x0e00, buf, 2);
49544832a71SVasily Khoruzhick  out:
4965f503ee9STakashi Iwai 	up_read(&chip->shutdown_rwsem);
49744832a71SVasily Khoruzhick 	return err;
49844832a71SVasily Khoruzhick }
49944832a71SVasily Khoruzhick 
5005f503ee9STakashi Iwai static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol,
5015f503ee9STakashi Iwai 				     struct snd_ctl_elem_value *ucontrol)
50244832a71SVasily Khoruzhick {
5035f503ee9STakashi Iwai 	struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
5045f503ee9STakashi Iwai 	struct usb_mixer_interface *mixer = list->mixer;
5055f503ee9STakashi Iwai 	unsigned int value = ucontrol->value.enumerated.item[0];
5065f503ee9STakashi Iwai 	int err;
5075f503ee9STakashi Iwai 
5085f503ee9STakashi Iwai 	if (value > 1)
5095f503ee9STakashi Iwai 		return -EINVAL;
5105f503ee9STakashi Iwai 
5115f503ee9STakashi Iwai 	if (value == kcontrol->private_value)
5125f503ee9STakashi Iwai 		return 0;
5135f503ee9STakashi Iwai 
5145f503ee9STakashi Iwai 	kcontrol->private_value = value;
5155f503ee9STakashi Iwai 	err = snd_emu0204_ch_switch_update(mixer, value);
5165f503ee9STakashi Iwai 	return err < 0 ? err : 1;
5175f503ee9STakashi Iwai }
5185f503ee9STakashi Iwai 
5195f503ee9STakashi Iwai static int snd_emu0204_ch_switch_resume(struct usb_mixer_elem_list *list)
5205f503ee9STakashi Iwai {
5215f503ee9STakashi Iwai 	return snd_emu0204_ch_switch_update(list->mixer,
5225f503ee9STakashi Iwai 					    list->kctl->private_value);
5235f503ee9STakashi Iwai }
5245f503ee9STakashi Iwai 
5255f503ee9STakashi Iwai static struct snd_kcontrol_new snd_emu0204_control = {
52644832a71SVasily Khoruzhick 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
52744832a71SVasily Khoruzhick 	.name = "Front Jack Channels",
52844832a71SVasily Khoruzhick 	.info = snd_emu0204_ch_switch_info,
52944832a71SVasily Khoruzhick 	.get = snd_emu0204_ch_switch_get,
53044832a71SVasily Khoruzhick 	.put = snd_emu0204_ch_switch_put,
53144832a71SVasily Khoruzhick 	.private_value = 0,
53244832a71SVasily Khoruzhick };
53344832a71SVasily Khoruzhick 
53444832a71SVasily Khoruzhick static int snd_emu0204_controls_create(struct usb_mixer_interface *mixer)
53544832a71SVasily Khoruzhick {
5365f503ee9STakashi Iwai 	return add_single_ctl_with_resume(mixer, 0,
5375f503ee9STakashi Iwai 					  snd_emu0204_ch_switch_resume,
5385f503ee9STakashi Iwai 					  &snd_emu0204_control, NULL);
53944832a71SVasily Khoruzhick }
54044832a71SVasily Khoruzhick 
5411d31affbSDenis Washington /* ASUS Xonar U1 / U3 controls */
5421d31affbSDenis Washington 
5437b1eda22SDaniel Mack static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol,
5447b1eda22SDaniel Mack 				   struct snd_ctl_elem_value *ucontrol)
5457b1eda22SDaniel Mack {
5467b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
5477b1eda22SDaniel Mack 
5487b1eda22SDaniel Mack 	ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02);
5497b1eda22SDaniel Mack 	return 0;
5507b1eda22SDaniel Mack }
5517b1eda22SDaniel Mack 
5527b1eda22SDaniel Mack static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
5537b1eda22SDaniel Mack 				   struct snd_ctl_elem_value *ucontrol)
5547b1eda22SDaniel Mack {
5557b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
5567b1eda22SDaniel Mack 	u8 old_status, new_status;
5577b1eda22SDaniel Mack 	int err, changed;
5587b1eda22SDaniel Mack 
5597b1eda22SDaniel Mack 	old_status = mixer->xonar_u1_status;
5607b1eda22SDaniel Mack 	if (ucontrol->value.integer.value[0])
5617b1eda22SDaniel Mack 		new_status = old_status | 0x02;
5627b1eda22SDaniel Mack 	else
5637b1eda22SDaniel Mack 		new_status = old_status & ~0x02;
5647b1eda22SDaniel Mack 	changed = new_status != old_status;
565888ea7d5STakashi Iwai 	down_read(&mixer->chip->shutdown_rwsem);
566888ea7d5STakashi Iwai 	if (mixer->chip->shutdown)
567888ea7d5STakashi Iwai 		err = -ENODEV;
568888ea7d5STakashi Iwai 	else
5697b1eda22SDaniel Mack 		err = snd_usb_ctl_msg(mixer->chip->dev,
5707b1eda22SDaniel Mack 			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x08,
5717b1eda22SDaniel Mack 			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
57217d900c4SClemens Ladisch 			      50, 0, &new_status, 1);
573888ea7d5STakashi Iwai 	up_read(&mixer->chip->shutdown_rwsem);
5747b1eda22SDaniel Mack 	if (err < 0)
5757b1eda22SDaniel Mack 		return err;
5767b1eda22SDaniel Mack 	mixer->xonar_u1_status = new_status;
5777b1eda22SDaniel Mack 	return changed;
5787b1eda22SDaniel Mack }
5797b1eda22SDaniel Mack 
5807b1eda22SDaniel Mack static struct snd_kcontrol_new snd_xonar_u1_output_switch = {
5817b1eda22SDaniel Mack 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5827b1eda22SDaniel Mack 	.name = "Digital Playback Switch",
5837b1eda22SDaniel Mack 	.info = snd_ctl_boolean_mono_info,
5847b1eda22SDaniel Mack 	.get = snd_xonar_u1_switch_get,
5857b1eda22SDaniel Mack 	.put = snd_xonar_u1_switch_put,
5867b1eda22SDaniel Mack };
5877b1eda22SDaniel Mack 
5887b1eda22SDaniel Mack static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)
5897b1eda22SDaniel Mack {
5907b1eda22SDaniel Mack 	int err;
5917b1eda22SDaniel Mack 
5927b1eda22SDaniel Mack 	err = snd_ctl_add(mixer->chip->card,
5937b1eda22SDaniel Mack 			  snd_ctl_new1(&snd_xonar_u1_output_switch, mixer));
5947b1eda22SDaniel Mack 	if (err < 0)
5957b1eda22SDaniel Mack 		return err;
5967b1eda22SDaniel Mack 	mixer->xonar_u1_status = 0x05;
5977b1eda22SDaniel Mack 	return 0;
5987b1eda22SDaniel Mack }
5997b1eda22SDaniel Mack 
600d497a82fSDamien Zammit /* Digidesign Mbox 1 clock source switch (internal/spdif) */
601d497a82fSDamien Zammit 
602d497a82fSDamien Zammit static int snd_mbox1_switch_get(struct snd_kcontrol *kctl,
603d497a82fSDamien Zammit 				struct snd_ctl_elem_value *ucontrol)
604d497a82fSDamien Zammit {
605d497a82fSDamien Zammit 	ucontrol->value.enumerated.item[0] = kctl->private_value;
606d497a82fSDamien Zammit 	return 0;
607d497a82fSDamien Zammit }
608d497a82fSDamien Zammit 
609d497a82fSDamien Zammit static int snd_mbox1_switch_put(struct snd_kcontrol *kctl,
610d497a82fSDamien Zammit 				struct snd_ctl_elem_value *ucontrol)
611d497a82fSDamien Zammit {
612d497a82fSDamien Zammit 	struct snd_usb_audio *chip;
613d497a82fSDamien Zammit 	struct usb_mixer_interface *mixer;
614d497a82fSDamien Zammit 	int err;
615d497a82fSDamien Zammit 	bool cur_val, new_val;
616d497a82fSDamien Zammit 	unsigned char buff[3];
617d497a82fSDamien Zammit 
618d497a82fSDamien Zammit 	cur_val = kctl->private_value;
619d497a82fSDamien Zammit 	new_val = ucontrol->value.enumerated.item[0];
620d497a82fSDamien Zammit 
621d497a82fSDamien Zammit 	mixer = snd_kcontrol_chip(kctl);
622d497a82fSDamien Zammit 	if (snd_BUG_ON(!mixer))
623d497a82fSDamien Zammit 		return -EINVAL;
624d497a82fSDamien Zammit 
625d497a82fSDamien Zammit 	chip = mixer->chip;
626d497a82fSDamien Zammit 	if (snd_BUG_ON(!chip))
627d497a82fSDamien Zammit 		return -EINVAL;
628d497a82fSDamien Zammit 
629d497a82fSDamien Zammit 	if (cur_val == new_val)
630d497a82fSDamien Zammit 		return 0;
631d497a82fSDamien Zammit 
632d497a82fSDamien Zammit 	down_read(&chip->shutdown_rwsem);
633d497a82fSDamien Zammit 	if (chip->shutdown) {
634d497a82fSDamien Zammit 		err = -ENODEV;
635d497a82fSDamien Zammit 		goto err;
636d497a82fSDamien Zammit 	}
637d497a82fSDamien Zammit 
638d497a82fSDamien Zammit 	/* Prepare for magic command to toggle clock source */
639d497a82fSDamien Zammit 	err = snd_usb_ctl_msg(chip->dev,
640d497a82fSDamien Zammit 				usb_rcvctrlpipe(chip->dev, 0), 0x81,
641d497a82fSDamien Zammit 				USB_DIR_IN |
642d497a82fSDamien Zammit 				USB_TYPE_CLASS |
643d497a82fSDamien Zammit 				USB_RECIP_INTERFACE, 0x00, 0x500, buff, 1);
644d497a82fSDamien Zammit 	if (err < 0)
645d497a82fSDamien Zammit 		goto err;
646d497a82fSDamien Zammit 	err = snd_usb_ctl_msg(chip->dev,
647d497a82fSDamien Zammit 				usb_rcvctrlpipe(chip->dev, 0), 0x81,
648d497a82fSDamien Zammit 				USB_DIR_IN |
649d497a82fSDamien Zammit 				USB_TYPE_CLASS |
650d497a82fSDamien Zammit 				USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
651d497a82fSDamien Zammit 	if (err < 0)
652d497a82fSDamien Zammit 		goto err;
653d497a82fSDamien Zammit 
654d497a82fSDamien Zammit 	/* 2 possibilities:	Internal    -> send sample rate
655d497a82fSDamien Zammit 	 *			S/PDIF sync -> send zeroes
656d497a82fSDamien Zammit 	 * NB: Sample rate locked to 48kHz on purpose to
657d497a82fSDamien Zammit 	 *     prevent user from resetting the sample rate
658d497a82fSDamien Zammit 	 *     while S/PDIF sync is enabled and confusing
659d497a82fSDamien Zammit 	 *     this configuration.
660d497a82fSDamien Zammit 	 */
661d497a82fSDamien Zammit 	if (new_val == 0) {
662d497a82fSDamien Zammit 		buff[0] = 0x80;
663d497a82fSDamien Zammit 		buff[1] = 0xbb;
664d497a82fSDamien Zammit 		buff[2] = 0x00;
665d497a82fSDamien Zammit 	} else {
666d497a82fSDamien Zammit 		buff[0] = buff[1] = buff[2] = 0x00;
667d497a82fSDamien Zammit 	}
668d497a82fSDamien Zammit 
669d497a82fSDamien Zammit 	/* Send the magic command to toggle the clock source */
670d497a82fSDamien Zammit 	err = snd_usb_ctl_msg(chip->dev,
671d497a82fSDamien Zammit 				usb_sndctrlpipe(chip->dev, 0), 0x1,
672d497a82fSDamien Zammit 				USB_TYPE_CLASS |
673d497a82fSDamien Zammit 				USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
674d497a82fSDamien Zammit 	if (err < 0)
675d497a82fSDamien Zammit 		goto err;
676d497a82fSDamien Zammit 	err = snd_usb_ctl_msg(chip->dev,
677d497a82fSDamien Zammit 				usb_rcvctrlpipe(chip->dev, 0), 0x81,
678d497a82fSDamien Zammit 				USB_DIR_IN |
679d497a82fSDamien Zammit 				USB_TYPE_CLASS |
680d497a82fSDamien Zammit 				USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
681d497a82fSDamien Zammit 	if (err < 0)
682d497a82fSDamien Zammit 		goto err;
683d497a82fSDamien Zammit 	err = snd_usb_ctl_msg(chip->dev,
684d497a82fSDamien Zammit 				usb_rcvctrlpipe(chip->dev, 0), 0x81,
685d497a82fSDamien Zammit 				USB_DIR_IN |
686d497a82fSDamien Zammit 				USB_TYPE_CLASS |
687d497a82fSDamien Zammit 				USB_RECIP_ENDPOINT, 0x100, 0x2, buff, 3);
688d497a82fSDamien Zammit 	if (err < 0)
689d497a82fSDamien Zammit 		goto err;
690d497a82fSDamien Zammit 	kctl->private_value = new_val;
691d497a82fSDamien Zammit 
692d497a82fSDamien Zammit err:
693d497a82fSDamien Zammit 	up_read(&chip->shutdown_rwsem);
694d497a82fSDamien Zammit 	return err < 0 ? err : 1;
695d497a82fSDamien Zammit }
696d497a82fSDamien Zammit 
697d497a82fSDamien Zammit static int snd_mbox1_switch_info(struct snd_kcontrol *kcontrol,
698d497a82fSDamien Zammit 				 struct snd_ctl_elem_info *uinfo)
699d497a82fSDamien Zammit {
700d497a82fSDamien Zammit 	static const char *const texts[2] = {
701d497a82fSDamien Zammit 		"Internal",
702d497a82fSDamien Zammit 		"S/PDIF"
703d497a82fSDamien Zammit 	};
704d497a82fSDamien Zammit 
705d497a82fSDamien Zammit 	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
706d497a82fSDamien Zammit }
707d497a82fSDamien Zammit 
708d497a82fSDamien Zammit static struct snd_kcontrol_new snd_mbox1_switch = {
709d497a82fSDamien Zammit 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
710d497a82fSDamien Zammit 	.name = "Clock Source",
711d497a82fSDamien Zammit 	.index = 0,
712d497a82fSDamien Zammit 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
713d497a82fSDamien Zammit 	.info = snd_mbox1_switch_info,
714d497a82fSDamien Zammit 	.get = snd_mbox1_switch_get,
715d497a82fSDamien Zammit 	.put = snd_mbox1_switch_put,
716d497a82fSDamien Zammit 	.private_value = 0
717d497a82fSDamien Zammit };
718d497a82fSDamien Zammit 
719d497a82fSDamien Zammit static int snd_mbox1_create_sync_switch(struct usb_mixer_interface *mixer)
720d497a82fSDamien Zammit {
721d497a82fSDamien Zammit 	return snd_ctl_add(mixer->chip->card,
722d497a82fSDamien Zammit 			snd_ctl_new1(&snd_mbox1_switch, mixer));
723d497a82fSDamien Zammit }
724d497a82fSDamien Zammit 
72554a8c500SDaniel Mack /* Native Instruments device quirks */
72654a8c500SDaniel Mack 
72754a8c500SDaniel Mack #define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex))
72854a8c500SDaniel Mack 
72954a8c500SDaniel Mack static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
73054a8c500SDaniel Mack 					     struct snd_ctl_elem_value *ucontrol)
73154a8c500SDaniel Mack {
73254a8c500SDaniel Mack 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
73354a8c500SDaniel Mack 	struct usb_device *dev = mixer->chip->dev;
73454a8c500SDaniel Mack 	u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
73554a8c500SDaniel Mack 	u16 wIndex = kcontrol->private_value & 0xffff;
73654a8c500SDaniel Mack 	u8 tmp;
737888ea7d5STakashi Iwai 	int ret;
73854a8c500SDaniel Mack 
739888ea7d5STakashi Iwai 	down_read(&mixer->chip->shutdown_rwsem);
740888ea7d5STakashi Iwai 	if (mixer->chip->shutdown)
741888ea7d5STakashi Iwai 		ret = -ENODEV;
742888ea7d5STakashi Iwai 	else
74301cb156eSTakashi Iwai 		ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
74454a8c500SDaniel Mack 				  USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
745889d6684SEldad Zack 				  0, wIndex,
74601cb156eSTakashi Iwai 				  &tmp, sizeof(tmp));
747888ea7d5STakashi Iwai 	up_read(&mixer->chip->shutdown_rwsem);
74854a8c500SDaniel Mack 
74954a8c500SDaniel Mack 	if (ret < 0) {
7500ba41d91STakashi Iwai 		dev_err(&dev->dev,
75154a8c500SDaniel Mack 			"unable to issue vendor read request (ret = %d)", ret);
75254a8c500SDaniel Mack 		return ret;
75354a8c500SDaniel Mack 	}
75454a8c500SDaniel Mack 
75554a8c500SDaniel Mack 	ucontrol->value.integer.value[0] = tmp;
75654a8c500SDaniel Mack 
75754a8c500SDaniel Mack 	return 0;
75854a8c500SDaniel Mack }
75954a8c500SDaniel Mack 
76054a8c500SDaniel Mack static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
76154a8c500SDaniel Mack 					     struct snd_ctl_elem_value *ucontrol)
76254a8c500SDaniel Mack {
76354a8c500SDaniel Mack 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
76454a8c500SDaniel Mack 	struct usb_device *dev = mixer->chip->dev;
76554a8c500SDaniel Mack 	u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
76654a8c500SDaniel Mack 	u16 wIndex = kcontrol->private_value & 0xffff;
76754a8c500SDaniel Mack 	u16 wValue = ucontrol->value.integer.value[0];
768888ea7d5STakashi Iwai 	int ret;
76954a8c500SDaniel Mack 
770888ea7d5STakashi Iwai 	down_read(&mixer->chip->shutdown_rwsem);
771888ea7d5STakashi Iwai 	if (mixer->chip->shutdown)
772888ea7d5STakashi Iwai 		ret = -ENODEV;
773888ea7d5STakashi Iwai 	else
774888ea7d5STakashi Iwai 		ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
77554a8c500SDaniel Mack 				  USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
776889d6684SEldad Zack 				  wValue, wIndex,
77754a8c500SDaniel Mack 				  NULL, 0, 1000);
778888ea7d5STakashi Iwai 	up_read(&mixer->chip->shutdown_rwsem);
77954a8c500SDaniel Mack 
78054a8c500SDaniel Mack 	if (ret < 0) {
7810ba41d91STakashi Iwai 		dev_err(&dev->dev,
78254a8c500SDaniel Mack 			"unable to issue vendor write request (ret = %d)", ret);
78354a8c500SDaniel Mack 		return ret;
78454a8c500SDaniel Mack 	}
78554a8c500SDaniel Mack 
78654a8c500SDaniel Mack 	return 0;
78754a8c500SDaniel Mack }
78854a8c500SDaniel Mack 
78954a8c500SDaniel Mack static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = {
79054a8c500SDaniel Mack 	{
79154a8c500SDaniel Mack 		.name = "Direct Thru Channel A",
79254a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x01, 0x03),
79354a8c500SDaniel Mack 	},
79454a8c500SDaniel Mack 	{
79554a8c500SDaniel Mack 		.name = "Direct Thru Channel B",
79654a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x01, 0x05),
79754a8c500SDaniel Mack 	},
79854a8c500SDaniel Mack 	{
79954a8c500SDaniel Mack 		.name = "Phono Input Channel A",
80054a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x02, 0x03),
80154a8c500SDaniel Mack 	},
80254a8c500SDaniel Mack 	{
80354a8c500SDaniel Mack 		.name = "Phono Input Channel B",
80454a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x02, 0x05),
80554a8c500SDaniel Mack 	},
80654a8c500SDaniel Mack };
80754a8c500SDaniel Mack 
80854a8c500SDaniel Mack static struct snd_kcontrol_new snd_nativeinstruments_ta10_mixers[] = {
80954a8c500SDaniel Mack 	{
81054a8c500SDaniel Mack 		.name = "Direct Thru Channel A",
81154a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x01, 0x03),
81254a8c500SDaniel Mack 	},
81354a8c500SDaniel Mack 	{
81454a8c500SDaniel Mack 		.name = "Direct Thru Channel B",
81554a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x01, 0x05),
81654a8c500SDaniel Mack 	},
81754a8c500SDaniel Mack 	{
81854a8c500SDaniel Mack 		.name = "Direct Thru Channel C",
81954a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x01, 0x07),
82054a8c500SDaniel Mack 	},
82154a8c500SDaniel Mack 	{
82254a8c500SDaniel Mack 		.name = "Direct Thru Channel D",
82354a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x01, 0x09),
82454a8c500SDaniel Mack 	},
82554a8c500SDaniel Mack 	{
82654a8c500SDaniel Mack 		.name = "Phono Input Channel A",
82754a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x02, 0x03),
82854a8c500SDaniel Mack 	},
82954a8c500SDaniel Mack 	{
83054a8c500SDaniel Mack 		.name = "Phono Input Channel B",
83154a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x02, 0x05),
83254a8c500SDaniel Mack 	},
83354a8c500SDaniel Mack 	{
83454a8c500SDaniel Mack 		.name = "Phono Input Channel C",
83554a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x02, 0x07),
83654a8c500SDaniel Mack 	},
83754a8c500SDaniel Mack 	{
83854a8c500SDaniel Mack 		.name = "Phono Input Channel D",
83954a8c500SDaniel Mack 		.private_value = _MAKE_NI_CONTROL(0x02, 0x09),
84054a8c500SDaniel Mack 	},
84154a8c500SDaniel Mack };
84254a8c500SDaniel Mack 
84354a8c500SDaniel Mack static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
84454a8c500SDaniel Mack 					      const struct snd_kcontrol_new *kc,
84554a8c500SDaniel Mack 					      unsigned int count)
84654a8c500SDaniel Mack {
84754a8c500SDaniel Mack 	int i, err = 0;
84854a8c500SDaniel Mack 	struct snd_kcontrol_new template = {
84954a8c500SDaniel Mack 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
85054a8c500SDaniel Mack 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
85154a8c500SDaniel Mack 		.get = snd_nativeinstruments_control_get,
85254a8c500SDaniel Mack 		.put = snd_nativeinstruments_control_put,
85354a8c500SDaniel Mack 		.info = snd_ctl_boolean_mono_info,
85454a8c500SDaniel Mack 	};
85554a8c500SDaniel Mack 
85654a8c500SDaniel Mack 	for (i = 0; i < count; i++) {
85754a8c500SDaniel Mack 		struct snd_kcontrol *c;
85854a8c500SDaniel Mack 
85954a8c500SDaniel Mack 		template.name = kc[i].name;
86054a8c500SDaniel Mack 		template.private_value = kc[i].private_value;
86154a8c500SDaniel Mack 
86254a8c500SDaniel Mack 		c = snd_ctl_new1(&template, mixer);
86354a8c500SDaniel Mack 		err = snd_ctl_add(mixer->chip->card, c);
86454a8c500SDaniel Mack 
86554a8c500SDaniel Mack 		if (err < 0)
86654a8c500SDaniel Mack 			break;
86754a8c500SDaniel Mack 	}
86854a8c500SDaniel Mack 
86954a8c500SDaniel Mack 	return err;
87054a8c500SDaniel Mack }
87154a8c500SDaniel Mack 
872d5a0bf6cSDaniel Mack /* M-Audio FastTrack Ultra quirks */
873e9a25e04SMatt Gruskin /* FTU Effect switch (also used by C400/C600) */
874d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val {
875d34bf148SFelix Homann 	struct usb_mixer_interface *mixer;
876d34bf148SFelix Homann 	int cached_value;
877d34bf148SFelix Homann 	int is_cached;
878d847ce0eSEldad Zack 	int bUnitID;
879d847ce0eSEldad Zack 	int validx;
880d34bf148SFelix Homann };
881d34bf148SFelix Homann 
882d34bf148SFelix Homann static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol,
883d34bf148SFelix Homann 					struct snd_ctl_elem_info *uinfo)
884d34bf148SFelix Homann {
8857bbd03e0STakashi Iwai 	static const char *const texts[8] = {
8867bbd03e0STakashi Iwai 		"Room 1", "Room 2", "Room 3", "Hall 1",
8877bbd03e0STakashi Iwai 		"Hall 2", "Plate", "Delay", "Echo"
888d34bf148SFelix Homann 	};
889d34bf148SFelix Homann 
8907bbd03e0STakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
891d34bf148SFelix Homann }
892d34bf148SFelix Homann 
893d34bf148SFelix Homann static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
894d34bf148SFelix Homann 					struct snd_ctl_elem_value *ucontrol)
895d34bf148SFelix Homann {
896d34bf148SFelix Homann 	struct snd_usb_audio *chip;
897d34bf148SFelix Homann 	struct usb_mixer_interface *mixer;
898d34bf148SFelix Homann 	struct snd_ftu_eff_switch_priv_val *pval;
899d34bf148SFelix Homann 	int err;
900d34bf148SFelix Homann 	unsigned char value[2];
901d847ce0eSEldad Zack 	int id, validx;
902d34bf148SFelix Homann 
903d34bf148SFelix Homann 	const int val_len = 2;
904d34bf148SFelix Homann 
905d34bf148SFelix Homann 	value[0] = 0x00;
906d34bf148SFelix Homann 	value[1] = 0x00;
907d34bf148SFelix Homann 
908d34bf148SFelix Homann 	pval = (struct snd_ftu_eff_switch_priv_val *)
909d34bf148SFelix Homann 		kctl->private_value;
910d34bf148SFelix Homann 
911d34bf148SFelix Homann 	if (pval->is_cached) {
912d34bf148SFelix Homann 		ucontrol->value.enumerated.item[0] = pval->cached_value;
913d34bf148SFelix Homann 		return 0;
914d34bf148SFelix Homann 	}
915d34bf148SFelix Homann 
916d34bf148SFelix Homann 	mixer = (struct usb_mixer_interface *) pval->mixer;
917d34bf148SFelix Homann 	if (snd_BUG_ON(!mixer))
918d34bf148SFelix Homann 		return -EINVAL;
919d34bf148SFelix Homann 
920d34bf148SFelix Homann 	chip = (struct snd_usb_audio *) mixer->chip;
921d34bf148SFelix Homann 	if (snd_BUG_ON(!chip))
922d34bf148SFelix Homann 		return -EINVAL;
923d34bf148SFelix Homann 
924d847ce0eSEldad Zack 	id = pval->bUnitID;
925d847ce0eSEldad Zack 	validx = pval->validx;
926d34bf148SFelix Homann 
927888ea7d5STakashi Iwai 	down_read(&mixer->chip->shutdown_rwsem);
928888ea7d5STakashi Iwai 	if (mixer->chip->shutdown)
929888ea7d5STakashi Iwai 		err = -ENODEV;
930888ea7d5STakashi Iwai 	else
931d34bf148SFelix Homann 		err = snd_usb_ctl_msg(chip->dev,
932d34bf148SFelix Homann 			usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
933d34bf148SFelix Homann 			USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
934d34bf148SFelix Homann 			validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
935d34bf148SFelix Homann 			value, val_len);
936888ea7d5STakashi Iwai 	up_read(&mixer->chip->shutdown_rwsem);
937d34bf148SFelix Homann 	if (err < 0)
938d34bf148SFelix Homann 		return err;
939d34bf148SFelix Homann 
940d34bf148SFelix Homann 	ucontrol->value.enumerated.item[0] = value[0];
941d34bf148SFelix Homann 	pval->cached_value = value[0];
942d34bf148SFelix Homann 	pval->is_cached = 1;
943d34bf148SFelix Homann 
944d34bf148SFelix Homann 	return 0;
945d34bf148SFelix Homann }
946d34bf148SFelix Homann 
947d34bf148SFelix Homann static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
948d34bf148SFelix Homann 					struct snd_ctl_elem_value *ucontrol)
949d34bf148SFelix Homann {
950d34bf148SFelix Homann 	struct snd_usb_audio *chip;
951d34bf148SFelix Homann 	struct snd_ftu_eff_switch_priv_val *pval;
952d34bf148SFelix Homann 
953d34bf148SFelix Homann 	struct usb_mixer_interface *mixer;
954d34bf148SFelix Homann 	int changed, cur_val, err, new_val;
955d34bf148SFelix Homann 	unsigned char value[2];
956d847ce0eSEldad Zack 	int id, validx;
957d34bf148SFelix Homann 
958d34bf148SFelix Homann 	const int val_len = 2;
959d34bf148SFelix Homann 
960d34bf148SFelix Homann 	changed = 0;
961d34bf148SFelix Homann 
962d34bf148SFelix Homann 	pval = (struct snd_ftu_eff_switch_priv_val *)
963d34bf148SFelix Homann 		kctl->private_value;
964d34bf148SFelix Homann 	cur_val = pval->cached_value;
965d34bf148SFelix Homann 	new_val = ucontrol->value.enumerated.item[0];
966d34bf148SFelix Homann 
967d34bf148SFelix Homann 	mixer = (struct usb_mixer_interface *) pval->mixer;
968d34bf148SFelix Homann 	if (snd_BUG_ON(!mixer))
969d34bf148SFelix Homann 		return -EINVAL;
970d34bf148SFelix Homann 
971d34bf148SFelix Homann 	chip = (struct snd_usb_audio *) mixer->chip;
972d34bf148SFelix Homann 	if (snd_BUG_ON(!chip))
973d34bf148SFelix Homann 		return -EINVAL;
974d34bf148SFelix Homann 
975d847ce0eSEldad Zack 	id = pval->bUnitID;
976d847ce0eSEldad Zack 	validx = pval->validx;
977d847ce0eSEldad Zack 
978d34bf148SFelix Homann 	if (!pval->is_cached) {
979d34bf148SFelix Homann 		/* Read current value */
980888ea7d5STakashi Iwai 		down_read(&mixer->chip->shutdown_rwsem);
981888ea7d5STakashi Iwai 		if (mixer->chip->shutdown)
982888ea7d5STakashi Iwai 			err = -ENODEV;
983888ea7d5STakashi Iwai 		else
984d34bf148SFelix Homann 			err = snd_usb_ctl_msg(chip->dev,
985d34bf148SFelix Homann 				usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
986d34bf148SFelix Homann 				USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
987d34bf148SFelix Homann 				validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
988d34bf148SFelix Homann 				value, val_len);
989888ea7d5STakashi Iwai 		up_read(&mixer->chip->shutdown_rwsem);
990d34bf148SFelix Homann 		if (err < 0)
991d34bf148SFelix Homann 			return err;
992d34bf148SFelix Homann 
993d34bf148SFelix Homann 		cur_val = value[0];
994d34bf148SFelix Homann 		pval->cached_value = cur_val;
995d34bf148SFelix Homann 		pval->is_cached = 1;
996d34bf148SFelix Homann 	}
997d34bf148SFelix Homann 	/* update value if needed */
998d34bf148SFelix Homann 	if (cur_val != new_val) {
999d34bf148SFelix Homann 		value[0] = new_val;
1000d34bf148SFelix Homann 		value[1] = 0;
1001888ea7d5STakashi Iwai 		down_read(&mixer->chip->shutdown_rwsem);
1002888ea7d5STakashi Iwai 		if (mixer->chip->shutdown)
1003888ea7d5STakashi Iwai 			err = -ENODEV;
1004888ea7d5STakashi Iwai 		else
1005d34bf148SFelix Homann 			err = snd_usb_ctl_msg(chip->dev,
1006d34bf148SFelix Homann 				usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
1007d34bf148SFelix Homann 				USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
1008d34bf148SFelix Homann 				validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
1009d34bf148SFelix Homann 				value, val_len);
1010888ea7d5STakashi Iwai 		up_read(&mixer->chip->shutdown_rwsem);
1011d34bf148SFelix Homann 		if (err < 0)
1012d34bf148SFelix Homann 			return err;
1013d34bf148SFelix Homann 
1014d34bf148SFelix Homann 		pval->cached_value = new_val;
1015d34bf148SFelix Homann 		pval->is_cached = 1;
1016d34bf148SFelix Homann 		changed = 1;
1017d34bf148SFelix Homann 	}
1018d34bf148SFelix Homann 
1019d34bf148SFelix Homann 	return changed;
1020d34bf148SFelix Homann }
1021d34bf148SFelix Homann 
10221a290581STakashi Iwai static void kctl_private_value_free(struct snd_kcontrol *kctl)
10231a290581STakashi Iwai {
10241a290581STakashi Iwai 	kfree((void *)kctl->private_value);
10251a290581STakashi Iwai }
10261a290581STakashi Iwai 
1027d847ce0eSEldad Zack static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer,
1028d847ce0eSEldad Zack 	int validx, int bUnitID)
1029d34bf148SFelix Homann {
1030d34bf148SFelix Homann 	static struct snd_kcontrol_new template = {
1031d34bf148SFelix Homann 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1032d34bf148SFelix Homann 		.name = "Effect Program Switch",
1033d34bf148SFelix Homann 		.index = 0,
1034d34bf148SFelix Homann 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1035d34bf148SFelix Homann 		.info = snd_ftu_eff_switch_info,
1036d34bf148SFelix Homann 		.get = snd_ftu_eff_switch_get,
1037d34bf148SFelix Homann 		.put = snd_ftu_eff_switch_put
1038d34bf148SFelix Homann 	};
1039d34bf148SFelix Homann 
1040d34bf148SFelix Homann 	int err;
1041d34bf148SFelix Homann 	struct snd_kcontrol *kctl;
1042d34bf148SFelix Homann 	struct snd_ftu_eff_switch_priv_val *pval;
1043d34bf148SFelix Homann 
1044d34bf148SFelix Homann 	pval = kzalloc(sizeof(*pval), GFP_KERNEL);
1045d34bf148SFelix Homann 	if (!pval)
1046d34bf148SFelix Homann 		return -ENOMEM;
1047d34bf148SFelix Homann 
1048d34bf148SFelix Homann 	pval->cached_value = 0;
1049d34bf148SFelix Homann 	pval->is_cached = 0;
1050d34bf148SFelix Homann 	pval->mixer = mixer;
1051d847ce0eSEldad Zack 	pval->bUnitID = bUnitID;
1052d847ce0eSEldad Zack 	pval->validx = validx;
1053d34bf148SFelix Homann 
1054d34bf148SFelix Homann 	template.private_value = (unsigned long) pval;
1055d34bf148SFelix Homann 	kctl = snd_ctl_new1(&template, mixer->chip);
1056d34bf148SFelix Homann 	if (!kctl) {
1057d34bf148SFelix Homann 		kfree(pval);
1058d34bf148SFelix Homann 		return -ENOMEM;
1059d34bf148SFelix Homann 	}
1060d34bf148SFelix Homann 
10611a290581STakashi Iwai 	kctl->private_free = kctl_private_value_free;
1062d34bf148SFelix Homann 	err = snd_ctl_add(mixer->chip->card, kctl);
1063d34bf148SFelix Homann 	if (err < 0)
1064d34bf148SFelix Homann 		return err;
1065d34bf148SFelix Homann 
1066d34bf148SFelix Homann 	return 0;
1067d34bf148SFelix Homann }
1068d5a0bf6cSDaniel Mack 
1069cfe8f97cSFelix Homann /* Create volume controls for FTU devices*/
1070cfe8f97cSFelix Homann static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
1071d5a0bf6cSDaniel Mack {
1072d5a0bf6cSDaniel Mack 	char name[64];
10738a4d1d39SFelix Homann 	unsigned int control, cmask;
1074d5a0bf6cSDaniel Mack 	int in, out, err;
1075d5a0bf6cSDaniel Mack 
10768a4d1d39SFelix Homann 	const unsigned int id = 5;
10778a4d1d39SFelix Homann 	const int val_type = USB_MIXER_S16;
10788a4d1d39SFelix Homann 
1079d5a0bf6cSDaniel Mack 	for (out = 0; out < 8; out++) {
10808a4d1d39SFelix Homann 		control = out + 1;
1081d5a0bf6cSDaniel Mack 		for (in = 0; in < 8; in++) {
10828a4d1d39SFelix Homann 			cmask = 1 << in;
1083d5a0bf6cSDaniel Mack 			snprintf(name, sizeof(name),
10848a4d1d39SFelix Homann 				"AIn%d - Out%d Capture Volume",
10858a4d1d39SFelix Homann 				in  + 1, out + 1);
10868a4d1d39SFelix Homann 			err = snd_create_std_mono_ctl(mixer, id, control,
10878a4d1d39SFelix Homann 							cmask, val_type, name,
108825ee7ef8SFelix Homann 							&snd_usb_mixer_vol_tlv);
1089d5a0bf6cSDaniel Mack 			if (err < 0)
1090d5a0bf6cSDaniel Mack 				return err;
1091d5a0bf6cSDaniel Mack 		}
1092d5a0bf6cSDaniel Mack 		for (in = 8; in < 16; in++) {
10938a4d1d39SFelix Homann 			cmask = 1 << in;
1094d5a0bf6cSDaniel Mack 			snprintf(name, sizeof(name),
10958a4d1d39SFelix Homann 				"DIn%d - Out%d Playback Volume",
10968a4d1d39SFelix Homann 				in - 7, out + 1);
10978a4d1d39SFelix Homann 			err = snd_create_std_mono_ctl(mixer, id, control,
10988a4d1d39SFelix Homann 							cmask, val_type, name,
109925ee7ef8SFelix Homann 							&snd_usb_mixer_vol_tlv);
1100d5a0bf6cSDaniel Mack 			if (err < 0)
1101d5a0bf6cSDaniel Mack 				return err;
1102d5a0bf6cSDaniel Mack 		}
1103d5a0bf6cSDaniel Mack 	}
1104d5a0bf6cSDaniel Mack 
1105d5a0bf6cSDaniel Mack 	return 0;
1106d5a0bf6cSDaniel Mack }
1107d5a0bf6cSDaniel Mack 
1108d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */
1109d34bf148SFelix Homann static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
1110d34bf148SFelix Homann {
1111d34bf148SFelix Homann 	static const char name[] = "Effect Volume";
1112d34bf148SFelix Homann 	const unsigned int id = 6;
1113d34bf148SFelix Homann 	const int val_type = USB_MIXER_U8;
1114d34bf148SFelix Homann 	const unsigned int control = 2;
1115d34bf148SFelix Homann 	const unsigned int cmask = 0;
1116d34bf148SFelix Homann 
1117d34bf148SFelix Homann 	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
1118d34bf148SFelix Homann 					name, snd_usb_mixer_vol_tlv);
1119d34bf148SFelix Homann }
1120d34bf148SFelix Homann 
1121d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */
1122d34bf148SFelix Homann static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
1123d34bf148SFelix Homann {
1124d34bf148SFelix Homann 	static const char name[] = "Effect Duration";
1125d34bf148SFelix Homann 	const unsigned int id = 6;
1126d34bf148SFelix Homann 	const int val_type = USB_MIXER_S16;
1127d34bf148SFelix Homann 	const unsigned int control = 3;
1128d34bf148SFelix Homann 	const unsigned int cmask = 0;
1129d34bf148SFelix Homann 
1130d34bf148SFelix Homann 	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
1131d34bf148SFelix Homann 					name, snd_usb_mixer_vol_tlv);
1132d34bf148SFelix Homann }
1133d34bf148SFelix Homann 
1134d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */
1135d34bf148SFelix Homann static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
1136d34bf148SFelix Homann {
1137d34bf148SFelix Homann 	static const char name[] = "Effect Feedback Volume";
1138d34bf148SFelix Homann 	const unsigned int id = 6;
1139d34bf148SFelix Homann 	const int val_type = USB_MIXER_U8;
1140d34bf148SFelix Homann 	const unsigned int control = 4;
1141d34bf148SFelix Homann 	const unsigned int cmask = 0;
1142d34bf148SFelix Homann 
1143d34bf148SFelix Homann 	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
1144d34bf148SFelix Homann 					name, NULL);
1145d34bf148SFelix Homann }
1146d34bf148SFelix Homann 
1147d34bf148SFelix Homann static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer)
1148d34bf148SFelix Homann {
1149d34bf148SFelix Homann 	unsigned int cmask;
1150d34bf148SFelix Homann 	int err, ch;
1151d34bf148SFelix Homann 	char name[48];
1152d34bf148SFelix Homann 
1153d34bf148SFelix Homann 	const unsigned int id = 7;
1154d34bf148SFelix Homann 	const int val_type = USB_MIXER_S16;
1155d34bf148SFelix Homann 	const unsigned int control = 7;
1156d34bf148SFelix Homann 
1157d34bf148SFelix Homann 	for (ch = 0; ch < 4; ++ch) {
1158d34bf148SFelix Homann 		cmask = 1 << ch;
1159d34bf148SFelix Homann 		snprintf(name, sizeof(name),
1160d34bf148SFelix Homann 			"Effect Return %d Volume", ch + 1);
1161d34bf148SFelix Homann 		err = snd_create_std_mono_ctl(mixer, id, control,
1162d34bf148SFelix Homann 						cmask, val_type, name,
1163d34bf148SFelix Homann 						snd_usb_mixer_vol_tlv);
1164d34bf148SFelix Homann 		if (err < 0)
1165d34bf148SFelix Homann 			return err;
1166d34bf148SFelix Homann 	}
1167d34bf148SFelix Homann 
1168d34bf148SFelix Homann 	return 0;
1169d34bf148SFelix Homann }
1170d34bf148SFelix Homann 
1171d34bf148SFelix Homann static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer)
1172d34bf148SFelix Homann {
1173d34bf148SFelix Homann 	unsigned int  cmask;
1174d34bf148SFelix Homann 	int err, ch;
1175d34bf148SFelix Homann 	char name[48];
1176d34bf148SFelix Homann 
1177d34bf148SFelix Homann 	const unsigned int id = 5;
1178d34bf148SFelix Homann 	const int val_type = USB_MIXER_S16;
1179d34bf148SFelix Homann 	const unsigned int control = 9;
1180d34bf148SFelix Homann 
1181d34bf148SFelix Homann 	for (ch = 0; ch < 8; ++ch) {
1182d34bf148SFelix Homann 		cmask = 1 << ch;
1183d34bf148SFelix Homann 		snprintf(name, sizeof(name),
1184d34bf148SFelix Homann 			"Effect Send AIn%d Volume", ch + 1);
1185d34bf148SFelix Homann 		err = snd_create_std_mono_ctl(mixer, id, control, cmask,
1186d34bf148SFelix Homann 						val_type, name,
1187d34bf148SFelix Homann 						snd_usb_mixer_vol_tlv);
1188d34bf148SFelix Homann 		if (err < 0)
1189d34bf148SFelix Homann 			return err;
1190d34bf148SFelix Homann 	}
1191d34bf148SFelix Homann 	for (ch = 8; ch < 16; ++ch) {
1192d34bf148SFelix Homann 		cmask = 1 << ch;
1193d34bf148SFelix Homann 		snprintf(name, sizeof(name),
1194d34bf148SFelix Homann 			"Effect Send DIn%d Volume", ch - 7);
1195d34bf148SFelix Homann 		err = snd_create_std_mono_ctl(mixer, id, control, cmask,
1196d34bf148SFelix Homann 						val_type, name,
1197d34bf148SFelix Homann 						snd_usb_mixer_vol_tlv);
1198d34bf148SFelix Homann 		if (err < 0)
1199d34bf148SFelix Homann 			return err;
1200d34bf148SFelix Homann 	}
1201d34bf148SFelix Homann 	return 0;
1202d34bf148SFelix Homann }
1203d34bf148SFelix Homann 
1204cfe8f97cSFelix Homann static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer)
12057536c301SMark Hills {
12068a4d1d39SFelix Homann 	int err;
12077536c301SMark Hills 
1208cfe8f97cSFelix Homann 	err = snd_ftu_create_volume_ctls(mixer);
12098a4d1d39SFelix Homann 	if (err < 0)
12108a4d1d39SFelix Homann 		return err;
12117536c301SMark Hills 
1212d847ce0eSEldad Zack 	err = snd_ftu_create_effect_switch(mixer, 1, 6);
1213d34bf148SFelix Homann 	if (err < 0)
1214d34bf148SFelix Homann 		return err;
1215d847ce0eSEldad Zack 
1216d34bf148SFelix Homann 	err = snd_ftu_create_effect_volume_ctl(mixer);
1217d34bf148SFelix Homann 	if (err < 0)
1218d34bf148SFelix Homann 		return err;
1219d34bf148SFelix Homann 
1220d34bf148SFelix Homann 	err = snd_ftu_create_effect_duration_ctl(mixer);
1221d34bf148SFelix Homann 	if (err < 0)
1222d34bf148SFelix Homann 		return err;
1223d34bf148SFelix Homann 
1224d34bf148SFelix Homann 	err = snd_ftu_create_effect_feedback_ctl(mixer);
1225d34bf148SFelix Homann 	if (err < 0)
1226d34bf148SFelix Homann 		return err;
1227d34bf148SFelix Homann 
1228d34bf148SFelix Homann 	err = snd_ftu_create_effect_return_ctls(mixer);
1229d34bf148SFelix Homann 	if (err < 0)
1230d34bf148SFelix Homann 		return err;
1231d34bf148SFelix Homann 
1232d34bf148SFelix Homann 	err = snd_ftu_create_effect_send_ctls(mixer);
1233d34bf148SFelix Homann 	if (err < 0)
1234d34bf148SFelix Homann 		return err;
1235d34bf148SFelix Homann 
12368a4d1d39SFelix Homann 	return 0;
12377536c301SMark Hills }
12387536c301SMark Hills 
12397b1eda22SDaniel Mack void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
12407b1eda22SDaniel Mack 			       unsigned char samplerate_id)
12417b1eda22SDaniel Mack {
12427b1eda22SDaniel Mack 	struct usb_mixer_interface *mixer;
12437b1eda22SDaniel Mack 	struct usb_mixer_elem_info *cval;
12447b1eda22SDaniel Mack 	int unitid = 12; /* SamleRate ExtensionUnit ID */
12457b1eda22SDaniel Mack 
12467b1eda22SDaniel Mack 	list_for_each_entry(mixer, &chip->mixer_list, list) {
12473360b84bSTakashi Iwai 		cval = (struct usb_mixer_elem_info *)mixer->id_elems[unitid];
12487b1eda22SDaniel Mack 		if (cval) {
12497b1eda22SDaniel Mack 			snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
12507b1eda22SDaniel Mack 						    cval->control << 8,
12517b1eda22SDaniel Mack 						    samplerate_id);
12527b1eda22SDaniel Mack 			snd_usb_mixer_notify_id(mixer, unitid);
12537b1eda22SDaniel Mack 		}
12547b1eda22SDaniel Mack 		break;
12557b1eda22SDaniel Mack 	}
12567b1eda22SDaniel Mack }
12577b1eda22SDaniel Mack 
1258e9a25e04SMatt Gruskin /* M-Audio Fast Track C400/C600 */
1259e9a25e04SMatt Gruskin /* C400/C600 volume controls, this control needs a volume quirk, see mixer.c */
126009d8e3a7SEldad Zack static int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer)
126109d8e3a7SEldad Zack {
126209d8e3a7SEldad Zack 	char name[64];
126309d8e3a7SEldad Zack 	unsigned int cmask, offset;
126409d8e3a7SEldad Zack 	int out, chan, err;
1265e9a25e04SMatt Gruskin 	int num_outs = 0;
1266e9a25e04SMatt Gruskin 	int num_ins = 0;
126709d8e3a7SEldad Zack 
126809d8e3a7SEldad Zack 	const unsigned int id = 0x40;
126909d8e3a7SEldad Zack 	const int val_type = USB_MIXER_S16;
127009d8e3a7SEldad Zack 	const int control = 1;
127109d8e3a7SEldad Zack 
1272e9a25e04SMatt Gruskin 	switch (mixer->chip->usb_id) {
1273e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2030):
1274e9a25e04SMatt Gruskin 		num_outs = 6;
1275e9a25e04SMatt Gruskin 		num_ins = 4;
1276e9a25e04SMatt Gruskin 		break;
1277e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2031):
1278e9a25e04SMatt Gruskin 		num_outs = 8;
1279e9a25e04SMatt Gruskin 		num_ins = 6;
1280e9a25e04SMatt Gruskin 		break;
1281e9a25e04SMatt Gruskin 	}
1282e9a25e04SMatt Gruskin 
1283e9a25e04SMatt Gruskin 	for (chan = 0; chan < num_outs + num_ins; chan++) {
1284e9a25e04SMatt Gruskin 		for (out = 0; out < num_outs; out++) {
1285e9a25e04SMatt Gruskin 			if (chan < num_outs) {
128609d8e3a7SEldad Zack 				snprintf(name, sizeof(name),
128709d8e3a7SEldad Zack 					"PCM%d-Out%d Playback Volume",
128809d8e3a7SEldad Zack 					chan + 1, out + 1);
128909d8e3a7SEldad Zack 			} else {
129009d8e3a7SEldad Zack 				snprintf(name, sizeof(name),
129109d8e3a7SEldad Zack 					"In%d-Out%d Playback Volume",
1292e9a25e04SMatt Gruskin 					chan - num_outs + 1, out + 1);
129309d8e3a7SEldad Zack 			}
129409d8e3a7SEldad Zack 
129509d8e3a7SEldad Zack 			cmask = (out == 0) ? 0 : 1 << (out - 1);
1296e9a25e04SMatt Gruskin 			offset = chan * num_outs;
129709d8e3a7SEldad Zack 			err = snd_create_std_mono_ctl_offset(mixer, id, control,
129809d8e3a7SEldad Zack 						cmask, val_type, offset, name,
129909d8e3a7SEldad Zack 						&snd_usb_mixer_vol_tlv);
130009d8e3a7SEldad Zack 			if (err < 0)
130109d8e3a7SEldad Zack 				return err;
130209d8e3a7SEldad Zack 		}
130309d8e3a7SEldad Zack 	}
130409d8e3a7SEldad Zack 
130509d8e3a7SEldad Zack 	return 0;
130609d8e3a7SEldad Zack }
130709d8e3a7SEldad Zack 
130809d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */
130909d8e3a7SEldad Zack static int snd_c400_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
131009d8e3a7SEldad Zack {
131109d8e3a7SEldad Zack 	static const char name[] = "Effect Volume";
131209d8e3a7SEldad Zack 	const unsigned int id = 0x43;
131309d8e3a7SEldad Zack 	const int val_type = USB_MIXER_U8;
131409d8e3a7SEldad Zack 	const unsigned int control = 3;
131509d8e3a7SEldad Zack 	const unsigned int cmask = 0;
131609d8e3a7SEldad Zack 
131709d8e3a7SEldad Zack 	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
131809d8e3a7SEldad Zack 					name, snd_usb_mixer_vol_tlv);
131909d8e3a7SEldad Zack }
132009d8e3a7SEldad Zack 
132109d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */
132209d8e3a7SEldad Zack static int snd_c400_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
132309d8e3a7SEldad Zack {
132409d8e3a7SEldad Zack 	static const char name[] = "Effect Duration";
132509d8e3a7SEldad Zack 	const unsigned int id = 0x43;
132609d8e3a7SEldad Zack 	const int val_type = USB_MIXER_S16;
132709d8e3a7SEldad Zack 	const unsigned int control = 4;
132809d8e3a7SEldad Zack 	const unsigned int cmask = 0;
132909d8e3a7SEldad Zack 
133009d8e3a7SEldad Zack 	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
133109d8e3a7SEldad Zack 					name, snd_usb_mixer_vol_tlv);
133209d8e3a7SEldad Zack }
133309d8e3a7SEldad Zack 
133409d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */
133509d8e3a7SEldad Zack static int snd_c400_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
133609d8e3a7SEldad Zack {
133709d8e3a7SEldad Zack 	static const char name[] = "Effect Feedback Volume";
133809d8e3a7SEldad Zack 	const unsigned int id = 0x43;
133909d8e3a7SEldad Zack 	const int val_type = USB_MIXER_U8;
134009d8e3a7SEldad Zack 	const unsigned int control = 5;
134109d8e3a7SEldad Zack 	const unsigned int cmask = 0;
134209d8e3a7SEldad Zack 
134309d8e3a7SEldad Zack 	return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
134409d8e3a7SEldad Zack 					name, NULL);
134509d8e3a7SEldad Zack }
134609d8e3a7SEldad Zack 
134709d8e3a7SEldad Zack static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer)
134809d8e3a7SEldad Zack {
134909d8e3a7SEldad Zack 	char name[64];
135009d8e3a7SEldad Zack 	unsigned int cmask;
135109d8e3a7SEldad Zack 	int chan, err;
1352e9a25e04SMatt Gruskin 	int num_outs = 0;
1353e9a25e04SMatt Gruskin 	int num_ins = 0;
135409d8e3a7SEldad Zack 
135509d8e3a7SEldad Zack 	const unsigned int id = 0x42;
135609d8e3a7SEldad Zack 	const int val_type = USB_MIXER_S16;
135709d8e3a7SEldad Zack 	const int control = 1;
135809d8e3a7SEldad Zack 
1359e9a25e04SMatt Gruskin 	switch (mixer->chip->usb_id) {
1360e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2030):
1361e9a25e04SMatt Gruskin 		num_outs = 6;
1362e9a25e04SMatt Gruskin 		num_ins = 4;
1363e9a25e04SMatt Gruskin 		break;
1364e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2031):
1365e9a25e04SMatt Gruskin 		num_outs = 8;
1366e9a25e04SMatt Gruskin 		num_ins = 6;
1367e9a25e04SMatt Gruskin 		break;
1368e9a25e04SMatt Gruskin 	}
1369e9a25e04SMatt Gruskin 
1370e9a25e04SMatt Gruskin 	for (chan = 0; chan < num_outs + num_ins; chan++) {
1371e9a25e04SMatt Gruskin 		if (chan < num_outs) {
137209d8e3a7SEldad Zack 			snprintf(name, sizeof(name),
137309d8e3a7SEldad Zack 				"Effect Send DOut%d",
137409d8e3a7SEldad Zack 				chan + 1);
137509d8e3a7SEldad Zack 		} else {
137609d8e3a7SEldad Zack 			snprintf(name, sizeof(name),
137709d8e3a7SEldad Zack 				"Effect Send AIn%d",
1378e9a25e04SMatt Gruskin 				chan - num_outs + 1);
137909d8e3a7SEldad Zack 		}
138009d8e3a7SEldad Zack 
138109d8e3a7SEldad Zack 		cmask = (chan == 0) ? 0 : 1 << (chan - 1);
138209d8e3a7SEldad Zack 		err = snd_create_std_mono_ctl(mixer, id, control,
138309d8e3a7SEldad Zack 						cmask, val_type, name,
138409d8e3a7SEldad Zack 						&snd_usb_mixer_vol_tlv);
138509d8e3a7SEldad Zack 		if (err < 0)
138609d8e3a7SEldad Zack 			return err;
138709d8e3a7SEldad Zack 	}
138809d8e3a7SEldad Zack 
138909d8e3a7SEldad Zack 	return 0;
139009d8e3a7SEldad Zack }
139109d8e3a7SEldad Zack 
139209d8e3a7SEldad Zack static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer)
139309d8e3a7SEldad Zack {
139409d8e3a7SEldad Zack 	char name[64];
139509d8e3a7SEldad Zack 	unsigned int cmask;
139609d8e3a7SEldad Zack 	int chan, err;
1397e9a25e04SMatt Gruskin 	int num_outs = 0;
1398e9a25e04SMatt Gruskin 	int offset = 0;
139909d8e3a7SEldad Zack 
140009d8e3a7SEldad Zack 	const unsigned int id = 0x40;
140109d8e3a7SEldad Zack 	const int val_type = USB_MIXER_S16;
140209d8e3a7SEldad Zack 	const int control = 1;
140309d8e3a7SEldad Zack 
1404e9a25e04SMatt Gruskin 	switch (mixer->chip->usb_id) {
1405e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2030):
1406e9a25e04SMatt Gruskin 		num_outs = 6;
1407e9a25e04SMatt Gruskin 		offset = 0x3c;
1408e9a25e04SMatt Gruskin 		/* { 0x3c, 0x43, 0x3e, 0x45, 0x40, 0x47 } */
1409e9a25e04SMatt Gruskin 		break;
1410e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2031):
1411e9a25e04SMatt Gruskin 		num_outs = 8;
1412e9a25e04SMatt Gruskin 		offset = 0x70;
1413e9a25e04SMatt Gruskin 		/* { 0x70, 0x79, 0x72, 0x7b, 0x74, 0x7d, 0x76, 0x7f } */
1414e9a25e04SMatt Gruskin 		break;
1415e9a25e04SMatt Gruskin 	}
1416e9a25e04SMatt Gruskin 
1417e9a25e04SMatt Gruskin 	for (chan = 0; chan < num_outs; chan++) {
141809d8e3a7SEldad Zack 		snprintf(name, sizeof(name),
141909d8e3a7SEldad Zack 			"Effect Return %d",
142009d8e3a7SEldad Zack 			chan + 1);
142109d8e3a7SEldad Zack 
1422e9a25e04SMatt Gruskin 		cmask = (chan == 0) ? 0 :
1423e9a25e04SMatt Gruskin 			1 << (chan + (chan % 2) * num_outs - 1);
142409d8e3a7SEldad Zack 		err = snd_create_std_mono_ctl_offset(mixer, id, control,
142509d8e3a7SEldad Zack 						cmask, val_type, offset, name,
142609d8e3a7SEldad Zack 						&snd_usb_mixer_vol_tlv);
142709d8e3a7SEldad Zack 		if (err < 0)
142809d8e3a7SEldad Zack 			return err;
142909d8e3a7SEldad Zack 	}
143009d8e3a7SEldad Zack 
143109d8e3a7SEldad Zack 	return 0;
143209d8e3a7SEldad Zack }
143309d8e3a7SEldad Zack 
143409d8e3a7SEldad Zack static int snd_c400_create_mixer(struct usb_mixer_interface *mixer)
143509d8e3a7SEldad Zack {
143609d8e3a7SEldad Zack 	int err;
143709d8e3a7SEldad Zack 
143809d8e3a7SEldad Zack 	err = snd_c400_create_vol_ctls(mixer);
143909d8e3a7SEldad Zack 	if (err < 0)
144009d8e3a7SEldad Zack 		return err;
144109d8e3a7SEldad Zack 
144209d8e3a7SEldad Zack 	err = snd_c400_create_effect_vol_ctls(mixer);
144309d8e3a7SEldad Zack 	if (err < 0)
144409d8e3a7SEldad Zack 		return err;
144509d8e3a7SEldad Zack 
144609d8e3a7SEldad Zack 	err = snd_c400_create_effect_ret_vol_ctls(mixer);
144709d8e3a7SEldad Zack 	if (err < 0)
144809d8e3a7SEldad Zack 		return err;
144909d8e3a7SEldad Zack 
145009d8e3a7SEldad Zack 	err = snd_ftu_create_effect_switch(mixer, 2, 0x43);
145109d8e3a7SEldad Zack 	if (err < 0)
145209d8e3a7SEldad Zack 		return err;
145309d8e3a7SEldad Zack 
145409d8e3a7SEldad Zack 	err = snd_c400_create_effect_volume_ctl(mixer);
145509d8e3a7SEldad Zack 	if (err < 0)
145609d8e3a7SEldad Zack 		return err;
145709d8e3a7SEldad Zack 
145809d8e3a7SEldad Zack 	err = snd_c400_create_effect_duration_ctl(mixer);
145909d8e3a7SEldad Zack 	if (err < 0)
146009d8e3a7SEldad Zack 		return err;
146109d8e3a7SEldad Zack 
146209d8e3a7SEldad Zack 	err = snd_c400_create_effect_feedback_ctl(mixer);
146309d8e3a7SEldad Zack 	if (err < 0)
146409d8e3a7SEldad Zack 		return err;
146509d8e3a7SEldad Zack 
146609d8e3a7SEldad Zack 	return 0;
146709d8e3a7SEldad Zack }
146809d8e3a7SEldad Zack 
1469b71dad18SMark Hills /*
1470b71dad18SMark Hills  * The mixer units for Ebox-44 are corrupt, and even where they
1471b71dad18SMark Hills  * are valid they presents mono controls as L and R channels of
1472b71dad18SMark Hills  * stereo. So we provide a good mixer here.
1473b71dad18SMark Hills  */
1474e8e7da23SSachin Kamat static struct std_mono_table ebox44_table[] = {
1475989b0138SMark Hills 	{
1476989b0138SMark Hills 		.unitid = 4,
1477989b0138SMark Hills 		.control = 1,
1478989b0138SMark Hills 		.cmask = 0x0,
1479989b0138SMark Hills 		.val_type = USB_MIXER_INV_BOOLEAN,
1480989b0138SMark Hills 		.name = "Headphone Playback Switch"
1481989b0138SMark Hills 	},
1482989b0138SMark Hills 	{
1483989b0138SMark Hills 		.unitid = 4,
1484989b0138SMark Hills 		.control = 2,
1485989b0138SMark Hills 		.cmask = 0x1,
1486989b0138SMark Hills 		.val_type = USB_MIXER_S16,
1487989b0138SMark Hills 		.name = "Headphone A Mix Playback Volume"
1488989b0138SMark Hills 	},
1489989b0138SMark Hills 	{
1490989b0138SMark Hills 		.unitid = 4,
1491989b0138SMark Hills 		.control = 2,
1492989b0138SMark Hills 		.cmask = 0x2,
1493989b0138SMark Hills 		.val_type = USB_MIXER_S16,
1494989b0138SMark Hills 		.name = "Headphone B Mix Playback Volume"
1495989b0138SMark Hills 	},
1496b71dad18SMark Hills 
1497989b0138SMark Hills 	{
1498989b0138SMark Hills 		.unitid = 7,
1499989b0138SMark Hills 		.control = 1,
1500989b0138SMark Hills 		.cmask = 0x0,
1501989b0138SMark Hills 		.val_type = USB_MIXER_INV_BOOLEAN,
1502989b0138SMark Hills 		.name = "Output Playback Switch"
1503989b0138SMark Hills 	},
1504989b0138SMark Hills 	{
1505989b0138SMark Hills 		.unitid = 7,
1506989b0138SMark Hills 		.control = 2,
1507989b0138SMark Hills 		.cmask = 0x1,
1508989b0138SMark Hills 		.val_type = USB_MIXER_S16,
1509989b0138SMark Hills 		.name = "Output A Playback Volume"
1510989b0138SMark Hills 	},
1511989b0138SMark Hills 	{
1512989b0138SMark Hills 		.unitid = 7,
1513989b0138SMark Hills 		.control = 2,
1514989b0138SMark Hills 		.cmask = 0x2,
1515989b0138SMark Hills 		.val_type = USB_MIXER_S16,
1516989b0138SMark Hills 		.name = "Output B Playback Volume"
1517989b0138SMark Hills 	},
1518b71dad18SMark Hills 
1519989b0138SMark Hills 	{
1520989b0138SMark Hills 		.unitid = 10,
1521989b0138SMark Hills 		.control = 1,
1522989b0138SMark Hills 		.cmask = 0x0,
1523989b0138SMark Hills 		.val_type = USB_MIXER_INV_BOOLEAN,
1524989b0138SMark Hills 		.name = "Input Capture Switch"
1525989b0138SMark Hills 	},
1526989b0138SMark Hills 	{
1527989b0138SMark Hills 		.unitid = 10,
1528989b0138SMark Hills 		.control = 2,
1529989b0138SMark Hills 		.cmask = 0x1,
1530989b0138SMark Hills 		.val_type = USB_MIXER_S16,
1531989b0138SMark Hills 		.name = "Input A Capture Volume"
1532989b0138SMark Hills 	},
1533989b0138SMark Hills 	{
1534989b0138SMark Hills 		.unitid = 10,
1535989b0138SMark Hills 		.control = 2,
1536989b0138SMark Hills 		.cmask = 0x2,
1537989b0138SMark Hills 		.val_type = USB_MIXER_S16,
1538989b0138SMark Hills 		.name = "Input B Capture Volume"
1539989b0138SMark Hills 	},
1540b71dad18SMark Hills 
1541b71dad18SMark Hills 	{}
1542b71dad18SMark Hills };
1543b71dad18SMark Hills 
1544066624c6SPrzemek Rudy /* Audio Advantage Micro II findings:
1545066624c6SPrzemek Rudy  *
1546066624c6SPrzemek Rudy  * Mapping spdif AES bits to vendor register.bit:
1547066624c6SPrzemek Rudy  * AES0: [0 0 0 0 2.3 2.2 2.1 2.0] - default 0x00
1548066624c6SPrzemek Rudy  * AES1: [3.3 3.2.3.1.3.0 2.7 2.6 2.5 2.4] - default: 0x01
1549066624c6SPrzemek Rudy  * AES2: [0 0 0 0 0 0 0 0]
1550066624c6SPrzemek Rudy  * AES3: [0 0 0 0 0 0 x 0] - 'x' bit is set basing on standard usb request
1551066624c6SPrzemek Rudy  *                           (UAC_EP_CS_ATTR_SAMPLE_RATE) for Audio Devices
1552066624c6SPrzemek Rudy  *
1553066624c6SPrzemek Rudy  * power on values:
1554066624c6SPrzemek Rudy  * r2: 0x10
1555066624c6SPrzemek Rudy  * r3: 0x20 (b7 is zeroed just before playback (except IEC61937) and set
1556066624c6SPrzemek Rudy  *           just after it to 0xa0, presumably it disables/mutes some analog
1557066624c6SPrzemek Rudy  *           parts when there is no audio.)
1558066624c6SPrzemek Rudy  * r9: 0x28
1559066624c6SPrzemek Rudy  *
1560066624c6SPrzemek Rudy  * Optical transmitter on/off:
1561066624c6SPrzemek Rudy  * vendor register.bit: 9.1
1562066624c6SPrzemek Rudy  * 0 - on (0x28 register value)
1563066624c6SPrzemek Rudy  * 1 - off (0x2a register value)
1564066624c6SPrzemek Rudy  *
1565066624c6SPrzemek Rudy  */
1566066624c6SPrzemek Rudy static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol,
1567066624c6SPrzemek Rudy 	struct snd_ctl_elem_info *uinfo)
1568066624c6SPrzemek Rudy {
1569066624c6SPrzemek Rudy 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
1570066624c6SPrzemek Rudy 	uinfo->count = 1;
1571066624c6SPrzemek Rudy 	return 0;
1572066624c6SPrzemek Rudy }
1573066624c6SPrzemek Rudy 
1574066624c6SPrzemek Rudy static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
1575066624c6SPrzemek Rudy 	struct snd_ctl_elem_value *ucontrol)
1576066624c6SPrzemek Rudy {
1577066624c6SPrzemek Rudy 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
1578066624c6SPrzemek Rudy 	int err;
1579066624c6SPrzemek Rudy 	struct usb_interface *iface;
1580066624c6SPrzemek Rudy 	struct usb_host_interface *alts;
1581066624c6SPrzemek Rudy 	unsigned int ep;
1582066624c6SPrzemek Rudy 	unsigned char data[3];
1583066624c6SPrzemek Rudy 	int rate;
1584066624c6SPrzemek Rudy 
1585066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff;
1586066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff;
1587066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[2] = 0x00;
1588066624c6SPrzemek Rudy 
1589066624c6SPrzemek Rudy 	/* use known values for that card: interface#1 altsetting#1 */
1590066624c6SPrzemek Rudy 	iface = usb_ifnum_to_if(mixer->chip->dev, 1);
1591066624c6SPrzemek Rudy 	alts = &iface->altsetting[1];
1592066624c6SPrzemek Rudy 	ep = get_endpoint(alts, 0)->bEndpointAddress;
1593066624c6SPrzemek Rudy 
1594066624c6SPrzemek Rudy 	err = snd_usb_ctl_msg(mixer->chip->dev,
1595066624c6SPrzemek Rudy 			usb_rcvctrlpipe(mixer->chip->dev, 0),
1596066624c6SPrzemek Rudy 			UAC_GET_CUR,
1597066624c6SPrzemek Rudy 			USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
1598066624c6SPrzemek Rudy 			UAC_EP_CS_ATTR_SAMPLE_RATE << 8,
1599066624c6SPrzemek Rudy 			ep,
1600066624c6SPrzemek Rudy 			data,
1601066624c6SPrzemek Rudy 			sizeof(data));
1602066624c6SPrzemek Rudy 	if (err < 0)
1603066624c6SPrzemek Rudy 		goto end;
1604066624c6SPrzemek Rudy 
1605066624c6SPrzemek Rudy 	rate = data[0] | (data[1] << 8) | (data[2] << 16);
1606066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[3] = (rate == 48000) ?
1607066624c6SPrzemek Rudy 			IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100;
1608066624c6SPrzemek Rudy 
1609066624c6SPrzemek Rudy 	err = 0;
1610066624c6SPrzemek Rudy end:
1611066624c6SPrzemek Rudy 	return err;
1612066624c6SPrzemek Rudy }
1613066624c6SPrzemek Rudy 
1614066624c6SPrzemek Rudy static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
1615066624c6SPrzemek Rudy 	struct snd_ctl_elem_value *ucontrol)
1616066624c6SPrzemek Rudy {
1617066624c6SPrzemek Rudy 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
1618066624c6SPrzemek Rudy 	int err;
1619066624c6SPrzemek Rudy 	u8 reg;
1620066624c6SPrzemek Rudy 	unsigned long priv_backup = kcontrol->private_value;
1621066624c6SPrzemek Rudy 
1622066624c6SPrzemek Rudy 	reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) |
1623066624c6SPrzemek Rudy 			(ucontrol->value.iec958.status[0] & 0x0f);
1624066624c6SPrzemek Rudy 	err = snd_usb_ctl_msg(mixer->chip->dev,
1625066624c6SPrzemek Rudy 			usb_sndctrlpipe(mixer->chip->dev, 0),
1626066624c6SPrzemek Rudy 			UAC_SET_CUR,
1627066624c6SPrzemek Rudy 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
1628066624c6SPrzemek Rudy 			reg,
1629066624c6SPrzemek Rudy 			2,
1630066624c6SPrzemek Rudy 			NULL,
1631066624c6SPrzemek Rudy 			0);
1632066624c6SPrzemek Rudy 	if (err < 0)
1633066624c6SPrzemek Rudy 		goto end;
1634066624c6SPrzemek Rudy 
1635066624c6SPrzemek Rudy 	kcontrol->private_value &= 0xfffff0f0;
1636066624c6SPrzemek Rudy 	kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8;
1637066624c6SPrzemek Rudy 	kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f);
1638066624c6SPrzemek Rudy 
1639066624c6SPrzemek Rudy 	reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ?
1640066624c6SPrzemek Rudy 			0xa0 : 0x20;
1641066624c6SPrzemek Rudy 	reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f;
1642066624c6SPrzemek Rudy 	err = snd_usb_ctl_msg(mixer->chip->dev,
1643066624c6SPrzemek Rudy 			usb_sndctrlpipe(mixer->chip->dev, 0),
1644066624c6SPrzemek Rudy 			UAC_SET_CUR,
1645066624c6SPrzemek Rudy 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
1646066624c6SPrzemek Rudy 			reg,
1647066624c6SPrzemek Rudy 			3,
1648066624c6SPrzemek Rudy 			NULL,
1649066624c6SPrzemek Rudy 			0);
1650066624c6SPrzemek Rudy 	if (err < 0)
1651066624c6SPrzemek Rudy 		goto end;
1652066624c6SPrzemek Rudy 
1653066624c6SPrzemek Rudy 	kcontrol->private_value &= 0xffff0fff;
1654066624c6SPrzemek Rudy 	kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8;
1655066624c6SPrzemek Rudy 
1656066624c6SPrzemek Rudy 	/* The frequency bits in AES3 cannot be set via register access. */
1657066624c6SPrzemek Rudy 
1658066624c6SPrzemek Rudy 	/* Silently ignore any bits from the request that cannot be set. */
1659066624c6SPrzemek Rudy 
1660066624c6SPrzemek Rudy 	err = (priv_backup != kcontrol->private_value);
1661066624c6SPrzemek Rudy end:
1662066624c6SPrzemek Rudy 	return err;
1663066624c6SPrzemek Rudy }
1664066624c6SPrzemek Rudy 
1665066624c6SPrzemek Rudy static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol,
1666066624c6SPrzemek Rudy 	struct snd_ctl_elem_value *ucontrol)
1667066624c6SPrzemek Rudy {
1668066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[0] = 0x0f;
1669066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[1] = 0xff;
1670066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[2] = 0x00;
1671066624c6SPrzemek Rudy 	ucontrol->value.iec958.status[3] = 0x00;
1672066624c6SPrzemek Rudy 
1673066624c6SPrzemek Rudy 	return 0;
1674066624c6SPrzemek Rudy }
1675066624c6SPrzemek Rudy 
1676066624c6SPrzemek Rudy static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol,
1677066624c6SPrzemek Rudy 	struct snd_ctl_elem_value *ucontrol)
1678066624c6SPrzemek Rudy {
1679066624c6SPrzemek Rudy 	ucontrol->value.integer.value[0] = !(kcontrol->private_value & 0x02);
1680066624c6SPrzemek Rudy 
1681066624c6SPrzemek Rudy 	return 0;
1682066624c6SPrzemek Rudy }
1683066624c6SPrzemek Rudy 
1684066624c6SPrzemek Rudy static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
1685066624c6SPrzemek Rudy 	struct snd_ctl_elem_value *ucontrol)
1686066624c6SPrzemek Rudy {
1687066624c6SPrzemek Rudy 	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
1688066624c6SPrzemek Rudy 	int err;
1689066624c6SPrzemek Rudy 	u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
1690066624c6SPrzemek Rudy 
1691066624c6SPrzemek Rudy 	err = snd_usb_ctl_msg(mixer->chip->dev,
1692066624c6SPrzemek Rudy 			usb_sndctrlpipe(mixer->chip->dev, 0),
1693066624c6SPrzemek Rudy 			UAC_SET_CUR,
1694066624c6SPrzemek Rudy 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
1695066624c6SPrzemek Rudy 			reg,
1696066624c6SPrzemek Rudy 			9,
1697066624c6SPrzemek Rudy 			NULL,
1698066624c6SPrzemek Rudy 			0);
1699066624c6SPrzemek Rudy 
1700066624c6SPrzemek Rudy 	if (!err) {
1701066624c6SPrzemek Rudy 		err = (reg != (kcontrol->private_value & 0x0ff));
1702066624c6SPrzemek Rudy 		if (err)
1703066624c6SPrzemek Rudy 			kcontrol->private_value = reg;
1704066624c6SPrzemek Rudy 	}
1705066624c6SPrzemek Rudy 
1706066624c6SPrzemek Rudy 	return err;
1707066624c6SPrzemek Rudy }
1708066624c6SPrzemek Rudy 
1709066624c6SPrzemek Rudy static struct snd_kcontrol_new snd_microii_mixer_spdif[] = {
1710066624c6SPrzemek Rudy 	{
1711066624c6SPrzemek Rudy 		.iface =    SNDRV_CTL_ELEM_IFACE_PCM,
1712066624c6SPrzemek Rudy 		.name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
1713066624c6SPrzemek Rudy 		.info =     snd_microii_spdif_info,
1714066624c6SPrzemek Rudy 		.get =      snd_microii_spdif_default_get,
1715066624c6SPrzemek Rudy 		.put =      snd_microii_spdif_default_put,
1716066624c6SPrzemek Rudy 		.private_value = 0x00000100UL,/* reset value */
1717066624c6SPrzemek Rudy 	},
1718066624c6SPrzemek Rudy 	{
1719066624c6SPrzemek Rudy 		.access =   SNDRV_CTL_ELEM_ACCESS_READ,
1720066624c6SPrzemek Rudy 		.iface =    SNDRV_CTL_ELEM_IFACE_PCM,
1721066624c6SPrzemek Rudy 		.name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
1722066624c6SPrzemek Rudy 		.info =     snd_microii_spdif_info,
1723066624c6SPrzemek Rudy 		.get =      snd_microii_spdif_mask_get,
1724066624c6SPrzemek Rudy 	},
1725066624c6SPrzemek Rudy 	{
1726066624c6SPrzemek Rudy 		.iface =    SNDRV_CTL_ELEM_IFACE_MIXER,
1727066624c6SPrzemek Rudy 		.name =     SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
1728066624c6SPrzemek Rudy 		.info =     snd_ctl_boolean_mono_info,
1729066624c6SPrzemek Rudy 		.get =      snd_microii_spdif_switch_get,
1730066624c6SPrzemek Rudy 		.put =      snd_microii_spdif_switch_put,
1731066624c6SPrzemek Rudy 		.private_value = 0x00000028UL,/* reset value */
1732066624c6SPrzemek Rudy 	}
1733066624c6SPrzemek Rudy };
1734066624c6SPrzemek Rudy 
1735066624c6SPrzemek Rudy static int snd_microii_controls_create(struct usb_mixer_interface *mixer)
1736066624c6SPrzemek Rudy {
1737066624c6SPrzemek Rudy 	int err, i;
1738066624c6SPrzemek Rudy 
1739066624c6SPrzemek Rudy 	for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) {
1740066624c6SPrzemek Rudy 		err = snd_ctl_add(mixer->chip->card,
1741066624c6SPrzemek Rudy 			snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer));
1742066624c6SPrzemek Rudy 		if (err < 0)
1743066624c6SPrzemek Rudy 			return err;
1744066624c6SPrzemek Rudy 	}
1745066624c6SPrzemek Rudy 
174618e4753fSMikulas Patocka 	return 0;
1747066624c6SPrzemek Rudy }
1748066624c6SPrzemek Rudy 
17497b1eda22SDaniel Mack int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
17507b1eda22SDaniel Mack {
17513347b26cSDaniel Mack 	int err = 0;
17527b1eda22SDaniel Mack 	struct snd_info_entry *entry;
17537b1eda22SDaniel Mack 
17547b1eda22SDaniel Mack 	if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0)
17557b1eda22SDaniel Mack 		return err;
17567b1eda22SDaniel Mack 
17573347b26cSDaniel Mack 	switch (mixer->chip->usb_id) {
17583347b26cSDaniel Mack 	case USB_ID(0x041e, 0x3020):
17593347b26cSDaniel Mack 	case USB_ID(0x041e, 0x3040):
17603347b26cSDaniel Mack 	case USB_ID(0x041e, 0x3042):
17617cdd8d73SMathieu Bouffard 	case USB_ID(0x041e, 0x30df):
17623347b26cSDaniel Mack 	case USB_ID(0x041e, 0x3048):
17633347b26cSDaniel Mack 		err = snd_audigy2nx_controls_create(mixer);
17643347b26cSDaniel Mack 		if (err < 0)
17653347b26cSDaniel Mack 			break;
17667b1eda22SDaniel Mack 		if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry))
17677b1eda22SDaniel Mack 			snd_info_set_text_ops(entry, mixer,
17687b1eda22SDaniel Mack 					      snd_audigy2nx_proc_read);
17693347b26cSDaniel Mack 		break;
17707b1eda22SDaniel Mack 
177144832a71SVasily Khoruzhick 	/* EMU0204 */
177244832a71SVasily Khoruzhick 	case USB_ID(0x041e, 0x3f19):
177344832a71SVasily Khoruzhick 		err = snd_emu0204_controls_create(mixer);
177444832a71SVasily Khoruzhick 		if (err < 0)
177544832a71SVasily Khoruzhick 			break;
177644832a71SVasily Khoruzhick 		break;
177744832a71SVasily Khoruzhick 
177809d8e3a7SEldad Zack 	case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
1779e9a25e04SMatt Gruskin 	case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C400 */
178009d8e3a7SEldad Zack 		err = snd_c400_create_mixer(mixer);
178109d8e3a7SEldad Zack 		break;
178209d8e3a7SEldad Zack 
1783d5a0bf6cSDaniel Mack 	case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
1784d5a0bf6cSDaniel Mack 	case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
1785cfe8f97cSFelix Homann 		err = snd_ftu_create_mixer(mixer);
1786d5a0bf6cSDaniel Mack 		break;
1787d5a0bf6cSDaniel Mack 
17881d31affbSDenis Washington 	case USB_ID(0x0b05, 0x1739): /* ASUS Xonar U1 */
17891d31affbSDenis Washington 	case USB_ID(0x0b05, 0x1743): /* ASUS Xonar U1 (2) */
17901d31affbSDenis Washington 	case USB_ID(0x0b05, 0x17a0): /* ASUS Xonar U3 */
17917b1eda22SDaniel Mack 		err = snd_xonar_u1_controls_create(mixer);
17923347b26cSDaniel Mack 		break;
17937b1eda22SDaniel Mack 
1794066624c6SPrzemek Rudy 	case USB_ID(0x0d8c, 0x0103): /* Audio Advantage Micro II */
1795066624c6SPrzemek Rudy 		err = snd_microii_controls_create(mixer);
1796066624c6SPrzemek Rudy 		break;
1797066624c6SPrzemek Rudy 
1798d497a82fSDamien Zammit 	case USB_ID(0x0dba, 0x1000): /* Digidesign Mbox 1 */
1799d497a82fSDamien Zammit 		err = snd_mbox1_create_sync_switch(mixer);
1800d497a82fSDamien Zammit 		break;
1801d497a82fSDamien Zammit 
18023347b26cSDaniel Mack 	case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */
180354a8c500SDaniel Mack 		err = snd_nativeinstruments_create_mixer(mixer,
180454a8c500SDaniel Mack 				snd_nativeinstruments_ta6_mixers,
180554a8c500SDaniel Mack 				ARRAY_SIZE(snd_nativeinstruments_ta6_mixers));
18063347b26cSDaniel Mack 		break;
180754a8c500SDaniel Mack 
18083347b26cSDaniel Mack 	case USB_ID(0x17cc, 0x1021): /* Traktor Audio 10 */
180954a8c500SDaniel Mack 		err = snd_nativeinstruments_create_mixer(mixer,
181054a8c500SDaniel Mack 				snd_nativeinstruments_ta10_mixers,
181154a8c500SDaniel Mack 				ARRAY_SIZE(snd_nativeinstruments_ta10_mixers));
18123347b26cSDaniel Mack 		break;
18137536c301SMark Hills 
18147536c301SMark Hills 	case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */
1815b71dad18SMark Hills 		/* detection is disabled in mixer_maps.c */
1816b71dad18SMark Hills 		err = snd_create_std_mono_table(mixer, ebox44_table);
18177536c301SMark Hills 		break;
181876b188c4SChris J Arges 
181976b188c4SChris J Arges 	case USB_ID(0x1235, 0x8012): /* Focusrite Scarlett 6i6 */
182076b188c4SChris J Arges 	case USB_ID(0x1235, 0x8002): /* Focusrite Scarlett 8i6 */
182176b188c4SChris J Arges 	case USB_ID(0x1235, 0x8004): /* Focusrite Scarlett 18i6 */
182276b188c4SChris J Arges 	case USB_ID(0x1235, 0x8014): /* Focusrite Scarlett 18i8 */
182376b188c4SChris J Arges 	case USB_ID(0x1235, 0x800c): /* Focusrite Scarlett 18i20 */
182476b188c4SChris J Arges 		err = snd_scarlett_controls_create(mixer);
182576b188c4SChris J Arges 		break;
182654a8c500SDaniel Mack 	}
182754a8c500SDaniel Mack 
18283347b26cSDaniel Mack 	return err;
18297b1eda22SDaniel Mack }
18307b1eda22SDaniel Mack 
18317b1eda22SDaniel Mack void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
18327b1eda22SDaniel Mack 				    int unitid)
18337b1eda22SDaniel Mack {
18347b1eda22SDaniel Mack 	if (!mixer->rc_cfg)
18357b1eda22SDaniel Mack 		return;
18367b1eda22SDaniel Mack 	/* unit ids specific to Extigy/Audigy 2 NX: */
18377b1eda22SDaniel Mack 	switch (unitid) {
18387b1eda22SDaniel Mack 	case 0: /* remote control */
18397b1eda22SDaniel Mack 		mixer->rc_urb->dev = mixer->chip->dev;
18407b1eda22SDaniel Mack 		usb_submit_urb(mixer->rc_urb, GFP_ATOMIC);
18417b1eda22SDaniel Mack 		break;
18427b1eda22SDaniel Mack 	case 4: /* digital in jack */
18437b1eda22SDaniel Mack 	case 7: /* line in jacks */
18447b1eda22SDaniel Mack 	case 19: /* speaker out jacks */
18457b1eda22SDaniel Mack 	case 20: /* headphones out jack */
18467b1eda22SDaniel Mack 		break;
18477b1eda22SDaniel Mack 	/* live24ext: 4 = line-in jack */
18487b1eda22SDaniel Mack 	case 3:	/* hp-out jack (may actuate Mute) */
18497b1eda22SDaniel Mack 		if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
18507b1eda22SDaniel Mack 		    mixer->chip->usb_id == USB_ID(0x041e, 0x3048))
18517b1eda22SDaniel Mack 			snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id);
18527b1eda22SDaniel Mack 		break;
18537b1eda22SDaniel Mack 	default:
18540ba41d91STakashi Iwai 		usb_audio_dbg(mixer->chip, "memory change in unknown unit %d\n", unitid);
18557b1eda22SDaniel Mack 		break;
18567b1eda22SDaniel Mack 	}
18577b1eda22SDaniel Mack }
18587b1eda22SDaniel Mack 
1859