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 4361d31affbSDenis Washington /* ASUS Xonar U1 / U3 controls */ 4371d31affbSDenis Washington 4387b1eda22SDaniel Mack static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, 4397b1eda22SDaniel Mack struct snd_ctl_elem_value *ucontrol) 4407b1eda22SDaniel Mack { 4417b1eda22SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 4427b1eda22SDaniel Mack 4437b1eda22SDaniel Mack ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02); 4447b1eda22SDaniel Mack return 0; 4457b1eda22SDaniel Mack } 4467b1eda22SDaniel Mack 4477b1eda22SDaniel Mack static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, 4487b1eda22SDaniel Mack struct snd_ctl_elem_value *ucontrol) 4497b1eda22SDaniel Mack { 4507b1eda22SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 4517b1eda22SDaniel Mack u8 old_status, new_status; 4527b1eda22SDaniel Mack int err, changed; 4537b1eda22SDaniel Mack 4547b1eda22SDaniel Mack old_status = mixer->xonar_u1_status; 4557b1eda22SDaniel Mack if (ucontrol->value.integer.value[0]) 4567b1eda22SDaniel Mack new_status = old_status | 0x02; 4577b1eda22SDaniel Mack else 4587b1eda22SDaniel Mack new_status = old_status & ~0x02; 4597b1eda22SDaniel Mack changed = new_status != old_status; 460888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 461888ea7d5STakashi Iwai if (mixer->chip->shutdown) 462888ea7d5STakashi Iwai err = -ENODEV; 463888ea7d5STakashi Iwai else 4647b1eda22SDaniel Mack err = snd_usb_ctl_msg(mixer->chip->dev, 4657b1eda22SDaniel Mack usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, 4667b1eda22SDaniel Mack USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 46717d900c4SClemens Ladisch 50, 0, &new_status, 1); 468888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 4697b1eda22SDaniel Mack if (err < 0) 4707b1eda22SDaniel Mack return err; 4717b1eda22SDaniel Mack mixer->xonar_u1_status = new_status; 4727b1eda22SDaniel Mack return changed; 4737b1eda22SDaniel Mack } 4747b1eda22SDaniel Mack 4757b1eda22SDaniel Mack static struct snd_kcontrol_new snd_xonar_u1_output_switch = { 4767b1eda22SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4777b1eda22SDaniel Mack .name = "Digital Playback Switch", 4787b1eda22SDaniel Mack .info = snd_ctl_boolean_mono_info, 4797b1eda22SDaniel Mack .get = snd_xonar_u1_switch_get, 4807b1eda22SDaniel Mack .put = snd_xonar_u1_switch_put, 4817b1eda22SDaniel Mack }; 4827b1eda22SDaniel Mack 4837b1eda22SDaniel Mack static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) 4847b1eda22SDaniel Mack { 4857b1eda22SDaniel Mack int err; 4867b1eda22SDaniel Mack 4877b1eda22SDaniel Mack err = snd_ctl_add(mixer->chip->card, 4887b1eda22SDaniel Mack snd_ctl_new1(&snd_xonar_u1_output_switch, mixer)); 4897b1eda22SDaniel Mack if (err < 0) 4907b1eda22SDaniel Mack return err; 4917b1eda22SDaniel Mack mixer->xonar_u1_status = 0x05; 4927b1eda22SDaniel Mack return 0; 4937b1eda22SDaniel Mack } 4947b1eda22SDaniel Mack 49554a8c500SDaniel Mack /* Native Instruments device quirks */ 49654a8c500SDaniel Mack 49754a8c500SDaniel Mack #define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex)) 49854a8c500SDaniel Mack 49954a8c500SDaniel Mack static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, 50054a8c500SDaniel Mack struct snd_ctl_elem_value *ucontrol) 50154a8c500SDaniel Mack { 50254a8c500SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 50354a8c500SDaniel Mack struct usb_device *dev = mixer->chip->dev; 50454a8c500SDaniel Mack u8 bRequest = (kcontrol->private_value >> 16) & 0xff; 50554a8c500SDaniel Mack u16 wIndex = kcontrol->private_value & 0xffff; 50654a8c500SDaniel Mack u8 tmp; 507888ea7d5STakashi Iwai int ret; 50854a8c500SDaniel Mack 509888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 510888ea7d5STakashi Iwai if (mixer->chip->shutdown) 511888ea7d5STakashi Iwai ret = -ENODEV; 512888ea7d5STakashi Iwai else 513888ea7d5STakashi Iwai ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, 51454a8c500SDaniel Mack USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 515889d6684SEldad Zack 0, wIndex, 51654a8c500SDaniel Mack &tmp, sizeof(tmp), 1000); 517888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 51854a8c500SDaniel Mack 51954a8c500SDaniel Mack if (ret < 0) { 52054a8c500SDaniel Mack snd_printk(KERN_ERR 52154a8c500SDaniel Mack "unable to issue vendor read request (ret = %d)", ret); 52254a8c500SDaniel Mack return ret; 52354a8c500SDaniel Mack } 52454a8c500SDaniel Mack 52554a8c500SDaniel Mack ucontrol->value.integer.value[0] = tmp; 52654a8c500SDaniel Mack 52754a8c500SDaniel Mack return 0; 52854a8c500SDaniel Mack } 52954a8c500SDaniel Mack 53054a8c500SDaniel Mack static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, 53154a8c500SDaniel Mack struct snd_ctl_elem_value *ucontrol) 53254a8c500SDaniel Mack { 53354a8c500SDaniel Mack struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 53454a8c500SDaniel Mack struct usb_device *dev = mixer->chip->dev; 53554a8c500SDaniel Mack u8 bRequest = (kcontrol->private_value >> 16) & 0xff; 53654a8c500SDaniel Mack u16 wIndex = kcontrol->private_value & 0xffff; 53754a8c500SDaniel Mack u16 wValue = ucontrol->value.integer.value[0]; 538888ea7d5STakashi Iwai int ret; 53954a8c500SDaniel Mack 540888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 541888ea7d5STakashi Iwai if (mixer->chip->shutdown) 542888ea7d5STakashi Iwai ret = -ENODEV; 543888ea7d5STakashi Iwai else 544888ea7d5STakashi Iwai ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, 54554a8c500SDaniel Mack USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 546889d6684SEldad Zack wValue, wIndex, 54754a8c500SDaniel Mack NULL, 0, 1000); 548888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 54954a8c500SDaniel Mack 55054a8c500SDaniel Mack if (ret < 0) { 55154a8c500SDaniel Mack snd_printk(KERN_ERR 55254a8c500SDaniel Mack "unable to issue vendor write request (ret = %d)", ret); 55354a8c500SDaniel Mack return ret; 55454a8c500SDaniel Mack } 55554a8c500SDaniel Mack 55654a8c500SDaniel Mack return 0; 55754a8c500SDaniel Mack } 55854a8c500SDaniel Mack 55954a8c500SDaniel Mack static struct snd_kcontrol_new snd_nativeinstruments_ta6_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 = "Phono Input Channel A", 57054a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x03), 57154a8c500SDaniel Mack }, 57254a8c500SDaniel Mack { 57354a8c500SDaniel Mack .name = "Phono Input Channel B", 57454a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x05), 57554a8c500SDaniel Mack }, 57654a8c500SDaniel Mack }; 57754a8c500SDaniel Mack 57854a8c500SDaniel Mack static struct snd_kcontrol_new snd_nativeinstruments_ta10_mixers[] = { 57954a8c500SDaniel Mack { 58054a8c500SDaniel Mack .name = "Direct Thru Channel A", 58154a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x03), 58254a8c500SDaniel Mack }, 58354a8c500SDaniel Mack { 58454a8c500SDaniel Mack .name = "Direct Thru Channel B", 58554a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x05), 58654a8c500SDaniel Mack }, 58754a8c500SDaniel Mack { 58854a8c500SDaniel Mack .name = "Direct Thru Channel C", 58954a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x07), 59054a8c500SDaniel Mack }, 59154a8c500SDaniel Mack { 59254a8c500SDaniel Mack .name = "Direct Thru Channel D", 59354a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x09), 59454a8c500SDaniel Mack }, 59554a8c500SDaniel Mack { 59654a8c500SDaniel Mack .name = "Phono Input Channel A", 59754a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x03), 59854a8c500SDaniel Mack }, 59954a8c500SDaniel Mack { 60054a8c500SDaniel Mack .name = "Phono Input Channel B", 60154a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x05), 60254a8c500SDaniel Mack }, 60354a8c500SDaniel Mack { 60454a8c500SDaniel Mack .name = "Phono Input Channel C", 60554a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x07), 60654a8c500SDaniel Mack }, 60754a8c500SDaniel Mack { 60854a8c500SDaniel Mack .name = "Phono Input Channel D", 60954a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x09), 61054a8c500SDaniel Mack }, 61154a8c500SDaniel Mack }; 61254a8c500SDaniel Mack 61354a8c500SDaniel Mack static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, 61454a8c500SDaniel Mack const struct snd_kcontrol_new *kc, 61554a8c500SDaniel Mack unsigned int count) 61654a8c500SDaniel Mack { 61754a8c500SDaniel Mack int i, err = 0; 61854a8c500SDaniel Mack struct snd_kcontrol_new template = { 61954a8c500SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 62054a8c500SDaniel Mack .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 62154a8c500SDaniel Mack .get = snd_nativeinstruments_control_get, 62254a8c500SDaniel Mack .put = snd_nativeinstruments_control_put, 62354a8c500SDaniel Mack .info = snd_ctl_boolean_mono_info, 62454a8c500SDaniel Mack }; 62554a8c500SDaniel Mack 62654a8c500SDaniel Mack for (i = 0; i < count; i++) { 62754a8c500SDaniel Mack struct snd_kcontrol *c; 62854a8c500SDaniel Mack 62954a8c500SDaniel Mack template.name = kc[i].name; 63054a8c500SDaniel Mack template.private_value = kc[i].private_value; 63154a8c500SDaniel Mack 63254a8c500SDaniel Mack c = snd_ctl_new1(&template, mixer); 63354a8c500SDaniel Mack err = snd_ctl_add(mixer->chip->card, c); 63454a8c500SDaniel Mack 63554a8c500SDaniel Mack if (err < 0) 63654a8c500SDaniel Mack break; 63754a8c500SDaniel Mack } 63854a8c500SDaniel Mack 63954a8c500SDaniel Mack return err; 64054a8c500SDaniel Mack } 64154a8c500SDaniel Mack 642d5a0bf6cSDaniel Mack /* M-Audio FastTrack Ultra quirks */ 643e9a25e04SMatt Gruskin /* FTU Effect switch (also used by C400/C600) */ 644d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val { 645d34bf148SFelix Homann struct usb_mixer_interface *mixer; 646d34bf148SFelix Homann int cached_value; 647d34bf148SFelix Homann int is_cached; 648d847ce0eSEldad Zack int bUnitID; 649d847ce0eSEldad Zack int validx; 650d34bf148SFelix Homann }; 651d34bf148SFelix Homann 652d34bf148SFelix Homann static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, 653d34bf148SFelix Homann struct snd_ctl_elem_info *uinfo) 654d34bf148SFelix Homann { 655d34bf148SFelix Homann static const char *texts[8] = {"Room 1", 656d34bf148SFelix Homann "Room 2", 657d34bf148SFelix Homann "Room 3", 658d34bf148SFelix Homann "Hall 1", 659d34bf148SFelix Homann "Hall 2", 660d34bf148SFelix Homann "Plate", 661d34bf148SFelix Homann "Delay", 662d34bf148SFelix Homann "Echo" 663d34bf148SFelix Homann }; 664d34bf148SFelix Homann 665d34bf148SFelix Homann uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 666d34bf148SFelix Homann uinfo->count = 1; 667d34bf148SFelix Homann uinfo->value.enumerated.items = 8; 668d34bf148SFelix Homann if (uinfo->value.enumerated.item > 7) 669d34bf148SFelix Homann uinfo->value.enumerated.item = 7; 670d34bf148SFelix Homann strcpy(uinfo->value.enumerated.name, 671d34bf148SFelix Homann texts[uinfo->value.enumerated.item]); 672d34bf148SFelix Homann 673d34bf148SFelix Homann return 0; 674d34bf148SFelix Homann } 675d34bf148SFelix Homann 676d34bf148SFelix Homann static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, 677d34bf148SFelix Homann struct snd_ctl_elem_value *ucontrol) 678d34bf148SFelix Homann { 679d34bf148SFelix Homann struct snd_usb_audio *chip; 680d34bf148SFelix Homann struct usb_mixer_interface *mixer; 681d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val *pval; 682d34bf148SFelix Homann int err; 683d34bf148SFelix Homann unsigned char value[2]; 684d847ce0eSEldad Zack int id, validx; 685d34bf148SFelix Homann 686d34bf148SFelix Homann const int val_len = 2; 687d34bf148SFelix Homann 688d34bf148SFelix Homann value[0] = 0x00; 689d34bf148SFelix Homann value[1] = 0x00; 690d34bf148SFelix Homann 691d34bf148SFelix Homann pval = (struct snd_ftu_eff_switch_priv_val *) 692d34bf148SFelix Homann kctl->private_value; 693d34bf148SFelix Homann 694d34bf148SFelix Homann if (pval->is_cached) { 695d34bf148SFelix Homann ucontrol->value.enumerated.item[0] = pval->cached_value; 696d34bf148SFelix Homann return 0; 697d34bf148SFelix Homann } 698d34bf148SFelix Homann 699d34bf148SFelix Homann mixer = (struct usb_mixer_interface *) pval->mixer; 700d34bf148SFelix Homann if (snd_BUG_ON(!mixer)) 701d34bf148SFelix Homann return -EINVAL; 702d34bf148SFelix Homann 703d34bf148SFelix Homann chip = (struct snd_usb_audio *) mixer->chip; 704d34bf148SFelix Homann if (snd_BUG_ON(!chip)) 705d34bf148SFelix Homann return -EINVAL; 706d34bf148SFelix Homann 707d847ce0eSEldad Zack id = pval->bUnitID; 708d847ce0eSEldad Zack validx = pval->validx; 709d34bf148SFelix Homann 710888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 711888ea7d5STakashi Iwai if (mixer->chip->shutdown) 712888ea7d5STakashi Iwai err = -ENODEV; 713888ea7d5STakashi Iwai else 714d34bf148SFelix Homann err = snd_usb_ctl_msg(chip->dev, 715d34bf148SFelix Homann usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, 716d34bf148SFelix Homann USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 717d34bf148SFelix Homann validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), 718d34bf148SFelix Homann value, val_len); 719888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 720d34bf148SFelix Homann if (err < 0) 721d34bf148SFelix Homann return err; 722d34bf148SFelix Homann 723d34bf148SFelix Homann ucontrol->value.enumerated.item[0] = value[0]; 724d34bf148SFelix Homann pval->cached_value = value[0]; 725d34bf148SFelix Homann pval->is_cached = 1; 726d34bf148SFelix Homann 727d34bf148SFelix Homann return 0; 728d34bf148SFelix Homann } 729d34bf148SFelix Homann 730d34bf148SFelix Homann static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, 731d34bf148SFelix Homann struct snd_ctl_elem_value *ucontrol) 732d34bf148SFelix Homann { 733d34bf148SFelix Homann struct snd_usb_audio *chip; 734d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val *pval; 735d34bf148SFelix Homann 736d34bf148SFelix Homann struct usb_mixer_interface *mixer; 737d34bf148SFelix Homann int changed, cur_val, err, new_val; 738d34bf148SFelix Homann unsigned char value[2]; 739d847ce0eSEldad Zack int id, validx; 740d34bf148SFelix Homann 741d34bf148SFelix Homann const int val_len = 2; 742d34bf148SFelix Homann 743d34bf148SFelix Homann changed = 0; 744d34bf148SFelix Homann 745d34bf148SFelix Homann pval = (struct snd_ftu_eff_switch_priv_val *) 746d34bf148SFelix Homann kctl->private_value; 747d34bf148SFelix Homann cur_val = pval->cached_value; 748d34bf148SFelix Homann new_val = ucontrol->value.enumerated.item[0]; 749d34bf148SFelix Homann 750d34bf148SFelix Homann mixer = (struct usb_mixer_interface *) pval->mixer; 751d34bf148SFelix Homann if (snd_BUG_ON(!mixer)) 752d34bf148SFelix Homann return -EINVAL; 753d34bf148SFelix Homann 754d34bf148SFelix Homann chip = (struct snd_usb_audio *) mixer->chip; 755d34bf148SFelix Homann if (snd_BUG_ON(!chip)) 756d34bf148SFelix Homann return -EINVAL; 757d34bf148SFelix Homann 758d847ce0eSEldad Zack id = pval->bUnitID; 759d847ce0eSEldad Zack validx = pval->validx; 760d847ce0eSEldad Zack 761d34bf148SFelix Homann if (!pval->is_cached) { 762d34bf148SFelix Homann /* Read current value */ 763888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 764888ea7d5STakashi Iwai if (mixer->chip->shutdown) 765888ea7d5STakashi Iwai err = -ENODEV; 766888ea7d5STakashi Iwai else 767d34bf148SFelix Homann err = snd_usb_ctl_msg(chip->dev, 768d34bf148SFelix Homann usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, 769d34bf148SFelix Homann USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 770d34bf148SFelix Homann validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), 771d34bf148SFelix Homann value, val_len); 772888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 773d34bf148SFelix Homann if (err < 0) 774d34bf148SFelix Homann return err; 775d34bf148SFelix Homann 776d34bf148SFelix Homann cur_val = value[0]; 777d34bf148SFelix Homann pval->cached_value = cur_val; 778d34bf148SFelix Homann pval->is_cached = 1; 779d34bf148SFelix Homann } 780d34bf148SFelix Homann /* update value if needed */ 781d34bf148SFelix Homann if (cur_val != new_val) { 782d34bf148SFelix Homann value[0] = new_val; 783d34bf148SFelix Homann value[1] = 0; 784888ea7d5STakashi Iwai down_read(&mixer->chip->shutdown_rwsem); 785888ea7d5STakashi Iwai if (mixer->chip->shutdown) 786888ea7d5STakashi Iwai err = -ENODEV; 787888ea7d5STakashi Iwai else 788d34bf148SFelix Homann err = snd_usb_ctl_msg(chip->dev, 789d34bf148SFelix Homann usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, 790d34bf148SFelix Homann USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 791d34bf148SFelix Homann validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), 792d34bf148SFelix Homann value, val_len); 793888ea7d5STakashi Iwai up_read(&mixer->chip->shutdown_rwsem); 794d34bf148SFelix Homann if (err < 0) 795d34bf148SFelix Homann return err; 796d34bf148SFelix Homann 797d34bf148SFelix Homann pval->cached_value = new_val; 798d34bf148SFelix Homann pval->is_cached = 1; 799d34bf148SFelix Homann changed = 1; 800d34bf148SFelix Homann } 801d34bf148SFelix Homann 802d34bf148SFelix Homann return changed; 803d34bf148SFelix Homann } 804d34bf148SFelix Homann 805d847ce0eSEldad Zack static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, 806d847ce0eSEldad Zack int validx, int bUnitID) 807d34bf148SFelix Homann { 808d34bf148SFelix Homann static struct snd_kcontrol_new template = { 809d34bf148SFelix Homann .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 810d34bf148SFelix Homann .name = "Effect Program Switch", 811d34bf148SFelix Homann .index = 0, 812d34bf148SFelix Homann .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 813d34bf148SFelix Homann .info = snd_ftu_eff_switch_info, 814d34bf148SFelix Homann .get = snd_ftu_eff_switch_get, 815d34bf148SFelix Homann .put = snd_ftu_eff_switch_put 816d34bf148SFelix Homann }; 817d34bf148SFelix Homann 818d34bf148SFelix Homann int err; 819d34bf148SFelix Homann struct snd_kcontrol *kctl; 820d34bf148SFelix Homann struct snd_ftu_eff_switch_priv_val *pval; 821d34bf148SFelix Homann 822d34bf148SFelix Homann pval = kzalloc(sizeof(*pval), GFP_KERNEL); 823d34bf148SFelix Homann if (!pval) 824d34bf148SFelix Homann return -ENOMEM; 825d34bf148SFelix Homann 826d34bf148SFelix Homann pval->cached_value = 0; 827d34bf148SFelix Homann pval->is_cached = 0; 828d34bf148SFelix Homann pval->mixer = mixer; 829d847ce0eSEldad Zack pval->bUnitID = bUnitID; 830d847ce0eSEldad Zack pval->validx = validx; 831d34bf148SFelix Homann 832d34bf148SFelix Homann template.private_value = (unsigned long) pval; 833d34bf148SFelix Homann kctl = snd_ctl_new1(&template, mixer->chip); 834d34bf148SFelix Homann if (!kctl) { 835d34bf148SFelix Homann kfree(pval); 836d34bf148SFelix Homann return -ENOMEM; 837d34bf148SFelix Homann } 838d34bf148SFelix Homann 839d34bf148SFelix Homann err = snd_ctl_add(mixer->chip->card, kctl); 840d34bf148SFelix Homann if (err < 0) 841d34bf148SFelix Homann return err; 842d34bf148SFelix Homann 843d34bf148SFelix Homann return 0; 844d34bf148SFelix Homann } 845d5a0bf6cSDaniel Mack 846cfe8f97cSFelix Homann /* Create volume controls for FTU devices*/ 847cfe8f97cSFelix Homann static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) 848d5a0bf6cSDaniel Mack { 849d5a0bf6cSDaniel Mack char name[64]; 8508a4d1d39SFelix Homann unsigned int control, cmask; 851d5a0bf6cSDaniel Mack int in, out, err; 852d5a0bf6cSDaniel Mack 8538a4d1d39SFelix Homann const unsigned int id = 5; 8548a4d1d39SFelix Homann const int val_type = USB_MIXER_S16; 8558a4d1d39SFelix Homann 856d5a0bf6cSDaniel Mack for (out = 0; out < 8; out++) { 8578a4d1d39SFelix Homann control = out + 1; 858d5a0bf6cSDaniel Mack for (in = 0; in < 8; in++) { 8598a4d1d39SFelix Homann cmask = 1 << in; 860d5a0bf6cSDaniel Mack snprintf(name, sizeof(name), 8618a4d1d39SFelix Homann "AIn%d - Out%d Capture Volume", 8628a4d1d39SFelix Homann in + 1, out + 1); 8638a4d1d39SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, 8648a4d1d39SFelix Homann cmask, val_type, name, 86525ee7ef8SFelix Homann &snd_usb_mixer_vol_tlv); 866d5a0bf6cSDaniel Mack if (err < 0) 867d5a0bf6cSDaniel Mack return err; 868d5a0bf6cSDaniel Mack } 869d5a0bf6cSDaniel Mack for (in = 8; in < 16; in++) { 8708a4d1d39SFelix Homann cmask = 1 << in; 871d5a0bf6cSDaniel Mack snprintf(name, sizeof(name), 8728a4d1d39SFelix Homann "DIn%d - Out%d Playback Volume", 8738a4d1d39SFelix Homann in - 7, out + 1); 8748a4d1d39SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, 8758a4d1d39SFelix Homann cmask, val_type, name, 87625ee7ef8SFelix Homann &snd_usb_mixer_vol_tlv); 877d5a0bf6cSDaniel Mack if (err < 0) 878d5a0bf6cSDaniel Mack return err; 879d5a0bf6cSDaniel Mack } 880d5a0bf6cSDaniel Mack } 881d5a0bf6cSDaniel Mack 882d5a0bf6cSDaniel Mack return 0; 883d5a0bf6cSDaniel Mack } 884d5a0bf6cSDaniel Mack 885d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */ 886d34bf148SFelix Homann static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer) 887d34bf148SFelix Homann { 888d34bf148SFelix Homann static const char name[] = "Effect Volume"; 889d34bf148SFelix Homann const unsigned int id = 6; 890d34bf148SFelix Homann const int val_type = USB_MIXER_U8; 891d34bf148SFelix Homann const unsigned int control = 2; 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, snd_usb_mixer_vol_tlv); 896d34bf148SFelix Homann } 897d34bf148SFelix Homann 898d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */ 899d34bf148SFelix Homann static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer) 900d34bf148SFelix Homann { 901d34bf148SFelix Homann static const char name[] = "Effect Duration"; 902d34bf148SFelix Homann const unsigned int id = 6; 903d34bf148SFelix Homann const int val_type = USB_MIXER_S16; 904d34bf148SFelix Homann const unsigned int control = 3; 905d34bf148SFelix Homann const unsigned int cmask = 0; 906d34bf148SFelix Homann 907d34bf148SFelix Homann return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 908d34bf148SFelix Homann name, snd_usb_mixer_vol_tlv); 909d34bf148SFelix Homann } 910d34bf148SFelix Homann 911d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */ 912d34bf148SFelix Homann static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) 913d34bf148SFelix Homann { 914d34bf148SFelix Homann static const char name[] = "Effect Feedback Volume"; 915d34bf148SFelix Homann const unsigned int id = 6; 916d34bf148SFelix Homann const int val_type = USB_MIXER_U8; 917d34bf148SFelix Homann const unsigned int control = 4; 918d34bf148SFelix Homann const unsigned int cmask = 0; 919d34bf148SFelix Homann 920d34bf148SFelix Homann return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 921d34bf148SFelix Homann name, NULL); 922d34bf148SFelix Homann } 923d34bf148SFelix Homann 924d34bf148SFelix Homann static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer) 925d34bf148SFelix Homann { 926d34bf148SFelix Homann unsigned int cmask; 927d34bf148SFelix Homann int err, ch; 928d34bf148SFelix Homann char name[48]; 929d34bf148SFelix Homann 930d34bf148SFelix Homann const unsigned int id = 7; 931d34bf148SFelix Homann const int val_type = USB_MIXER_S16; 932d34bf148SFelix Homann const unsigned int control = 7; 933d34bf148SFelix Homann 934d34bf148SFelix Homann for (ch = 0; ch < 4; ++ch) { 935d34bf148SFelix Homann cmask = 1 << ch; 936d34bf148SFelix Homann snprintf(name, sizeof(name), 937d34bf148SFelix Homann "Effect Return %d Volume", ch + 1); 938d34bf148SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, 939d34bf148SFelix Homann cmask, val_type, name, 940d34bf148SFelix Homann snd_usb_mixer_vol_tlv); 941d34bf148SFelix Homann if (err < 0) 942d34bf148SFelix Homann return err; 943d34bf148SFelix Homann } 944d34bf148SFelix Homann 945d34bf148SFelix Homann return 0; 946d34bf148SFelix Homann } 947d34bf148SFelix Homann 948d34bf148SFelix Homann static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) 949d34bf148SFelix Homann { 950d34bf148SFelix Homann unsigned int cmask; 951d34bf148SFelix Homann int err, ch; 952d34bf148SFelix Homann char name[48]; 953d34bf148SFelix Homann 954d34bf148SFelix Homann const unsigned int id = 5; 955d34bf148SFelix Homann const int val_type = USB_MIXER_S16; 956d34bf148SFelix Homann const unsigned int control = 9; 957d34bf148SFelix Homann 958d34bf148SFelix Homann for (ch = 0; ch < 8; ++ch) { 959d34bf148SFelix Homann cmask = 1 << ch; 960d34bf148SFelix Homann snprintf(name, sizeof(name), 961d34bf148SFelix Homann "Effect Send AIn%d Volume", ch + 1); 962d34bf148SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, cmask, 963d34bf148SFelix Homann val_type, name, 964d34bf148SFelix Homann snd_usb_mixer_vol_tlv); 965d34bf148SFelix Homann if (err < 0) 966d34bf148SFelix Homann return err; 967d34bf148SFelix Homann } 968d34bf148SFelix Homann for (ch = 8; ch < 16; ++ch) { 969d34bf148SFelix Homann cmask = 1 << ch; 970d34bf148SFelix Homann snprintf(name, sizeof(name), 971d34bf148SFelix Homann "Effect Send DIn%d Volume", ch - 7); 972d34bf148SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, cmask, 973d34bf148SFelix Homann val_type, name, 974d34bf148SFelix Homann snd_usb_mixer_vol_tlv); 975d34bf148SFelix Homann if (err < 0) 976d34bf148SFelix Homann return err; 977d34bf148SFelix Homann } 978d34bf148SFelix Homann return 0; 979d34bf148SFelix Homann } 980d34bf148SFelix Homann 981cfe8f97cSFelix Homann static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) 9827536c301SMark Hills { 9838a4d1d39SFelix Homann int err; 9847536c301SMark Hills 985cfe8f97cSFelix Homann err = snd_ftu_create_volume_ctls(mixer); 9868a4d1d39SFelix Homann if (err < 0) 9878a4d1d39SFelix Homann return err; 9887536c301SMark Hills 989d847ce0eSEldad Zack err = snd_ftu_create_effect_switch(mixer, 1, 6); 990d34bf148SFelix Homann if (err < 0) 991d34bf148SFelix Homann return err; 992d847ce0eSEldad Zack 993d34bf148SFelix Homann err = snd_ftu_create_effect_volume_ctl(mixer); 994d34bf148SFelix Homann if (err < 0) 995d34bf148SFelix Homann return err; 996d34bf148SFelix Homann 997d34bf148SFelix Homann err = snd_ftu_create_effect_duration_ctl(mixer); 998d34bf148SFelix Homann if (err < 0) 999d34bf148SFelix Homann return err; 1000d34bf148SFelix Homann 1001d34bf148SFelix Homann err = snd_ftu_create_effect_feedback_ctl(mixer); 1002d34bf148SFelix Homann if (err < 0) 1003d34bf148SFelix Homann return err; 1004d34bf148SFelix Homann 1005d34bf148SFelix Homann err = snd_ftu_create_effect_return_ctls(mixer); 1006d34bf148SFelix Homann if (err < 0) 1007d34bf148SFelix Homann return err; 1008d34bf148SFelix Homann 1009d34bf148SFelix Homann err = snd_ftu_create_effect_send_ctls(mixer); 1010d34bf148SFelix Homann if (err < 0) 1011d34bf148SFelix Homann return err; 1012d34bf148SFelix Homann 10138a4d1d39SFelix Homann return 0; 10147536c301SMark Hills } 10157536c301SMark Hills 10167b1eda22SDaniel Mack void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, 10177b1eda22SDaniel Mack unsigned char samplerate_id) 10187b1eda22SDaniel Mack { 10197b1eda22SDaniel Mack struct usb_mixer_interface *mixer; 10207b1eda22SDaniel Mack struct usb_mixer_elem_info *cval; 10217b1eda22SDaniel Mack int unitid = 12; /* SamleRate ExtensionUnit ID */ 10227b1eda22SDaniel Mack 10237b1eda22SDaniel Mack list_for_each_entry(mixer, &chip->mixer_list, list) { 10247b1eda22SDaniel Mack cval = mixer->id_elems[unitid]; 10257b1eda22SDaniel Mack if (cval) { 10267b1eda22SDaniel Mack snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, 10277b1eda22SDaniel Mack cval->control << 8, 10287b1eda22SDaniel Mack samplerate_id); 10297b1eda22SDaniel Mack snd_usb_mixer_notify_id(mixer, unitid); 10307b1eda22SDaniel Mack } 10317b1eda22SDaniel Mack break; 10327b1eda22SDaniel Mack } 10337b1eda22SDaniel Mack } 10347b1eda22SDaniel Mack 1035e9a25e04SMatt Gruskin /* M-Audio Fast Track C400/C600 */ 1036e9a25e04SMatt Gruskin /* C400/C600 volume controls, this control needs a volume quirk, see mixer.c */ 103709d8e3a7SEldad Zack static int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer) 103809d8e3a7SEldad Zack { 103909d8e3a7SEldad Zack char name[64]; 104009d8e3a7SEldad Zack unsigned int cmask, offset; 104109d8e3a7SEldad Zack int out, chan, err; 1042e9a25e04SMatt Gruskin int num_outs = 0; 1043e9a25e04SMatt Gruskin int num_ins = 0; 104409d8e3a7SEldad Zack 104509d8e3a7SEldad Zack const unsigned int id = 0x40; 104609d8e3a7SEldad Zack const int val_type = USB_MIXER_S16; 104709d8e3a7SEldad Zack const int control = 1; 104809d8e3a7SEldad Zack 1049e9a25e04SMatt Gruskin switch (mixer->chip->usb_id) { 1050e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2030): 1051e9a25e04SMatt Gruskin num_outs = 6; 1052e9a25e04SMatt Gruskin num_ins = 4; 1053e9a25e04SMatt Gruskin break; 1054e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2031): 1055e9a25e04SMatt Gruskin num_outs = 8; 1056e9a25e04SMatt Gruskin num_ins = 6; 1057e9a25e04SMatt Gruskin break; 1058e9a25e04SMatt Gruskin } 1059e9a25e04SMatt Gruskin 1060e9a25e04SMatt Gruskin for (chan = 0; chan < num_outs + num_ins; chan++) { 1061e9a25e04SMatt Gruskin for (out = 0; out < num_outs; out++) { 1062e9a25e04SMatt Gruskin if (chan < num_outs) { 106309d8e3a7SEldad Zack snprintf(name, sizeof(name), 106409d8e3a7SEldad Zack "PCM%d-Out%d Playback Volume", 106509d8e3a7SEldad Zack chan + 1, out + 1); 106609d8e3a7SEldad Zack } else { 106709d8e3a7SEldad Zack snprintf(name, sizeof(name), 106809d8e3a7SEldad Zack "In%d-Out%d Playback Volume", 1069e9a25e04SMatt Gruskin chan - num_outs + 1, out + 1); 107009d8e3a7SEldad Zack } 107109d8e3a7SEldad Zack 107209d8e3a7SEldad Zack cmask = (out == 0) ? 0 : 1 << (out - 1); 1073e9a25e04SMatt Gruskin offset = chan * num_outs; 107409d8e3a7SEldad Zack err = snd_create_std_mono_ctl_offset(mixer, id, control, 107509d8e3a7SEldad Zack cmask, val_type, offset, name, 107609d8e3a7SEldad Zack &snd_usb_mixer_vol_tlv); 107709d8e3a7SEldad Zack if (err < 0) 107809d8e3a7SEldad Zack return err; 107909d8e3a7SEldad Zack } 108009d8e3a7SEldad Zack } 108109d8e3a7SEldad Zack 108209d8e3a7SEldad Zack return 0; 108309d8e3a7SEldad Zack } 108409d8e3a7SEldad Zack 108509d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */ 108609d8e3a7SEldad Zack static int snd_c400_create_effect_volume_ctl(struct usb_mixer_interface *mixer) 108709d8e3a7SEldad Zack { 108809d8e3a7SEldad Zack static const char name[] = "Effect Volume"; 108909d8e3a7SEldad Zack const unsigned int id = 0x43; 109009d8e3a7SEldad Zack const int val_type = USB_MIXER_U8; 109109d8e3a7SEldad Zack const unsigned int control = 3; 109209d8e3a7SEldad Zack const unsigned int cmask = 0; 109309d8e3a7SEldad Zack 109409d8e3a7SEldad Zack return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 109509d8e3a7SEldad Zack name, snd_usb_mixer_vol_tlv); 109609d8e3a7SEldad Zack } 109709d8e3a7SEldad Zack 109809d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */ 109909d8e3a7SEldad Zack static int snd_c400_create_effect_duration_ctl(struct usb_mixer_interface *mixer) 110009d8e3a7SEldad Zack { 110109d8e3a7SEldad Zack static const char name[] = "Effect Duration"; 110209d8e3a7SEldad Zack const unsigned int id = 0x43; 110309d8e3a7SEldad Zack const int val_type = USB_MIXER_S16; 110409d8e3a7SEldad Zack const unsigned int control = 4; 110509d8e3a7SEldad Zack const unsigned int cmask = 0; 110609d8e3a7SEldad Zack 110709d8e3a7SEldad Zack return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 110809d8e3a7SEldad Zack name, snd_usb_mixer_vol_tlv); 110909d8e3a7SEldad Zack } 111009d8e3a7SEldad Zack 111109d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */ 111209d8e3a7SEldad Zack static int snd_c400_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) 111309d8e3a7SEldad Zack { 111409d8e3a7SEldad Zack static const char name[] = "Effect Feedback Volume"; 111509d8e3a7SEldad Zack const unsigned int id = 0x43; 111609d8e3a7SEldad Zack const int val_type = USB_MIXER_U8; 111709d8e3a7SEldad Zack const unsigned int control = 5; 111809d8e3a7SEldad Zack const unsigned int cmask = 0; 111909d8e3a7SEldad Zack 112009d8e3a7SEldad Zack return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 112109d8e3a7SEldad Zack name, NULL); 112209d8e3a7SEldad Zack } 112309d8e3a7SEldad Zack 112409d8e3a7SEldad Zack static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer) 112509d8e3a7SEldad Zack { 112609d8e3a7SEldad Zack char name[64]; 112709d8e3a7SEldad Zack unsigned int cmask; 112809d8e3a7SEldad Zack int chan, err; 1129e9a25e04SMatt Gruskin int num_outs = 0; 1130e9a25e04SMatt Gruskin int num_ins = 0; 113109d8e3a7SEldad Zack 113209d8e3a7SEldad Zack const unsigned int id = 0x42; 113309d8e3a7SEldad Zack const int val_type = USB_MIXER_S16; 113409d8e3a7SEldad Zack const int control = 1; 113509d8e3a7SEldad Zack 1136e9a25e04SMatt Gruskin switch (mixer->chip->usb_id) { 1137e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2030): 1138e9a25e04SMatt Gruskin num_outs = 6; 1139e9a25e04SMatt Gruskin num_ins = 4; 1140e9a25e04SMatt Gruskin break; 1141e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2031): 1142e9a25e04SMatt Gruskin num_outs = 8; 1143e9a25e04SMatt Gruskin num_ins = 6; 1144e9a25e04SMatt Gruskin break; 1145e9a25e04SMatt Gruskin } 1146e9a25e04SMatt Gruskin 1147e9a25e04SMatt Gruskin for (chan = 0; chan < num_outs + num_ins; chan++) { 1148e9a25e04SMatt Gruskin if (chan < num_outs) { 114909d8e3a7SEldad Zack snprintf(name, sizeof(name), 115009d8e3a7SEldad Zack "Effect Send DOut%d", 115109d8e3a7SEldad Zack chan + 1); 115209d8e3a7SEldad Zack } else { 115309d8e3a7SEldad Zack snprintf(name, sizeof(name), 115409d8e3a7SEldad Zack "Effect Send AIn%d", 1155e9a25e04SMatt Gruskin chan - num_outs + 1); 115609d8e3a7SEldad Zack } 115709d8e3a7SEldad Zack 115809d8e3a7SEldad Zack cmask = (chan == 0) ? 0 : 1 << (chan - 1); 115909d8e3a7SEldad Zack err = snd_create_std_mono_ctl(mixer, id, control, 116009d8e3a7SEldad Zack cmask, val_type, name, 116109d8e3a7SEldad Zack &snd_usb_mixer_vol_tlv); 116209d8e3a7SEldad Zack if (err < 0) 116309d8e3a7SEldad Zack return err; 116409d8e3a7SEldad Zack } 116509d8e3a7SEldad Zack 116609d8e3a7SEldad Zack return 0; 116709d8e3a7SEldad Zack } 116809d8e3a7SEldad Zack 116909d8e3a7SEldad Zack static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer) 117009d8e3a7SEldad Zack { 117109d8e3a7SEldad Zack char name[64]; 117209d8e3a7SEldad Zack unsigned int cmask; 117309d8e3a7SEldad Zack int chan, err; 1174e9a25e04SMatt Gruskin int num_outs = 0; 1175e9a25e04SMatt Gruskin int offset = 0; 117609d8e3a7SEldad Zack 117709d8e3a7SEldad Zack const unsigned int id = 0x40; 117809d8e3a7SEldad Zack const int val_type = USB_MIXER_S16; 117909d8e3a7SEldad Zack const int control = 1; 118009d8e3a7SEldad Zack 1181e9a25e04SMatt Gruskin switch (mixer->chip->usb_id) { 1182e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2030): 1183e9a25e04SMatt Gruskin num_outs = 6; 1184e9a25e04SMatt Gruskin offset = 0x3c; 1185e9a25e04SMatt Gruskin /* { 0x3c, 0x43, 0x3e, 0x45, 0x40, 0x47 } */ 1186e9a25e04SMatt Gruskin break; 1187e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2031): 1188e9a25e04SMatt Gruskin num_outs = 8; 1189e9a25e04SMatt Gruskin offset = 0x70; 1190e9a25e04SMatt Gruskin /* { 0x70, 0x79, 0x72, 0x7b, 0x74, 0x7d, 0x76, 0x7f } */ 1191e9a25e04SMatt Gruskin break; 1192e9a25e04SMatt Gruskin } 1193e9a25e04SMatt Gruskin 1194e9a25e04SMatt Gruskin for (chan = 0; chan < num_outs; chan++) { 119509d8e3a7SEldad Zack snprintf(name, sizeof(name), 119609d8e3a7SEldad Zack "Effect Return %d", 119709d8e3a7SEldad Zack chan + 1); 119809d8e3a7SEldad Zack 1199e9a25e04SMatt Gruskin cmask = (chan == 0) ? 0 : 1200e9a25e04SMatt Gruskin 1 << (chan + (chan % 2) * num_outs - 1); 120109d8e3a7SEldad Zack err = snd_create_std_mono_ctl_offset(mixer, id, control, 120209d8e3a7SEldad Zack cmask, val_type, offset, name, 120309d8e3a7SEldad Zack &snd_usb_mixer_vol_tlv); 120409d8e3a7SEldad Zack if (err < 0) 120509d8e3a7SEldad Zack return err; 120609d8e3a7SEldad Zack } 120709d8e3a7SEldad Zack 120809d8e3a7SEldad Zack return 0; 120909d8e3a7SEldad Zack } 121009d8e3a7SEldad Zack 121109d8e3a7SEldad Zack static int snd_c400_create_mixer(struct usb_mixer_interface *mixer) 121209d8e3a7SEldad Zack { 121309d8e3a7SEldad Zack int err; 121409d8e3a7SEldad Zack 121509d8e3a7SEldad Zack err = snd_c400_create_vol_ctls(mixer); 121609d8e3a7SEldad Zack if (err < 0) 121709d8e3a7SEldad Zack return err; 121809d8e3a7SEldad Zack 121909d8e3a7SEldad Zack err = snd_c400_create_effect_vol_ctls(mixer); 122009d8e3a7SEldad Zack if (err < 0) 122109d8e3a7SEldad Zack return err; 122209d8e3a7SEldad Zack 122309d8e3a7SEldad Zack err = snd_c400_create_effect_ret_vol_ctls(mixer); 122409d8e3a7SEldad Zack if (err < 0) 122509d8e3a7SEldad Zack return err; 122609d8e3a7SEldad Zack 122709d8e3a7SEldad Zack err = snd_ftu_create_effect_switch(mixer, 2, 0x43); 122809d8e3a7SEldad Zack if (err < 0) 122909d8e3a7SEldad Zack return err; 123009d8e3a7SEldad Zack 123109d8e3a7SEldad Zack err = snd_c400_create_effect_volume_ctl(mixer); 123209d8e3a7SEldad Zack if (err < 0) 123309d8e3a7SEldad Zack return err; 123409d8e3a7SEldad Zack 123509d8e3a7SEldad Zack err = snd_c400_create_effect_duration_ctl(mixer); 123609d8e3a7SEldad Zack if (err < 0) 123709d8e3a7SEldad Zack return err; 123809d8e3a7SEldad Zack 123909d8e3a7SEldad Zack err = snd_c400_create_effect_feedback_ctl(mixer); 124009d8e3a7SEldad Zack if (err < 0) 124109d8e3a7SEldad Zack return err; 124209d8e3a7SEldad Zack 124309d8e3a7SEldad Zack return 0; 124409d8e3a7SEldad Zack } 124509d8e3a7SEldad Zack 1246b71dad18SMark Hills /* 1247b71dad18SMark Hills * The mixer units for Ebox-44 are corrupt, and even where they 1248b71dad18SMark Hills * are valid they presents mono controls as L and R channels of 1249b71dad18SMark Hills * stereo. So we provide a good mixer here. 1250b71dad18SMark Hills */ 1251e8e7da23SSachin Kamat static struct std_mono_table ebox44_table[] = { 1252989b0138SMark Hills { 1253989b0138SMark Hills .unitid = 4, 1254989b0138SMark Hills .control = 1, 1255989b0138SMark Hills .cmask = 0x0, 1256989b0138SMark Hills .val_type = USB_MIXER_INV_BOOLEAN, 1257989b0138SMark Hills .name = "Headphone Playback Switch" 1258989b0138SMark Hills }, 1259989b0138SMark Hills { 1260989b0138SMark Hills .unitid = 4, 1261989b0138SMark Hills .control = 2, 1262989b0138SMark Hills .cmask = 0x1, 1263989b0138SMark Hills .val_type = USB_MIXER_S16, 1264989b0138SMark Hills .name = "Headphone A Mix Playback Volume" 1265989b0138SMark Hills }, 1266989b0138SMark Hills { 1267989b0138SMark Hills .unitid = 4, 1268989b0138SMark Hills .control = 2, 1269989b0138SMark Hills .cmask = 0x2, 1270989b0138SMark Hills .val_type = USB_MIXER_S16, 1271989b0138SMark Hills .name = "Headphone B Mix Playback Volume" 1272989b0138SMark Hills }, 1273b71dad18SMark Hills 1274989b0138SMark Hills { 1275989b0138SMark Hills .unitid = 7, 1276989b0138SMark Hills .control = 1, 1277989b0138SMark Hills .cmask = 0x0, 1278989b0138SMark Hills .val_type = USB_MIXER_INV_BOOLEAN, 1279989b0138SMark Hills .name = "Output Playback Switch" 1280989b0138SMark Hills }, 1281989b0138SMark Hills { 1282989b0138SMark Hills .unitid = 7, 1283989b0138SMark Hills .control = 2, 1284989b0138SMark Hills .cmask = 0x1, 1285989b0138SMark Hills .val_type = USB_MIXER_S16, 1286989b0138SMark Hills .name = "Output A Playback Volume" 1287989b0138SMark Hills }, 1288989b0138SMark Hills { 1289989b0138SMark Hills .unitid = 7, 1290989b0138SMark Hills .control = 2, 1291989b0138SMark Hills .cmask = 0x2, 1292989b0138SMark Hills .val_type = USB_MIXER_S16, 1293989b0138SMark Hills .name = "Output B Playback Volume" 1294989b0138SMark Hills }, 1295b71dad18SMark Hills 1296989b0138SMark Hills { 1297989b0138SMark Hills .unitid = 10, 1298989b0138SMark Hills .control = 1, 1299989b0138SMark Hills .cmask = 0x0, 1300989b0138SMark Hills .val_type = USB_MIXER_INV_BOOLEAN, 1301989b0138SMark Hills .name = "Input Capture Switch" 1302989b0138SMark Hills }, 1303989b0138SMark Hills { 1304989b0138SMark Hills .unitid = 10, 1305989b0138SMark Hills .control = 2, 1306989b0138SMark Hills .cmask = 0x1, 1307989b0138SMark Hills .val_type = USB_MIXER_S16, 1308989b0138SMark Hills .name = "Input A Capture Volume" 1309989b0138SMark Hills }, 1310989b0138SMark Hills { 1311989b0138SMark Hills .unitid = 10, 1312989b0138SMark Hills .control = 2, 1313989b0138SMark Hills .cmask = 0x2, 1314989b0138SMark Hills .val_type = USB_MIXER_S16, 1315989b0138SMark Hills .name = "Input B Capture Volume" 1316989b0138SMark Hills }, 1317b71dad18SMark Hills 1318b71dad18SMark Hills {} 1319b71dad18SMark Hills }; 1320b71dad18SMark Hills 1321066624c6SPrzemek Rudy /* Audio Advantage Micro II findings: 1322066624c6SPrzemek Rudy * 1323066624c6SPrzemek Rudy * Mapping spdif AES bits to vendor register.bit: 1324066624c6SPrzemek Rudy * AES0: [0 0 0 0 2.3 2.2 2.1 2.0] - default 0x00 1325066624c6SPrzemek Rudy * AES1: [3.3 3.2.3.1.3.0 2.7 2.6 2.5 2.4] - default: 0x01 1326066624c6SPrzemek Rudy * AES2: [0 0 0 0 0 0 0 0] 1327066624c6SPrzemek Rudy * AES3: [0 0 0 0 0 0 x 0] - 'x' bit is set basing on standard usb request 1328066624c6SPrzemek Rudy * (UAC_EP_CS_ATTR_SAMPLE_RATE) for Audio Devices 1329066624c6SPrzemek Rudy * 1330066624c6SPrzemek Rudy * power on values: 1331066624c6SPrzemek Rudy * r2: 0x10 1332066624c6SPrzemek Rudy * r3: 0x20 (b7 is zeroed just before playback (except IEC61937) and set 1333066624c6SPrzemek Rudy * just after it to 0xa0, presumably it disables/mutes some analog 1334066624c6SPrzemek Rudy * parts when there is no audio.) 1335066624c6SPrzemek Rudy * r9: 0x28 1336066624c6SPrzemek Rudy * 1337066624c6SPrzemek Rudy * Optical transmitter on/off: 1338066624c6SPrzemek Rudy * vendor register.bit: 9.1 1339066624c6SPrzemek Rudy * 0 - on (0x28 register value) 1340066624c6SPrzemek Rudy * 1 - off (0x2a register value) 1341066624c6SPrzemek Rudy * 1342066624c6SPrzemek Rudy */ 1343066624c6SPrzemek Rudy static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol, 1344066624c6SPrzemek Rudy struct snd_ctl_elem_info *uinfo) 1345066624c6SPrzemek Rudy { 1346066624c6SPrzemek Rudy uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 1347066624c6SPrzemek Rudy uinfo->count = 1; 1348066624c6SPrzemek Rudy return 0; 1349066624c6SPrzemek Rudy } 1350066624c6SPrzemek Rudy 1351066624c6SPrzemek Rudy static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, 1352066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1353066624c6SPrzemek Rudy { 1354066624c6SPrzemek Rudy struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 1355066624c6SPrzemek Rudy int err; 1356066624c6SPrzemek Rudy struct usb_interface *iface; 1357066624c6SPrzemek Rudy struct usb_host_interface *alts; 1358066624c6SPrzemek Rudy unsigned int ep; 1359066624c6SPrzemek Rudy unsigned char data[3]; 1360066624c6SPrzemek Rudy int rate; 1361066624c6SPrzemek Rudy 1362066624c6SPrzemek Rudy ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff; 1363066624c6SPrzemek Rudy ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff; 1364066624c6SPrzemek Rudy ucontrol->value.iec958.status[2] = 0x00; 1365066624c6SPrzemek Rudy 1366066624c6SPrzemek Rudy /* use known values for that card: interface#1 altsetting#1 */ 1367066624c6SPrzemek Rudy iface = usb_ifnum_to_if(mixer->chip->dev, 1); 1368066624c6SPrzemek Rudy alts = &iface->altsetting[1]; 1369066624c6SPrzemek Rudy ep = get_endpoint(alts, 0)->bEndpointAddress; 1370066624c6SPrzemek Rudy 1371066624c6SPrzemek Rudy err = snd_usb_ctl_msg(mixer->chip->dev, 1372066624c6SPrzemek Rudy usb_rcvctrlpipe(mixer->chip->dev, 0), 1373066624c6SPrzemek Rudy UAC_GET_CUR, 1374066624c6SPrzemek Rudy USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, 1375066624c6SPrzemek Rudy UAC_EP_CS_ATTR_SAMPLE_RATE << 8, 1376066624c6SPrzemek Rudy ep, 1377066624c6SPrzemek Rudy data, 1378066624c6SPrzemek Rudy sizeof(data)); 1379066624c6SPrzemek Rudy if (err < 0) 1380066624c6SPrzemek Rudy goto end; 1381066624c6SPrzemek Rudy 1382066624c6SPrzemek Rudy rate = data[0] | (data[1] << 8) | (data[2] << 16); 1383066624c6SPrzemek Rudy ucontrol->value.iec958.status[3] = (rate == 48000) ? 1384066624c6SPrzemek Rudy IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100; 1385066624c6SPrzemek Rudy 1386066624c6SPrzemek Rudy err = 0; 1387066624c6SPrzemek Rudy end: 1388066624c6SPrzemek Rudy return err; 1389066624c6SPrzemek Rudy } 1390066624c6SPrzemek Rudy 1391066624c6SPrzemek Rudy static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, 1392066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1393066624c6SPrzemek Rudy { 1394066624c6SPrzemek Rudy struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 1395066624c6SPrzemek Rudy int err; 1396066624c6SPrzemek Rudy u8 reg; 1397066624c6SPrzemek Rudy unsigned long priv_backup = kcontrol->private_value; 1398066624c6SPrzemek Rudy 1399066624c6SPrzemek Rudy reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) | 1400066624c6SPrzemek Rudy (ucontrol->value.iec958.status[0] & 0x0f); 1401066624c6SPrzemek Rudy err = snd_usb_ctl_msg(mixer->chip->dev, 1402066624c6SPrzemek Rudy usb_sndctrlpipe(mixer->chip->dev, 0), 1403066624c6SPrzemek Rudy UAC_SET_CUR, 1404066624c6SPrzemek Rudy USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 1405066624c6SPrzemek Rudy reg, 1406066624c6SPrzemek Rudy 2, 1407066624c6SPrzemek Rudy NULL, 1408066624c6SPrzemek Rudy 0); 1409066624c6SPrzemek Rudy if (err < 0) 1410066624c6SPrzemek Rudy goto end; 1411066624c6SPrzemek Rudy 1412066624c6SPrzemek Rudy kcontrol->private_value &= 0xfffff0f0; 1413066624c6SPrzemek Rudy kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8; 1414066624c6SPrzemek Rudy kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f); 1415066624c6SPrzemek Rudy 1416066624c6SPrzemek Rudy reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ? 1417066624c6SPrzemek Rudy 0xa0 : 0x20; 1418066624c6SPrzemek Rudy reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f; 1419066624c6SPrzemek Rudy err = snd_usb_ctl_msg(mixer->chip->dev, 1420066624c6SPrzemek Rudy usb_sndctrlpipe(mixer->chip->dev, 0), 1421066624c6SPrzemek Rudy UAC_SET_CUR, 1422066624c6SPrzemek Rudy USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 1423066624c6SPrzemek Rudy reg, 1424066624c6SPrzemek Rudy 3, 1425066624c6SPrzemek Rudy NULL, 1426066624c6SPrzemek Rudy 0); 1427066624c6SPrzemek Rudy if (err < 0) 1428066624c6SPrzemek Rudy goto end; 1429066624c6SPrzemek Rudy 1430066624c6SPrzemek Rudy kcontrol->private_value &= 0xffff0fff; 1431066624c6SPrzemek Rudy kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8; 1432066624c6SPrzemek Rudy 1433066624c6SPrzemek Rudy /* The frequency bits in AES3 cannot be set via register access. */ 1434066624c6SPrzemek Rudy 1435066624c6SPrzemek Rudy /* Silently ignore any bits from the request that cannot be set. */ 1436066624c6SPrzemek Rudy 1437066624c6SPrzemek Rudy err = (priv_backup != kcontrol->private_value); 1438066624c6SPrzemek Rudy end: 1439066624c6SPrzemek Rudy return err; 1440066624c6SPrzemek Rudy } 1441066624c6SPrzemek Rudy 1442066624c6SPrzemek Rudy static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol, 1443066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1444066624c6SPrzemek Rudy { 1445066624c6SPrzemek Rudy ucontrol->value.iec958.status[0] = 0x0f; 1446066624c6SPrzemek Rudy ucontrol->value.iec958.status[1] = 0xff; 1447066624c6SPrzemek Rudy ucontrol->value.iec958.status[2] = 0x00; 1448066624c6SPrzemek Rudy ucontrol->value.iec958.status[3] = 0x00; 1449066624c6SPrzemek Rudy 1450066624c6SPrzemek Rudy return 0; 1451066624c6SPrzemek Rudy } 1452066624c6SPrzemek Rudy 1453066624c6SPrzemek Rudy static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol, 1454066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1455066624c6SPrzemek Rudy { 1456066624c6SPrzemek Rudy ucontrol->value.integer.value[0] = !(kcontrol->private_value & 0x02); 1457066624c6SPrzemek Rudy 1458066624c6SPrzemek Rudy return 0; 1459066624c6SPrzemek Rudy } 1460066624c6SPrzemek Rudy 1461066624c6SPrzemek Rudy static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol, 1462066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1463066624c6SPrzemek Rudy { 1464066624c6SPrzemek Rudy struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); 1465066624c6SPrzemek Rudy int err; 1466066624c6SPrzemek Rudy u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a; 1467066624c6SPrzemek Rudy 1468066624c6SPrzemek Rudy err = snd_usb_ctl_msg(mixer->chip->dev, 1469066624c6SPrzemek Rudy usb_sndctrlpipe(mixer->chip->dev, 0), 1470066624c6SPrzemek Rudy UAC_SET_CUR, 1471066624c6SPrzemek Rudy USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 1472066624c6SPrzemek Rudy reg, 1473066624c6SPrzemek Rudy 9, 1474066624c6SPrzemek Rudy NULL, 1475066624c6SPrzemek Rudy 0); 1476066624c6SPrzemek Rudy 1477066624c6SPrzemek Rudy if (!err) { 1478066624c6SPrzemek Rudy err = (reg != (kcontrol->private_value & 0x0ff)); 1479066624c6SPrzemek Rudy if (err) 1480066624c6SPrzemek Rudy kcontrol->private_value = reg; 1481066624c6SPrzemek Rudy } 1482066624c6SPrzemek Rudy 1483066624c6SPrzemek Rudy return err; 1484066624c6SPrzemek Rudy } 1485066624c6SPrzemek Rudy 1486066624c6SPrzemek Rudy static struct snd_kcontrol_new snd_microii_mixer_spdif[] = { 1487066624c6SPrzemek Rudy { 1488066624c6SPrzemek Rudy .iface = SNDRV_CTL_ELEM_IFACE_PCM, 1489066624c6SPrzemek Rudy .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), 1490066624c6SPrzemek Rudy .info = snd_microii_spdif_info, 1491066624c6SPrzemek Rudy .get = snd_microii_spdif_default_get, 1492066624c6SPrzemek Rudy .put = snd_microii_spdif_default_put, 1493066624c6SPrzemek Rudy .private_value = 0x00000100UL,/* reset value */ 1494066624c6SPrzemek Rudy }, 1495066624c6SPrzemek Rudy { 1496066624c6SPrzemek Rudy .access = SNDRV_CTL_ELEM_ACCESS_READ, 1497066624c6SPrzemek Rudy .iface = SNDRV_CTL_ELEM_IFACE_PCM, 1498066624c6SPrzemek Rudy .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), 1499066624c6SPrzemek Rudy .info = snd_microii_spdif_info, 1500066624c6SPrzemek Rudy .get = snd_microii_spdif_mask_get, 1501066624c6SPrzemek Rudy }, 1502066624c6SPrzemek Rudy { 1503066624c6SPrzemek Rudy .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1504066624c6SPrzemek Rudy .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), 1505066624c6SPrzemek Rudy .info = snd_ctl_boolean_mono_info, 1506066624c6SPrzemek Rudy .get = snd_microii_spdif_switch_get, 1507066624c6SPrzemek Rudy .put = snd_microii_spdif_switch_put, 1508066624c6SPrzemek Rudy .private_value = 0x00000028UL,/* reset value */ 1509066624c6SPrzemek Rudy } 1510066624c6SPrzemek Rudy }; 1511066624c6SPrzemek Rudy 1512066624c6SPrzemek Rudy static int snd_microii_controls_create(struct usb_mixer_interface *mixer) 1513066624c6SPrzemek Rudy { 1514066624c6SPrzemek Rudy int err, i; 1515066624c6SPrzemek Rudy 1516066624c6SPrzemek Rudy for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) { 1517066624c6SPrzemek Rudy err = snd_ctl_add(mixer->chip->card, 1518066624c6SPrzemek Rudy snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer)); 1519066624c6SPrzemek Rudy if (err < 0) 1520066624c6SPrzemek Rudy return err; 1521066624c6SPrzemek Rudy } 1522066624c6SPrzemek Rudy 1523066624c6SPrzemek Rudy return err; 1524066624c6SPrzemek Rudy } 1525066624c6SPrzemek Rudy 15267b1eda22SDaniel Mack int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) 15277b1eda22SDaniel Mack { 15283347b26cSDaniel Mack int err = 0; 15297b1eda22SDaniel Mack struct snd_info_entry *entry; 15307b1eda22SDaniel Mack 15317b1eda22SDaniel Mack if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) 15327b1eda22SDaniel Mack return err; 15337b1eda22SDaniel Mack 15343347b26cSDaniel Mack switch (mixer->chip->usb_id) { 15353347b26cSDaniel Mack case USB_ID(0x041e, 0x3020): 15363347b26cSDaniel Mack case USB_ID(0x041e, 0x3040): 15373347b26cSDaniel Mack case USB_ID(0x041e, 0x3042): 15387cdd8d73SMathieu Bouffard case USB_ID(0x041e, 0x30df): 15393347b26cSDaniel Mack case USB_ID(0x041e, 0x3048): 15403347b26cSDaniel Mack err = snd_audigy2nx_controls_create(mixer); 15413347b26cSDaniel Mack if (err < 0) 15423347b26cSDaniel Mack break; 15437b1eda22SDaniel Mack if (!snd_card_proc_new(mixer->chip->card, "audigy2nx", &entry)) 15447b1eda22SDaniel Mack snd_info_set_text_ops(entry, mixer, 15457b1eda22SDaniel Mack snd_audigy2nx_proc_read); 15463347b26cSDaniel Mack break; 15477b1eda22SDaniel Mack 154809d8e3a7SEldad Zack case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ 1549e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C400 */ 155009d8e3a7SEldad Zack err = snd_c400_create_mixer(mixer); 155109d8e3a7SEldad Zack break; 155209d8e3a7SEldad Zack 1553d5a0bf6cSDaniel Mack case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ 1554d5a0bf6cSDaniel Mack case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ 1555cfe8f97cSFelix Homann err = snd_ftu_create_mixer(mixer); 1556d5a0bf6cSDaniel Mack break; 1557d5a0bf6cSDaniel Mack 15581d31affbSDenis Washington case USB_ID(0x0b05, 0x1739): /* ASUS Xonar U1 */ 15591d31affbSDenis Washington case USB_ID(0x0b05, 0x1743): /* ASUS Xonar U1 (2) */ 15601d31affbSDenis Washington case USB_ID(0x0b05, 0x17a0): /* ASUS Xonar U3 */ 15617b1eda22SDaniel Mack err = snd_xonar_u1_controls_create(mixer); 15623347b26cSDaniel Mack break; 15637b1eda22SDaniel Mack 1564066624c6SPrzemek Rudy case USB_ID(0x0d8c, 0x0103): /* Audio Advantage Micro II */ 1565066624c6SPrzemek Rudy err = snd_microii_controls_create(mixer); 1566066624c6SPrzemek Rudy break; 1567066624c6SPrzemek Rudy 15683347b26cSDaniel Mack case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */ 156954a8c500SDaniel Mack err = snd_nativeinstruments_create_mixer(mixer, 157054a8c500SDaniel Mack snd_nativeinstruments_ta6_mixers, 157154a8c500SDaniel Mack ARRAY_SIZE(snd_nativeinstruments_ta6_mixers)); 15723347b26cSDaniel Mack break; 157354a8c500SDaniel Mack 15743347b26cSDaniel Mack case USB_ID(0x17cc, 0x1021): /* Traktor Audio 10 */ 157554a8c500SDaniel Mack err = snd_nativeinstruments_create_mixer(mixer, 157654a8c500SDaniel Mack snd_nativeinstruments_ta10_mixers, 157754a8c500SDaniel Mack ARRAY_SIZE(snd_nativeinstruments_ta10_mixers)); 15783347b26cSDaniel Mack break; 15797536c301SMark Hills 15807536c301SMark Hills case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */ 1581b71dad18SMark Hills /* detection is disabled in mixer_maps.c */ 1582b71dad18SMark Hills err = snd_create_std_mono_table(mixer, ebox44_table); 15837536c301SMark Hills break; 158454a8c500SDaniel Mack } 158554a8c500SDaniel Mack 15863347b26cSDaniel Mack return err; 15877b1eda22SDaniel Mack } 15887b1eda22SDaniel Mack 15897b1eda22SDaniel Mack void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, 15907b1eda22SDaniel Mack int unitid) 15917b1eda22SDaniel Mack { 15927b1eda22SDaniel Mack if (!mixer->rc_cfg) 15937b1eda22SDaniel Mack return; 15947b1eda22SDaniel Mack /* unit ids specific to Extigy/Audigy 2 NX: */ 15957b1eda22SDaniel Mack switch (unitid) { 15967b1eda22SDaniel Mack case 0: /* remote control */ 15977b1eda22SDaniel Mack mixer->rc_urb->dev = mixer->chip->dev; 15987b1eda22SDaniel Mack usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); 15997b1eda22SDaniel Mack break; 16007b1eda22SDaniel Mack case 4: /* digital in jack */ 16017b1eda22SDaniel Mack case 7: /* line in jacks */ 16027b1eda22SDaniel Mack case 19: /* speaker out jacks */ 16037b1eda22SDaniel Mack case 20: /* headphones out jack */ 16047b1eda22SDaniel Mack break; 16057b1eda22SDaniel Mack /* live24ext: 4 = line-in jack */ 16067b1eda22SDaniel Mack case 3: /* hp-out jack (may actuate Mute) */ 16077b1eda22SDaniel Mack if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 16087b1eda22SDaniel Mack mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) 16097b1eda22SDaniel Mack snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id); 16107b1eda22SDaniel Mack break; 16117b1eda22SDaniel Mack default: 16127b1eda22SDaniel Mack snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid); 16137b1eda22SDaniel Mack break; 16147b1eda22SDaniel Mack } 16157b1eda22SDaniel Mack } 16167b1eda22SDaniel Mack 1617