11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 27b1eda22SDaniel Mack /* 37b1eda22SDaniel Mack * USB Audio Driver for ALSA 47b1eda22SDaniel Mack * 57b1eda22SDaniel Mack * Quirks and vendor-specific extensions for mixer interfaces 67b1eda22SDaniel Mack * 77b1eda22SDaniel Mack * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> 87b1eda22SDaniel Mack * 97b1eda22SDaniel Mack * Many codes borrowed from audio.c by 107b1eda22SDaniel Mack * Alan Cox (alan@lxorguk.ukuu.org.uk) 117b1eda22SDaniel Mack * Thomas Sailer (sailer@ife.ee.ethz.ch) 127b1eda22SDaniel Mack * 13066624c6SPrzemek Rudy * Audio Advantage Micro II support added by: 14066624c6SPrzemek Rudy * Przemek Rudy (prudy1@o2.pl) 157b1eda22SDaniel Mack */ 167b1eda22SDaniel Mack 17388fdb8fSIan Douglas Scott #include <linux/hid.h> 187b1eda22SDaniel Mack #include <linux/init.h> 19d39f1d68SJussi Laako #include <linux/math64.h> 2036db0456SStephen Rothwell #include <linux/slab.h> 217b1eda22SDaniel Mack #include <linux/usb.h> 227b1eda22SDaniel Mack #include <linux/usb/audio.h> 237b1eda22SDaniel Mack 24066624c6SPrzemek Rudy #include <sound/asoundef.h> 257b1eda22SDaniel Mack #include <sound/core.h> 267b1eda22SDaniel Mack #include <sound/control.h> 277b1eda22SDaniel Mack #include <sound/hwdep.h> 287b1eda22SDaniel Mack #include <sound/info.h> 2942e3121dSAnssi Hannula #include <sound/tlv.h> 307b1eda22SDaniel Mack 317b1eda22SDaniel Mack #include "usbaudio.h" 32f0b5e634SDaniel Mack #include "mixer.h" 337b1eda22SDaniel Mack #include "mixer_quirks.h" 3476b188c4SChris J Arges #include "mixer_scarlett.h" 359e4d5c1bSGeoffrey D. Bennett #include "mixer_scarlett_gen2.h" 36d2bb390aSDetlef Urban #include "mixer_us16x08.h" 378dc5efe3SNick Kossifidis #include "mixer_s1810c.h" 387b1eda22SDaniel Mack #include "helper.h" 397b1eda22SDaniel Mack 40b71dad18SMark Hills struct std_mono_table { 41b71dad18SMark Hills unsigned int unitid, control, cmask; 42b71dad18SMark Hills int val_type; 43b71dad18SMark Hills const char *name; 44b71dad18SMark Hills snd_kcontrol_tlv_rw_t *tlv_callback; 45b71dad18SMark Hills }; 46b71dad18SMark Hills 478a4d1d39SFelix Homann /* This function allows for the creation of standard UAC controls. 488a4d1d39SFelix Homann * See the quirks for M-Audio FTUs or Ebox-44. 498a4d1d39SFelix Homann * If you don't want to set a TLV callback pass NULL. 508a4d1d39SFelix Homann * 518a4d1d39SFelix Homann * Since there doesn't seem to be a devices that needs a multichannel 528a4d1d39SFelix Homann * version, we keep it mono for simplicity. 538a4d1d39SFelix Homann */ 549f814105SEldad Zack static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer, 558a4d1d39SFelix Homann unsigned int unitid, 568a4d1d39SFelix Homann unsigned int control, 578a4d1d39SFelix Homann unsigned int cmask, 588a4d1d39SFelix Homann int val_type, 599f814105SEldad Zack unsigned int idx_off, 608a4d1d39SFelix Homann const char *name, 618a4d1d39SFelix Homann snd_kcontrol_tlv_rw_t *tlv_callback) 628a4d1d39SFelix Homann { 638a4d1d39SFelix Homann struct usb_mixer_elem_info *cval; 648a4d1d39SFelix Homann struct snd_kcontrol *kctl; 658a4d1d39SFelix Homann 668a4d1d39SFelix Homann cval = kzalloc(sizeof(*cval), GFP_KERNEL); 678a4d1d39SFelix Homann if (!cval) 688a4d1d39SFelix Homann return -ENOMEM; 698a4d1d39SFelix Homann 703360b84bSTakashi Iwai snd_usb_mixer_elem_init_std(&cval->head, mixer, unitid); 718a4d1d39SFelix Homann cval->val_type = val_type; 728a4d1d39SFelix Homann cval->channels = 1; 738a4d1d39SFelix Homann cval->control = control; 748a4d1d39SFelix Homann cval->cmask = cmask; 759f814105SEldad Zack cval->idx_off = idx_off; 768a4d1d39SFelix Homann 777df4a691SMark Hills /* get_min_max() is called only for integer volumes later, 787df4a691SMark Hills * so provide a short-cut for booleans */ 798a4d1d39SFelix Homann cval->min = 0; 808a4d1d39SFelix Homann cval->max = 1; 818a4d1d39SFelix Homann cval->res = 0; 828a4d1d39SFelix Homann cval->dBmin = 0; 838a4d1d39SFelix Homann cval->dBmax = 0; 848a4d1d39SFelix Homann 858a4d1d39SFelix Homann /* Create control */ 868a4d1d39SFelix Homann kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval); 878a4d1d39SFelix Homann if (!kctl) { 888a4d1d39SFelix Homann kfree(cval); 898a4d1d39SFelix Homann return -ENOMEM; 908a4d1d39SFelix Homann } 918a4d1d39SFelix Homann 928a4d1d39SFelix Homann /* Set name */ 938a4d1d39SFelix Homann snprintf(kctl->id.name, sizeof(kctl->id.name), name); 94eef90451SChris J Arges kctl->private_free = snd_usb_mixer_elem_free; 958a4d1d39SFelix Homann 968a4d1d39SFelix Homann /* set TLV */ 978a4d1d39SFelix Homann if (tlv_callback) { 988a4d1d39SFelix Homann kctl->tlv.c = tlv_callback; 998a4d1d39SFelix Homann kctl->vd[0].access |= 1008a4d1d39SFelix Homann SNDRV_CTL_ELEM_ACCESS_TLV_READ | 1018a4d1d39SFelix Homann SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; 1028a4d1d39SFelix Homann } 1038a4d1d39SFelix Homann /* Add control to mixer */ 1043360b84bSTakashi Iwai return snd_usb_mixer_add_control(&cval->head, kctl); 1058a4d1d39SFelix Homann } 1068a4d1d39SFelix Homann 1079f814105SEldad Zack static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, 1089f814105SEldad Zack unsigned int unitid, 1099f814105SEldad Zack unsigned int control, 1109f814105SEldad Zack unsigned int cmask, 1119f814105SEldad Zack int val_type, 1129f814105SEldad Zack const char *name, 1139f814105SEldad Zack snd_kcontrol_tlv_rw_t *tlv_callback) 1149f814105SEldad Zack { 1159f814105SEldad Zack return snd_create_std_mono_ctl_offset(mixer, unitid, control, cmask, 1169f814105SEldad Zack val_type, 0 /* Offset */, name, tlv_callback); 1179f814105SEldad Zack } 1189f814105SEldad Zack 1197b1eda22SDaniel Mack /* 120b71dad18SMark Hills * Create a set of standard UAC controls from a table 121b71dad18SMark Hills */ 122b71dad18SMark Hills static int snd_create_std_mono_table(struct usb_mixer_interface *mixer, 123a01df925STakashi Iwai const struct std_mono_table *t) 124b71dad18SMark Hills { 125b71dad18SMark Hills int err; 126b71dad18SMark Hills 127b71dad18SMark Hills while (t->name != NULL) { 128b71dad18SMark Hills err = snd_create_std_mono_ctl(mixer, t->unitid, t->control, 129b71dad18SMark Hills t->cmask, t->val_type, t->name, t->tlv_callback); 130b71dad18SMark Hills if (err < 0) 131b71dad18SMark Hills return err; 132b71dad18SMark Hills t++; 133b71dad18SMark Hills } 134b71dad18SMark Hills 135b71dad18SMark Hills return 0; 136b71dad18SMark Hills } 137b71dad18SMark Hills 1389cf3689bSTakashi Iwai static int add_single_ctl_with_resume(struct usb_mixer_interface *mixer, 1399cf3689bSTakashi Iwai int id, 1409cf3689bSTakashi Iwai usb_mixer_elem_resume_func_t resume, 1419cf3689bSTakashi Iwai const struct snd_kcontrol_new *knew, 1429cf3689bSTakashi Iwai struct usb_mixer_elem_list **listp) 1439cf3689bSTakashi Iwai { 1449cf3689bSTakashi Iwai struct usb_mixer_elem_list *list; 1459cf3689bSTakashi Iwai struct snd_kcontrol *kctl; 1469cf3689bSTakashi Iwai 1479cf3689bSTakashi Iwai list = kzalloc(sizeof(*list), GFP_KERNEL); 1489cf3689bSTakashi Iwai if (!list) 1499cf3689bSTakashi Iwai return -ENOMEM; 1509cf3689bSTakashi Iwai if (listp) 1519cf3689bSTakashi Iwai *listp = list; 1529cf3689bSTakashi Iwai list->mixer = mixer; 1539cf3689bSTakashi Iwai list->id = id; 15444609fc0SKai-Heng Feng list->reset_resume = resume; 1559cf3689bSTakashi Iwai kctl = snd_ctl_new1(knew, list); 1569cf3689bSTakashi Iwai if (!kctl) { 1579cf3689bSTakashi Iwai kfree(list); 1589cf3689bSTakashi Iwai return -ENOMEM; 1599cf3689bSTakashi Iwai } 1609cf3689bSTakashi Iwai kctl->private_free = snd_usb_mixer_elem_free; 161220345e9STakashi Iwai /* don't use snd_usb_mixer_add_control() here, this is a special list element */ 162220345e9STakashi Iwai return snd_usb_mixer_add_list(list, kctl, false); 1639cf3689bSTakashi Iwai } 1649cf3689bSTakashi Iwai 165b71dad18SMark Hills /* 1667b1eda22SDaniel Mack * Sound Blaster remote control configuration 1677b1eda22SDaniel Mack * 1687b1eda22SDaniel Mack * format of remote control data: 1697b1eda22SDaniel Mack * Extigy: xx 00 1707b1eda22SDaniel Mack * Audigy 2 NX: 06 80 xx 00 00 00 1717b1eda22SDaniel Mack * Live! 24-bit: 06 80 xx yy 22 83 1727b1eda22SDaniel Mack */ 1737b1eda22SDaniel Mack static const struct rc_config { 1747b1eda22SDaniel Mack u32 usb_id; 1757b1eda22SDaniel Mack u8 offset; 1767b1eda22SDaniel Mack u8 length; 1777b1eda22SDaniel Mack u8 packet_length; 1787b1eda22SDaniel Mack u8 min_packet_length; /* minimum accepted length of the URB result */ 1797b1eda22SDaniel Mack u8 mute_mixer_id; 1807b1eda22SDaniel Mack u32 mute_code; 1817b1eda22SDaniel Mack } rc_configs[] = { 1827b1eda22SDaniel Mack { USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */ 1837b1eda22SDaniel Mack { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */ 1847b1eda22SDaniel Mack { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ 185ca8dc34eSMandar Joshi { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 */ 1867cdd8d73SMathieu Bouffard { USB_ID(0x041e, 0x30df), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ 1873dc8523fSDmitry M. Fedin { USB_ID(0x041e, 0x3237), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ 188fec90088SMirko Dietrich { USB_ID(0x041e, 0x3263), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ 1897b1eda22SDaniel Mack { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ 1907b1eda22SDaniel Mack }; 1917b1eda22SDaniel Mack 1927b1eda22SDaniel Mack static void snd_usb_soundblaster_remote_complete(struct urb *urb) 1937b1eda22SDaniel Mack { 1947b1eda22SDaniel Mack struct usb_mixer_interface *mixer = urb->context; 1957b1eda22SDaniel Mack const struct rc_config *rc = mixer->rc_cfg; 1967b1eda22SDaniel Mack u32 code; 1977b1eda22SDaniel Mack 1987b1eda22SDaniel Mack if (urb->status < 0 || urb->actual_length < rc->min_packet_length) 1997b1eda22SDaniel Mack return; 2007b1eda22SDaniel Mack 2017b1eda22SDaniel Mack code = mixer->rc_buffer[rc->offset]; 2027b1eda22SDaniel Mack if (rc->length == 2) 2037b1eda22SDaniel Mack code |= mixer->rc_buffer[rc->offset + 1] << 8; 2047b1eda22SDaniel Mack 2057b1eda22SDaniel Mack /* the Mute button actually changes the mixer control */ 2067b1eda22SDaniel Mack if (code == rc->mute_code) 2077b1eda22SDaniel Mack snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id); 2087b1eda22SDaniel Mack mixer->rc_code = code; 2097b1eda22SDaniel Mack wmb(); 2107b1eda22SDaniel Mack wake_up(&mixer->rc_waitq); 2117b1eda22SDaniel Mack } 2127b1eda22SDaniel Mack 2137b1eda22SDaniel Mack static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf, 2147b1eda22SDaniel Mack long count, loff_t *offset) 2157b1eda22SDaniel Mack { 2167b1eda22SDaniel Mack struct usb_mixer_interface *mixer = hw->private_data; 2177b1eda22SDaniel Mack int err; 2187b1eda22SDaniel Mack u32 rc_code; 2197b1eda22SDaniel Mack 2207b1eda22SDaniel Mack if (count != 1 && count != 4) 2217b1eda22SDaniel Mack return -EINVAL; 2227b1eda22SDaniel Mack err = wait_event_interruptible(mixer->rc_waitq, 2237b1eda22SDaniel Mack (rc_code = xchg(&mixer->rc_code, 0)) != 0); 2247b1eda22SDaniel Mack if (err == 0) { 2257b1eda22SDaniel Mack if (count == 1) 2267b1eda22SDaniel Mack err = put_user(rc_code, buf); 2277b1eda22SDaniel Mack else 2287b1eda22SDaniel Mack err = put_user(rc_code, (u32 __user *)buf); 2297b1eda22SDaniel Mack } 2307b1eda22SDaniel Mack return err < 0 ? err : count; 2317b1eda22SDaniel Mack } 2327b1eda22SDaniel Mack 233680ef72aSAl Viro static __poll_t snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *file, 2347b1eda22SDaniel Mack poll_table *wait) 2357b1eda22SDaniel Mack { 2367b1eda22SDaniel Mack struct usb_mixer_interface *mixer = hw->private_data; 2377b1eda22SDaniel Mack 2387b1eda22SDaniel Mack poll_wait(file, &mixer->rc_waitq, wait); 239a9a08845SLinus Torvalds return mixer->rc_code ? EPOLLIN | EPOLLRDNORM : 0; 2407b1eda22SDaniel Mack } 2417b1eda22SDaniel Mack 2427b1eda22SDaniel Mack static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) 2437b1eda22SDaniel Mack { 2447b1eda22SDaniel Mack struct snd_hwdep *hwdep; 2457b1eda22SDaniel Mack int err, len, i; 2467b1eda22SDaniel Mack 2477b1eda22SDaniel Mack for (i = 0; i < ARRAY_SIZE(rc_configs); ++i) 2487b1eda22SDaniel Mack if (rc_configs[i].usb_id == mixer->chip->usb_id) 2497b1eda22SDaniel Mack break; 2507b1eda22SDaniel Mack if (i >= ARRAY_SIZE(rc_configs)) 2517b1eda22SDaniel Mack return 0; 2527b1eda22SDaniel Mack mixer->rc_cfg = &rc_configs[i]; 2537b1eda22SDaniel Mack 2547b1eda22SDaniel Mack len = mixer->rc_cfg->packet_length; 2557b1eda22SDaniel Mack 2567b1eda22SDaniel Mack init_waitqueue_head(&mixer->rc_waitq); 2577b1eda22SDaniel Mack err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep); 2587b1eda22SDaniel Mack if (err < 0) 2597b1eda22SDaniel Mack return err; 2607b1eda22SDaniel Mack snprintf(hwdep->name, sizeof(hwdep->name), 2617b1eda22SDaniel Mack "%s remote control", mixer->chip->card->shortname); 2627b1eda22SDaniel Mack hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC; 2637b1eda22SDaniel Mack hwdep->private_data = mixer; 2647b1eda22SDaniel Mack hwdep->ops.read = snd_usb_sbrc_hwdep_read; 2657b1eda22SDaniel Mack hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; 2667b1eda22SDaniel Mack hwdep->exclusive = 1; 2677b1eda22SDaniel Mack 2687b1eda22SDaniel Mack mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); 2697b1eda22SDaniel Mack if (!mixer->rc_urb) 2707b1eda22SDaniel Mack return -ENOMEM; 2717b1eda22SDaniel Mack mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL); 2727b1eda22SDaniel Mack if (!mixer->rc_setup_packet) { 2737b1eda22SDaniel Mack usb_free_urb(mixer->rc_urb); 2747b1eda22SDaniel Mack mixer->rc_urb = NULL; 2757b1eda22SDaniel Mack return -ENOMEM; 2767b1eda22SDaniel Mack } 2777b1eda22SDaniel Mack mixer->rc_setup_packet->bRequestType = 2787b1eda22SDaniel Mack USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; 2797b1eda22SDaniel Mack mixer->rc_setup_packet->bRequest = UAC_GET_MEM; 2807b1eda22SDaniel Mack mixer->rc_setup_packet->wValue = cpu_to_le16(0); 2817b1eda22SDaniel Mack mixer->rc_setup_packet->wIndex = cpu_to_le16(0); 2827b1eda22SDaniel Mack mixer->rc_setup_packet->wLength = cpu_to_le16(len); 2837b1eda22SDaniel Mack usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev, 2847b1eda22SDaniel Mack usb_rcvctrlpipe(mixer->chip->dev, 0), 2857b1eda22SDaniel Mack (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len, 2867b1eda22SDaniel Mack snd_usb_soundblaster_remote_complete, mixer); 2877b1eda22SDaniel Mack return 0; 2887b1eda22SDaniel Mack } 2897b1eda22SDaniel Mack 2907b1eda22SDaniel Mack #define snd_audigy2nx_led_info snd_ctl_boolean_mono_info 2917b1eda22SDaniel Mack 2927b1eda22SDaniel Mack static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2937b1eda22SDaniel Mack { 2949cf3689bSTakashi Iwai ucontrol->value.integer.value[0] = kcontrol->private_value >> 8; 2957b1eda22SDaniel Mack return 0; 2967b1eda22SDaniel Mack } 2977b1eda22SDaniel Mack 2989cf3689bSTakashi Iwai static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer, 2999cf3689bSTakashi Iwai int value, int index) 3007b1eda22SDaniel Mack { 3019cf3689bSTakashi Iwai struct snd_usb_audio *chip = mixer->chip; 3029cf3689bSTakashi Iwai int err; 3037b1eda22SDaniel Mack 30447ab1545STakashi Iwai err = snd_usb_lock_shutdown(chip); 30547ab1545STakashi Iwai if (err < 0) 30647ab1545STakashi Iwai return err; 30747ab1545STakashi Iwai 3089cf3689bSTakashi Iwai if (chip->usb_id == USB_ID(0x041e, 0x3042)) 3099cf3689bSTakashi Iwai err = snd_usb_ctl_msg(chip->dev, 3109cf3689bSTakashi Iwai usb_sndctrlpipe(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 */ 3149cf3689bSTakashi Iwai if (chip->usb_id == USB_ID(0x041e, 0x30df)) 3159cf3689bSTakashi Iwai err = snd_usb_ctl_msg(chip->dev, 3169cf3689bSTakashi Iwai usb_sndctrlpipe(chip->dev, 0), 0x24, 3177cdd8d73SMathieu Bouffard USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 31817d900c4SClemens Ladisch !value, 0, NULL, 0); 319ca8dc34eSMandar Joshi else 3209cf3689bSTakashi Iwai err = snd_usb_ctl_msg(chip->dev, 3219cf3689bSTakashi Iwai usb_sndctrlpipe(chip->dev, 0), 0x24, 3227b1eda22SDaniel Mack USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 32317d900c4SClemens Ladisch value, index + 2, NULL, 0); 32447ab1545STakashi Iwai snd_usb_unlock_shutdown(chip); 3257b1eda22SDaniel Mack return err; 3267b1eda22SDaniel Mack } 3277b1eda22SDaniel Mack 3289cf3689bSTakashi Iwai static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, 3299cf3689bSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 3307b1eda22SDaniel Mack { 3319cf3689bSTakashi Iwai struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 3329cf3689bSTakashi Iwai struct usb_mixer_interface *mixer = list->mixer; 3339cf3689bSTakashi Iwai int index = kcontrol->private_value & 0xff; 334e87359efSDan Carpenter unsigned int value = ucontrol->value.integer.value[0]; 3359cf3689bSTakashi Iwai int old_value = kcontrol->private_value >> 8; 3369cf3689bSTakashi Iwai int err; 3379cf3689bSTakashi Iwai 3389cf3689bSTakashi Iwai if (value > 1) 3399cf3689bSTakashi Iwai return -EINVAL; 3409cf3689bSTakashi Iwai if (value == old_value) 3419cf3689bSTakashi Iwai return 0; 3429cf3689bSTakashi Iwai kcontrol->private_value = (value << 8) | index; 3439cf3689bSTakashi Iwai err = snd_audigy2nx_led_update(mixer, value, index); 3449cf3689bSTakashi Iwai return err < 0 ? err : 1; 3459cf3689bSTakashi Iwai } 3469cf3689bSTakashi Iwai 3479cf3689bSTakashi Iwai static int snd_audigy2nx_led_resume(struct usb_mixer_elem_list *list) 3489cf3689bSTakashi Iwai { 3499cf3689bSTakashi Iwai int priv_value = list->kctl->private_value; 3509cf3689bSTakashi Iwai 3519cf3689bSTakashi Iwai return snd_audigy2nx_led_update(list->mixer, priv_value >> 8, 3529cf3689bSTakashi Iwai priv_value & 0xff); 3539cf3689bSTakashi Iwai } 3549cf3689bSTakashi Iwai 3559cf3689bSTakashi Iwai /* name and private_value are set dynamically */ 356905e46acSBhumika Goyal static const struct snd_kcontrol_new snd_audigy2nx_control = { 3577b1eda22SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3587b1eda22SDaniel Mack .info = snd_audigy2nx_led_info, 3597b1eda22SDaniel Mack .get = snd_audigy2nx_led_get, 3607b1eda22SDaniel Mack .put = snd_audigy2nx_led_put, 3619cf3689bSTakashi Iwai }; 3629cf3689bSTakashi Iwai 3639cf3689bSTakashi Iwai static const char * const snd_audigy2nx_led_names[] = { 3649cf3689bSTakashi Iwai "CMSS LED Switch", 3659cf3689bSTakashi Iwai "Power LED Switch", 3669cf3689bSTakashi Iwai "Dolby Digital LED Switch", 3677b1eda22SDaniel Mack }; 3687b1eda22SDaniel Mack 3697b1eda22SDaniel Mack static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) 3707b1eda22SDaniel Mack { 3717b1eda22SDaniel Mack int i, err; 3727b1eda22SDaniel Mack 3739cf3689bSTakashi Iwai for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_led_names); ++i) { 3749cf3689bSTakashi Iwai struct snd_kcontrol_new knew; 3759cf3689bSTakashi Iwai 376ca8dc34eSMandar Joshi /* USB X-Fi S51 doesn't have a CMSS LED */ 377ca8dc34eSMandar Joshi if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0) 378ca8dc34eSMandar Joshi continue; 3797cdd8d73SMathieu Bouffard /* USB X-Fi S51 Pro doesn't have one either */ 3807cdd8d73SMathieu Bouffard if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0) 3817cdd8d73SMathieu Bouffard continue; 3827b1eda22SDaniel Mack if (i > 1 && /* Live24ext has 2 LEDs only */ 3837b1eda22SDaniel Mack (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 384ca8dc34eSMandar Joshi mixer->chip->usb_id == USB_ID(0x041e, 0x3042) || 3857cdd8d73SMathieu Bouffard mixer->chip->usb_id == USB_ID(0x041e, 0x30df) || 3867b1eda22SDaniel Mack mixer->chip->usb_id == USB_ID(0x041e, 0x3048))) 3877b1eda22SDaniel Mack break; 3889cf3689bSTakashi Iwai 3899cf3689bSTakashi Iwai knew = snd_audigy2nx_control; 3909cf3689bSTakashi Iwai knew.name = snd_audigy2nx_led_names[i]; 3919cf3689bSTakashi Iwai knew.private_value = (1 << 8) | i; /* LED on as default */ 3929cf3689bSTakashi Iwai err = add_single_ctl_with_resume(mixer, 0, 3939cf3689bSTakashi Iwai snd_audigy2nx_led_resume, 3949cf3689bSTakashi Iwai &knew, NULL); 3957b1eda22SDaniel Mack if (err < 0) 3967b1eda22SDaniel Mack return err; 3977b1eda22SDaniel Mack } 3987b1eda22SDaniel Mack return 0; 3997b1eda22SDaniel Mack } 4007b1eda22SDaniel Mack 4017b1eda22SDaniel Mack static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, 4027b1eda22SDaniel Mack struct snd_info_buffer *buffer) 4037b1eda22SDaniel Mack { 4047b1eda22SDaniel Mack static const struct sb_jack { 4057b1eda22SDaniel Mack int unitid; 4067b1eda22SDaniel Mack const char *name; 4077b1eda22SDaniel Mack } jacks_audigy2nx[] = { 4087b1eda22SDaniel Mack {4, "dig in "}, 4097b1eda22SDaniel Mack {7, "line in"}, 4107b1eda22SDaniel Mack {19, "spk out"}, 4117b1eda22SDaniel Mack {20, "hph out"}, 4127b1eda22SDaniel Mack {-1, NULL} 4137b1eda22SDaniel Mack }, jacks_live24ext[] = { 4147b1eda22SDaniel Mack {4, "line in"}, /* &1=Line, &2=Mic*/ 4157b1eda22SDaniel Mack {3, "hph out"}, /* headphones */ 4167b1eda22SDaniel Mack {0, "RC "}, /* last command, 6 bytes see rc_config above */ 4177b1eda22SDaniel Mack {-1, NULL} 4187b1eda22SDaniel Mack }; 4197b1eda22SDaniel Mack const struct sb_jack *jacks; 4207b1eda22SDaniel Mack struct usb_mixer_interface *mixer = entry->private_data; 4217b1eda22SDaniel Mack int i, err; 4227b1eda22SDaniel Mack u8 buf[3]; 4237b1eda22SDaniel Mack 4247b1eda22SDaniel Mack snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); 4257b1eda22SDaniel Mack if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) 4267b1eda22SDaniel Mack jacks = jacks_audigy2nx; 4277b1eda22SDaniel Mack else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 4287b1eda22SDaniel Mack mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) 4297b1eda22SDaniel Mack jacks = jacks_live24ext; 4307b1eda22SDaniel Mack else 4317b1eda22SDaniel Mack return; 4327b1eda22SDaniel Mack 4337b1eda22SDaniel Mack for (i = 0; jacks[i].name; ++i) { 4347b1eda22SDaniel Mack snd_iprintf(buffer, "%s: ", jacks[i].name); 43547ab1545STakashi Iwai err = snd_usb_lock_shutdown(mixer->chip); 43647ab1545STakashi Iwai if (err < 0) 43747ab1545STakashi Iwai return; 4387b1eda22SDaniel Mack err = snd_usb_ctl_msg(mixer->chip->dev, 4397b1eda22SDaniel Mack usb_rcvctrlpipe(mixer->chip->dev, 0), 4407b1eda22SDaniel Mack UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | 4417b1eda22SDaniel Mack USB_RECIP_INTERFACE, 0, 44217d900c4SClemens Ladisch jacks[i].unitid << 8, buf, 3); 44347ab1545STakashi Iwai snd_usb_unlock_shutdown(mixer->chip); 4447b1eda22SDaniel Mack if (err == 3 && (buf[0] == 3 || buf[0] == 6)) 4457b1eda22SDaniel Mack snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); 4467b1eda22SDaniel Mack else 4477b1eda22SDaniel Mack snd_iprintf(buffer, "?\n"); 4487b1eda22SDaniel Mack } 4497b1eda22SDaniel Mack } 4507b1eda22SDaniel Mack 45144832a71SVasily Khoruzhick /* EMU0204 */ 45244832a71SVasily Khoruzhick static int snd_emu0204_ch_switch_info(struct snd_kcontrol *kcontrol, 45344832a71SVasily Khoruzhick struct snd_ctl_elem_info *uinfo) 45444832a71SVasily Khoruzhick { 4557bbd03e0STakashi Iwai static const char * const texts[2] = {"1/2", "3/4"}; 45644832a71SVasily Khoruzhick 4577bbd03e0STakashi Iwai return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 45844832a71SVasily Khoruzhick } 45944832a71SVasily Khoruzhick 46044832a71SVasily Khoruzhick static int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol, 46144832a71SVasily Khoruzhick struct snd_ctl_elem_value *ucontrol) 46244832a71SVasily Khoruzhick { 46344832a71SVasily Khoruzhick ucontrol->value.enumerated.item[0] = kcontrol->private_value; 46444832a71SVasily Khoruzhick return 0; 46544832a71SVasily Khoruzhick } 46644832a71SVasily Khoruzhick 4675f503ee9STakashi Iwai static int snd_emu0204_ch_switch_update(struct usb_mixer_interface *mixer, 4685f503ee9STakashi Iwai int value) 46944832a71SVasily Khoruzhick { 4705f503ee9STakashi Iwai struct snd_usb_audio *chip = mixer->chip; 4715f503ee9STakashi Iwai int err; 47244832a71SVasily Khoruzhick unsigned char buf[2]; 47344832a71SVasily Khoruzhick 47447ab1545STakashi Iwai err = snd_usb_lock_shutdown(chip); 47547ab1545STakashi Iwai if (err < 0) 47647ab1545STakashi Iwai return err; 4775f503ee9STakashi Iwai 4785f503ee9STakashi Iwai buf[0] = 0x01; 4795f503ee9STakashi Iwai buf[1] = value ? 0x02 : 0x01; 4805f503ee9STakashi Iwai err = snd_usb_ctl_msg(chip->dev, 4815f503ee9STakashi Iwai usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, 48244832a71SVasily Khoruzhick USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 48344832a71SVasily Khoruzhick 0x0400, 0x0e00, buf, 2); 48447ab1545STakashi Iwai snd_usb_unlock_shutdown(chip); 48544832a71SVasily Khoruzhick return err; 48644832a71SVasily Khoruzhick } 48744832a71SVasily Khoruzhick 4885f503ee9STakashi Iwai static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol, 4895f503ee9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 49044832a71SVasily Khoruzhick { 4915f503ee9STakashi Iwai struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 4925f503ee9STakashi Iwai struct usb_mixer_interface *mixer = list->mixer; 4935f503ee9STakashi Iwai unsigned int value = ucontrol->value.enumerated.item[0]; 4945f503ee9STakashi Iwai int err; 4955f503ee9STakashi Iwai 4965f503ee9STakashi Iwai if (value > 1) 4975f503ee9STakashi Iwai return -EINVAL; 4985f503ee9STakashi Iwai 4995f503ee9STakashi Iwai if (value == kcontrol->private_value) 5005f503ee9STakashi Iwai return 0; 5015f503ee9STakashi Iwai 5025f503ee9STakashi Iwai kcontrol->private_value = value; 5035f503ee9STakashi Iwai err = snd_emu0204_ch_switch_update(mixer, value); 5045f503ee9STakashi Iwai return err < 0 ? err : 1; 5055f503ee9STakashi Iwai } 5065f503ee9STakashi Iwai 5075f503ee9STakashi Iwai static int snd_emu0204_ch_switch_resume(struct usb_mixer_elem_list *list) 5085f503ee9STakashi Iwai { 5095f503ee9STakashi Iwai return snd_emu0204_ch_switch_update(list->mixer, 5105f503ee9STakashi Iwai list->kctl->private_value); 5115f503ee9STakashi Iwai } 5125f503ee9STakashi Iwai 513195727e8STakashi Iwai static const struct snd_kcontrol_new snd_emu0204_control = { 51444832a71SVasily Khoruzhick .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 51544832a71SVasily Khoruzhick .name = "Front Jack Channels", 51644832a71SVasily Khoruzhick .info = snd_emu0204_ch_switch_info, 51744832a71SVasily Khoruzhick .get = snd_emu0204_ch_switch_get, 51844832a71SVasily Khoruzhick .put = snd_emu0204_ch_switch_put, 51944832a71SVasily Khoruzhick .private_value = 0, 52044832a71SVasily Khoruzhick }; 52144832a71SVasily Khoruzhick 52244832a71SVasily Khoruzhick static int snd_emu0204_controls_create(struct usb_mixer_interface *mixer) 52344832a71SVasily Khoruzhick { 5245f503ee9STakashi Iwai return add_single_ctl_with_resume(mixer, 0, 5255f503ee9STakashi Iwai snd_emu0204_ch_switch_resume, 5265f503ee9STakashi Iwai &snd_emu0204_control, NULL); 52744832a71SVasily Khoruzhick } 52844832a71SVasily Khoruzhick 5291d31affbSDenis Washington /* ASUS Xonar U1 / U3 controls */ 5301d31affbSDenis Washington 5317b1eda22SDaniel Mack static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, 5327b1eda22SDaniel Mack struct snd_ctl_elem_value *ucontrol) 5337b1eda22SDaniel Mack { 5342bfb14c3STakashi Iwai ucontrol->value.integer.value[0] = !!(kcontrol->private_value & 0x02); 5357b1eda22SDaniel Mack return 0; 5367b1eda22SDaniel Mack } 5377b1eda22SDaniel Mack 5382bfb14c3STakashi Iwai static int snd_xonar_u1_switch_update(struct usb_mixer_interface *mixer, 5392bfb14c3STakashi Iwai unsigned char status) 5402bfb14c3STakashi Iwai { 5412bfb14c3STakashi Iwai struct snd_usb_audio *chip = mixer->chip; 5422bfb14c3STakashi Iwai int err; 5432bfb14c3STakashi Iwai 54447ab1545STakashi Iwai err = snd_usb_lock_shutdown(chip); 54547ab1545STakashi Iwai if (err < 0) 54647ab1545STakashi Iwai return err; 5472bfb14c3STakashi Iwai err = snd_usb_ctl_msg(chip->dev, 5482bfb14c3STakashi Iwai usb_sndctrlpipe(chip->dev, 0), 0x08, 5492bfb14c3STakashi Iwai USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 5502bfb14c3STakashi Iwai 50, 0, &status, 1); 55147ab1545STakashi Iwai snd_usb_unlock_shutdown(chip); 5522bfb14c3STakashi Iwai return err; 5532bfb14c3STakashi Iwai } 5542bfb14c3STakashi Iwai 5557b1eda22SDaniel Mack static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, 5567b1eda22SDaniel Mack struct snd_ctl_elem_value *ucontrol) 5577b1eda22SDaniel Mack { 5582bfb14c3STakashi Iwai struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 5597b1eda22SDaniel Mack u8 old_status, new_status; 5602bfb14c3STakashi Iwai int err; 5617b1eda22SDaniel Mack 5622bfb14c3STakashi Iwai old_status = kcontrol->private_value; 5637b1eda22SDaniel Mack if (ucontrol->value.integer.value[0]) 5647b1eda22SDaniel Mack new_status = old_status | 0x02; 5657b1eda22SDaniel Mack else 5667b1eda22SDaniel Mack new_status = old_status & ~0x02; 5672bfb14c3STakashi Iwai if (new_status == old_status) 5682bfb14c3STakashi Iwai return 0; 5692bfb14c3STakashi Iwai 5702bfb14c3STakashi Iwai kcontrol->private_value = new_status; 5712bfb14c3STakashi Iwai err = snd_xonar_u1_switch_update(list->mixer, new_status); 5722bfb14c3STakashi Iwai return err < 0 ? err : 1; 5732bfb14c3STakashi Iwai } 5742bfb14c3STakashi Iwai 5752bfb14c3STakashi Iwai static int snd_xonar_u1_switch_resume(struct usb_mixer_elem_list *list) 5762bfb14c3STakashi Iwai { 5772bfb14c3STakashi Iwai return snd_xonar_u1_switch_update(list->mixer, 5782bfb14c3STakashi Iwai list->kctl->private_value); 5797b1eda22SDaniel Mack } 5807b1eda22SDaniel Mack 581195727e8STakashi Iwai static const struct snd_kcontrol_new snd_xonar_u1_output_switch = { 5827b1eda22SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5837b1eda22SDaniel Mack .name = "Digital Playback Switch", 5847b1eda22SDaniel Mack .info = snd_ctl_boolean_mono_info, 5857b1eda22SDaniel Mack .get = snd_xonar_u1_switch_get, 5867b1eda22SDaniel Mack .put = snd_xonar_u1_switch_put, 5872bfb14c3STakashi Iwai .private_value = 0x05, 5887b1eda22SDaniel Mack }; 5897b1eda22SDaniel Mack 5907b1eda22SDaniel Mack static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) 5917b1eda22SDaniel Mack { 5922bfb14c3STakashi Iwai return add_single_ctl_with_resume(mixer, 0, 5932bfb14c3STakashi Iwai snd_xonar_u1_switch_resume, 5942bfb14c3STakashi Iwai &snd_xonar_u1_output_switch, NULL); 5957b1eda22SDaniel Mack } 5967b1eda22SDaniel Mack 597d497a82fSDamien Zammit /* Digidesign Mbox 1 clock source switch (internal/spdif) */ 598d497a82fSDamien Zammit 599d497a82fSDamien Zammit static int snd_mbox1_switch_get(struct snd_kcontrol *kctl, 600d497a82fSDamien Zammit struct snd_ctl_elem_value *ucontrol) 601d497a82fSDamien Zammit { 602d497a82fSDamien Zammit ucontrol->value.enumerated.item[0] = kctl->private_value; 603d497a82fSDamien Zammit return 0; 604d497a82fSDamien Zammit } 605d497a82fSDamien Zammit 60625a9a4f9STakashi Iwai static int snd_mbox1_switch_update(struct usb_mixer_interface *mixer, int val) 607d497a82fSDamien Zammit { 60825a9a4f9STakashi Iwai struct snd_usb_audio *chip = mixer->chip; 609d497a82fSDamien Zammit int err; 610d497a82fSDamien Zammit unsigned char buff[3]; 611d497a82fSDamien Zammit 61247ab1545STakashi Iwai err = snd_usb_lock_shutdown(chip); 61347ab1545STakashi Iwai if (err < 0) 61447ab1545STakashi Iwai return err; 615d497a82fSDamien Zammit 616d497a82fSDamien Zammit /* Prepare for magic command to toggle clock source */ 617d497a82fSDamien Zammit err = snd_usb_ctl_msg(chip->dev, 618d497a82fSDamien Zammit usb_rcvctrlpipe(chip->dev, 0), 0x81, 619d497a82fSDamien Zammit USB_DIR_IN | 620d497a82fSDamien Zammit USB_TYPE_CLASS | 621d497a82fSDamien Zammit USB_RECIP_INTERFACE, 0x00, 0x500, buff, 1); 622d497a82fSDamien Zammit if (err < 0) 623d497a82fSDamien Zammit goto err; 624d497a82fSDamien Zammit err = snd_usb_ctl_msg(chip->dev, 625d497a82fSDamien Zammit usb_rcvctrlpipe(chip->dev, 0), 0x81, 626d497a82fSDamien Zammit USB_DIR_IN | 627d497a82fSDamien Zammit USB_TYPE_CLASS | 628d497a82fSDamien Zammit USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3); 629d497a82fSDamien Zammit if (err < 0) 630d497a82fSDamien Zammit goto err; 631d497a82fSDamien Zammit 632d497a82fSDamien Zammit /* 2 possibilities: Internal -> send sample rate 633d497a82fSDamien Zammit * S/PDIF sync -> send zeroes 634d497a82fSDamien Zammit * NB: Sample rate locked to 48kHz on purpose to 635d497a82fSDamien Zammit * prevent user from resetting the sample rate 636d497a82fSDamien Zammit * while S/PDIF sync is enabled and confusing 637d497a82fSDamien Zammit * this configuration. 638d497a82fSDamien Zammit */ 63925a9a4f9STakashi Iwai if (val == 0) { 640d497a82fSDamien Zammit buff[0] = 0x80; 641d497a82fSDamien Zammit buff[1] = 0xbb; 642d497a82fSDamien Zammit buff[2] = 0x00; 643d497a82fSDamien Zammit } else { 644d497a82fSDamien Zammit buff[0] = buff[1] = buff[2] = 0x00; 645d497a82fSDamien Zammit } 646d497a82fSDamien Zammit 647d497a82fSDamien Zammit /* Send the magic command to toggle the clock source */ 648d497a82fSDamien Zammit err = snd_usb_ctl_msg(chip->dev, 649d497a82fSDamien Zammit usb_sndctrlpipe(chip->dev, 0), 0x1, 650d497a82fSDamien Zammit USB_TYPE_CLASS | 651d497a82fSDamien Zammit USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3); 652d497a82fSDamien Zammit if (err < 0) 653d497a82fSDamien Zammit goto err; 654d497a82fSDamien Zammit err = snd_usb_ctl_msg(chip->dev, 655d497a82fSDamien Zammit usb_rcvctrlpipe(chip->dev, 0), 0x81, 656d497a82fSDamien Zammit USB_DIR_IN | 657d497a82fSDamien Zammit USB_TYPE_CLASS | 658d497a82fSDamien Zammit USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3); 659d497a82fSDamien Zammit if (err < 0) 660d497a82fSDamien Zammit goto err; 661d497a82fSDamien Zammit err = snd_usb_ctl_msg(chip->dev, 662d497a82fSDamien Zammit usb_rcvctrlpipe(chip->dev, 0), 0x81, 663d497a82fSDamien Zammit USB_DIR_IN | 664d497a82fSDamien Zammit USB_TYPE_CLASS | 665d497a82fSDamien Zammit USB_RECIP_ENDPOINT, 0x100, 0x2, buff, 3); 666d497a82fSDamien Zammit if (err < 0) 667d497a82fSDamien Zammit goto err; 668d497a82fSDamien Zammit 669d497a82fSDamien Zammit err: 67047ab1545STakashi Iwai snd_usb_unlock_shutdown(chip); 67125a9a4f9STakashi Iwai return err; 67225a9a4f9STakashi Iwai } 67325a9a4f9STakashi Iwai 67425a9a4f9STakashi Iwai static int snd_mbox1_switch_put(struct snd_kcontrol *kctl, 67525a9a4f9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 67625a9a4f9STakashi Iwai { 67725a9a4f9STakashi Iwai struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); 67825a9a4f9STakashi Iwai struct usb_mixer_interface *mixer = list->mixer; 67925a9a4f9STakashi Iwai int err; 68025a9a4f9STakashi Iwai bool cur_val, new_val; 68125a9a4f9STakashi Iwai 68225a9a4f9STakashi Iwai cur_val = kctl->private_value; 68325a9a4f9STakashi Iwai new_val = ucontrol->value.enumerated.item[0]; 68425a9a4f9STakashi Iwai if (cur_val == new_val) 68525a9a4f9STakashi Iwai return 0; 68625a9a4f9STakashi Iwai 68725a9a4f9STakashi Iwai kctl->private_value = new_val; 68825a9a4f9STakashi Iwai err = snd_mbox1_switch_update(mixer, new_val); 689d497a82fSDamien Zammit return err < 0 ? err : 1; 690d497a82fSDamien Zammit } 691d497a82fSDamien Zammit 692d497a82fSDamien Zammit static int snd_mbox1_switch_info(struct snd_kcontrol *kcontrol, 693d497a82fSDamien Zammit struct snd_ctl_elem_info *uinfo) 694d497a82fSDamien Zammit { 695d497a82fSDamien Zammit static const char *const texts[2] = { 696d497a82fSDamien Zammit "Internal", 697d497a82fSDamien Zammit "S/PDIF" 698d497a82fSDamien Zammit }; 699d497a82fSDamien Zammit 700d497a82fSDamien Zammit return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 701d497a82fSDamien Zammit } 702d497a82fSDamien Zammit 70325a9a4f9STakashi Iwai static int snd_mbox1_switch_resume(struct usb_mixer_elem_list *list) 70425a9a4f9STakashi Iwai { 70525a9a4f9STakashi Iwai return snd_mbox1_switch_update(list->mixer, list->kctl->private_value); 70625a9a4f9STakashi Iwai } 70725a9a4f9STakashi Iwai 708195727e8STakashi Iwai static const struct snd_kcontrol_new snd_mbox1_switch = { 709d497a82fSDamien Zammit .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 710d497a82fSDamien Zammit .name = "Clock Source", 711d497a82fSDamien Zammit .index = 0, 712d497a82fSDamien Zammit .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 713d497a82fSDamien Zammit .info = snd_mbox1_switch_info, 714d497a82fSDamien Zammit .get = snd_mbox1_switch_get, 715d497a82fSDamien Zammit .put = snd_mbox1_switch_put, 716d497a82fSDamien Zammit .private_value = 0 717d497a82fSDamien Zammit }; 718d497a82fSDamien Zammit 719d497a82fSDamien Zammit static int snd_mbox1_create_sync_switch(struct usb_mixer_interface *mixer) 720d497a82fSDamien Zammit { 72125a9a4f9STakashi Iwai return add_single_ctl_with_resume(mixer, 0, 72225a9a4f9STakashi Iwai snd_mbox1_switch_resume, 72325a9a4f9STakashi Iwai &snd_mbox1_switch, NULL); 724d497a82fSDamien Zammit } 725d497a82fSDamien Zammit 72654a8c500SDaniel Mack /* Native Instruments device quirks */ 72754a8c500SDaniel Mack 72854a8c500SDaniel Mack #define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex)) 72954a8c500SDaniel Mack 730da6d2769STakashi Iwai static int snd_ni_control_init_val(struct usb_mixer_interface *mixer, 731da6d2769STakashi Iwai struct snd_kcontrol *kctl) 732da6d2769STakashi Iwai { 733da6d2769STakashi Iwai struct usb_device *dev = mixer->chip->dev; 734da6d2769STakashi Iwai unsigned int pval = kctl->private_value; 735da6d2769STakashi Iwai u8 value; 736da6d2769STakashi Iwai int err; 737da6d2769STakashi Iwai 738da6d2769STakashi Iwai err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 739da6d2769STakashi Iwai (pval >> 16) & 0xff, 740da6d2769STakashi Iwai USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 741da6d2769STakashi Iwai 0, pval & 0xffff, &value, 1); 742da6d2769STakashi Iwai if (err < 0) { 743da6d2769STakashi Iwai dev_err(&dev->dev, 744da6d2769STakashi Iwai "unable to issue vendor read request (ret = %d)", err); 745da6d2769STakashi Iwai return err; 746da6d2769STakashi Iwai } 747da6d2769STakashi Iwai 7482acf5a3eSColin Ian King kctl->private_value |= ((unsigned int)value << 24); 749da6d2769STakashi Iwai return 0; 750da6d2769STakashi Iwai } 751da6d2769STakashi Iwai 75254a8c500SDaniel Mack static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, 75354a8c500SDaniel Mack struct snd_ctl_elem_value *ucontrol) 75454a8c500SDaniel Mack { 755da6d2769STakashi Iwai ucontrol->value.integer.value[0] = kcontrol->private_value >> 24; 756da6d2769STakashi Iwai return 0; 75754a8c500SDaniel Mack } 75854a8c500SDaniel Mack 759da6d2769STakashi Iwai static int snd_ni_update_cur_val(struct usb_mixer_elem_list *list) 760da6d2769STakashi Iwai { 761da6d2769STakashi Iwai struct snd_usb_audio *chip = list->mixer->chip; 762da6d2769STakashi Iwai unsigned int pval = list->kctl->private_value; 763da6d2769STakashi Iwai int err; 76454a8c500SDaniel Mack 76547ab1545STakashi Iwai err = snd_usb_lock_shutdown(chip); 76647ab1545STakashi Iwai if (err < 0) 76747ab1545STakashi Iwai return err; 768da6d2769STakashi Iwai err = usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), 769da6d2769STakashi Iwai (pval >> 16) & 0xff, 770da6d2769STakashi Iwai USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 771da6d2769STakashi Iwai pval >> 24, pval & 0xffff, NULL, 0, 1000); 77247ab1545STakashi Iwai snd_usb_unlock_shutdown(chip); 773da6d2769STakashi Iwai return err; 77454a8c500SDaniel Mack } 77554a8c500SDaniel Mack 77654a8c500SDaniel Mack static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, 77754a8c500SDaniel Mack struct snd_ctl_elem_value *ucontrol) 77854a8c500SDaniel Mack { 779da6d2769STakashi Iwai struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 780da6d2769STakashi Iwai u8 oldval = (kcontrol->private_value >> 24) & 0xff; 781da6d2769STakashi Iwai u8 newval = ucontrol->value.integer.value[0]; 782da6d2769STakashi Iwai int err; 78354a8c500SDaniel Mack 784da6d2769STakashi Iwai if (oldval == newval) 78554a8c500SDaniel Mack return 0; 786da6d2769STakashi Iwai 787da6d2769STakashi Iwai kcontrol->private_value &= ~(0xff << 24); 788c4a359a0STakashi Iwai kcontrol->private_value |= (unsigned int)newval << 24; 789da6d2769STakashi Iwai err = snd_ni_update_cur_val(list); 790da6d2769STakashi Iwai return err < 0 ? err : 1; 79154a8c500SDaniel Mack } 79254a8c500SDaniel Mack 793195727e8STakashi Iwai static const struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = { 79454a8c500SDaniel Mack { 79554a8c500SDaniel Mack .name = "Direct Thru Channel A", 79654a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x03), 79754a8c500SDaniel Mack }, 79854a8c500SDaniel Mack { 79954a8c500SDaniel Mack .name = "Direct Thru Channel B", 80054a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x05), 80154a8c500SDaniel Mack }, 80254a8c500SDaniel Mack { 80354a8c500SDaniel Mack .name = "Phono Input Channel A", 80454a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x03), 80554a8c500SDaniel Mack }, 80654a8c500SDaniel Mack { 80754a8c500SDaniel Mack .name = "Phono Input Channel B", 80854a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x05), 80954a8c500SDaniel Mack }, 81054a8c500SDaniel Mack }; 81154a8c500SDaniel Mack 812195727e8STakashi Iwai static const struct snd_kcontrol_new snd_nativeinstruments_ta10_mixers[] = { 81354a8c500SDaniel Mack { 81454a8c500SDaniel Mack .name = "Direct Thru Channel A", 81554a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x03), 81654a8c500SDaniel Mack }, 81754a8c500SDaniel Mack { 81854a8c500SDaniel Mack .name = "Direct Thru Channel B", 81954a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x05), 82054a8c500SDaniel Mack }, 82154a8c500SDaniel Mack { 82254a8c500SDaniel Mack .name = "Direct Thru Channel C", 82354a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x07), 82454a8c500SDaniel Mack }, 82554a8c500SDaniel Mack { 82654a8c500SDaniel Mack .name = "Direct Thru Channel D", 82754a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x01, 0x09), 82854a8c500SDaniel Mack }, 82954a8c500SDaniel Mack { 83054a8c500SDaniel Mack .name = "Phono Input Channel A", 83154a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x03), 83254a8c500SDaniel Mack }, 83354a8c500SDaniel Mack { 83454a8c500SDaniel Mack .name = "Phono Input Channel B", 83554a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x05), 83654a8c500SDaniel Mack }, 83754a8c500SDaniel Mack { 83854a8c500SDaniel Mack .name = "Phono Input Channel C", 83954a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x07), 84054a8c500SDaniel Mack }, 84154a8c500SDaniel Mack { 84254a8c500SDaniel Mack .name = "Phono Input Channel D", 84354a8c500SDaniel Mack .private_value = _MAKE_NI_CONTROL(0x02, 0x09), 84454a8c500SDaniel Mack }, 84554a8c500SDaniel Mack }; 84654a8c500SDaniel Mack 84754a8c500SDaniel Mack static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, 84854a8c500SDaniel Mack const struct snd_kcontrol_new *kc, 84954a8c500SDaniel Mack unsigned int count) 85054a8c500SDaniel Mack { 85154a8c500SDaniel Mack int i, err = 0; 85254a8c500SDaniel Mack struct snd_kcontrol_new template = { 85354a8c500SDaniel Mack .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 85454a8c500SDaniel Mack .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 85554a8c500SDaniel Mack .get = snd_nativeinstruments_control_get, 85654a8c500SDaniel Mack .put = snd_nativeinstruments_control_put, 85754a8c500SDaniel Mack .info = snd_ctl_boolean_mono_info, 85854a8c500SDaniel Mack }; 85954a8c500SDaniel Mack 86054a8c500SDaniel Mack for (i = 0; i < count; i++) { 861da6d2769STakashi Iwai struct usb_mixer_elem_list *list; 86254a8c500SDaniel Mack 86354a8c500SDaniel Mack template.name = kc[i].name; 86454a8c500SDaniel Mack template.private_value = kc[i].private_value; 86554a8c500SDaniel Mack 866da6d2769STakashi Iwai err = add_single_ctl_with_resume(mixer, 0, 867da6d2769STakashi Iwai snd_ni_update_cur_val, 868da6d2769STakashi Iwai &template, &list); 86954a8c500SDaniel Mack if (err < 0) 87054a8c500SDaniel Mack break; 871da6d2769STakashi Iwai snd_ni_control_init_val(mixer, list->kctl); 87254a8c500SDaniel Mack } 87354a8c500SDaniel Mack 87454a8c500SDaniel Mack return err; 87554a8c500SDaniel Mack } 87654a8c500SDaniel Mack 877d5a0bf6cSDaniel Mack /* M-Audio FastTrack Ultra quirks */ 878e9a25e04SMatt Gruskin /* FTU Effect switch (also used by C400/C600) */ 879d34bf148SFelix Homann static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, 880d34bf148SFelix Homann struct snd_ctl_elem_info *uinfo) 881d34bf148SFelix Homann { 8827bbd03e0STakashi Iwai static const char *const texts[8] = { 8837bbd03e0STakashi Iwai "Room 1", "Room 2", "Room 3", "Hall 1", 8847bbd03e0STakashi Iwai "Hall 2", "Plate", "Delay", "Echo" 885d34bf148SFelix Homann }; 886d34bf148SFelix Homann 8877bbd03e0STakashi Iwai return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 888d34bf148SFelix Homann } 889d34bf148SFelix Homann 8900b4e9cfcSTakashi Iwai static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer, 8910b4e9cfcSTakashi Iwai struct snd_kcontrol *kctl) 892d34bf148SFelix Homann { 8930b4e9cfcSTakashi Iwai struct usb_device *dev = mixer->chip->dev; 8940b4e9cfcSTakashi Iwai unsigned int pval = kctl->private_value; 895d34bf148SFelix Homann int err; 896d34bf148SFelix Homann unsigned char value[2]; 897d34bf148SFelix Homann 898d34bf148SFelix Homann value[0] = 0x00; 899d34bf148SFelix Homann value[1] = 0x00; 900d34bf148SFelix Homann 9010b4e9cfcSTakashi Iwai err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, 902d34bf148SFelix Homann USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 9030b4e9cfcSTakashi Iwai pval & 0xff00, 9040b4e9cfcSTakashi Iwai snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8), 9050b4e9cfcSTakashi Iwai value, 2); 906d34bf148SFelix Homann if (err < 0) 907d34bf148SFelix Homann return err; 908d34bf148SFelix Homann 9092acf5a3eSColin Ian King kctl->private_value |= (unsigned int)value[0] << 24; 910d34bf148SFelix Homann return 0; 911d34bf148SFelix Homann } 912d34bf148SFelix Homann 9130b4e9cfcSTakashi Iwai static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, 9140b4e9cfcSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 9150b4e9cfcSTakashi Iwai { 9160b4e9cfcSTakashi Iwai ucontrol->value.enumerated.item[0] = kctl->private_value >> 24; 9170b4e9cfcSTakashi Iwai return 0; 9180b4e9cfcSTakashi Iwai } 9190b4e9cfcSTakashi Iwai 9200b4e9cfcSTakashi Iwai static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list) 9210b4e9cfcSTakashi Iwai { 9220b4e9cfcSTakashi Iwai struct snd_usb_audio *chip = list->mixer->chip; 9230b4e9cfcSTakashi Iwai unsigned int pval = list->kctl->private_value; 9240b4e9cfcSTakashi Iwai unsigned char value[2]; 9250b4e9cfcSTakashi Iwai int err; 9260b4e9cfcSTakashi Iwai 9270b4e9cfcSTakashi Iwai value[0] = pval >> 24; 9280b4e9cfcSTakashi Iwai value[1] = 0; 9290b4e9cfcSTakashi Iwai 93047ab1545STakashi Iwai err = snd_usb_lock_shutdown(chip); 93147ab1545STakashi Iwai if (err < 0) 93247ab1545STakashi Iwai return err; 9330b4e9cfcSTakashi Iwai err = snd_usb_ctl_msg(chip->dev, 9340b4e9cfcSTakashi Iwai usb_sndctrlpipe(chip->dev, 0), 9350b4e9cfcSTakashi Iwai UAC_SET_CUR, 9360b4e9cfcSTakashi Iwai USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 9370b4e9cfcSTakashi Iwai pval & 0xff00, 9380b4e9cfcSTakashi Iwai snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8), 9390b4e9cfcSTakashi Iwai value, 2); 94047ab1545STakashi Iwai snd_usb_unlock_shutdown(chip); 9410b4e9cfcSTakashi Iwai return err; 9420b4e9cfcSTakashi Iwai } 9430b4e9cfcSTakashi Iwai 944d34bf148SFelix Homann static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, 945d34bf148SFelix Homann struct snd_ctl_elem_value *ucontrol) 946d34bf148SFelix Homann { 9470b4e9cfcSTakashi Iwai struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); 9480b4e9cfcSTakashi Iwai unsigned int pval = list->kctl->private_value; 9490b4e9cfcSTakashi Iwai int cur_val, err, new_val; 950d34bf148SFelix Homann 9510b4e9cfcSTakashi Iwai cur_val = pval >> 24; 952d34bf148SFelix Homann new_val = ucontrol->value.enumerated.item[0]; 9530b4e9cfcSTakashi Iwai if (cur_val == new_val) 9540b4e9cfcSTakashi Iwai return 0; 955d34bf148SFelix Homann 9560b4e9cfcSTakashi Iwai kctl->private_value &= ~(0xff << 24); 9570b4e9cfcSTakashi Iwai kctl->private_value |= new_val << 24; 9580b4e9cfcSTakashi Iwai err = snd_ftu_eff_switch_update(list); 9590b4e9cfcSTakashi Iwai return err < 0 ? err : 1; 9601a290581STakashi Iwai } 9611a290581STakashi Iwai 962d847ce0eSEldad Zack static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, 963d847ce0eSEldad Zack int validx, int bUnitID) 964d34bf148SFelix Homann { 965d34bf148SFelix Homann static struct snd_kcontrol_new template = { 966d34bf148SFelix Homann .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 967d34bf148SFelix Homann .name = "Effect Program Switch", 968d34bf148SFelix Homann .index = 0, 969d34bf148SFelix Homann .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 970d34bf148SFelix Homann .info = snd_ftu_eff_switch_info, 971d34bf148SFelix Homann .get = snd_ftu_eff_switch_get, 972d34bf148SFelix Homann .put = snd_ftu_eff_switch_put 973d34bf148SFelix Homann }; 9740b4e9cfcSTakashi Iwai struct usb_mixer_elem_list *list; 975d34bf148SFelix Homann int err; 976d34bf148SFelix Homann 9770b4e9cfcSTakashi Iwai err = add_single_ctl_with_resume(mixer, bUnitID, 9780b4e9cfcSTakashi Iwai snd_ftu_eff_switch_update, 9790b4e9cfcSTakashi Iwai &template, &list); 980d34bf148SFelix Homann if (err < 0) 981d34bf148SFelix Homann return err; 9820b4e9cfcSTakashi Iwai list->kctl->private_value = (validx << 8) | bUnitID; 9830b4e9cfcSTakashi Iwai snd_ftu_eff_switch_init(mixer, list->kctl); 984d34bf148SFelix Homann return 0; 985d34bf148SFelix Homann } 986d5a0bf6cSDaniel Mack 987cfe8f97cSFelix Homann /* Create volume controls for FTU devices*/ 988cfe8f97cSFelix Homann static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) 989d5a0bf6cSDaniel Mack { 990d5a0bf6cSDaniel Mack char name[64]; 9918a4d1d39SFelix Homann unsigned int control, cmask; 992d5a0bf6cSDaniel Mack int in, out, err; 993d5a0bf6cSDaniel Mack 9948a4d1d39SFelix Homann const unsigned int id = 5; 9958a4d1d39SFelix Homann const int val_type = USB_MIXER_S16; 9968a4d1d39SFelix Homann 997d5a0bf6cSDaniel Mack for (out = 0; out < 8; out++) { 9988a4d1d39SFelix Homann control = out + 1; 999d5a0bf6cSDaniel Mack for (in = 0; in < 8; in++) { 10008a4d1d39SFelix Homann cmask = 1 << in; 1001d5a0bf6cSDaniel Mack snprintf(name, sizeof(name), 10028a4d1d39SFelix Homann "AIn%d - Out%d Capture Volume", 10038a4d1d39SFelix Homann in + 1, out + 1); 10048a4d1d39SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, 10058a4d1d39SFelix Homann cmask, val_type, name, 100625ee7ef8SFelix Homann &snd_usb_mixer_vol_tlv); 1007d5a0bf6cSDaniel Mack if (err < 0) 1008d5a0bf6cSDaniel Mack return err; 1009d5a0bf6cSDaniel Mack } 1010d5a0bf6cSDaniel Mack for (in = 8; in < 16; in++) { 10118a4d1d39SFelix Homann cmask = 1 << in; 1012d5a0bf6cSDaniel Mack snprintf(name, sizeof(name), 10138a4d1d39SFelix Homann "DIn%d - Out%d Playback Volume", 10148a4d1d39SFelix Homann in - 7, out + 1); 10158a4d1d39SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, 10168a4d1d39SFelix Homann cmask, val_type, name, 101725ee7ef8SFelix Homann &snd_usb_mixer_vol_tlv); 1018d5a0bf6cSDaniel Mack if (err < 0) 1019d5a0bf6cSDaniel Mack return err; 1020d5a0bf6cSDaniel Mack } 1021d5a0bf6cSDaniel Mack } 1022d5a0bf6cSDaniel Mack 1023d5a0bf6cSDaniel Mack return 0; 1024d5a0bf6cSDaniel Mack } 1025d5a0bf6cSDaniel Mack 1026d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */ 1027d34bf148SFelix Homann static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer) 1028d34bf148SFelix Homann { 1029d34bf148SFelix Homann static const char name[] = "Effect Volume"; 1030d34bf148SFelix Homann const unsigned int id = 6; 1031d34bf148SFelix Homann const int val_type = USB_MIXER_U8; 1032d34bf148SFelix Homann const unsigned int control = 2; 1033d34bf148SFelix Homann const unsigned int cmask = 0; 1034d34bf148SFelix Homann 1035d34bf148SFelix Homann return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 1036d34bf148SFelix Homann name, snd_usb_mixer_vol_tlv); 1037d34bf148SFelix Homann } 1038d34bf148SFelix Homann 1039d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */ 1040d34bf148SFelix Homann static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer) 1041d34bf148SFelix Homann { 1042d34bf148SFelix Homann static const char name[] = "Effect Duration"; 1043d34bf148SFelix Homann const unsigned int id = 6; 1044d34bf148SFelix Homann const int val_type = USB_MIXER_S16; 1045d34bf148SFelix Homann const unsigned int control = 3; 1046d34bf148SFelix Homann const unsigned int cmask = 0; 1047d34bf148SFelix Homann 1048d34bf148SFelix Homann return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 1049d34bf148SFelix Homann name, snd_usb_mixer_vol_tlv); 1050d34bf148SFelix Homann } 1051d34bf148SFelix Homann 1052d34bf148SFelix Homann /* This control needs a volume quirk, see mixer.c */ 1053d34bf148SFelix Homann static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) 1054d34bf148SFelix Homann { 1055d34bf148SFelix Homann static const char name[] = "Effect Feedback Volume"; 1056d34bf148SFelix Homann const unsigned int id = 6; 1057d34bf148SFelix Homann const int val_type = USB_MIXER_U8; 1058d34bf148SFelix Homann const unsigned int control = 4; 1059d34bf148SFelix Homann const unsigned int cmask = 0; 1060d34bf148SFelix Homann 1061d34bf148SFelix Homann return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 1062d34bf148SFelix Homann name, NULL); 1063d34bf148SFelix Homann } 1064d34bf148SFelix Homann 1065d34bf148SFelix Homann static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer) 1066d34bf148SFelix Homann { 1067d34bf148SFelix Homann unsigned int cmask; 1068d34bf148SFelix Homann int err, ch; 1069d34bf148SFelix Homann char name[48]; 1070d34bf148SFelix Homann 1071d34bf148SFelix Homann const unsigned int id = 7; 1072d34bf148SFelix Homann const int val_type = USB_MIXER_S16; 1073d34bf148SFelix Homann const unsigned int control = 7; 1074d34bf148SFelix Homann 1075d34bf148SFelix Homann for (ch = 0; ch < 4; ++ch) { 1076d34bf148SFelix Homann cmask = 1 << ch; 1077d34bf148SFelix Homann snprintf(name, sizeof(name), 1078d34bf148SFelix Homann "Effect Return %d Volume", ch + 1); 1079d34bf148SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, 1080d34bf148SFelix Homann cmask, val_type, name, 1081d34bf148SFelix Homann snd_usb_mixer_vol_tlv); 1082d34bf148SFelix Homann if (err < 0) 1083d34bf148SFelix Homann return err; 1084d34bf148SFelix Homann } 1085d34bf148SFelix Homann 1086d34bf148SFelix Homann return 0; 1087d34bf148SFelix Homann } 1088d34bf148SFelix Homann 1089d34bf148SFelix Homann static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) 1090d34bf148SFelix Homann { 1091d34bf148SFelix Homann unsigned int cmask; 1092d34bf148SFelix Homann int err, ch; 1093d34bf148SFelix Homann char name[48]; 1094d34bf148SFelix Homann 1095d34bf148SFelix Homann const unsigned int id = 5; 1096d34bf148SFelix Homann const int val_type = USB_MIXER_S16; 1097d34bf148SFelix Homann const unsigned int control = 9; 1098d34bf148SFelix Homann 1099d34bf148SFelix Homann for (ch = 0; ch < 8; ++ch) { 1100d34bf148SFelix Homann cmask = 1 << ch; 1101d34bf148SFelix Homann snprintf(name, sizeof(name), 1102d34bf148SFelix Homann "Effect Send AIn%d Volume", ch + 1); 1103d34bf148SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, cmask, 1104d34bf148SFelix Homann val_type, name, 1105d34bf148SFelix Homann snd_usb_mixer_vol_tlv); 1106d34bf148SFelix Homann if (err < 0) 1107d34bf148SFelix Homann return err; 1108d34bf148SFelix Homann } 1109d34bf148SFelix Homann for (ch = 8; ch < 16; ++ch) { 1110d34bf148SFelix Homann cmask = 1 << ch; 1111d34bf148SFelix Homann snprintf(name, sizeof(name), 1112d34bf148SFelix Homann "Effect Send DIn%d Volume", ch - 7); 1113d34bf148SFelix Homann err = snd_create_std_mono_ctl(mixer, id, control, cmask, 1114d34bf148SFelix Homann val_type, name, 1115d34bf148SFelix Homann snd_usb_mixer_vol_tlv); 1116d34bf148SFelix Homann if (err < 0) 1117d34bf148SFelix Homann return err; 1118d34bf148SFelix Homann } 1119d34bf148SFelix Homann return 0; 1120d34bf148SFelix Homann } 1121d34bf148SFelix Homann 1122cfe8f97cSFelix Homann static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) 11237536c301SMark Hills { 11248a4d1d39SFelix Homann int err; 11257536c301SMark Hills 1126cfe8f97cSFelix Homann err = snd_ftu_create_volume_ctls(mixer); 11278a4d1d39SFelix Homann if (err < 0) 11288a4d1d39SFelix Homann return err; 11297536c301SMark Hills 1130d847ce0eSEldad Zack err = snd_ftu_create_effect_switch(mixer, 1, 6); 1131d34bf148SFelix Homann if (err < 0) 1132d34bf148SFelix Homann return err; 1133d847ce0eSEldad Zack 1134d34bf148SFelix Homann err = snd_ftu_create_effect_volume_ctl(mixer); 1135d34bf148SFelix Homann if (err < 0) 1136d34bf148SFelix Homann return err; 1137d34bf148SFelix Homann 1138d34bf148SFelix Homann err = snd_ftu_create_effect_duration_ctl(mixer); 1139d34bf148SFelix Homann if (err < 0) 1140d34bf148SFelix Homann return err; 1141d34bf148SFelix Homann 1142d34bf148SFelix Homann err = snd_ftu_create_effect_feedback_ctl(mixer); 1143d34bf148SFelix Homann if (err < 0) 1144d34bf148SFelix Homann return err; 1145d34bf148SFelix Homann 1146d34bf148SFelix Homann err = snd_ftu_create_effect_return_ctls(mixer); 1147d34bf148SFelix Homann if (err < 0) 1148d34bf148SFelix Homann return err; 1149d34bf148SFelix Homann 1150d34bf148SFelix Homann err = snd_ftu_create_effect_send_ctls(mixer); 1151d34bf148SFelix Homann if (err < 0) 1152d34bf148SFelix Homann return err; 1153d34bf148SFelix Homann 11548a4d1d39SFelix Homann return 0; 11557536c301SMark Hills } 11567536c301SMark Hills 11577b1eda22SDaniel Mack void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, 11587b1eda22SDaniel Mack unsigned char samplerate_id) 11597b1eda22SDaniel Mack { 11607b1eda22SDaniel Mack struct usb_mixer_interface *mixer; 11617b1eda22SDaniel Mack struct usb_mixer_elem_info *cval; 11626de3c9e3STakashi Iwai int unitid = 12; /* SampleRate ExtensionUnit ID */ 11637b1eda22SDaniel Mack 11647b1eda22SDaniel Mack list_for_each_entry(mixer, &chip->mixer_list, list) { 11656de3c9e3STakashi Iwai if (mixer->id_elems[unitid]) { 11668c558076STakashi Iwai cval = mixer_elem_list_to_info(mixer->id_elems[unitid]); 11677b1eda22SDaniel Mack snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, 11687b1eda22SDaniel Mack cval->control << 8, 11697b1eda22SDaniel Mack samplerate_id); 11707b1eda22SDaniel Mack snd_usb_mixer_notify_id(mixer, unitid); 11717b1eda22SDaniel Mack break; 11727b1eda22SDaniel Mack } 11737b1eda22SDaniel Mack } 11746de3c9e3STakashi Iwai } 11757b1eda22SDaniel Mack 1176e9a25e04SMatt Gruskin /* M-Audio Fast Track C400/C600 */ 1177e9a25e04SMatt Gruskin /* C400/C600 volume controls, this control needs a volume quirk, see mixer.c */ 117809d8e3a7SEldad Zack static int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer) 117909d8e3a7SEldad Zack { 118009d8e3a7SEldad Zack char name[64]; 118109d8e3a7SEldad Zack unsigned int cmask, offset; 118209d8e3a7SEldad Zack int out, chan, err; 1183e9a25e04SMatt Gruskin int num_outs = 0; 1184e9a25e04SMatt Gruskin int num_ins = 0; 118509d8e3a7SEldad Zack 118609d8e3a7SEldad Zack const unsigned int id = 0x40; 118709d8e3a7SEldad Zack const int val_type = USB_MIXER_S16; 118809d8e3a7SEldad Zack const int control = 1; 118909d8e3a7SEldad Zack 1190e9a25e04SMatt Gruskin switch (mixer->chip->usb_id) { 1191e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2030): 1192e9a25e04SMatt Gruskin num_outs = 6; 1193e9a25e04SMatt Gruskin num_ins = 4; 1194e9a25e04SMatt Gruskin break; 1195e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2031): 1196e9a25e04SMatt Gruskin num_outs = 8; 1197e9a25e04SMatt Gruskin num_ins = 6; 1198e9a25e04SMatt Gruskin break; 1199e9a25e04SMatt Gruskin } 1200e9a25e04SMatt Gruskin 1201e9a25e04SMatt Gruskin for (chan = 0; chan < num_outs + num_ins; chan++) { 1202e9a25e04SMatt Gruskin for (out = 0; out < num_outs; out++) { 1203e9a25e04SMatt Gruskin if (chan < num_outs) { 120409d8e3a7SEldad Zack snprintf(name, sizeof(name), 120509d8e3a7SEldad Zack "PCM%d-Out%d Playback Volume", 120609d8e3a7SEldad Zack chan + 1, out + 1); 120709d8e3a7SEldad Zack } else { 120809d8e3a7SEldad Zack snprintf(name, sizeof(name), 120909d8e3a7SEldad Zack "In%d-Out%d Playback Volume", 1210e9a25e04SMatt Gruskin chan - num_outs + 1, out + 1); 121109d8e3a7SEldad Zack } 121209d8e3a7SEldad Zack 121309d8e3a7SEldad Zack cmask = (out == 0) ? 0 : 1 << (out - 1); 1214e9a25e04SMatt Gruskin offset = chan * num_outs; 121509d8e3a7SEldad Zack err = snd_create_std_mono_ctl_offset(mixer, id, control, 121609d8e3a7SEldad Zack cmask, val_type, offset, name, 121709d8e3a7SEldad Zack &snd_usb_mixer_vol_tlv); 121809d8e3a7SEldad Zack if (err < 0) 121909d8e3a7SEldad Zack return err; 122009d8e3a7SEldad Zack } 122109d8e3a7SEldad Zack } 122209d8e3a7SEldad Zack 122309d8e3a7SEldad Zack return 0; 122409d8e3a7SEldad Zack } 122509d8e3a7SEldad Zack 122609d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */ 122709d8e3a7SEldad Zack static int snd_c400_create_effect_volume_ctl(struct usb_mixer_interface *mixer) 122809d8e3a7SEldad Zack { 122909d8e3a7SEldad Zack static const char name[] = "Effect Volume"; 123009d8e3a7SEldad Zack const unsigned int id = 0x43; 123109d8e3a7SEldad Zack const int val_type = USB_MIXER_U8; 123209d8e3a7SEldad Zack const unsigned int control = 3; 123309d8e3a7SEldad Zack const unsigned int cmask = 0; 123409d8e3a7SEldad Zack 123509d8e3a7SEldad Zack return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 123609d8e3a7SEldad Zack name, snd_usb_mixer_vol_tlv); 123709d8e3a7SEldad Zack } 123809d8e3a7SEldad Zack 123909d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */ 124009d8e3a7SEldad Zack static int snd_c400_create_effect_duration_ctl(struct usb_mixer_interface *mixer) 124109d8e3a7SEldad Zack { 124209d8e3a7SEldad Zack static const char name[] = "Effect Duration"; 124309d8e3a7SEldad Zack const unsigned int id = 0x43; 124409d8e3a7SEldad Zack const int val_type = USB_MIXER_S16; 124509d8e3a7SEldad Zack const unsigned int control = 4; 124609d8e3a7SEldad Zack const unsigned int cmask = 0; 124709d8e3a7SEldad Zack 124809d8e3a7SEldad Zack return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 124909d8e3a7SEldad Zack name, snd_usb_mixer_vol_tlv); 125009d8e3a7SEldad Zack } 125109d8e3a7SEldad Zack 125209d8e3a7SEldad Zack /* This control needs a volume quirk, see mixer.c */ 125309d8e3a7SEldad Zack static int snd_c400_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) 125409d8e3a7SEldad Zack { 125509d8e3a7SEldad Zack static const char name[] = "Effect Feedback Volume"; 125609d8e3a7SEldad Zack const unsigned int id = 0x43; 125709d8e3a7SEldad Zack const int val_type = USB_MIXER_U8; 125809d8e3a7SEldad Zack const unsigned int control = 5; 125909d8e3a7SEldad Zack const unsigned int cmask = 0; 126009d8e3a7SEldad Zack 126109d8e3a7SEldad Zack return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 126209d8e3a7SEldad Zack name, NULL); 126309d8e3a7SEldad Zack } 126409d8e3a7SEldad Zack 126509d8e3a7SEldad Zack static int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer) 126609d8e3a7SEldad Zack { 126709d8e3a7SEldad Zack char name[64]; 126809d8e3a7SEldad Zack unsigned int cmask; 126909d8e3a7SEldad Zack int chan, err; 1270e9a25e04SMatt Gruskin int num_outs = 0; 1271e9a25e04SMatt Gruskin int num_ins = 0; 127209d8e3a7SEldad Zack 127309d8e3a7SEldad Zack const unsigned int id = 0x42; 127409d8e3a7SEldad Zack const int val_type = USB_MIXER_S16; 127509d8e3a7SEldad Zack const int control = 1; 127609d8e3a7SEldad Zack 1277e9a25e04SMatt Gruskin switch (mixer->chip->usb_id) { 1278e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2030): 1279e9a25e04SMatt Gruskin num_outs = 6; 1280e9a25e04SMatt Gruskin num_ins = 4; 1281e9a25e04SMatt Gruskin break; 1282e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2031): 1283e9a25e04SMatt Gruskin num_outs = 8; 1284e9a25e04SMatt Gruskin num_ins = 6; 1285e9a25e04SMatt Gruskin break; 1286e9a25e04SMatt Gruskin } 1287e9a25e04SMatt Gruskin 1288e9a25e04SMatt Gruskin for (chan = 0; chan < num_outs + num_ins; chan++) { 1289e9a25e04SMatt Gruskin if (chan < num_outs) { 129009d8e3a7SEldad Zack snprintf(name, sizeof(name), 129109d8e3a7SEldad Zack "Effect Send DOut%d", 129209d8e3a7SEldad Zack chan + 1); 129309d8e3a7SEldad Zack } else { 129409d8e3a7SEldad Zack snprintf(name, sizeof(name), 129509d8e3a7SEldad Zack "Effect Send AIn%d", 1296e9a25e04SMatt Gruskin chan - num_outs + 1); 129709d8e3a7SEldad Zack } 129809d8e3a7SEldad Zack 129909d8e3a7SEldad Zack cmask = (chan == 0) ? 0 : 1 << (chan - 1); 130009d8e3a7SEldad Zack err = snd_create_std_mono_ctl(mixer, id, control, 130109d8e3a7SEldad Zack cmask, val_type, name, 130209d8e3a7SEldad Zack &snd_usb_mixer_vol_tlv); 130309d8e3a7SEldad Zack if (err < 0) 130409d8e3a7SEldad Zack return err; 130509d8e3a7SEldad Zack } 130609d8e3a7SEldad Zack 130709d8e3a7SEldad Zack return 0; 130809d8e3a7SEldad Zack } 130909d8e3a7SEldad Zack 131009d8e3a7SEldad Zack static int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer) 131109d8e3a7SEldad Zack { 131209d8e3a7SEldad Zack char name[64]; 131309d8e3a7SEldad Zack unsigned int cmask; 131409d8e3a7SEldad Zack int chan, err; 1315e9a25e04SMatt Gruskin int num_outs = 0; 1316e9a25e04SMatt Gruskin int offset = 0; 131709d8e3a7SEldad Zack 131809d8e3a7SEldad Zack const unsigned int id = 0x40; 131909d8e3a7SEldad Zack const int val_type = USB_MIXER_S16; 132009d8e3a7SEldad Zack const int control = 1; 132109d8e3a7SEldad Zack 1322e9a25e04SMatt Gruskin switch (mixer->chip->usb_id) { 1323e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2030): 1324e9a25e04SMatt Gruskin num_outs = 6; 1325e9a25e04SMatt Gruskin offset = 0x3c; 1326e9a25e04SMatt Gruskin /* { 0x3c, 0x43, 0x3e, 0x45, 0x40, 0x47 } */ 1327e9a25e04SMatt Gruskin break; 1328e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2031): 1329e9a25e04SMatt Gruskin num_outs = 8; 1330e9a25e04SMatt Gruskin offset = 0x70; 1331e9a25e04SMatt Gruskin /* { 0x70, 0x79, 0x72, 0x7b, 0x74, 0x7d, 0x76, 0x7f } */ 1332e9a25e04SMatt Gruskin break; 1333e9a25e04SMatt Gruskin } 1334e9a25e04SMatt Gruskin 1335e9a25e04SMatt Gruskin for (chan = 0; chan < num_outs; chan++) { 133609d8e3a7SEldad Zack snprintf(name, sizeof(name), 133709d8e3a7SEldad Zack "Effect Return %d", 133809d8e3a7SEldad Zack chan + 1); 133909d8e3a7SEldad Zack 1340e9a25e04SMatt Gruskin cmask = (chan == 0) ? 0 : 1341e9a25e04SMatt Gruskin 1 << (chan + (chan % 2) * num_outs - 1); 134209d8e3a7SEldad Zack err = snd_create_std_mono_ctl_offset(mixer, id, control, 134309d8e3a7SEldad Zack cmask, val_type, offset, name, 134409d8e3a7SEldad Zack &snd_usb_mixer_vol_tlv); 134509d8e3a7SEldad Zack if (err < 0) 134609d8e3a7SEldad Zack return err; 134709d8e3a7SEldad Zack } 134809d8e3a7SEldad Zack 134909d8e3a7SEldad Zack return 0; 135009d8e3a7SEldad Zack } 135109d8e3a7SEldad Zack 135209d8e3a7SEldad Zack static int snd_c400_create_mixer(struct usb_mixer_interface *mixer) 135309d8e3a7SEldad Zack { 135409d8e3a7SEldad Zack int err; 135509d8e3a7SEldad Zack 135609d8e3a7SEldad Zack err = snd_c400_create_vol_ctls(mixer); 135709d8e3a7SEldad Zack if (err < 0) 135809d8e3a7SEldad Zack return err; 135909d8e3a7SEldad Zack 136009d8e3a7SEldad Zack err = snd_c400_create_effect_vol_ctls(mixer); 136109d8e3a7SEldad Zack if (err < 0) 136209d8e3a7SEldad Zack return err; 136309d8e3a7SEldad Zack 136409d8e3a7SEldad Zack err = snd_c400_create_effect_ret_vol_ctls(mixer); 136509d8e3a7SEldad Zack if (err < 0) 136609d8e3a7SEldad Zack return err; 136709d8e3a7SEldad Zack 136809d8e3a7SEldad Zack err = snd_ftu_create_effect_switch(mixer, 2, 0x43); 136909d8e3a7SEldad Zack if (err < 0) 137009d8e3a7SEldad Zack return err; 137109d8e3a7SEldad Zack 137209d8e3a7SEldad Zack err = snd_c400_create_effect_volume_ctl(mixer); 137309d8e3a7SEldad Zack if (err < 0) 137409d8e3a7SEldad Zack return err; 137509d8e3a7SEldad Zack 137609d8e3a7SEldad Zack err = snd_c400_create_effect_duration_ctl(mixer); 137709d8e3a7SEldad Zack if (err < 0) 137809d8e3a7SEldad Zack return err; 137909d8e3a7SEldad Zack 138009d8e3a7SEldad Zack err = snd_c400_create_effect_feedback_ctl(mixer); 138109d8e3a7SEldad Zack if (err < 0) 138209d8e3a7SEldad Zack return err; 138309d8e3a7SEldad Zack 138409d8e3a7SEldad Zack return 0; 138509d8e3a7SEldad Zack } 138609d8e3a7SEldad Zack 1387b71dad18SMark Hills /* 1388b71dad18SMark Hills * The mixer units for Ebox-44 are corrupt, and even where they 1389b71dad18SMark Hills * are valid they presents mono controls as L and R channels of 1390b71dad18SMark Hills * stereo. So we provide a good mixer here. 1391b71dad18SMark Hills */ 1392a01df925STakashi Iwai static const struct std_mono_table ebox44_table[] = { 1393989b0138SMark Hills { 1394989b0138SMark Hills .unitid = 4, 1395989b0138SMark Hills .control = 1, 1396989b0138SMark Hills .cmask = 0x0, 1397989b0138SMark Hills .val_type = USB_MIXER_INV_BOOLEAN, 1398989b0138SMark Hills .name = "Headphone Playback Switch" 1399989b0138SMark Hills }, 1400989b0138SMark Hills { 1401989b0138SMark Hills .unitid = 4, 1402989b0138SMark Hills .control = 2, 1403989b0138SMark Hills .cmask = 0x1, 1404989b0138SMark Hills .val_type = USB_MIXER_S16, 1405989b0138SMark Hills .name = "Headphone A Mix Playback Volume" 1406989b0138SMark Hills }, 1407989b0138SMark Hills { 1408989b0138SMark Hills .unitid = 4, 1409989b0138SMark Hills .control = 2, 1410989b0138SMark Hills .cmask = 0x2, 1411989b0138SMark Hills .val_type = USB_MIXER_S16, 1412989b0138SMark Hills .name = "Headphone B Mix Playback Volume" 1413989b0138SMark Hills }, 1414b71dad18SMark Hills 1415989b0138SMark Hills { 1416989b0138SMark Hills .unitid = 7, 1417989b0138SMark Hills .control = 1, 1418989b0138SMark Hills .cmask = 0x0, 1419989b0138SMark Hills .val_type = USB_MIXER_INV_BOOLEAN, 1420989b0138SMark Hills .name = "Output Playback Switch" 1421989b0138SMark Hills }, 1422989b0138SMark Hills { 1423989b0138SMark Hills .unitid = 7, 1424989b0138SMark Hills .control = 2, 1425989b0138SMark Hills .cmask = 0x1, 1426989b0138SMark Hills .val_type = USB_MIXER_S16, 1427989b0138SMark Hills .name = "Output A Playback Volume" 1428989b0138SMark Hills }, 1429989b0138SMark Hills { 1430989b0138SMark Hills .unitid = 7, 1431989b0138SMark Hills .control = 2, 1432989b0138SMark Hills .cmask = 0x2, 1433989b0138SMark Hills .val_type = USB_MIXER_S16, 1434989b0138SMark Hills .name = "Output B Playback Volume" 1435989b0138SMark Hills }, 1436b71dad18SMark Hills 1437989b0138SMark Hills { 1438989b0138SMark Hills .unitid = 10, 1439989b0138SMark Hills .control = 1, 1440989b0138SMark Hills .cmask = 0x0, 1441989b0138SMark Hills .val_type = USB_MIXER_INV_BOOLEAN, 1442989b0138SMark Hills .name = "Input Capture Switch" 1443989b0138SMark Hills }, 1444989b0138SMark Hills { 1445989b0138SMark Hills .unitid = 10, 1446989b0138SMark Hills .control = 2, 1447989b0138SMark Hills .cmask = 0x1, 1448989b0138SMark Hills .val_type = USB_MIXER_S16, 1449989b0138SMark Hills .name = "Input A Capture Volume" 1450989b0138SMark Hills }, 1451989b0138SMark Hills { 1452989b0138SMark Hills .unitid = 10, 1453989b0138SMark Hills .control = 2, 1454989b0138SMark Hills .cmask = 0x2, 1455989b0138SMark Hills .val_type = USB_MIXER_S16, 1456989b0138SMark Hills .name = "Input B Capture Volume" 1457989b0138SMark Hills }, 1458b71dad18SMark Hills 1459b71dad18SMark Hills {} 1460b71dad18SMark Hills }; 1461b71dad18SMark Hills 1462066624c6SPrzemek Rudy /* Audio Advantage Micro II findings: 1463066624c6SPrzemek Rudy * 1464066624c6SPrzemek Rudy * Mapping spdif AES bits to vendor register.bit: 1465066624c6SPrzemek Rudy * AES0: [0 0 0 0 2.3 2.2 2.1 2.0] - default 0x00 1466066624c6SPrzemek Rudy * AES1: [3.3 3.2.3.1.3.0 2.7 2.6 2.5 2.4] - default: 0x01 1467066624c6SPrzemek Rudy * AES2: [0 0 0 0 0 0 0 0] 1468066624c6SPrzemek Rudy * AES3: [0 0 0 0 0 0 x 0] - 'x' bit is set basing on standard usb request 1469066624c6SPrzemek Rudy * (UAC_EP_CS_ATTR_SAMPLE_RATE) for Audio Devices 1470066624c6SPrzemek Rudy * 1471066624c6SPrzemek Rudy * power on values: 1472066624c6SPrzemek Rudy * r2: 0x10 1473066624c6SPrzemek Rudy * r3: 0x20 (b7 is zeroed just before playback (except IEC61937) and set 1474066624c6SPrzemek Rudy * just after it to 0xa0, presumably it disables/mutes some analog 1475066624c6SPrzemek Rudy * parts when there is no audio.) 1476066624c6SPrzemek Rudy * r9: 0x28 1477066624c6SPrzemek Rudy * 1478066624c6SPrzemek Rudy * Optical transmitter on/off: 1479066624c6SPrzemek Rudy * vendor register.bit: 9.1 1480066624c6SPrzemek Rudy * 0 - on (0x28 register value) 1481066624c6SPrzemek Rudy * 1 - off (0x2a register value) 1482066624c6SPrzemek Rudy * 1483066624c6SPrzemek Rudy */ 1484066624c6SPrzemek Rudy static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol, 1485066624c6SPrzemek Rudy struct snd_ctl_elem_info *uinfo) 1486066624c6SPrzemek Rudy { 1487066624c6SPrzemek Rudy uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 1488066624c6SPrzemek Rudy uinfo->count = 1; 1489066624c6SPrzemek Rudy return 0; 1490066624c6SPrzemek Rudy } 1491066624c6SPrzemek Rudy 1492066624c6SPrzemek Rudy static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, 1493066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1494066624c6SPrzemek Rudy { 1495288673beSTakashi Iwai struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 1496288673beSTakashi Iwai struct snd_usb_audio *chip = list->mixer->chip; 1497066624c6SPrzemek Rudy int err; 1498066624c6SPrzemek Rudy struct usb_interface *iface; 1499066624c6SPrzemek Rudy struct usb_host_interface *alts; 1500066624c6SPrzemek Rudy unsigned int ep; 1501066624c6SPrzemek Rudy unsigned char data[3]; 1502066624c6SPrzemek Rudy int rate; 1503066624c6SPrzemek Rudy 150447ab1545STakashi Iwai err = snd_usb_lock_shutdown(chip); 150547ab1545STakashi Iwai if (err < 0) 150647ab1545STakashi Iwai return err; 1507288673beSTakashi Iwai 1508066624c6SPrzemek Rudy ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff; 1509066624c6SPrzemek Rudy ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff; 1510066624c6SPrzemek Rudy ucontrol->value.iec958.status[2] = 0x00; 1511066624c6SPrzemek Rudy 1512066624c6SPrzemek Rudy /* use known values for that card: interface#1 altsetting#1 */ 1513288673beSTakashi Iwai iface = usb_ifnum_to_if(chip->dev, 1); 151459e1947cSXiyu Yang if (!iface || iface->num_altsetting < 2) { 151559e1947cSXiyu Yang err = -EINVAL; 151659e1947cSXiyu Yang goto end; 151759e1947cSXiyu Yang } 1518066624c6SPrzemek Rudy alts = &iface->altsetting[1]; 151959e1947cSXiyu Yang if (get_iface_desc(alts)->bNumEndpoints < 1) { 152059e1947cSXiyu Yang err = -EINVAL; 152159e1947cSXiyu Yang goto end; 152259e1947cSXiyu Yang } 1523066624c6SPrzemek Rudy ep = get_endpoint(alts, 0)->bEndpointAddress; 1524066624c6SPrzemek Rudy 1525288673beSTakashi Iwai err = snd_usb_ctl_msg(chip->dev, 1526288673beSTakashi Iwai usb_rcvctrlpipe(chip->dev, 0), 1527066624c6SPrzemek Rudy UAC_GET_CUR, 1528066624c6SPrzemek Rudy USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, 1529066624c6SPrzemek Rudy UAC_EP_CS_ATTR_SAMPLE_RATE << 8, 1530066624c6SPrzemek Rudy ep, 1531066624c6SPrzemek Rudy data, 1532066624c6SPrzemek Rudy sizeof(data)); 1533066624c6SPrzemek Rudy if (err < 0) 1534066624c6SPrzemek Rudy goto end; 1535066624c6SPrzemek Rudy 1536066624c6SPrzemek Rudy rate = data[0] | (data[1] << 8) | (data[2] << 16); 1537066624c6SPrzemek Rudy ucontrol->value.iec958.status[3] = (rate == 48000) ? 1538066624c6SPrzemek Rudy IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100; 1539066624c6SPrzemek Rudy 1540066624c6SPrzemek Rudy err = 0; 1541066624c6SPrzemek Rudy end: 154247ab1545STakashi Iwai snd_usb_unlock_shutdown(chip); 1543066624c6SPrzemek Rudy return err; 1544066624c6SPrzemek Rudy } 1545066624c6SPrzemek Rudy 1546288673beSTakashi Iwai static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) 1547066624c6SPrzemek Rudy { 1548288673beSTakashi Iwai struct snd_usb_audio *chip = list->mixer->chip; 1549288673beSTakashi Iwai unsigned int pval = list->kctl->private_value; 1550066624c6SPrzemek Rudy u8 reg; 1551288673beSTakashi Iwai int err; 1552066624c6SPrzemek Rudy 155347ab1545STakashi Iwai err = snd_usb_lock_shutdown(chip); 155447ab1545STakashi Iwai if (err < 0) 155547ab1545STakashi Iwai return err; 1556288673beSTakashi Iwai 1557288673beSTakashi Iwai reg = ((pval >> 4) & 0xf0) | (pval & 0x0f); 1558288673beSTakashi Iwai err = snd_usb_ctl_msg(chip->dev, 1559288673beSTakashi Iwai usb_sndctrlpipe(chip->dev, 0), 1560066624c6SPrzemek Rudy UAC_SET_CUR, 1561066624c6SPrzemek Rudy USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 1562066624c6SPrzemek Rudy reg, 1563066624c6SPrzemek Rudy 2, 1564066624c6SPrzemek Rudy NULL, 1565066624c6SPrzemek Rudy 0); 1566066624c6SPrzemek Rudy if (err < 0) 1567066624c6SPrzemek Rudy goto end; 1568066624c6SPrzemek Rudy 1569288673beSTakashi Iwai reg = (pval & IEC958_AES0_NONAUDIO) ? 0xa0 : 0x20; 1570288673beSTakashi Iwai reg |= (pval >> 12) & 0x0f; 1571288673beSTakashi Iwai err = snd_usb_ctl_msg(chip->dev, 1572288673beSTakashi Iwai usb_sndctrlpipe(chip->dev, 0), 1573066624c6SPrzemek Rudy UAC_SET_CUR, 1574066624c6SPrzemek Rudy USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 1575066624c6SPrzemek Rudy reg, 1576066624c6SPrzemek Rudy 3, 1577066624c6SPrzemek Rudy NULL, 1578066624c6SPrzemek Rudy 0); 1579066624c6SPrzemek Rudy if (err < 0) 1580066624c6SPrzemek Rudy goto end; 1581066624c6SPrzemek Rudy 1582288673beSTakashi Iwai end: 158347ab1545STakashi Iwai snd_usb_unlock_shutdown(chip); 1584288673beSTakashi Iwai return err; 1585288673beSTakashi Iwai } 1586288673beSTakashi Iwai 1587288673beSTakashi Iwai static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, 1588288673beSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 1589288673beSTakashi Iwai { 1590288673beSTakashi Iwai struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 1591288673beSTakashi Iwai unsigned int pval, pval_old; 1592288673beSTakashi Iwai int err; 1593288673beSTakashi Iwai 1594288673beSTakashi Iwai pval = pval_old = kcontrol->private_value; 1595288673beSTakashi Iwai pval &= 0xfffff0f0; 1596288673beSTakashi Iwai pval |= (ucontrol->value.iec958.status[1] & 0x0f) << 8; 1597288673beSTakashi Iwai pval |= (ucontrol->value.iec958.status[0] & 0x0f); 1598288673beSTakashi Iwai 1599288673beSTakashi Iwai pval &= 0xffff0fff; 1600288673beSTakashi Iwai pval |= (ucontrol->value.iec958.status[1] & 0xf0) << 8; 1601066624c6SPrzemek Rudy 1602066624c6SPrzemek Rudy /* The frequency bits in AES3 cannot be set via register access. */ 1603066624c6SPrzemek Rudy 1604066624c6SPrzemek Rudy /* Silently ignore any bits from the request that cannot be set. */ 1605066624c6SPrzemek Rudy 1606288673beSTakashi Iwai if (pval == pval_old) 1607288673beSTakashi Iwai return 0; 1608288673beSTakashi Iwai 1609288673beSTakashi Iwai kcontrol->private_value = pval; 1610288673beSTakashi Iwai err = snd_microii_spdif_default_update(list); 1611288673beSTakashi Iwai return err < 0 ? err : 1; 1612066624c6SPrzemek Rudy } 1613066624c6SPrzemek Rudy 1614066624c6SPrzemek Rudy static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol, 1615066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1616066624c6SPrzemek Rudy { 1617066624c6SPrzemek Rudy ucontrol->value.iec958.status[0] = 0x0f; 1618066624c6SPrzemek Rudy ucontrol->value.iec958.status[1] = 0xff; 1619066624c6SPrzemek Rudy ucontrol->value.iec958.status[2] = 0x00; 1620066624c6SPrzemek Rudy ucontrol->value.iec958.status[3] = 0x00; 1621066624c6SPrzemek Rudy 1622066624c6SPrzemek Rudy return 0; 1623066624c6SPrzemek Rudy } 1624066624c6SPrzemek Rudy 1625066624c6SPrzemek Rudy static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol, 1626066624c6SPrzemek Rudy struct snd_ctl_elem_value *ucontrol) 1627066624c6SPrzemek Rudy { 1628066624c6SPrzemek Rudy ucontrol->value.integer.value[0] = !(kcontrol->private_value & 0x02); 1629066624c6SPrzemek Rudy 1630066624c6SPrzemek Rudy return 0; 1631066624c6SPrzemek Rudy } 1632066624c6SPrzemek Rudy 1633288673beSTakashi Iwai static int snd_microii_spdif_switch_update(struct usb_mixer_elem_list *list) 1634066624c6SPrzemek Rudy { 1635288673beSTakashi Iwai struct snd_usb_audio *chip = list->mixer->chip; 1636288673beSTakashi Iwai u8 reg = list->kctl->private_value; 1637066624c6SPrzemek Rudy int err; 1638066624c6SPrzemek Rudy 163947ab1545STakashi Iwai err = snd_usb_lock_shutdown(chip); 164047ab1545STakashi Iwai if (err < 0) 164147ab1545STakashi Iwai return err; 1642288673beSTakashi Iwai 1643288673beSTakashi Iwai err = snd_usb_ctl_msg(chip->dev, 1644288673beSTakashi Iwai usb_sndctrlpipe(chip->dev, 0), 1645066624c6SPrzemek Rudy UAC_SET_CUR, 1646066624c6SPrzemek Rudy USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 1647066624c6SPrzemek Rudy reg, 1648066624c6SPrzemek Rudy 9, 1649066624c6SPrzemek Rudy NULL, 1650066624c6SPrzemek Rudy 0); 1651066624c6SPrzemek Rudy 165247ab1545STakashi Iwai snd_usb_unlock_shutdown(chip); 1653288673beSTakashi Iwai return err; 1654066624c6SPrzemek Rudy } 1655066624c6SPrzemek Rudy 1656288673beSTakashi Iwai static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol, 1657288673beSTakashi Iwai struct snd_ctl_elem_value *ucontrol) 1658288673beSTakashi Iwai { 1659288673beSTakashi Iwai struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 1660288673beSTakashi Iwai u8 reg; 1661288673beSTakashi Iwai int err; 1662288673beSTakashi Iwai 1663288673beSTakashi Iwai reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a; 1664288673beSTakashi Iwai if (reg != list->kctl->private_value) 1665288673beSTakashi Iwai return 0; 1666288673beSTakashi Iwai 1667288673beSTakashi Iwai kcontrol->private_value = reg; 1668288673beSTakashi Iwai err = snd_microii_spdif_switch_update(list); 1669288673beSTakashi Iwai return err < 0 ? err : 1; 1670066624c6SPrzemek Rudy } 1671066624c6SPrzemek Rudy 1672195727e8STakashi Iwai static const struct snd_kcontrol_new snd_microii_mixer_spdif[] = { 1673066624c6SPrzemek Rudy { 1674066624c6SPrzemek Rudy .iface = SNDRV_CTL_ELEM_IFACE_PCM, 1675066624c6SPrzemek Rudy .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), 1676066624c6SPrzemek Rudy .info = snd_microii_spdif_info, 1677066624c6SPrzemek Rudy .get = snd_microii_spdif_default_get, 1678066624c6SPrzemek Rudy .put = snd_microii_spdif_default_put, 1679066624c6SPrzemek Rudy .private_value = 0x00000100UL,/* reset value */ 1680066624c6SPrzemek Rudy }, 1681066624c6SPrzemek Rudy { 1682066624c6SPrzemek Rudy .access = SNDRV_CTL_ELEM_ACCESS_READ, 1683066624c6SPrzemek Rudy .iface = SNDRV_CTL_ELEM_IFACE_PCM, 1684066624c6SPrzemek Rudy .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), 1685066624c6SPrzemek Rudy .info = snd_microii_spdif_info, 1686066624c6SPrzemek Rudy .get = snd_microii_spdif_mask_get, 1687066624c6SPrzemek Rudy }, 1688066624c6SPrzemek Rudy { 1689066624c6SPrzemek Rudy .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1690066624c6SPrzemek Rudy .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), 1691066624c6SPrzemek Rudy .info = snd_ctl_boolean_mono_info, 1692066624c6SPrzemek Rudy .get = snd_microii_spdif_switch_get, 1693066624c6SPrzemek Rudy .put = snd_microii_spdif_switch_put, 1694066624c6SPrzemek Rudy .private_value = 0x00000028UL,/* reset value */ 1695066624c6SPrzemek Rudy } 1696066624c6SPrzemek Rudy }; 1697066624c6SPrzemek Rudy 1698066624c6SPrzemek Rudy static int snd_microii_controls_create(struct usb_mixer_interface *mixer) 1699066624c6SPrzemek Rudy { 1700066624c6SPrzemek Rudy int err, i; 1701ff40e0d4SPierre-Louis Bossart static const usb_mixer_elem_resume_func_t resume_funcs[] = { 1702288673beSTakashi Iwai snd_microii_spdif_default_update, 1703288673beSTakashi Iwai NULL, 1704288673beSTakashi Iwai snd_microii_spdif_switch_update 1705288673beSTakashi Iwai }; 1706066624c6SPrzemek Rudy 1707066624c6SPrzemek Rudy for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) { 1708288673beSTakashi Iwai err = add_single_ctl_with_resume(mixer, 0, 1709288673beSTakashi Iwai resume_funcs[i], 1710288673beSTakashi Iwai &snd_microii_mixer_spdif[i], 1711288673beSTakashi Iwai NULL); 1712066624c6SPrzemek Rudy if (err < 0) 1713066624c6SPrzemek Rudy return err; 1714066624c6SPrzemek Rudy } 1715066624c6SPrzemek Rudy 171618e4753fSMikulas Patocka return 0; 1717066624c6SPrzemek Rudy } 1718066624c6SPrzemek Rudy 1719388fdb8fSIan Douglas Scott /* Creative Sound Blaster E1 */ 1720388fdb8fSIan Douglas Scott 1721388fdb8fSIan Douglas Scott static int snd_soundblaster_e1_switch_get(struct snd_kcontrol *kcontrol, 1722388fdb8fSIan Douglas Scott struct snd_ctl_elem_value *ucontrol) 1723388fdb8fSIan Douglas Scott { 1724388fdb8fSIan Douglas Scott ucontrol->value.integer.value[0] = kcontrol->private_value; 1725388fdb8fSIan Douglas Scott return 0; 1726388fdb8fSIan Douglas Scott } 1727388fdb8fSIan Douglas Scott 1728388fdb8fSIan Douglas Scott static int snd_soundblaster_e1_switch_update(struct usb_mixer_interface *mixer, 1729388fdb8fSIan Douglas Scott unsigned char state) 1730388fdb8fSIan Douglas Scott { 1731388fdb8fSIan Douglas Scott struct snd_usb_audio *chip = mixer->chip; 1732388fdb8fSIan Douglas Scott int err; 1733388fdb8fSIan Douglas Scott unsigned char buff[2]; 1734388fdb8fSIan Douglas Scott 1735388fdb8fSIan Douglas Scott buff[0] = 0x02; 1736388fdb8fSIan Douglas Scott buff[1] = state ? 0x02 : 0x00; 1737388fdb8fSIan Douglas Scott 1738388fdb8fSIan Douglas Scott err = snd_usb_lock_shutdown(chip); 1739388fdb8fSIan Douglas Scott if (err < 0) 1740388fdb8fSIan Douglas Scott return err; 1741388fdb8fSIan Douglas Scott err = snd_usb_ctl_msg(chip->dev, 1742388fdb8fSIan Douglas Scott usb_sndctrlpipe(chip->dev, 0), HID_REQ_SET_REPORT, 1743388fdb8fSIan Douglas Scott USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 1744388fdb8fSIan Douglas Scott 0x0202, 3, buff, 2); 1745388fdb8fSIan Douglas Scott snd_usb_unlock_shutdown(chip); 1746388fdb8fSIan Douglas Scott return err; 1747388fdb8fSIan Douglas Scott } 1748388fdb8fSIan Douglas Scott 1749388fdb8fSIan Douglas Scott static int snd_soundblaster_e1_switch_put(struct snd_kcontrol *kcontrol, 1750388fdb8fSIan Douglas Scott struct snd_ctl_elem_value *ucontrol) 1751388fdb8fSIan Douglas Scott { 1752388fdb8fSIan Douglas Scott struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 1753388fdb8fSIan Douglas Scott unsigned char value = !!ucontrol->value.integer.value[0]; 1754388fdb8fSIan Douglas Scott int err; 1755388fdb8fSIan Douglas Scott 1756388fdb8fSIan Douglas Scott if (kcontrol->private_value == value) 1757388fdb8fSIan Douglas Scott return 0; 1758388fdb8fSIan Douglas Scott kcontrol->private_value = value; 1759388fdb8fSIan Douglas Scott err = snd_soundblaster_e1_switch_update(list->mixer, value); 1760388fdb8fSIan Douglas Scott return err < 0 ? err : 1; 1761388fdb8fSIan Douglas Scott } 1762388fdb8fSIan Douglas Scott 1763388fdb8fSIan Douglas Scott static int snd_soundblaster_e1_switch_resume(struct usb_mixer_elem_list *list) 1764388fdb8fSIan Douglas Scott { 1765388fdb8fSIan Douglas Scott return snd_soundblaster_e1_switch_update(list->mixer, 1766388fdb8fSIan Douglas Scott list->kctl->private_value); 1767388fdb8fSIan Douglas Scott } 1768388fdb8fSIan Douglas Scott 1769388fdb8fSIan Douglas Scott static int snd_soundblaster_e1_switch_info(struct snd_kcontrol *kcontrol, 1770388fdb8fSIan Douglas Scott struct snd_ctl_elem_info *uinfo) 1771388fdb8fSIan Douglas Scott { 1772388fdb8fSIan Douglas Scott static const char *const texts[2] = { 1773388fdb8fSIan Douglas Scott "Mic", "Aux" 1774388fdb8fSIan Douglas Scott }; 1775388fdb8fSIan Douglas Scott 1776388fdb8fSIan Douglas Scott return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 1777388fdb8fSIan Douglas Scott } 1778388fdb8fSIan Douglas Scott 1779195727e8STakashi Iwai static const struct snd_kcontrol_new snd_soundblaster_e1_input_switch = { 1780388fdb8fSIan Douglas Scott .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1781388fdb8fSIan Douglas Scott .name = "Input Source", 1782388fdb8fSIan Douglas Scott .info = snd_soundblaster_e1_switch_info, 1783388fdb8fSIan Douglas Scott .get = snd_soundblaster_e1_switch_get, 1784388fdb8fSIan Douglas Scott .put = snd_soundblaster_e1_switch_put, 1785388fdb8fSIan Douglas Scott .private_value = 0, 1786388fdb8fSIan Douglas Scott }; 1787388fdb8fSIan Douglas Scott 1788388fdb8fSIan Douglas Scott static int snd_soundblaster_e1_switch_create(struct usb_mixer_interface *mixer) 1789388fdb8fSIan Douglas Scott { 1790388fdb8fSIan Douglas Scott return add_single_ctl_with_resume(mixer, 0, 1791388fdb8fSIan Douglas Scott snd_soundblaster_e1_switch_resume, 1792388fdb8fSIan Douglas Scott &snd_soundblaster_e1_input_switch, 1793388fdb8fSIan Douglas Scott NULL); 1794388fdb8fSIan Douglas Scott } 1795388fdb8fSIan Douglas Scott 1796964af639STakashi Iwai static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id) 1797964af639STakashi Iwai { 1798964af639STakashi Iwai u16 buf = 0; 1799964af639STakashi Iwai 1800964af639STakashi Iwai snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, 1801964af639STakashi Iwai USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 1802964af639STakashi Iwai ch, snd_usb_ctrl_intf(chip) | (id << 8), 1803964af639STakashi Iwai &buf, 2); 1804964af639STakashi Iwai } 1805964af639STakashi Iwai 1806964af639STakashi Iwai static int dell_dock_mixer_init(struct usb_mixer_interface *mixer) 1807964af639STakashi Iwai { 1808964af639STakashi Iwai /* fix to 0dB playback volumes */ 1809964af639STakashi Iwai dell_dock_init_vol(mixer->chip, 1, 16); 1810964af639STakashi Iwai dell_dock_init_vol(mixer->chip, 2, 16); 1811964af639STakashi Iwai dell_dock_init_vol(mixer->chip, 1, 19); 1812964af639STakashi Iwai dell_dock_init_vol(mixer->chip, 2, 19); 1813964af639STakashi Iwai return 0; 1814964af639STakashi Iwai } 1815964af639STakashi Iwai 1816d39f1d68SJussi Laako /* RME Class Compliant device quirks */ 1817d39f1d68SJussi Laako 1818d39f1d68SJussi Laako #define SND_RME_GET_STATUS1 23 1819d39f1d68SJussi Laako #define SND_RME_GET_CURRENT_FREQ 17 1820d39f1d68SJussi Laako #define SND_RME_CLK_SYSTEM_SHIFT 16 1821d39f1d68SJussi Laako #define SND_RME_CLK_SYSTEM_MASK 0x1f 1822d39f1d68SJussi Laako #define SND_RME_CLK_AES_SHIFT 8 1823d39f1d68SJussi Laako #define SND_RME_CLK_SPDIF_SHIFT 12 1824d39f1d68SJussi Laako #define SND_RME_CLK_AES_SPDIF_MASK 0xf 1825d39f1d68SJussi Laako #define SND_RME_CLK_SYNC_SHIFT 6 1826d39f1d68SJussi Laako #define SND_RME_CLK_SYNC_MASK 0x3 1827d39f1d68SJussi Laako #define SND_RME_CLK_FREQMUL_SHIFT 18 1828d39f1d68SJussi Laako #define SND_RME_CLK_FREQMUL_MASK 0x7 1829d39f1d68SJussi Laako #define SND_RME_CLK_SYSTEM(x) \ 1830d39f1d68SJussi Laako ((x >> SND_RME_CLK_SYSTEM_SHIFT) & SND_RME_CLK_SYSTEM_MASK) 1831d39f1d68SJussi Laako #define SND_RME_CLK_AES(x) \ 1832d39f1d68SJussi Laako ((x >> SND_RME_CLK_AES_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) 1833d39f1d68SJussi Laako #define SND_RME_CLK_SPDIF(x) \ 1834d39f1d68SJussi Laako ((x >> SND_RME_CLK_SPDIF_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) 1835d39f1d68SJussi Laako #define SND_RME_CLK_SYNC(x) \ 1836d39f1d68SJussi Laako ((x >> SND_RME_CLK_SYNC_SHIFT) & SND_RME_CLK_SYNC_MASK) 1837d39f1d68SJussi Laako #define SND_RME_CLK_FREQMUL(x) \ 1838d39f1d68SJussi Laako ((x >> SND_RME_CLK_FREQMUL_SHIFT) & SND_RME_CLK_FREQMUL_MASK) 1839d39f1d68SJussi Laako #define SND_RME_CLK_AES_LOCK 0x1 1840d39f1d68SJussi Laako #define SND_RME_CLK_AES_SYNC 0x4 1841d39f1d68SJussi Laako #define SND_RME_CLK_SPDIF_LOCK 0x2 1842d39f1d68SJussi Laako #define SND_RME_CLK_SPDIF_SYNC 0x8 1843d39f1d68SJussi Laako #define SND_RME_SPDIF_IF_SHIFT 4 1844d39f1d68SJussi Laako #define SND_RME_SPDIF_FORMAT_SHIFT 5 1845d39f1d68SJussi Laako #define SND_RME_BINARY_MASK 0x1 1846d39f1d68SJussi Laako #define SND_RME_SPDIF_IF(x) \ 1847d39f1d68SJussi Laako ((x >> SND_RME_SPDIF_IF_SHIFT) & SND_RME_BINARY_MASK) 1848d39f1d68SJussi Laako #define SND_RME_SPDIF_FORMAT(x) \ 1849d39f1d68SJussi Laako ((x >> SND_RME_SPDIF_FORMAT_SHIFT) & SND_RME_BINARY_MASK) 1850d39f1d68SJussi Laako 1851d39f1d68SJussi Laako static const u32 snd_rme_rate_table[] = { 1852d39f1d68SJussi Laako 32000, 44100, 48000, 50000, 1853d39f1d68SJussi Laako 64000, 88200, 96000, 100000, 1854d39f1d68SJussi Laako 128000, 176400, 192000, 200000, 1855d39f1d68SJussi Laako 256000, 352800, 384000, 400000, 1856d39f1d68SJussi Laako 512000, 705600, 768000, 800000 1857d39f1d68SJussi Laako }; 1858d39f1d68SJussi Laako /* maximum number of items for AES and S/PDIF rates for above table */ 1859d39f1d68SJussi Laako #define SND_RME_RATE_IDX_AES_SPDIF_NUM 12 1860d39f1d68SJussi Laako 1861d39f1d68SJussi Laako enum snd_rme_domain { 1862d39f1d68SJussi Laako SND_RME_DOMAIN_SYSTEM, 1863d39f1d68SJussi Laako SND_RME_DOMAIN_AES, 1864d39f1d68SJussi Laako SND_RME_DOMAIN_SPDIF 1865d39f1d68SJussi Laako }; 1866d39f1d68SJussi Laako 1867d39f1d68SJussi Laako enum snd_rme_clock_status { 1868d39f1d68SJussi Laako SND_RME_CLOCK_NOLOCK, 1869d39f1d68SJussi Laako SND_RME_CLOCK_LOCK, 1870d39f1d68SJussi Laako SND_RME_CLOCK_SYNC 1871d39f1d68SJussi Laako }; 1872d39f1d68SJussi Laako 1873d39f1d68SJussi Laako static int snd_rme_read_value(struct snd_usb_audio *chip, 1874d39f1d68SJussi Laako unsigned int item, 1875d39f1d68SJussi Laako u32 *value) 1876d39f1d68SJussi Laako { 1877d39f1d68SJussi Laako struct usb_device *dev = chip->dev; 1878d39f1d68SJussi Laako int err; 1879d39f1d68SJussi Laako 1880d39f1d68SJussi Laako err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 1881d39f1d68SJussi Laako item, 1882d39f1d68SJussi Laako USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1883d39f1d68SJussi Laako 0, 0, 1884d39f1d68SJussi Laako value, sizeof(*value)); 1885d39f1d68SJussi Laako if (err < 0) 1886d39f1d68SJussi Laako dev_err(&dev->dev, 1887d39f1d68SJussi Laako "unable to issue vendor read request %d (ret = %d)", 1888d39f1d68SJussi Laako item, err); 1889d39f1d68SJussi Laako return err; 1890d39f1d68SJussi Laako } 1891d39f1d68SJussi Laako 1892d39f1d68SJussi Laako static int snd_rme_get_status1(struct snd_kcontrol *kcontrol, 1893d39f1d68SJussi Laako u32 *status1) 1894d39f1d68SJussi Laako { 1895d39f1d68SJussi Laako struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 1896d39f1d68SJussi Laako struct snd_usb_audio *chip = list->mixer->chip; 1897d39f1d68SJussi Laako int err; 1898d39f1d68SJussi Laako 1899d39f1d68SJussi Laako err = snd_usb_lock_shutdown(chip); 1900d39f1d68SJussi Laako if (err < 0) 1901d39f1d68SJussi Laako return err; 1902d39f1d68SJussi Laako err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, status1); 1903d39f1d68SJussi Laako snd_usb_unlock_shutdown(chip); 1904d39f1d68SJussi Laako return err; 1905d39f1d68SJussi Laako } 1906d39f1d68SJussi Laako 1907d39f1d68SJussi Laako static int snd_rme_rate_get(struct snd_kcontrol *kcontrol, 1908d39f1d68SJussi Laako struct snd_ctl_elem_value *ucontrol) 1909d39f1d68SJussi Laako { 1910d39f1d68SJussi Laako u32 status1; 1911d39f1d68SJussi Laako u32 rate = 0; 1912d39f1d68SJussi Laako int idx; 1913d39f1d68SJussi Laako int err; 1914d39f1d68SJussi Laako 1915d39f1d68SJussi Laako err = snd_rme_get_status1(kcontrol, &status1); 1916d39f1d68SJussi Laako if (err < 0) 1917d39f1d68SJussi Laako return err; 1918d39f1d68SJussi Laako switch (kcontrol->private_value) { 1919d39f1d68SJussi Laako case SND_RME_DOMAIN_SYSTEM: 1920d39f1d68SJussi Laako idx = SND_RME_CLK_SYSTEM(status1); 1921d39f1d68SJussi Laako if (idx < ARRAY_SIZE(snd_rme_rate_table)) 1922d39f1d68SJussi Laako rate = snd_rme_rate_table[idx]; 1923d39f1d68SJussi Laako break; 1924d39f1d68SJussi Laako case SND_RME_DOMAIN_AES: 1925d39f1d68SJussi Laako idx = SND_RME_CLK_AES(status1); 1926d39f1d68SJussi Laako if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM) 1927d39f1d68SJussi Laako rate = snd_rme_rate_table[idx]; 1928d39f1d68SJussi Laako break; 1929d39f1d68SJussi Laako case SND_RME_DOMAIN_SPDIF: 1930d39f1d68SJussi Laako idx = SND_RME_CLK_SPDIF(status1); 1931d39f1d68SJussi Laako if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM) 1932d39f1d68SJussi Laako rate = snd_rme_rate_table[idx]; 1933d39f1d68SJussi Laako break; 1934d39f1d68SJussi Laako default: 1935d39f1d68SJussi Laako return -EINVAL; 1936d39f1d68SJussi Laako } 1937d39f1d68SJussi Laako ucontrol->value.integer.value[0] = rate; 1938d39f1d68SJussi Laako return 0; 1939d39f1d68SJussi Laako } 1940d39f1d68SJussi Laako 1941d39f1d68SJussi Laako static int snd_rme_sync_state_get(struct snd_kcontrol *kcontrol, 1942d39f1d68SJussi Laako struct snd_ctl_elem_value *ucontrol) 1943d39f1d68SJussi Laako { 1944d39f1d68SJussi Laako u32 status1; 1945d39f1d68SJussi Laako int idx = SND_RME_CLOCK_NOLOCK; 1946d39f1d68SJussi Laako int err; 1947d39f1d68SJussi Laako 1948d39f1d68SJussi Laako err = snd_rme_get_status1(kcontrol, &status1); 1949d39f1d68SJussi Laako if (err < 0) 1950d39f1d68SJussi Laako return err; 1951d39f1d68SJussi Laako switch (kcontrol->private_value) { 1952d39f1d68SJussi Laako case SND_RME_DOMAIN_AES: /* AES */ 1953d39f1d68SJussi Laako if (status1 & SND_RME_CLK_AES_SYNC) 1954d39f1d68SJussi Laako idx = SND_RME_CLOCK_SYNC; 1955d39f1d68SJussi Laako else if (status1 & SND_RME_CLK_AES_LOCK) 1956d39f1d68SJussi Laako idx = SND_RME_CLOCK_LOCK; 1957d39f1d68SJussi Laako break; 1958d39f1d68SJussi Laako case SND_RME_DOMAIN_SPDIF: /* SPDIF */ 1959d39f1d68SJussi Laako if (status1 & SND_RME_CLK_SPDIF_SYNC) 1960d39f1d68SJussi Laako idx = SND_RME_CLOCK_SYNC; 1961d39f1d68SJussi Laako else if (status1 & SND_RME_CLK_SPDIF_LOCK) 1962d39f1d68SJussi Laako idx = SND_RME_CLOCK_LOCK; 1963d39f1d68SJussi Laako break; 1964d39f1d68SJussi Laako default: 1965d39f1d68SJussi Laako return -EINVAL; 1966d39f1d68SJussi Laako } 1967d39f1d68SJussi Laako ucontrol->value.enumerated.item[0] = idx; 1968d39f1d68SJussi Laako return 0; 1969d39f1d68SJussi Laako } 1970d39f1d68SJussi Laako 1971d39f1d68SJussi Laako static int snd_rme_spdif_if_get(struct snd_kcontrol *kcontrol, 1972d39f1d68SJussi Laako struct snd_ctl_elem_value *ucontrol) 1973d39f1d68SJussi Laako { 1974d39f1d68SJussi Laako u32 status1; 1975d39f1d68SJussi Laako int err; 1976d39f1d68SJussi Laako 1977d39f1d68SJussi Laako err = snd_rme_get_status1(kcontrol, &status1); 1978d39f1d68SJussi Laako if (err < 0) 1979d39f1d68SJussi Laako return err; 1980d39f1d68SJussi Laako ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_IF(status1); 1981d39f1d68SJussi Laako return 0; 1982d39f1d68SJussi Laako } 1983d39f1d68SJussi Laako 1984d39f1d68SJussi Laako static int snd_rme_spdif_format_get(struct snd_kcontrol *kcontrol, 1985d39f1d68SJussi Laako struct snd_ctl_elem_value *ucontrol) 1986d39f1d68SJussi Laako { 1987d39f1d68SJussi Laako u32 status1; 1988d39f1d68SJussi Laako int err; 1989d39f1d68SJussi Laako 1990d39f1d68SJussi Laako err = snd_rme_get_status1(kcontrol, &status1); 1991d39f1d68SJussi Laako if (err < 0) 1992d39f1d68SJussi Laako return err; 1993d39f1d68SJussi Laako ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_FORMAT(status1); 1994d39f1d68SJussi Laako return 0; 1995d39f1d68SJussi Laako } 1996d39f1d68SJussi Laako 1997d39f1d68SJussi Laako static int snd_rme_sync_source_get(struct snd_kcontrol *kcontrol, 1998d39f1d68SJussi Laako struct snd_ctl_elem_value *ucontrol) 1999d39f1d68SJussi Laako { 2000d39f1d68SJussi Laako u32 status1; 2001d39f1d68SJussi Laako int err; 2002d39f1d68SJussi Laako 2003d39f1d68SJussi Laako err = snd_rme_get_status1(kcontrol, &status1); 2004d39f1d68SJussi Laako if (err < 0) 2005d39f1d68SJussi Laako return err; 2006d39f1d68SJussi Laako ucontrol->value.enumerated.item[0] = SND_RME_CLK_SYNC(status1); 2007d39f1d68SJussi Laako return 0; 2008d39f1d68SJussi Laako } 2009d39f1d68SJussi Laako 2010d39f1d68SJussi Laako static int snd_rme_current_freq_get(struct snd_kcontrol *kcontrol, 2011d39f1d68SJussi Laako struct snd_ctl_elem_value *ucontrol) 2012d39f1d68SJussi Laako { 2013d39f1d68SJussi Laako struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 2014d39f1d68SJussi Laako struct snd_usb_audio *chip = list->mixer->chip; 2015d39f1d68SJussi Laako u32 status1; 2016d39f1d68SJussi Laako const u64 num = 104857600000000ULL; 2017d39f1d68SJussi Laako u32 den; 2018d39f1d68SJussi Laako unsigned int freq; 2019d39f1d68SJussi Laako int err; 2020d39f1d68SJussi Laako 2021d39f1d68SJussi Laako err = snd_usb_lock_shutdown(chip); 2022d39f1d68SJussi Laako if (err < 0) 2023d39f1d68SJussi Laako return err; 2024d39f1d68SJussi Laako err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, &status1); 2025d39f1d68SJussi Laako if (err < 0) 2026d39f1d68SJussi Laako goto end; 2027d39f1d68SJussi Laako err = snd_rme_read_value(chip, SND_RME_GET_CURRENT_FREQ, &den); 2028d39f1d68SJussi Laako if (err < 0) 2029d39f1d68SJussi Laako goto end; 2030d39f1d68SJussi Laako freq = (den == 0) ? 0 : div64_u64(num, den); 2031d39f1d68SJussi Laako freq <<= SND_RME_CLK_FREQMUL(status1); 2032d39f1d68SJussi Laako ucontrol->value.integer.value[0] = freq; 2033d39f1d68SJussi Laako 2034d39f1d68SJussi Laako end: 2035d39f1d68SJussi Laako snd_usb_unlock_shutdown(chip); 2036d39f1d68SJussi Laako return err; 2037d39f1d68SJussi Laako } 2038d39f1d68SJussi Laako 2039d39f1d68SJussi Laako static int snd_rme_rate_info(struct snd_kcontrol *kcontrol, 2040d39f1d68SJussi Laako struct snd_ctl_elem_info *uinfo) 2041d39f1d68SJussi Laako { 2042d39f1d68SJussi Laako uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2043d39f1d68SJussi Laako uinfo->count = 1; 2044d39f1d68SJussi Laako switch (kcontrol->private_value) { 2045d39f1d68SJussi Laako case SND_RME_DOMAIN_SYSTEM: 2046d39f1d68SJussi Laako uinfo->value.integer.min = 32000; 2047d39f1d68SJussi Laako uinfo->value.integer.max = 800000; 2048d39f1d68SJussi Laako break; 2049d39f1d68SJussi Laako case SND_RME_DOMAIN_AES: 2050d39f1d68SJussi Laako case SND_RME_DOMAIN_SPDIF: 2051d39f1d68SJussi Laako default: 2052d39f1d68SJussi Laako uinfo->value.integer.min = 0; 2053d39f1d68SJussi Laako uinfo->value.integer.max = 200000; 2054d39f1d68SJussi Laako } 2055d39f1d68SJussi Laako uinfo->value.integer.step = 0; 2056d39f1d68SJussi Laako return 0; 2057d39f1d68SJussi Laako } 2058d39f1d68SJussi Laako 2059d39f1d68SJussi Laako static int snd_rme_sync_state_info(struct snd_kcontrol *kcontrol, 2060d39f1d68SJussi Laako struct snd_ctl_elem_info *uinfo) 2061d39f1d68SJussi Laako { 2062d39f1d68SJussi Laako static const char *const sync_states[] = { 2063d39f1d68SJussi Laako "No Lock", "Lock", "Sync" 2064d39f1d68SJussi Laako }; 2065d39f1d68SJussi Laako 2066d39f1d68SJussi Laako return snd_ctl_enum_info(uinfo, 1, 2067d39f1d68SJussi Laako ARRAY_SIZE(sync_states), sync_states); 2068d39f1d68SJussi Laako } 2069d39f1d68SJussi Laako 2070d39f1d68SJussi Laako static int snd_rme_spdif_if_info(struct snd_kcontrol *kcontrol, 2071d39f1d68SJussi Laako struct snd_ctl_elem_info *uinfo) 2072d39f1d68SJussi Laako { 2073d39f1d68SJussi Laako static const char *const spdif_if[] = { 2074d39f1d68SJussi Laako "Coaxial", "Optical" 2075d39f1d68SJussi Laako }; 2076d39f1d68SJussi Laako 2077d39f1d68SJussi Laako return snd_ctl_enum_info(uinfo, 1, 2078d39f1d68SJussi Laako ARRAY_SIZE(spdif_if), spdif_if); 2079d39f1d68SJussi Laako } 2080d39f1d68SJussi Laako 2081d39f1d68SJussi Laako static int snd_rme_spdif_format_info(struct snd_kcontrol *kcontrol, 2082d39f1d68SJussi Laako struct snd_ctl_elem_info *uinfo) 2083d39f1d68SJussi Laako { 2084d39f1d68SJussi Laako static const char *const optical_type[] = { 2085d39f1d68SJussi Laako "Consumer", "Professional" 2086d39f1d68SJussi Laako }; 2087d39f1d68SJussi Laako 2088d39f1d68SJussi Laako return snd_ctl_enum_info(uinfo, 1, 2089d39f1d68SJussi Laako ARRAY_SIZE(optical_type), optical_type); 2090d39f1d68SJussi Laako } 2091d39f1d68SJussi Laako 2092d39f1d68SJussi Laako static int snd_rme_sync_source_info(struct snd_kcontrol *kcontrol, 2093d39f1d68SJussi Laako struct snd_ctl_elem_info *uinfo) 2094d39f1d68SJussi Laako { 2095d39f1d68SJussi Laako static const char *const sync_sources[] = { 2096d39f1d68SJussi Laako "Internal", "AES", "SPDIF", "Internal" 2097d39f1d68SJussi Laako }; 2098d39f1d68SJussi Laako 2099d39f1d68SJussi Laako return snd_ctl_enum_info(uinfo, 1, 2100d39f1d68SJussi Laako ARRAY_SIZE(sync_sources), sync_sources); 2101d39f1d68SJussi Laako } 2102d39f1d68SJussi Laako 2103195727e8STakashi Iwai static const struct snd_kcontrol_new snd_rme_controls[] = { 2104d39f1d68SJussi Laako { 2105d39f1d68SJussi Laako .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2106d39f1d68SJussi Laako .name = "AES Rate", 2107d39f1d68SJussi Laako .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 2108d39f1d68SJussi Laako .info = snd_rme_rate_info, 2109d39f1d68SJussi Laako .get = snd_rme_rate_get, 2110d39f1d68SJussi Laako .private_value = SND_RME_DOMAIN_AES 2111d39f1d68SJussi Laako }, 2112d39f1d68SJussi Laako { 2113d39f1d68SJussi Laako .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2114d39f1d68SJussi Laako .name = "AES Sync", 2115d39f1d68SJussi Laako .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 2116d39f1d68SJussi Laako .info = snd_rme_sync_state_info, 2117d39f1d68SJussi Laako .get = snd_rme_sync_state_get, 2118d39f1d68SJussi Laako .private_value = SND_RME_DOMAIN_AES 2119d39f1d68SJussi Laako }, 2120d39f1d68SJussi Laako { 2121d39f1d68SJussi Laako .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2122d39f1d68SJussi Laako .name = "SPDIF Rate", 2123d39f1d68SJussi Laako .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 2124d39f1d68SJussi Laako .info = snd_rme_rate_info, 2125d39f1d68SJussi Laako .get = snd_rme_rate_get, 2126d39f1d68SJussi Laako .private_value = SND_RME_DOMAIN_SPDIF 2127d39f1d68SJussi Laako }, 2128d39f1d68SJussi Laako { 2129d39f1d68SJussi Laako .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2130d39f1d68SJussi Laako .name = "SPDIF Sync", 2131d39f1d68SJussi Laako .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 2132d39f1d68SJussi Laako .info = snd_rme_sync_state_info, 2133d39f1d68SJussi Laako .get = snd_rme_sync_state_get, 2134d39f1d68SJussi Laako .private_value = SND_RME_DOMAIN_SPDIF 2135d39f1d68SJussi Laako }, 2136d39f1d68SJussi Laako { 2137d39f1d68SJussi Laako .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2138d39f1d68SJussi Laako .name = "SPDIF Interface", 2139d39f1d68SJussi Laako .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 2140d39f1d68SJussi Laako .info = snd_rme_spdif_if_info, 2141d39f1d68SJussi Laako .get = snd_rme_spdif_if_get, 2142d39f1d68SJussi Laako }, 2143d39f1d68SJussi Laako { 2144d39f1d68SJussi Laako .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2145d39f1d68SJussi Laako .name = "SPDIF Format", 2146d39f1d68SJussi Laako .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 2147d39f1d68SJussi Laako .info = snd_rme_spdif_format_info, 2148d39f1d68SJussi Laako .get = snd_rme_spdif_format_get, 2149d39f1d68SJussi Laako }, 2150d39f1d68SJussi Laako { 2151d39f1d68SJussi Laako .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2152d39f1d68SJussi Laako .name = "Sync Source", 2153d39f1d68SJussi Laako .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 2154d39f1d68SJussi Laako .info = snd_rme_sync_source_info, 2155d39f1d68SJussi Laako .get = snd_rme_sync_source_get 2156d39f1d68SJussi Laako }, 2157d39f1d68SJussi Laako { 2158d39f1d68SJussi Laako .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2159d39f1d68SJussi Laako .name = "System Rate", 2160d39f1d68SJussi Laako .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 2161d39f1d68SJussi Laako .info = snd_rme_rate_info, 2162d39f1d68SJussi Laako .get = snd_rme_rate_get, 2163d39f1d68SJussi Laako .private_value = SND_RME_DOMAIN_SYSTEM 2164d39f1d68SJussi Laako }, 2165d39f1d68SJussi Laako { 2166d39f1d68SJussi Laako .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2167d39f1d68SJussi Laako .name = "Current Frequency", 2168d39f1d68SJussi Laako .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 2169d39f1d68SJussi Laako .info = snd_rme_rate_info, 2170d39f1d68SJussi Laako .get = snd_rme_current_freq_get 2171d39f1d68SJussi Laako } 2172d39f1d68SJussi Laako }; 2173d39f1d68SJussi Laako 2174d39f1d68SJussi Laako static int snd_rme_controls_create(struct usb_mixer_interface *mixer) 2175d39f1d68SJussi Laako { 2176d39f1d68SJussi Laako int err, i; 2177d39f1d68SJussi Laako 2178d39f1d68SJussi Laako for (i = 0; i < ARRAY_SIZE(snd_rme_controls); ++i) { 2179d39f1d68SJussi Laako err = add_single_ctl_with_resume(mixer, 0, 2180d39f1d68SJussi Laako NULL, 2181d39f1d68SJussi Laako &snd_rme_controls[i], 2182d39f1d68SJussi Laako NULL); 2183d39f1d68SJussi Laako if (err < 0) 2184d39f1d68SJussi Laako return err; 2185d39f1d68SJussi Laako } 2186d39f1d68SJussi Laako 2187d39f1d68SJussi Laako return 0; 2188d39f1d68SJussi Laako } 2189d39f1d68SJussi Laako 21903e8f3bd0SThomas Ebeling /* 21913e8f3bd0SThomas Ebeling * RME Babyface Pro (FS) 21923e8f3bd0SThomas Ebeling * 21933e8f3bd0SThomas Ebeling * These devices exposes a couple of DSP functions via request to EP0. 21943e8f3bd0SThomas Ebeling * Switches are available via control registers, while routing is controlled 21953e8f3bd0SThomas Ebeling * by controlling the volume on each possible crossing point. 219647b4f5f5SThomas Ebeling * Volume control is linear, from -inf (dec. 0) to +6dB (dec. 65536) with 21973e8f3bd0SThomas Ebeling * 0dB being at dec. 32768. 21983e8f3bd0SThomas Ebeling */ 21993e8f3bd0SThomas Ebeling enum { 22003e8f3bd0SThomas Ebeling SND_BBFPRO_CTL_REG1 = 0, 22013e8f3bd0SThomas Ebeling SND_BBFPRO_CTL_REG2 22023e8f3bd0SThomas Ebeling }; 22033e8f3bd0SThomas Ebeling 22043e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_REG_MASK 1 22053e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_IDX_MASK 0xff 22063e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_IDX_SHIFT 1 22073e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_VAL_MASK 1 22083e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_VAL_SHIFT 9 22093e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_REG1_CLK_MASTER 0 22103e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_REG1_CLK_OPTICAL 1 22113e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_REG1_SPDIF_PRO 7 22123e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_REG1_SPDIF_EMPH 8 22133e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_REG1_SPDIF_OPTICAL 10 22143e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_REG2_48V_AN1 0 22153e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_REG2_48V_AN2 1 22163e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_REG2_SENS_IN3 2 22173e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_REG2_SENS_IN4 3 22183e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_REG2_PAD_AN1 4 22193e8f3bd0SThomas Ebeling #define SND_BBFPRO_CTL_REG2_PAD_AN2 5 22203e8f3bd0SThomas Ebeling 22213e8f3bd0SThomas Ebeling #define SND_BBFPRO_MIXER_IDX_MASK 0x1ff 22223e8f3bd0SThomas Ebeling #define SND_BBFPRO_MIXER_VAL_MASK 0x3ffff 22233e8f3bd0SThomas Ebeling #define SND_BBFPRO_MIXER_VAL_SHIFT 9 22243e8f3bd0SThomas Ebeling #define SND_BBFPRO_MIXER_VAL_MIN 0 // -inf 222547b4f5f5SThomas Ebeling #define SND_BBFPRO_MIXER_VAL_MAX 65536 // +6dB 22263e8f3bd0SThomas Ebeling 22273e8f3bd0SThomas Ebeling #define SND_BBFPRO_USBREQ_CTL_REG1 0x10 22283e8f3bd0SThomas Ebeling #define SND_BBFPRO_USBREQ_CTL_REG2 0x17 22293e8f3bd0SThomas Ebeling #define SND_BBFPRO_USBREQ_MIXER 0x12 22303e8f3bd0SThomas Ebeling 22313e8f3bd0SThomas Ebeling static int snd_bbfpro_ctl_update(struct usb_mixer_interface *mixer, u8 reg, 22323e8f3bd0SThomas Ebeling u8 index, u8 value) 22333e8f3bd0SThomas Ebeling { 22343e8f3bd0SThomas Ebeling int err; 22353e8f3bd0SThomas Ebeling u16 usb_req, usb_idx, usb_val; 22363e8f3bd0SThomas Ebeling struct snd_usb_audio *chip = mixer->chip; 22373e8f3bd0SThomas Ebeling 22383e8f3bd0SThomas Ebeling err = snd_usb_lock_shutdown(chip); 22393e8f3bd0SThomas Ebeling if (err < 0) 22403e8f3bd0SThomas Ebeling return err; 22413e8f3bd0SThomas Ebeling 22423e8f3bd0SThomas Ebeling if (reg == SND_BBFPRO_CTL_REG1) { 22433e8f3bd0SThomas Ebeling usb_req = SND_BBFPRO_USBREQ_CTL_REG1; 22443e8f3bd0SThomas Ebeling if (index == SND_BBFPRO_CTL_REG1_CLK_OPTICAL) { 22453e8f3bd0SThomas Ebeling usb_idx = 3; 22463e8f3bd0SThomas Ebeling usb_val = value ? 3 : 0; 22473e8f3bd0SThomas Ebeling } else { 22483e8f3bd0SThomas Ebeling usb_idx = 1 << index; 22493e8f3bd0SThomas Ebeling usb_val = value ? usb_idx : 0; 22503e8f3bd0SThomas Ebeling } 22513e8f3bd0SThomas Ebeling } else { 22523e8f3bd0SThomas Ebeling usb_req = SND_BBFPRO_USBREQ_CTL_REG2; 22533e8f3bd0SThomas Ebeling usb_idx = 1 << index; 22543e8f3bd0SThomas Ebeling usb_val = value ? usb_idx : 0; 22553e8f3bd0SThomas Ebeling } 22563e8f3bd0SThomas Ebeling 22573e8f3bd0SThomas Ebeling err = snd_usb_ctl_msg(chip->dev, 22583e8f3bd0SThomas Ebeling usb_sndctrlpipe(chip->dev, 0), usb_req, 22593e8f3bd0SThomas Ebeling USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 2260f99e24a6SThomas Ebeling usb_val, usb_idx, NULL, 0); 22613e8f3bd0SThomas Ebeling 22623e8f3bd0SThomas Ebeling snd_usb_unlock_shutdown(chip); 22633e8f3bd0SThomas Ebeling return err; 22643e8f3bd0SThomas Ebeling } 22653e8f3bd0SThomas Ebeling 22663e8f3bd0SThomas Ebeling static int snd_bbfpro_ctl_get(struct snd_kcontrol *kcontrol, 22673e8f3bd0SThomas Ebeling struct snd_ctl_elem_value *ucontrol) 22683e8f3bd0SThomas Ebeling { 22693e8f3bd0SThomas Ebeling u8 reg, idx, val; 22703e8f3bd0SThomas Ebeling int pv; 22713e8f3bd0SThomas Ebeling 22723e8f3bd0SThomas Ebeling pv = kcontrol->private_value; 22733e8f3bd0SThomas Ebeling reg = pv & SND_BBFPRO_CTL_REG_MASK; 22743e8f3bd0SThomas Ebeling idx = (pv >> SND_BBFPRO_CTL_IDX_SHIFT) & SND_BBFPRO_CTL_IDX_MASK; 22753e8f3bd0SThomas Ebeling val = kcontrol->private_value >> SND_BBFPRO_CTL_VAL_SHIFT; 22763e8f3bd0SThomas Ebeling 22773e8f3bd0SThomas Ebeling if ((reg == SND_BBFPRO_CTL_REG1 && 22783e8f3bd0SThomas Ebeling idx == SND_BBFPRO_CTL_REG1_CLK_OPTICAL) || 22793e8f3bd0SThomas Ebeling (reg == SND_BBFPRO_CTL_REG2 && 22803e8f3bd0SThomas Ebeling (idx == SND_BBFPRO_CTL_REG2_SENS_IN3 || 22813e8f3bd0SThomas Ebeling idx == SND_BBFPRO_CTL_REG2_SENS_IN4))) { 22823e8f3bd0SThomas Ebeling ucontrol->value.enumerated.item[0] = val; 22833e8f3bd0SThomas Ebeling } else { 22843e8f3bd0SThomas Ebeling ucontrol->value.integer.value[0] = val; 22853e8f3bd0SThomas Ebeling } 22863e8f3bd0SThomas Ebeling return 0; 22873e8f3bd0SThomas Ebeling } 22883e8f3bd0SThomas Ebeling 22893e8f3bd0SThomas Ebeling static int snd_bbfpro_ctl_info(struct snd_kcontrol *kcontrol, 22903e8f3bd0SThomas Ebeling struct snd_ctl_elem_info *uinfo) 22913e8f3bd0SThomas Ebeling { 22923e8f3bd0SThomas Ebeling u8 reg, idx; 22933e8f3bd0SThomas Ebeling int pv; 22943e8f3bd0SThomas Ebeling 22953e8f3bd0SThomas Ebeling pv = kcontrol->private_value; 22963e8f3bd0SThomas Ebeling reg = pv & SND_BBFPRO_CTL_REG_MASK; 22973e8f3bd0SThomas Ebeling idx = (pv >> SND_BBFPRO_CTL_IDX_SHIFT) & SND_BBFPRO_CTL_IDX_MASK; 22983e8f3bd0SThomas Ebeling 22993e8f3bd0SThomas Ebeling if (reg == SND_BBFPRO_CTL_REG1 && 23003e8f3bd0SThomas Ebeling idx == SND_BBFPRO_CTL_REG1_CLK_OPTICAL) { 23013e8f3bd0SThomas Ebeling static const char * const texts[2] = { 23023e8f3bd0SThomas Ebeling "AutoSync", 23033e8f3bd0SThomas Ebeling "Internal" 23043e8f3bd0SThomas Ebeling }; 23053e8f3bd0SThomas Ebeling return snd_ctl_enum_info(uinfo, 1, 2, texts); 23063e8f3bd0SThomas Ebeling } else if (reg == SND_BBFPRO_CTL_REG2 && 23073e8f3bd0SThomas Ebeling (idx == SND_BBFPRO_CTL_REG2_SENS_IN3 || 23083e8f3bd0SThomas Ebeling idx == SND_BBFPRO_CTL_REG2_SENS_IN4)) { 23093e8f3bd0SThomas Ebeling static const char * const texts[2] = { 23103e8f3bd0SThomas Ebeling "-10dBV", 23113e8f3bd0SThomas Ebeling "+4dBu" 23123e8f3bd0SThomas Ebeling }; 23133e8f3bd0SThomas Ebeling return snd_ctl_enum_info(uinfo, 1, 2, texts); 23143e8f3bd0SThomas Ebeling } 23153e8f3bd0SThomas Ebeling 23163e8f3bd0SThomas Ebeling uinfo->count = 1; 23173e8f3bd0SThomas Ebeling uinfo->value.integer.min = 0; 23183e8f3bd0SThomas Ebeling uinfo->value.integer.max = 1; 23193e8f3bd0SThomas Ebeling uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 23203e8f3bd0SThomas Ebeling return 0; 23213e8f3bd0SThomas Ebeling } 23223e8f3bd0SThomas Ebeling 23233e8f3bd0SThomas Ebeling static int snd_bbfpro_ctl_put(struct snd_kcontrol *kcontrol, 23243e8f3bd0SThomas Ebeling struct snd_ctl_elem_value *ucontrol) 23253e8f3bd0SThomas Ebeling { 23263e8f3bd0SThomas Ebeling int err; 23273e8f3bd0SThomas Ebeling u8 reg, idx; 23283e8f3bd0SThomas Ebeling int old_value, pv, val; 23293e8f3bd0SThomas Ebeling 23303e8f3bd0SThomas Ebeling struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 23313e8f3bd0SThomas Ebeling struct usb_mixer_interface *mixer = list->mixer; 23323e8f3bd0SThomas Ebeling 23333e8f3bd0SThomas Ebeling pv = kcontrol->private_value; 23343e8f3bd0SThomas Ebeling reg = pv & SND_BBFPRO_CTL_REG_MASK; 23353e8f3bd0SThomas Ebeling idx = (pv >> SND_BBFPRO_CTL_IDX_SHIFT) & SND_BBFPRO_CTL_IDX_MASK; 23363e8f3bd0SThomas Ebeling old_value = (pv >> SND_BBFPRO_CTL_VAL_SHIFT) & SND_BBFPRO_CTL_VAL_MASK; 23373e8f3bd0SThomas Ebeling 23383e8f3bd0SThomas Ebeling if ((reg == SND_BBFPRO_CTL_REG1 && 23393e8f3bd0SThomas Ebeling idx == SND_BBFPRO_CTL_REG1_CLK_OPTICAL) || 23403e8f3bd0SThomas Ebeling (reg == SND_BBFPRO_CTL_REG2 && 23413e8f3bd0SThomas Ebeling (idx == SND_BBFPRO_CTL_REG2_SENS_IN3 || 23423e8f3bd0SThomas Ebeling idx == SND_BBFPRO_CTL_REG2_SENS_IN4))) { 23433e8f3bd0SThomas Ebeling val = ucontrol->value.enumerated.item[0]; 23443e8f3bd0SThomas Ebeling } else { 23453e8f3bd0SThomas Ebeling val = ucontrol->value.integer.value[0]; 23463e8f3bd0SThomas Ebeling } 23473e8f3bd0SThomas Ebeling 23483e8f3bd0SThomas Ebeling if (val > 1) 23493e8f3bd0SThomas Ebeling return -EINVAL; 23503e8f3bd0SThomas Ebeling 23513e8f3bd0SThomas Ebeling if (val == old_value) 23523e8f3bd0SThomas Ebeling return 0; 23533e8f3bd0SThomas Ebeling 23543e8f3bd0SThomas Ebeling kcontrol->private_value = reg 23553e8f3bd0SThomas Ebeling | ((idx & SND_BBFPRO_CTL_IDX_MASK) << SND_BBFPRO_CTL_IDX_SHIFT) 23563e8f3bd0SThomas Ebeling | ((val & SND_BBFPRO_CTL_VAL_MASK) << SND_BBFPRO_CTL_VAL_SHIFT); 23573e8f3bd0SThomas Ebeling 23583e8f3bd0SThomas Ebeling err = snd_bbfpro_ctl_update(mixer, reg, idx, val); 23593e8f3bd0SThomas Ebeling return err < 0 ? err : 1; 23603e8f3bd0SThomas Ebeling } 23613e8f3bd0SThomas Ebeling 23623e8f3bd0SThomas Ebeling static int snd_bbfpro_ctl_resume(struct usb_mixer_elem_list *list) 23633e8f3bd0SThomas Ebeling { 23643e8f3bd0SThomas Ebeling u8 reg, idx; 23653e8f3bd0SThomas Ebeling int value, pv; 23663e8f3bd0SThomas Ebeling 23673e8f3bd0SThomas Ebeling pv = list->kctl->private_value; 23683e8f3bd0SThomas Ebeling reg = pv & SND_BBFPRO_CTL_REG_MASK; 23693e8f3bd0SThomas Ebeling idx = (pv >> SND_BBFPRO_CTL_IDX_SHIFT) & SND_BBFPRO_CTL_IDX_MASK; 23703e8f3bd0SThomas Ebeling value = (pv >> SND_BBFPRO_CTL_VAL_SHIFT) & SND_BBFPRO_CTL_VAL_MASK; 23713e8f3bd0SThomas Ebeling 23723e8f3bd0SThomas Ebeling return snd_bbfpro_ctl_update(list->mixer, reg, idx, value); 23733e8f3bd0SThomas Ebeling } 23743e8f3bd0SThomas Ebeling 23753e8f3bd0SThomas Ebeling static int snd_bbfpro_vol_update(struct usb_mixer_interface *mixer, u16 index, 23763e8f3bd0SThomas Ebeling u32 value) 23773e8f3bd0SThomas Ebeling { 23783e8f3bd0SThomas Ebeling struct snd_usb_audio *chip = mixer->chip; 23793e8f3bd0SThomas Ebeling int err; 23803e8f3bd0SThomas Ebeling u16 idx; 23813e8f3bd0SThomas Ebeling u16 usb_idx, usb_val; 23823e8f3bd0SThomas Ebeling u32 v; 23833e8f3bd0SThomas Ebeling 23843e8f3bd0SThomas Ebeling err = snd_usb_lock_shutdown(chip); 23853e8f3bd0SThomas Ebeling if (err < 0) 23863e8f3bd0SThomas Ebeling return err; 23873e8f3bd0SThomas Ebeling 23883e8f3bd0SThomas Ebeling idx = index & SND_BBFPRO_MIXER_IDX_MASK; 23893e8f3bd0SThomas Ebeling // 18 bit linear volume, split so 2 bits end up in index. 23903e8f3bd0SThomas Ebeling v = value & SND_BBFPRO_MIXER_VAL_MASK; 23913e8f3bd0SThomas Ebeling usb_idx = idx | (v & 0x3) << 14; 23923e8f3bd0SThomas Ebeling usb_val = (v >> 2) & 0xffff; 23933e8f3bd0SThomas Ebeling 23943e8f3bd0SThomas Ebeling err = snd_usb_ctl_msg(chip->dev, 23953e8f3bd0SThomas Ebeling usb_sndctrlpipe(chip->dev, 0), 23963e8f3bd0SThomas Ebeling SND_BBFPRO_USBREQ_MIXER, 23973e8f3bd0SThomas Ebeling USB_DIR_OUT | USB_TYPE_VENDOR | 23983e8f3bd0SThomas Ebeling USB_RECIP_DEVICE, 2399f99e24a6SThomas Ebeling usb_val, usb_idx, NULL, 0); 24003e8f3bd0SThomas Ebeling 24013e8f3bd0SThomas Ebeling snd_usb_unlock_shutdown(chip); 24023e8f3bd0SThomas Ebeling return err; 24033e8f3bd0SThomas Ebeling } 24043e8f3bd0SThomas Ebeling 24053e8f3bd0SThomas Ebeling static int snd_bbfpro_vol_get(struct snd_kcontrol *kcontrol, 24063e8f3bd0SThomas Ebeling struct snd_ctl_elem_value *ucontrol) 24073e8f3bd0SThomas Ebeling { 24083e8f3bd0SThomas Ebeling ucontrol->value.integer.value[0] = 24093e8f3bd0SThomas Ebeling kcontrol->private_value >> SND_BBFPRO_MIXER_VAL_SHIFT; 24103e8f3bd0SThomas Ebeling return 0; 24113e8f3bd0SThomas Ebeling } 24123e8f3bd0SThomas Ebeling 24133e8f3bd0SThomas Ebeling static int snd_bbfpro_vol_info(struct snd_kcontrol *kcontrol, 24143e8f3bd0SThomas Ebeling struct snd_ctl_elem_info *uinfo) 24153e8f3bd0SThomas Ebeling { 24163e8f3bd0SThomas Ebeling uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 24173e8f3bd0SThomas Ebeling uinfo->count = 1; 24183e8f3bd0SThomas Ebeling uinfo->value.integer.min = SND_BBFPRO_MIXER_VAL_MIN; 24193e8f3bd0SThomas Ebeling uinfo->value.integer.max = SND_BBFPRO_MIXER_VAL_MAX; 24203e8f3bd0SThomas Ebeling return 0; 24213e8f3bd0SThomas Ebeling } 24223e8f3bd0SThomas Ebeling 24233e8f3bd0SThomas Ebeling static int snd_bbfpro_vol_put(struct snd_kcontrol *kcontrol, 24243e8f3bd0SThomas Ebeling struct snd_ctl_elem_value *ucontrol) 24253e8f3bd0SThomas Ebeling { 24263e8f3bd0SThomas Ebeling int err; 24273e8f3bd0SThomas Ebeling u16 idx; 24283e8f3bd0SThomas Ebeling u32 new_val, old_value, uvalue; 24293e8f3bd0SThomas Ebeling struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 24303e8f3bd0SThomas Ebeling struct usb_mixer_interface *mixer = list->mixer; 24313e8f3bd0SThomas Ebeling 24323e8f3bd0SThomas Ebeling uvalue = ucontrol->value.integer.value[0]; 24333e8f3bd0SThomas Ebeling idx = kcontrol->private_value & SND_BBFPRO_MIXER_IDX_MASK; 24343e8f3bd0SThomas Ebeling old_value = kcontrol->private_value >> SND_BBFPRO_MIXER_VAL_SHIFT; 24353e8f3bd0SThomas Ebeling 24363e8f3bd0SThomas Ebeling if (uvalue > SND_BBFPRO_MIXER_VAL_MAX) 24373e8f3bd0SThomas Ebeling return -EINVAL; 24383e8f3bd0SThomas Ebeling 24393e8f3bd0SThomas Ebeling if (uvalue == old_value) 24403e8f3bd0SThomas Ebeling return 0; 24413e8f3bd0SThomas Ebeling 24423e8f3bd0SThomas Ebeling new_val = uvalue & SND_BBFPRO_MIXER_VAL_MASK; 24433e8f3bd0SThomas Ebeling 24443e8f3bd0SThomas Ebeling kcontrol->private_value = idx 24453e8f3bd0SThomas Ebeling | (new_val << SND_BBFPRO_MIXER_VAL_SHIFT); 24463e8f3bd0SThomas Ebeling 24473e8f3bd0SThomas Ebeling err = snd_bbfpro_vol_update(mixer, idx, new_val); 24483e8f3bd0SThomas Ebeling return err < 0 ? err : 1; 24493e8f3bd0SThomas Ebeling } 24503e8f3bd0SThomas Ebeling 24513e8f3bd0SThomas Ebeling static int snd_bbfpro_vol_resume(struct usb_mixer_elem_list *list) 24523e8f3bd0SThomas Ebeling { 24533e8f3bd0SThomas Ebeling int pv = list->kctl->private_value; 24543e8f3bd0SThomas Ebeling u16 idx = pv & SND_BBFPRO_MIXER_IDX_MASK; 24553e8f3bd0SThomas Ebeling u32 val = (pv >> SND_BBFPRO_MIXER_VAL_SHIFT) 24563e8f3bd0SThomas Ebeling & SND_BBFPRO_MIXER_VAL_MASK; 24573e8f3bd0SThomas Ebeling return snd_bbfpro_vol_update(list->mixer, idx, val); 24583e8f3bd0SThomas Ebeling } 24593e8f3bd0SThomas Ebeling 24603e8f3bd0SThomas Ebeling // Predfine elements 24613e8f3bd0SThomas Ebeling static const struct snd_kcontrol_new snd_bbfpro_ctl_control = { 24623e8f3bd0SThomas Ebeling .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 24633e8f3bd0SThomas Ebeling .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 24643e8f3bd0SThomas Ebeling .index = 0, 24653e8f3bd0SThomas Ebeling .info = snd_bbfpro_ctl_info, 24663e8f3bd0SThomas Ebeling .get = snd_bbfpro_ctl_get, 24673e8f3bd0SThomas Ebeling .put = snd_bbfpro_ctl_put 24683e8f3bd0SThomas Ebeling }; 24693e8f3bd0SThomas Ebeling 24703e8f3bd0SThomas Ebeling static const struct snd_kcontrol_new snd_bbfpro_vol_control = { 24713e8f3bd0SThomas Ebeling .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 24723e8f3bd0SThomas Ebeling .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 24733e8f3bd0SThomas Ebeling .index = 0, 24743e8f3bd0SThomas Ebeling .info = snd_bbfpro_vol_info, 24753e8f3bd0SThomas Ebeling .get = snd_bbfpro_vol_get, 24763e8f3bd0SThomas Ebeling .put = snd_bbfpro_vol_put 24773e8f3bd0SThomas Ebeling }; 24783e8f3bd0SThomas Ebeling 24793e8f3bd0SThomas Ebeling static int snd_bbfpro_ctl_add(struct usb_mixer_interface *mixer, u8 reg, 24803e8f3bd0SThomas Ebeling u8 index, char *name) 24813e8f3bd0SThomas Ebeling { 24823e8f3bd0SThomas Ebeling struct snd_kcontrol_new knew = snd_bbfpro_ctl_control; 24833e8f3bd0SThomas Ebeling 24843e8f3bd0SThomas Ebeling knew.name = name; 24853e8f3bd0SThomas Ebeling knew.private_value = (reg & SND_BBFPRO_CTL_REG_MASK) 24863e8f3bd0SThomas Ebeling | ((index & SND_BBFPRO_CTL_IDX_MASK) 24873e8f3bd0SThomas Ebeling << SND_BBFPRO_CTL_IDX_SHIFT); 24883e8f3bd0SThomas Ebeling 24893e8f3bd0SThomas Ebeling return add_single_ctl_with_resume(mixer, 0, snd_bbfpro_ctl_resume, 24903e8f3bd0SThomas Ebeling &knew, NULL); 24913e8f3bd0SThomas Ebeling } 24923e8f3bd0SThomas Ebeling 24933e8f3bd0SThomas Ebeling static int snd_bbfpro_vol_add(struct usb_mixer_interface *mixer, u16 index, 24943e8f3bd0SThomas Ebeling char *name) 24953e8f3bd0SThomas Ebeling { 24963e8f3bd0SThomas Ebeling struct snd_kcontrol_new knew = snd_bbfpro_vol_control; 24973e8f3bd0SThomas Ebeling 24983e8f3bd0SThomas Ebeling knew.name = name; 24993e8f3bd0SThomas Ebeling knew.private_value = index & SND_BBFPRO_MIXER_IDX_MASK; 25003e8f3bd0SThomas Ebeling 25013e8f3bd0SThomas Ebeling return add_single_ctl_with_resume(mixer, 0, snd_bbfpro_vol_resume, 25023e8f3bd0SThomas Ebeling &knew, NULL); 25033e8f3bd0SThomas Ebeling } 25043e8f3bd0SThomas Ebeling 25053e8f3bd0SThomas Ebeling static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) 25063e8f3bd0SThomas Ebeling { 25073e8f3bd0SThomas Ebeling int err, i, o; 25083e8f3bd0SThomas Ebeling char name[48]; 25093e8f3bd0SThomas Ebeling 25103e8f3bd0SThomas Ebeling static const char * const input[] = { 25113e8f3bd0SThomas Ebeling "AN1", "AN2", "IN3", "IN4", "AS1", "AS2", "ADAT3", 25123e8f3bd0SThomas Ebeling "ADAT4", "ADAT5", "ADAT6", "ADAT7", "ADAT8"}; 25133e8f3bd0SThomas Ebeling 25143e8f3bd0SThomas Ebeling static const char * const output[] = { 25153e8f3bd0SThomas Ebeling "AN1", "AN2", "PH3", "PH4", "AS1", "AS2", "ADAT3", "ADAT4", 25163e8f3bd0SThomas Ebeling "ADAT5", "ADAT6", "ADAT7", "ADAT8"}; 25173e8f3bd0SThomas Ebeling 25183e8f3bd0SThomas Ebeling for (o = 0 ; o < 12 ; ++o) { 25193e8f3bd0SThomas Ebeling for (i = 0 ; i < 12 ; ++i) { 25203e8f3bd0SThomas Ebeling // Line routing 25213e8f3bd0SThomas Ebeling snprintf(name, sizeof(name), 25223e8f3bd0SThomas Ebeling "%s-%s-%s Playback Volume", 25233e8f3bd0SThomas Ebeling (i < 2 ? "Mic" : "Line"), 25243e8f3bd0SThomas Ebeling input[i], output[o]); 25253e8f3bd0SThomas Ebeling err = snd_bbfpro_vol_add(mixer, (26 * o + i), name); 25263e8f3bd0SThomas Ebeling if (err < 0) 25273e8f3bd0SThomas Ebeling return err; 25283e8f3bd0SThomas Ebeling 25293e8f3bd0SThomas Ebeling // PCM routing... yes, it is output remapping 25303e8f3bd0SThomas Ebeling snprintf(name, sizeof(name), 25313e8f3bd0SThomas Ebeling "PCM-%s-%s Playback Volume", 25323e8f3bd0SThomas Ebeling output[i], output[o]); 25333e8f3bd0SThomas Ebeling err = snd_bbfpro_vol_add(mixer, (26 * o + 12 + i), 25343e8f3bd0SThomas Ebeling name); 25353e8f3bd0SThomas Ebeling if (err < 0) 25363e8f3bd0SThomas Ebeling return err; 25373e8f3bd0SThomas Ebeling } 25383e8f3bd0SThomas Ebeling } 25393e8f3bd0SThomas Ebeling 25403e8f3bd0SThomas Ebeling // Control Reg 1 25413e8f3bd0SThomas Ebeling err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG1, 25423e8f3bd0SThomas Ebeling SND_BBFPRO_CTL_REG1_CLK_OPTICAL, 25433e8f3bd0SThomas Ebeling "Sample Clock Source"); 25443e8f3bd0SThomas Ebeling if (err < 0) 25453e8f3bd0SThomas Ebeling return err; 25463e8f3bd0SThomas Ebeling 25473e8f3bd0SThomas Ebeling err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG1, 25483e8f3bd0SThomas Ebeling SND_BBFPRO_CTL_REG1_SPDIF_PRO, 25493e8f3bd0SThomas Ebeling "IEC958 Pro Mask"); 25503e8f3bd0SThomas Ebeling if (err < 0) 25513e8f3bd0SThomas Ebeling return err; 25523e8f3bd0SThomas Ebeling 25533e8f3bd0SThomas Ebeling err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG1, 25543e8f3bd0SThomas Ebeling SND_BBFPRO_CTL_REG1_SPDIF_EMPH, 25553e8f3bd0SThomas Ebeling "IEC958 Emphasis"); 25563e8f3bd0SThomas Ebeling if (err < 0) 25573e8f3bd0SThomas Ebeling return err; 25583e8f3bd0SThomas Ebeling 25593e8f3bd0SThomas Ebeling err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG1, 25603e8f3bd0SThomas Ebeling SND_BBFPRO_CTL_REG1_SPDIF_OPTICAL, 25613e8f3bd0SThomas Ebeling "IEC958 Switch"); 25623e8f3bd0SThomas Ebeling if (err < 0) 25633e8f3bd0SThomas Ebeling return err; 25643e8f3bd0SThomas Ebeling 25653e8f3bd0SThomas Ebeling // Control Reg 2 25663e8f3bd0SThomas Ebeling err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, 25673e8f3bd0SThomas Ebeling SND_BBFPRO_CTL_REG2_48V_AN1, 25683e8f3bd0SThomas Ebeling "Mic-AN1 48V"); 25693e8f3bd0SThomas Ebeling if (err < 0) 25703e8f3bd0SThomas Ebeling return err; 25713e8f3bd0SThomas Ebeling 25723e8f3bd0SThomas Ebeling err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, 25733e8f3bd0SThomas Ebeling SND_BBFPRO_CTL_REG2_48V_AN2, 25743e8f3bd0SThomas Ebeling "Mic-AN2 48V"); 25753e8f3bd0SThomas Ebeling if (err < 0) 25763e8f3bd0SThomas Ebeling return err; 25773e8f3bd0SThomas Ebeling 25783e8f3bd0SThomas Ebeling err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, 25793e8f3bd0SThomas Ebeling SND_BBFPRO_CTL_REG2_SENS_IN3, 25803e8f3bd0SThomas Ebeling "Line-IN3 Sens."); 25813e8f3bd0SThomas Ebeling if (err < 0) 25823e8f3bd0SThomas Ebeling return err; 25833e8f3bd0SThomas Ebeling 25843e8f3bd0SThomas Ebeling err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, 25853e8f3bd0SThomas Ebeling SND_BBFPRO_CTL_REG2_SENS_IN4, 25863e8f3bd0SThomas Ebeling "Line-IN4 Sens."); 25873e8f3bd0SThomas Ebeling if (err < 0) 25883e8f3bd0SThomas Ebeling return err; 25893e8f3bd0SThomas Ebeling 25903e8f3bd0SThomas Ebeling err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, 25913e8f3bd0SThomas Ebeling SND_BBFPRO_CTL_REG2_PAD_AN1, 25923e8f3bd0SThomas Ebeling "Mic-AN1 PAD"); 25933e8f3bd0SThomas Ebeling if (err < 0) 25943e8f3bd0SThomas Ebeling return err; 25953e8f3bd0SThomas Ebeling 25963e8f3bd0SThomas Ebeling err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, 25973e8f3bd0SThomas Ebeling SND_BBFPRO_CTL_REG2_PAD_AN2, 25983e8f3bd0SThomas Ebeling "Mic-AN2 PAD"); 25993e8f3bd0SThomas Ebeling if (err < 0) 26003e8f3bd0SThomas Ebeling return err; 26013e8f3bd0SThomas Ebeling 26023e8f3bd0SThomas Ebeling return 0; 26033e8f3bd0SThomas Ebeling } 26043e8f3bd0SThomas Ebeling 2605cdc01a15SFrantišek Kučera /* 2606a07df82cSOlivia Mackintosh * Pioneer DJ DJM Mixers 2607cdc01a15SFrantišek Kučera * 2608a07df82cSOlivia Mackintosh * These devices generally have options for soft-switching the playback and 2609a07df82cSOlivia Mackintosh * capture sources in addition to the recording level. Although different 2610a07df82cSOlivia Mackintosh * devices have different configurations, there seems to be canonical values 2611a07df82cSOlivia Mackintosh * for specific capture/playback types: See the definitions of these below. 2612cdc01a15SFrantišek Kučera * 2613a07df82cSOlivia Mackintosh * The wValue is masked with the stereo channel number. e.g. Setting Ch2 to 2614a07df82cSOlivia Mackintosh * capture phono would be 0x0203. Capture, playback and capture level have 2615a07df82cSOlivia Mackintosh * different wIndexes. 2616cdc01a15SFrantišek Kučera */ 2617cdc01a15SFrantišek Kučera 2618a07df82cSOlivia Mackintosh // Capture types 2619a07df82cSOlivia Mackintosh #define SND_DJM_CAP_LINE 0x00 2620a07df82cSOlivia Mackintosh #define SND_DJM_CAP_CDLINE 0x01 2621fee03efcSFabian Lesniak #define SND_DJM_CAP_DIGITAL 0x02 2622a07df82cSOlivia Mackintosh #define SND_DJM_CAP_PHONO 0x03 2623a07df82cSOlivia Mackintosh #define SND_DJM_CAP_PFADER 0x06 2624a07df82cSOlivia Mackintosh #define SND_DJM_CAP_XFADERA 0x07 2625a07df82cSOlivia Mackintosh #define SND_DJM_CAP_XFADERB 0x08 2626a07df82cSOlivia Mackintosh #define SND_DJM_CAP_MIC 0x09 2627a07df82cSOlivia Mackintosh #define SND_DJM_CAP_AUX 0x0d 2628a07df82cSOlivia Mackintosh #define SND_DJM_CAP_RECOUT 0x0a 2629a07df82cSOlivia Mackintosh #define SND_DJM_CAP_NONE 0x0f 2630a07df82cSOlivia Mackintosh #define SND_DJM_CAP_CH1PFADER 0x11 2631a07df82cSOlivia Mackintosh #define SND_DJM_CAP_CH2PFADER 0x12 2632fee03efcSFabian Lesniak #define SND_DJM_CAP_CH3PFADER 0x13 2633fee03efcSFabian Lesniak #define SND_DJM_CAP_CH4PFADER 0x14 2634cdc01a15SFrantišek Kučera 2635a07df82cSOlivia Mackintosh // Playback types 2636a07df82cSOlivia Mackintosh #define SND_DJM_PB_CH1 0x00 2637a07df82cSOlivia Mackintosh #define SND_DJM_PB_CH2 0x01 2638a07df82cSOlivia Mackintosh #define SND_DJM_PB_AUX 0x04 2639cdc01a15SFrantišek Kučera 2640a07df82cSOlivia Mackintosh #define SND_DJM_WINDEX_CAP 0x8002 2641a07df82cSOlivia Mackintosh #define SND_DJM_WINDEX_CAPLVL 0x8003 2642a07df82cSOlivia Mackintosh #define SND_DJM_WINDEX_PB 0x8016 2643cdc01a15SFrantišek Kučera 2644a07df82cSOlivia Mackintosh // kcontrol->private_value layout 2645a07df82cSOlivia Mackintosh #define SND_DJM_VALUE_MASK 0x0000ffff 2646a07df82cSOlivia Mackintosh #define SND_DJM_GROUP_MASK 0x00ff0000 2647a07df82cSOlivia Mackintosh #define SND_DJM_DEVICE_MASK 0xff000000 2648a07df82cSOlivia Mackintosh #define SND_DJM_GROUP_SHIFT 16 2649a07df82cSOlivia Mackintosh #define SND_DJM_DEVICE_SHIFT 24 2650cdc01a15SFrantišek Kučera 2651a07df82cSOlivia Mackintosh // device table index 26527687850bSNicolas MURE // used for the snd_djm_devices table, so please update accordingly 2653a07df82cSOlivia Mackintosh #define SND_DJM_250MK2_IDX 0x0 2654a07df82cSOlivia Mackintosh #define SND_DJM_750_IDX 0x1 26557687850bSNicolas MURE #define SND_DJM_850_IDX 0x2 26567687850bSNicolas MURE #define SND_DJM_900NXS2_IDX 0x3 2657cdc01a15SFrantišek Kučera 2658cdc01a15SFrantišek Kučera 2659a07df82cSOlivia Mackintosh #define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \ 2660cdc01a15SFrantišek Kučera .name = _name, \ 2661a07df82cSOlivia Mackintosh .options = snd_djm_opts_##suffix, \ 2662a07df82cSOlivia Mackintosh .noptions = ARRAY_SIZE(snd_djm_opts_##suffix), \ 2663a07df82cSOlivia Mackintosh .default_value = _default_value, \ 2664a07df82cSOlivia Mackintosh .wIndex = _windex } 2665cdc01a15SFrantišek Kučera 2666a07df82cSOlivia Mackintosh #define SND_DJM_DEVICE(suffix) { \ 2667a07df82cSOlivia Mackintosh .controls = snd_djm_ctls_##suffix, \ 2668a07df82cSOlivia Mackintosh .ncontrols = ARRAY_SIZE(snd_djm_ctls_##suffix) } 2669a07df82cSOlivia Mackintosh 2670a07df82cSOlivia Mackintosh 2671a07df82cSOlivia Mackintosh struct snd_djm_device { 2672a07df82cSOlivia Mackintosh const char *name; 2673a07df82cSOlivia Mackintosh const struct snd_djm_ctl *controls; 2674a07df82cSOlivia Mackintosh size_t ncontrols; 2675cdc01a15SFrantišek Kučera }; 2676cdc01a15SFrantišek Kučera 2677a07df82cSOlivia Mackintosh struct snd_djm_ctl { 2678cdc01a15SFrantišek Kučera const char *name; 2679a07df82cSOlivia Mackintosh const u16 *options; 2680a07df82cSOlivia Mackintosh size_t noptions; 2681a07df82cSOlivia Mackintosh u16 default_value; 2682a07df82cSOlivia Mackintosh u16 wIndex; 2683a07df82cSOlivia Mackintosh }; 2684cdc01a15SFrantišek Kučera 2685a07df82cSOlivia Mackintosh static const char *snd_djm_get_label_caplevel(u16 wvalue) 2686a07df82cSOlivia Mackintosh { 2687a07df82cSOlivia Mackintosh switch (wvalue) { 2688a07df82cSOlivia Mackintosh case 0x0000: return "-19dB"; 2689a07df82cSOlivia Mackintosh case 0x0100: return "-15dB"; 2690a07df82cSOlivia Mackintosh case 0x0200: return "-10dB"; 2691a07df82cSOlivia Mackintosh case 0x0300: return "-5dB"; 2692a07df82cSOlivia Mackintosh default: return NULL; 2693a07df82cSOlivia Mackintosh } 2694a07df82cSOlivia Mackintosh }; 2695a07df82cSOlivia Mackintosh 2696b8db8be8SNicolas MURE static const char *snd_djm_get_label_cap_common(u16 wvalue) 2697a07df82cSOlivia Mackintosh { 2698a07df82cSOlivia Mackintosh switch (wvalue & 0x00ff) { 2699a07df82cSOlivia Mackintosh case SND_DJM_CAP_LINE: return "Control Tone LINE"; 2700a07df82cSOlivia Mackintosh case SND_DJM_CAP_CDLINE: return "Control Tone CD/LINE"; 2701fee03efcSFabian Lesniak case SND_DJM_CAP_DIGITAL: return "Control Tone DIGITAL"; 2702a07df82cSOlivia Mackintosh case SND_DJM_CAP_PHONO: return "Control Tone PHONO"; 2703a07df82cSOlivia Mackintosh case SND_DJM_CAP_PFADER: return "Post Fader"; 2704a07df82cSOlivia Mackintosh case SND_DJM_CAP_XFADERA: return "Cross Fader A"; 2705a07df82cSOlivia Mackintosh case SND_DJM_CAP_XFADERB: return "Cross Fader B"; 2706a07df82cSOlivia Mackintosh case SND_DJM_CAP_MIC: return "Mic"; 2707a07df82cSOlivia Mackintosh case SND_DJM_CAP_RECOUT: return "Rec Out"; 2708a07df82cSOlivia Mackintosh case SND_DJM_CAP_AUX: return "Aux"; 2709a07df82cSOlivia Mackintosh case SND_DJM_CAP_NONE: return "None"; 2710a07df82cSOlivia Mackintosh case SND_DJM_CAP_CH1PFADER: return "Post Fader Ch1"; 2711a07df82cSOlivia Mackintosh case SND_DJM_CAP_CH2PFADER: return "Post Fader Ch2"; 2712fee03efcSFabian Lesniak case SND_DJM_CAP_CH3PFADER: return "Post Fader Ch3"; 2713fee03efcSFabian Lesniak case SND_DJM_CAP_CH4PFADER: return "Post Fader Ch4"; 2714a07df82cSOlivia Mackintosh default: return NULL; 2715a07df82cSOlivia Mackintosh } 2716a07df82cSOlivia Mackintosh }; 2717a07df82cSOlivia Mackintosh 2718b8db8be8SNicolas MURE // The DJM-850 has different values for CD/LINE and LINE capture 2719b8db8be8SNicolas MURE // control options than the other DJM declared in this file. 2720b8db8be8SNicolas MURE static const char *snd_djm_get_label_cap_850(u16 wvalue) 2721b8db8be8SNicolas MURE { 2722b8db8be8SNicolas MURE switch (wvalue & 0x00ff) { 2723b8db8be8SNicolas MURE case 0x00: return "Control Tone CD/LINE"; 2724b8db8be8SNicolas MURE case 0x01: return "Control Tone LINE"; 2725b8db8be8SNicolas MURE default: return snd_djm_get_label_cap_common(wvalue); 2726b8db8be8SNicolas MURE } 2727b8db8be8SNicolas MURE }; 2728b8db8be8SNicolas MURE 2729b8db8be8SNicolas MURE static const char *snd_djm_get_label_cap(u8 device_idx, u16 wvalue) 2730b8db8be8SNicolas MURE { 2731b8db8be8SNicolas MURE switch (device_idx) { 2732b8db8be8SNicolas MURE case SND_DJM_850_IDX: return snd_djm_get_label_cap_850(wvalue); 2733b8db8be8SNicolas MURE default: return snd_djm_get_label_cap_common(wvalue); 2734b8db8be8SNicolas MURE } 2735b8db8be8SNicolas MURE }; 2736b8db8be8SNicolas MURE 2737a07df82cSOlivia Mackintosh static const char *snd_djm_get_label_pb(u16 wvalue) 2738a07df82cSOlivia Mackintosh { 2739a07df82cSOlivia Mackintosh switch (wvalue & 0x00ff) { 2740a07df82cSOlivia Mackintosh case SND_DJM_PB_CH1: return "Ch1"; 2741a07df82cSOlivia Mackintosh case SND_DJM_PB_CH2: return "Ch2"; 2742a07df82cSOlivia Mackintosh case SND_DJM_PB_AUX: return "Aux"; 2743a07df82cSOlivia Mackintosh default: return NULL; 2744a07df82cSOlivia Mackintosh } 2745a07df82cSOlivia Mackintosh }; 2746a07df82cSOlivia Mackintosh 2747b8db8be8SNicolas MURE static const char *snd_djm_get_label(u8 device_idx, u16 wvalue, u16 windex) 2748a07df82cSOlivia Mackintosh { 2749a07df82cSOlivia Mackintosh switch (windex) { 2750a07df82cSOlivia Mackintosh case SND_DJM_WINDEX_CAPLVL: return snd_djm_get_label_caplevel(wvalue); 2751b8db8be8SNicolas MURE case SND_DJM_WINDEX_CAP: return snd_djm_get_label_cap(device_idx, wvalue); 2752a07df82cSOlivia Mackintosh case SND_DJM_WINDEX_PB: return snd_djm_get_label_pb(wvalue); 2753a07df82cSOlivia Mackintosh default: return NULL; 2754a07df82cSOlivia Mackintosh } 2755a07df82cSOlivia Mackintosh }; 2756a07df82cSOlivia Mackintosh 27577687850bSNicolas MURE // common DJM capture level option values 2758a07df82cSOlivia Mackintosh static const u16 snd_djm_opts_cap_level[] = { 2759a07df82cSOlivia Mackintosh 0x0000, 0x0100, 0x0200, 0x0300 }; 2760a07df82cSOlivia Mackintosh 27617687850bSNicolas MURE 27627687850bSNicolas MURE // DJM-250MK2 2763a07df82cSOlivia Mackintosh static const u16 snd_djm_opts_250mk2_cap1[] = { 2764a07df82cSOlivia Mackintosh 0x0103, 0x0100, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d, 0x010a }; 2765a07df82cSOlivia Mackintosh 2766a07df82cSOlivia Mackintosh static const u16 snd_djm_opts_250mk2_cap2[] = { 2767a07df82cSOlivia Mackintosh 0x0203, 0x0200, 0x0206, 0x0207, 0x0208, 0x0209, 0x020d, 0x020a }; 2768a07df82cSOlivia Mackintosh 2769a07df82cSOlivia Mackintosh static const u16 snd_djm_opts_250mk2_cap3[] = { 2770a07df82cSOlivia Mackintosh 0x030a, 0x0311, 0x0312, 0x0307, 0x0308, 0x0309, 0x030d }; 2771a07df82cSOlivia Mackintosh 2772a07df82cSOlivia Mackintosh static const u16 snd_djm_opts_250mk2_pb1[] = { 0x0100, 0x0101, 0x0104 }; 2773a07df82cSOlivia Mackintosh static const u16 snd_djm_opts_250mk2_pb2[] = { 0x0200, 0x0201, 0x0204 }; 2774a07df82cSOlivia Mackintosh static const u16 snd_djm_opts_250mk2_pb3[] = { 0x0300, 0x0301, 0x0304 }; 2775a07df82cSOlivia Mackintosh 2776a07df82cSOlivia Mackintosh static const struct snd_djm_ctl snd_djm_ctls_250mk2[] = { 2777a07df82cSOlivia Mackintosh SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), 2778a07df82cSOlivia Mackintosh SND_DJM_CTL("Ch1 Input", 250mk2_cap1, 2, SND_DJM_WINDEX_CAP), 2779a07df82cSOlivia Mackintosh SND_DJM_CTL("Ch2 Input", 250mk2_cap2, 2, SND_DJM_WINDEX_CAP), 2780a07df82cSOlivia Mackintosh SND_DJM_CTL("Ch3 Input", 250mk2_cap3, 0, SND_DJM_WINDEX_CAP), 2781a07df82cSOlivia Mackintosh SND_DJM_CTL("Ch1 Output", 250mk2_pb1, 0, SND_DJM_WINDEX_PB), 2782a07df82cSOlivia Mackintosh SND_DJM_CTL("Ch2 Output", 250mk2_pb2, 1, SND_DJM_WINDEX_PB), 2783a07df82cSOlivia Mackintosh SND_DJM_CTL("Ch3 Output", 250mk2_pb3, 2, SND_DJM_WINDEX_PB) 2784a07df82cSOlivia Mackintosh }; 2785a07df82cSOlivia Mackintosh 2786a07df82cSOlivia Mackintosh 2787a07df82cSOlivia Mackintosh // DJM-750 2788a07df82cSOlivia Mackintosh static const u16 snd_djm_opts_750_cap1[] = { 2789a07df82cSOlivia Mackintosh 0x0101, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a, 0x010f }; 2790a07df82cSOlivia Mackintosh static const u16 snd_djm_opts_750_cap2[] = { 2791a07df82cSOlivia Mackintosh 0x0200, 0x0201, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020f }; 2792a07df82cSOlivia Mackintosh static const u16 snd_djm_opts_750_cap3[] = { 2793a07df82cSOlivia Mackintosh 0x0300, 0x0301, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030f }; 2794a07df82cSOlivia Mackintosh static const u16 snd_djm_opts_750_cap4[] = { 2795a07df82cSOlivia Mackintosh 0x0401, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f }; 2796a07df82cSOlivia Mackintosh 2797a07df82cSOlivia Mackintosh static const struct snd_djm_ctl snd_djm_ctls_750[] = { 2798a07df82cSOlivia Mackintosh SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), 2799a07df82cSOlivia Mackintosh SND_DJM_CTL("Ch1 Input", 750_cap1, 2, SND_DJM_WINDEX_CAP), 2800a07df82cSOlivia Mackintosh SND_DJM_CTL("Ch2 Input", 750_cap2, 2, SND_DJM_WINDEX_CAP), 2801a07df82cSOlivia Mackintosh SND_DJM_CTL("Ch3 Input", 750_cap3, 0, SND_DJM_WINDEX_CAP), 2802a07df82cSOlivia Mackintosh SND_DJM_CTL("Ch4 Input", 750_cap4, 0, SND_DJM_WINDEX_CAP) 2803a07df82cSOlivia Mackintosh }; 2804a07df82cSOlivia Mackintosh 2805a07df82cSOlivia Mackintosh 28067687850bSNicolas MURE // DJM-850 28077687850bSNicolas MURE static const u16 snd_djm_opts_850_cap1[] = { 28087687850bSNicolas MURE 0x0100, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a, 0x010f }; 28097687850bSNicolas MURE static const u16 snd_djm_opts_850_cap2[] = { 28107687850bSNicolas MURE 0x0200, 0x0201, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020f }; 28117687850bSNicolas MURE static const u16 snd_djm_opts_850_cap3[] = { 28127687850bSNicolas MURE 0x0300, 0x0301, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030f }; 28137687850bSNicolas MURE static const u16 snd_djm_opts_850_cap4[] = { 28147687850bSNicolas MURE 0x0400, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f }; 28157687850bSNicolas MURE 28167687850bSNicolas MURE static const struct snd_djm_ctl snd_djm_ctls_850[] = { 28177687850bSNicolas MURE SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), 28187687850bSNicolas MURE SND_DJM_CTL("Ch1 Input", 850_cap1, 1, SND_DJM_WINDEX_CAP), 28197687850bSNicolas MURE SND_DJM_CTL("Ch2 Input", 850_cap2, 0, SND_DJM_WINDEX_CAP), 28207687850bSNicolas MURE SND_DJM_CTL("Ch3 Input", 850_cap3, 0, SND_DJM_WINDEX_CAP), 28217687850bSNicolas MURE SND_DJM_CTL("Ch4 Input", 850_cap4, 1, SND_DJM_WINDEX_CAP) 28227687850bSNicolas MURE }; 28237687850bSNicolas MURE 28247687850bSNicolas MURE 2825fee03efcSFabian Lesniak // DJM-900NXS2 2826fee03efcSFabian Lesniak static const u16 snd_djm_opts_900nxs2_cap1[] = { 2827fee03efcSFabian Lesniak 0x0100, 0x0102, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a }; 2828fee03efcSFabian Lesniak static const u16 snd_djm_opts_900nxs2_cap2[] = { 2829fee03efcSFabian Lesniak 0x0200, 0x0202, 0x0203, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a }; 2830fee03efcSFabian Lesniak static const u16 snd_djm_opts_900nxs2_cap3[] = { 2831fee03efcSFabian Lesniak 0x0300, 0x0302, 0x0303, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a }; 2832fee03efcSFabian Lesniak static const u16 snd_djm_opts_900nxs2_cap4[] = { 2833fee03efcSFabian Lesniak 0x0400, 0x0402, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a }; 2834fee03efcSFabian Lesniak static const u16 snd_djm_opts_900nxs2_cap5[] = { 2835fee03efcSFabian Lesniak 0x0507, 0x0508, 0x0509, 0x050a, 0x0511, 0x0512, 0x0513, 0x0514 }; 2836fee03efcSFabian Lesniak 2837fee03efcSFabian Lesniak static const struct snd_djm_ctl snd_djm_ctls_900nxs2[] = { 2838fee03efcSFabian Lesniak SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), 2839fee03efcSFabian Lesniak SND_DJM_CTL("Ch1 Input", 900nxs2_cap1, 2, SND_DJM_WINDEX_CAP), 2840fee03efcSFabian Lesniak SND_DJM_CTL("Ch2 Input", 900nxs2_cap2, 2, SND_DJM_WINDEX_CAP), 2841fee03efcSFabian Lesniak SND_DJM_CTL("Ch3 Input", 900nxs2_cap3, 2, SND_DJM_WINDEX_CAP), 2842fee03efcSFabian Lesniak SND_DJM_CTL("Ch4 Input", 900nxs2_cap4, 2, SND_DJM_WINDEX_CAP), 2843fee03efcSFabian Lesniak SND_DJM_CTL("Ch5 Input", 900nxs2_cap5, 3, SND_DJM_WINDEX_CAP) 2844fee03efcSFabian Lesniak }; 2845fee03efcSFabian Lesniak 2846fee03efcSFabian Lesniak 2847a07df82cSOlivia Mackintosh static const struct snd_djm_device snd_djm_devices[] = { 2848a07df82cSOlivia Mackintosh SND_DJM_DEVICE(250mk2), 2849fee03efcSFabian Lesniak SND_DJM_DEVICE(750), 28507687850bSNicolas MURE SND_DJM_DEVICE(850), 2851fee03efcSFabian Lesniak SND_DJM_DEVICE(900nxs2) 2852a07df82cSOlivia Mackintosh }; 2853a07df82cSOlivia Mackintosh 2854a07df82cSOlivia Mackintosh 2855a07df82cSOlivia Mackintosh static int snd_djm_controls_info(struct snd_kcontrol *kctl, 2856a07df82cSOlivia Mackintosh struct snd_ctl_elem_info *info) 2857a07df82cSOlivia Mackintosh { 2858a07df82cSOlivia Mackintosh unsigned long private_value = kctl->private_value; 2859a07df82cSOlivia Mackintosh u8 device_idx = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT; 2860a07df82cSOlivia Mackintosh u8 ctl_idx = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT; 2861a07df82cSOlivia Mackintosh const struct snd_djm_device *device = &snd_djm_devices[device_idx]; 2862a07df82cSOlivia Mackintosh const char *name; 2863a07df82cSOlivia Mackintosh const struct snd_djm_ctl *ctl; 2864a07df82cSOlivia Mackintosh size_t noptions; 2865a07df82cSOlivia Mackintosh 2866a07df82cSOlivia Mackintosh if (ctl_idx >= device->ncontrols) 2867cdc01a15SFrantišek Kučera return -EINVAL; 2868cdc01a15SFrantišek Kučera 2869a07df82cSOlivia Mackintosh ctl = &device->controls[ctl_idx]; 2870a07df82cSOlivia Mackintosh noptions = ctl->noptions; 2871a07df82cSOlivia Mackintosh if (info->value.enumerated.item >= noptions) 2872a07df82cSOlivia Mackintosh info->value.enumerated.item = noptions - 1; 2873a07df82cSOlivia Mackintosh 2874b8db8be8SNicolas MURE name = snd_djm_get_label(device_idx, 2875b8db8be8SNicolas MURE ctl->options[info->value.enumerated.item], 2876a07df82cSOlivia Mackintosh ctl->wIndex); 2877a07df82cSOlivia Mackintosh if (!name) 2878a07df82cSOlivia Mackintosh return -EINVAL; 2879a07df82cSOlivia Mackintosh 288075b1a8f9SJoe Perches strscpy(info->value.enumerated.name, name, sizeof(info->value.enumerated.name)); 2881cdc01a15SFrantišek Kučera info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2882cdc01a15SFrantišek Kučera info->count = 1; 2883a07df82cSOlivia Mackintosh info->value.enumerated.items = noptions; 2884cdc01a15SFrantišek Kučera return 0; 2885cdc01a15SFrantišek Kučera } 2886cdc01a15SFrantišek Kučera 2887a07df82cSOlivia Mackintosh static int snd_djm_controls_update(struct usb_mixer_interface *mixer, 2888a07df82cSOlivia Mackintosh u8 device_idx, u8 group, u16 value) 2889cdc01a15SFrantišek Kučera { 2890cdc01a15SFrantišek Kučera int err; 2891a07df82cSOlivia Mackintosh const struct snd_djm_device *device = &snd_djm_devices[device_idx]; 2892cdc01a15SFrantišek Kučera 2893a07df82cSOlivia Mackintosh if ((group >= device->ncontrols) || value >= device->controls[group].noptions) 2894cdc01a15SFrantišek Kučera return -EINVAL; 2895cdc01a15SFrantišek Kučera 2896cdc01a15SFrantišek Kučera err = snd_usb_lock_shutdown(mixer->chip); 2897cdc01a15SFrantišek Kučera if (err) 2898cdc01a15SFrantišek Kučera return err; 2899cdc01a15SFrantišek Kučera 2900cdc01a15SFrantišek Kučera err = snd_usb_ctl_msg( 2901cdc01a15SFrantišek Kučera mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 2902cdc01a15SFrantišek Kučera USB_REQ_SET_FEATURE, 2903cdc01a15SFrantišek Kučera USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 2904a07df82cSOlivia Mackintosh device->controls[group].options[value], 2905a07df82cSOlivia Mackintosh device->controls[group].wIndex, 2906cdc01a15SFrantišek Kučera NULL, 0); 2907cdc01a15SFrantišek Kučera 2908cdc01a15SFrantišek Kučera snd_usb_unlock_shutdown(mixer->chip); 2909cdc01a15SFrantišek Kučera return err; 2910cdc01a15SFrantišek Kučera } 2911cdc01a15SFrantišek Kučera 2912a07df82cSOlivia Mackintosh static int snd_djm_controls_get(struct snd_kcontrol *kctl, 2913a07df82cSOlivia Mackintosh struct snd_ctl_elem_value *elem) 2914cdc01a15SFrantišek Kučera { 2915a07df82cSOlivia Mackintosh elem->value.enumerated.item[0] = kctl->private_value & SND_DJM_VALUE_MASK; 2916cdc01a15SFrantišek Kučera return 0; 2917cdc01a15SFrantišek Kučera } 2918cdc01a15SFrantišek Kučera 2919a07df82cSOlivia Mackintosh static int snd_djm_controls_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem) 2920cdc01a15SFrantišek Kučera { 2921cdc01a15SFrantišek Kučera struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); 2922cdc01a15SFrantišek Kučera struct usb_mixer_interface *mixer = list->mixer; 2923cdc01a15SFrantišek Kučera unsigned long private_value = kctl->private_value; 2924a07df82cSOlivia Mackintosh 2925a07df82cSOlivia Mackintosh u8 device = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT; 2926a07df82cSOlivia Mackintosh u8 group = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT; 2927cdc01a15SFrantišek Kučera u16 value = elem->value.enumerated.item[0]; 2928cdc01a15SFrantišek Kučera 292950b1affcSColin Ian King kctl->private_value = (((unsigned long)device << SND_DJM_DEVICE_SHIFT) | 2930a07df82cSOlivia Mackintosh (group << SND_DJM_GROUP_SHIFT) | 2931a07df82cSOlivia Mackintosh value); 2932cdc01a15SFrantišek Kučera 2933a07df82cSOlivia Mackintosh return snd_djm_controls_update(mixer, device, group, value); 2934cdc01a15SFrantišek Kučera } 2935cdc01a15SFrantišek Kučera 2936a07df82cSOlivia Mackintosh static int snd_djm_controls_resume(struct usb_mixer_elem_list *list) 2937cdc01a15SFrantišek Kučera { 2938cdc01a15SFrantišek Kučera unsigned long private_value = list->kctl->private_value; 2939a07df82cSOlivia Mackintosh u8 device = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT; 2940a07df82cSOlivia Mackintosh u8 group = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT; 2941a07df82cSOlivia Mackintosh u16 value = (private_value & SND_DJM_VALUE_MASK); 2942cdc01a15SFrantišek Kučera 2943a07df82cSOlivia Mackintosh return snd_djm_controls_update(list->mixer, device, group, value); 2944cdc01a15SFrantišek Kučera } 2945cdc01a15SFrantišek Kučera 2946a07df82cSOlivia Mackintosh static int snd_djm_controls_create(struct usb_mixer_interface *mixer, 2947a07df82cSOlivia Mackintosh const u8 device_idx) 2948cdc01a15SFrantišek Kučera { 2949cdc01a15SFrantišek Kučera int err, i; 2950a07df82cSOlivia Mackintosh u16 value; 2951a07df82cSOlivia Mackintosh 2952a07df82cSOlivia Mackintosh const struct snd_djm_device *device = &snd_djm_devices[device_idx]; 2953a07df82cSOlivia Mackintosh 2954cdc01a15SFrantišek Kučera struct snd_kcontrol_new knew = { 2955cdc01a15SFrantišek Kučera .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2956cdc01a15SFrantišek Kučera .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 2957cdc01a15SFrantišek Kučera .index = 0, 2958a07df82cSOlivia Mackintosh .info = snd_djm_controls_info, 2959a07df82cSOlivia Mackintosh .get = snd_djm_controls_get, 2960a07df82cSOlivia Mackintosh .put = snd_djm_controls_put 2961cdc01a15SFrantišek Kučera }; 2962cdc01a15SFrantišek Kučera 2963a07df82cSOlivia Mackintosh for (i = 0; i < device->ncontrols; i++) { 2964a07df82cSOlivia Mackintosh value = device->controls[i].default_value; 2965a07df82cSOlivia Mackintosh knew.name = device->controls[i].name; 2966a07df82cSOlivia Mackintosh knew.private_value = ( 296750b1affcSColin Ian King ((unsigned long)device_idx << SND_DJM_DEVICE_SHIFT) | 2968a07df82cSOlivia Mackintosh (i << SND_DJM_GROUP_SHIFT) | 2969a07df82cSOlivia Mackintosh value); 2970a07df82cSOlivia Mackintosh err = snd_djm_controls_update(mixer, device_idx, i, value); 2971cdc01a15SFrantišek Kučera if (err) 2972cdc01a15SFrantišek Kučera return err; 2973a07df82cSOlivia Mackintosh err = add_single_ctl_with_resume(mixer, 0, snd_djm_controls_resume, 2974cdc01a15SFrantišek Kučera &knew, NULL); 2975cdc01a15SFrantišek Kučera if (err) 2976cdc01a15SFrantišek Kučera return err; 2977cdc01a15SFrantišek Kučera } 2978cdc01a15SFrantišek Kučera return 0; 2979cdc01a15SFrantišek Kučera } 2980cdc01a15SFrantišek Kučera 29817b1eda22SDaniel Mack int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) 29827b1eda22SDaniel Mack { 29833347b26cSDaniel Mack int err = 0; 29847b1eda22SDaniel Mack 2985f25ecf8fSTakashi Iwai err = snd_usb_soundblaster_remote_init(mixer); 2986f25ecf8fSTakashi Iwai if (err < 0) 29877b1eda22SDaniel Mack return err; 29887b1eda22SDaniel Mack 29893347b26cSDaniel Mack switch (mixer->chip->usb_id) { 2990d2bb390aSDetlef Urban /* Tascam US-16x08 */ 2991d2bb390aSDetlef Urban case USB_ID(0x0644, 0x8047): 2992d2bb390aSDetlef Urban err = snd_us16x08_controls_create(mixer); 2993d2bb390aSDetlef Urban break; 29943347b26cSDaniel Mack case USB_ID(0x041e, 0x3020): 29953347b26cSDaniel Mack case USB_ID(0x041e, 0x3040): 29963347b26cSDaniel Mack case USB_ID(0x041e, 0x3042): 29977cdd8d73SMathieu Bouffard case USB_ID(0x041e, 0x30df): 29983347b26cSDaniel Mack case USB_ID(0x041e, 0x3048): 29993347b26cSDaniel Mack err = snd_audigy2nx_controls_create(mixer); 30003347b26cSDaniel Mack if (err < 0) 30013347b26cSDaniel Mack break; 30027449054aSTakashi Iwai snd_card_ro_proc_new(mixer->chip->card, "audigy2nx", 30037449054aSTakashi Iwai mixer, snd_audigy2nx_proc_read); 30043347b26cSDaniel Mack break; 30057b1eda22SDaniel Mack 300644832a71SVasily Khoruzhick /* EMU0204 */ 300744832a71SVasily Khoruzhick case USB_ID(0x041e, 0x3f19): 300844832a71SVasily Khoruzhick err = snd_emu0204_controls_create(mixer); 300944832a71SVasily Khoruzhick break; 301044832a71SVasily Khoruzhick 301109d8e3a7SEldad Zack case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ 3012e9a25e04SMatt Gruskin case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C400 */ 301309d8e3a7SEldad Zack err = snd_c400_create_mixer(mixer); 301409d8e3a7SEldad Zack break; 301509d8e3a7SEldad Zack 3016d5a0bf6cSDaniel Mack case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ 3017d5a0bf6cSDaniel Mack case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ 3018cfe8f97cSFelix Homann err = snd_ftu_create_mixer(mixer); 3019d5a0bf6cSDaniel Mack break; 3020d5a0bf6cSDaniel Mack 30211d31affbSDenis Washington case USB_ID(0x0b05, 0x1739): /* ASUS Xonar U1 */ 30221d31affbSDenis Washington case USB_ID(0x0b05, 0x1743): /* ASUS Xonar U1 (2) */ 30231d31affbSDenis Washington case USB_ID(0x0b05, 0x17a0): /* ASUS Xonar U3 */ 30247b1eda22SDaniel Mack err = snd_xonar_u1_controls_create(mixer); 30253347b26cSDaniel Mack break; 30267b1eda22SDaniel Mack 3027066624c6SPrzemek Rudy case USB_ID(0x0d8c, 0x0103): /* Audio Advantage Micro II */ 3028066624c6SPrzemek Rudy err = snd_microii_controls_create(mixer); 3029066624c6SPrzemek Rudy break; 3030066624c6SPrzemek Rudy 3031d497a82fSDamien Zammit case USB_ID(0x0dba, 0x1000): /* Digidesign Mbox 1 */ 3032d497a82fSDamien Zammit err = snd_mbox1_create_sync_switch(mixer); 3033d497a82fSDamien Zammit break; 3034d497a82fSDamien Zammit 30353347b26cSDaniel Mack case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */ 303654a8c500SDaniel Mack err = snd_nativeinstruments_create_mixer(mixer, 303754a8c500SDaniel Mack snd_nativeinstruments_ta6_mixers, 303854a8c500SDaniel Mack ARRAY_SIZE(snd_nativeinstruments_ta6_mixers)); 30393347b26cSDaniel Mack break; 304054a8c500SDaniel Mack 30413347b26cSDaniel Mack case USB_ID(0x17cc, 0x1021): /* Traktor Audio 10 */ 304254a8c500SDaniel Mack err = snd_nativeinstruments_create_mixer(mixer, 304354a8c500SDaniel Mack snd_nativeinstruments_ta10_mixers, 304454a8c500SDaniel Mack ARRAY_SIZE(snd_nativeinstruments_ta10_mixers)); 30453347b26cSDaniel Mack break; 30467536c301SMark Hills 30477536c301SMark Hills case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */ 3048b71dad18SMark Hills /* detection is disabled in mixer_maps.c */ 3049b71dad18SMark Hills err = snd_create_std_mono_table(mixer, ebox44_table); 30507536c301SMark Hills break; 305176b188c4SChris J Arges 305276b188c4SChris J Arges case USB_ID(0x1235, 0x8012): /* Focusrite Scarlett 6i6 */ 305376b188c4SChris J Arges case USB_ID(0x1235, 0x8002): /* Focusrite Scarlett 8i6 */ 305476b188c4SChris J Arges case USB_ID(0x1235, 0x8004): /* Focusrite Scarlett 18i6 */ 305576b188c4SChris J Arges case USB_ID(0x1235, 0x8014): /* Focusrite Scarlett 18i8 */ 305676b188c4SChris J Arges case USB_ID(0x1235, 0x800c): /* Focusrite Scarlett 18i20 */ 305776b188c4SChris J Arges err = snd_scarlett_controls_create(mixer); 305876b188c4SChris J Arges break; 3059388fdb8fSIan Douglas Scott 30609e4d5c1bSGeoffrey D. Bennett case USB_ID(0x1235, 0x8203): /* Focusrite Scarlett 6i6 2nd Gen */ 30619e4d5c1bSGeoffrey D. Bennett case USB_ID(0x1235, 0x8204): /* Focusrite Scarlett 18i8 2nd Gen */ 30629e4d5c1bSGeoffrey D. Bennett case USB_ID(0x1235, 0x8201): /* Focusrite Scarlett 18i20 2nd Gen */ 3063*4be47798SGeoffrey D. Bennett case USB_ID(0x1235, 0x8212): /* Focusrite Scarlett 4i4 3rd Gen */ 3064*4be47798SGeoffrey D. Bennett case USB_ID(0x1235, 0x8213): /* Focusrite Scarlett 8i6 3rd Gen */ 3065*4be47798SGeoffrey D. Bennett case USB_ID(0x1235, 0x8214): /* Focusrite Scarlett 18i8 3rd Gen */ 3066*4be47798SGeoffrey D. Bennett case USB_ID(0x1235, 0x8215): /* Focusrite Scarlett 18i20 3rd Gen */ 3067265d1a90SGeoffrey D. Bennett err = snd_scarlett_gen2_init(mixer); 30689e4d5c1bSGeoffrey D. Bennett break; 30699e4d5c1bSGeoffrey D. Bennett 3070388fdb8fSIan Douglas Scott case USB_ID(0x041e, 0x323b): /* Creative Sound Blaster E1 */ 3071388fdb8fSIan Douglas Scott err = snd_soundblaster_e1_switch_create(mixer); 3072388fdb8fSIan Douglas Scott break; 3073964af639STakashi Iwai case USB_ID(0x0bda, 0x4014): /* Dell WD15 dock */ 3074964af639STakashi Iwai err = dell_dock_mixer_init(mixer); 3075964af639STakashi Iwai break; 3076d39f1d68SJussi Laako 3077d39f1d68SJussi Laako case USB_ID(0x2a39, 0x3fd2): /* RME ADI-2 Pro */ 3078d39f1d68SJussi Laako case USB_ID(0x2a39, 0x3fd3): /* RME ADI-2 DAC */ 3079d39f1d68SJussi Laako case USB_ID(0x2a39, 0x3fd4): /* RME */ 3080d39f1d68SJussi Laako err = snd_rme_controls_create(mixer); 3081d39f1d68SJussi Laako break; 30828dc5efe3SNick Kossifidis 30838dc5efe3SNick Kossifidis case USB_ID(0x0194f, 0x010c): /* Presonus Studio 1810c */ 30848dc5efe3SNick Kossifidis err = snd_sc1810_init_mixer(mixer); 30858dc5efe3SNick Kossifidis break; 30863e8f3bd0SThomas Ebeling case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */ 30873e8f3bd0SThomas Ebeling err = snd_bbfpro_controls_create(mixer); 30883e8f3bd0SThomas Ebeling break; 3089cdc01a15SFrantišek Kučera case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */ 3090a07df82cSOlivia Mackintosh err = snd_djm_controls_create(mixer, SND_DJM_250MK2_IDX); 3091a07df82cSOlivia Mackintosh break; 3092a07df82cSOlivia Mackintosh case USB_ID(0x08e4, 0x017f): /* Pioneer DJ DJM-750 */ 3093a07df82cSOlivia Mackintosh err = snd_djm_controls_create(mixer, SND_DJM_750_IDX); 3094cdc01a15SFrantišek Kučera break; 30957687850bSNicolas MURE case USB_ID(0x08e4, 0x0163): /* Pioneer DJ DJM-850 */ 30967687850bSNicolas MURE err = snd_djm_controls_create(mixer, SND_DJM_850_IDX); 30977687850bSNicolas MURE break; 3098fee03efcSFabian Lesniak case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */ 3099fee03efcSFabian Lesniak err = snd_djm_controls_create(mixer, SND_DJM_900NXS2_IDX); 3100fee03efcSFabian Lesniak break; 310154a8c500SDaniel Mack } 310254a8c500SDaniel Mack 31033347b26cSDaniel Mack return err; 31047b1eda22SDaniel Mack } 31057b1eda22SDaniel Mack 3106964af639STakashi Iwai #ifdef CONFIG_PM 3107964af639STakashi Iwai void snd_usb_mixer_resume_quirk(struct usb_mixer_interface *mixer) 3108964af639STakashi Iwai { 3109964af639STakashi Iwai switch (mixer->chip->usb_id) { 3110964af639STakashi Iwai case USB_ID(0x0bda, 0x4014): /* Dell WD15 dock */ 3111964af639STakashi Iwai dell_dock_mixer_init(mixer); 3112964af639STakashi Iwai break; 3113964af639STakashi Iwai } 3114964af639STakashi Iwai } 3115964af639STakashi Iwai #endif 3116964af639STakashi Iwai 31177b1eda22SDaniel Mack void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, 31187b1eda22SDaniel Mack int unitid) 31197b1eda22SDaniel Mack { 31207b1eda22SDaniel Mack if (!mixer->rc_cfg) 31217b1eda22SDaniel Mack return; 31227b1eda22SDaniel Mack /* unit ids specific to Extigy/Audigy 2 NX: */ 31237b1eda22SDaniel Mack switch (unitid) { 31247b1eda22SDaniel Mack case 0: /* remote control */ 31257b1eda22SDaniel Mack mixer->rc_urb->dev = mixer->chip->dev; 31267b1eda22SDaniel Mack usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); 31277b1eda22SDaniel Mack break; 31287b1eda22SDaniel Mack case 4: /* digital in jack */ 31297b1eda22SDaniel Mack case 7: /* line in jacks */ 31307b1eda22SDaniel Mack case 19: /* speaker out jacks */ 31317b1eda22SDaniel Mack case 20: /* headphones out jack */ 31327b1eda22SDaniel Mack break; 31337b1eda22SDaniel Mack /* live24ext: 4 = line-in jack */ 31347b1eda22SDaniel Mack case 3: /* hp-out jack (may actuate Mute) */ 31357b1eda22SDaniel Mack if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 31367b1eda22SDaniel Mack mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) 31377b1eda22SDaniel Mack snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id); 31387b1eda22SDaniel Mack break; 31397b1eda22SDaniel Mack default: 31400ba41d91STakashi Iwai usb_audio_dbg(mixer->chip, "memory change in unknown unit %d\n", unitid); 31417b1eda22SDaniel Mack break; 31427b1eda22SDaniel Mack } 31437b1eda22SDaniel Mack } 31447b1eda22SDaniel Mack 314542e3121dSAnssi Hannula static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer, 3146eb1a74b7SAnssi Hannula struct usb_mixer_elem_info *cval, 314742e3121dSAnssi Hannula struct snd_kcontrol *kctl) 314842e3121dSAnssi Hannula { 314942e3121dSAnssi Hannula /* Approximation using 10 ranges based on output measurement on hw v1.2. 315042e3121dSAnssi Hannula * This seems close to the cubic mapping e.g. alsamixer uses. */ 315142e3121dSAnssi Hannula static const DECLARE_TLV_DB_RANGE(scale, 315242e3121dSAnssi Hannula 0, 1, TLV_DB_MINMAX_ITEM(-5300, -4970), 315342e3121dSAnssi Hannula 2, 5, TLV_DB_MINMAX_ITEM(-4710, -4160), 315442e3121dSAnssi Hannula 6, 7, TLV_DB_MINMAX_ITEM(-3884, -3710), 315542e3121dSAnssi Hannula 8, 14, TLV_DB_MINMAX_ITEM(-3443, -2560), 315642e3121dSAnssi Hannula 15, 16, TLV_DB_MINMAX_ITEM(-2475, -2324), 315742e3121dSAnssi Hannula 17, 19, TLV_DB_MINMAX_ITEM(-2228, -2031), 315842e3121dSAnssi Hannula 20, 26, TLV_DB_MINMAX_ITEM(-1910, -1393), 315942e3121dSAnssi Hannula 27, 31, TLV_DB_MINMAX_ITEM(-1322, -1032), 316042e3121dSAnssi Hannula 32, 40, TLV_DB_MINMAX_ITEM(-968, -490), 316142e3121dSAnssi Hannula 41, 50, TLV_DB_MINMAX_ITEM(-441, 0), 316242e3121dSAnssi Hannula ); 316342e3121dSAnssi Hannula 3164eb1a74b7SAnssi Hannula if (cval->min == 0 && cval->max == 50) { 3165eb1a74b7SAnssi Hannula usb_audio_info(mixer->chip, "applying DragonFly dB scale quirk (0-50 variant)\n"); 316642e3121dSAnssi Hannula kctl->tlv.p = scale; 316742e3121dSAnssi Hannula kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; 316842e3121dSAnssi Hannula kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; 3169eb1a74b7SAnssi Hannula 3170eb1a74b7SAnssi Hannula } else if (cval->min == 0 && cval->max <= 1000) { 3171eb1a74b7SAnssi Hannula /* Some other clearly broken DragonFly variant. 3172eb1a74b7SAnssi Hannula * At least a 0..53 variant (hw v1.0) exists. 3173eb1a74b7SAnssi Hannula */ 3174eb1a74b7SAnssi Hannula usb_audio_info(mixer->chip, "ignoring too narrow dB range on a DragonFly device"); 3175eb1a74b7SAnssi Hannula kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; 3176eb1a74b7SAnssi Hannula } 317742e3121dSAnssi Hannula } 317842e3121dSAnssi Hannula 317942e3121dSAnssi Hannula void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, 318042e3121dSAnssi Hannula struct usb_mixer_elem_info *cval, int unitid, 318142e3121dSAnssi Hannula struct snd_kcontrol *kctl) 318242e3121dSAnssi Hannula { 318342e3121dSAnssi Hannula switch (mixer->chip->usb_id) { 318442e3121dSAnssi Hannula case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */ 3185eb1a74b7SAnssi Hannula if (unitid == 7 && cval->control == UAC_FU_VOLUME) 3186eb1a74b7SAnssi Hannula snd_dragonfly_quirk_db_scale(mixer, cval, kctl); 318742e3121dSAnssi Hannula break; 31880f174b35STakashi Iwai /* lowest playback value is muted on C-Media devices */ 31890f174b35STakashi Iwai case USB_ID(0x0d8c, 0x000c): 31900f174b35STakashi Iwai case USB_ID(0x0d8c, 0x0014): 31910f174b35STakashi Iwai if (strstr(kctl->id.name, "Playback")) 31920f174b35STakashi Iwai cval->min_mute = 1; 31930f174b35STakashi Iwai break; 319442e3121dSAnssi Hannula } 319542e3121dSAnssi Hannula } 319642e3121dSAnssi Hannula 3197