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