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