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" 447b1eda22SDaniel Mack #include "helper.h" 457b1eda22SDaniel Mack 46d5a0bf6cSDaniel Mack extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl; 47d5a0bf6cSDaniel Mack 48b71dad18SMark Hills struct std_mono_table { 49b71dad18SMark Hills unsigned int unitid, control, cmask; 50b71dad18SMark Hills int val_type; 51b71dad18SMark Hills const char *name; 52b71dad18SMark Hills snd_kcontrol_tlv_rw_t *tlv_callback; 53b71dad18SMark Hills }; 54b71dad18SMark Hills 558a4d1d39SFelix Homann /* private_free callback */ 568a4d1d39SFelix Homann static void usb_mixer_elem_free(struct snd_kcontrol *kctl) 578a4d1d39SFelix Homann { 588a4d1d39SFelix Homann kfree(kctl->private_data); 598a4d1d39SFelix Homann kctl->private_data = NULL; 608a4d1d39SFelix Homann } 618a4d1d39SFelix Homann 628a4d1d39SFelix Homann /* This function allows for the creation of standard UAC controls. 638a4d1d39SFelix Homann * See the quirks for M-Audio FTUs or Ebox-44. 648a4d1d39SFelix Homann * If you don't want to set a TLV callback pass NULL. 658a4d1d39SFelix Homann * 668a4d1d39SFelix Homann * Since there doesn't seem to be a devices that needs a multichannel 678a4d1d39SFelix Homann * version, we keep it mono for simplicity. 688a4d1d39SFelix Homann */ 699f814105SEldad Zack static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer, 708a4d1d39SFelix Homann unsigned int unitid, 718a4d1d39SFelix Homann unsigned int control, 728a4d1d39SFelix Homann unsigned int cmask, 738a4d1d39SFelix Homann int val_type, 749f814105SEldad Zack unsigned int idx_off, 758a4d1d39SFelix Homann const char *name, 768a4d1d39SFelix Homann snd_kcontrol_tlv_rw_t *tlv_callback) 778a4d1d39SFelix Homann { 788a4d1d39SFelix Homann int err; 798a4d1d39SFelix Homann struct usb_mixer_elem_info *cval; 808a4d1d39SFelix Homann struct snd_kcontrol *kctl; 818a4d1d39SFelix Homann 828a4d1d39SFelix Homann cval = kzalloc(sizeof(*cval), GFP_KERNEL); 838a4d1d39SFelix Homann if (!cval) 848a4d1d39SFelix Homann return -ENOMEM; 858a4d1d39SFelix Homann 868a4d1d39SFelix Homann cval->id = unitid; 878a4d1d39SFelix Homann cval->mixer = mixer; 888a4d1d39SFelix Homann cval->val_type = val_type; 898a4d1d39SFelix Homann cval->channels = 1; 908a4d1d39SFelix Homann cval->control = control; 918a4d1d39SFelix Homann cval->cmask = cmask; 929f814105SEldad Zack cval->idx_off = idx_off; 938a4d1d39SFelix Homann 947df4a691SMark Hills /* get_min_max() is called only for integer volumes later, 957df4a691SMark Hills * so provide a short-cut for booleans */ 968a4d1d39SFelix Homann cval->min = 0; 978a4d1d39SFelix Homann cval->max = 1; 988a4d1d39SFelix Homann cval->res = 0; 998a4d1d39SFelix Homann cval->dBmin = 0; 1008a4d1d39SFelix Homann cval->dBmax = 0; 1018a4d1d39SFelix Homann 1028a4d1d39SFelix Homann /* Create control */ 1038a4d1d39SFelix Homann kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval); 1048a4d1d39SFelix Homann if (!kctl) { 1058a4d1d39SFelix Homann kfree(cval); 1068a4d1d39SFelix Homann return -ENOMEM; 1078a4d1d39SFelix Homann } 1088a4d1d39SFelix Homann 1098a4d1d39SFelix Homann /* Set name */ 1108a4d1d39SFelix Homann snprintf(kctl->id.name, sizeof(kctl->id.name), name); 1118a4d1d39SFelix Homann kctl->private_free = usb_mixer_elem_free; 1128a4d1d39SFelix Homann 1138a4d1d39SFelix Homann /* set TLV */ 1148a4d1d39SFelix Homann if (tlv_callback) { 1158a4d1d39SFelix Homann kctl->tlv.c = tlv_callback; 1168a4d1d39SFelix Homann kctl->vd[0].access |= 1178a4d1d39SFelix Homann SNDRV_CTL_ELEM_ACCESS_TLV_READ | 1188a4d1d39SFelix Homann SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; 1198a4d1d39SFelix Homann } 1208a4d1d39SFelix Homann /* Add control to mixer */ 1218a4d1d39SFelix Homann err = snd_usb_mixer_add_control(mixer, kctl); 1228a4d1d39SFelix Homann if (err < 0) 1238a4d1d39SFelix Homann return err; 1248a4d1d39SFelix Homann 1258a4d1d39SFelix Homann return 0; 1268a4d1d39SFelix Homann } 1278a4d1d39SFelix Homann 1289f814105SEldad Zack static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, 1299f814105SEldad Zack unsigned int unitid, 1309f814105SEldad Zack unsigned int control, 1319f814105SEldad Zack unsigned int cmask, 1329f814105SEldad Zack int val_type, 1339f814105SEldad Zack const char *name, 1349f814105SEldad Zack snd_kcontrol_tlv_rw_t *tlv_callback) 1359f814105SEldad Zack { 1369f814105SEldad Zack return snd_create_std_mono_ctl_offset(mixer, unitid, control, cmask, 1379f814105SEldad Zack val_type, 0 /* Offset */, name, tlv_callback); 1389f814105SEldad Zack } 1399f814105SEldad Zack 1407b1eda22SDaniel Mack /* 141b71dad18SMark Hills * Create a set of standard UAC controls from a table 142b71dad18SMark Hills */ 143b71dad18SMark Hills static int snd_create_std_mono_table(struct usb_mixer_interface *mixer, 144b71dad18SMark Hills struct std_mono_table *t) 145b71dad18SMark Hills { 146b71dad18SMark Hills int err; 147b71dad18SMark Hills 148b71dad18SMark Hills while (t->name != NULL) { 149b71dad18SMark Hills err = snd_create_std_mono_ctl(mixer, t->unitid, t->control, 150b71dad18SMark Hills t->cmask, t->val_type, t->name, t->tlv_callback); 151b71dad18SMark Hills if (err < 0) 152b71dad18SMark Hills return err; 153b71dad18SMark Hills t++; 154b71dad18SMark Hills } 155b71dad18SMark Hills 156b71dad18SMark Hills return 0; 157b71dad18SMark Hills } 158b71dad18SMark Hills 159b71dad18SMark Hills /* 1607b1eda22SDaniel Mack * Sound Blaster remote control configuration 1617b1eda22SDaniel Mack * 1627b1eda22SDaniel Mack * format of remote control data: 1637b1eda22SDaniel Mack * Extigy: xx 00 1647b1eda22SDaniel Mack * Audigy 2 NX: 06 80 xx 00 00 00 1657b1eda22SDaniel Mack * Live! 24-bit: 06 80 xx yy 22 83 1667b1eda22SDaniel Mack */ 1677b1eda22SDaniel Mack static const struct rc_config { 1687b1eda22SDaniel Mack u32 usb_id; 1697b1eda22SDaniel Mack u8 offset; 1707b1eda22SDaniel Mack u8 length; 1717b1eda22SDaniel Mack u8 packet_length; 1727b1eda22SDaniel Mack u8 min_packet_length; /* minimum accepted length of the URB result */ 1737b1eda22SDaniel Mack u8 mute_mixer_id; 1747b1eda22SDaniel Mack u32 mute_code; 1757b1eda22SDaniel Mack } rc_configs[] = { 1767b1eda22SDaniel Mack { USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */ 1777b1eda22SDaniel Mack { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */ 1787b1eda22SDaniel Mack { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ 179ca8dc34eSMandar Joshi { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 */ 1807cdd8d73SMathieu Bouffard { USB_ID(0x041e, 0x30df), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ 1817b1eda22SDaniel Mack { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ 1827b1eda22SDaniel Mack }; 1837b1eda22SDaniel Mack 1847b1eda22SDaniel Mack static void snd_usb_soundblaster_remote_complete(struct urb *urb) 1857b1eda22SDaniel Mack { 1867b1eda22SDaniel Mack struct usb_mixer_interface *mixer = urb->context; 1877b1eda22SDaniel Mack const struct rc_config *rc = mixer->rc_cfg; 1887b1eda22SDaniel Mack u32 code; 1897b1eda22SDaniel Mack 1907b1eda22SDaniel Mack if (urb->status < 0 || urb->actual_length < rc->min_packet_length) 1917b1eda22SDaniel Mack return; 1927b1eda22SDaniel Mack 1937b1eda22SDaniel Mack code = mixer->rc_buffer[rc->offset]; 1947b1eda22SDaniel Mack if (rc->length == 2) 1957b1eda22SDaniel Mack code |= mixer->rc_buffer[rc->offset + 1] << 8; 1967b1eda22SDaniel Mack 1977b1eda22SDaniel Mack /* the Mute button actually changes the mixer control */ 1987b1eda22SDaniel Mack if (code == rc->mute_code) 1997b1eda22SDaniel Mack snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id); 2007b1eda22SDaniel Mack mixer->rc_code = code; 2017b1eda22SDaniel Mack wmb(); 2027b1eda22SDaniel Mack wake_up(&mixer->rc_waitq); 2037b1eda22SDaniel Mack } 2047b1eda22SDaniel Mack 2057b1eda22SDaniel Mack static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf, 2067b1eda22SDaniel Mack long count, loff_t *offset) 2077b1eda22SDaniel Mack { 2087b1eda22SDaniel Mack struct usb_mixer_interface *mixer = hw->private_data; 2097b1eda22SDaniel Mack int err; 2107b1eda22SDaniel Mack u32 rc_code; 2117b1eda22SDaniel Mack 2127b1eda22SDaniel Mack if (count != 1 && count != 4) 2137b1eda22SDaniel Mack return -EINVAL; 2147b1eda22SDaniel Mack err = wait_event_interruptible(mixer->rc_waitq, 2157b1eda22SDaniel Mack (rc_code = xchg(&mixer->rc_code, 0)) != 0); 2167b1eda22SDaniel Mack if (err == 0) { 2177b1eda22SDaniel Mack if (count == 1) 2187b1eda22SDaniel Mack err = put_user(rc_code, buf); 2197b1eda22SDaniel Mack else 2207b1eda22SDaniel Mack err = put_user(rc_code, (u32 __user *)buf); 2217b1eda22SDaniel Mack } 2227b1eda22SDaniel Mack return err < 0 ? err : count; 2237b1eda22SDaniel Mack } 2247b1eda22SDaniel Mack 2257b1eda22SDaniel Mack static unsigned int snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *file, 2267b1eda22SDaniel Mack poll_table *wait) 2277b1eda22SDaniel Mack { 2287b1eda22SDaniel Mack struct usb_mixer_interface *mixer = hw->private_data; 2297b1eda22SDaniel Mack 2307b1eda22SDaniel Mack poll_wait(file, &mixer->rc_waitq, wait); 2317b1eda22SDaniel Mack return mixer->rc_code ? POLLIN | POLLRDNORM : 0; 2327b1eda22SDaniel Mack } 2337b1eda22SDaniel Mack 2347b1eda22SDaniel Mack static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) 2357b1eda22SDaniel Mack { 2367b1eda22SDaniel Mack struct snd_hwdep *hwdep; 2377b1eda22SDaniel Mack int err, len, i; 2387b1eda22SDaniel Mack 2397b1eda22SDaniel Mack for (i = 0; i < ARRAY_SIZE(rc_configs); ++i) 2407b1eda22SDaniel Mack if (rc_configs[i].usb_id == mixer->chip->usb_id) 2417b1eda22SDaniel Mack break; 2427b1eda22SDaniel Mack if (i >= ARRAY_SIZE(rc_configs)) 2437b1eda22SDaniel Mack return 0; 2447b1eda22SDaniel Mack mixer->rc_cfg = &rc_configs[i]; 2457b1eda22SDaniel Mack 2467b1eda22SDaniel Mack len = mixer->rc_cfg->packet_length; 2477b1eda22SDaniel Mack 2487b1eda22SDaniel Mack init_waitqueue_head(&mixer->rc_waitq); 2497b1eda22SDaniel Mack err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep); 2507b1eda22SDaniel Mack if (err < 0) 2517b1eda22SDaniel Mack return err; 2527b1eda22SDaniel Mack snprintf(hwdep->name, sizeof(hwdep->name), 2537b1eda22SDaniel Mack "%s remote control", mixer->chip->card->shortname); 2547b1eda22SDaniel Mack hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC; 2557b1eda22SDaniel Mack hwdep->private_data = mixer; 2567b1eda22SDaniel Mack hwdep->ops.read = snd_usb_sbrc_hwdep_read; 2577b1eda22SDaniel Mack hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; 2587b1eda22SDaniel Mack hwdep->exclusive = 1; 2597b1eda22SDaniel Mack 2607b1eda22SDaniel Mack mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); 2617b1eda22SDaniel Mack if (!mixer->rc_urb) 2627b1eda22SDaniel Mack return -ENOMEM; 2637b1eda22SDaniel Mack mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL); 2647b1eda22SDaniel Mack if (!mixer->rc_setup_packet) { 2657b1eda22SDaniel Mack usb_free_urb(mixer->rc_urb); 2667b1eda22SDaniel Mack mixer->rc_urb = NULL; 2677b1eda22SDaniel Mack return -ENOMEM; 2687b1eda22SDaniel Mack } 2697b1eda22SDaniel Mack mixer->rc_setup_packet->bRequestType = 2707b1eda22SDaniel Mack USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; 2717b1eda22SDaniel Mack mixer->rc_setup_packet->bRequest = UAC_GET_MEM; 2727b1eda22SDaniel Mack mixer->rc_setup_packet->wValue = cpu_to_le16(0); 2737b1eda22SDaniel Mack mixer->rc_setup_packet->wIndex = cpu_to_le16(0); 2747b1eda22SDaniel Mack mixer->rc_setup_packet->wLength = cpu_to_le16(len); 2757b1eda22SDaniel Mack usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev, 2767b1eda22SDaniel Mack usb_rcvctrlpipe(mixer->chip->dev, 0), 2777b1eda22SDaniel Mack (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len, 2787b1eda22SDaniel Mack snd_usb_soundblaster_remote_complete, mixer); 2797b1eda22SDaniel Mack return 0; 2807b1eda22SDaniel Mack } 2817b1eda22SDaniel Mack 2827b1eda22SDaniel Mack #define snd_audigy2nx_led_info snd_ctl_boolean_mono_info 2837b1eda22SDaniel Mack 2847b1eda22SDaniel Mack static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2857b1eda22SDaniel Mack { 2867b1eda22SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 2877b1eda22SDaniel Mack int index = kcontrol->private_value; 2887b1eda22SDaniel Mack 2897b1eda22SDaniel Mack ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index]; 2907b1eda22SDaniel Mack return 0; 2917b1eda22SDaniel Mack } 2927b1eda22SDaniel Mack 2937b1eda22SDaniel Mack static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2947b1eda22SDaniel Mack { 2957b1eda22SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 2967b1eda22SDaniel Mack int index = kcontrol->private_value; 2977b1eda22SDaniel Mack int value = ucontrol->value.integer.value[0]; 2987b1eda22SDaniel Mack int err, changed; 2997b1eda22SDaniel Mack 3007b1eda22SDaniel Mack if (value > 1) 3017b1eda22SDaniel Mack return -EINVAL; 3027b1eda22SDaniel Mack changed = value != mixer->audigy2nx_leds[index]; 303888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 304888ea7d5STakashi Iwai if (mixer->chip->shutdown) { 305888ea7d5STakashi Iwai err = -ENODEV; 306888ea7d5STakashi Iwai goto out; 307888ea7d5STakashi Iwai } 308ca8dc34eSMandar Joshi if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) 309ca8dc34eSMandar Joshi err = snd_usb_ctl_msg(mixer->chip->dev, 310ca8dc34eSMandar Joshi usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, 311ca8dc34eSMandar Joshi USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 31217d900c4SClemens Ladisch !value, 0, NULL, 0); 3137cdd8d73SMathieu Bouffard /* USB X-Fi S51 Pro */ 3147cdd8d73SMathieu Bouffard if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) 3157cdd8d73SMathieu Bouffard err = snd_usb_ctl_msg(mixer->chip->dev, 3167cdd8d73SMathieu Bouffard usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, 3177cdd8d73SMathieu Bouffard USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 31817d900c4SClemens Ladisch !value, 0, NULL, 0); 319ca8dc34eSMandar Joshi else 3207b1eda22SDaniel Mack err = snd_usb_ctl_msg(mixer->chip->dev, 3217b1eda22SDaniel Mack usb_sndctrlpipe(mixer->chip->dev, 0), 0x24, 3227b1eda22SDaniel Mack USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 32317d900c4SClemens Ladisch value, index + 2, NULL, 0); 324888ea7d5STakashi Iwai out: 325888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 3267b1eda22SDaniel Mack if (err < 0) 3277b1eda22SDaniel Mack return err; 3287b1eda22SDaniel Mack mixer->audigy2nx_leds[index] = value; 3297b1eda22SDaniel Mack return changed; 3307b1eda22SDaniel Mack } 3317b1eda22SDaniel Mack 3327b1eda22SDaniel Mack static struct snd_kcontrol_new snd_audigy2nx_controls[] = { 3337b1eda22SDaniel Mack { 3347b1eda22SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3357b1eda22SDaniel Mack .name = "CMSS LED Switch", 3367b1eda22SDaniel Mack .info = snd_audigy2nx_led_info, 3377b1eda22SDaniel Mack .get = snd_audigy2nx_led_get, 3387b1eda22SDaniel Mack .put = snd_audigy2nx_led_put, 3397b1eda22SDaniel Mack .private_value = 0, 3407b1eda22SDaniel Mack }, 3417b1eda22SDaniel Mack { 3427b1eda22SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3437b1eda22SDaniel Mack .name = "Power LED Switch", 3447b1eda22SDaniel Mack .info = snd_audigy2nx_led_info, 3457b1eda22SDaniel Mack .get = snd_audigy2nx_led_get, 3467b1eda22SDaniel Mack .put = snd_audigy2nx_led_put, 3477b1eda22SDaniel Mack .private_value = 1, 3487b1eda22SDaniel Mack }, 3497b1eda22SDaniel Mack { 3507b1eda22SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3517b1eda22SDaniel Mack .name = "Dolby Digital LED Switch", 3527b1eda22SDaniel Mack .info = snd_audigy2nx_led_info, 3537b1eda22SDaniel Mack .get = snd_audigy2nx_led_get, 3547b1eda22SDaniel Mack .put = snd_audigy2nx_led_put, 3557b1eda22SDaniel Mack .private_value = 2, 3567b1eda22SDaniel Mack }, 3577b1eda22SDaniel Mack }; 3587b1eda22SDaniel Mack 3597b1eda22SDaniel Mack static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) 3607b1eda22SDaniel Mack { 3617b1eda22SDaniel Mack int i, err; 3627b1eda22SDaniel Mack 3637b1eda22SDaniel Mack for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) { 364ca8dc34eSMandar Joshi /* USB X-Fi S51 doesn't have a CMSS LED */ 365ca8dc34eSMandar Joshi if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0) 366ca8dc34eSMandar Joshi continue; 3677cdd8d73SMathieu Bouffard /* USB X-Fi S51 Pro doesn't have one either */ 3687cdd8d73SMathieu Bouffard if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0) 3697cdd8d73SMathieu Bouffard continue; 3707b1eda22SDaniel Mack if (i > 1 && /* Live24ext has 2 LEDs only */ 3717b1eda22SDaniel Mack (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 372ca8dc34eSMandar Joshi mixer->chip->usb_id == USB_ID(0x041e, 0x3042) || 3737cdd8d73SMathieu Bouffard mixer->chip->usb_id == USB_ID(0x041e, 0x30df) || 3747b1eda22SDaniel Mack mixer->chip->usb_id == USB_ID(0x041e, 0x3048))) 3757b1eda22SDaniel Mack break; 3767b1eda22SDaniel Mack err = snd_ctl_add(mixer->chip->card, 3777b1eda22SDaniel Mack snd_ctl_new1(&snd_audigy2nx_controls[i], mixer)); 3787b1eda22SDaniel Mack if (err < 0) 3797b1eda22SDaniel Mack return err; 3807b1eda22SDaniel Mack } 3817b1eda22SDaniel Mack mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */ 3827b1eda22SDaniel Mack return 0; 3837b1eda22SDaniel Mack } 3847b1eda22SDaniel Mack 3857b1eda22SDaniel Mack static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, 3867b1eda22SDaniel Mack struct snd_info_buffer *buffer) 3877b1eda22SDaniel Mack { 3887b1eda22SDaniel Mack static const struct sb_jack { 3897b1eda22SDaniel Mack int unitid; 3907b1eda22SDaniel Mack const char *name; 3917b1eda22SDaniel Mack } jacks_audigy2nx[] = { 3927b1eda22SDaniel Mack {4, "dig in "}, 3937b1eda22SDaniel Mack {7, "line in"}, 3947b1eda22SDaniel Mack {19, "spk out"}, 3957b1eda22SDaniel Mack {20, "hph out"}, 3967b1eda22SDaniel Mack {-1, NULL} 3977b1eda22SDaniel Mack }, jacks_live24ext[] = { 3987b1eda22SDaniel Mack {4, "line in"}, /* &1=Line, &2=Mic*/ 3997b1eda22SDaniel Mack {3, "hph out"}, /* headphones */ 4007b1eda22SDaniel Mack {0, "RC "}, /* last command, 6 bytes see rc_config above */ 4017b1eda22SDaniel Mack {-1, NULL} 4027b1eda22SDaniel Mack }; 4037b1eda22SDaniel Mack const struct sb_jack *jacks; 4047b1eda22SDaniel Mack struct usb_mixer_interface *mixer = entry->private_data; 4057b1eda22SDaniel Mack int i, err; 4067b1eda22SDaniel Mack u8 buf[3]; 4077b1eda22SDaniel Mack 4087b1eda22SDaniel Mack snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); 4097b1eda22SDaniel Mack if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) 4107b1eda22SDaniel Mack jacks = jacks_audigy2nx; 4117b1eda22SDaniel Mack else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 4127b1eda22SDaniel Mack mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) 4137b1eda22SDaniel Mack jacks = jacks_live24ext; 4147b1eda22SDaniel Mack else 4157b1eda22SDaniel Mack return; 4167b1eda22SDaniel Mack 4177b1eda22SDaniel Mack for (i = 0; jacks[i].name; ++i) { 4187b1eda22SDaniel Mack snd_iprintf(buffer, "%s: ", jacks[i].name); 419888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 420888ea7d5STakashi Iwai if (mixer->chip->shutdown) 421888ea7d5STakashi Iwai err = 0; 422888ea7d5STakashi Iwai else 4237b1eda22SDaniel Mack err = snd_usb_ctl_msg(mixer->chip->dev, 4247b1eda22SDaniel Mack usb_rcvctrlpipe(mixer->chip->dev, 0), 4257b1eda22SDaniel Mack UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | 4267b1eda22SDaniel Mack USB_RECIP_INTERFACE, 0, 42717d900c4SClemens Ladisch jacks[i].unitid << 8, buf, 3); 428888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 4297b1eda22SDaniel Mack if (err == 3 && (buf[0] == 3 || buf[0] == 6)) 4307b1eda22SDaniel Mack snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); 4317b1eda22SDaniel Mack else 4327b1eda22SDaniel Mack snd_iprintf(buffer, "?\n"); 4337b1eda22SDaniel Mack } 4347b1eda22SDaniel Mack } 4357b1eda22SDaniel Mack 43644832a71SVasily Khoruzhick /* EMU0204 */ 43744832a71SVasily Khoruzhick static int snd_emu0204_ch_switch_info(struct snd_kcontrol *kcontrol, 43844832a71SVasily Khoruzhick struct snd_ctl_elem_info *uinfo) 43944832a71SVasily Khoruzhick { 44044832a71SVasily Khoruzhick static const char *texts[2] = {"1/2", 44144832a71SVasily Khoruzhick "3/4" 44244832a71SVasily Khoruzhick }; 44344832a71SVasily Khoruzhick 44444832a71SVasily Khoruzhick uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 44544832a71SVasily Khoruzhick uinfo->count = 1; 44644832a71SVasily Khoruzhick uinfo->value.enumerated.items = 2; 44744832a71SVasily Khoruzhick if (uinfo->value.enumerated.item > 1) 44844832a71SVasily Khoruzhick uinfo->value.enumerated.item = 1; 44944832a71SVasily Khoruzhick strcpy(uinfo->value.enumerated.name, 45044832a71SVasily Khoruzhick texts[uinfo->value.enumerated.item]); 45144832a71SVasily Khoruzhick 45244832a71SVasily Khoruzhick return 0; 45344832a71SVasily Khoruzhick } 45444832a71SVasily Khoruzhick 45544832a71SVasily Khoruzhick static int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol, 45644832a71SVasily Khoruzhick struct snd_ctl_elem_value *ucontrol) 45744832a71SVasily Khoruzhick { 45844832a71SVasily Khoruzhick ucontrol->value.enumerated.item[0] = kcontrol->private_value; 45944832a71SVasily Khoruzhick return 0; 46044832a71SVasily Khoruzhick } 46144832a71SVasily Khoruzhick 46244832a71SVasily Khoruzhick static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol, 46344832a71SVasily Khoruzhick struct snd_ctl_elem_value *ucontrol) 46444832a71SVasily Khoruzhick { 46544832a71SVasily Khoruzhick struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 46644832a71SVasily Khoruzhick unsigned int value = ucontrol->value.enumerated.item[0]; 46744832a71SVasily Khoruzhick int err, changed; 46844832a71SVasily Khoruzhick unsigned char buf[2]; 46944832a71SVasily Khoruzhick 47044832a71SVasily Khoruzhick if (value > 1) 47144832a71SVasily Khoruzhick return -EINVAL; 47244832a71SVasily Khoruzhick 47344832a71SVasily Khoruzhick buf[0] = 0x01; 47444832a71SVasily Khoruzhick buf[1] = value ? 0x02 : 0x01; 47544832a71SVasily Khoruzhick 47644832a71SVasily Khoruzhick changed = value != kcontrol->private_value; 47744832a71SVasily Khoruzhick down_read(&mixer->chip->shutdown_rwsem); 47844832a71SVasily Khoruzhick if (mixer->chip->shutdown) { 47944832a71SVasily Khoruzhick err = -ENODEV; 48044832a71SVasily Khoruzhick goto out; 48144832a71SVasily Khoruzhick } 48244832a71SVasily Khoruzhick err = snd_usb_ctl_msg(mixer->chip->dev, 48344832a71SVasily Khoruzhick usb_sndctrlpipe(mixer->chip->dev, 0), UAC_SET_CUR, 48444832a71SVasily Khoruzhick USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 48544832a71SVasily Khoruzhick 0x0400, 0x0e00, buf, 2); 48644832a71SVasily Khoruzhick out: 48744832a71SVasily Khoruzhick up_read(&mixer->chip->shutdown_rwsem); 48844832a71SVasily Khoruzhick if (err < 0) 48944832a71SVasily Khoruzhick return err; 49044832a71SVasily Khoruzhick kcontrol->private_value = value; 49144832a71SVasily Khoruzhick return changed; 49244832a71SVasily Khoruzhick } 49344832a71SVasily Khoruzhick 49444832a71SVasily Khoruzhick 49544832a71SVasily Khoruzhick static struct snd_kcontrol_new snd_emu0204_controls[] = { 49644832a71SVasily Khoruzhick { 49744832a71SVasily Khoruzhick .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 49844832a71SVasily Khoruzhick .name = "Front Jack Channels", 49944832a71SVasily Khoruzhick .info = snd_emu0204_ch_switch_info, 50044832a71SVasily Khoruzhick .get = snd_emu0204_ch_switch_get, 50144832a71SVasily Khoruzhick .put = snd_emu0204_ch_switch_put, 50244832a71SVasily Khoruzhick .private_value = 0, 50344832a71SVasily Khoruzhick }, 50444832a71SVasily Khoruzhick }; 50544832a71SVasily Khoruzhick 50644832a71SVasily Khoruzhick static int snd_emu0204_controls_create(struct usb_mixer_interface *mixer) 50744832a71SVasily Khoruzhick { 50844832a71SVasily Khoruzhick int i, err; 50944832a71SVasily Khoruzhick 51044832a71SVasily Khoruzhick for (i = 0; i < ARRAY_SIZE(snd_emu0204_controls); ++i) { 51144832a71SVasily Khoruzhick err = snd_ctl_add(mixer->chip->card, 51244832a71SVasily Khoruzhick snd_ctl_new1(&snd_emu0204_controls[i], mixer)); 51344832a71SVasily Khoruzhick if (err < 0) 51444832a71SVasily Khoruzhick return err; 51544832a71SVasily Khoruzhick } 51644832a71SVasily Khoruzhick 51744832a71SVasily Khoruzhick return 0; 51844832a71SVasily Khoruzhick } 5191d31affbSDenis Washington /* ASUS Xonar U1 / U3 controls */ 5201d31affbSDenis Washington 5217b1eda22SDaniel Mack static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, 5227b1eda22SDaniel Mack struct snd_ctl_elem_value *ucontrol) 5237b1eda22SDaniel Mack { 5247b1eda22SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 5257b1eda22SDaniel Mack 5267b1eda22SDaniel Mack ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02); 5277b1eda22SDaniel Mack return 0; 5287b1eda22SDaniel Mack } 5297b1eda22SDaniel Mack 5307b1eda22SDaniel Mack static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, 5317b1eda22SDaniel Mack struct snd_ctl_elem_value *ucontrol) 5327b1eda22SDaniel Mack { 5337b1eda22SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 5347b1eda22SDaniel Mack u8 old_status, new_status; 5357b1eda22SDaniel Mack int err, changed; 5367b1eda22SDaniel Mack 5377b1eda22SDaniel Mack old_status = mixer->xonar_u1_status; 5387b1eda22SDaniel Mack if (ucontrol->value.integer.value[0]) 5397b1eda22SDaniel Mack new_status = old_status | 0x02; 5407b1eda22SDaniel Mack else 5417b1eda22SDaniel Mack new_status = old_status & ~0x02; 5427b1eda22SDaniel Mack changed = new_status != old_status; 543888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 544888ea7d5STakashi Iwai if (mixer->chip->shutdown) 545888ea7d5STakashi Iwai err = -ENODEV; 546888ea7d5STakashi Iwai else 5477b1eda22SDaniel Mack err = snd_usb_ctl_msg(mixer->chip->dev, 5487b1eda22SDaniel Mack usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, 5497b1eda22SDaniel Mack USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 55017d900c4SClemens Ladisch 50, 0, &new_status, 1); 551888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 5527b1eda22SDaniel Mack if (err < 0) 5537b1eda22SDaniel Mack return err; 5547b1eda22SDaniel Mack mixer->xonar_u1_status = new_status; 5557b1eda22SDaniel Mack return changed; 5567b1eda22SDaniel Mack } 5577b1eda22SDaniel Mack 5587b1eda22SDaniel Mack static struct snd_kcontrol_new snd_xonar_u1_output_switch = { 5597b1eda22SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5607b1eda22SDaniel Mack .name = "Digital Playback Switch", 5617b1eda22SDaniel Mack .info = snd_ctl_boolean_mono_info, 5627b1eda22SDaniel Mack .get = snd_xonar_u1_switch_get, 5637b1eda22SDaniel Mack .put = snd_xonar_u1_switch_put, 5647b1eda22SDaniel Mack }; 5657b1eda22SDaniel Mack 5667b1eda22SDaniel Mack static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) 5677b1eda22SDaniel Mack { 5687b1eda22SDaniel Mack int err; 5697b1eda22SDaniel Mack 5707b1eda22SDaniel Mack err = snd_ctl_add(mixer->chip->card, 5717b1eda22SDaniel Mack snd_ctl_new1(&snd_xonar_u1_output_switch, mixer)); 5727b1eda22SDaniel Mack if (err < 0) 5737b1eda22SDaniel Mack return err; 5747b1eda22SDaniel Mack mixer->xonar_u1_status = 0x05; 5757b1eda22SDaniel Mack return 0; 5767b1eda22SDaniel Mack } 5777b1eda22SDaniel Mack 57854a8c500SDaniel Mack /* Native Instruments device quirks */ 57954a8c500SDaniel Mack 58054a8c500SDaniel Mack #define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex)) 58154a8c500SDaniel Mack 58254a8c500SDaniel Mack static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, 58354a8c500SDaniel Mack struct snd_ctl_elem_value *ucontrol) 58454a8c500SDaniel Mack { 58554a8c500SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 58654a8c500SDaniel Mack struct usb_device *dev = mixer->chip->dev; 58754a8c500SDaniel Mack u8 bRequest = (kcontrol->private_value >> 16) & 0xff; 58854a8c500SDaniel Mack u16 wIndex = kcontrol->private_value & 0xffff; 58954a8c500SDaniel Mack u8 tmp; 590888ea7d5STakashi Iwai int ret; 59154a8c500SDaniel Mack 592888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 593888ea7d5STakashi Iwai if (mixer->chip->shutdown) 594888ea7d5STakashi Iwai ret = -ENODEV; 595888ea7d5STakashi Iwai else 596888ea7d5STakashi Iwai ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, 59754a8c500SDaniel Mack USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 598889d6684SEldad Zack 0, wIndex, 59954a8c500SDaniel Mack &tmp, sizeof(tmp), 1000); 600888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 60154a8c500SDaniel Mack 60254a8c500SDaniel Mack if (ret < 0) { 60354a8c500SDaniel Mack snd_printk(KERN_ERR 60454a8c500SDaniel Mack "unable to issue vendor read request (ret = %d)", ret); 60554a8c500SDaniel Mack return ret; 60654a8c500SDaniel Mack } 60754a8c500SDaniel Mack 60854a8c500SDaniel Mack ucontrol->value.integer.value[0] = tmp; 60954a8c500SDaniel Mack 61054a8c500SDaniel Mack return 0; 61154a8c500SDaniel Mack } 61254a8c500SDaniel Mack 61354a8c500SDaniel Mack static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, 61454a8c500SDaniel Mack struct snd_ctl_elem_value *ucontrol) 61554a8c500SDaniel Mack { 61654a8c500SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 61754a8c500SDaniel Mack struct usb_device *dev = mixer->chip->dev; 61854a8c500SDaniel Mack u8 bRequest = (kcontrol->private_value >> 16) & 0xff; 61954a8c500SDaniel Mack u16 wIndex = kcontrol->private_value & 0xffff; 62054a8c500SDaniel Mack u16 wValue = ucontrol->value.integer.value[0]; 621888ea7d5STakashi Iwai int ret; 62254a8c500SDaniel Mack 623888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 624888ea7d5STakashi Iwai if (mixer->chip->shutdown) 625888ea7d5STakashi Iwai ret = -ENODEV; 626888ea7d5STakashi Iwai else 627888ea7d5STakashi Iwai ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, 62854a8c500SDaniel Mack USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 629889d6684SEldad Zack wValue, wIndex, 63054a8c500SDaniel Mack NULL, 0, 1000); 631888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 63254a8c500SDaniel Mack 63354a8c500SDaniel Mack if (ret < 0) { 63454a8c500SDaniel Mack snd_printk(KERN_ERR 63554a8c500SDaniel Mack "unable to issue vendor write request (ret = %d)", ret); 63654a8c500SDaniel Mack return ret; 63754a8c500SDaniel Mack } 63854a8c500SDaniel Mack 63954a8c500SDaniel Mack return 0; 64054a8c500SDaniel Mack } 64154a8c500SDaniel Mack 64254a8c500SDaniel Mack static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = { 64354a8c500SDaniel Mack { 64454a8c500SDaniel Mack .name = "Direct Thru Channel A", 64554a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x03), 64654a8c500SDaniel Mack }, 64754a8c500SDaniel Mack { 64854a8c500SDaniel Mack .name = "Direct Thru Channel B", 64954a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x05), 65054a8c500SDaniel Mack }, 65154a8c500SDaniel Mack { 65254a8c500SDaniel Mack .name = "Phono Input Channel A", 65354a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x03), 65454a8c500SDaniel Mack }, 65554a8c500SDaniel Mack { 65654a8c500SDaniel Mack .name = "Phono Input Channel B", 65754a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x05), 65854a8c500SDaniel Mack }, 65954a8c500SDaniel Mack }; 66054a8c500SDaniel Mack 66154a8c500SDaniel Mack static struct snd_kcontrol_new snd_nativeinstruments_ta10_mixers[] = { 66254a8c500SDaniel Mack { 66354a8c500SDaniel Mack .name = "Direct Thru Channel A", 66454a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x03), 66554a8c500SDaniel Mack }, 66654a8c500SDaniel Mack { 66754a8c500SDaniel Mack .name = "Direct Thru Channel B", 66854a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x05), 66954a8c500SDaniel Mack }, 67054a8c500SDaniel Mack { 67154a8c500SDaniel Mack .name = "Direct Thru Channel C", 67254a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x07), 67354a8c500SDaniel Mack }, 67454a8c500SDaniel Mack { 67554a8c500SDaniel Mack .name = "Direct Thru Channel D", 67654a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x09), 67754a8c500SDaniel Mack }, 67854a8c500SDaniel Mack { 67954a8c500SDaniel Mack .name = "Phono Input Channel A", 68054a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x03), 68154a8c500SDaniel Mack }, 68254a8c500SDaniel Mack { 68354a8c500SDaniel Mack .name = "Phono Input Channel B", 68454a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x05), 68554a8c500SDaniel Mack }, 68654a8c500SDaniel Mack { 68754a8c500SDaniel Mack .name = "Phono Input Channel C", 68854a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x07), 68954a8c500SDaniel Mack }, 69054a8c500SDaniel Mack { 69154a8c500SDaniel Mack .name = "Phono Input Channel D", 69254a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x09), 69354a8c500SDaniel Mack }, 69454a8c500SDaniel Mack }; 69554a8c500SDaniel Mack 69654a8c500SDaniel Mack static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, 69754a8c500SDaniel Mack const struct snd_kcontrol_new *kc, 69854a8c500SDaniel Mack unsigned int count) 69954a8c500SDaniel Mack { 70054a8c500SDaniel Mack int i, err = 0; 70154a8c500SDaniel Mack struct snd_kcontrol_new template = { 70254a8c500SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 70354a8c500SDaniel Mack .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 70454a8c500SDaniel Mack .get = snd_nativeinstruments_control_get, 70554a8c500SDaniel Mack .put = snd_nativeinstruments_control_put, 70654a8c500SDaniel Mack .info = snd_ctl_boolean_mono_info, 70754a8c500SDaniel Mack }; 70854a8c500SDaniel Mack 70954a8c500SDaniel Mack for (i = 0; i < count; i++) { 71054a8c500SDaniel Mack struct snd_kcontrol *c; 71154a8c500SDaniel Mack 71254a8c500SDaniel Mack template.name = kc[i].name; 71354a8c500SDaniel Mack template.private_value = kc[i].private_value; 71454a8c500SDaniel Mack 71554a8c500SDaniel Mack c = snd_ctl_new1(&template, mixer); 71654a8c500SDaniel Mack err = snd_ctl_add(mixer->chip->card, c); 71754a8c500SDaniel Mack 71854a8c500SDaniel Mack if (err < 0) 71954a8c500SDaniel Mack break; 72054a8c500SDaniel Mack } 72154a8c500SDaniel Mack 72254a8c500SDaniel Mack return err; 72354a8c500SDaniel Mack } 72454a8c500SDaniel Mack 725d5a0bf6cSDaniel Mack /* M-Audio FastTrack Ultra quirks */ 726e9a25e04SMatt Gruskin /* FTU Effect switch (also used by C400/C600) */ 727d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val { 728d34bf148SFelix Homann struct usb_mixer_interface *mixer; 729d34bf148SFelix Homann int cached_value; 730d34bf148SFelix Homann int is_cached; 731d847ce0eSEldad Zack int bUnitID; 732d847ce0eSEldad Zack int validx; 733d34bf148SFelix Homann }; 734d34bf148SFelix Homann 735d34bf148SFelix Homann static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, 736d34bf148SFelix Homann struct snd_ctl_elem_info *uinfo) 737d34bf148SFelix Homann { 738d34bf148SFelix Homann static const char *texts[8] = {"Room 1", 739d34bf148SFelix Homann "Room 2", 740d34bf148SFelix Homann "Room 3", 741d34bf148SFelix Homann "Hall 1", 742d34bf148SFelix Homann "Hall 2", 743d34bf148SFelix Homann "Plate", 744d34bf148SFelix Homann "Delay", 745d34bf148SFelix Homann "Echo" 746d34bf148SFelix Homann }; 747d34bf148SFelix Homann 748d34bf148SFelix Homann uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 749d34bf148SFelix Homann uinfo->count = 1; 750d34bf148SFelix Homann uinfo->value.enumerated.items = 8; 751d34bf148SFelix Homann if (uinfo->value.enumerated.item > 7) 752d34bf148SFelix Homann uinfo->value.enumerated.item = 7; 753d34bf148SFelix Homann strcpy(uinfo->value.enumerated.name, 754d34bf148SFelix Homann texts[uinfo->value.enumerated.item]); 755d34bf148SFelix Homann 756d34bf148SFelix Homann return 0; 757d34bf148SFelix Homann } 758d34bf148SFelix Homann 759d34bf148SFelix Homann static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, 760d34bf148SFelix Homann struct snd_ctl_elem_value *ucontrol) 761d34bf148SFelix Homann { 762d34bf148SFelix Homann struct snd_usb_audio *chip; 763d34bf148SFelix Homann struct usb_mixer_interface *mixer; 764d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val *pval; 765d34bf148SFelix Homann int err; 766d34bf148SFelix Homann unsigned char value[2]; 767d847ce0eSEldad Zack int id, validx; 768d34bf148SFelix Homann 769d34bf148SFelix Homann const int val_len = 2; 770d34bf148SFelix Homann 771d34bf148SFelix Homann value[0] = 0x00; 772d34bf148SFelix Homann value[1] = 0x00; 773d34bf148SFelix Homann 774d34bf148SFelix Homann pval = (struct snd_ftu_eff_switch_priv_val *) 775d34bf148SFelix Homann kctl->private_value; 776d34bf148SFelix Homann 777d34bf148SFelix Homann if (pval->is_cached) { 778d34bf148SFelix Homann ucontrol->value.enumerated.item[0] = pval->cached_value; 779d34bf148SFelix Homann return 0; 780d34bf148SFelix Homann } 781d34bf148SFelix Homann 782d34bf148SFelix Homann mixer = (struct usb_mixer_interface *) pval->mixer; 783d34bf148SFelix Homann if (snd_BUG_ON(!mixer)) 784d34bf148SFelix Homann return -EINVAL; 785d34bf148SFelix Homann 786d34bf148SFelix Homann chip = (struct snd_usb_audio *) mixer->chip; 787d34bf148SFelix Homann if (snd_BUG_ON(!chip)) 788d34bf148SFelix Homann return -EINVAL; 789d34bf148SFelix Homann 790d847ce0eSEldad Zack id = pval->bUnitID; 791d847ce0eSEldad Zack validx = pval->validx; 792d34bf148SFelix Homann 793888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 794888ea7d5STakashi Iwai if (mixer->chip->shutdown) 795888ea7d5STakashi Iwai err = -ENODEV; 796888ea7d5STakashi Iwai else 797d34bf148SFelix Homann err = snd_usb_ctl_msg(chip->dev, 798d34bf148SFelix Homann usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, 799d34bf148SFelix Homann USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 800d34bf148SFelix Homann validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), 801d34bf148SFelix Homann value, val_len); 802888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 803d34bf148SFelix Homann if (err < 0) 804d34bf148SFelix Homann return err; 805d34bf148SFelix Homann 806d34bf148SFelix Homann ucontrol->value.enumerated.item[0] = value[0]; 807d34bf148SFelix Homann pval->cached_value = value[0]; 808d34bf148SFelix Homann pval->is_cached = 1; 809d34bf148SFelix Homann 810d34bf148SFelix Homann return 0; 811d34bf148SFelix Homann } 812d34bf148SFelix Homann 813d34bf148SFelix Homann static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, 814d34bf148SFelix Homann struct snd_ctl_elem_value *ucontrol) 815d34bf148SFelix Homann { 816d34bf148SFelix Homann struct snd_usb_audio *chip; 817d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val *pval; 818d34bf148SFelix Homann 819d34bf148SFelix Homann struct usb_mixer_interface *mixer; 820d34bf148SFelix Homann int changed, cur_val, err, new_val; 821d34bf148SFelix Homann unsigned char value[2]; 822d847ce0eSEldad Zack int id, validx; 823d34bf148SFelix Homann 824d34bf148SFelix Homann const int val_len = 2; 825d34bf148SFelix Homann 826d34bf148SFelix Homann changed = 0; 827d34bf148SFelix Homann 828d34bf148SFelix Homann pval = (struct snd_ftu_eff_switch_priv_val *) 829d34bf148SFelix Homann kctl->private_value; 830d34bf148SFelix Homann cur_val = pval->cached_value; 831d34bf148SFelix Homann new_val = ucontrol->value.enumerated.item[0]; 832d34bf148SFelix Homann 833d34bf148SFelix Homann mixer = (struct usb_mixer_interface *) pval->mixer; 834d34bf148SFelix Homann if (snd_BUG_ON(!mixer)) 835d34bf148SFelix Homann return -EINVAL; 836d34bf148SFelix Homann 837d34bf148SFelix Homann chip = (struct snd_usb_audio *) mixer->chip; 838d34bf148SFelix Homann if (snd_BUG_ON(!chip)) 839d34bf148SFelix Homann return -EINVAL; 840d34bf148SFelix Homann 841d847ce0eSEldad Zack id = pval->bUnitID; 842d847ce0eSEldad Zack validx = pval->validx; 843d847ce0eSEldad Zack 844d34bf148SFelix Homann if (!pval->is_cached) { 845d34bf148SFelix Homann /* Read current value */ 846888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 847888ea7d5STakashi Iwai if (mixer->chip->shutdown) 848888ea7d5STakashi Iwai err = -ENODEV; 849888ea7d5STakashi Iwai else 850d34bf148SFelix Homann err = snd_usb_ctl_msg(chip->dev, 851d34bf148SFelix Homann usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, 852d34bf148SFelix Homann USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 853d34bf148SFelix Homann validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), 854d34bf148SFelix Homann value, val_len); 855888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 856d34bf148SFelix Homann if (err < 0) 857d34bf148SFelix Homann return err; 858d34bf148SFelix Homann 859d34bf148SFelix Homann cur_val = value[0]; 860d34bf148SFelix Homann pval->cached_value = cur_val; 861d34bf148SFelix Homann pval->is_cached = 1; 862d34bf148SFelix Homann } 863d34bf148SFelix Homann /* update value if needed */ 864d34bf148SFelix Homann if (cur_val != new_val) { 865d34bf148SFelix Homann value[0] = new_val; 866d34bf148SFelix Homann value[1] = 0; 867888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 868888ea7d5STakashi Iwai if (mixer->chip->shutdown) 869888ea7d5STakashi Iwai err = -ENODEV; 870888ea7d5STakashi Iwai else 871d34bf148SFelix Homann err = snd_usb_ctl_msg(chip->dev, 872d34bf148SFelix Homann usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, 873d34bf148SFelix Homann USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 874d34bf148SFelix Homann validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), 875d34bf148SFelix Homann value, val_len); 876888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 877d34bf148SFelix Homann if (err < 0) 878d34bf148SFelix Homann return err; 879d34bf148SFelix Homann 880d34bf148SFelix Homann pval->cached_value = new_val; 881d34bf148SFelix Homann pval->is_cached = 1; 882d34bf148SFelix Homann changed = 1; 883d34bf148SFelix Homann } 884d34bf148SFelix Homann 885d34bf148SFelix Homann return changed; 886d34bf148SFelix Homann } 887d34bf148SFelix Homann 888d847ce0eSEldad Zack static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, 889d847ce0eSEldad Zack int validx, int bUnitID) 890d34bf148SFelix Homann { 891d34bf148SFelix Homann static struct snd_kcontrol_new template = { 892d34bf148SFelix Homann .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 893d34bf148SFelix Homann .name = "Effect Program Switch", 894d34bf148SFelix Homann .index = 0, 895d34bf148SFelix Homann .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 896d34bf148SFelix Homann .info = snd_ftu_eff_switch_info, 897d34bf148SFelix Homann .get = snd_ftu_eff_switch_get, 898d34bf148SFelix Homann .put = snd_ftu_eff_switch_put 899d34bf148SFelix Homann }; 900d34bf148SFelix Homann 901d34bf148SFelix Homann int err; 902d34bf148SFelix Homann struct snd_kcontrol *kctl; 903d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val *pval; 904d34bf148SFelix Homann 905d34bf148SFelix Homann pval = kzalloc(sizeof(*pval), GFP_KERNEL); 906d34bf148SFelix Homann if (!pval) 907d34bf148SFelix Homann return -ENOMEM; 908d34bf148SFelix Homann 909d34bf148SFelix Homann pval->cached_value = 0; 910d34bf148SFelix Homann pval->is_cached = 0; 911d34bf148SFelix Homann pval->mixer = mixer; 912d847ce0eSEldad Zack pval->bUnitID = bUnitID; 913d847ce0eSEldad Zack pval->validx = validx; 914d34bf148SFelix Homann 915d34bf148SFelix Homann template.private_value = (unsigned long) pval; 916d34bf148SFelix Homann kctl = snd_ctl_new1(&template, mixer->chip); 917d34bf148SFelix Homann if (!kctl) { 918d34bf148SFelix Homann kfree(pval); 919d34bf148SFelix Homann return -ENOMEM; 920d34bf148SFelix Homann } 921d34bf148SFelix Homann 922d34bf148SFelix Homann err = snd_ctl_add(mixer->chip->card, kctl); 923d34bf148SFelix Homann if (err < 0) 924d34bf148SFelix Homann return err; 925d34bf148SFelix Homann 926d34bf148SFelix Homann return 0; 927d34bf148SFelix Homann } 928d5a0bf6cSDaniel Mack 929cfe8f97cSFelix Homann /* Create volume controls for FTU devices*/ 930cfe8f97cSFelix Homann static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) 931d5a0bf6cSDaniel Mack { 932d5a0bf6cSDaniel Mack char name[64]; 9338a4d1d39SFelix Homann unsigned int control, cmask; 934d5a0bf6cSDaniel Mack int in, out, err; 935d5a0bf6cSDaniel Mack 9368a4d1d39SFelix Homann const unsigned int id = 5; 9378a4d1d39SFelix Homann const int val_type = USB_MIXER_S16; 9388a4d1d39SFelix Homann 939d5a0bf6cSDaniel Mack for (out = 0; out < 8; out++) { 9408a4d1d39SFelix Homann control = out + 1; 941d5a0bf6cSDaniel Mack for (in = 0; in < 8; in++) { 9428a4d1d39SFelix Homann cmask = 1 << in; 943d5a0bf6cSDaniel Mack snprintf(name, sizeof(name), 9448a4d1d39SFelix Homann "AIn%d - Out%d Capture Volume", 9458a4d1d39SFelix Homann in + 1, out + 1); 9468a4d1d39SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, 9478a4d1d39SFelix Homann cmask, val_type, name, 94825ee7ef8SFelix Homann &snd_usb_mixer_vol_tlv); 949d5a0bf6cSDaniel Mack if (err < 0) 950d5a0bf6cSDaniel Mack return err; 951d5a0bf6cSDaniel Mack } 952d5a0bf6cSDaniel Mack for (in = 8; in < 16; in++) { 9538a4d1d39SFelix Homann cmask = 1 << in; 954d5a0bf6cSDaniel Mack snprintf(name, sizeof(name), 9558a4d1d39SFelix Homann "DIn%d - Out%d Playback Volume", 9568a4d1d39SFelix Homann in - 7, out + 1); 9578a4d1d39SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, 9588a4d1d39SFelix Homann cmask, val_type, name, 95925ee7ef8SFelix Homann &snd_usb_mixer_vol_tlv); 960d5a0bf6cSDaniel Mack if (err < 0) 961d5a0bf6cSDaniel Mack return err; 962d5a0bf6cSDaniel Mack } 963d5a0bf6cSDaniel Mack } 964d5a0bf6cSDaniel Mack 965d5a0bf6cSDaniel Mack return 0; 966d5a0bf6cSDaniel Mack } 967d5a0bf6cSDaniel Mack 968d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */ 969d34bf148SFelix Homann static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer) 970d34bf148SFelix Homann { 971d34bf148SFelix Homann static const char name[] = "Effect Volume"; 972d34bf148SFelix Homann const unsigned int id = 6; 973d34bf148SFelix Homann const int val_type = USB_MIXER_U8; 974d34bf148SFelix Homann const unsigned int control = 2; 975d34bf148SFelix Homann const unsigned int cmask = 0; 976d34bf148SFelix Homann 977d34bf148SFelix Homann return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 978d34bf148SFelix Homann name, snd_usb_mixer_vol_tlv); 979d34bf148SFelix Homann } 980d34bf148SFelix Homann 981d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */ 982d34bf148SFelix Homann static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer) 983d34bf148SFelix Homann { 984d34bf148SFelix Homann static const char name[] = "Effect Duration"; 985d34bf148SFelix Homann const unsigned int id = 6; 986d34bf148SFelix Homann const int val_type = USB_MIXER_S16; 987d34bf148SFelix Homann const unsigned int control = 3; 988d34bf148SFelix Homann const unsigned int cmask = 0; 989d34bf148SFelix Homann 990d34bf148SFelix Homann return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 991d34bf148SFelix Homann name, snd_usb_mixer_vol_tlv); 992d34bf148SFelix Homann } 993d34bf148SFelix Homann 994d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */ 995d34bf148SFelix Homann static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) 996d34bf148SFelix Homann { 997d34bf148SFelix Homann static const char name[] = "Effect Feedback Volume"; 998d34bf148SFelix Homann const unsigned int id = 6; 999d34bf148SFelix Homann const int val_type = USB_MIXER_U8; 1000d34bf148SFelix Homann const unsigned int control = 4; 1001d34bf148SFelix Homann const unsigned int cmask = 0; 1002d34bf148SFelix Homann 1003d34bf148SFelix Homann return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 1004d34bf148SFelix Homann name, NULL); 1005d34bf148SFelix Homann } 1006d34bf148SFelix Homann 1007d34bf148SFelix Homann static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer) 1008d34bf148SFelix Homann { 1009d34bf148SFelix Homann unsigned int cmask; 1010d34bf148SFelix Homann int err, ch; 1011d34bf148SFelix Homann char name[48]; 1012d34bf148SFelix Homann 1013d34bf148SFelix Homann const unsigned int id = 7; 1014d34bf148SFelix Homann const int val_type = USB_MIXER_S16; 1015d34bf148SFelix Homann const unsigned int control = 7; 1016d34bf148SFelix Homann 1017d34bf148SFelix Homann for (ch = 0; ch < 4; ++ch) { 1018d34bf148SFelix Homann cmask = 1 << ch; 1019d34bf148SFelix Homann snprintf(name, sizeof(name), 1020d34bf148SFelix Homann "Effect Return %d Volume", ch + 1); 1021d34bf148SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, 1022d34bf148SFelix Homann cmask, val_type, name, 1023d34bf148SFelix Homann snd_usb_mixer_vol_tlv); 1024d34bf148SFelix Homann if (err < 0) 1025d34bf148SFelix Homann return err; 1026d34bf148SFelix Homann } 1027d34bf148SFelix Homann 1028d34bf148SFelix Homann return 0; 1029d34bf148SFelix Homann } 1030d34bf148SFelix Homann 1031d34bf148SFelix Homann static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) 1032d34bf148SFelix Homann { 1033d34bf148SFelix Homann unsigned int cmask; 1034d34bf148SFelix Homann int err, ch; 1035d34bf148SFelix Homann char name[48]; 1036d34bf148SFelix Homann 1037d34bf148SFelix Homann const unsigned int id = 5; 1038d34bf148SFelix Homann const int val_type = USB_MIXER_S16; 1039d34bf148SFelix Homann const unsigned int control = 9; 1040d34bf148SFelix Homann 1041d34bf148SFelix Homann for (ch = 0; ch < 8; ++ch) { 1042d34bf148SFelix Homann cmask = 1 << ch; 1043d34bf148SFelix Homann snprintf(name, sizeof(name), 1044d34bf148SFelix Homann "Effect Send AIn%d Volume", ch + 1); 1045d34bf148SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, cmask, 1046d34bf148SFelix Homann val_type, name, 1047d34bf148SFelix Homann snd_usb_mixer_vol_tlv); 1048d34bf148SFelix Homann if (err < 0) 1049d34bf148SFelix Homann return err; 1050d34bf148SFelix Homann } 1051d34bf148SFelix Homann for (ch = 8; ch < 16; ++ch) { 1052d34bf148SFelix Homann cmask = 1 << ch; 1053d34bf148SFelix Homann snprintf(name, sizeof(name), 1054d34bf148SFelix Homann "Effect Send DIn%d Volume", ch - 7); 1055d34bf148SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, cmask, 1056d34bf148SFelix Homann val_type, name, 1057d34bf148SFelix Homann snd_usb_mixer_vol_tlv); 1058d34bf148SFelix Homann if (err < 0) 1059d34bf148SFelix Homann return err; 1060d34bf148SFelix Homann } 1061d34bf148SFelix Homann return 0; 1062d34bf148SFelix Homann } 1063d34bf148SFelix Homann 1064cfe8f97cSFelix Homann static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) 10657536c301SMark Hills { 10668a4d1d39SFelix Homann int err; 10677536c301SMark Hills 1068cfe8f97cSFelix Homann err = snd_ftu_create_volume_ctls(mixer); 10698a4d1d39SFelix Homann if (err < 0) 10708a4d1d39SFelix Homann return err; 10717536c301SMark Hills 1072d847ce0eSEldad Zack err = snd_ftu_create_effect_switch(mixer, 1, 6); 1073d34bf148SFelix Homann if (err < 0) 1074d34bf148SFelix Homann return err; 1075d847ce0eSEldad Zack 1076d34bf148SFelix Homann err = snd_ftu_create_effect_volume_ctl(mixer); 1077d34bf148SFelix Homann if (err < 0) 1078d34bf148SFelix Homann return err; 1079d34bf148SFelix Homann 1080d34bf148SFelix Homann err = snd_ftu_create_effect_duration_ctl(mixer); 1081d34bf148SFelix Homann if (err < 0) 1082d34bf148SFelix Homann return err; 1083d34bf148SFelix Homann 1084d34bf148SFelix Homann err = snd_ftu_create_effect_feedback_ctl(mixer); 1085d34bf148SFelix Homann if (err < 0) 1086d34bf148SFelix Homann return err; 1087d34bf148SFelix Homann 1088d34bf148SFelix Homann err = snd_ftu_create_effect_return_ctls(mixer); 1089d34bf148SFelix Homann if (err < 0) 1090d34bf148SFelix Homann return err; 1091d34bf148SFelix Homann 1092d34bf148SFelix Homann err = snd_ftu_create_effect_send_ctls(mixer); 1093d34bf148SFelix Homann if (err < 0) 1094d34bf148SFelix Homann return err; 1095d34bf148SFelix Homann 10968a4d1d39SFelix Homann return 0; 10977536c301SMark Hills } 10987536c301SMark Hills 10997b1eda22SDaniel Mack void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, 11007b1eda22SDaniel Mack unsigned char samplerate_id) 11017b1eda22SDaniel Mack { 11027b1eda22SDaniel Mack struct usb_mixer_interface *mixer; 11037b1eda22SDaniel Mack struct usb_mixer_elem_info *cval; 11047b1eda22SDaniel Mack int unitid = 12; /* SamleRate ExtensionUnit ID */ 11057b1eda22SDaniel Mack 11067b1eda22SDaniel Mack list_for_each_entry(mixer, &chip->mixer_list, list) { 11077b1eda22SDaniel Mack cval = mixer->id_elems[unitid]; 11087b1eda22SDaniel Mack if (cval) { 11097b1eda22SDaniel Mack snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, 11107b1eda22SDaniel Mack cval->control << 8, 11117b1eda22SDaniel Mack samplerate_id); 11127b1eda22SDaniel Mack snd_usb_mixer_notify_id(mixer, unitid); 11137b1eda22SDaniel Mack } 11147b1eda22SDaniel Mack break; 11157b1eda22SDaniel Mack } 11167b1eda22SDaniel Mack } 11177b1eda22SDaniel Mack 1118e9a25e04SMatt Gruskin /* M-Audio Fast Track C400/C600 */ 1119e9a25e04SMatt Gruskin /* C400/C600 volume controls, this control needs a volume quirk, see mixer.c */ 112009d8e3a7SEldad Zack static int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer) 112109d8e3a7SEldad Zack { 112209d8e3a7SEldad Zack char name[64]; 112309d8e3a7SEldad Zack unsigned int cmask, offset; 112409d8e3a7SEldad Zack int out, chan, err; 1125e9a25e04SMatt Gruskin int num_outs = 0; 1126e9a25e04SMatt Gruskin int num_ins = 0; 112709d8e3a7SEldad Zack 112809d8e3a7SEldad Zack const unsigned int id = 0x40; 112909d8e3a7SEldad Zack const int val_type = USB_MIXER_S16; 113009d8e3a7SEldad Zack const int control = 1; 113109d8e3a7SEldad Zack 1132e9a25e04SMatt Gruskin switch (mixer->chip->usb_id) { 1133e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2030): 1134e9a25e04SMatt Gruskin num_outs = 6; 1135e9a25e04SMatt Gruskin num_ins = 4; 1136e9a25e04SMatt Gruskin break; 1137e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2031): 1138e9a25e04SMatt Gruskin num_outs = 8; 1139e9a25e04SMatt Gruskin num_ins = 6; 1140e9a25e04SMatt Gruskin break; 1141e9a25e04SMatt Gruskin } 1142e9a25e04SMatt Gruskin 1143e9a25e04SMatt Gruskin for (chan = 0; chan < num_outs + num_ins; chan++) { 1144e9a25e04SMatt Gruskin for (out = 0; out < num_outs; out++) { 1145e9a25e04SMatt Gruskin if (chan < num_outs) { 114609d8e3a7SEldad Zack snprintf(name, sizeof(name), 114709d8e3a7SEldad Zack "PCM%d-Out%d Playback Volume", 114809d8e3a7SEldad Zack chan + 1, out + 1); 114909d8e3a7SEldad Zack } else { 115009d8e3a7SEldad Zack snprintf(name, sizeof(name), 115109d8e3a7SEldad Zack "In%d-Out%d Playback Volume", 1152e9a25e04SMatt Gruskin chan - num_outs + 1, out + 1); 115309d8e3a7SEldad Zack } 115409d8e3a7SEldad Zack 115509d8e3a7SEldad Zack cmask = (out == 0) ? 0 : 1 << (out - 1); 1156e9a25e04SMatt Gruskin offset = chan * num_outs; 115709d8e3a7SEldad Zack err = snd_create_std_mono_ctl_offset(mixer, id, control, 115809d8e3a7SEldad Zack cmask, val_type, offset, name, 115909d8e3a7SEldad Zack &snd_usb_mixer_vol_tlv); 116009d8e3a7SEldad Zack if (err < 0) 116109d8e3a7SEldad Zack return err; 116209d8e3a7SEldad Zack } 116309d8e3a7SEldad Zack } 116409d8e3a7SEldad Zack 116509d8e3a7SEldad Zack return 0; 116609d8e3a7SEldad Zack } 116709d8e3a7SEldad Zack 116809d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */ 116909d8e3a7SEldad Zack static int snd_c400_create_effect_volume_ctl(struct usb_mixer_interface *mixer) 117009d8e3a7SEldad Zack { 117109d8e3a7SEldad Zack static const char name[] = "Effect Volume"; 117209d8e3a7SEldad Zack const unsigned int id = 0x43; 117309d8e3a7SEldad Zack const int val_type = USB_MIXER_U8; 117409d8e3a7SEldad Zack const unsigned int control = 3; 117509d8e3a7SEldad Zack const unsigned int cmask = 0; 117609d8e3a7SEldad Zack 117709d8e3a7SEldad Zack return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 117809d8e3a7SEldad Zack name, snd_usb_mixer_vol_tlv); 117909d8e3a7SEldad Zack } 118009d8e3a7SEldad Zack 118109d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */ 118209d8e3a7SEldad Zack static int snd_c400_create_effect_duration_ctl(struct usb_mixer_interface *mixer) 118309d8e3a7SEldad Zack { 118409d8e3a7SEldad Zack static const char name[] = "Effect Duration"; 118509d8e3a7SEldad Zack const unsigned int id = 0x43; 118609d8e3a7SEldad Zack const int val_type = USB_MIXER_S16; 118709d8e3a7SEldad Zack const unsigned int control = 4; 118809d8e3a7SEldad Zack const unsigned int cmask = 0; 118909d8e3a7SEldad Zack 119009d8e3a7SEldad Zack return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 119109d8e3a7SEldad Zack name, snd_usb_mixer_vol_tlv); 119209d8e3a7SEldad Zack } 119309d8e3a7SEldad Zack 119409d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */ 119509d8e3a7SEldad Zack static int snd_c400_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) 119609d8e3a7SEldad Zack { 119709d8e3a7SEldad Zack static const char name[] = "Effect Feedback Volume"; 119809d8e3a7SEldad Zack const unsigned int id = 0x43; 119909d8e3a7SEldad Zack const int val_type = USB_MIXER_U8; 120009d8e3a7SEldad Zack const unsigned int control = 5; 120109d8e3a7SEldad Zack const unsigned int cmask = 0; 120209d8e3a7SEldad Zack 120309d8e3a7SEldad Zack return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 120409d8e3a7SEldad Zack name, NULL); 120509d8e3a7SEldad Zack } 120609d8e3a7SEldad Zack 120709d8e3a7SEldad Zack static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer) 120809d8e3a7SEldad Zack { 120909d8e3a7SEldad Zack char name[64]; 121009d8e3a7SEldad Zack unsigned int cmask; 121109d8e3a7SEldad Zack int chan, err; 1212e9a25e04SMatt Gruskin int num_outs = 0; 1213e9a25e04SMatt Gruskin int num_ins = 0; 121409d8e3a7SEldad Zack 121509d8e3a7SEldad Zack const unsigned int id = 0x42; 121609d8e3a7SEldad Zack const int val_type = USB_MIXER_S16; 121709d8e3a7SEldad Zack const int control = 1; 121809d8e3a7SEldad Zack 1219e9a25e04SMatt Gruskin switch (mixer->chip->usb_id) { 1220e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2030): 1221e9a25e04SMatt Gruskin num_outs = 6; 1222e9a25e04SMatt Gruskin num_ins = 4; 1223e9a25e04SMatt Gruskin break; 1224e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2031): 1225e9a25e04SMatt Gruskin num_outs = 8; 1226e9a25e04SMatt Gruskin num_ins = 6; 1227e9a25e04SMatt Gruskin break; 1228e9a25e04SMatt Gruskin } 1229e9a25e04SMatt Gruskin 1230e9a25e04SMatt Gruskin for (chan = 0; chan < num_outs + num_ins; chan++) { 1231e9a25e04SMatt Gruskin if (chan < num_outs) { 123209d8e3a7SEldad Zack snprintf(name, sizeof(name), 123309d8e3a7SEldad Zack "Effect Send DOut%d", 123409d8e3a7SEldad Zack chan + 1); 123509d8e3a7SEldad Zack } else { 123609d8e3a7SEldad Zack snprintf(name, sizeof(name), 123709d8e3a7SEldad Zack "Effect Send AIn%d", 1238e9a25e04SMatt Gruskin chan - num_outs + 1); 123909d8e3a7SEldad Zack } 124009d8e3a7SEldad Zack 124109d8e3a7SEldad Zack cmask = (chan == 0) ? 0 : 1 << (chan - 1); 124209d8e3a7SEldad Zack err = snd_create_std_mono_ctl(mixer, id, control, 124309d8e3a7SEldad Zack cmask, val_type, name, 124409d8e3a7SEldad Zack &snd_usb_mixer_vol_tlv); 124509d8e3a7SEldad Zack if (err < 0) 124609d8e3a7SEldad Zack return err; 124709d8e3a7SEldad Zack } 124809d8e3a7SEldad Zack 124909d8e3a7SEldad Zack return 0; 125009d8e3a7SEldad Zack } 125109d8e3a7SEldad Zack 125209d8e3a7SEldad Zack static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer) 125309d8e3a7SEldad Zack { 125409d8e3a7SEldad Zack char name[64]; 125509d8e3a7SEldad Zack unsigned int cmask; 125609d8e3a7SEldad Zack int chan, err; 1257e9a25e04SMatt Gruskin int num_outs = 0; 1258e9a25e04SMatt Gruskin int offset = 0; 125909d8e3a7SEldad Zack 126009d8e3a7SEldad Zack const unsigned int id = 0x40; 126109d8e3a7SEldad Zack const int val_type = USB_MIXER_S16; 126209d8e3a7SEldad Zack const int control = 1; 126309d8e3a7SEldad Zack 1264e9a25e04SMatt Gruskin switch (mixer->chip->usb_id) { 1265e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2030): 1266e9a25e04SMatt Gruskin num_outs = 6; 1267e9a25e04SMatt Gruskin offset = 0x3c; 1268e9a25e04SMatt Gruskin /* { 0x3c, 0x43, 0x3e, 0x45, 0x40, 0x47 } */ 1269e9a25e04SMatt Gruskin break; 1270e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2031): 1271e9a25e04SMatt Gruskin num_outs = 8; 1272e9a25e04SMatt Gruskin offset = 0x70; 1273e9a25e04SMatt Gruskin /* { 0x70, 0x79, 0x72, 0x7b, 0x74, 0x7d, 0x76, 0x7f } */ 1274e9a25e04SMatt Gruskin break; 1275e9a25e04SMatt Gruskin } 1276e9a25e04SMatt Gruskin 1277e9a25e04SMatt Gruskin for (chan = 0; chan < num_outs; chan++) { 127809d8e3a7SEldad Zack snprintf(name, sizeof(name), 127909d8e3a7SEldad Zack "Effect Return %d", 128009d8e3a7SEldad Zack chan + 1); 128109d8e3a7SEldad Zack 1282e9a25e04SMatt Gruskin cmask = (chan == 0) ? 0 : 1283e9a25e04SMatt Gruskin 1 << (chan + (chan % 2) * num_outs - 1); 128409d8e3a7SEldad Zack err = snd_create_std_mono_ctl_offset(mixer, id, control, 128509d8e3a7SEldad Zack cmask, val_type, offset, name, 128609d8e3a7SEldad Zack &snd_usb_mixer_vol_tlv); 128709d8e3a7SEldad Zack if (err < 0) 128809d8e3a7SEldad Zack return err; 128909d8e3a7SEldad Zack } 129009d8e3a7SEldad Zack 129109d8e3a7SEldad Zack return 0; 129209d8e3a7SEldad Zack } 129309d8e3a7SEldad Zack 129409d8e3a7SEldad Zack static int snd_c400_create_mixer(struct usb_mixer_interface *mixer) 129509d8e3a7SEldad Zack { 129609d8e3a7SEldad Zack int err; 129709d8e3a7SEldad Zack 129809d8e3a7SEldad Zack err = snd_c400_create_vol_ctls(mixer); 129909d8e3a7SEldad Zack if (err < 0) 130009d8e3a7SEldad Zack return err; 130109d8e3a7SEldad Zack 130209d8e3a7SEldad Zack err = snd_c400_create_effect_vol_ctls(mixer); 130309d8e3a7SEldad Zack if (err < 0) 130409d8e3a7SEldad Zack return err; 130509d8e3a7SEldad Zack 130609d8e3a7SEldad Zack err = snd_c400_create_effect_ret_vol_ctls(mixer); 130709d8e3a7SEldad Zack if (err < 0) 130809d8e3a7SEldad Zack return err; 130909d8e3a7SEldad Zack 131009d8e3a7SEldad Zack err = snd_ftu_create_effect_switch(mixer, 2, 0x43); 131109d8e3a7SEldad Zack if (err < 0) 131209d8e3a7SEldad Zack return err; 131309d8e3a7SEldad Zack 131409d8e3a7SEldad Zack err = snd_c400_create_effect_volume_ctl(mixer); 131509d8e3a7SEldad Zack if (err < 0) 131609d8e3a7SEldad Zack return err; 131709d8e3a7SEldad Zack 131809d8e3a7SEldad Zack err = snd_c400_create_effect_duration_ctl(mixer); 131909d8e3a7SEldad Zack if (err < 0) 132009d8e3a7SEldad Zack return err; 132109d8e3a7SEldad Zack 132209d8e3a7SEldad Zack err = snd_c400_create_effect_feedback_ctl(mixer); 132309d8e3a7SEldad Zack if (err < 0) 132409d8e3a7SEldad Zack return err; 132509d8e3a7SEldad Zack 132609d8e3a7SEldad Zack return 0; 132709d8e3a7SEldad Zack } 132809d8e3a7SEldad Zack 1329b71dad18SMark Hills /* 1330b71dad18SMark Hills * The mixer units for Ebox-44 are corrupt, and even where they 1331b71dad18SMark Hills * are valid they presents mono controls as L and R channels of 1332b71dad18SMark Hills * stereo. So we provide a good mixer here. 1333b71dad18SMark Hills */ 1334e8e7da23SSachin Kamat static struct std_mono_table ebox44_table[] = { 1335989b0138SMark Hills { 1336989b0138SMark Hills .unitid = 4, 1337989b0138SMark Hills .control = 1, 1338989b0138SMark Hills .cmask = 0x0, 1339989b0138SMark Hills .val_type = USB_MIXER_INV_BOOLEAN, 1340989b0138SMark Hills .name = "Headphone Playback Switch" 1341989b0138SMark Hills }, 1342989b0138SMark Hills { 1343989b0138SMark Hills .unitid = 4, 1344989b0138SMark Hills .control = 2, 1345989b0138SMark Hills .cmask = 0x1, 1346989b0138SMark Hills .val_type = USB_MIXER_S16, 1347989b0138SMark Hills .name = "Headphone A Mix Playback Volume" 1348989b0138SMark Hills }, 1349989b0138SMark Hills { 1350989b0138SMark Hills .unitid = 4, 1351989b0138SMark Hills .control = 2, 1352989b0138SMark Hills .cmask = 0x2, 1353989b0138SMark Hills .val_type = USB_MIXER_S16, 1354989b0138SMark Hills .name = "Headphone B Mix Playback Volume" 1355989b0138SMark Hills }, 1356b71dad18SMark Hills 1357989b0138SMark Hills { 1358989b0138SMark Hills .unitid = 7, 1359989b0138SMark Hills .control = 1, 1360989b0138SMark Hills .cmask = 0x0, 1361989b0138SMark Hills .val_type = USB_MIXER_INV_BOOLEAN, 1362989b0138SMark Hills .name = "Output Playback Switch" 1363989b0138SMark Hills }, 1364989b0138SMark Hills { 1365989b0138SMark Hills .unitid = 7, 1366989b0138SMark Hills .control = 2, 1367989b0138SMark Hills .cmask = 0x1, 1368989b0138SMark Hills .val_type = USB_MIXER_S16, 1369989b0138SMark Hills .name = "Output A Playback Volume" 1370989b0138SMark Hills }, 1371989b0138SMark Hills { 1372989b0138SMark Hills .unitid = 7, 1373989b0138SMark Hills .control = 2, 1374989b0138SMark Hills .cmask = 0x2, 1375989b0138SMark Hills .val_type = USB_MIXER_S16, 1376989b0138SMark Hills .name = "Output B Playback Volume" 1377989b0138SMark Hills }, 1378b71dad18SMark Hills 1379989b0138SMark Hills { 1380989b0138SMark Hills .unitid = 10, 1381989b0138SMark Hills .control = 1, 1382989b0138SMark Hills .cmask = 0x0, 1383989b0138SMark Hills .val_type = USB_MIXER_INV_BOOLEAN, 1384989b0138SMark Hills .name = "Input Capture Switch" 1385989b0138SMark Hills }, 1386989b0138SMark Hills { 1387989b0138SMark Hills .unitid = 10, 1388989b0138SMark Hills .control = 2, 1389989b0138SMark Hills .cmask = 0x1, 1390989b0138SMark Hills .val_type = USB_MIXER_S16, 1391989b0138SMark Hills .name = "Input A Capture Volume" 1392989b0138SMark Hills }, 1393989b0138SMark Hills { 1394989b0138SMark Hills .unitid = 10, 1395989b0138SMark Hills .control = 2, 1396989b0138SMark Hills .cmask = 0x2, 1397989b0138SMark Hills .val_type = USB_MIXER_S16, 1398989b0138SMark Hills .name = "Input B Capture Volume" 1399989b0138SMark Hills }, 1400b71dad18SMark Hills 1401b71dad18SMark Hills {} 1402b71dad18SMark Hills }; 1403b71dad18SMark Hills 1404066624c6SPrzemek Rudy /* Audio Advantage Micro II findings: 1405066624c6SPrzemek Rudy * 1406066624c6SPrzemek Rudy * Mapping spdif AES bits to vendor register.bit: 1407066624c6SPrzemek Rudy * AES0: [0 0 0 0 2.3 2.2 2.1 2.0] - default 0x00 1408066624c6SPrzemek Rudy * AES1: [3.3 3.2.3.1.3.0 2.7 2.6 2.5 2.4] - default: 0x01 1409066624c6SPrzemek Rudy * AES2: [0 0 0 0 0 0 0 0] 1410066624c6SPrzemek Rudy * AES3: [0 0 0 0 0 0 x 0] - 'x' bit is set basing on standard usb request 1411066624c6SPrzemek Rudy * (UAC_EP_CS_ATTR_SAMPLE_RATE) for Audio Devices 1412066624c6SPrzemek Rudy * 1413066624c6SPrzemek Rudy * power on values: 1414066624c6SPrzemek Rudy * r2: 0x10 1415066624c6SPrzemek Rudy * r3: 0x20 (b7 is zeroed just before playback (except IEC61937) and set 1416066624c6SPrzemek Rudy * just after it to 0xa0, presumably it disables/mutes some analog 1417066624c6SPrzemek Rudy * parts when there is no audio.) 1418066624c6SPrzemek Rudy * r9: 0x28 1419066624c6SPrzemek Rudy * 1420066624c6SPrzemek Rudy * Optical transmitter on/off: 1421066624c6SPrzemek Rudy * vendor register.bit: 9.1 1422066624c6SPrzemek Rudy * 0 - on (0x28 register value) 1423066624c6SPrzemek Rudy * 1 - off (0x2a register value) 1424066624c6SPrzemek Rudy * 1425066624c6SPrzemek Rudy */ 1426066624c6SPrzemek Rudy static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol, 1427066624c6SPrzemek Rudy struct snd_ctl_elem_info *uinfo) 1428066624c6SPrzemek Rudy { 1429066624c6SPrzemek Rudy uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 1430066624c6SPrzemek Rudy uinfo->count = 1; 1431066624c6SPrzemek Rudy return 0; 1432066624c6SPrzemek Rudy } 1433066624c6SPrzemek Rudy 1434066624c6SPrzemek Rudy static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, 1435066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1436066624c6SPrzemek Rudy { 1437066624c6SPrzemek Rudy struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 1438066624c6SPrzemek Rudy int err; 1439066624c6SPrzemek Rudy struct usb_interface *iface; 1440066624c6SPrzemek Rudy struct usb_host_interface *alts; 1441066624c6SPrzemek Rudy unsigned int ep; 1442066624c6SPrzemek Rudy unsigned char data[3]; 1443066624c6SPrzemek Rudy int rate; 1444066624c6SPrzemek Rudy 1445066624c6SPrzemek Rudy ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff; 1446066624c6SPrzemek Rudy ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff; 1447066624c6SPrzemek Rudy ucontrol->value.iec958.status[2] = 0x00; 1448066624c6SPrzemek Rudy 1449066624c6SPrzemek Rudy /* use known values for that card: interface#1 altsetting#1 */ 1450066624c6SPrzemek Rudy iface = usb_ifnum_to_if(mixer->chip->dev, 1); 1451066624c6SPrzemek Rudy alts = &iface->altsetting[1]; 1452066624c6SPrzemek Rudy ep = get_endpoint(alts, 0)->bEndpointAddress; 1453066624c6SPrzemek Rudy 1454066624c6SPrzemek Rudy err = snd_usb_ctl_msg(mixer->chip->dev, 1455066624c6SPrzemek Rudy usb_rcvctrlpipe(mixer->chip->dev, 0), 1456066624c6SPrzemek Rudy UAC_GET_CUR, 1457066624c6SPrzemek Rudy USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, 1458066624c6SPrzemek Rudy UAC_EP_CS_ATTR_SAMPLE_RATE << 8, 1459066624c6SPrzemek Rudy ep, 1460066624c6SPrzemek Rudy data, 1461066624c6SPrzemek Rudy sizeof(data)); 1462066624c6SPrzemek Rudy if (err < 0) 1463066624c6SPrzemek Rudy goto end; 1464066624c6SPrzemek Rudy 1465066624c6SPrzemek Rudy rate = data[0] | (data[1] << 8) | (data[2] << 16); 1466066624c6SPrzemek Rudy ucontrol->value.iec958.status[3] = (rate == 48000) ? 1467066624c6SPrzemek Rudy IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100; 1468066624c6SPrzemek Rudy 1469066624c6SPrzemek Rudy err = 0; 1470066624c6SPrzemek Rudy end: 1471066624c6SPrzemek Rudy return err; 1472066624c6SPrzemek Rudy } 1473066624c6SPrzemek Rudy 1474066624c6SPrzemek Rudy static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, 1475066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1476066624c6SPrzemek Rudy { 1477066624c6SPrzemek Rudy struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 1478066624c6SPrzemek Rudy int err; 1479066624c6SPrzemek Rudy u8 reg; 1480066624c6SPrzemek Rudy unsigned long priv_backup = kcontrol->private_value; 1481066624c6SPrzemek Rudy 1482066624c6SPrzemek Rudy reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) | 1483066624c6SPrzemek Rudy (ucontrol->value.iec958.status[0] & 0x0f); 1484066624c6SPrzemek Rudy err = snd_usb_ctl_msg(mixer->chip->dev, 1485066624c6SPrzemek Rudy usb_sndctrlpipe(mixer->chip->dev, 0), 1486066624c6SPrzemek Rudy UAC_SET_CUR, 1487066624c6SPrzemek Rudy USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 1488066624c6SPrzemek Rudy reg, 1489066624c6SPrzemek Rudy 2, 1490066624c6SPrzemek Rudy NULL, 1491066624c6SPrzemek Rudy 0); 1492066624c6SPrzemek Rudy if (err < 0) 1493066624c6SPrzemek Rudy goto end; 1494066624c6SPrzemek Rudy 1495066624c6SPrzemek Rudy kcontrol->private_value &= 0xfffff0f0; 1496066624c6SPrzemek Rudy kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8; 1497066624c6SPrzemek Rudy kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f); 1498066624c6SPrzemek Rudy 1499066624c6SPrzemek Rudy reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ? 1500066624c6SPrzemek Rudy 0xa0 : 0x20; 1501066624c6SPrzemek Rudy reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f; 1502066624c6SPrzemek Rudy err = snd_usb_ctl_msg(mixer->chip->dev, 1503066624c6SPrzemek Rudy usb_sndctrlpipe(mixer->chip->dev, 0), 1504066624c6SPrzemek Rudy UAC_SET_CUR, 1505066624c6SPrzemek Rudy USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 1506066624c6SPrzemek Rudy reg, 1507066624c6SPrzemek Rudy 3, 1508066624c6SPrzemek Rudy NULL, 1509066624c6SPrzemek Rudy 0); 1510066624c6SPrzemek Rudy if (err < 0) 1511066624c6SPrzemek Rudy goto end; 1512066624c6SPrzemek Rudy 1513066624c6SPrzemek Rudy kcontrol->private_value &= 0xffff0fff; 1514066624c6SPrzemek Rudy kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8; 1515066624c6SPrzemek Rudy 1516066624c6SPrzemek Rudy /* The frequency bits in AES3 cannot be set via register access. */ 1517066624c6SPrzemek Rudy 1518066624c6SPrzemek Rudy /* Silently ignore any bits from the request that cannot be set. */ 1519066624c6SPrzemek Rudy 1520066624c6SPrzemek Rudy err = (priv_backup != kcontrol->private_value); 1521066624c6SPrzemek Rudy end: 1522066624c6SPrzemek Rudy return err; 1523066624c6SPrzemek Rudy } 1524066624c6SPrzemek Rudy 1525066624c6SPrzemek Rudy static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol, 1526066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1527066624c6SPrzemek Rudy { 1528066624c6SPrzemek Rudy ucontrol->value.iec958.status[0] = 0x0f; 1529066624c6SPrzemek Rudy ucontrol->value.iec958.status[1] = 0xff; 1530066624c6SPrzemek Rudy ucontrol->value.iec958.status[2] = 0x00; 1531066624c6SPrzemek Rudy ucontrol->value.iec958.status[3] = 0x00; 1532066624c6SPrzemek Rudy 1533066624c6SPrzemek Rudy return 0; 1534066624c6SPrzemek Rudy } 1535066624c6SPrzemek Rudy 1536066624c6SPrzemek Rudy static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol, 1537066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1538066624c6SPrzemek Rudy { 1539066624c6SPrzemek Rudy ucontrol->value.integer.value[0] = !(kcontrol->private_value & 0x02); 1540066624c6SPrzemek Rudy 1541066624c6SPrzemek Rudy return 0; 1542066624c6SPrzemek Rudy } 1543066624c6SPrzemek Rudy 1544066624c6SPrzemek Rudy static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol, 1545066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1546066624c6SPrzemek Rudy { 1547066624c6SPrzemek Rudy struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 1548066624c6SPrzemek Rudy int err; 1549066624c6SPrzemek Rudy u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a; 1550066624c6SPrzemek Rudy 1551066624c6SPrzemek Rudy err = snd_usb_ctl_msg(mixer->chip->dev, 1552066624c6SPrzemek Rudy usb_sndctrlpipe(mixer->chip->dev, 0), 1553066624c6SPrzemek Rudy UAC_SET_CUR, 1554066624c6SPrzemek Rudy USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 1555066624c6SPrzemek Rudy reg, 1556066624c6SPrzemek Rudy 9, 1557066624c6SPrzemek Rudy NULL, 1558066624c6SPrzemek Rudy 0); 1559066624c6SPrzemek Rudy 1560066624c6SPrzemek Rudy if (!err) { 1561066624c6SPrzemek Rudy err = (reg != (kcontrol->private_value & 0x0ff)); 1562066624c6SPrzemek Rudy if (err) 1563066624c6SPrzemek Rudy kcontrol->private_value = reg; 1564066624c6SPrzemek Rudy } 1565066624c6SPrzemek Rudy 1566066624c6SPrzemek Rudy return err; 1567066624c6SPrzemek Rudy } 1568066624c6SPrzemek Rudy 1569066624c6SPrzemek Rudy static struct snd_kcontrol_new snd_microii_mixer_spdif[] = { 1570066624c6SPrzemek Rudy { 1571066624c6SPrzemek Rudy .iface = SNDRV_CTL_ELEM_IFACE_PCM, 1572066624c6SPrzemek Rudy .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), 1573066624c6SPrzemek Rudy .info = snd_microii_spdif_info, 1574066624c6SPrzemek Rudy .get = snd_microii_spdif_default_get, 1575066624c6SPrzemek Rudy .put = snd_microii_spdif_default_put, 1576066624c6SPrzemek Rudy .private_value = 0x00000100UL,/* reset value */ 1577066624c6SPrzemek Rudy }, 1578066624c6SPrzemek Rudy { 1579066624c6SPrzemek Rudy .access = SNDRV_CTL_ELEM_ACCESS_READ, 1580066624c6SPrzemek Rudy .iface = SNDRV_CTL_ELEM_IFACE_PCM, 1581066624c6SPrzemek Rudy .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), 1582066624c6SPrzemek Rudy .info = snd_microii_spdif_info, 1583066624c6SPrzemek Rudy .get = snd_microii_spdif_mask_get, 1584066624c6SPrzemek Rudy }, 1585066624c6SPrzemek Rudy { 1586066624c6SPrzemek Rudy .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1587066624c6SPrzemek Rudy .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), 1588066624c6SPrzemek Rudy .info = snd_ctl_boolean_mono_info, 1589066624c6SPrzemek Rudy .get = snd_microii_spdif_switch_get, 1590066624c6SPrzemek Rudy .put = snd_microii_spdif_switch_put, 1591066624c6SPrzemek Rudy .private_value = 0x00000028UL,/* reset value */ 1592066624c6SPrzemek Rudy } 1593066624c6SPrzemek Rudy }; 1594066624c6SPrzemek Rudy 1595066624c6SPrzemek Rudy static int snd_microii_controls_create(struct usb_mixer_interface *mixer) 1596066624c6SPrzemek Rudy { 1597066624c6SPrzemek Rudy int err, i; 1598066624c6SPrzemek Rudy 1599066624c6SPrzemek Rudy for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) { 1600066624c6SPrzemek Rudy err = snd_ctl_add(mixer->chip->card, 1601066624c6SPrzemek Rudy snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer)); 1602066624c6SPrzemek Rudy if (err < 0) 1603066624c6SPrzemek Rudy return err; 1604066624c6SPrzemek Rudy } 1605066624c6SPrzemek Rudy 1606066624c6SPrzemek Rudy return err; 1607066624c6SPrzemek Rudy } 1608066624c6SPrzemek Rudy 16097b1eda22SDaniel Mack int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) 16107b1eda22SDaniel Mack { 16113347b26cSDaniel Mack int err = 0; 16127b1eda22SDaniel Mack struct snd_info_entry *entry; 16137b1eda22SDaniel Mack 16147b1eda22SDaniel Mack if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) 16157b1eda22SDaniel Mack return err; 16167b1eda22SDaniel Mack 16173347b26cSDaniel Mack switch (mixer->chip->usb_id) { 16183347b26cSDaniel Mack case USB_ID(0x041e, 0x3020): 16193347b26cSDaniel Mack case USB_ID(0x041e, 0x3040): 16203347b26cSDaniel Mack case USB_ID(0x041e, 0x3042): 16217cdd8d73SMathieu Bouffard case USB_ID(0x041e, 0x30df): 16223347b26cSDaniel Mack case USB_ID(0x041e, 0x3048): 16233347b26cSDaniel Mack err = snd_audigy2nx_controls_create(mixer); 16243347b26cSDaniel Mack if (err < 0) 16253347b26cSDaniel Mack break; 16267b1eda22SDaniel Mack if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry)) 16277b1eda22SDaniel Mack snd_info_set_text_ops(entry, mixer, 16287b1eda22SDaniel Mack snd_audigy2nx_proc_read); 16293347b26cSDaniel Mack break; 16307b1eda22SDaniel Mack 163144832a71SVasily Khoruzhick /* EMU0204 */ 163244832a71SVasily Khoruzhick case USB_ID(0x041e, 0x3f19): 163344832a71SVasily Khoruzhick err = snd_emu0204_controls_create(mixer); 163444832a71SVasily Khoruzhick if (err < 0) 163544832a71SVasily Khoruzhick break; 163644832a71SVasily Khoruzhick break; 163744832a71SVasily Khoruzhick 163809d8e3a7SEldad Zack case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ 1639e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C400 */ 164009d8e3a7SEldad Zack err = snd_c400_create_mixer(mixer); 164109d8e3a7SEldad Zack break; 164209d8e3a7SEldad Zack 1643d5a0bf6cSDaniel Mack case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ 1644d5a0bf6cSDaniel Mack case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ 1645cfe8f97cSFelix Homann err = snd_ftu_create_mixer(mixer); 1646d5a0bf6cSDaniel Mack break; 1647d5a0bf6cSDaniel Mack 16481d31affbSDenis Washington case USB_ID(0x0b05, 0x1739): /* ASUS Xonar U1 */ 16491d31affbSDenis Washington case USB_ID(0x0b05, 0x1743): /* ASUS Xonar U1 (2) */ 16501d31affbSDenis Washington case USB_ID(0x0b05, 0x17a0): /* ASUS Xonar U3 */ 16517b1eda22SDaniel Mack err = snd_xonar_u1_controls_create(mixer); 16523347b26cSDaniel Mack break; 16537b1eda22SDaniel Mack 1654066624c6SPrzemek Rudy case USB_ID(0x0d8c, 0x0103): /* Audio Advantage Micro II */ 1655066624c6SPrzemek Rudy err = snd_microii_controls_create(mixer); 1656066624c6SPrzemek Rudy break; 1657066624c6SPrzemek Rudy 16583347b26cSDaniel Mack case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */ 165954a8c500SDaniel Mack err = snd_nativeinstruments_create_mixer(mixer, 166054a8c500SDaniel Mack snd_nativeinstruments_ta6_mixers, 166154a8c500SDaniel Mack ARRAY_SIZE(snd_nativeinstruments_ta6_mixers)); 16623347b26cSDaniel Mack break; 166354a8c500SDaniel Mack 16643347b26cSDaniel Mack case USB_ID(0x17cc, 0x1021): /* Traktor Audio 10 */ 166554a8c500SDaniel Mack err = snd_nativeinstruments_create_mixer(mixer, 166654a8c500SDaniel Mack snd_nativeinstruments_ta10_mixers, 166754a8c500SDaniel Mack ARRAY_SIZE(snd_nativeinstruments_ta10_mixers)); 16683347b26cSDaniel Mack break; 16697536c301SMark Hills 16707536c301SMark Hills case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */ 1671b71dad18SMark Hills /* detection is disabled in mixer_maps.c */ 1672b71dad18SMark Hills err = snd_create_std_mono_table(mixer, ebox44_table); 16737536c301SMark Hills break; 167454a8c500SDaniel Mack } 167554a8c500SDaniel Mack 16763347b26cSDaniel Mack return err; 16777b1eda22SDaniel Mack } 16787b1eda22SDaniel Mack 16797b1eda22SDaniel Mack void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, 16807b1eda22SDaniel Mack int unitid) 16817b1eda22SDaniel Mack { 16827b1eda22SDaniel Mack if (!mixer->rc_cfg) 16837b1eda22SDaniel Mack return; 16847b1eda22SDaniel Mack /* unit ids specific to Extigy/Audigy 2 NX: */ 16857b1eda22SDaniel Mack switch (unitid) { 16867b1eda22SDaniel Mack case 0: /* remote control */ 16877b1eda22SDaniel Mack mixer->rc_urb->dev = mixer->chip->dev; 16887b1eda22SDaniel Mack usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); 16897b1eda22SDaniel Mack break; 16907b1eda22SDaniel Mack case 4: /* digital in jack */ 16917b1eda22SDaniel Mack case 7: /* line in jacks */ 16927b1eda22SDaniel Mack case 19: /* speaker out jacks */ 16937b1eda22SDaniel Mack case 20: /* headphones out jack */ 16947b1eda22SDaniel Mack break; 16957b1eda22SDaniel Mack /* live24ext: 4 = line-in jack */ 16967b1eda22SDaniel Mack case 3: /* hp-out jack (may actuate Mute) */ 16977b1eda22SDaniel Mack if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 16987b1eda22SDaniel Mack mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) 16997b1eda22SDaniel Mack snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id); 17007b1eda22SDaniel Mack break; 17017b1eda22SDaniel Mack default: 17027b1eda22SDaniel Mack snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); 17037b1eda22SDaniel Mack break; 17047b1eda22SDaniel Mack } 17057b1eda22SDaniel Mack } 17067b1eda22SDaniel Mack 1707