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 * 127b1eda22SDaniel Mack * 137b1eda22SDaniel Mack * This program is free software; you can redistribute it and/or modify 147b1eda22SDaniel Mack * it under the terms of the GNU General Public License as published by 157b1eda22SDaniel Mack * the Free Software Foundation; either version 2 of the License, or 167b1eda22SDaniel Mack * (at your option) any later version. 177b1eda22SDaniel Mack * 187b1eda22SDaniel Mack * This program is distributed in the hope that it will be useful, 197b1eda22SDaniel Mack * but WITHOUT ANY WARRANTY; without even the implied warranty of 207b1eda22SDaniel Mack * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 217b1eda22SDaniel Mack * GNU General Public License for more details. 227b1eda22SDaniel Mack * 237b1eda22SDaniel Mack * You should have received a copy of the GNU General Public License 247b1eda22SDaniel Mack * along with this program; if not, write to the Free Software 257b1eda22SDaniel Mack * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 267b1eda22SDaniel Mack */ 277b1eda22SDaniel Mack 287b1eda22SDaniel Mack #include <linux/init.h> 2936db0456SStephen Rothwell #include <linux/slab.h> 307b1eda22SDaniel Mack #include <linux/usb.h> 317b1eda22SDaniel Mack #include <linux/usb/audio.h> 327b1eda22SDaniel Mack 337b1eda22SDaniel Mack #include <sound/core.h> 347b1eda22SDaniel Mack #include <sound/control.h> 357b1eda22SDaniel Mack #include <sound/hwdep.h> 367b1eda22SDaniel Mack #include <sound/info.h> 377b1eda22SDaniel Mack 387b1eda22SDaniel Mack #include "usbaudio.h" 39f0b5e634SDaniel Mack #include "mixer.h" 407b1eda22SDaniel Mack #include "mixer_quirks.h" 417b1eda22SDaniel Mack #include "helper.h" 427b1eda22SDaniel Mack 43d5a0bf6cSDaniel Mack extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl; 44d5a0bf6cSDaniel Mack 45b71dad18SMark Hills struct std_mono_table { 46b71dad18SMark Hills unsigned int unitid, control, cmask; 47b71dad18SMark Hills int val_type; 48b71dad18SMark Hills const char *name; 49b71dad18SMark Hills snd_kcontrol_tlv_rw_t *tlv_callback; 50b71dad18SMark Hills }; 51b71dad18SMark Hills 528a4d1d39SFelix Homann /* private_free callback */ 538a4d1d39SFelix Homann static void usb_mixer_elem_free(struct snd_kcontrol *kctl) 548a4d1d39SFelix Homann { 558a4d1d39SFelix Homann kfree(kctl->private_data); 568a4d1d39SFelix Homann kctl->private_data = NULL; 578a4d1d39SFelix Homann } 588a4d1d39SFelix Homann 598a4d1d39SFelix Homann /* This function allows for the creation of standard UAC controls. 608a4d1d39SFelix Homann * See the quirks for M-Audio FTUs or Ebox-44. 618a4d1d39SFelix Homann * If you don't want to set a TLV callback pass NULL. 628a4d1d39SFelix Homann * 638a4d1d39SFelix Homann * Since there doesn't seem to be a devices that needs a multichannel 648a4d1d39SFelix Homann * version, we keep it mono for simplicity. 658a4d1d39SFelix Homann */ 668a4d1d39SFelix Homann static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, 678a4d1d39SFelix Homann unsigned int unitid, 688a4d1d39SFelix Homann unsigned int control, 698a4d1d39SFelix Homann unsigned int cmask, 708a4d1d39SFelix Homann int val_type, 718a4d1d39SFelix Homann const char *name, 728a4d1d39SFelix Homann snd_kcontrol_tlv_rw_t *tlv_callback) 738a4d1d39SFelix Homann { 748a4d1d39SFelix Homann int err; 758a4d1d39SFelix Homann struct usb_mixer_elem_info *cval; 768a4d1d39SFelix Homann struct snd_kcontrol *kctl; 778a4d1d39SFelix Homann 788a4d1d39SFelix Homann cval = kzalloc(sizeof(*cval), GFP_KERNEL); 798a4d1d39SFelix Homann if (!cval) 808a4d1d39SFelix Homann return -ENOMEM; 818a4d1d39SFelix Homann 828a4d1d39SFelix Homann cval->id = unitid; 838a4d1d39SFelix Homann cval->mixer = mixer; 848a4d1d39SFelix Homann cval->val_type = val_type; 858a4d1d39SFelix Homann cval->channels = 1; 868a4d1d39SFelix Homann cval->control = control; 878a4d1d39SFelix Homann cval->cmask = cmask; 888a4d1d39SFelix Homann 897df4a691SMark Hills /* get_min_max() is called only for integer volumes later, 907df4a691SMark Hills * so provide a short-cut for booleans */ 918a4d1d39SFelix Homann cval->min = 0; 928a4d1d39SFelix Homann cval->max = 1; 938a4d1d39SFelix Homann cval->res = 0; 948a4d1d39SFelix Homann cval->dBmin = 0; 958a4d1d39SFelix Homann cval->dBmax = 0; 968a4d1d39SFelix Homann 978a4d1d39SFelix Homann /* Create control */ 988a4d1d39SFelix Homann kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval); 998a4d1d39SFelix Homann if (!kctl) { 1008a4d1d39SFelix Homann kfree(cval); 1018a4d1d39SFelix Homann return -ENOMEM; 1028a4d1d39SFelix Homann } 1038a4d1d39SFelix Homann 1048a4d1d39SFelix Homann /* Set name */ 1058a4d1d39SFelix Homann snprintf(kctl->id.name, sizeof(kctl->id.name), name); 1068a4d1d39SFelix Homann kctl->private_free = usb_mixer_elem_free; 1078a4d1d39SFelix Homann 1088a4d1d39SFelix Homann /* set TLV */ 1098a4d1d39SFelix Homann if (tlv_callback) { 1108a4d1d39SFelix Homann kctl->tlv.c = tlv_callback; 1118a4d1d39SFelix Homann kctl->vd[0].access |= 1128a4d1d39SFelix Homann SNDRV_CTL_ELEM_ACCESS_TLV_READ | 1138a4d1d39SFelix Homann SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; 1148a4d1d39SFelix Homann } 1158a4d1d39SFelix Homann /* Add control to mixer */ 1168a4d1d39SFelix Homann err = snd_usb_mixer_add_control(mixer, kctl); 1178a4d1d39SFelix Homann if (err < 0) 1188a4d1d39SFelix Homann return err; 1198a4d1d39SFelix Homann 1208a4d1d39SFelix Homann return 0; 1218a4d1d39SFelix Homann } 1228a4d1d39SFelix Homann 1237b1eda22SDaniel Mack /* 124b71dad18SMark Hills * Create a set of standard UAC controls from a table 125b71dad18SMark Hills */ 126b71dad18SMark Hills static int snd_create_std_mono_table(struct usb_mixer_interface *mixer, 127b71dad18SMark Hills struct std_mono_table *t) 128b71dad18SMark Hills { 129b71dad18SMark Hills int err; 130b71dad18SMark Hills 131b71dad18SMark Hills while (t->name != NULL) { 132b71dad18SMark Hills err = snd_create_std_mono_ctl(mixer, t->unitid, t->control, 133b71dad18SMark Hills t->cmask, t->val_type, t->name, t->tlv_callback); 134b71dad18SMark Hills if (err < 0) 135b71dad18SMark Hills return err; 136b71dad18SMark Hills t++; 137b71dad18SMark Hills } 138b71dad18SMark Hills 139b71dad18SMark Hills return 0; 140b71dad18SMark Hills } 141b71dad18SMark Hills 142b71dad18SMark Hills /* 1437b1eda22SDaniel Mack * Sound Blaster remote control configuration 1447b1eda22SDaniel Mack * 1457b1eda22SDaniel Mack * format of remote control data: 1467b1eda22SDaniel Mack * Extigy: xx 00 1477b1eda22SDaniel Mack * Audigy 2 NX: 06 80 xx 00 00 00 1487b1eda22SDaniel Mack * Live! 24-bit: 06 80 xx yy 22 83 1497b1eda22SDaniel Mack */ 1507b1eda22SDaniel Mack static const struct rc_config { 1517b1eda22SDaniel Mack u32 usb_id; 1527b1eda22SDaniel Mack u8 offset; 1537b1eda22SDaniel Mack u8 length; 1547b1eda22SDaniel Mack u8 packet_length; 1557b1eda22SDaniel Mack u8 min_packet_length; /* minimum accepted length of the URB result */ 1567b1eda22SDaniel Mack u8 mute_mixer_id; 1577b1eda22SDaniel Mack u32 mute_code; 1587b1eda22SDaniel Mack } rc_configs[] = { 1597b1eda22SDaniel Mack { USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */ 1607b1eda22SDaniel Mack { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */ 1617b1eda22SDaniel Mack { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ 162ca8dc34eSMandar Joshi { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 */ 1637cdd8d73SMathieu Bouffard { USB_ID(0x041e, 0x30df), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ 1647b1eda22SDaniel Mack { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ 1657b1eda22SDaniel Mack }; 1667b1eda22SDaniel Mack 1677b1eda22SDaniel Mack static void snd_usb_soundblaster_remote_complete(struct urb *urb) 1687b1eda22SDaniel Mack { 1697b1eda22SDaniel Mack struct usb_mixer_interface *mixer = urb->context; 1707b1eda22SDaniel Mack const struct rc_config *rc = mixer->rc_cfg; 1717b1eda22SDaniel Mack u32 code; 1727b1eda22SDaniel Mack 1737b1eda22SDaniel Mack if (urb->status < 0 || urb->actual_length < rc->min_packet_length) 1747b1eda22SDaniel Mack return; 1757b1eda22SDaniel Mack 1767b1eda22SDaniel Mack code = mixer->rc_buffer[rc->offset]; 1777b1eda22SDaniel Mack if (rc->length == 2) 1787b1eda22SDaniel Mack code |= mixer->rc_buffer[rc->offset + 1] << 8; 1797b1eda22SDaniel Mack 1807b1eda22SDaniel Mack /* the Mute button actually changes the mixer control */ 1817b1eda22SDaniel Mack if (code == rc->mute_code) 1827b1eda22SDaniel Mack snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id); 1837b1eda22SDaniel Mack mixer->rc_code = code; 1847b1eda22SDaniel Mack wmb(); 1857b1eda22SDaniel Mack wake_up(&mixer->rc_waitq); 1867b1eda22SDaniel Mack } 1877b1eda22SDaniel Mack 1887b1eda22SDaniel Mack static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf, 1897b1eda22SDaniel Mack long count, loff_t *offset) 1907b1eda22SDaniel Mack { 1917b1eda22SDaniel Mack struct usb_mixer_interface *mixer = hw->private_data; 1927b1eda22SDaniel Mack int err; 1937b1eda22SDaniel Mack u32 rc_code; 1947b1eda22SDaniel Mack 1957b1eda22SDaniel Mack if (count != 1 && count != 4) 1967b1eda22SDaniel Mack return -EINVAL; 1977b1eda22SDaniel Mack err = wait_event_interruptible(mixer->rc_waitq, 1987b1eda22SDaniel Mack (rc_code = xchg(&mixer->rc_code, 0)) != 0); 1997b1eda22SDaniel Mack if (err == 0) { 2007b1eda22SDaniel Mack if (count == 1) 2017b1eda22SDaniel Mack err = put_user(rc_code, buf); 2027b1eda22SDaniel Mack else 2037b1eda22SDaniel Mack err = put_user(rc_code, (u32 __user *)buf); 2047b1eda22SDaniel Mack } 2057b1eda22SDaniel Mack return err < 0 ? err : count; 2067b1eda22SDaniel Mack } 2077b1eda22SDaniel Mack 2087b1eda22SDaniel Mack static unsigned int snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *file, 2097b1eda22SDaniel Mack poll_table *wait) 2107b1eda22SDaniel Mack { 2117b1eda22SDaniel Mack struct usb_mixer_interface *mixer = hw->private_data; 2127b1eda22SDaniel Mack 2137b1eda22SDaniel Mack poll_wait(file, &mixer->rc_waitq, wait); 2147b1eda22SDaniel Mack return mixer->rc_code ? POLLIN | POLLRDNORM : 0; 2157b1eda22SDaniel Mack } 2167b1eda22SDaniel Mack 2177b1eda22SDaniel Mack static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) 2187b1eda22SDaniel Mack { 2197b1eda22SDaniel Mack struct snd_hwdep *hwdep; 2207b1eda22SDaniel Mack int err, len, i; 2217b1eda22SDaniel Mack 2227b1eda22SDaniel Mack for (i = 0; i < ARRAY_SIZE(rc_configs); ++i) 2237b1eda22SDaniel Mack if (rc_configs[i].usb_id == mixer->chip->usb_id) 2247b1eda22SDaniel Mack break; 2257b1eda22SDaniel Mack if (i >= ARRAY_SIZE(rc_configs)) 2267b1eda22SDaniel Mack return 0; 2277b1eda22SDaniel Mack mixer->rc_cfg = &rc_configs[i]; 2287b1eda22SDaniel Mack 2297b1eda22SDaniel Mack len = mixer->rc_cfg->packet_length; 2307b1eda22SDaniel Mack 2317b1eda22SDaniel Mack init_waitqueue_head(&mixer->rc_waitq); 2327b1eda22SDaniel Mack err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep); 2337b1eda22SDaniel Mack if (err < 0) 2347b1eda22SDaniel Mack return err; 2357b1eda22SDaniel Mack snprintf(hwdep->name, sizeof(hwdep->name), 2367b1eda22SDaniel Mack "%s remote control", mixer->chip->card->shortname); 2377b1eda22SDaniel Mack hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC; 2387b1eda22SDaniel Mack hwdep->private_data = mixer; 2397b1eda22SDaniel Mack hwdep->ops.read = snd_usb_sbrc_hwdep_read; 2407b1eda22SDaniel Mack hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; 2417b1eda22SDaniel Mack hwdep->exclusive = 1; 2427b1eda22SDaniel Mack 2437b1eda22SDaniel Mack mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); 2447b1eda22SDaniel Mack if (!mixer->rc_urb) 2457b1eda22SDaniel Mack return -ENOMEM; 2467b1eda22SDaniel Mack mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL); 2477b1eda22SDaniel Mack if (!mixer->rc_setup_packet) { 2487b1eda22SDaniel Mack usb_free_urb(mixer->rc_urb); 2497b1eda22SDaniel Mack mixer->rc_urb = NULL; 2507b1eda22SDaniel Mack return -ENOMEM; 2517b1eda22SDaniel Mack } 2527b1eda22SDaniel Mack mixer->rc_setup_packet->bRequestType = 2537b1eda22SDaniel Mack USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; 2547b1eda22SDaniel Mack mixer->rc_setup_packet->bRequest = UAC_GET_MEM; 2557b1eda22SDaniel Mack mixer->rc_setup_packet->wValue = cpu_to_le16(0); 2567b1eda22SDaniel Mack mixer->rc_setup_packet->wIndex = cpu_to_le16(0); 2577b1eda22SDaniel Mack mixer->rc_setup_packet->wLength = cpu_to_le16(len); 2587b1eda22SDaniel Mack usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev, 2597b1eda22SDaniel Mack usb_rcvctrlpipe(mixer->chip->dev, 0), 2607b1eda22SDaniel Mack (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len, 2617b1eda22SDaniel Mack snd_usb_soundblaster_remote_complete, mixer); 2627b1eda22SDaniel Mack return 0; 2637b1eda22SDaniel Mack } 2647b1eda22SDaniel Mack 2657b1eda22SDaniel Mack #define snd_audigy2nx_led_info snd_ctl_boolean_mono_info 2667b1eda22SDaniel Mack 2677b1eda22SDaniel Mack static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2687b1eda22SDaniel Mack { 2697b1eda22SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 2707b1eda22SDaniel Mack int index = kcontrol->private_value; 2717b1eda22SDaniel Mack 2727b1eda22SDaniel Mack ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index]; 2737b1eda22SDaniel Mack return 0; 2747b1eda22SDaniel Mack } 2757b1eda22SDaniel Mack 2767b1eda22SDaniel Mack static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2777b1eda22SDaniel Mack { 2787b1eda22SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 2797b1eda22SDaniel Mack int index = kcontrol->private_value; 2807b1eda22SDaniel Mack int value = ucontrol->value.integer.value[0]; 2817b1eda22SDaniel Mack int err, changed; 2827b1eda22SDaniel Mack 2837b1eda22SDaniel Mack if (value > 1) 2847b1eda22SDaniel Mack return -EINVAL; 2857b1eda22SDaniel Mack changed = value != mixer->audigy2nx_leds[index]; 286888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 287888ea7d5STakashi Iwai if (mixer->chip->shutdown) { 288888ea7d5STakashi Iwai err = -ENODEV; 289888ea7d5STakashi Iwai goto out; 290888ea7d5STakashi Iwai } 291ca8dc34eSMandar Joshi if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) 292ca8dc34eSMandar Joshi err = snd_usb_ctl_msg(mixer->chip->dev, 293ca8dc34eSMandar Joshi usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, 294ca8dc34eSMandar Joshi USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 29517d900c4SClemens Ladisch !value, 0, NULL, 0); 2967cdd8d73SMathieu Bouffard /* USB X-Fi S51 Pro */ 2977cdd8d73SMathieu Bouffard if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) 2987cdd8d73SMathieu Bouffard err = snd_usb_ctl_msg(mixer->chip->dev, 2997cdd8d73SMathieu Bouffard usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, 3007cdd8d73SMathieu Bouffard USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 30117d900c4SClemens Ladisch !value, 0, NULL, 0); 302ca8dc34eSMandar Joshi else 3037b1eda22SDaniel Mack err = snd_usb_ctl_msg(mixer->chip->dev, 3047b1eda22SDaniel Mack usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, 3057b1eda22SDaniel Mack USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 30617d900c4SClemens Ladisch value, index + 2, NULL, 0); 307888ea7d5STakashi Iwai out: 308888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 3097b1eda22SDaniel Mack if (err < 0) 3107b1eda22SDaniel Mack return err; 3117b1eda22SDaniel Mack mixer->audigy2nx_leds[index] = value; 3127b1eda22SDaniel Mack return changed; 3137b1eda22SDaniel Mack } 3147b1eda22SDaniel Mack 3157b1eda22SDaniel Mack static struct snd_kcontrol_new snd_audigy2nx_controls[] = { 3167b1eda22SDaniel Mack { 3177b1eda22SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3187b1eda22SDaniel Mack .name = "CMSS LED Switch", 3197b1eda22SDaniel Mack .info = snd_audigy2nx_led_info, 3207b1eda22SDaniel Mack .get = snd_audigy2nx_led_get, 3217b1eda22SDaniel Mack .put = snd_audigy2nx_led_put, 3227b1eda22SDaniel Mack .private_value = 0, 3237b1eda22SDaniel Mack }, 3247b1eda22SDaniel Mack { 3257b1eda22SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3267b1eda22SDaniel Mack .name = "Power LED Switch", 3277b1eda22SDaniel Mack .info = snd_audigy2nx_led_info, 3287b1eda22SDaniel Mack .get = snd_audigy2nx_led_get, 3297b1eda22SDaniel Mack .put = snd_audigy2nx_led_put, 3307b1eda22SDaniel Mack .private_value = 1, 3317b1eda22SDaniel Mack }, 3327b1eda22SDaniel Mack { 3337b1eda22SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3347b1eda22SDaniel Mack .name = "Dolby Digital LED Switch", 3357b1eda22SDaniel Mack .info = snd_audigy2nx_led_info, 3367b1eda22SDaniel Mack .get = snd_audigy2nx_led_get, 3377b1eda22SDaniel Mack .put = snd_audigy2nx_led_put, 3387b1eda22SDaniel Mack .private_value = 2, 3397b1eda22SDaniel Mack }, 3407b1eda22SDaniel Mack }; 3417b1eda22SDaniel Mack 3427b1eda22SDaniel Mack static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) 3437b1eda22SDaniel Mack { 3447b1eda22SDaniel Mack int i, err; 3457b1eda22SDaniel Mack 3467b1eda22SDaniel Mack for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { 347ca8dc34eSMandar Joshi /* USB X-Fi S51 doesn't have a CMSS LED */ 348ca8dc34eSMandar Joshi if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0) 349ca8dc34eSMandar Joshi continue; 3507cdd8d73SMathieu Bouffard /* USB X-Fi S51 Pro doesn't have one either */ 3517cdd8d73SMathieu Bouffard if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0) 3527cdd8d73SMathieu Bouffard continue; 3537b1eda22SDaniel Mack if (i > 1 && /* Live24ext has 2 LEDs only */ 3547b1eda22SDaniel Mack (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 355ca8dc34eSMandar Joshi mixer->chip->usb_id == USB_ID(0x041e, 0x3042) || 3567cdd8d73SMathieu Bouffard mixer->chip->usb_id == USB_ID(0x041e, 0x30df) || 3577b1eda22SDaniel Mack mixer->chip->usb_id == USB_ID(0x041e, 0x3048))) 3587b1eda22SDaniel Mack break; 3597b1eda22SDaniel Mack err = snd_ctl_add(mixer->chip->card, 3607b1eda22SDaniel Mack snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); 3617b1eda22SDaniel Mack if (err < 0) 3627b1eda22SDaniel Mack return err; 3637b1eda22SDaniel Mack } 3647b1eda22SDaniel Mack mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */ 3657b1eda22SDaniel Mack return 0; 3667b1eda22SDaniel Mack } 3677b1eda22SDaniel Mack 3687b1eda22SDaniel Mack static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, 3697b1eda22SDaniel Mack struct snd_info_buffer *buffer) 3707b1eda22SDaniel Mack { 3717b1eda22SDaniel Mack static const struct sb_jack { 3727b1eda22SDaniel Mack int unitid; 3737b1eda22SDaniel Mack const char *name; 3747b1eda22SDaniel Mack } jacks_audigy2nx[] = { 3757b1eda22SDaniel Mack {4, "dig in "}, 3767b1eda22SDaniel Mack {7, "line in"}, 3777b1eda22SDaniel Mack {19, "spk out"}, 3787b1eda22SDaniel Mack {20, "hph out"}, 3797b1eda22SDaniel Mack {-1, NULL} 3807b1eda22SDaniel Mack }, jacks_live24ext[] = { 3817b1eda22SDaniel Mack {4, "line in"}, /* &1=Line, &2=Mic*/ 3827b1eda22SDaniel Mack {3, "hph out"}, /* headphones */ 3837b1eda22SDaniel Mack {0, "RC "}, /* last command, 6 bytes see rc_config above */ 3847b1eda22SDaniel Mack {-1, NULL} 3857b1eda22SDaniel Mack }; 3867b1eda22SDaniel Mack const struct sb_jack *jacks; 3877b1eda22SDaniel Mack struct usb_mixer_interface *mixer = entry->private_data; 3887b1eda22SDaniel Mack int i, err; 3897b1eda22SDaniel Mack u8 buf[3]; 3907b1eda22SDaniel Mack 3917b1eda22SDaniel Mack snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); 3927b1eda22SDaniel Mack if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) 3937b1eda22SDaniel Mack jacks = jacks_audigy2nx; 3947b1eda22SDaniel Mack else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 3957b1eda22SDaniel Mack mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) 3967b1eda22SDaniel Mack jacks = jacks_live24ext; 3977b1eda22SDaniel Mack else 3987b1eda22SDaniel Mack return; 3997b1eda22SDaniel Mack 4007b1eda22SDaniel Mack for (i = 0; jacks[i].name; ++i) { 4017b1eda22SDaniel Mack snd_iprintf(buffer, "%s: ", jacks[i].name); 402888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 403888ea7d5STakashi Iwai if (mixer->chip->shutdown) 404888ea7d5STakashi Iwai err = 0; 405888ea7d5STakashi Iwai else 4067b1eda22SDaniel Mack err = snd_usb_ctl_msg(mixer->chip->dev, 4077b1eda22SDaniel Mack usb_rcvctrlpipe(mixer->chip->dev, 0), 4087b1eda22SDaniel Mack UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | 4097b1eda22SDaniel Mack USB_RECIP_INTERFACE, 0, 41017d900c4SClemens Ladisch jacks[i].unitid << 8, buf, 3); 411888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 4127b1eda22SDaniel Mack if (err == 3 && (buf[0] == 3 || buf[0] == 6)) 4137b1eda22SDaniel Mack snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); 4147b1eda22SDaniel Mack else 4157b1eda22SDaniel Mack snd_iprintf(buffer, "?\n"); 4167b1eda22SDaniel Mack } 4177b1eda22SDaniel Mack } 4187b1eda22SDaniel Mack 4197b1eda22SDaniel Mack static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, 4207b1eda22SDaniel Mack struct snd_ctl_elem_value *ucontrol) 4217b1eda22SDaniel Mack { 4227b1eda22SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 4237b1eda22SDaniel Mack 4247b1eda22SDaniel Mack ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02); 4257b1eda22SDaniel Mack return 0; 4267b1eda22SDaniel Mack } 4277b1eda22SDaniel Mack 4287b1eda22SDaniel Mack static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, 4297b1eda22SDaniel Mack struct snd_ctl_elem_value *ucontrol) 4307b1eda22SDaniel Mack { 4317b1eda22SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 4327b1eda22SDaniel Mack u8 old_status, new_status; 4337b1eda22SDaniel Mack int err, changed; 4347b1eda22SDaniel Mack 4357b1eda22SDaniel Mack old_status = mixer->xonar_u1_status; 4367b1eda22SDaniel Mack if (ucontrol->value.integer.value[0]) 4377b1eda22SDaniel Mack new_status = old_status | 0x02; 4387b1eda22SDaniel Mack else 4397b1eda22SDaniel Mack new_status = old_status & ~0x02; 4407b1eda22SDaniel Mack changed = new_status != old_status; 441888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 442888ea7d5STakashi Iwai if (mixer->chip->shutdown) 443888ea7d5STakashi Iwai err = -ENODEV; 444888ea7d5STakashi Iwai else 4457b1eda22SDaniel Mack err = snd_usb_ctl_msg(mixer->chip->dev, 4467b1eda22SDaniel Mack usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, 4477b1eda22SDaniel Mack USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 44817d900c4SClemens Ladisch 50, 0, &new_status, 1); 449888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 4507b1eda22SDaniel Mack if (err < 0) 4517b1eda22SDaniel Mack return err; 4527b1eda22SDaniel Mack mixer->xonar_u1_status = new_status; 4537b1eda22SDaniel Mack return changed; 4547b1eda22SDaniel Mack } 4557b1eda22SDaniel Mack 4567b1eda22SDaniel Mack static struct snd_kcontrol_new snd_xonar_u1_output_switch = { 4577b1eda22SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4587b1eda22SDaniel Mack .name = "Digital Playback Switch", 4597b1eda22SDaniel Mack .info = snd_ctl_boolean_mono_info, 4607b1eda22SDaniel Mack .get = snd_xonar_u1_switch_get, 4617b1eda22SDaniel Mack .put = snd_xonar_u1_switch_put, 4627b1eda22SDaniel Mack }; 4637b1eda22SDaniel Mack 4647b1eda22SDaniel Mack static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) 4657b1eda22SDaniel Mack { 4667b1eda22SDaniel Mack int err; 4677b1eda22SDaniel Mack 4687b1eda22SDaniel Mack err = snd_ctl_add(mixer->chip->card, 4697b1eda22SDaniel Mack snd_ctl_new1(&snd_xonar_u1_output_switch, mixer)); 4707b1eda22SDaniel Mack if (err < 0) 4717b1eda22SDaniel Mack return err; 4727b1eda22SDaniel Mack mixer->xonar_u1_status = 0x05; 4737b1eda22SDaniel Mack return 0; 4747b1eda22SDaniel Mack } 4757b1eda22SDaniel Mack 47654a8c500SDaniel Mack /* Native Instruments device quirks */ 47754a8c500SDaniel Mack 47854a8c500SDaniel Mack #define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex)) 47954a8c500SDaniel Mack 48054a8c500SDaniel Mack static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, 48154a8c500SDaniel Mack struct snd_ctl_elem_value *ucontrol) 48254a8c500SDaniel Mack { 48354a8c500SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 48454a8c500SDaniel Mack struct usb_device *dev = mixer->chip->dev; 48554a8c500SDaniel Mack u8 bRequest = (kcontrol->private_value >> 16) & 0xff; 48654a8c500SDaniel Mack u16 wIndex = kcontrol->private_value & 0xffff; 48754a8c500SDaniel Mack u8 tmp; 488888ea7d5STakashi Iwai int ret; 48954a8c500SDaniel Mack 490888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 491888ea7d5STakashi Iwai if (mixer->chip->shutdown) 492888ea7d5STakashi Iwai ret = -ENODEV; 493888ea7d5STakashi Iwai else 494888ea7d5STakashi Iwai ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, 49554a8c500SDaniel Mack USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 49654a8c500SDaniel Mack 0, cpu_to_le16(wIndex), 49754a8c500SDaniel Mack &tmp, sizeof(tmp), 1000); 498888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 49954a8c500SDaniel Mack 50054a8c500SDaniel Mack if (ret < 0) { 50154a8c500SDaniel Mack snd_printk(KERN_ERR 50254a8c500SDaniel Mack "unable to issue vendor read request (ret = %d)", ret); 50354a8c500SDaniel Mack return ret; 50454a8c500SDaniel Mack } 50554a8c500SDaniel Mack 50654a8c500SDaniel Mack ucontrol->value.integer.value[0] = tmp; 50754a8c500SDaniel Mack 50854a8c500SDaniel Mack return 0; 50954a8c500SDaniel Mack } 51054a8c500SDaniel Mack 51154a8c500SDaniel Mack static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, 51254a8c500SDaniel Mack struct snd_ctl_elem_value *ucontrol) 51354a8c500SDaniel Mack { 51454a8c500SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 51554a8c500SDaniel Mack struct usb_device *dev = mixer->chip->dev; 51654a8c500SDaniel Mack u8 bRequest = (kcontrol->private_value >> 16) & 0xff; 51754a8c500SDaniel Mack u16 wIndex = kcontrol->private_value & 0xffff; 51854a8c500SDaniel Mack u16 wValue = ucontrol->value.integer.value[0]; 519888ea7d5STakashi Iwai int ret; 52054a8c500SDaniel Mack 521888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 522888ea7d5STakashi Iwai if (mixer->chip->shutdown) 523888ea7d5STakashi Iwai ret = -ENODEV; 524888ea7d5STakashi Iwai else 525888ea7d5STakashi Iwai ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, 52654a8c500SDaniel Mack USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 52754a8c500SDaniel Mack cpu_to_le16(wValue), cpu_to_le16(wIndex), 52854a8c500SDaniel Mack NULL, 0, 1000); 529888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 53054a8c500SDaniel Mack 53154a8c500SDaniel Mack if (ret < 0) { 53254a8c500SDaniel Mack snd_printk(KERN_ERR 53354a8c500SDaniel Mack "unable to issue vendor write request (ret = %d)", ret); 53454a8c500SDaniel Mack return ret; 53554a8c500SDaniel Mack } 53654a8c500SDaniel Mack 53754a8c500SDaniel Mack return 0; 53854a8c500SDaniel Mack } 53954a8c500SDaniel Mack 54054a8c500SDaniel Mack static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = { 54154a8c500SDaniel Mack { 54254a8c500SDaniel Mack .name = "Direct Thru Channel A", 54354a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x03), 54454a8c500SDaniel Mack }, 54554a8c500SDaniel Mack { 54654a8c500SDaniel Mack .name = "Direct Thru Channel B", 54754a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x05), 54854a8c500SDaniel Mack }, 54954a8c500SDaniel Mack { 55054a8c500SDaniel Mack .name = "Phono Input Channel A", 55154a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x03), 55254a8c500SDaniel Mack }, 55354a8c500SDaniel Mack { 55454a8c500SDaniel Mack .name = "Phono Input Channel B", 55554a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x05), 55654a8c500SDaniel Mack }, 55754a8c500SDaniel Mack }; 55854a8c500SDaniel Mack 55954a8c500SDaniel Mack static struct snd_kcontrol_new snd_nativeinstruments_ta10_mixers[] = { 56054a8c500SDaniel Mack { 56154a8c500SDaniel Mack .name = "Direct Thru Channel A", 56254a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x03), 56354a8c500SDaniel Mack }, 56454a8c500SDaniel Mack { 56554a8c500SDaniel Mack .name = "Direct Thru Channel B", 56654a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x05), 56754a8c500SDaniel Mack }, 56854a8c500SDaniel Mack { 56954a8c500SDaniel Mack .name = "Direct Thru Channel C", 57054a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x07), 57154a8c500SDaniel Mack }, 57254a8c500SDaniel Mack { 57354a8c500SDaniel Mack .name = "Direct Thru Channel D", 57454a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x09), 57554a8c500SDaniel Mack }, 57654a8c500SDaniel Mack { 57754a8c500SDaniel Mack .name = "Phono Input Channel A", 57854a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x03), 57954a8c500SDaniel Mack }, 58054a8c500SDaniel Mack { 58154a8c500SDaniel Mack .name = "Phono Input Channel B", 58254a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x05), 58354a8c500SDaniel Mack }, 58454a8c500SDaniel Mack { 58554a8c500SDaniel Mack .name = "Phono Input Channel C", 58654a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x07), 58754a8c500SDaniel Mack }, 58854a8c500SDaniel Mack { 58954a8c500SDaniel Mack .name = "Phono Input Channel D", 59054a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x09), 59154a8c500SDaniel Mack }, 59254a8c500SDaniel Mack }; 59354a8c500SDaniel Mack 59454a8c500SDaniel Mack static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, 59554a8c500SDaniel Mack const struct snd_kcontrol_new *kc, 59654a8c500SDaniel Mack unsigned int count) 59754a8c500SDaniel Mack { 59854a8c500SDaniel Mack int i, err = 0; 59954a8c500SDaniel Mack struct snd_kcontrol_new template = { 60054a8c500SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 60154a8c500SDaniel Mack .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 60254a8c500SDaniel Mack .get = snd_nativeinstruments_control_get, 60354a8c500SDaniel Mack .put = snd_nativeinstruments_control_put, 60454a8c500SDaniel Mack .info = snd_ctl_boolean_mono_info, 60554a8c500SDaniel Mack }; 60654a8c500SDaniel Mack 60754a8c500SDaniel Mack for (i = 0; i < count; i++) { 60854a8c500SDaniel Mack struct snd_kcontrol *c; 60954a8c500SDaniel Mack 61054a8c500SDaniel Mack template.name = kc[i].name; 61154a8c500SDaniel Mack template.private_value = kc[i].private_value; 61254a8c500SDaniel Mack 61354a8c500SDaniel Mack c = snd_ctl_new1(&template, mixer); 61454a8c500SDaniel Mack err = snd_ctl_add(mixer->chip->card, c); 61554a8c500SDaniel Mack 61654a8c500SDaniel Mack if (err < 0) 61754a8c500SDaniel Mack break; 61854a8c500SDaniel Mack } 61954a8c500SDaniel Mack 62054a8c500SDaniel Mack return err; 62154a8c500SDaniel Mack } 62254a8c500SDaniel Mack 623d5a0bf6cSDaniel Mack /* M-Audio FastTrack Ultra quirks */ 624d34bf148SFelix Homann /* FTU Effect switch */ 625d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val { 626d34bf148SFelix Homann struct usb_mixer_interface *mixer; 627d34bf148SFelix Homann int cached_value; 628d34bf148SFelix Homann int is_cached; 629d34bf148SFelix Homann }; 630d34bf148SFelix Homann 631d34bf148SFelix Homann static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, 632d34bf148SFelix Homann struct snd_ctl_elem_info *uinfo) 633d34bf148SFelix Homann { 634d34bf148SFelix Homann static const char *texts[8] = {"Room 1", 635d34bf148SFelix Homann "Room 2", 636d34bf148SFelix Homann "Room 3", 637d34bf148SFelix Homann "Hall 1", 638d34bf148SFelix Homann "Hall 2", 639d34bf148SFelix Homann "Plate", 640d34bf148SFelix Homann "Delay", 641d34bf148SFelix Homann "Echo" 642d34bf148SFelix Homann }; 643d34bf148SFelix Homann 644d34bf148SFelix Homann uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 645d34bf148SFelix Homann uinfo->count = 1; 646d34bf148SFelix Homann uinfo->value.enumerated.items = 8; 647d34bf148SFelix Homann if (uinfo->value.enumerated.item > 7) 648d34bf148SFelix Homann uinfo->value.enumerated.item = 7; 649d34bf148SFelix Homann strcpy(uinfo->value.enumerated.name, 650d34bf148SFelix Homann texts[uinfo->value.enumerated.item]); 651d34bf148SFelix Homann 652d34bf148SFelix Homann return 0; 653d34bf148SFelix Homann } 654d34bf148SFelix Homann 655d34bf148SFelix Homann static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, 656d34bf148SFelix Homann struct snd_ctl_elem_value *ucontrol) 657d34bf148SFelix Homann { 658d34bf148SFelix Homann struct snd_usb_audio *chip; 659d34bf148SFelix Homann struct usb_mixer_interface *mixer; 660d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val *pval; 661d34bf148SFelix Homann int err; 662d34bf148SFelix Homann unsigned char value[2]; 663d34bf148SFelix Homann 664d34bf148SFelix Homann const int id = 6; 665d34bf148SFelix Homann const int validx = 1; 666d34bf148SFelix Homann const int val_len = 2; 667d34bf148SFelix Homann 668d34bf148SFelix Homann value[0] = 0x00; 669d34bf148SFelix Homann value[1] = 0x00; 670d34bf148SFelix Homann 671d34bf148SFelix Homann pval = (struct snd_ftu_eff_switch_priv_val *) 672d34bf148SFelix Homann kctl->private_value; 673d34bf148SFelix Homann 674d34bf148SFelix Homann if (pval->is_cached) { 675d34bf148SFelix Homann ucontrol->value.enumerated.item[0] = pval->cached_value; 676d34bf148SFelix Homann return 0; 677d34bf148SFelix Homann } 678d34bf148SFelix Homann 679d34bf148SFelix Homann mixer = (struct usb_mixer_interface *) pval->mixer; 680d34bf148SFelix Homann if (snd_BUG_ON(!mixer)) 681d34bf148SFelix Homann return -EINVAL; 682d34bf148SFelix Homann 683d34bf148SFelix Homann chip = (struct snd_usb_audio *) mixer->chip; 684d34bf148SFelix Homann if (snd_BUG_ON(!chip)) 685d34bf148SFelix Homann return -EINVAL; 686d34bf148SFelix Homann 687d34bf148SFelix Homann 688888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 689888ea7d5STakashi Iwai if (mixer->chip->shutdown) 690888ea7d5STakashi Iwai err = -ENODEV; 691888ea7d5STakashi Iwai else 692d34bf148SFelix Homann err = snd_usb_ctl_msg(chip->dev, 693d34bf148SFelix Homann usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, 694d34bf148SFelix Homann USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 695d34bf148SFelix Homann validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), 696d34bf148SFelix Homann value, val_len); 697888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 698d34bf148SFelix Homann if (err < 0) 699d34bf148SFelix Homann return err; 700d34bf148SFelix Homann 701d34bf148SFelix Homann ucontrol->value.enumerated.item[0] = value[0]; 702d34bf148SFelix Homann pval->cached_value = value[0]; 703d34bf148SFelix Homann pval->is_cached = 1; 704d34bf148SFelix Homann 705d34bf148SFelix Homann return 0; 706d34bf148SFelix Homann } 707d34bf148SFelix Homann 708d34bf148SFelix Homann static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, 709d34bf148SFelix Homann struct snd_ctl_elem_value *ucontrol) 710d34bf148SFelix Homann { 711d34bf148SFelix Homann struct snd_usb_audio *chip; 712d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val *pval; 713d34bf148SFelix Homann 714d34bf148SFelix Homann struct usb_mixer_interface *mixer; 715d34bf148SFelix Homann int changed, cur_val, err, new_val; 716d34bf148SFelix Homann unsigned char value[2]; 717d34bf148SFelix Homann 718d34bf148SFelix Homann 719d34bf148SFelix Homann const int id = 6; 720d34bf148SFelix Homann const int validx = 1; 721d34bf148SFelix Homann const int val_len = 2; 722d34bf148SFelix Homann 723d34bf148SFelix Homann changed = 0; 724d34bf148SFelix Homann 725d34bf148SFelix Homann pval = (struct snd_ftu_eff_switch_priv_val *) 726d34bf148SFelix Homann kctl->private_value; 727d34bf148SFelix Homann cur_val = pval->cached_value; 728d34bf148SFelix Homann new_val = ucontrol->value.enumerated.item[0]; 729d34bf148SFelix Homann 730d34bf148SFelix Homann mixer = (struct usb_mixer_interface *) pval->mixer; 731d34bf148SFelix Homann if (snd_BUG_ON(!mixer)) 732d34bf148SFelix Homann return -EINVAL; 733d34bf148SFelix Homann 734d34bf148SFelix Homann chip = (struct snd_usb_audio *) mixer->chip; 735d34bf148SFelix Homann if (snd_BUG_ON(!chip)) 736d34bf148SFelix Homann return -EINVAL; 737d34bf148SFelix Homann 738d34bf148SFelix Homann if (!pval->is_cached) { 739d34bf148SFelix Homann /* Read current value */ 740888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 741888ea7d5STakashi Iwai if (mixer->chip->shutdown) 742888ea7d5STakashi Iwai err = -ENODEV; 743888ea7d5STakashi Iwai else 744d34bf148SFelix Homann err = snd_usb_ctl_msg(chip->dev, 745d34bf148SFelix Homann usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, 746d34bf148SFelix Homann USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 747d34bf148SFelix Homann validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), 748d34bf148SFelix Homann value, val_len); 749888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 750d34bf148SFelix Homann if (err < 0) 751d34bf148SFelix Homann return err; 752d34bf148SFelix Homann 753d34bf148SFelix Homann cur_val = value[0]; 754d34bf148SFelix Homann pval->cached_value = cur_val; 755d34bf148SFelix Homann pval->is_cached = 1; 756d34bf148SFelix Homann } 757d34bf148SFelix Homann /* update value if needed */ 758d34bf148SFelix Homann if (cur_val != new_val) { 759d34bf148SFelix Homann value[0] = new_val; 760d34bf148SFelix Homann value[1] = 0; 761888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 762888ea7d5STakashi Iwai if (mixer->chip->shutdown) 763888ea7d5STakashi Iwai err = -ENODEV; 764888ea7d5STakashi Iwai else 765d34bf148SFelix Homann err = snd_usb_ctl_msg(chip->dev, 766d34bf148SFelix Homann usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, 767d34bf148SFelix Homann USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 768d34bf148SFelix Homann validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), 769d34bf148SFelix Homann value, val_len); 770888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 771d34bf148SFelix Homann if (err < 0) 772d34bf148SFelix Homann return err; 773d34bf148SFelix Homann 774d34bf148SFelix Homann pval->cached_value = new_val; 775d34bf148SFelix Homann pval->is_cached = 1; 776d34bf148SFelix Homann changed = 1; 777d34bf148SFelix Homann } 778d34bf148SFelix Homann 779d34bf148SFelix Homann return changed; 780d34bf148SFelix Homann } 781d34bf148SFelix Homann 782d34bf148SFelix Homann static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer) 783d34bf148SFelix Homann { 784d34bf148SFelix Homann static struct snd_kcontrol_new template = { 785d34bf148SFelix Homann .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 786d34bf148SFelix Homann .name = "Effect Program Switch", 787d34bf148SFelix Homann .index = 0, 788d34bf148SFelix Homann .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 789d34bf148SFelix Homann .info = snd_ftu_eff_switch_info, 790d34bf148SFelix Homann .get = snd_ftu_eff_switch_get, 791d34bf148SFelix Homann .put = snd_ftu_eff_switch_put 792d34bf148SFelix Homann }; 793d34bf148SFelix Homann 794d34bf148SFelix Homann int err; 795d34bf148SFelix Homann struct snd_kcontrol *kctl; 796d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val *pval; 797d34bf148SFelix Homann 798d34bf148SFelix Homann pval = kzalloc(sizeof(*pval), GFP_KERNEL); 799d34bf148SFelix Homann if (!pval) 800d34bf148SFelix Homann return -ENOMEM; 801d34bf148SFelix Homann 802d34bf148SFelix Homann pval->cached_value = 0; 803d34bf148SFelix Homann pval->is_cached = 0; 804d34bf148SFelix Homann pval->mixer = mixer; 805d34bf148SFelix Homann 806d34bf148SFelix Homann template.private_value = (unsigned long) pval; 807d34bf148SFelix Homann kctl = snd_ctl_new1(&template, mixer->chip); 808d34bf148SFelix Homann if (!kctl) { 809d34bf148SFelix Homann kfree(pval); 810d34bf148SFelix Homann return -ENOMEM; 811d34bf148SFelix Homann } 812d34bf148SFelix Homann 813d34bf148SFelix Homann err = snd_ctl_add(mixer->chip->card, kctl); 814d34bf148SFelix Homann if (err < 0) 815d34bf148SFelix Homann return err; 816d34bf148SFelix Homann 817d34bf148SFelix Homann return 0; 818d34bf148SFelix Homann } 819d5a0bf6cSDaniel Mack 820cfe8f97cSFelix Homann /* Create volume controls for FTU devices*/ 821cfe8f97cSFelix Homann static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) 822d5a0bf6cSDaniel Mack { 823d5a0bf6cSDaniel Mack char name[64]; 8248a4d1d39SFelix Homann unsigned int control, cmask; 825d5a0bf6cSDaniel Mack int in, out, err; 826d5a0bf6cSDaniel Mack 8278a4d1d39SFelix Homann const unsigned int id = 5; 8288a4d1d39SFelix Homann const int val_type = USB_MIXER_S16; 8298a4d1d39SFelix Homann 830d5a0bf6cSDaniel Mack for (out = 0; out < 8; out++) { 8318a4d1d39SFelix Homann control = out + 1; 832d5a0bf6cSDaniel Mack for (in = 0; in < 8; in++) { 8338a4d1d39SFelix Homann cmask = 1 << in; 834d5a0bf6cSDaniel Mack snprintf(name, sizeof(name), 8358a4d1d39SFelix Homann "AIn%d - Out%d Capture Volume", 8368a4d1d39SFelix Homann in + 1, out + 1); 8378a4d1d39SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, 8388a4d1d39SFelix Homann cmask, val_type, name, 83925ee7ef8SFelix Homann &snd_usb_mixer_vol_tlv); 840d5a0bf6cSDaniel Mack if (err < 0) 841d5a0bf6cSDaniel Mack return err; 842d5a0bf6cSDaniel Mack } 843d5a0bf6cSDaniel Mack for (in = 8; in < 16; in++) { 8448a4d1d39SFelix Homann cmask = 1 << in; 845d5a0bf6cSDaniel Mack snprintf(name, sizeof(name), 8468a4d1d39SFelix Homann "DIn%d - Out%d Playback Volume", 8478a4d1d39SFelix Homann in - 7, out + 1); 8488a4d1d39SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, 8498a4d1d39SFelix Homann cmask, val_type, name, 85025ee7ef8SFelix Homann &snd_usb_mixer_vol_tlv); 851d5a0bf6cSDaniel Mack if (err < 0) 852d5a0bf6cSDaniel Mack return err; 853d5a0bf6cSDaniel Mack } 854d5a0bf6cSDaniel Mack } 855d5a0bf6cSDaniel Mack 856d5a0bf6cSDaniel Mack return 0; 857d5a0bf6cSDaniel Mack } 858d5a0bf6cSDaniel Mack 859d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */ 860d34bf148SFelix Homann static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer) 861d34bf148SFelix Homann { 862d34bf148SFelix Homann static const char name[] = "Effect Volume"; 863d34bf148SFelix Homann const unsigned int id = 6; 864d34bf148SFelix Homann const int val_type = USB_MIXER_U8; 865d34bf148SFelix Homann const unsigned int control = 2; 866d34bf148SFelix Homann const unsigned int cmask = 0; 867d34bf148SFelix Homann 868d34bf148SFelix Homann return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 869d34bf148SFelix Homann name, snd_usb_mixer_vol_tlv); 870d34bf148SFelix Homann } 871d34bf148SFelix Homann 872d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */ 873d34bf148SFelix Homann static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer) 874d34bf148SFelix Homann { 875d34bf148SFelix Homann static const char name[] = "Effect Duration"; 876d34bf148SFelix Homann const unsigned int id = 6; 877d34bf148SFelix Homann const int val_type = USB_MIXER_S16; 878d34bf148SFelix Homann const unsigned int control = 3; 879d34bf148SFelix Homann const unsigned int cmask = 0; 880d34bf148SFelix Homann 881d34bf148SFelix Homann return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 882d34bf148SFelix Homann name, snd_usb_mixer_vol_tlv); 883d34bf148SFelix Homann } 884d34bf148SFelix Homann 885d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */ 886d34bf148SFelix Homann static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) 887d34bf148SFelix Homann { 888d34bf148SFelix Homann static const char name[] = "Effect Feedback Volume"; 889d34bf148SFelix Homann const unsigned int id = 6; 890d34bf148SFelix Homann const int val_type = USB_MIXER_U8; 891d34bf148SFelix Homann const unsigned int control = 4; 892d34bf148SFelix Homann const unsigned int cmask = 0; 893d34bf148SFelix Homann 894d34bf148SFelix Homann return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 895d34bf148SFelix Homann name, NULL); 896d34bf148SFelix Homann } 897d34bf148SFelix Homann 898d34bf148SFelix Homann static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer) 899d34bf148SFelix Homann { 900d34bf148SFelix Homann unsigned int cmask; 901d34bf148SFelix Homann int err, ch; 902d34bf148SFelix Homann char name[48]; 903d34bf148SFelix Homann 904d34bf148SFelix Homann const unsigned int id = 7; 905d34bf148SFelix Homann const int val_type = USB_MIXER_S16; 906d34bf148SFelix Homann const unsigned int control = 7; 907d34bf148SFelix Homann 908d34bf148SFelix Homann for (ch = 0; ch < 4; ++ch) { 909d34bf148SFelix Homann cmask = 1 << ch; 910d34bf148SFelix Homann snprintf(name, sizeof(name), 911d34bf148SFelix Homann "Effect Return %d Volume", ch + 1); 912d34bf148SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, 913d34bf148SFelix Homann cmask, val_type, name, 914d34bf148SFelix Homann snd_usb_mixer_vol_tlv); 915d34bf148SFelix Homann if (err < 0) 916d34bf148SFelix Homann return err; 917d34bf148SFelix Homann } 918d34bf148SFelix Homann 919d34bf148SFelix Homann return 0; 920d34bf148SFelix Homann } 921d34bf148SFelix Homann 922d34bf148SFelix Homann static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) 923d34bf148SFelix Homann { 924d34bf148SFelix Homann unsigned int cmask; 925d34bf148SFelix Homann int err, ch; 926d34bf148SFelix Homann char name[48]; 927d34bf148SFelix Homann 928d34bf148SFelix Homann const unsigned int id = 5; 929d34bf148SFelix Homann const int val_type = USB_MIXER_S16; 930d34bf148SFelix Homann const unsigned int control = 9; 931d34bf148SFelix Homann 932d34bf148SFelix Homann for (ch = 0; ch < 8; ++ch) { 933d34bf148SFelix Homann cmask = 1 << ch; 934d34bf148SFelix Homann snprintf(name, sizeof(name), 935d34bf148SFelix Homann "Effect Send AIn%d Volume", ch + 1); 936d34bf148SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, cmask, 937d34bf148SFelix Homann val_type, name, 938d34bf148SFelix Homann snd_usb_mixer_vol_tlv); 939d34bf148SFelix Homann if (err < 0) 940d34bf148SFelix Homann return err; 941d34bf148SFelix Homann } 942d34bf148SFelix Homann for (ch = 8; ch < 16; ++ch) { 943d34bf148SFelix Homann cmask = 1 << ch; 944d34bf148SFelix Homann snprintf(name, sizeof(name), 945d34bf148SFelix Homann "Effect Send DIn%d Volume", ch - 7); 946d34bf148SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, cmask, 947d34bf148SFelix Homann val_type, name, 948d34bf148SFelix Homann snd_usb_mixer_vol_tlv); 949d34bf148SFelix Homann if (err < 0) 950d34bf148SFelix Homann return err; 951d34bf148SFelix Homann } 952d34bf148SFelix Homann return 0; 953d34bf148SFelix Homann } 954d34bf148SFelix Homann 955cfe8f97cSFelix Homann static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) 9567536c301SMark Hills { 9578a4d1d39SFelix Homann int err; 9587536c301SMark Hills 959cfe8f97cSFelix Homann err = snd_ftu_create_volume_ctls(mixer); 9608a4d1d39SFelix Homann if (err < 0) 9618a4d1d39SFelix Homann return err; 9627536c301SMark Hills 963d34bf148SFelix Homann err = snd_ftu_create_effect_switch(mixer); 964d34bf148SFelix Homann if (err < 0) 965d34bf148SFelix Homann return err; 966d34bf148SFelix Homann err = snd_ftu_create_effect_volume_ctl(mixer); 967d34bf148SFelix Homann if (err < 0) 968d34bf148SFelix Homann return err; 969d34bf148SFelix Homann 970d34bf148SFelix Homann err = snd_ftu_create_effect_duration_ctl(mixer); 971d34bf148SFelix Homann if (err < 0) 972d34bf148SFelix Homann return err; 973d34bf148SFelix Homann 974d34bf148SFelix Homann err = snd_ftu_create_effect_feedback_ctl(mixer); 975d34bf148SFelix Homann if (err < 0) 976d34bf148SFelix Homann return err; 977d34bf148SFelix Homann 978d34bf148SFelix Homann err = snd_ftu_create_effect_return_ctls(mixer); 979d34bf148SFelix Homann if (err < 0) 980d34bf148SFelix Homann return err; 981d34bf148SFelix Homann 982d34bf148SFelix Homann err = snd_ftu_create_effect_send_ctls(mixer); 983d34bf148SFelix Homann if (err < 0) 984d34bf148SFelix Homann return err; 985d34bf148SFelix Homann 9868a4d1d39SFelix Homann return 0; 9877536c301SMark Hills } 9887536c301SMark Hills 9897b1eda22SDaniel Mack void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, 9907b1eda22SDaniel Mack unsigned char samplerate_id) 9917b1eda22SDaniel Mack { 9927b1eda22SDaniel Mack struct usb_mixer_interface *mixer; 9937b1eda22SDaniel Mack struct usb_mixer_elem_info *cval; 9947b1eda22SDaniel Mack int unitid = 12; /* SamleRate ExtensionUnit ID */ 9957b1eda22SDaniel Mack 9967b1eda22SDaniel Mack list_for_each_entry(mixer, &chip->mixer_list, list) { 9977b1eda22SDaniel Mack cval = mixer->id_elems[unitid]; 9987b1eda22SDaniel Mack if (cval) { 9997b1eda22SDaniel Mack snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, 10007b1eda22SDaniel Mack cval->control << 8, 10017b1eda22SDaniel Mack samplerate_id); 10027b1eda22SDaniel Mack snd_usb_mixer_notify_id(mixer, unitid); 10037b1eda22SDaniel Mack } 10047b1eda22SDaniel Mack break; 10057b1eda22SDaniel Mack } 10067b1eda22SDaniel Mack } 10077b1eda22SDaniel Mack 1008b71dad18SMark Hills /* 1009b71dad18SMark Hills * The mixer units for Ebox-44 are corrupt, and even where they 1010b71dad18SMark Hills * are valid they presents mono controls as L and R channels of 1011b71dad18SMark Hills * stereo. So we provide a good mixer here. 1012b71dad18SMark Hills */ 1013b71dad18SMark Hills struct std_mono_table ebox44_table[] = { 1014989b0138SMark Hills { 1015989b0138SMark Hills .unitid = 4, 1016989b0138SMark Hills .control = 1, 1017989b0138SMark Hills .cmask = 0x0, 1018989b0138SMark Hills .val_type = USB_MIXER_INV_BOOLEAN, 1019989b0138SMark Hills .name = "Headphone Playback Switch" 1020989b0138SMark Hills }, 1021989b0138SMark Hills { 1022989b0138SMark Hills .unitid = 4, 1023989b0138SMark Hills .control = 2, 1024989b0138SMark Hills .cmask = 0x1, 1025989b0138SMark Hills .val_type = USB_MIXER_S16, 1026989b0138SMark Hills .name = "Headphone A Mix Playback Volume" 1027989b0138SMark Hills }, 1028989b0138SMark Hills { 1029989b0138SMark Hills .unitid = 4, 1030989b0138SMark Hills .control = 2, 1031989b0138SMark Hills .cmask = 0x2, 1032989b0138SMark Hills .val_type = USB_MIXER_S16, 1033989b0138SMark Hills .name = "Headphone B Mix Playback Volume" 1034989b0138SMark Hills }, 1035b71dad18SMark Hills 1036989b0138SMark Hills { 1037989b0138SMark Hills .unitid = 7, 1038989b0138SMark Hills .control = 1, 1039989b0138SMark Hills .cmask = 0x0, 1040989b0138SMark Hills .val_type = USB_MIXER_INV_BOOLEAN, 1041989b0138SMark Hills .name = "Output Playback Switch" 1042989b0138SMark Hills }, 1043989b0138SMark Hills { 1044989b0138SMark Hills .unitid = 7, 1045989b0138SMark Hills .control = 2, 1046989b0138SMark Hills .cmask = 0x1, 1047989b0138SMark Hills .val_type = USB_MIXER_S16, 1048989b0138SMark Hills .name = "Output A Playback Volume" 1049989b0138SMark Hills }, 1050989b0138SMark Hills { 1051989b0138SMark Hills .unitid = 7, 1052989b0138SMark Hills .control = 2, 1053989b0138SMark Hills .cmask = 0x2, 1054989b0138SMark Hills .val_type = USB_MIXER_S16, 1055989b0138SMark Hills .name = "Output B Playback Volume" 1056989b0138SMark Hills }, 1057b71dad18SMark Hills 1058989b0138SMark Hills { 1059989b0138SMark Hills .unitid = 10, 1060989b0138SMark Hills .control = 1, 1061989b0138SMark Hills .cmask = 0x0, 1062989b0138SMark Hills .val_type = USB_MIXER_INV_BOOLEAN, 1063989b0138SMark Hills .name = "Input Capture Switch" 1064989b0138SMark Hills }, 1065989b0138SMark Hills { 1066989b0138SMark Hills .unitid = 10, 1067989b0138SMark Hills .control = 2, 1068989b0138SMark Hills .cmask = 0x1, 1069989b0138SMark Hills .val_type = USB_MIXER_S16, 1070989b0138SMark Hills .name = "Input A Capture Volume" 1071989b0138SMark Hills }, 1072989b0138SMark Hills { 1073989b0138SMark Hills .unitid = 10, 1074989b0138SMark Hills .control = 2, 1075989b0138SMark Hills .cmask = 0x2, 1076989b0138SMark Hills .val_type = USB_MIXER_S16, 1077989b0138SMark Hills .name = "Input B Capture Volume" 1078989b0138SMark Hills }, 1079b71dad18SMark Hills 1080b71dad18SMark Hills {} 1081b71dad18SMark Hills }; 1082b71dad18SMark Hills 10837b1eda22SDaniel Mack int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) 10847b1eda22SDaniel Mack { 10853347b26cSDaniel Mack int err = 0; 10867b1eda22SDaniel Mack struct snd_info_entry *entry; 10877b1eda22SDaniel Mack 10887b1eda22SDaniel Mack if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) 10897b1eda22SDaniel Mack return err; 10907b1eda22SDaniel Mack 10913347b26cSDaniel Mack switch (mixer->chip->usb_id) { 10923347b26cSDaniel Mack case USB_ID(0x041e, 0x3020): 10933347b26cSDaniel Mack case USB_ID(0x041e, 0x3040): 10943347b26cSDaniel Mack case USB_ID(0x041e, 0x3042): 10957cdd8d73SMathieu Bouffard case USB_ID(0x041e, 0x30df): 10963347b26cSDaniel Mack case USB_ID(0x041e, 0x3048): 10973347b26cSDaniel Mack err = snd_audigy2nx_controls_create(mixer); 10983347b26cSDaniel Mack if (err < 0) 10993347b26cSDaniel Mack break; 11007b1eda22SDaniel Mack if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry)) 11017b1eda22SDaniel Mack snd_info_set_text_ops(entry, mixer, 11027b1eda22SDaniel Mack snd_audigy2nx_proc_read); 11033347b26cSDaniel Mack break; 11047b1eda22SDaniel Mack 1105d5a0bf6cSDaniel Mack case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ 1106d5a0bf6cSDaniel Mack case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ 1107cfe8f97cSFelix Homann err = snd_ftu_create_mixer(mixer); 1108d5a0bf6cSDaniel Mack break; 1109d5a0bf6cSDaniel Mack 11103347b26cSDaniel Mack case USB_ID(0x0b05, 0x1739): 11113347b26cSDaniel Mack case USB_ID(0x0b05, 0x1743): 11127b1eda22SDaniel Mack err = snd_xonar_u1_controls_create(mixer); 11133347b26cSDaniel Mack break; 11147b1eda22SDaniel Mack 11153347b26cSDaniel Mack case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */ 111654a8c500SDaniel Mack err = snd_nativeinstruments_create_mixer(mixer, 111754a8c500SDaniel Mack snd_nativeinstruments_ta6_mixers, 111854a8c500SDaniel Mack ARRAY_SIZE(snd_nativeinstruments_ta6_mixers)); 11193347b26cSDaniel Mack break; 112054a8c500SDaniel Mack 11213347b26cSDaniel Mack case USB_ID(0x17cc, 0x1021): /* Traktor Audio 10 */ 112254a8c500SDaniel Mack err = snd_nativeinstruments_create_mixer(mixer, 112354a8c500SDaniel Mack snd_nativeinstruments_ta10_mixers, 112454a8c500SDaniel Mack ARRAY_SIZE(snd_nativeinstruments_ta10_mixers)); 11253347b26cSDaniel Mack break; 11267536c301SMark Hills 11277536c301SMark Hills case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */ 1128b71dad18SMark Hills /* detection is disabled in mixer_maps.c */ 1129b71dad18SMark Hills err = snd_create_std_mono_table(mixer, ebox44_table); 11307536c301SMark Hills break; 113154a8c500SDaniel Mack } 113254a8c500SDaniel Mack 11333347b26cSDaniel Mack return err; 11347b1eda22SDaniel Mack } 11357b1eda22SDaniel Mack 11367b1eda22SDaniel Mack void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, 11377b1eda22SDaniel Mack int unitid) 11387b1eda22SDaniel Mack { 11397b1eda22SDaniel Mack if (!mixer->rc_cfg) 11407b1eda22SDaniel Mack return; 11417b1eda22SDaniel Mack /* unit ids specific to Extigy/Audigy 2 NX: */ 11427b1eda22SDaniel Mack switch (unitid) { 11437b1eda22SDaniel Mack case 0: /* remote control */ 11447b1eda22SDaniel Mack mixer->rc_urb->dev = mixer->chip->dev; 11457b1eda22SDaniel Mack usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); 11467b1eda22SDaniel Mack break; 11477b1eda22SDaniel Mack case 4: /* digital in jack */ 11487b1eda22SDaniel Mack case 7: /* line in jacks */ 11497b1eda22SDaniel Mack case 19: /* speaker out jacks */ 11507b1eda22SDaniel Mack case 20: /* headphones out jack */ 11517b1eda22SDaniel Mack break; 11527b1eda22SDaniel Mack /* live24ext: 4 = line-in jack */ 11537b1eda22SDaniel Mack case 3: /* hp-out jack (may actuate Mute) */ 11547b1eda22SDaniel Mack if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 11557b1eda22SDaniel Mack mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) 11567b1eda22SDaniel Mack snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id); 11577b1eda22SDaniel Mack break; 11587b1eda22SDaniel Mack default: 11597b1eda22SDaniel Mack snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); 11607b1eda22SDaniel Mack break; 11617b1eda22SDaniel Mack } 11627b1eda22SDaniel Mack } 11637b1eda22SDaniel Mack 1164