162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * USB Audio Driver for ALSA 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Quirks and vendor-specific extensions for mixer interfaces 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Many codes borrowed from audio.c by 1062306a36Sopenharmony_ci * Alan Cox (alan@lxorguk.ukuu.org.uk) 1162306a36Sopenharmony_ci * Thomas Sailer (sailer@ife.ee.ethz.ch) 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Audio Advantage Micro II support added by: 1462306a36Sopenharmony_ci * Przemek Rudy (prudy1@o2.pl) 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/hid.h> 1862306a36Sopenharmony_ci#include <linux/init.h> 1962306a36Sopenharmony_ci#include <linux/math64.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/usb.h> 2262306a36Sopenharmony_ci#include <linux/usb/audio.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <sound/asoundef.h> 2562306a36Sopenharmony_ci#include <sound/core.h> 2662306a36Sopenharmony_ci#include <sound/control.h> 2762306a36Sopenharmony_ci#include <sound/hda_verbs.h> 2862306a36Sopenharmony_ci#include <sound/hwdep.h> 2962306a36Sopenharmony_ci#include <sound/info.h> 3062306a36Sopenharmony_ci#include <sound/tlv.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "usbaudio.h" 3362306a36Sopenharmony_ci#include "mixer.h" 3462306a36Sopenharmony_ci#include "mixer_quirks.h" 3562306a36Sopenharmony_ci#include "mixer_scarlett.h" 3662306a36Sopenharmony_ci#include "mixer_scarlett_gen2.h" 3762306a36Sopenharmony_ci#include "mixer_us16x08.h" 3862306a36Sopenharmony_ci#include "mixer_s1810c.h" 3962306a36Sopenharmony_ci#include "helper.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistruct std_mono_table { 4262306a36Sopenharmony_ci unsigned int unitid, control, cmask; 4362306a36Sopenharmony_ci int val_type; 4462306a36Sopenharmony_ci const char *name; 4562306a36Sopenharmony_ci snd_kcontrol_tlv_rw_t *tlv_callback; 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* This function allows for the creation of standard UAC controls. 4962306a36Sopenharmony_ci * See the quirks for M-Audio FTUs or Ebox-44. 5062306a36Sopenharmony_ci * If you don't want to set a TLV callback pass NULL. 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * Since there doesn't seem to be a devices that needs a multichannel 5362306a36Sopenharmony_ci * version, we keep it mono for simplicity. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_cistatic int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer, 5662306a36Sopenharmony_ci unsigned int unitid, 5762306a36Sopenharmony_ci unsigned int control, 5862306a36Sopenharmony_ci unsigned int cmask, 5962306a36Sopenharmony_ci int val_type, 6062306a36Sopenharmony_ci unsigned int idx_off, 6162306a36Sopenharmony_ci const char *name, 6262306a36Sopenharmony_ci snd_kcontrol_tlv_rw_t *tlv_callback) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct usb_mixer_elem_info *cval; 6562306a36Sopenharmony_ci struct snd_kcontrol *kctl; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci cval = kzalloc(sizeof(*cval), GFP_KERNEL); 6862306a36Sopenharmony_ci if (!cval) 6962306a36Sopenharmony_ci return -ENOMEM; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci snd_usb_mixer_elem_init_std(&cval->head, mixer, unitid); 7262306a36Sopenharmony_ci cval->val_type = val_type; 7362306a36Sopenharmony_ci cval->channels = 1; 7462306a36Sopenharmony_ci cval->control = control; 7562306a36Sopenharmony_ci cval->cmask = cmask; 7662306a36Sopenharmony_ci cval->idx_off = idx_off; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* get_min_max() is called only for integer volumes later, 7962306a36Sopenharmony_ci * so provide a short-cut for booleans */ 8062306a36Sopenharmony_ci cval->min = 0; 8162306a36Sopenharmony_ci cval->max = 1; 8262306a36Sopenharmony_ci cval->res = 0; 8362306a36Sopenharmony_ci cval->dBmin = 0; 8462306a36Sopenharmony_ci cval->dBmax = 0; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* Create control */ 8762306a36Sopenharmony_ci kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval); 8862306a36Sopenharmony_ci if (!kctl) { 8962306a36Sopenharmony_ci kfree(cval); 9062306a36Sopenharmony_ci return -ENOMEM; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* Set name */ 9462306a36Sopenharmony_ci snprintf(kctl->id.name, sizeof(kctl->id.name), name); 9562306a36Sopenharmony_ci kctl->private_free = snd_usb_mixer_elem_free; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* set TLV */ 9862306a36Sopenharmony_ci if (tlv_callback) { 9962306a36Sopenharmony_ci kctl->tlv.c = tlv_callback; 10062306a36Sopenharmony_ci kctl->vd[0].access |= 10162306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ | 10262306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci /* Add control to mixer */ 10562306a36Sopenharmony_ci return snd_usb_mixer_add_control(&cval->head, kctl); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, 10962306a36Sopenharmony_ci unsigned int unitid, 11062306a36Sopenharmony_ci unsigned int control, 11162306a36Sopenharmony_ci unsigned int cmask, 11262306a36Sopenharmony_ci int val_type, 11362306a36Sopenharmony_ci const char *name, 11462306a36Sopenharmony_ci snd_kcontrol_tlv_rw_t *tlv_callback) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci return snd_create_std_mono_ctl_offset(mixer, unitid, control, cmask, 11762306a36Sopenharmony_ci val_type, 0 /* Offset */, name, tlv_callback); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* 12162306a36Sopenharmony_ci * Create a set of standard UAC controls from a table 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_cistatic int snd_create_std_mono_table(struct usb_mixer_interface *mixer, 12462306a36Sopenharmony_ci const struct std_mono_table *t) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci int err; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci while (t->name != NULL) { 12962306a36Sopenharmony_ci err = snd_create_std_mono_ctl(mixer, t->unitid, t->control, 13062306a36Sopenharmony_ci t->cmask, t->val_type, t->name, t->tlv_callback); 13162306a36Sopenharmony_ci if (err < 0) 13262306a36Sopenharmony_ci return err; 13362306a36Sopenharmony_ci t++; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic int add_single_ctl_with_resume(struct usb_mixer_interface *mixer, 14062306a36Sopenharmony_ci int id, 14162306a36Sopenharmony_ci usb_mixer_elem_resume_func_t resume, 14262306a36Sopenharmony_ci const struct snd_kcontrol_new *knew, 14362306a36Sopenharmony_ci struct usb_mixer_elem_list **listp) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct usb_mixer_elem_list *list; 14662306a36Sopenharmony_ci struct snd_kcontrol *kctl; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci list = kzalloc(sizeof(*list), GFP_KERNEL); 14962306a36Sopenharmony_ci if (!list) 15062306a36Sopenharmony_ci return -ENOMEM; 15162306a36Sopenharmony_ci if (listp) 15262306a36Sopenharmony_ci *listp = list; 15362306a36Sopenharmony_ci list->mixer = mixer; 15462306a36Sopenharmony_ci list->id = id; 15562306a36Sopenharmony_ci list->resume = resume; 15662306a36Sopenharmony_ci kctl = snd_ctl_new1(knew, list); 15762306a36Sopenharmony_ci if (!kctl) { 15862306a36Sopenharmony_ci kfree(list); 15962306a36Sopenharmony_ci return -ENOMEM; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci kctl->private_free = snd_usb_mixer_elem_free; 16262306a36Sopenharmony_ci /* don't use snd_usb_mixer_add_control() here, this is a special list element */ 16362306a36Sopenharmony_ci return snd_usb_mixer_add_list(list, kctl, false); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* 16762306a36Sopenharmony_ci * Sound Blaster remote control configuration 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * format of remote control data: 17062306a36Sopenharmony_ci * Extigy: xx 00 17162306a36Sopenharmony_ci * Audigy 2 NX: 06 80 xx 00 00 00 17262306a36Sopenharmony_ci * Live! 24-bit: 06 80 xx yy 22 83 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_cistatic const struct rc_config { 17562306a36Sopenharmony_ci u32 usb_id; 17662306a36Sopenharmony_ci u8 offset; 17762306a36Sopenharmony_ci u8 length; 17862306a36Sopenharmony_ci u8 packet_length; 17962306a36Sopenharmony_ci u8 min_packet_length; /* minimum accepted length of the URB result */ 18062306a36Sopenharmony_ci u8 mute_mixer_id; 18162306a36Sopenharmony_ci u32 mute_code; 18262306a36Sopenharmony_ci} rc_configs[] = { 18362306a36Sopenharmony_ci { USB_ID(0x041e, 0x3000), 0, 1, 2, 1, 18, 0x0013 }, /* Extigy */ 18462306a36Sopenharmony_ci { USB_ID(0x041e, 0x3020), 2, 1, 6, 6, 18, 0x0013 }, /* Audigy 2 NX */ 18562306a36Sopenharmony_ci { USB_ID(0x041e, 0x3040), 2, 2, 6, 6, 2, 0x6e91 }, /* Live! 24-bit */ 18662306a36Sopenharmony_ci { USB_ID(0x041e, 0x3042), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 */ 18762306a36Sopenharmony_ci { USB_ID(0x041e, 0x30df), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ 18862306a36Sopenharmony_ci { USB_ID(0x041e, 0x3237), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ 18962306a36Sopenharmony_ci { USB_ID(0x041e, 0x3263), 0, 1, 1, 1, 1, 0x000d }, /* Usb X-Fi S51 Pro */ 19062306a36Sopenharmony_ci { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ 19162306a36Sopenharmony_ci}; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic void snd_usb_soundblaster_remote_complete(struct urb *urb) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct usb_mixer_interface *mixer = urb->context; 19662306a36Sopenharmony_ci const struct rc_config *rc = mixer->rc_cfg; 19762306a36Sopenharmony_ci u32 code; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (urb->status < 0 || urb->actual_length < rc->min_packet_length) 20062306a36Sopenharmony_ci return; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci code = mixer->rc_buffer[rc->offset]; 20362306a36Sopenharmony_ci if (rc->length == 2) 20462306a36Sopenharmony_ci code |= mixer->rc_buffer[rc->offset + 1] << 8; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* the Mute button actually changes the mixer control */ 20762306a36Sopenharmony_ci if (code == rc->mute_code) 20862306a36Sopenharmony_ci snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id); 20962306a36Sopenharmony_ci mixer->rc_code = code; 21062306a36Sopenharmony_ci wmb(); 21162306a36Sopenharmony_ci wake_up(&mixer->rc_waitq); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf, 21562306a36Sopenharmony_ci long count, loff_t *offset) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct usb_mixer_interface *mixer = hw->private_data; 21862306a36Sopenharmony_ci int err; 21962306a36Sopenharmony_ci u32 rc_code; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (count != 1 && count != 4) 22262306a36Sopenharmony_ci return -EINVAL; 22362306a36Sopenharmony_ci err = wait_event_interruptible(mixer->rc_waitq, 22462306a36Sopenharmony_ci (rc_code = xchg(&mixer->rc_code, 0)) != 0); 22562306a36Sopenharmony_ci if (err == 0) { 22662306a36Sopenharmony_ci if (count == 1) 22762306a36Sopenharmony_ci err = put_user(rc_code, buf); 22862306a36Sopenharmony_ci else 22962306a36Sopenharmony_ci err = put_user(rc_code, (u32 __user *)buf); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci return err < 0 ? err : count; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic __poll_t snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *file, 23562306a36Sopenharmony_ci poll_table *wait) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct usb_mixer_interface *mixer = hw->private_data; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci poll_wait(file, &mixer->rc_waitq, wait); 24062306a36Sopenharmony_ci return mixer->rc_code ? EPOLLIN | EPOLLRDNORM : 0; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct snd_hwdep *hwdep; 24662306a36Sopenharmony_ci int err, len, i; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rc_configs); ++i) 24962306a36Sopenharmony_ci if (rc_configs[i].usb_id == mixer->chip->usb_id) 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci if (i >= ARRAY_SIZE(rc_configs)) 25262306a36Sopenharmony_ci return 0; 25362306a36Sopenharmony_ci mixer->rc_cfg = &rc_configs[i]; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci len = mixer->rc_cfg->packet_length; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci init_waitqueue_head(&mixer->rc_waitq); 25862306a36Sopenharmony_ci err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep); 25962306a36Sopenharmony_ci if (err < 0) 26062306a36Sopenharmony_ci return err; 26162306a36Sopenharmony_ci snprintf(hwdep->name, sizeof(hwdep->name), 26262306a36Sopenharmony_ci "%s remote control", mixer->chip->card->shortname); 26362306a36Sopenharmony_ci hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC; 26462306a36Sopenharmony_ci hwdep->private_data = mixer; 26562306a36Sopenharmony_ci hwdep->ops.read = snd_usb_sbrc_hwdep_read; 26662306a36Sopenharmony_ci hwdep->ops.poll = snd_usb_sbrc_hwdep_poll; 26762306a36Sopenharmony_ci hwdep->exclusive = 1; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL); 27062306a36Sopenharmony_ci if (!mixer->rc_urb) 27162306a36Sopenharmony_ci return -ENOMEM; 27262306a36Sopenharmony_ci mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL); 27362306a36Sopenharmony_ci if (!mixer->rc_setup_packet) { 27462306a36Sopenharmony_ci usb_free_urb(mixer->rc_urb); 27562306a36Sopenharmony_ci mixer->rc_urb = NULL; 27662306a36Sopenharmony_ci return -ENOMEM; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci mixer->rc_setup_packet->bRequestType = 27962306a36Sopenharmony_ci USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; 28062306a36Sopenharmony_ci mixer->rc_setup_packet->bRequest = UAC_GET_MEM; 28162306a36Sopenharmony_ci mixer->rc_setup_packet->wValue = cpu_to_le16(0); 28262306a36Sopenharmony_ci mixer->rc_setup_packet->wIndex = cpu_to_le16(0); 28362306a36Sopenharmony_ci mixer->rc_setup_packet->wLength = cpu_to_le16(len); 28462306a36Sopenharmony_ci usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev, 28562306a36Sopenharmony_ci usb_rcvctrlpipe(mixer->chip->dev, 0), 28662306a36Sopenharmony_ci (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len, 28762306a36Sopenharmony_ci snd_usb_soundblaster_remote_complete, mixer); 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci#define snd_audigy2nx_led_info snd_ctl_boolean_mono_info 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci ucontrol->value.integer.value[0] = kcontrol->private_value >> 8; 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer, 30062306a36Sopenharmony_ci int value, int index) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct snd_usb_audio *chip = mixer->chip; 30362306a36Sopenharmony_ci int err; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 30662306a36Sopenharmony_ci if (err < 0) 30762306a36Sopenharmony_ci return err; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (chip->usb_id == USB_ID(0x041e, 0x3042)) 31062306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 31162306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), 0x24, 31262306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 31362306a36Sopenharmony_ci !value, 0, NULL, 0); 31462306a36Sopenharmony_ci /* USB X-Fi S51 Pro */ 31562306a36Sopenharmony_ci if (chip->usb_id == USB_ID(0x041e, 0x30df)) 31662306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 31762306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), 0x24, 31862306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 31962306a36Sopenharmony_ci !value, 0, NULL, 0); 32062306a36Sopenharmony_ci else 32162306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 32262306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), 0x24, 32362306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 32462306a36Sopenharmony_ci value, index + 2, NULL, 0); 32562306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 32662306a36Sopenharmony_ci return err; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, 33062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 33362306a36Sopenharmony_ci struct usb_mixer_interface *mixer = list->mixer; 33462306a36Sopenharmony_ci int index = kcontrol->private_value & 0xff; 33562306a36Sopenharmony_ci unsigned int value = ucontrol->value.integer.value[0]; 33662306a36Sopenharmony_ci int old_value = kcontrol->private_value >> 8; 33762306a36Sopenharmony_ci int err; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (value > 1) 34062306a36Sopenharmony_ci return -EINVAL; 34162306a36Sopenharmony_ci if (value == old_value) 34262306a36Sopenharmony_ci return 0; 34362306a36Sopenharmony_ci kcontrol->private_value = (value << 8) | index; 34462306a36Sopenharmony_ci err = snd_audigy2nx_led_update(mixer, value, index); 34562306a36Sopenharmony_ci return err < 0 ? err : 1; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int snd_audigy2nx_led_resume(struct usb_mixer_elem_list *list) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci int priv_value = list->kctl->private_value; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return snd_audigy2nx_led_update(list->mixer, priv_value >> 8, 35362306a36Sopenharmony_ci priv_value & 0xff); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/* name and private_value are set dynamically */ 35762306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_audigy2nx_control = { 35862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 35962306a36Sopenharmony_ci .info = snd_audigy2nx_led_info, 36062306a36Sopenharmony_ci .get = snd_audigy2nx_led_get, 36162306a36Sopenharmony_ci .put = snd_audigy2nx_led_put, 36262306a36Sopenharmony_ci}; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic const char * const snd_audigy2nx_led_names[] = { 36562306a36Sopenharmony_ci "CMSS LED Switch", 36662306a36Sopenharmony_ci "Power LED Switch", 36762306a36Sopenharmony_ci "Dolby Digital LED Switch", 36862306a36Sopenharmony_ci}; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci int i, err; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_led_names); ++i) { 37562306a36Sopenharmony_ci struct snd_kcontrol_new knew; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* USB X-Fi S51 doesn't have a CMSS LED */ 37862306a36Sopenharmony_ci if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0) 37962306a36Sopenharmony_ci continue; 38062306a36Sopenharmony_ci /* USB X-Fi S51 Pro doesn't have one either */ 38162306a36Sopenharmony_ci if ((mixer->chip->usb_id == USB_ID(0x041e, 0x30df)) && i == 0) 38262306a36Sopenharmony_ci continue; 38362306a36Sopenharmony_ci if (i > 1 && /* Live24ext has 2 LEDs only */ 38462306a36Sopenharmony_ci (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 38562306a36Sopenharmony_ci mixer->chip->usb_id == USB_ID(0x041e, 0x3042) || 38662306a36Sopenharmony_ci mixer->chip->usb_id == USB_ID(0x041e, 0x30df) || 38762306a36Sopenharmony_ci mixer->chip->usb_id == USB_ID(0x041e, 0x3048))) 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci knew = snd_audigy2nx_control; 39162306a36Sopenharmony_ci knew.name = snd_audigy2nx_led_names[i]; 39262306a36Sopenharmony_ci knew.private_value = (1 << 8) | i; /* LED on as default */ 39362306a36Sopenharmony_ci err = add_single_ctl_with_resume(mixer, 0, 39462306a36Sopenharmony_ci snd_audigy2nx_led_resume, 39562306a36Sopenharmony_ci &knew, NULL); 39662306a36Sopenharmony_ci if (err < 0) 39762306a36Sopenharmony_ci return err; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci return 0; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic void snd_audigy2nx_proc_read(struct snd_info_entry *entry, 40362306a36Sopenharmony_ci struct snd_info_buffer *buffer) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci static const struct sb_jack { 40662306a36Sopenharmony_ci int unitid; 40762306a36Sopenharmony_ci const char *name; 40862306a36Sopenharmony_ci } jacks_audigy2nx[] = { 40962306a36Sopenharmony_ci {4, "dig in "}, 41062306a36Sopenharmony_ci {7, "line in"}, 41162306a36Sopenharmony_ci {19, "spk out"}, 41262306a36Sopenharmony_ci {20, "hph out"}, 41362306a36Sopenharmony_ci {-1, NULL} 41462306a36Sopenharmony_ci }, jacks_live24ext[] = { 41562306a36Sopenharmony_ci {4, "line in"}, /* &1=Line, &2=Mic*/ 41662306a36Sopenharmony_ci {3, "hph out"}, /* headphones */ 41762306a36Sopenharmony_ci {0, "RC "}, /* last command, 6 bytes see rc_config above */ 41862306a36Sopenharmony_ci {-1, NULL} 41962306a36Sopenharmony_ci }; 42062306a36Sopenharmony_ci const struct sb_jack *jacks; 42162306a36Sopenharmony_ci struct usb_mixer_interface *mixer = entry->private_data; 42262306a36Sopenharmony_ci int i, err; 42362306a36Sopenharmony_ci u8 buf[3]; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname); 42662306a36Sopenharmony_ci if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) 42762306a36Sopenharmony_ci jacks = jacks_audigy2nx; 42862306a36Sopenharmony_ci else if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 42962306a36Sopenharmony_ci mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) 43062306a36Sopenharmony_ci jacks = jacks_live24ext; 43162306a36Sopenharmony_ci else 43262306a36Sopenharmony_ci return; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci for (i = 0; jacks[i].name; ++i) { 43562306a36Sopenharmony_ci snd_iprintf(buffer, "%s: ", jacks[i].name); 43662306a36Sopenharmony_ci err = snd_usb_lock_shutdown(mixer->chip); 43762306a36Sopenharmony_ci if (err < 0) 43862306a36Sopenharmony_ci return; 43962306a36Sopenharmony_ci err = snd_usb_ctl_msg(mixer->chip->dev, 44062306a36Sopenharmony_ci usb_rcvctrlpipe(mixer->chip->dev, 0), 44162306a36Sopenharmony_ci UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | 44262306a36Sopenharmony_ci USB_RECIP_INTERFACE, 0, 44362306a36Sopenharmony_ci jacks[i].unitid << 8, buf, 3); 44462306a36Sopenharmony_ci snd_usb_unlock_shutdown(mixer->chip); 44562306a36Sopenharmony_ci if (err == 3 && (buf[0] == 3 || buf[0] == 6)) 44662306a36Sopenharmony_ci snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); 44762306a36Sopenharmony_ci else 44862306a36Sopenharmony_ci snd_iprintf(buffer, "?\n"); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci/* EMU0204 */ 45362306a36Sopenharmony_cistatic int snd_emu0204_ch_switch_info(struct snd_kcontrol *kcontrol, 45462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci static const char * const texts[2] = {"1/2", "3/4"}; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol, 46262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = kcontrol->private_value; 46562306a36Sopenharmony_ci return 0; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic int snd_emu0204_ch_switch_update(struct usb_mixer_interface *mixer, 46962306a36Sopenharmony_ci int value) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct snd_usb_audio *chip = mixer->chip; 47262306a36Sopenharmony_ci int err; 47362306a36Sopenharmony_ci unsigned char buf[2]; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 47662306a36Sopenharmony_ci if (err < 0) 47762306a36Sopenharmony_ci return err; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci buf[0] = 0x01; 48062306a36Sopenharmony_ci buf[1] = value ? 0x02 : 0x01; 48162306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 48262306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, 48362306a36Sopenharmony_ci USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 48462306a36Sopenharmony_ci 0x0400, 0x0e00, buf, 2); 48562306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 48662306a36Sopenharmony_ci return err; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol, 49062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 49362306a36Sopenharmony_ci struct usb_mixer_interface *mixer = list->mixer; 49462306a36Sopenharmony_ci unsigned int value = ucontrol->value.enumerated.item[0]; 49562306a36Sopenharmony_ci int err; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (value > 1) 49862306a36Sopenharmony_ci return -EINVAL; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (value == kcontrol->private_value) 50162306a36Sopenharmony_ci return 0; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci kcontrol->private_value = value; 50462306a36Sopenharmony_ci err = snd_emu0204_ch_switch_update(mixer, value); 50562306a36Sopenharmony_ci return err < 0 ? err : 1; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic int snd_emu0204_ch_switch_resume(struct usb_mixer_elem_list *list) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci return snd_emu0204_ch_switch_update(list->mixer, 51162306a36Sopenharmony_ci list->kctl->private_value); 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu0204_control = { 51562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 51662306a36Sopenharmony_ci .name = "Front Jack Channels", 51762306a36Sopenharmony_ci .info = snd_emu0204_ch_switch_info, 51862306a36Sopenharmony_ci .get = snd_emu0204_ch_switch_get, 51962306a36Sopenharmony_ci .put = snd_emu0204_ch_switch_put, 52062306a36Sopenharmony_ci .private_value = 0, 52162306a36Sopenharmony_ci}; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic int snd_emu0204_controls_create(struct usb_mixer_interface *mixer) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci return add_single_ctl_with_resume(mixer, 0, 52662306a36Sopenharmony_ci snd_emu0204_ch_switch_resume, 52762306a36Sopenharmony_ci &snd_emu0204_control, NULL); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci/* ASUS Xonar U1 / U3 controls */ 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, 53362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci ucontrol->value.integer.value[0] = !!(kcontrol->private_value & 0x02); 53662306a36Sopenharmony_ci return 0; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int snd_xonar_u1_switch_update(struct usb_mixer_interface *mixer, 54062306a36Sopenharmony_ci unsigned char status) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct snd_usb_audio *chip = mixer->chip; 54362306a36Sopenharmony_ci int err; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 54662306a36Sopenharmony_ci if (err < 0) 54762306a36Sopenharmony_ci return err; 54862306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 54962306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), 0x08, 55062306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 55162306a36Sopenharmony_ci 50, 0, &status, 1); 55262306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 55362306a36Sopenharmony_ci return err; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, 55762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 56062306a36Sopenharmony_ci u8 old_status, new_status; 56162306a36Sopenharmony_ci int err; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci old_status = kcontrol->private_value; 56462306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) 56562306a36Sopenharmony_ci new_status = old_status | 0x02; 56662306a36Sopenharmony_ci else 56762306a36Sopenharmony_ci new_status = old_status & ~0x02; 56862306a36Sopenharmony_ci if (new_status == old_status) 56962306a36Sopenharmony_ci return 0; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci kcontrol->private_value = new_status; 57262306a36Sopenharmony_ci err = snd_xonar_u1_switch_update(list->mixer, new_status); 57362306a36Sopenharmony_ci return err < 0 ? err : 1; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic int snd_xonar_u1_switch_resume(struct usb_mixer_elem_list *list) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci return snd_xonar_u1_switch_update(list->mixer, 57962306a36Sopenharmony_ci list->kctl->private_value); 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_xonar_u1_output_switch = { 58362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 58462306a36Sopenharmony_ci .name = "Digital Playback Switch", 58562306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 58662306a36Sopenharmony_ci .get = snd_xonar_u1_switch_get, 58762306a36Sopenharmony_ci .put = snd_xonar_u1_switch_put, 58862306a36Sopenharmony_ci .private_value = 0x05, 58962306a36Sopenharmony_ci}; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci return add_single_ctl_with_resume(mixer, 0, 59462306a36Sopenharmony_ci snd_xonar_u1_switch_resume, 59562306a36Sopenharmony_ci &snd_xonar_u1_output_switch, NULL); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/* Digidesign Mbox 1 helper functions */ 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic int snd_mbox1_is_spdif_synced(struct snd_usb_audio *chip) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci unsigned char buff[3]; 60362306a36Sopenharmony_ci int err; 60462306a36Sopenharmony_ci int is_spdif_synced; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci /* Read clock source */ 60762306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 60862306a36Sopenharmony_ci usb_rcvctrlpipe(chip->dev, 0), 0x81, 60962306a36Sopenharmony_ci USB_DIR_IN | 61062306a36Sopenharmony_ci USB_TYPE_CLASS | 61162306a36Sopenharmony_ci USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3); 61262306a36Sopenharmony_ci if (err < 0) 61362306a36Sopenharmony_ci return err; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* spdif sync: buff is all zeroes */ 61662306a36Sopenharmony_ci is_spdif_synced = !(buff[0] | buff[1] | buff[2]); 61762306a36Sopenharmony_ci return is_spdif_synced; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic int snd_mbox1_set_clk_source(struct snd_usb_audio *chip, int rate_or_zero) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci /* 2 possibilities: Internal -> expects sample rate 62362306a36Sopenharmony_ci * S/PDIF sync -> expects rate = 0 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ci unsigned char buff[3]; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci buff[0] = (rate_or_zero >> 0) & 0xff; 62862306a36Sopenharmony_ci buff[1] = (rate_or_zero >> 8) & 0xff; 62962306a36Sopenharmony_ci buff[2] = (rate_or_zero >> 16) & 0xff; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* Set clock source */ 63262306a36Sopenharmony_ci return snd_usb_ctl_msg(chip->dev, 63362306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), 0x1, 63462306a36Sopenharmony_ci USB_TYPE_CLASS | 63562306a36Sopenharmony_ci USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3); 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic int snd_mbox1_is_spdif_input(struct snd_usb_audio *chip) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci /* Hardware gives 2 possibilities: ANALOG Source -> 0x01 64162306a36Sopenharmony_ci * S/PDIF Source -> 0x02 64262306a36Sopenharmony_ci */ 64362306a36Sopenharmony_ci int err; 64462306a36Sopenharmony_ci unsigned char source[1]; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* Read input source */ 64762306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 64862306a36Sopenharmony_ci usb_rcvctrlpipe(chip->dev, 0), 0x81, 64962306a36Sopenharmony_ci USB_DIR_IN | 65062306a36Sopenharmony_ci USB_TYPE_CLASS | 65162306a36Sopenharmony_ci USB_RECIP_INTERFACE, 0x00, 0x500, source, 1); 65262306a36Sopenharmony_ci if (err < 0) 65362306a36Sopenharmony_ci return err; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci return (source[0] == 2); 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic int snd_mbox1_set_input_source(struct snd_usb_audio *chip, int is_spdif) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci /* NB: Setting the input source to S/PDIF resets the clock source to S/PDIF 66162306a36Sopenharmony_ci * Hardware expects 2 possibilities: ANALOG Source -> 0x01 66262306a36Sopenharmony_ci * S/PDIF Source -> 0x02 66362306a36Sopenharmony_ci */ 66462306a36Sopenharmony_ci unsigned char buff[1]; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci buff[0] = (is_spdif & 1) + 1; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* Set input source */ 66962306a36Sopenharmony_ci return snd_usb_ctl_msg(chip->dev, 67062306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), 0x1, 67162306a36Sopenharmony_ci USB_TYPE_CLASS | 67262306a36Sopenharmony_ci USB_RECIP_INTERFACE, 0x00, 0x500, buff, 1); 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci/* Digidesign Mbox 1 clock source switch (internal/spdif) */ 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic int snd_mbox1_clk_switch_get(struct snd_kcontrol *kctl, 67862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); 68162306a36Sopenharmony_ci struct snd_usb_audio *chip = list->mixer->chip; 68262306a36Sopenharmony_ci int err; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 68562306a36Sopenharmony_ci if (err < 0) 68662306a36Sopenharmony_ci goto err; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci err = snd_mbox1_is_spdif_synced(chip); 68962306a36Sopenharmony_ci if (err < 0) 69062306a36Sopenharmony_ci goto err; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci kctl->private_value = err; 69362306a36Sopenharmony_ci err = 0; 69462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = kctl->private_value; 69562306a36Sopenharmony_cierr: 69662306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 69762306a36Sopenharmony_ci return err; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic int snd_mbox1_clk_switch_update(struct usb_mixer_interface *mixer, int is_spdif_sync) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci struct snd_usb_audio *chip = mixer->chip; 70362306a36Sopenharmony_ci int err; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 70662306a36Sopenharmony_ci if (err < 0) 70762306a36Sopenharmony_ci return err; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci err = snd_mbox1_is_spdif_input(chip); 71062306a36Sopenharmony_ci if (err < 0) 71162306a36Sopenharmony_ci goto err; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci err = snd_mbox1_is_spdif_synced(chip); 71462306a36Sopenharmony_ci if (err < 0) 71562306a36Sopenharmony_ci goto err; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci /* FIXME: hardcoded sample rate */ 71862306a36Sopenharmony_ci err = snd_mbox1_set_clk_source(chip, is_spdif_sync ? 0 : 48000); 71962306a36Sopenharmony_ci if (err < 0) 72062306a36Sopenharmony_ci goto err; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci err = snd_mbox1_is_spdif_synced(chip); 72362306a36Sopenharmony_cierr: 72462306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 72562306a36Sopenharmony_ci return err; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic int snd_mbox1_clk_switch_put(struct snd_kcontrol *kctl, 72962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); 73262306a36Sopenharmony_ci struct usb_mixer_interface *mixer = list->mixer; 73362306a36Sopenharmony_ci int err; 73462306a36Sopenharmony_ci bool cur_val, new_val; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci cur_val = kctl->private_value; 73762306a36Sopenharmony_ci new_val = ucontrol->value.enumerated.item[0]; 73862306a36Sopenharmony_ci if (cur_val == new_val) 73962306a36Sopenharmony_ci return 0; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci kctl->private_value = new_val; 74262306a36Sopenharmony_ci err = snd_mbox1_clk_switch_update(mixer, new_val); 74362306a36Sopenharmony_ci return err < 0 ? err : 1; 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic int snd_mbox1_clk_switch_info(struct snd_kcontrol *kcontrol, 74762306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci static const char *const texts[2] = { 75062306a36Sopenharmony_ci "Internal", 75162306a36Sopenharmony_ci "S/PDIF" 75262306a36Sopenharmony_ci }; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic int snd_mbox1_clk_switch_resume(struct usb_mixer_elem_list *list) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci return snd_mbox1_clk_switch_update(list->mixer, list->kctl->private_value); 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci/* Digidesign Mbox 1 input source switch (analog/spdif) */ 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic int snd_mbox1_src_switch_get(struct snd_kcontrol *kctl, 76562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = kctl->private_value; 76862306a36Sopenharmony_ci return 0; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic int snd_mbox1_src_switch_update(struct usb_mixer_interface *mixer, int is_spdif_input) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci struct snd_usb_audio *chip = mixer->chip; 77462306a36Sopenharmony_ci int err; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 77762306a36Sopenharmony_ci if (err < 0) 77862306a36Sopenharmony_ci return err; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci err = snd_mbox1_is_spdif_input(chip); 78162306a36Sopenharmony_ci if (err < 0) 78262306a36Sopenharmony_ci goto err; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci err = snd_mbox1_set_input_source(chip, is_spdif_input); 78562306a36Sopenharmony_ci if (err < 0) 78662306a36Sopenharmony_ci goto err; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci err = snd_mbox1_is_spdif_input(chip); 78962306a36Sopenharmony_ci if (err < 0) 79062306a36Sopenharmony_ci goto err; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci err = snd_mbox1_is_spdif_synced(chip); 79362306a36Sopenharmony_cierr: 79462306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 79562306a36Sopenharmony_ci return err; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic int snd_mbox1_src_switch_put(struct snd_kcontrol *kctl, 79962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); 80262306a36Sopenharmony_ci struct usb_mixer_interface *mixer = list->mixer; 80362306a36Sopenharmony_ci int err; 80462306a36Sopenharmony_ci bool cur_val, new_val; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci cur_val = kctl->private_value; 80762306a36Sopenharmony_ci new_val = ucontrol->value.enumerated.item[0]; 80862306a36Sopenharmony_ci if (cur_val == new_val) 80962306a36Sopenharmony_ci return 0; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci kctl->private_value = new_val; 81262306a36Sopenharmony_ci err = snd_mbox1_src_switch_update(mixer, new_val); 81362306a36Sopenharmony_ci return err < 0 ? err : 1; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic int snd_mbox1_src_switch_info(struct snd_kcontrol *kcontrol, 81762306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci static const char *const texts[2] = { 82062306a36Sopenharmony_ci "Analog", 82162306a36Sopenharmony_ci "S/PDIF" 82262306a36Sopenharmony_ci }; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic int snd_mbox1_src_switch_resume(struct usb_mixer_elem_list *list) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci return snd_mbox1_src_switch_update(list->mixer, list->kctl->private_value); 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_mbox1_clk_switch = { 83362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 83462306a36Sopenharmony_ci .name = "Clock Source", 83562306a36Sopenharmony_ci .index = 0, 83662306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 83762306a36Sopenharmony_ci .info = snd_mbox1_clk_switch_info, 83862306a36Sopenharmony_ci .get = snd_mbox1_clk_switch_get, 83962306a36Sopenharmony_ci .put = snd_mbox1_clk_switch_put, 84062306a36Sopenharmony_ci .private_value = 0 84162306a36Sopenharmony_ci}; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_mbox1_src_switch = { 84462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 84562306a36Sopenharmony_ci .name = "Input Source", 84662306a36Sopenharmony_ci .index = 1, 84762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 84862306a36Sopenharmony_ci .info = snd_mbox1_src_switch_info, 84962306a36Sopenharmony_ci .get = snd_mbox1_src_switch_get, 85062306a36Sopenharmony_ci .put = snd_mbox1_src_switch_put, 85162306a36Sopenharmony_ci .private_value = 0 85262306a36Sopenharmony_ci}; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_cistatic int snd_mbox1_controls_create(struct usb_mixer_interface *mixer) 85562306a36Sopenharmony_ci{ 85662306a36Sopenharmony_ci int err; 85762306a36Sopenharmony_ci err = add_single_ctl_with_resume(mixer, 0, 85862306a36Sopenharmony_ci snd_mbox1_clk_switch_resume, 85962306a36Sopenharmony_ci &snd_mbox1_clk_switch, NULL); 86062306a36Sopenharmony_ci if (err < 0) 86162306a36Sopenharmony_ci return err; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci return add_single_ctl_with_resume(mixer, 1, 86462306a36Sopenharmony_ci snd_mbox1_src_switch_resume, 86562306a36Sopenharmony_ci &snd_mbox1_src_switch, NULL); 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci/* Native Instruments device quirks */ 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci#define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex)) 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_cistatic int snd_ni_control_init_val(struct usb_mixer_interface *mixer, 87362306a36Sopenharmony_ci struct snd_kcontrol *kctl) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci struct usb_device *dev = mixer->chip->dev; 87662306a36Sopenharmony_ci unsigned int pval = kctl->private_value; 87762306a36Sopenharmony_ci u8 value; 87862306a36Sopenharmony_ci int err; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 88162306a36Sopenharmony_ci (pval >> 16) & 0xff, 88262306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 88362306a36Sopenharmony_ci 0, pval & 0xffff, &value, 1); 88462306a36Sopenharmony_ci if (err < 0) { 88562306a36Sopenharmony_ci dev_err(&dev->dev, 88662306a36Sopenharmony_ci "unable to issue vendor read request (ret = %d)", err); 88762306a36Sopenharmony_ci return err; 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci kctl->private_value |= ((unsigned int)value << 24); 89162306a36Sopenharmony_ci return 0; 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, 89562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci ucontrol->value.integer.value[0] = kcontrol->private_value >> 24; 89862306a36Sopenharmony_ci return 0; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic int snd_ni_update_cur_val(struct usb_mixer_elem_list *list) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct snd_usb_audio *chip = list->mixer->chip; 90462306a36Sopenharmony_ci unsigned int pval = list->kctl->private_value; 90562306a36Sopenharmony_ci int err; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 90862306a36Sopenharmony_ci if (err < 0) 90962306a36Sopenharmony_ci return err; 91062306a36Sopenharmony_ci err = usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), 91162306a36Sopenharmony_ci (pval >> 16) & 0xff, 91262306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 91362306a36Sopenharmony_ci pval >> 24, pval & 0xffff, NULL, 0, 1000); 91462306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 91562306a36Sopenharmony_ci return err; 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_cistatic int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, 91962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 92262306a36Sopenharmony_ci u8 oldval = (kcontrol->private_value >> 24) & 0xff; 92362306a36Sopenharmony_ci u8 newval = ucontrol->value.integer.value[0]; 92462306a36Sopenharmony_ci int err; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (oldval == newval) 92762306a36Sopenharmony_ci return 0; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci kcontrol->private_value &= ~(0xff << 24); 93062306a36Sopenharmony_ci kcontrol->private_value |= (unsigned int)newval << 24; 93162306a36Sopenharmony_ci err = snd_ni_update_cur_val(list); 93262306a36Sopenharmony_ci return err < 0 ? err : 1; 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = { 93662306a36Sopenharmony_ci { 93762306a36Sopenharmony_ci .name = "Direct Thru Channel A", 93862306a36Sopenharmony_ci .private_value = _MAKE_NI_CONTROL(0x01, 0x03), 93962306a36Sopenharmony_ci }, 94062306a36Sopenharmony_ci { 94162306a36Sopenharmony_ci .name = "Direct Thru Channel B", 94262306a36Sopenharmony_ci .private_value = _MAKE_NI_CONTROL(0x01, 0x05), 94362306a36Sopenharmony_ci }, 94462306a36Sopenharmony_ci { 94562306a36Sopenharmony_ci .name = "Phono Input Channel A", 94662306a36Sopenharmony_ci .private_value = _MAKE_NI_CONTROL(0x02, 0x03), 94762306a36Sopenharmony_ci }, 94862306a36Sopenharmony_ci { 94962306a36Sopenharmony_ci .name = "Phono Input Channel B", 95062306a36Sopenharmony_ci .private_value = _MAKE_NI_CONTROL(0x02, 0x05), 95162306a36Sopenharmony_ci }, 95262306a36Sopenharmony_ci}; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_nativeinstruments_ta10_mixers[] = { 95562306a36Sopenharmony_ci { 95662306a36Sopenharmony_ci .name = "Direct Thru Channel A", 95762306a36Sopenharmony_ci .private_value = _MAKE_NI_CONTROL(0x01, 0x03), 95862306a36Sopenharmony_ci }, 95962306a36Sopenharmony_ci { 96062306a36Sopenharmony_ci .name = "Direct Thru Channel B", 96162306a36Sopenharmony_ci .private_value = _MAKE_NI_CONTROL(0x01, 0x05), 96262306a36Sopenharmony_ci }, 96362306a36Sopenharmony_ci { 96462306a36Sopenharmony_ci .name = "Direct Thru Channel C", 96562306a36Sopenharmony_ci .private_value = _MAKE_NI_CONTROL(0x01, 0x07), 96662306a36Sopenharmony_ci }, 96762306a36Sopenharmony_ci { 96862306a36Sopenharmony_ci .name = "Direct Thru Channel D", 96962306a36Sopenharmony_ci .private_value = _MAKE_NI_CONTROL(0x01, 0x09), 97062306a36Sopenharmony_ci }, 97162306a36Sopenharmony_ci { 97262306a36Sopenharmony_ci .name = "Phono Input Channel A", 97362306a36Sopenharmony_ci .private_value = _MAKE_NI_CONTROL(0x02, 0x03), 97462306a36Sopenharmony_ci }, 97562306a36Sopenharmony_ci { 97662306a36Sopenharmony_ci .name = "Phono Input Channel B", 97762306a36Sopenharmony_ci .private_value = _MAKE_NI_CONTROL(0x02, 0x05), 97862306a36Sopenharmony_ci }, 97962306a36Sopenharmony_ci { 98062306a36Sopenharmony_ci .name = "Phono Input Channel C", 98162306a36Sopenharmony_ci .private_value = _MAKE_NI_CONTROL(0x02, 0x07), 98262306a36Sopenharmony_ci }, 98362306a36Sopenharmony_ci { 98462306a36Sopenharmony_ci .name = "Phono Input Channel D", 98562306a36Sopenharmony_ci .private_value = _MAKE_NI_CONTROL(0x02, 0x09), 98662306a36Sopenharmony_ci }, 98762306a36Sopenharmony_ci}; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_cistatic int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, 99062306a36Sopenharmony_ci const struct snd_kcontrol_new *kc, 99162306a36Sopenharmony_ci unsigned int count) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci int i, err = 0; 99462306a36Sopenharmony_ci struct snd_kcontrol_new template = { 99562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 99662306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 99762306a36Sopenharmony_ci .get = snd_nativeinstruments_control_get, 99862306a36Sopenharmony_ci .put = snd_nativeinstruments_control_put, 99962306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 100062306a36Sopenharmony_ci }; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci for (i = 0; i < count; i++) { 100362306a36Sopenharmony_ci struct usb_mixer_elem_list *list; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci template.name = kc[i].name; 100662306a36Sopenharmony_ci template.private_value = kc[i].private_value; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci err = add_single_ctl_with_resume(mixer, 0, 100962306a36Sopenharmony_ci snd_ni_update_cur_val, 101062306a36Sopenharmony_ci &template, &list); 101162306a36Sopenharmony_ci if (err < 0) 101262306a36Sopenharmony_ci break; 101362306a36Sopenharmony_ci snd_ni_control_init_val(mixer, list->kctl); 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci return err; 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci/* M-Audio FastTrack Ultra quirks */ 102062306a36Sopenharmony_ci/* FTU Effect switch (also used by C400/C600) */ 102162306a36Sopenharmony_cistatic int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, 102262306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci static const char *const texts[8] = { 102562306a36Sopenharmony_ci "Room 1", "Room 2", "Room 3", "Hall 1", 102662306a36Sopenharmony_ci "Hall 2", "Plate", "Delay", "Echo" 102762306a36Sopenharmony_ci }; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_cistatic int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer, 103362306a36Sopenharmony_ci struct snd_kcontrol *kctl) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci struct usb_device *dev = mixer->chip->dev; 103662306a36Sopenharmony_ci unsigned int pval = kctl->private_value; 103762306a36Sopenharmony_ci int err; 103862306a36Sopenharmony_ci unsigned char value[2]; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci value[0] = 0x00; 104162306a36Sopenharmony_ci value[1] = 0x00; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, 104462306a36Sopenharmony_ci USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 104562306a36Sopenharmony_ci pval & 0xff00, 104662306a36Sopenharmony_ci snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8), 104762306a36Sopenharmony_ci value, 2); 104862306a36Sopenharmony_ci if (err < 0) 104962306a36Sopenharmony_ci return err; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci kctl->private_value |= (unsigned int)value[0] << 24; 105262306a36Sopenharmony_ci return 0; 105362306a36Sopenharmony_ci} 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_cistatic int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, 105662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = kctl->private_value >> 24; 105962306a36Sopenharmony_ci return 0; 106062306a36Sopenharmony_ci} 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_cistatic int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list) 106362306a36Sopenharmony_ci{ 106462306a36Sopenharmony_ci struct snd_usb_audio *chip = list->mixer->chip; 106562306a36Sopenharmony_ci unsigned int pval = list->kctl->private_value; 106662306a36Sopenharmony_ci unsigned char value[2]; 106762306a36Sopenharmony_ci int err; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci value[0] = pval >> 24; 107062306a36Sopenharmony_ci value[1] = 0; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 107362306a36Sopenharmony_ci if (err < 0) 107462306a36Sopenharmony_ci return err; 107562306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 107662306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), 107762306a36Sopenharmony_ci UAC_SET_CUR, 107862306a36Sopenharmony_ci USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 107962306a36Sopenharmony_ci pval & 0xff00, 108062306a36Sopenharmony_ci snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8), 108162306a36Sopenharmony_ci value, 2); 108262306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 108362306a36Sopenharmony_ci return err; 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_cistatic int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, 108762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); 109062306a36Sopenharmony_ci unsigned int pval = list->kctl->private_value; 109162306a36Sopenharmony_ci int cur_val, err, new_val; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci cur_val = pval >> 24; 109462306a36Sopenharmony_ci new_val = ucontrol->value.enumerated.item[0]; 109562306a36Sopenharmony_ci if (cur_val == new_val) 109662306a36Sopenharmony_ci return 0; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci kctl->private_value &= ~(0xff << 24); 109962306a36Sopenharmony_ci kctl->private_value |= new_val << 24; 110062306a36Sopenharmony_ci err = snd_ftu_eff_switch_update(list); 110162306a36Sopenharmony_ci return err < 0 ? err : 1; 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cistatic int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer, 110562306a36Sopenharmony_ci int validx, int bUnitID) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci static struct snd_kcontrol_new template = { 110862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 110962306a36Sopenharmony_ci .name = "Effect Program Switch", 111062306a36Sopenharmony_ci .index = 0, 111162306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 111262306a36Sopenharmony_ci .info = snd_ftu_eff_switch_info, 111362306a36Sopenharmony_ci .get = snd_ftu_eff_switch_get, 111462306a36Sopenharmony_ci .put = snd_ftu_eff_switch_put 111562306a36Sopenharmony_ci }; 111662306a36Sopenharmony_ci struct usb_mixer_elem_list *list; 111762306a36Sopenharmony_ci int err; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci err = add_single_ctl_with_resume(mixer, bUnitID, 112062306a36Sopenharmony_ci snd_ftu_eff_switch_update, 112162306a36Sopenharmony_ci &template, &list); 112262306a36Sopenharmony_ci if (err < 0) 112362306a36Sopenharmony_ci return err; 112462306a36Sopenharmony_ci list->kctl->private_value = (validx << 8) | bUnitID; 112562306a36Sopenharmony_ci snd_ftu_eff_switch_init(mixer, list->kctl); 112662306a36Sopenharmony_ci return 0; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci/* Create volume controls for FTU devices*/ 113062306a36Sopenharmony_cistatic int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci char name[64]; 113362306a36Sopenharmony_ci unsigned int control, cmask; 113462306a36Sopenharmony_ci int in, out, err; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci const unsigned int id = 5; 113762306a36Sopenharmony_ci const int val_type = USB_MIXER_S16; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci for (out = 0; out < 8; out++) { 114062306a36Sopenharmony_ci control = out + 1; 114162306a36Sopenharmony_ci for (in = 0; in < 8; in++) { 114262306a36Sopenharmony_ci cmask = 1 << in; 114362306a36Sopenharmony_ci snprintf(name, sizeof(name), 114462306a36Sopenharmony_ci "AIn%d - Out%d Capture Volume", 114562306a36Sopenharmony_ci in + 1, out + 1); 114662306a36Sopenharmony_ci err = snd_create_std_mono_ctl(mixer, id, control, 114762306a36Sopenharmony_ci cmask, val_type, name, 114862306a36Sopenharmony_ci &snd_usb_mixer_vol_tlv); 114962306a36Sopenharmony_ci if (err < 0) 115062306a36Sopenharmony_ci return err; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci for (in = 8; in < 16; in++) { 115362306a36Sopenharmony_ci cmask = 1 << in; 115462306a36Sopenharmony_ci snprintf(name, sizeof(name), 115562306a36Sopenharmony_ci "DIn%d - Out%d Playback Volume", 115662306a36Sopenharmony_ci in - 7, out + 1); 115762306a36Sopenharmony_ci err = snd_create_std_mono_ctl(mixer, id, control, 115862306a36Sopenharmony_ci cmask, val_type, name, 115962306a36Sopenharmony_ci &snd_usb_mixer_vol_tlv); 116062306a36Sopenharmony_ci if (err < 0) 116162306a36Sopenharmony_ci return err; 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci return 0; 116662306a36Sopenharmony_ci} 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci/* This control needs a volume quirk, see mixer.c */ 116962306a36Sopenharmony_cistatic int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci static const char name[] = "Effect Volume"; 117262306a36Sopenharmony_ci const unsigned int id = 6; 117362306a36Sopenharmony_ci const int val_type = USB_MIXER_U8; 117462306a36Sopenharmony_ci const unsigned int control = 2; 117562306a36Sopenharmony_ci const unsigned int cmask = 0; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 117862306a36Sopenharmony_ci name, snd_usb_mixer_vol_tlv); 117962306a36Sopenharmony_ci} 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci/* This control needs a volume quirk, see mixer.c */ 118262306a36Sopenharmony_cistatic int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer) 118362306a36Sopenharmony_ci{ 118462306a36Sopenharmony_ci static const char name[] = "Effect Duration"; 118562306a36Sopenharmony_ci const unsigned int id = 6; 118662306a36Sopenharmony_ci const int val_type = USB_MIXER_S16; 118762306a36Sopenharmony_ci const unsigned int control = 3; 118862306a36Sopenharmony_ci const unsigned int cmask = 0; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 119162306a36Sopenharmony_ci name, snd_usb_mixer_vol_tlv); 119262306a36Sopenharmony_ci} 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci/* This control needs a volume quirk, see mixer.c */ 119562306a36Sopenharmony_cistatic int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci static const char name[] = "Effect Feedback Volume"; 119862306a36Sopenharmony_ci const unsigned int id = 6; 119962306a36Sopenharmony_ci const int val_type = USB_MIXER_U8; 120062306a36Sopenharmony_ci const unsigned int control = 4; 120162306a36Sopenharmony_ci const unsigned int cmask = 0; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 120462306a36Sopenharmony_ci name, NULL); 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_cistatic int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer) 120862306a36Sopenharmony_ci{ 120962306a36Sopenharmony_ci unsigned int cmask; 121062306a36Sopenharmony_ci int err, ch; 121162306a36Sopenharmony_ci char name[48]; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci const unsigned int id = 7; 121462306a36Sopenharmony_ci const int val_type = USB_MIXER_S16; 121562306a36Sopenharmony_ci const unsigned int control = 7; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci for (ch = 0; ch < 4; ++ch) { 121862306a36Sopenharmony_ci cmask = 1 << ch; 121962306a36Sopenharmony_ci snprintf(name, sizeof(name), 122062306a36Sopenharmony_ci "Effect Return %d Volume", ch + 1); 122162306a36Sopenharmony_ci err = snd_create_std_mono_ctl(mixer, id, control, 122262306a36Sopenharmony_ci cmask, val_type, name, 122362306a36Sopenharmony_ci snd_usb_mixer_vol_tlv); 122462306a36Sopenharmony_ci if (err < 0) 122562306a36Sopenharmony_ci return err; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci return 0; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci unsigned int cmask; 123462306a36Sopenharmony_ci int err, ch; 123562306a36Sopenharmony_ci char name[48]; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci const unsigned int id = 5; 123862306a36Sopenharmony_ci const int val_type = USB_MIXER_S16; 123962306a36Sopenharmony_ci const unsigned int control = 9; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci for (ch = 0; ch < 8; ++ch) { 124262306a36Sopenharmony_ci cmask = 1 << ch; 124362306a36Sopenharmony_ci snprintf(name, sizeof(name), 124462306a36Sopenharmony_ci "Effect Send AIn%d Volume", ch + 1); 124562306a36Sopenharmony_ci err = snd_create_std_mono_ctl(mixer, id, control, cmask, 124662306a36Sopenharmony_ci val_type, name, 124762306a36Sopenharmony_ci snd_usb_mixer_vol_tlv); 124862306a36Sopenharmony_ci if (err < 0) 124962306a36Sopenharmony_ci return err; 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci for (ch = 8; ch < 16; ++ch) { 125262306a36Sopenharmony_ci cmask = 1 << ch; 125362306a36Sopenharmony_ci snprintf(name, sizeof(name), 125462306a36Sopenharmony_ci "Effect Send DIn%d Volume", ch - 7); 125562306a36Sopenharmony_ci err = snd_create_std_mono_ctl(mixer, id, control, cmask, 125662306a36Sopenharmony_ci val_type, name, 125762306a36Sopenharmony_ci snd_usb_mixer_vol_tlv); 125862306a36Sopenharmony_ci if (err < 0) 125962306a36Sopenharmony_ci return err; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci return 0; 126262306a36Sopenharmony_ci} 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_cistatic int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) 126562306a36Sopenharmony_ci{ 126662306a36Sopenharmony_ci int err; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci err = snd_ftu_create_volume_ctls(mixer); 126962306a36Sopenharmony_ci if (err < 0) 127062306a36Sopenharmony_ci return err; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci err = snd_ftu_create_effect_switch(mixer, 1, 6); 127362306a36Sopenharmony_ci if (err < 0) 127462306a36Sopenharmony_ci return err; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci err = snd_ftu_create_effect_volume_ctl(mixer); 127762306a36Sopenharmony_ci if (err < 0) 127862306a36Sopenharmony_ci return err; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci err = snd_ftu_create_effect_duration_ctl(mixer); 128162306a36Sopenharmony_ci if (err < 0) 128262306a36Sopenharmony_ci return err; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci err = snd_ftu_create_effect_feedback_ctl(mixer); 128562306a36Sopenharmony_ci if (err < 0) 128662306a36Sopenharmony_ci return err; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci err = snd_ftu_create_effect_return_ctls(mixer); 128962306a36Sopenharmony_ci if (err < 0) 129062306a36Sopenharmony_ci return err; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci err = snd_ftu_create_effect_send_ctls(mixer); 129362306a36Sopenharmony_ci if (err < 0) 129462306a36Sopenharmony_ci return err; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci return 0; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_civoid snd_emuusb_set_samplerate(struct snd_usb_audio *chip, 130062306a36Sopenharmony_ci unsigned char samplerate_id) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci struct usb_mixer_interface *mixer; 130362306a36Sopenharmony_ci struct usb_mixer_elem_info *cval; 130462306a36Sopenharmony_ci int unitid = 12; /* SampleRate ExtensionUnit ID */ 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci list_for_each_entry(mixer, &chip->mixer_list, list) { 130762306a36Sopenharmony_ci if (mixer->id_elems[unitid]) { 130862306a36Sopenharmony_ci cval = mixer_elem_list_to_info(mixer->id_elems[unitid]); 130962306a36Sopenharmony_ci snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, 131062306a36Sopenharmony_ci cval->control << 8, 131162306a36Sopenharmony_ci samplerate_id); 131262306a36Sopenharmony_ci snd_usb_mixer_notify_id(mixer, unitid); 131362306a36Sopenharmony_ci break; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci} 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci/* M-Audio Fast Track C400/C600 */ 131962306a36Sopenharmony_ci/* C400/C600 volume controls, this control needs a volume quirk, see mixer.c */ 132062306a36Sopenharmony_cistatic int snd_c400_create_vol_ctls(struct usb_mixer_interface *mixer) 132162306a36Sopenharmony_ci{ 132262306a36Sopenharmony_ci char name[64]; 132362306a36Sopenharmony_ci unsigned int cmask, offset; 132462306a36Sopenharmony_ci int out, chan, err; 132562306a36Sopenharmony_ci int num_outs = 0; 132662306a36Sopenharmony_ci int num_ins = 0; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci const unsigned int id = 0x40; 132962306a36Sopenharmony_ci const int val_type = USB_MIXER_S16; 133062306a36Sopenharmony_ci const int control = 1; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci switch (mixer->chip->usb_id) { 133362306a36Sopenharmony_ci case USB_ID(0x0763, 0x2030): 133462306a36Sopenharmony_ci num_outs = 6; 133562306a36Sopenharmony_ci num_ins = 4; 133662306a36Sopenharmony_ci break; 133762306a36Sopenharmony_ci case USB_ID(0x0763, 0x2031): 133862306a36Sopenharmony_ci num_outs = 8; 133962306a36Sopenharmony_ci num_ins = 6; 134062306a36Sopenharmony_ci break; 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci for (chan = 0; chan < num_outs + num_ins; chan++) { 134462306a36Sopenharmony_ci for (out = 0; out < num_outs; out++) { 134562306a36Sopenharmony_ci if (chan < num_outs) { 134662306a36Sopenharmony_ci snprintf(name, sizeof(name), 134762306a36Sopenharmony_ci "PCM%d-Out%d Playback Volume", 134862306a36Sopenharmony_ci chan + 1, out + 1); 134962306a36Sopenharmony_ci } else { 135062306a36Sopenharmony_ci snprintf(name, sizeof(name), 135162306a36Sopenharmony_ci "In%d-Out%d Playback Volume", 135262306a36Sopenharmony_ci chan - num_outs + 1, out + 1); 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci cmask = (out == 0) ? 0 : 1 << (out - 1); 135662306a36Sopenharmony_ci offset = chan * num_outs; 135762306a36Sopenharmony_ci err = snd_create_std_mono_ctl_offset(mixer, id, control, 135862306a36Sopenharmony_ci cmask, val_type, offset, name, 135962306a36Sopenharmony_ci &snd_usb_mixer_vol_tlv); 136062306a36Sopenharmony_ci if (err < 0) 136162306a36Sopenharmony_ci return err; 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci return 0; 136662306a36Sopenharmony_ci} 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci/* This control needs a volume quirk, see mixer.c */ 136962306a36Sopenharmony_cistatic int snd_c400_create_effect_volume_ctl(struct usb_mixer_interface *mixer) 137062306a36Sopenharmony_ci{ 137162306a36Sopenharmony_ci static const char name[] = "Effect Volume"; 137262306a36Sopenharmony_ci const unsigned int id = 0x43; 137362306a36Sopenharmony_ci const int val_type = USB_MIXER_U8; 137462306a36Sopenharmony_ci const unsigned int control = 3; 137562306a36Sopenharmony_ci const unsigned int cmask = 0; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 137862306a36Sopenharmony_ci name, snd_usb_mixer_vol_tlv); 137962306a36Sopenharmony_ci} 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci/* This control needs a volume quirk, see mixer.c */ 138262306a36Sopenharmony_cistatic int snd_c400_create_effect_duration_ctl(struct usb_mixer_interface *mixer) 138362306a36Sopenharmony_ci{ 138462306a36Sopenharmony_ci static const char name[] = "Effect Duration"; 138562306a36Sopenharmony_ci const unsigned int id = 0x43; 138662306a36Sopenharmony_ci const int val_type = USB_MIXER_S16; 138762306a36Sopenharmony_ci const unsigned int control = 4; 138862306a36Sopenharmony_ci const unsigned int cmask = 0; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 139162306a36Sopenharmony_ci name, snd_usb_mixer_vol_tlv); 139262306a36Sopenharmony_ci} 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci/* This control needs a volume quirk, see mixer.c */ 139562306a36Sopenharmony_cistatic int snd_c400_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) 139662306a36Sopenharmony_ci{ 139762306a36Sopenharmony_ci static const char name[] = "Effect Feedback Volume"; 139862306a36Sopenharmony_ci const unsigned int id = 0x43; 139962306a36Sopenharmony_ci const int val_type = USB_MIXER_U8; 140062306a36Sopenharmony_ci const unsigned int control = 5; 140162306a36Sopenharmony_ci const unsigned int cmask = 0; 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, 140462306a36Sopenharmony_ci name, NULL); 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_cistatic int snd_c400_create_effect_vol_ctls(struct usb_mixer_interface *mixer) 140862306a36Sopenharmony_ci{ 140962306a36Sopenharmony_ci char name[64]; 141062306a36Sopenharmony_ci unsigned int cmask; 141162306a36Sopenharmony_ci int chan, err; 141262306a36Sopenharmony_ci int num_outs = 0; 141362306a36Sopenharmony_ci int num_ins = 0; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci const unsigned int id = 0x42; 141662306a36Sopenharmony_ci const int val_type = USB_MIXER_S16; 141762306a36Sopenharmony_ci const int control = 1; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci switch (mixer->chip->usb_id) { 142062306a36Sopenharmony_ci case USB_ID(0x0763, 0x2030): 142162306a36Sopenharmony_ci num_outs = 6; 142262306a36Sopenharmony_ci num_ins = 4; 142362306a36Sopenharmony_ci break; 142462306a36Sopenharmony_ci case USB_ID(0x0763, 0x2031): 142562306a36Sopenharmony_ci num_outs = 8; 142662306a36Sopenharmony_ci num_ins = 6; 142762306a36Sopenharmony_ci break; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci for (chan = 0; chan < num_outs + num_ins; chan++) { 143162306a36Sopenharmony_ci if (chan < num_outs) { 143262306a36Sopenharmony_ci snprintf(name, sizeof(name), 143362306a36Sopenharmony_ci "Effect Send DOut%d", 143462306a36Sopenharmony_ci chan + 1); 143562306a36Sopenharmony_ci } else { 143662306a36Sopenharmony_ci snprintf(name, sizeof(name), 143762306a36Sopenharmony_ci "Effect Send AIn%d", 143862306a36Sopenharmony_ci chan - num_outs + 1); 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci cmask = (chan == 0) ? 0 : 1 << (chan - 1); 144262306a36Sopenharmony_ci err = snd_create_std_mono_ctl(mixer, id, control, 144362306a36Sopenharmony_ci cmask, val_type, name, 144462306a36Sopenharmony_ci &snd_usb_mixer_vol_tlv); 144562306a36Sopenharmony_ci if (err < 0) 144662306a36Sopenharmony_ci return err; 144762306a36Sopenharmony_ci } 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci return 0; 145062306a36Sopenharmony_ci} 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_cistatic int snd_c400_create_effect_ret_vol_ctls(struct usb_mixer_interface *mixer) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci char name[64]; 145562306a36Sopenharmony_ci unsigned int cmask; 145662306a36Sopenharmony_ci int chan, err; 145762306a36Sopenharmony_ci int num_outs = 0; 145862306a36Sopenharmony_ci int offset = 0; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci const unsigned int id = 0x40; 146162306a36Sopenharmony_ci const int val_type = USB_MIXER_S16; 146262306a36Sopenharmony_ci const int control = 1; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci switch (mixer->chip->usb_id) { 146562306a36Sopenharmony_ci case USB_ID(0x0763, 0x2030): 146662306a36Sopenharmony_ci num_outs = 6; 146762306a36Sopenharmony_ci offset = 0x3c; 146862306a36Sopenharmony_ci /* { 0x3c, 0x43, 0x3e, 0x45, 0x40, 0x47 } */ 146962306a36Sopenharmony_ci break; 147062306a36Sopenharmony_ci case USB_ID(0x0763, 0x2031): 147162306a36Sopenharmony_ci num_outs = 8; 147262306a36Sopenharmony_ci offset = 0x70; 147362306a36Sopenharmony_ci /* { 0x70, 0x79, 0x72, 0x7b, 0x74, 0x7d, 0x76, 0x7f } */ 147462306a36Sopenharmony_ci break; 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci for (chan = 0; chan < num_outs; chan++) { 147862306a36Sopenharmony_ci snprintf(name, sizeof(name), 147962306a36Sopenharmony_ci "Effect Return %d", 148062306a36Sopenharmony_ci chan + 1); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci cmask = (chan == 0) ? 0 : 148362306a36Sopenharmony_ci 1 << (chan + (chan % 2) * num_outs - 1); 148462306a36Sopenharmony_ci err = snd_create_std_mono_ctl_offset(mixer, id, control, 148562306a36Sopenharmony_ci cmask, val_type, offset, name, 148662306a36Sopenharmony_ci &snd_usb_mixer_vol_tlv); 148762306a36Sopenharmony_ci if (err < 0) 148862306a36Sopenharmony_ci return err; 148962306a36Sopenharmony_ci } 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci return 0; 149262306a36Sopenharmony_ci} 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_cistatic int snd_c400_create_mixer(struct usb_mixer_interface *mixer) 149562306a36Sopenharmony_ci{ 149662306a36Sopenharmony_ci int err; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci err = snd_c400_create_vol_ctls(mixer); 149962306a36Sopenharmony_ci if (err < 0) 150062306a36Sopenharmony_ci return err; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci err = snd_c400_create_effect_vol_ctls(mixer); 150362306a36Sopenharmony_ci if (err < 0) 150462306a36Sopenharmony_ci return err; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci err = snd_c400_create_effect_ret_vol_ctls(mixer); 150762306a36Sopenharmony_ci if (err < 0) 150862306a36Sopenharmony_ci return err; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci err = snd_ftu_create_effect_switch(mixer, 2, 0x43); 151162306a36Sopenharmony_ci if (err < 0) 151262306a36Sopenharmony_ci return err; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci err = snd_c400_create_effect_volume_ctl(mixer); 151562306a36Sopenharmony_ci if (err < 0) 151662306a36Sopenharmony_ci return err; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci err = snd_c400_create_effect_duration_ctl(mixer); 151962306a36Sopenharmony_ci if (err < 0) 152062306a36Sopenharmony_ci return err; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci err = snd_c400_create_effect_feedback_ctl(mixer); 152362306a36Sopenharmony_ci if (err < 0) 152462306a36Sopenharmony_ci return err; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci return 0; 152762306a36Sopenharmony_ci} 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci/* 153062306a36Sopenharmony_ci * The mixer units for Ebox-44 are corrupt, and even where they 153162306a36Sopenharmony_ci * are valid they presents mono controls as L and R channels of 153262306a36Sopenharmony_ci * stereo. So we provide a good mixer here. 153362306a36Sopenharmony_ci */ 153462306a36Sopenharmony_cistatic const struct std_mono_table ebox44_table[] = { 153562306a36Sopenharmony_ci { 153662306a36Sopenharmony_ci .unitid = 4, 153762306a36Sopenharmony_ci .control = 1, 153862306a36Sopenharmony_ci .cmask = 0x0, 153962306a36Sopenharmony_ci .val_type = USB_MIXER_INV_BOOLEAN, 154062306a36Sopenharmony_ci .name = "Headphone Playback Switch" 154162306a36Sopenharmony_ci }, 154262306a36Sopenharmony_ci { 154362306a36Sopenharmony_ci .unitid = 4, 154462306a36Sopenharmony_ci .control = 2, 154562306a36Sopenharmony_ci .cmask = 0x1, 154662306a36Sopenharmony_ci .val_type = USB_MIXER_S16, 154762306a36Sopenharmony_ci .name = "Headphone A Mix Playback Volume" 154862306a36Sopenharmony_ci }, 154962306a36Sopenharmony_ci { 155062306a36Sopenharmony_ci .unitid = 4, 155162306a36Sopenharmony_ci .control = 2, 155262306a36Sopenharmony_ci .cmask = 0x2, 155362306a36Sopenharmony_ci .val_type = USB_MIXER_S16, 155462306a36Sopenharmony_ci .name = "Headphone B Mix Playback Volume" 155562306a36Sopenharmony_ci }, 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci { 155862306a36Sopenharmony_ci .unitid = 7, 155962306a36Sopenharmony_ci .control = 1, 156062306a36Sopenharmony_ci .cmask = 0x0, 156162306a36Sopenharmony_ci .val_type = USB_MIXER_INV_BOOLEAN, 156262306a36Sopenharmony_ci .name = "Output Playback Switch" 156362306a36Sopenharmony_ci }, 156462306a36Sopenharmony_ci { 156562306a36Sopenharmony_ci .unitid = 7, 156662306a36Sopenharmony_ci .control = 2, 156762306a36Sopenharmony_ci .cmask = 0x1, 156862306a36Sopenharmony_ci .val_type = USB_MIXER_S16, 156962306a36Sopenharmony_ci .name = "Output A Playback Volume" 157062306a36Sopenharmony_ci }, 157162306a36Sopenharmony_ci { 157262306a36Sopenharmony_ci .unitid = 7, 157362306a36Sopenharmony_ci .control = 2, 157462306a36Sopenharmony_ci .cmask = 0x2, 157562306a36Sopenharmony_ci .val_type = USB_MIXER_S16, 157662306a36Sopenharmony_ci .name = "Output B Playback Volume" 157762306a36Sopenharmony_ci }, 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci { 158062306a36Sopenharmony_ci .unitid = 10, 158162306a36Sopenharmony_ci .control = 1, 158262306a36Sopenharmony_ci .cmask = 0x0, 158362306a36Sopenharmony_ci .val_type = USB_MIXER_INV_BOOLEAN, 158462306a36Sopenharmony_ci .name = "Input Capture Switch" 158562306a36Sopenharmony_ci }, 158662306a36Sopenharmony_ci { 158762306a36Sopenharmony_ci .unitid = 10, 158862306a36Sopenharmony_ci .control = 2, 158962306a36Sopenharmony_ci .cmask = 0x1, 159062306a36Sopenharmony_ci .val_type = USB_MIXER_S16, 159162306a36Sopenharmony_ci .name = "Input A Capture Volume" 159262306a36Sopenharmony_ci }, 159362306a36Sopenharmony_ci { 159462306a36Sopenharmony_ci .unitid = 10, 159562306a36Sopenharmony_ci .control = 2, 159662306a36Sopenharmony_ci .cmask = 0x2, 159762306a36Sopenharmony_ci .val_type = USB_MIXER_S16, 159862306a36Sopenharmony_ci .name = "Input B Capture Volume" 159962306a36Sopenharmony_ci }, 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci {} 160262306a36Sopenharmony_ci}; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci/* Audio Advantage Micro II findings: 160562306a36Sopenharmony_ci * 160662306a36Sopenharmony_ci * Mapping spdif AES bits to vendor register.bit: 160762306a36Sopenharmony_ci * AES0: [0 0 0 0 2.3 2.2 2.1 2.0] - default 0x00 160862306a36Sopenharmony_ci * AES1: [3.3 3.2.3.1.3.0 2.7 2.6 2.5 2.4] - default: 0x01 160962306a36Sopenharmony_ci * AES2: [0 0 0 0 0 0 0 0] 161062306a36Sopenharmony_ci * AES3: [0 0 0 0 0 0 x 0] - 'x' bit is set basing on standard usb request 161162306a36Sopenharmony_ci * (UAC_EP_CS_ATTR_SAMPLE_RATE) for Audio Devices 161262306a36Sopenharmony_ci * 161362306a36Sopenharmony_ci * power on values: 161462306a36Sopenharmony_ci * r2: 0x10 161562306a36Sopenharmony_ci * r3: 0x20 (b7 is zeroed just before playback (except IEC61937) and set 161662306a36Sopenharmony_ci * just after it to 0xa0, presumably it disables/mutes some analog 161762306a36Sopenharmony_ci * parts when there is no audio.) 161862306a36Sopenharmony_ci * r9: 0x28 161962306a36Sopenharmony_ci * 162062306a36Sopenharmony_ci * Optical transmitter on/off: 162162306a36Sopenharmony_ci * vendor register.bit: 9.1 162262306a36Sopenharmony_ci * 0 - on (0x28 register value) 162362306a36Sopenharmony_ci * 1 - off (0x2a register value) 162462306a36Sopenharmony_ci * 162562306a36Sopenharmony_ci */ 162662306a36Sopenharmony_cistatic int snd_microii_spdif_info(struct snd_kcontrol *kcontrol, 162762306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 162862306a36Sopenharmony_ci{ 162962306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 163062306a36Sopenharmony_ci uinfo->count = 1; 163162306a36Sopenharmony_ci return 0; 163262306a36Sopenharmony_ci} 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_cistatic int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, 163562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 163662306a36Sopenharmony_ci{ 163762306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 163862306a36Sopenharmony_ci struct snd_usb_audio *chip = list->mixer->chip; 163962306a36Sopenharmony_ci int err; 164062306a36Sopenharmony_ci struct usb_interface *iface; 164162306a36Sopenharmony_ci struct usb_host_interface *alts; 164262306a36Sopenharmony_ci unsigned int ep; 164362306a36Sopenharmony_ci unsigned char data[3]; 164462306a36Sopenharmony_ci int rate; 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 164762306a36Sopenharmony_ci if (err < 0) 164862306a36Sopenharmony_ci return err; 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff; 165162306a36Sopenharmony_ci ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff; 165262306a36Sopenharmony_ci ucontrol->value.iec958.status[2] = 0x00; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci /* use known values for that card: interface#1 altsetting#1 */ 165562306a36Sopenharmony_ci iface = usb_ifnum_to_if(chip->dev, 1); 165662306a36Sopenharmony_ci if (!iface || iface->num_altsetting < 2) { 165762306a36Sopenharmony_ci err = -EINVAL; 165862306a36Sopenharmony_ci goto end; 165962306a36Sopenharmony_ci } 166062306a36Sopenharmony_ci alts = &iface->altsetting[1]; 166162306a36Sopenharmony_ci if (get_iface_desc(alts)->bNumEndpoints < 1) { 166262306a36Sopenharmony_ci err = -EINVAL; 166362306a36Sopenharmony_ci goto end; 166462306a36Sopenharmony_ci } 166562306a36Sopenharmony_ci ep = get_endpoint(alts, 0)->bEndpointAddress; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 166862306a36Sopenharmony_ci usb_rcvctrlpipe(chip->dev, 0), 166962306a36Sopenharmony_ci UAC_GET_CUR, 167062306a36Sopenharmony_ci USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, 167162306a36Sopenharmony_ci UAC_EP_CS_ATTR_SAMPLE_RATE << 8, 167262306a36Sopenharmony_ci ep, 167362306a36Sopenharmony_ci data, 167462306a36Sopenharmony_ci sizeof(data)); 167562306a36Sopenharmony_ci if (err < 0) 167662306a36Sopenharmony_ci goto end; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci rate = data[0] | (data[1] << 8) | (data[2] << 16); 167962306a36Sopenharmony_ci ucontrol->value.iec958.status[3] = (rate == 48000) ? 168062306a36Sopenharmony_ci IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci err = 0; 168362306a36Sopenharmony_ci end: 168462306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 168562306a36Sopenharmony_ci return err; 168662306a36Sopenharmony_ci} 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_cistatic int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) 168962306a36Sopenharmony_ci{ 169062306a36Sopenharmony_ci struct snd_usb_audio *chip = list->mixer->chip; 169162306a36Sopenharmony_ci unsigned int pval = list->kctl->private_value; 169262306a36Sopenharmony_ci u8 reg; 169362306a36Sopenharmony_ci int err; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 169662306a36Sopenharmony_ci if (err < 0) 169762306a36Sopenharmony_ci return err; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci reg = ((pval >> 4) & 0xf0) | (pval & 0x0f); 170062306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 170162306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), 170262306a36Sopenharmony_ci UAC_SET_CUR, 170362306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 170462306a36Sopenharmony_ci reg, 170562306a36Sopenharmony_ci 2, 170662306a36Sopenharmony_ci NULL, 170762306a36Sopenharmony_ci 0); 170862306a36Sopenharmony_ci if (err < 0) 170962306a36Sopenharmony_ci goto end; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci reg = (pval & IEC958_AES0_NONAUDIO) ? 0xa0 : 0x20; 171262306a36Sopenharmony_ci reg |= (pval >> 12) & 0x0f; 171362306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 171462306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), 171562306a36Sopenharmony_ci UAC_SET_CUR, 171662306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 171762306a36Sopenharmony_ci reg, 171862306a36Sopenharmony_ci 3, 171962306a36Sopenharmony_ci NULL, 172062306a36Sopenharmony_ci 0); 172162306a36Sopenharmony_ci if (err < 0) 172262306a36Sopenharmony_ci goto end; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci end: 172562306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 172662306a36Sopenharmony_ci return err; 172762306a36Sopenharmony_ci} 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_cistatic int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol, 173062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 173162306a36Sopenharmony_ci{ 173262306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 173362306a36Sopenharmony_ci unsigned int pval, pval_old; 173462306a36Sopenharmony_ci int err; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci pval = pval_old = kcontrol->private_value; 173762306a36Sopenharmony_ci pval &= 0xfffff0f0; 173862306a36Sopenharmony_ci pval |= (ucontrol->value.iec958.status[1] & 0x0f) << 8; 173962306a36Sopenharmony_ci pval |= (ucontrol->value.iec958.status[0] & 0x0f); 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci pval &= 0xffff0fff; 174262306a36Sopenharmony_ci pval |= (ucontrol->value.iec958.status[1] & 0xf0) << 8; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci /* The frequency bits in AES3 cannot be set via register access. */ 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci /* Silently ignore any bits from the request that cannot be set. */ 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci if (pval == pval_old) 174962306a36Sopenharmony_ci return 0; 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci kcontrol->private_value = pval; 175262306a36Sopenharmony_ci err = snd_microii_spdif_default_update(list); 175362306a36Sopenharmony_ci return err < 0 ? err : 1; 175462306a36Sopenharmony_ci} 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_cistatic int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol, 175762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 175862306a36Sopenharmony_ci{ 175962306a36Sopenharmony_ci ucontrol->value.iec958.status[0] = 0x0f; 176062306a36Sopenharmony_ci ucontrol->value.iec958.status[1] = 0xff; 176162306a36Sopenharmony_ci ucontrol->value.iec958.status[2] = 0x00; 176262306a36Sopenharmony_ci ucontrol->value.iec958.status[3] = 0x00; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci return 0; 176562306a36Sopenharmony_ci} 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_cistatic int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol, 176862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 176962306a36Sopenharmony_ci{ 177062306a36Sopenharmony_ci ucontrol->value.integer.value[0] = !(kcontrol->private_value & 0x02); 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci return 0; 177362306a36Sopenharmony_ci} 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_cistatic int snd_microii_spdif_switch_update(struct usb_mixer_elem_list *list) 177662306a36Sopenharmony_ci{ 177762306a36Sopenharmony_ci struct snd_usb_audio *chip = list->mixer->chip; 177862306a36Sopenharmony_ci u8 reg = list->kctl->private_value; 177962306a36Sopenharmony_ci int err; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 178262306a36Sopenharmony_ci if (err < 0) 178362306a36Sopenharmony_ci return err; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 178662306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), 178762306a36Sopenharmony_ci UAC_SET_CUR, 178862306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 178962306a36Sopenharmony_ci reg, 179062306a36Sopenharmony_ci 9, 179162306a36Sopenharmony_ci NULL, 179262306a36Sopenharmony_ci 0); 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 179562306a36Sopenharmony_ci return err; 179662306a36Sopenharmony_ci} 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_cistatic int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol, 179962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 180062306a36Sopenharmony_ci{ 180162306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 180262306a36Sopenharmony_ci u8 reg; 180362306a36Sopenharmony_ci int err; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a; 180662306a36Sopenharmony_ci if (reg != list->kctl->private_value) 180762306a36Sopenharmony_ci return 0; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci kcontrol->private_value = reg; 181062306a36Sopenharmony_ci err = snd_microii_spdif_switch_update(list); 181162306a36Sopenharmony_ci return err < 0 ? err : 1; 181262306a36Sopenharmony_ci} 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_microii_mixer_spdif[] = { 181562306a36Sopenharmony_ci { 181662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 181762306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), 181862306a36Sopenharmony_ci .info = snd_microii_spdif_info, 181962306a36Sopenharmony_ci .get = snd_microii_spdif_default_get, 182062306a36Sopenharmony_ci .put = snd_microii_spdif_default_put, 182162306a36Sopenharmony_ci .private_value = 0x00000100UL,/* reset value */ 182262306a36Sopenharmony_ci }, 182362306a36Sopenharmony_ci { 182462306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 182562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 182662306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), 182762306a36Sopenharmony_ci .info = snd_microii_spdif_info, 182862306a36Sopenharmony_ci .get = snd_microii_spdif_mask_get, 182962306a36Sopenharmony_ci }, 183062306a36Sopenharmony_ci { 183162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 183262306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), 183362306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 183462306a36Sopenharmony_ci .get = snd_microii_spdif_switch_get, 183562306a36Sopenharmony_ci .put = snd_microii_spdif_switch_put, 183662306a36Sopenharmony_ci .private_value = 0x00000028UL,/* reset value */ 183762306a36Sopenharmony_ci } 183862306a36Sopenharmony_ci}; 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_cistatic int snd_microii_controls_create(struct usb_mixer_interface *mixer) 184162306a36Sopenharmony_ci{ 184262306a36Sopenharmony_ci int err, i; 184362306a36Sopenharmony_ci static const usb_mixer_elem_resume_func_t resume_funcs[] = { 184462306a36Sopenharmony_ci snd_microii_spdif_default_update, 184562306a36Sopenharmony_ci NULL, 184662306a36Sopenharmony_ci snd_microii_spdif_switch_update 184762306a36Sopenharmony_ci }; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) { 185062306a36Sopenharmony_ci err = add_single_ctl_with_resume(mixer, 0, 185162306a36Sopenharmony_ci resume_funcs[i], 185262306a36Sopenharmony_ci &snd_microii_mixer_spdif[i], 185362306a36Sopenharmony_ci NULL); 185462306a36Sopenharmony_ci if (err < 0) 185562306a36Sopenharmony_ci return err; 185662306a36Sopenharmony_ci } 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci return 0; 185962306a36Sopenharmony_ci} 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci/* Creative Sound Blaster E1 */ 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_cistatic int snd_soundblaster_e1_switch_get(struct snd_kcontrol *kcontrol, 186462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 186562306a36Sopenharmony_ci{ 186662306a36Sopenharmony_ci ucontrol->value.integer.value[0] = kcontrol->private_value; 186762306a36Sopenharmony_ci return 0; 186862306a36Sopenharmony_ci} 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_cistatic int snd_soundblaster_e1_switch_update(struct usb_mixer_interface *mixer, 187162306a36Sopenharmony_ci unsigned char state) 187262306a36Sopenharmony_ci{ 187362306a36Sopenharmony_ci struct snd_usb_audio *chip = mixer->chip; 187462306a36Sopenharmony_ci int err; 187562306a36Sopenharmony_ci unsigned char buff[2]; 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci buff[0] = 0x02; 187862306a36Sopenharmony_ci buff[1] = state ? 0x02 : 0x00; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 188162306a36Sopenharmony_ci if (err < 0) 188262306a36Sopenharmony_ci return err; 188362306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 188462306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), HID_REQ_SET_REPORT, 188562306a36Sopenharmony_ci USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 188662306a36Sopenharmony_ci 0x0202, 3, buff, 2); 188762306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 188862306a36Sopenharmony_ci return err; 188962306a36Sopenharmony_ci} 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_cistatic int snd_soundblaster_e1_switch_put(struct snd_kcontrol *kcontrol, 189262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 189362306a36Sopenharmony_ci{ 189462306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 189562306a36Sopenharmony_ci unsigned char value = !!ucontrol->value.integer.value[0]; 189662306a36Sopenharmony_ci int err; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci if (kcontrol->private_value == value) 189962306a36Sopenharmony_ci return 0; 190062306a36Sopenharmony_ci kcontrol->private_value = value; 190162306a36Sopenharmony_ci err = snd_soundblaster_e1_switch_update(list->mixer, value); 190262306a36Sopenharmony_ci return err < 0 ? err : 1; 190362306a36Sopenharmony_ci} 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_cistatic int snd_soundblaster_e1_switch_resume(struct usb_mixer_elem_list *list) 190662306a36Sopenharmony_ci{ 190762306a36Sopenharmony_ci return snd_soundblaster_e1_switch_update(list->mixer, 190862306a36Sopenharmony_ci list->kctl->private_value); 190962306a36Sopenharmony_ci} 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_cistatic int snd_soundblaster_e1_switch_info(struct snd_kcontrol *kcontrol, 191262306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 191362306a36Sopenharmony_ci{ 191462306a36Sopenharmony_ci static const char *const texts[2] = { 191562306a36Sopenharmony_ci "Mic", "Aux" 191662306a36Sopenharmony_ci }; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 191962306a36Sopenharmony_ci} 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_soundblaster_e1_input_switch = { 192262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 192362306a36Sopenharmony_ci .name = "Input Source", 192462306a36Sopenharmony_ci .info = snd_soundblaster_e1_switch_info, 192562306a36Sopenharmony_ci .get = snd_soundblaster_e1_switch_get, 192662306a36Sopenharmony_ci .put = snd_soundblaster_e1_switch_put, 192762306a36Sopenharmony_ci .private_value = 0, 192862306a36Sopenharmony_ci}; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_cistatic int snd_soundblaster_e1_switch_create(struct usb_mixer_interface *mixer) 193162306a36Sopenharmony_ci{ 193262306a36Sopenharmony_ci return add_single_ctl_with_resume(mixer, 0, 193362306a36Sopenharmony_ci snd_soundblaster_e1_switch_resume, 193462306a36Sopenharmony_ci &snd_soundblaster_e1_input_switch, 193562306a36Sopenharmony_ci NULL); 193662306a36Sopenharmony_ci} 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci/* 193962306a36Sopenharmony_ci * Dell WD15 dock jack detection 194062306a36Sopenharmony_ci * 194162306a36Sopenharmony_ci * The WD15 contains an ALC4020 USB audio controller and ALC3263 audio codec 194262306a36Sopenharmony_ci * from Realtek. It is a UAC 1 device, and UAC 1 does not support jack 194362306a36Sopenharmony_ci * detection. Instead, jack detection works by sending HD Audio commands over 194462306a36Sopenharmony_ci * vendor-type USB messages. 194562306a36Sopenharmony_ci */ 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci#define HDA_VERB_CMD(V, N, D) (((N) << 20) | ((V) << 8) | (D)) 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci#define REALTEK_HDA_VALUE 0x0038 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci#define REALTEK_HDA_SET 62 195262306a36Sopenharmony_ci#define REALTEK_MANUAL_MODE 72 195362306a36Sopenharmony_ci#define REALTEK_HDA_GET_OUT 88 195462306a36Sopenharmony_ci#define REALTEK_HDA_GET_IN 89 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci#define REALTEK_AUDIO_FUNCTION_GROUP 0x01 195762306a36Sopenharmony_ci#define REALTEK_LINE1 0x1a 195862306a36Sopenharmony_ci#define REALTEK_VENDOR_REGISTERS 0x20 195962306a36Sopenharmony_ci#define REALTEK_HP_OUT 0x21 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci#define REALTEK_CBJ_CTRL2 0x50 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci#define REALTEK_JACK_INTERRUPT_NODE 5 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci#define REALTEK_MIC_FLAG 0x100 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_cistatic int realtek_hda_set(struct snd_usb_audio *chip, u32 cmd) 196862306a36Sopenharmony_ci{ 196962306a36Sopenharmony_ci struct usb_device *dev = chip->dev; 197062306a36Sopenharmony_ci __be32 buf = cpu_to_be32(cmd); 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), REALTEK_HDA_SET, 197362306a36Sopenharmony_ci USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_OUT, 197462306a36Sopenharmony_ci REALTEK_HDA_VALUE, 0, &buf, sizeof(buf)); 197562306a36Sopenharmony_ci} 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_cistatic int realtek_hda_get(struct snd_usb_audio *chip, u32 cmd, u32 *value) 197862306a36Sopenharmony_ci{ 197962306a36Sopenharmony_ci struct usb_device *dev = chip->dev; 198062306a36Sopenharmony_ci int err; 198162306a36Sopenharmony_ci __be32 buf = cpu_to_be32(cmd); 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), REALTEK_HDA_GET_OUT, 198462306a36Sopenharmony_ci USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_OUT, 198562306a36Sopenharmony_ci REALTEK_HDA_VALUE, 0, &buf, sizeof(buf)); 198662306a36Sopenharmony_ci if (err < 0) 198762306a36Sopenharmony_ci return err; 198862306a36Sopenharmony_ci err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), REALTEK_HDA_GET_IN, 198962306a36Sopenharmony_ci USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_IN, 199062306a36Sopenharmony_ci REALTEK_HDA_VALUE, 0, &buf, sizeof(buf)); 199162306a36Sopenharmony_ci if (err < 0) 199262306a36Sopenharmony_ci return err; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci *value = be32_to_cpu(buf); 199562306a36Sopenharmony_ci return 0; 199662306a36Sopenharmony_ci} 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_cistatic int realtek_ctl_connector_get(struct snd_kcontrol *kcontrol, 199962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 200062306a36Sopenharmony_ci{ 200162306a36Sopenharmony_ci struct usb_mixer_elem_info *cval = kcontrol->private_data; 200262306a36Sopenharmony_ci struct snd_usb_audio *chip = cval->head.mixer->chip; 200362306a36Sopenharmony_ci u32 pv = kcontrol->private_value; 200462306a36Sopenharmony_ci u32 node_id = pv & 0xff; 200562306a36Sopenharmony_ci u32 sense; 200662306a36Sopenharmony_ci u32 cbj_ctrl2; 200762306a36Sopenharmony_ci bool presence; 200862306a36Sopenharmony_ci int err; 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 201162306a36Sopenharmony_ci if (err < 0) 201262306a36Sopenharmony_ci return err; 201362306a36Sopenharmony_ci err = realtek_hda_get(chip, 201462306a36Sopenharmony_ci HDA_VERB_CMD(AC_VERB_GET_PIN_SENSE, node_id, 0), 201562306a36Sopenharmony_ci &sense); 201662306a36Sopenharmony_ci if (err < 0) 201762306a36Sopenharmony_ci goto err; 201862306a36Sopenharmony_ci if (pv & REALTEK_MIC_FLAG) { 201962306a36Sopenharmony_ci err = realtek_hda_set(chip, 202062306a36Sopenharmony_ci HDA_VERB_CMD(AC_VERB_SET_COEF_INDEX, 202162306a36Sopenharmony_ci REALTEK_VENDOR_REGISTERS, 202262306a36Sopenharmony_ci REALTEK_CBJ_CTRL2)); 202362306a36Sopenharmony_ci if (err < 0) 202462306a36Sopenharmony_ci goto err; 202562306a36Sopenharmony_ci err = realtek_hda_get(chip, 202662306a36Sopenharmony_ci HDA_VERB_CMD(AC_VERB_GET_PROC_COEF, 202762306a36Sopenharmony_ci REALTEK_VENDOR_REGISTERS, 0), 202862306a36Sopenharmony_ci &cbj_ctrl2); 202962306a36Sopenharmony_ci if (err < 0) 203062306a36Sopenharmony_ci goto err; 203162306a36Sopenharmony_ci } 203262306a36Sopenharmony_cierr: 203362306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 203462306a36Sopenharmony_ci if (err < 0) 203562306a36Sopenharmony_ci return err; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci presence = sense & AC_PINSENSE_PRESENCE; 203862306a36Sopenharmony_ci if (pv & REALTEK_MIC_FLAG) 203962306a36Sopenharmony_ci presence = presence && (cbj_ctrl2 & 0x0070) == 0x0070; 204062306a36Sopenharmony_ci ucontrol->value.integer.value[0] = presence; 204162306a36Sopenharmony_ci return 0; 204262306a36Sopenharmony_ci} 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_cistatic const struct snd_kcontrol_new realtek_connector_ctl_ro = { 204562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_CARD, 204662306a36Sopenharmony_ci .name = "", /* will be filled later manually */ 204762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 204862306a36Sopenharmony_ci .info = snd_ctl_boolean_mono_info, 204962306a36Sopenharmony_ci .get = realtek_ctl_connector_get, 205062306a36Sopenharmony_ci}; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_cistatic int realtek_resume_jack(struct usb_mixer_elem_list *list) 205362306a36Sopenharmony_ci{ 205462306a36Sopenharmony_ci snd_ctl_notify(list->mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, 205562306a36Sopenharmony_ci &list->kctl->id); 205662306a36Sopenharmony_ci return 0; 205762306a36Sopenharmony_ci} 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_cistatic int realtek_add_jack(struct usb_mixer_interface *mixer, 206062306a36Sopenharmony_ci char *name, u32 val) 206162306a36Sopenharmony_ci{ 206262306a36Sopenharmony_ci struct usb_mixer_elem_info *cval; 206362306a36Sopenharmony_ci struct snd_kcontrol *kctl; 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci cval = kzalloc(sizeof(*cval), GFP_KERNEL); 206662306a36Sopenharmony_ci if (!cval) 206762306a36Sopenharmony_ci return -ENOMEM; 206862306a36Sopenharmony_ci snd_usb_mixer_elem_init_std(&cval->head, mixer, 206962306a36Sopenharmony_ci REALTEK_JACK_INTERRUPT_NODE); 207062306a36Sopenharmony_ci cval->head.resume = realtek_resume_jack; 207162306a36Sopenharmony_ci cval->val_type = USB_MIXER_BOOLEAN; 207262306a36Sopenharmony_ci cval->channels = 1; 207362306a36Sopenharmony_ci cval->min = 0; 207462306a36Sopenharmony_ci cval->max = 1; 207562306a36Sopenharmony_ci kctl = snd_ctl_new1(&realtek_connector_ctl_ro, cval); 207662306a36Sopenharmony_ci if (!kctl) { 207762306a36Sopenharmony_ci kfree(cval); 207862306a36Sopenharmony_ci return -ENOMEM; 207962306a36Sopenharmony_ci } 208062306a36Sopenharmony_ci kctl->private_value = val; 208162306a36Sopenharmony_ci strscpy(kctl->id.name, name, sizeof(kctl->id.name)); 208262306a36Sopenharmony_ci kctl->private_free = snd_usb_mixer_elem_free; 208362306a36Sopenharmony_ci return snd_usb_mixer_add_control(&cval->head, kctl); 208462306a36Sopenharmony_ci} 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_cistatic int dell_dock_mixer_create(struct usb_mixer_interface *mixer) 208762306a36Sopenharmony_ci{ 208862306a36Sopenharmony_ci int err; 208962306a36Sopenharmony_ci struct usb_device *dev = mixer->chip->dev; 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci /* Power down the audio codec to avoid loud pops in the next step. */ 209262306a36Sopenharmony_ci realtek_hda_set(mixer->chip, 209362306a36Sopenharmony_ci HDA_VERB_CMD(AC_VERB_SET_POWER_STATE, 209462306a36Sopenharmony_ci REALTEK_AUDIO_FUNCTION_GROUP, 209562306a36Sopenharmony_ci AC_PWRST_D3)); 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci /* 209862306a36Sopenharmony_ci * Turn off 'manual mode' in case it was enabled. This removes the need 209962306a36Sopenharmony_ci * to power cycle the dock after it was attached to a Windows machine. 210062306a36Sopenharmony_ci */ 210162306a36Sopenharmony_ci snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), REALTEK_MANUAL_MODE, 210262306a36Sopenharmony_ci USB_RECIP_DEVICE | USB_TYPE_VENDOR | USB_DIR_OUT, 210362306a36Sopenharmony_ci 0, 0, NULL, 0); 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci err = realtek_add_jack(mixer, "Line Out Jack", REALTEK_LINE1); 210662306a36Sopenharmony_ci if (err < 0) 210762306a36Sopenharmony_ci return err; 210862306a36Sopenharmony_ci err = realtek_add_jack(mixer, "Headphone Jack", REALTEK_HP_OUT); 210962306a36Sopenharmony_ci if (err < 0) 211062306a36Sopenharmony_ci return err; 211162306a36Sopenharmony_ci err = realtek_add_jack(mixer, "Headset Mic Jack", 211262306a36Sopenharmony_ci REALTEK_HP_OUT | REALTEK_MIC_FLAG); 211362306a36Sopenharmony_ci if (err < 0) 211462306a36Sopenharmony_ci return err; 211562306a36Sopenharmony_ci return 0; 211662306a36Sopenharmony_ci} 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_cistatic void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id) 211962306a36Sopenharmony_ci{ 212062306a36Sopenharmony_ci u16 buf = 0; 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, 212362306a36Sopenharmony_ci USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 212462306a36Sopenharmony_ci (UAC_FU_VOLUME << 8) | ch, 212562306a36Sopenharmony_ci snd_usb_ctrl_intf(chip) | (id << 8), 212662306a36Sopenharmony_ci &buf, 2); 212762306a36Sopenharmony_ci} 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_cistatic int dell_dock_mixer_init(struct usb_mixer_interface *mixer) 213062306a36Sopenharmony_ci{ 213162306a36Sopenharmony_ci /* fix to 0dB playback volumes */ 213262306a36Sopenharmony_ci dell_dock_init_vol(mixer->chip, 1, 16); 213362306a36Sopenharmony_ci dell_dock_init_vol(mixer->chip, 2, 16); 213462306a36Sopenharmony_ci dell_dock_init_vol(mixer->chip, 1, 19); 213562306a36Sopenharmony_ci dell_dock_init_vol(mixer->chip, 2, 19); 213662306a36Sopenharmony_ci return 0; 213762306a36Sopenharmony_ci} 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci/* RME Class Compliant device quirks */ 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci#define SND_RME_GET_STATUS1 23 214262306a36Sopenharmony_ci#define SND_RME_GET_CURRENT_FREQ 17 214362306a36Sopenharmony_ci#define SND_RME_CLK_SYSTEM_SHIFT 16 214462306a36Sopenharmony_ci#define SND_RME_CLK_SYSTEM_MASK 0x1f 214562306a36Sopenharmony_ci#define SND_RME_CLK_AES_SHIFT 8 214662306a36Sopenharmony_ci#define SND_RME_CLK_SPDIF_SHIFT 12 214762306a36Sopenharmony_ci#define SND_RME_CLK_AES_SPDIF_MASK 0xf 214862306a36Sopenharmony_ci#define SND_RME_CLK_SYNC_SHIFT 6 214962306a36Sopenharmony_ci#define SND_RME_CLK_SYNC_MASK 0x3 215062306a36Sopenharmony_ci#define SND_RME_CLK_FREQMUL_SHIFT 18 215162306a36Sopenharmony_ci#define SND_RME_CLK_FREQMUL_MASK 0x7 215262306a36Sopenharmony_ci#define SND_RME_CLK_SYSTEM(x) \ 215362306a36Sopenharmony_ci ((x >> SND_RME_CLK_SYSTEM_SHIFT) & SND_RME_CLK_SYSTEM_MASK) 215462306a36Sopenharmony_ci#define SND_RME_CLK_AES(x) \ 215562306a36Sopenharmony_ci ((x >> SND_RME_CLK_AES_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) 215662306a36Sopenharmony_ci#define SND_RME_CLK_SPDIF(x) \ 215762306a36Sopenharmony_ci ((x >> SND_RME_CLK_SPDIF_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) 215862306a36Sopenharmony_ci#define SND_RME_CLK_SYNC(x) \ 215962306a36Sopenharmony_ci ((x >> SND_RME_CLK_SYNC_SHIFT) & SND_RME_CLK_SYNC_MASK) 216062306a36Sopenharmony_ci#define SND_RME_CLK_FREQMUL(x) \ 216162306a36Sopenharmony_ci ((x >> SND_RME_CLK_FREQMUL_SHIFT) & SND_RME_CLK_FREQMUL_MASK) 216262306a36Sopenharmony_ci#define SND_RME_CLK_AES_LOCK 0x1 216362306a36Sopenharmony_ci#define SND_RME_CLK_AES_SYNC 0x4 216462306a36Sopenharmony_ci#define SND_RME_CLK_SPDIF_LOCK 0x2 216562306a36Sopenharmony_ci#define SND_RME_CLK_SPDIF_SYNC 0x8 216662306a36Sopenharmony_ci#define SND_RME_SPDIF_IF_SHIFT 4 216762306a36Sopenharmony_ci#define SND_RME_SPDIF_FORMAT_SHIFT 5 216862306a36Sopenharmony_ci#define SND_RME_BINARY_MASK 0x1 216962306a36Sopenharmony_ci#define SND_RME_SPDIF_IF(x) \ 217062306a36Sopenharmony_ci ((x >> SND_RME_SPDIF_IF_SHIFT) & SND_RME_BINARY_MASK) 217162306a36Sopenharmony_ci#define SND_RME_SPDIF_FORMAT(x) \ 217262306a36Sopenharmony_ci ((x >> SND_RME_SPDIF_FORMAT_SHIFT) & SND_RME_BINARY_MASK) 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_cistatic const u32 snd_rme_rate_table[] = { 217562306a36Sopenharmony_ci 32000, 44100, 48000, 50000, 217662306a36Sopenharmony_ci 64000, 88200, 96000, 100000, 217762306a36Sopenharmony_ci 128000, 176400, 192000, 200000, 217862306a36Sopenharmony_ci 256000, 352800, 384000, 400000, 217962306a36Sopenharmony_ci 512000, 705600, 768000, 800000 218062306a36Sopenharmony_ci}; 218162306a36Sopenharmony_ci/* maximum number of items for AES and S/PDIF rates for above table */ 218262306a36Sopenharmony_ci#define SND_RME_RATE_IDX_AES_SPDIF_NUM 12 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_cienum snd_rme_domain { 218562306a36Sopenharmony_ci SND_RME_DOMAIN_SYSTEM, 218662306a36Sopenharmony_ci SND_RME_DOMAIN_AES, 218762306a36Sopenharmony_ci SND_RME_DOMAIN_SPDIF 218862306a36Sopenharmony_ci}; 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_cienum snd_rme_clock_status { 219162306a36Sopenharmony_ci SND_RME_CLOCK_NOLOCK, 219262306a36Sopenharmony_ci SND_RME_CLOCK_LOCK, 219362306a36Sopenharmony_ci SND_RME_CLOCK_SYNC 219462306a36Sopenharmony_ci}; 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_cistatic int snd_rme_read_value(struct snd_usb_audio *chip, 219762306a36Sopenharmony_ci unsigned int item, 219862306a36Sopenharmony_ci u32 *value) 219962306a36Sopenharmony_ci{ 220062306a36Sopenharmony_ci struct usb_device *dev = chip->dev; 220162306a36Sopenharmony_ci int err; 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 220462306a36Sopenharmony_ci item, 220562306a36Sopenharmony_ci USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 220662306a36Sopenharmony_ci 0, 0, 220762306a36Sopenharmony_ci value, sizeof(*value)); 220862306a36Sopenharmony_ci if (err < 0) 220962306a36Sopenharmony_ci dev_err(&dev->dev, 221062306a36Sopenharmony_ci "unable to issue vendor read request %d (ret = %d)", 221162306a36Sopenharmony_ci item, err); 221262306a36Sopenharmony_ci return err; 221362306a36Sopenharmony_ci} 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_cistatic int snd_rme_get_status1(struct snd_kcontrol *kcontrol, 221662306a36Sopenharmony_ci u32 *status1) 221762306a36Sopenharmony_ci{ 221862306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 221962306a36Sopenharmony_ci struct snd_usb_audio *chip = list->mixer->chip; 222062306a36Sopenharmony_ci int err; 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 222362306a36Sopenharmony_ci if (err < 0) 222462306a36Sopenharmony_ci return err; 222562306a36Sopenharmony_ci err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, status1); 222662306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 222762306a36Sopenharmony_ci return err; 222862306a36Sopenharmony_ci} 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_cistatic int snd_rme_rate_get(struct snd_kcontrol *kcontrol, 223162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 223262306a36Sopenharmony_ci{ 223362306a36Sopenharmony_ci u32 status1; 223462306a36Sopenharmony_ci u32 rate = 0; 223562306a36Sopenharmony_ci int idx; 223662306a36Sopenharmony_ci int err; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci err = snd_rme_get_status1(kcontrol, &status1); 223962306a36Sopenharmony_ci if (err < 0) 224062306a36Sopenharmony_ci return err; 224162306a36Sopenharmony_ci switch (kcontrol->private_value) { 224262306a36Sopenharmony_ci case SND_RME_DOMAIN_SYSTEM: 224362306a36Sopenharmony_ci idx = SND_RME_CLK_SYSTEM(status1); 224462306a36Sopenharmony_ci if (idx < ARRAY_SIZE(snd_rme_rate_table)) 224562306a36Sopenharmony_ci rate = snd_rme_rate_table[idx]; 224662306a36Sopenharmony_ci break; 224762306a36Sopenharmony_ci case SND_RME_DOMAIN_AES: 224862306a36Sopenharmony_ci idx = SND_RME_CLK_AES(status1); 224962306a36Sopenharmony_ci if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM) 225062306a36Sopenharmony_ci rate = snd_rme_rate_table[idx]; 225162306a36Sopenharmony_ci break; 225262306a36Sopenharmony_ci case SND_RME_DOMAIN_SPDIF: 225362306a36Sopenharmony_ci idx = SND_RME_CLK_SPDIF(status1); 225462306a36Sopenharmony_ci if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM) 225562306a36Sopenharmony_ci rate = snd_rme_rate_table[idx]; 225662306a36Sopenharmony_ci break; 225762306a36Sopenharmony_ci default: 225862306a36Sopenharmony_ci return -EINVAL; 225962306a36Sopenharmony_ci } 226062306a36Sopenharmony_ci ucontrol->value.integer.value[0] = rate; 226162306a36Sopenharmony_ci return 0; 226262306a36Sopenharmony_ci} 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_cistatic int snd_rme_sync_state_get(struct snd_kcontrol *kcontrol, 226562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 226662306a36Sopenharmony_ci{ 226762306a36Sopenharmony_ci u32 status1; 226862306a36Sopenharmony_ci int idx = SND_RME_CLOCK_NOLOCK; 226962306a36Sopenharmony_ci int err; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci err = snd_rme_get_status1(kcontrol, &status1); 227262306a36Sopenharmony_ci if (err < 0) 227362306a36Sopenharmony_ci return err; 227462306a36Sopenharmony_ci switch (kcontrol->private_value) { 227562306a36Sopenharmony_ci case SND_RME_DOMAIN_AES: /* AES */ 227662306a36Sopenharmony_ci if (status1 & SND_RME_CLK_AES_SYNC) 227762306a36Sopenharmony_ci idx = SND_RME_CLOCK_SYNC; 227862306a36Sopenharmony_ci else if (status1 & SND_RME_CLK_AES_LOCK) 227962306a36Sopenharmony_ci idx = SND_RME_CLOCK_LOCK; 228062306a36Sopenharmony_ci break; 228162306a36Sopenharmony_ci case SND_RME_DOMAIN_SPDIF: /* SPDIF */ 228262306a36Sopenharmony_ci if (status1 & SND_RME_CLK_SPDIF_SYNC) 228362306a36Sopenharmony_ci idx = SND_RME_CLOCK_SYNC; 228462306a36Sopenharmony_ci else if (status1 & SND_RME_CLK_SPDIF_LOCK) 228562306a36Sopenharmony_ci idx = SND_RME_CLOCK_LOCK; 228662306a36Sopenharmony_ci break; 228762306a36Sopenharmony_ci default: 228862306a36Sopenharmony_ci return -EINVAL; 228962306a36Sopenharmony_ci } 229062306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = idx; 229162306a36Sopenharmony_ci return 0; 229262306a36Sopenharmony_ci} 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_cistatic int snd_rme_spdif_if_get(struct snd_kcontrol *kcontrol, 229562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 229662306a36Sopenharmony_ci{ 229762306a36Sopenharmony_ci u32 status1; 229862306a36Sopenharmony_ci int err; 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci err = snd_rme_get_status1(kcontrol, &status1); 230162306a36Sopenharmony_ci if (err < 0) 230262306a36Sopenharmony_ci return err; 230362306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_IF(status1); 230462306a36Sopenharmony_ci return 0; 230562306a36Sopenharmony_ci} 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_cistatic int snd_rme_spdif_format_get(struct snd_kcontrol *kcontrol, 230862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 230962306a36Sopenharmony_ci{ 231062306a36Sopenharmony_ci u32 status1; 231162306a36Sopenharmony_ci int err; 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci err = snd_rme_get_status1(kcontrol, &status1); 231462306a36Sopenharmony_ci if (err < 0) 231562306a36Sopenharmony_ci return err; 231662306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_FORMAT(status1); 231762306a36Sopenharmony_ci return 0; 231862306a36Sopenharmony_ci} 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_cistatic int snd_rme_sync_source_get(struct snd_kcontrol *kcontrol, 232162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 232262306a36Sopenharmony_ci{ 232362306a36Sopenharmony_ci u32 status1; 232462306a36Sopenharmony_ci int err; 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_ci err = snd_rme_get_status1(kcontrol, &status1); 232762306a36Sopenharmony_ci if (err < 0) 232862306a36Sopenharmony_ci return err; 232962306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = SND_RME_CLK_SYNC(status1); 233062306a36Sopenharmony_ci return 0; 233162306a36Sopenharmony_ci} 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_cistatic int snd_rme_current_freq_get(struct snd_kcontrol *kcontrol, 233462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 233562306a36Sopenharmony_ci{ 233662306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 233762306a36Sopenharmony_ci struct snd_usb_audio *chip = list->mixer->chip; 233862306a36Sopenharmony_ci u32 status1; 233962306a36Sopenharmony_ci const u64 num = 104857600000000ULL; 234062306a36Sopenharmony_ci u32 den; 234162306a36Sopenharmony_ci unsigned int freq; 234262306a36Sopenharmony_ci int err; 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 234562306a36Sopenharmony_ci if (err < 0) 234662306a36Sopenharmony_ci return err; 234762306a36Sopenharmony_ci err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, &status1); 234862306a36Sopenharmony_ci if (err < 0) 234962306a36Sopenharmony_ci goto end; 235062306a36Sopenharmony_ci err = snd_rme_read_value(chip, SND_RME_GET_CURRENT_FREQ, &den); 235162306a36Sopenharmony_ci if (err < 0) 235262306a36Sopenharmony_ci goto end; 235362306a36Sopenharmony_ci freq = (den == 0) ? 0 : div64_u64(num, den); 235462306a36Sopenharmony_ci freq <<= SND_RME_CLK_FREQMUL(status1); 235562306a36Sopenharmony_ci ucontrol->value.integer.value[0] = freq; 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ciend: 235862306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 235962306a36Sopenharmony_ci return err; 236062306a36Sopenharmony_ci} 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_cistatic int snd_rme_rate_info(struct snd_kcontrol *kcontrol, 236362306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 236462306a36Sopenharmony_ci{ 236562306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 236662306a36Sopenharmony_ci uinfo->count = 1; 236762306a36Sopenharmony_ci switch (kcontrol->private_value) { 236862306a36Sopenharmony_ci case SND_RME_DOMAIN_SYSTEM: 236962306a36Sopenharmony_ci uinfo->value.integer.min = 32000; 237062306a36Sopenharmony_ci uinfo->value.integer.max = 800000; 237162306a36Sopenharmony_ci break; 237262306a36Sopenharmony_ci case SND_RME_DOMAIN_AES: 237362306a36Sopenharmony_ci case SND_RME_DOMAIN_SPDIF: 237462306a36Sopenharmony_ci default: 237562306a36Sopenharmony_ci uinfo->value.integer.min = 0; 237662306a36Sopenharmony_ci uinfo->value.integer.max = 200000; 237762306a36Sopenharmony_ci } 237862306a36Sopenharmony_ci uinfo->value.integer.step = 0; 237962306a36Sopenharmony_ci return 0; 238062306a36Sopenharmony_ci} 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_cistatic int snd_rme_sync_state_info(struct snd_kcontrol *kcontrol, 238362306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 238462306a36Sopenharmony_ci{ 238562306a36Sopenharmony_ci static const char *const sync_states[] = { 238662306a36Sopenharmony_ci "No Lock", "Lock", "Sync" 238762306a36Sopenharmony_ci }; 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 239062306a36Sopenharmony_ci ARRAY_SIZE(sync_states), sync_states); 239162306a36Sopenharmony_ci} 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_cistatic int snd_rme_spdif_if_info(struct snd_kcontrol *kcontrol, 239462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 239562306a36Sopenharmony_ci{ 239662306a36Sopenharmony_ci static const char *const spdif_if[] = { 239762306a36Sopenharmony_ci "Coaxial", "Optical" 239862306a36Sopenharmony_ci }; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 240162306a36Sopenharmony_ci ARRAY_SIZE(spdif_if), spdif_if); 240262306a36Sopenharmony_ci} 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_cistatic int snd_rme_spdif_format_info(struct snd_kcontrol *kcontrol, 240562306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 240662306a36Sopenharmony_ci{ 240762306a36Sopenharmony_ci static const char *const optical_type[] = { 240862306a36Sopenharmony_ci "Consumer", "Professional" 240962306a36Sopenharmony_ci }; 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 241262306a36Sopenharmony_ci ARRAY_SIZE(optical_type), optical_type); 241362306a36Sopenharmony_ci} 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_cistatic int snd_rme_sync_source_info(struct snd_kcontrol *kcontrol, 241662306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 241762306a36Sopenharmony_ci{ 241862306a36Sopenharmony_ci static const char *const sync_sources[] = { 241962306a36Sopenharmony_ci "Internal", "AES", "SPDIF", "Internal" 242062306a36Sopenharmony_ci }; 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 242362306a36Sopenharmony_ci ARRAY_SIZE(sync_sources), sync_sources); 242462306a36Sopenharmony_ci} 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_rme_controls[] = { 242762306a36Sopenharmony_ci { 242862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 242962306a36Sopenharmony_ci .name = "AES Rate", 243062306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 243162306a36Sopenharmony_ci .info = snd_rme_rate_info, 243262306a36Sopenharmony_ci .get = snd_rme_rate_get, 243362306a36Sopenharmony_ci .private_value = SND_RME_DOMAIN_AES 243462306a36Sopenharmony_ci }, 243562306a36Sopenharmony_ci { 243662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 243762306a36Sopenharmony_ci .name = "AES Sync", 243862306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 243962306a36Sopenharmony_ci .info = snd_rme_sync_state_info, 244062306a36Sopenharmony_ci .get = snd_rme_sync_state_get, 244162306a36Sopenharmony_ci .private_value = SND_RME_DOMAIN_AES 244262306a36Sopenharmony_ci }, 244362306a36Sopenharmony_ci { 244462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 244562306a36Sopenharmony_ci .name = "SPDIF Rate", 244662306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 244762306a36Sopenharmony_ci .info = snd_rme_rate_info, 244862306a36Sopenharmony_ci .get = snd_rme_rate_get, 244962306a36Sopenharmony_ci .private_value = SND_RME_DOMAIN_SPDIF 245062306a36Sopenharmony_ci }, 245162306a36Sopenharmony_ci { 245262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 245362306a36Sopenharmony_ci .name = "SPDIF Sync", 245462306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 245562306a36Sopenharmony_ci .info = snd_rme_sync_state_info, 245662306a36Sopenharmony_ci .get = snd_rme_sync_state_get, 245762306a36Sopenharmony_ci .private_value = SND_RME_DOMAIN_SPDIF 245862306a36Sopenharmony_ci }, 245962306a36Sopenharmony_ci { 246062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 246162306a36Sopenharmony_ci .name = "SPDIF Interface", 246262306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 246362306a36Sopenharmony_ci .info = snd_rme_spdif_if_info, 246462306a36Sopenharmony_ci .get = snd_rme_spdif_if_get, 246562306a36Sopenharmony_ci }, 246662306a36Sopenharmony_ci { 246762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 246862306a36Sopenharmony_ci .name = "SPDIF Format", 246962306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 247062306a36Sopenharmony_ci .info = snd_rme_spdif_format_info, 247162306a36Sopenharmony_ci .get = snd_rme_spdif_format_get, 247262306a36Sopenharmony_ci }, 247362306a36Sopenharmony_ci { 247462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 247562306a36Sopenharmony_ci .name = "Sync Source", 247662306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 247762306a36Sopenharmony_ci .info = snd_rme_sync_source_info, 247862306a36Sopenharmony_ci .get = snd_rme_sync_source_get 247962306a36Sopenharmony_ci }, 248062306a36Sopenharmony_ci { 248162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 248262306a36Sopenharmony_ci .name = "System Rate", 248362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 248462306a36Sopenharmony_ci .info = snd_rme_rate_info, 248562306a36Sopenharmony_ci .get = snd_rme_rate_get, 248662306a36Sopenharmony_ci .private_value = SND_RME_DOMAIN_SYSTEM 248762306a36Sopenharmony_ci }, 248862306a36Sopenharmony_ci { 248962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 249062306a36Sopenharmony_ci .name = "Current Frequency", 249162306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 249262306a36Sopenharmony_ci .info = snd_rme_rate_info, 249362306a36Sopenharmony_ci .get = snd_rme_current_freq_get 249462306a36Sopenharmony_ci } 249562306a36Sopenharmony_ci}; 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_cistatic int snd_rme_controls_create(struct usb_mixer_interface *mixer) 249862306a36Sopenharmony_ci{ 249962306a36Sopenharmony_ci int err, i; 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_rme_controls); ++i) { 250262306a36Sopenharmony_ci err = add_single_ctl_with_resume(mixer, 0, 250362306a36Sopenharmony_ci NULL, 250462306a36Sopenharmony_ci &snd_rme_controls[i], 250562306a36Sopenharmony_ci NULL); 250662306a36Sopenharmony_ci if (err < 0) 250762306a36Sopenharmony_ci return err; 250862306a36Sopenharmony_ci } 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci return 0; 251162306a36Sopenharmony_ci} 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci/* 251462306a36Sopenharmony_ci * RME Babyface Pro (FS) 251562306a36Sopenharmony_ci * 251662306a36Sopenharmony_ci * These devices exposes a couple of DSP functions via request to EP0. 251762306a36Sopenharmony_ci * Switches are available via control registers, while routing is controlled 251862306a36Sopenharmony_ci * by controlling the volume on each possible crossing point. 251962306a36Sopenharmony_ci * Volume control is linear, from -inf (dec. 0) to +6dB (dec. 65536) with 252062306a36Sopenharmony_ci * 0dB being at dec. 32768. 252162306a36Sopenharmony_ci */ 252262306a36Sopenharmony_cienum { 252362306a36Sopenharmony_ci SND_BBFPRO_CTL_REG1 = 0, 252462306a36Sopenharmony_ci SND_BBFPRO_CTL_REG2 252562306a36Sopenharmony_ci}; 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci#define SND_BBFPRO_CTL_REG_MASK 1 252862306a36Sopenharmony_ci#define SND_BBFPRO_CTL_IDX_MASK 0xff 252962306a36Sopenharmony_ci#define SND_BBFPRO_CTL_IDX_SHIFT 1 253062306a36Sopenharmony_ci#define SND_BBFPRO_CTL_VAL_MASK 1 253162306a36Sopenharmony_ci#define SND_BBFPRO_CTL_VAL_SHIFT 9 253262306a36Sopenharmony_ci#define SND_BBFPRO_CTL_REG1_CLK_MASTER 0 253362306a36Sopenharmony_ci#define SND_BBFPRO_CTL_REG1_CLK_OPTICAL 1 253462306a36Sopenharmony_ci#define SND_BBFPRO_CTL_REG1_SPDIF_PRO 7 253562306a36Sopenharmony_ci#define SND_BBFPRO_CTL_REG1_SPDIF_EMPH 8 253662306a36Sopenharmony_ci#define SND_BBFPRO_CTL_REG1_SPDIF_OPTICAL 10 253762306a36Sopenharmony_ci#define SND_BBFPRO_CTL_REG2_48V_AN1 0 253862306a36Sopenharmony_ci#define SND_BBFPRO_CTL_REG2_48V_AN2 1 253962306a36Sopenharmony_ci#define SND_BBFPRO_CTL_REG2_SENS_IN3 2 254062306a36Sopenharmony_ci#define SND_BBFPRO_CTL_REG2_SENS_IN4 3 254162306a36Sopenharmony_ci#define SND_BBFPRO_CTL_REG2_PAD_AN1 4 254262306a36Sopenharmony_ci#define SND_BBFPRO_CTL_REG2_PAD_AN2 5 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_ci#define SND_BBFPRO_MIXER_IDX_MASK 0x1ff 254562306a36Sopenharmony_ci#define SND_BBFPRO_MIXER_VAL_MASK 0x3ffff 254662306a36Sopenharmony_ci#define SND_BBFPRO_MIXER_VAL_SHIFT 9 254762306a36Sopenharmony_ci#define SND_BBFPRO_MIXER_VAL_MIN 0 // -inf 254862306a36Sopenharmony_ci#define SND_BBFPRO_MIXER_VAL_MAX 65536 // +6dB 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci#define SND_BBFPRO_USBREQ_CTL_REG1 0x10 255162306a36Sopenharmony_ci#define SND_BBFPRO_USBREQ_CTL_REG2 0x17 255262306a36Sopenharmony_ci#define SND_BBFPRO_USBREQ_MIXER 0x12 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_cistatic int snd_bbfpro_ctl_update(struct usb_mixer_interface *mixer, u8 reg, 255562306a36Sopenharmony_ci u8 index, u8 value) 255662306a36Sopenharmony_ci{ 255762306a36Sopenharmony_ci int err; 255862306a36Sopenharmony_ci u16 usb_req, usb_idx, usb_val; 255962306a36Sopenharmony_ci struct snd_usb_audio *chip = mixer->chip; 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 256262306a36Sopenharmony_ci if (err < 0) 256362306a36Sopenharmony_ci return err; 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci if (reg == SND_BBFPRO_CTL_REG1) { 256662306a36Sopenharmony_ci usb_req = SND_BBFPRO_USBREQ_CTL_REG1; 256762306a36Sopenharmony_ci if (index == SND_BBFPRO_CTL_REG1_CLK_OPTICAL) { 256862306a36Sopenharmony_ci usb_idx = 3; 256962306a36Sopenharmony_ci usb_val = value ? 3 : 0; 257062306a36Sopenharmony_ci } else { 257162306a36Sopenharmony_ci usb_idx = 1 << index; 257262306a36Sopenharmony_ci usb_val = value ? usb_idx : 0; 257362306a36Sopenharmony_ci } 257462306a36Sopenharmony_ci } else { 257562306a36Sopenharmony_ci usb_req = SND_BBFPRO_USBREQ_CTL_REG2; 257662306a36Sopenharmony_ci usb_idx = 1 << index; 257762306a36Sopenharmony_ci usb_val = value ? usb_idx : 0; 257862306a36Sopenharmony_ci } 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 258162306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), usb_req, 258262306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 258362306a36Sopenharmony_ci usb_val, usb_idx, NULL, 0); 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 258662306a36Sopenharmony_ci return err; 258762306a36Sopenharmony_ci} 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_cistatic int snd_bbfpro_ctl_get(struct snd_kcontrol *kcontrol, 259062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 259162306a36Sopenharmony_ci{ 259262306a36Sopenharmony_ci u8 reg, idx, val; 259362306a36Sopenharmony_ci int pv; 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci pv = kcontrol->private_value; 259662306a36Sopenharmony_ci reg = pv & SND_BBFPRO_CTL_REG_MASK; 259762306a36Sopenharmony_ci idx = (pv >> SND_BBFPRO_CTL_IDX_SHIFT) & SND_BBFPRO_CTL_IDX_MASK; 259862306a36Sopenharmony_ci val = kcontrol->private_value >> SND_BBFPRO_CTL_VAL_SHIFT; 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci if ((reg == SND_BBFPRO_CTL_REG1 && 260162306a36Sopenharmony_ci idx == SND_BBFPRO_CTL_REG1_CLK_OPTICAL) || 260262306a36Sopenharmony_ci (reg == SND_BBFPRO_CTL_REG2 && 260362306a36Sopenharmony_ci (idx == SND_BBFPRO_CTL_REG2_SENS_IN3 || 260462306a36Sopenharmony_ci idx == SND_BBFPRO_CTL_REG2_SENS_IN4))) { 260562306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = val; 260662306a36Sopenharmony_ci } else { 260762306a36Sopenharmony_ci ucontrol->value.integer.value[0] = val; 260862306a36Sopenharmony_ci } 260962306a36Sopenharmony_ci return 0; 261062306a36Sopenharmony_ci} 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_cistatic int snd_bbfpro_ctl_info(struct snd_kcontrol *kcontrol, 261362306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 261462306a36Sopenharmony_ci{ 261562306a36Sopenharmony_ci u8 reg, idx; 261662306a36Sopenharmony_ci int pv; 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci pv = kcontrol->private_value; 261962306a36Sopenharmony_ci reg = pv & SND_BBFPRO_CTL_REG_MASK; 262062306a36Sopenharmony_ci idx = (pv >> SND_BBFPRO_CTL_IDX_SHIFT) & SND_BBFPRO_CTL_IDX_MASK; 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci if (reg == SND_BBFPRO_CTL_REG1 && 262362306a36Sopenharmony_ci idx == SND_BBFPRO_CTL_REG1_CLK_OPTICAL) { 262462306a36Sopenharmony_ci static const char * const texts[2] = { 262562306a36Sopenharmony_ci "AutoSync", 262662306a36Sopenharmony_ci "Internal" 262762306a36Sopenharmony_ci }; 262862306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 262962306a36Sopenharmony_ci } else if (reg == SND_BBFPRO_CTL_REG2 && 263062306a36Sopenharmony_ci (idx == SND_BBFPRO_CTL_REG2_SENS_IN3 || 263162306a36Sopenharmony_ci idx == SND_BBFPRO_CTL_REG2_SENS_IN4)) { 263262306a36Sopenharmony_ci static const char * const texts[2] = { 263362306a36Sopenharmony_ci "-10dBV", 263462306a36Sopenharmony_ci "+4dBu" 263562306a36Sopenharmony_ci }; 263662306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 263762306a36Sopenharmony_ci } 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci uinfo->count = 1; 264062306a36Sopenharmony_ci uinfo->value.integer.min = 0; 264162306a36Sopenharmony_ci uinfo->value.integer.max = 1; 264262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 264362306a36Sopenharmony_ci return 0; 264462306a36Sopenharmony_ci} 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_cistatic int snd_bbfpro_ctl_put(struct snd_kcontrol *kcontrol, 264762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 264862306a36Sopenharmony_ci{ 264962306a36Sopenharmony_ci int err; 265062306a36Sopenharmony_ci u8 reg, idx; 265162306a36Sopenharmony_ci int old_value, pv, val; 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 265462306a36Sopenharmony_ci struct usb_mixer_interface *mixer = list->mixer; 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci pv = kcontrol->private_value; 265762306a36Sopenharmony_ci reg = pv & SND_BBFPRO_CTL_REG_MASK; 265862306a36Sopenharmony_ci idx = (pv >> SND_BBFPRO_CTL_IDX_SHIFT) & SND_BBFPRO_CTL_IDX_MASK; 265962306a36Sopenharmony_ci old_value = (pv >> SND_BBFPRO_CTL_VAL_SHIFT) & SND_BBFPRO_CTL_VAL_MASK; 266062306a36Sopenharmony_ci 266162306a36Sopenharmony_ci if ((reg == SND_BBFPRO_CTL_REG1 && 266262306a36Sopenharmony_ci idx == SND_BBFPRO_CTL_REG1_CLK_OPTICAL) || 266362306a36Sopenharmony_ci (reg == SND_BBFPRO_CTL_REG2 && 266462306a36Sopenharmony_ci (idx == SND_BBFPRO_CTL_REG2_SENS_IN3 || 266562306a36Sopenharmony_ci idx == SND_BBFPRO_CTL_REG2_SENS_IN4))) { 266662306a36Sopenharmony_ci val = ucontrol->value.enumerated.item[0]; 266762306a36Sopenharmony_ci } else { 266862306a36Sopenharmony_ci val = ucontrol->value.integer.value[0]; 266962306a36Sopenharmony_ci } 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci if (val > 1) 267262306a36Sopenharmony_ci return -EINVAL; 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci if (val == old_value) 267562306a36Sopenharmony_ci return 0; 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci kcontrol->private_value = reg 267862306a36Sopenharmony_ci | ((idx & SND_BBFPRO_CTL_IDX_MASK) << SND_BBFPRO_CTL_IDX_SHIFT) 267962306a36Sopenharmony_ci | ((val & SND_BBFPRO_CTL_VAL_MASK) << SND_BBFPRO_CTL_VAL_SHIFT); 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci err = snd_bbfpro_ctl_update(mixer, reg, idx, val); 268262306a36Sopenharmony_ci return err < 0 ? err : 1; 268362306a36Sopenharmony_ci} 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_cistatic int snd_bbfpro_ctl_resume(struct usb_mixer_elem_list *list) 268662306a36Sopenharmony_ci{ 268762306a36Sopenharmony_ci u8 reg, idx; 268862306a36Sopenharmony_ci int value, pv; 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci pv = list->kctl->private_value; 269162306a36Sopenharmony_ci reg = pv & SND_BBFPRO_CTL_REG_MASK; 269262306a36Sopenharmony_ci idx = (pv >> SND_BBFPRO_CTL_IDX_SHIFT) & SND_BBFPRO_CTL_IDX_MASK; 269362306a36Sopenharmony_ci value = (pv >> SND_BBFPRO_CTL_VAL_SHIFT) & SND_BBFPRO_CTL_VAL_MASK; 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci return snd_bbfpro_ctl_update(list->mixer, reg, idx, value); 269662306a36Sopenharmony_ci} 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_cistatic int snd_bbfpro_vol_update(struct usb_mixer_interface *mixer, u16 index, 269962306a36Sopenharmony_ci u32 value) 270062306a36Sopenharmony_ci{ 270162306a36Sopenharmony_ci struct snd_usb_audio *chip = mixer->chip; 270262306a36Sopenharmony_ci int err; 270362306a36Sopenharmony_ci u16 idx; 270462306a36Sopenharmony_ci u16 usb_idx, usb_val; 270562306a36Sopenharmony_ci u32 v; 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci err = snd_usb_lock_shutdown(chip); 270862306a36Sopenharmony_ci if (err < 0) 270962306a36Sopenharmony_ci return err; 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci idx = index & SND_BBFPRO_MIXER_IDX_MASK; 271262306a36Sopenharmony_ci // 18 bit linear volume, split so 2 bits end up in index. 271362306a36Sopenharmony_ci v = value & SND_BBFPRO_MIXER_VAL_MASK; 271462306a36Sopenharmony_ci usb_idx = idx | (v & 0x3) << 14; 271562306a36Sopenharmony_ci usb_val = (v >> 2) & 0xffff; 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci err = snd_usb_ctl_msg(chip->dev, 271862306a36Sopenharmony_ci usb_sndctrlpipe(chip->dev, 0), 271962306a36Sopenharmony_ci SND_BBFPRO_USBREQ_MIXER, 272062306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | 272162306a36Sopenharmony_ci USB_RECIP_DEVICE, 272262306a36Sopenharmony_ci usb_val, usb_idx, NULL, 0); 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci snd_usb_unlock_shutdown(chip); 272562306a36Sopenharmony_ci return err; 272662306a36Sopenharmony_ci} 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_cistatic int snd_bbfpro_vol_get(struct snd_kcontrol *kcontrol, 272962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 273062306a36Sopenharmony_ci{ 273162306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 273262306a36Sopenharmony_ci kcontrol->private_value >> SND_BBFPRO_MIXER_VAL_SHIFT; 273362306a36Sopenharmony_ci return 0; 273462306a36Sopenharmony_ci} 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_cistatic int snd_bbfpro_vol_info(struct snd_kcontrol *kcontrol, 273762306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 273862306a36Sopenharmony_ci{ 273962306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 274062306a36Sopenharmony_ci uinfo->count = 1; 274162306a36Sopenharmony_ci uinfo->value.integer.min = SND_BBFPRO_MIXER_VAL_MIN; 274262306a36Sopenharmony_ci uinfo->value.integer.max = SND_BBFPRO_MIXER_VAL_MAX; 274362306a36Sopenharmony_ci return 0; 274462306a36Sopenharmony_ci} 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_cistatic int snd_bbfpro_vol_put(struct snd_kcontrol *kcontrol, 274762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 274862306a36Sopenharmony_ci{ 274962306a36Sopenharmony_ci int err; 275062306a36Sopenharmony_ci u16 idx; 275162306a36Sopenharmony_ci u32 new_val, old_value, uvalue; 275262306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); 275362306a36Sopenharmony_ci struct usb_mixer_interface *mixer = list->mixer; 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ci uvalue = ucontrol->value.integer.value[0]; 275662306a36Sopenharmony_ci idx = kcontrol->private_value & SND_BBFPRO_MIXER_IDX_MASK; 275762306a36Sopenharmony_ci old_value = kcontrol->private_value >> SND_BBFPRO_MIXER_VAL_SHIFT; 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci if (uvalue > SND_BBFPRO_MIXER_VAL_MAX) 276062306a36Sopenharmony_ci return -EINVAL; 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ci if (uvalue == old_value) 276362306a36Sopenharmony_ci return 0; 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci new_val = uvalue & SND_BBFPRO_MIXER_VAL_MASK; 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci kcontrol->private_value = idx 276862306a36Sopenharmony_ci | (new_val << SND_BBFPRO_MIXER_VAL_SHIFT); 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci err = snd_bbfpro_vol_update(mixer, idx, new_val); 277162306a36Sopenharmony_ci return err < 0 ? err : 1; 277262306a36Sopenharmony_ci} 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_cistatic int snd_bbfpro_vol_resume(struct usb_mixer_elem_list *list) 277562306a36Sopenharmony_ci{ 277662306a36Sopenharmony_ci int pv = list->kctl->private_value; 277762306a36Sopenharmony_ci u16 idx = pv & SND_BBFPRO_MIXER_IDX_MASK; 277862306a36Sopenharmony_ci u32 val = (pv >> SND_BBFPRO_MIXER_VAL_SHIFT) 277962306a36Sopenharmony_ci & SND_BBFPRO_MIXER_VAL_MASK; 278062306a36Sopenharmony_ci return snd_bbfpro_vol_update(list->mixer, idx, val); 278162306a36Sopenharmony_ci} 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci// Predfine elements 278462306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_bbfpro_ctl_control = { 278562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 278662306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 278762306a36Sopenharmony_ci .index = 0, 278862306a36Sopenharmony_ci .info = snd_bbfpro_ctl_info, 278962306a36Sopenharmony_ci .get = snd_bbfpro_ctl_get, 279062306a36Sopenharmony_ci .put = snd_bbfpro_ctl_put 279162306a36Sopenharmony_ci}; 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_bbfpro_vol_control = { 279462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 279562306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 279662306a36Sopenharmony_ci .index = 0, 279762306a36Sopenharmony_ci .info = snd_bbfpro_vol_info, 279862306a36Sopenharmony_ci .get = snd_bbfpro_vol_get, 279962306a36Sopenharmony_ci .put = snd_bbfpro_vol_put 280062306a36Sopenharmony_ci}; 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_cistatic int snd_bbfpro_ctl_add(struct usb_mixer_interface *mixer, u8 reg, 280362306a36Sopenharmony_ci u8 index, char *name) 280462306a36Sopenharmony_ci{ 280562306a36Sopenharmony_ci struct snd_kcontrol_new knew = snd_bbfpro_ctl_control; 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci knew.name = name; 280862306a36Sopenharmony_ci knew.private_value = (reg & SND_BBFPRO_CTL_REG_MASK) 280962306a36Sopenharmony_ci | ((index & SND_BBFPRO_CTL_IDX_MASK) 281062306a36Sopenharmony_ci << SND_BBFPRO_CTL_IDX_SHIFT); 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci return add_single_ctl_with_resume(mixer, 0, snd_bbfpro_ctl_resume, 281362306a36Sopenharmony_ci &knew, NULL); 281462306a36Sopenharmony_ci} 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_cistatic int snd_bbfpro_vol_add(struct usb_mixer_interface *mixer, u16 index, 281762306a36Sopenharmony_ci char *name) 281862306a36Sopenharmony_ci{ 281962306a36Sopenharmony_ci struct snd_kcontrol_new knew = snd_bbfpro_vol_control; 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci knew.name = name; 282262306a36Sopenharmony_ci knew.private_value = index & SND_BBFPRO_MIXER_IDX_MASK; 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci return add_single_ctl_with_resume(mixer, 0, snd_bbfpro_vol_resume, 282562306a36Sopenharmony_ci &knew, NULL); 282662306a36Sopenharmony_ci} 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_cistatic int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) 282962306a36Sopenharmony_ci{ 283062306a36Sopenharmony_ci int err, i, o; 283162306a36Sopenharmony_ci char name[48]; 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_ci static const char * const input[] = { 283462306a36Sopenharmony_ci "AN1", "AN2", "IN3", "IN4", "AS1", "AS2", "ADAT3", 283562306a36Sopenharmony_ci "ADAT4", "ADAT5", "ADAT6", "ADAT7", "ADAT8"}; 283662306a36Sopenharmony_ci 283762306a36Sopenharmony_ci static const char * const output[] = { 283862306a36Sopenharmony_ci "AN1", "AN2", "PH3", "PH4", "AS1", "AS2", "ADAT3", "ADAT4", 283962306a36Sopenharmony_ci "ADAT5", "ADAT6", "ADAT7", "ADAT8"}; 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci for (o = 0 ; o < 12 ; ++o) { 284262306a36Sopenharmony_ci for (i = 0 ; i < 12 ; ++i) { 284362306a36Sopenharmony_ci // Line routing 284462306a36Sopenharmony_ci snprintf(name, sizeof(name), 284562306a36Sopenharmony_ci "%s-%s-%s Playback Volume", 284662306a36Sopenharmony_ci (i < 2 ? "Mic" : "Line"), 284762306a36Sopenharmony_ci input[i], output[o]); 284862306a36Sopenharmony_ci err = snd_bbfpro_vol_add(mixer, (26 * o + i), name); 284962306a36Sopenharmony_ci if (err < 0) 285062306a36Sopenharmony_ci return err; 285162306a36Sopenharmony_ci 285262306a36Sopenharmony_ci // PCM routing... yes, it is output remapping 285362306a36Sopenharmony_ci snprintf(name, sizeof(name), 285462306a36Sopenharmony_ci "PCM-%s-%s Playback Volume", 285562306a36Sopenharmony_ci output[i], output[o]); 285662306a36Sopenharmony_ci err = snd_bbfpro_vol_add(mixer, (26 * o + 12 + i), 285762306a36Sopenharmony_ci name); 285862306a36Sopenharmony_ci if (err < 0) 285962306a36Sopenharmony_ci return err; 286062306a36Sopenharmony_ci } 286162306a36Sopenharmony_ci } 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci // Control Reg 1 286462306a36Sopenharmony_ci err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG1, 286562306a36Sopenharmony_ci SND_BBFPRO_CTL_REG1_CLK_OPTICAL, 286662306a36Sopenharmony_ci "Sample Clock Source"); 286762306a36Sopenharmony_ci if (err < 0) 286862306a36Sopenharmony_ci return err; 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG1, 287162306a36Sopenharmony_ci SND_BBFPRO_CTL_REG1_SPDIF_PRO, 287262306a36Sopenharmony_ci "IEC958 Pro Mask"); 287362306a36Sopenharmony_ci if (err < 0) 287462306a36Sopenharmony_ci return err; 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG1, 287762306a36Sopenharmony_ci SND_BBFPRO_CTL_REG1_SPDIF_EMPH, 287862306a36Sopenharmony_ci "IEC958 Emphasis"); 287962306a36Sopenharmony_ci if (err < 0) 288062306a36Sopenharmony_ci return err; 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_ci err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG1, 288362306a36Sopenharmony_ci SND_BBFPRO_CTL_REG1_SPDIF_OPTICAL, 288462306a36Sopenharmony_ci "IEC958 Switch"); 288562306a36Sopenharmony_ci if (err < 0) 288662306a36Sopenharmony_ci return err; 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci // Control Reg 2 288962306a36Sopenharmony_ci err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, 289062306a36Sopenharmony_ci SND_BBFPRO_CTL_REG2_48V_AN1, 289162306a36Sopenharmony_ci "Mic-AN1 48V"); 289262306a36Sopenharmony_ci if (err < 0) 289362306a36Sopenharmony_ci return err; 289462306a36Sopenharmony_ci 289562306a36Sopenharmony_ci err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, 289662306a36Sopenharmony_ci SND_BBFPRO_CTL_REG2_48V_AN2, 289762306a36Sopenharmony_ci "Mic-AN2 48V"); 289862306a36Sopenharmony_ci if (err < 0) 289962306a36Sopenharmony_ci return err; 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_ci err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, 290262306a36Sopenharmony_ci SND_BBFPRO_CTL_REG2_SENS_IN3, 290362306a36Sopenharmony_ci "Line-IN3 Sens."); 290462306a36Sopenharmony_ci if (err < 0) 290562306a36Sopenharmony_ci return err; 290662306a36Sopenharmony_ci 290762306a36Sopenharmony_ci err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, 290862306a36Sopenharmony_ci SND_BBFPRO_CTL_REG2_SENS_IN4, 290962306a36Sopenharmony_ci "Line-IN4 Sens."); 291062306a36Sopenharmony_ci if (err < 0) 291162306a36Sopenharmony_ci return err; 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, 291462306a36Sopenharmony_ci SND_BBFPRO_CTL_REG2_PAD_AN1, 291562306a36Sopenharmony_ci "Mic-AN1 PAD"); 291662306a36Sopenharmony_ci if (err < 0) 291762306a36Sopenharmony_ci return err; 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci err = snd_bbfpro_ctl_add(mixer, SND_BBFPRO_CTL_REG2, 292062306a36Sopenharmony_ci SND_BBFPRO_CTL_REG2_PAD_AN2, 292162306a36Sopenharmony_ci "Mic-AN2 PAD"); 292262306a36Sopenharmony_ci if (err < 0) 292362306a36Sopenharmony_ci return err; 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_ci return 0; 292662306a36Sopenharmony_ci} 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci/* 292962306a36Sopenharmony_ci * Pioneer DJ DJM Mixers 293062306a36Sopenharmony_ci * 293162306a36Sopenharmony_ci * These devices generally have options for soft-switching the playback and 293262306a36Sopenharmony_ci * capture sources in addition to the recording level. Although different 293362306a36Sopenharmony_ci * devices have different configurations, there seems to be canonical values 293462306a36Sopenharmony_ci * for specific capture/playback types: See the definitions of these below. 293562306a36Sopenharmony_ci * 293662306a36Sopenharmony_ci * The wValue is masked with the stereo channel number. e.g. Setting Ch2 to 293762306a36Sopenharmony_ci * capture phono would be 0x0203. Capture, playback and capture level have 293862306a36Sopenharmony_ci * different wIndexes. 293962306a36Sopenharmony_ci */ 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_ci// Capture types 294262306a36Sopenharmony_ci#define SND_DJM_CAP_LINE 0x00 294362306a36Sopenharmony_ci#define SND_DJM_CAP_CDLINE 0x01 294462306a36Sopenharmony_ci#define SND_DJM_CAP_DIGITAL 0x02 294562306a36Sopenharmony_ci#define SND_DJM_CAP_PHONO 0x03 294662306a36Sopenharmony_ci#define SND_DJM_CAP_PFADER 0x06 294762306a36Sopenharmony_ci#define SND_DJM_CAP_XFADERA 0x07 294862306a36Sopenharmony_ci#define SND_DJM_CAP_XFADERB 0x08 294962306a36Sopenharmony_ci#define SND_DJM_CAP_MIC 0x09 295062306a36Sopenharmony_ci#define SND_DJM_CAP_AUX 0x0d 295162306a36Sopenharmony_ci#define SND_DJM_CAP_RECOUT 0x0a 295262306a36Sopenharmony_ci#define SND_DJM_CAP_NONE 0x0f 295362306a36Sopenharmony_ci#define SND_DJM_CAP_CH1PFADER 0x11 295462306a36Sopenharmony_ci#define SND_DJM_CAP_CH2PFADER 0x12 295562306a36Sopenharmony_ci#define SND_DJM_CAP_CH3PFADER 0x13 295662306a36Sopenharmony_ci#define SND_DJM_CAP_CH4PFADER 0x14 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci// Playback types 295962306a36Sopenharmony_ci#define SND_DJM_PB_CH1 0x00 296062306a36Sopenharmony_ci#define SND_DJM_PB_CH2 0x01 296162306a36Sopenharmony_ci#define SND_DJM_PB_AUX 0x04 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_ci#define SND_DJM_WINDEX_CAP 0x8002 296462306a36Sopenharmony_ci#define SND_DJM_WINDEX_CAPLVL 0x8003 296562306a36Sopenharmony_ci#define SND_DJM_WINDEX_PB 0x8016 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci// kcontrol->private_value layout 296862306a36Sopenharmony_ci#define SND_DJM_VALUE_MASK 0x0000ffff 296962306a36Sopenharmony_ci#define SND_DJM_GROUP_MASK 0x00ff0000 297062306a36Sopenharmony_ci#define SND_DJM_DEVICE_MASK 0xff000000 297162306a36Sopenharmony_ci#define SND_DJM_GROUP_SHIFT 16 297262306a36Sopenharmony_ci#define SND_DJM_DEVICE_SHIFT 24 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci// device table index 297562306a36Sopenharmony_ci// used for the snd_djm_devices table, so please update accordingly 297662306a36Sopenharmony_ci#define SND_DJM_250MK2_IDX 0x0 297762306a36Sopenharmony_ci#define SND_DJM_750_IDX 0x1 297862306a36Sopenharmony_ci#define SND_DJM_850_IDX 0x2 297962306a36Sopenharmony_ci#define SND_DJM_900NXS2_IDX 0x3 298062306a36Sopenharmony_ci#define SND_DJM_750MK2_IDX 0x4 298162306a36Sopenharmony_ci#define SND_DJM_450_IDX 0x5 298262306a36Sopenharmony_ci 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci#define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \ 298562306a36Sopenharmony_ci .name = _name, \ 298662306a36Sopenharmony_ci .options = snd_djm_opts_##suffix, \ 298762306a36Sopenharmony_ci .noptions = ARRAY_SIZE(snd_djm_opts_##suffix), \ 298862306a36Sopenharmony_ci .default_value = _default_value, \ 298962306a36Sopenharmony_ci .wIndex = _windex } 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_ci#define SND_DJM_DEVICE(suffix) { \ 299262306a36Sopenharmony_ci .controls = snd_djm_ctls_##suffix, \ 299362306a36Sopenharmony_ci .ncontrols = ARRAY_SIZE(snd_djm_ctls_##suffix) } 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_cistruct snd_djm_device { 299762306a36Sopenharmony_ci const char *name; 299862306a36Sopenharmony_ci const struct snd_djm_ctl *controls; 299962306a36Sopenharmony_ci size_t ncontrols; 300062306a36Sopenharmony_ci}; 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_cistruct snd_djm_ctl { 300362306a36Sopenharmony_ci const char *name; 300462306a36Sopenharmony_ci const u16 *options; 300562306a36Sopenharmony_ci size_t noptions; 300662306a36Sopenharmony_ci u16 default_value; 300762306a36Sopenharmony_ci u16 wIndex; 300862306a36Sopenharmony_ci}; 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_cistatic const char *snd_djm_get_label_caplevel(u16 wvalue) 301162306a36Sopenharmony_ci{ 301262306a36Sopenharmony_ci switch (wvalue) { 301362306a36Sopenharmony_ci case 0x0000: return "-19dB"; 301462306a36Sopenharmony_ci case 0x0100: return "-15dB"; 301562306a36Sopenharmony_ci case 0x0200: return "-10dB"; 301662306a36Sopenharmony_ci case 0x0300: return "-5dB"; 301762306a36Sopenharmony_ci default: return NULL; 301862306a36Sopenharmony_ci } 301962306a36Sopenharmony_ci}; 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_cistatic const char *snd_djm_get_label_cap_common(u16 wvalue) 302262306a36Sopenharmony_ci{ 302362306a36Sopenharmony_ci switch (wvalue & 0x00ff) { 302462306a36Sopenharmony_ci case SND_DJM_CAP_LINE: return "Control Tone LINE"; 302562306a36Sopenharmony_ci case SND_DJM_CAP_CDLINE: return "Control Tone CD/LINE"; 302662306a36Sopenharmony_ci case SND_DJM_CAP_DIGITAL: return "Control Tone DIGITAL"; 302762306a36Sopenharmony_ci case SND_DJM_CAP_PHONO: return "Control Tone PHONO"; 302862306a36Sopenharmony_ci case SND_DJM_CAP_PFADER: return "Post Fader"; 302962306a36Sopenharmony_ci case SND_DJM_CAP_XFADERA: return "Cross Fader A"; 303062306a36Sopenharmony_ci case SND_DJM_CAP_XFADERB: return "Cross Fader B"; 303162306a36Sopenharmony_ci case SND_DJM_CAP_MIC: return "Mic"; 303262306a36Sopenharmony_ci case SND_DJM_CAP_RECOUT: return "Rec Out"; 303362306a36Sopenharmony_ci case SND_DJM_CAP_AUX: return "Aux"; 303462306a36Sopenharmony_ci case SND_DJM_CAP_NONE: return "None"; 303562306a36Sopenharmony_ci case SND_DJM_CAP_CH1PFADER: return "Post Fader Ch1"; 303662306a36Sopenharmony_ci case SND_DJM_CAP_CH2PFADER: return "Post Fader Ch2"; 303762306a36Sopenharmony_ci case SND_DJM_CAP_CH3PFADER: return "Post Fader Ch3"; 303862306a36Sopenharmony_ci case SND_DJM_CAP_CH4PFADER: return "Post Fader Ch4"; 303962306a36Sopenharmony_ci default: return NULL; 304062306a36Sopenharmony_ci } 304162306a36Sopenharmony_ci}; 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_ci// The DJM-850 has different values for CD/LINE and LINE capture 304462306a36Sopenharmony_ci// control options than the other DJM declared in this file. 304562306a36Sopenharmony_cistatic const char *snd_djm_get_label_cap_850(u16 wvalue) 304662306a36Sopenharmony_ci{ 304762306a36Sopenharmony_ci switch (wvalue & 0x00ff) { 304862306a36Sopenharmony_ci case 0x00: return "Control Tone CD/LINE"; 304962306a36Sopenharmony_ci case 0x01: return "Control Tone LINE"; 305062306a36Sopenharmony_ci default: return snd_djm_get_label_cap_common(wvalue); 305162306a36Sopenharmony_ci } 305262306a36Sopenharmony_ci}; 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_cistatic const char *snd_djm_get_label_cap(u8 device_idx, u16 wvalue) 305562306a36Sopenharmony_ci{ 305662306a36Sopenharmony_ci switch (device_idx) { 305762306a36Sopenharmony_ci case SND_DJM_850_IDX: return snd_djm_get_label_cap_850(wvalue); 305862306a36Sopenharmony_ci default: return snd_djm_get_label_cap_common(wvalue); 305962306a36Sopenharmony_ci } 306062306a36Sopenharmony_ci}; 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_cistatic const char *snd_djm_get_label_pb(u16 wvalue) 306362306a36Sopenharmony_ci{ 306462306a36Sopenharmony_ci switch (wvalue & 0x00ff) { 306562306a36Sopenharmony_ci case SND_DJM_PB_CH1: return "Ch1"; 306662306a36Sopenharmony_ci case SND_DJM_PB_CH2: return "Ch2"; 306762306a36Sopenharmony_ci case SND_DJM_PB_AUX: return "Aux"; 306862306a36Sopenharmony_ci default: return NULL; 306962306a36Sopenharmony_ci } 307062306a36Sopenharmony_ci}; 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_cistatic const char *snd_djm_get_label(u8 device_idx, u16 wvalue, u16 windex) 307362306a36Sopenharmony_ci{ 307462306a36Sopenharmony_ci switch (windex) { 307562306a36Sopenharmony_ci case SND_DJM_WINDEX_CAPLVL: return snd_djm_get_label_caplevel(wvalue); 307662306a36Sopenharmony_ci case SND_DJM_WINDEX_CAP: return snd_djm_get_label_cap(device_idx, wvalue); 307762306a36Sopenharmony_ci case SND_DJM_WINDEX_PB: return snd_djm_get_label_pb(wvalue); 307862306a36Sopenharmony_ci default: return NULL; 307962306a36Sopenharmony_ci } 308062306a36Sopenharmony_ci}; 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci// common DJM capture level option values 308362306a36Sopenharmony_cistatic const u16 snd_djm_opts_cap_level[] = { 308462306a36Sopenharmony_ci 0x0000, 0x0100, 0x0200, 0x0300 }; 308562306a36Sopenharmony_ci 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci// DJM-250MK2 308862306a36Sopenharmony_cistatic const u16 snd_djm_opts_250mk2_cap1[] = { 308962306a36Sopenharmony_ci 0x0103, 0x0100, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d, 0x010a }; 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_cistatic const u16 snd_djm_opts_250mk2_cap2[] = { 309262306a36Sopenharmony_ci 0x0203, 0x0200, 0x0206, 0x0207, 0x0208, 0x0209, 0x020d, 0x020a }; 309362306a36Sopenharmony_ci 309462306a36Sopenharmony_cistatic const u16 snd_djm_opts_250mk2_cap3[] = { 309562306a36Sopenharmony_ci 0x030a, 0x0311, 0x0312, 0x0307, 0x0308, 0x0309, 0x030d }; 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_cistatic const u16 snd_djm_opts_250mk2_pb1[] = { 0x0100, 0x0101, 0x0104 }; 309862306a36Sopenharmony_cistatic const u16 snd_djm_opts_250mk2_pb2[] = { 0x0200, 0x0201, 0x0204 }; 309962306a36Sopenharmony_cistatic const u16 snd_djm_opts_250mk2_pb3[] = { 0x0300, 0x0301, 0x0304 }; 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_cistatic const struct snd_djm_ctl snd_djm_ctls_250mk2[] = { 310262306a36Sopenharmony_ci SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), 310362306a36Sopenharmony_ci SND_DJM_CTL("Ch1 Input", 250mk2_cap1, 2, SND_DJM_WINDEX_CAP), 310462306a36Sopenharmony_ci SND_DJM_CTL("Ch2 Input", 250mk2_cap2, 2, SND_DJM_WINDEX_CAP), 310562306a36Sopenharmony_ci SND_DJM_CTL("Ch3 Input", 250mk2_cap3, 0, SND_DJM_WINDEX_CAP), 310662306a36Sopenharmony_ci SND_DJM_CTL("Ch1 Output", 250mk2_pb1, 0, SND_DJM_WINDEX_PB), 310762306a36Sopenharmony_ci SND_DJM_CTL("Ch2 Output", 250mk2_pb2, 1, SND_DJM_WINDEX_PB), 310862306a36Sopenharmony_ci SND_DJM_CTL("Ch3 Output", 250mk2_pb3, 2, SND_DJM_WINDEX_PB) 310962306a36Sopenharmony_ci}; 311062306a36Sopenharmony_ci 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci// DJM-450 311362306a36Sopenharmony_cistatic const u16 snd_djm_opts_450_cap1[] = { 311462306a36Sopenharmony_ci 0x0103, 0x0100, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d, 0x010a }; 311562306a36Sopenharmony_ci 311662306a36Sopenharmony_cistatic const u16 snd_djm_opts_450_cap2[] = { 311762306a36Sopenharmony_ci 0x0203, 0x0200, 0x0206, 0x0207, 0x0208, 0x0209, 0x020d, 0x020a }; 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_cistatic const u16 snd_djm_opts_450_cap3[] = { 312062306a36Sopenharmony_ci 0x030a, 0x0311, 0x0312, 0x0307, 0x0308, 0x0309, 0x030d }; 312162306a36Sopenharmony_ci 312262306a36Sopenharmony_cistatic const u16 snd_djm_opts_450_pb1[] = { 0x0100, 0x0101, 0x0104 }; 312362306a36Sopenharmony_cistatic const u16 snd_djm_opts_450_pb2[] = { 0x0200, 0x0201, 0x0204 }; 312462306a36Sopenharmony_cistatic const u16 snd_djm_opts_450_pb3[] = { 0x0300, 0x0301, 0x0304 }; 312562306a36Sopenharmony_ci 312662306a36Sopenharmony_cistatic const struct snd_djm_ctl snd_djm_ctls_450[] = { 312762306a36Sopenharmony_ci SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), 312862306a36Sopenharmony_ci SND_DJM_CTL("Ch1 Input", 450_cap1, 2, SND_DJM_WINDEX_CAP), 312962306a36Sopenharmony_ci SND_DJM_CTL("Ch2 Input", 450_cap2, 2, SND_DJM_WINDEX_CAP), 313062306a36Sopenharmony_ci SND_DJM_CTL("Ch3 Input", 450_cap3, 0, SND_DJM_WINDEX_CAP), 313162306a36Sopenharmony_ci SND_DJM_CTL("Ch1 Output", 450_pb1, 0, SND_DJM_WINDEX_PB), 313262306a36Sopenharmony_ci SND_DJM_CTL("Ch2 Output", 450_pb2, 1, SND_DJM_WINDEX_PB), 313362306a36Sopenharmony_ci SND_DJM_CTL("Ch3 Output", 450_pb3, 2, SND_DJM_WINDEX_PB) 313462306a36Sopenharmony_ci}; 313562306a36Sopenharmony_ci 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci// DJM-750 313862306a36Sopenharmony_cistatic const u16 snd_djm_opts_750_cap1[] = { 313962306a36Sopenharmony_ci 0x0101, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a, 0x010f }; 314062306a36Sopenharmony_cistatic const u16 snd_djm_opts_750_cap2[] = { 314162306a36Sopenharmony_ci 0x0200, 0x0201, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020f }; 314262306a36Sopenharmony_cistatic const u16 snd_djm_opts_750_cap3[] = { 314362306a36Sopenharmony_ci 0x0300, 0x0301, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030f }; 314462306a36Sopenharmony_cistatic const u16 snd_djm_opts_750_cap4[] = { 314562306a36Sopenharmony_ci 0x0401, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f }; 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_cistatic const struct snd_djm_ctl snd_djm_ctls_750[] = { 314862306a36Sopenharmony_ci SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), 314962306a36Sopenharmony_ci SND_DJM_CTL("Ch1 Input", 750_cap1, 2, SND_DJM_WINDEX_CAP), 315062306a36Sopenharmony_ci SND_DJM_CTL("Ch2 Input", 750_cap2, 2, SND_DJM_WINDEX_CAP), 315162306a36Sopenharmony_ci SND_DJM_CTL("Ch3 Input", 750_cap3, 0, SND_DJM_WINDEX_CAP), 315262306a36Sopenharmony_ci SND_DJM_CTL("Ch4 Input", 750_cap4, 0, SND_DJM_WINDEX_CAP) 315362306a36Sopenharmony_ci}; 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci// DJM-850 315762306a36Sopenharmony_cistatic const u16 snd_djm_opts_850_cap1[] = { 315862306a36Sopenharmony_ci 0x0100, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a, 0x010f }; 315962306a36Sopenharmony_cistatic const u16 snd_djm_opts_850_cap2[] = { 316062306a36Sopenharmony_ci 0x0200, 0x0201, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020f }; 316162306a36Sopenharmony_cistatic const u16 snd_djm_opts_850_cap3[] = { 316262306a36Sopenharmony_ci 0x0300, 0x0301, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030f }; 316362306a36Sopenharmony_cistatic const u16 snd_djm_opts_850_cap4[] = { 316462306a36Sopenharmony_ci 0x0400, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f }; 316562306a36Sopenharmony_ci 316662306a36Sopenharmony_cistatic const struct snd_djm_ctl snd_djm_ctls_850[] = { 316762306a36Sopenharmony_ci SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), 316862306a36Sopenharmony_ci SND_DJM_CTL("Ch1 Input", 850_cap1, 1, SND_DJM_WINDEX_CAP), 316962306a36Sopenharmony_ci SND_DJM_CTL("Ch2 Input", 850_cap2, 0, SND_DJM_WINDEX_CAP), 317062306a36Sopenharmony_ci SND_DJM_CTL("Ch3 Input", 850_cap3, 0, SND_DJM_WINDEX_CAP), 317162306a36Sopenharmony_ci SND_DJM_CTL("Ch4 Input", 850_cap4, 1, SND_DJM_WINDEX_CAP) 317262306a36Sopenharmony_ci}; 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci// DJM-900NXS2 317662306a36Sopenharmony_cistatic const u16 snd_djm_opts_900nxs2_cap1[] = { 317762306a36Sopenharmony_ci 0x0100, 0x0102, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a }; 317862306a36Sopenharmony_cistatic const u16 snd_djm_opts_900nxs2_cap2[] = { 317962306a36Sopenharmony_ci 0x0200, 0x0202, 0x0203, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a }; 318062306a36Sopenharmony_cistatic const u16 snd_djm_opts_900nxs2_cap3[] = { 318162306a36Sopenharmony_ci 0x0300, 0x0302, 0x0303, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a }; 318262306a36Sopenharmony_cistatic const u16 snd_djm_opts_900nxs2_cap4[] = { 318362306a36Sopenharmony_ci 0x0400, 0x0402, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a }; 318462306a36Sopenharmony_cistatic const u16 snd_djm_opts_900nxs2_cap5[] = { 318562306a36Sopenharmony_ci 0x0507, 0x0508, 0x0509, 0x050a, 0x0511, 0x0512, 0x0513, 0x0514 }; 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_cistatic const struct snd_djm_ctl snd_djm_ctls_900nxs2[] = { 318862306a36Sopenharmony_ci SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), 318962306a36Sopenharmony_ci SND_DJM_CTL("Ch1 Input", 900nxs2_cap1, 2, SND_DJM_WINDEX_CAP), 319062306a36Sopenharmony_ci SND_DJM_CTL("Ch2 Input", 900nxs2_cap2, 2, SND_DJM_WINDEX_CAP), 319162306a36Sopenharmony_ci SND_DJM_CTL("Ch3 Input", 900nxs2_cap3, 2, SND_DJM_WINDEX_CAP), 319262306a36Sopenharmony_ci SND_DJM_CTL("Ch4 Input", 900nxs2_cap4, 2, SND_DJM_WINDEX_CAP), 319362306a36Sopenharmony_ci SND_DJM_CTL("Ch5 Input", 900nxs2_cap5, 3, SND_DJM_WINDEX_CAP) 319462306a36Sopenharmony_ci}; 319562306a36Sopenharmony_ci 319662306a36Sopenharmony_ci// DJM-750MK2 319762306a36Sopenharmony_cistatic const u16 snd_djm_opts_750mk2_cap1[] = { 319862306a36Sopenharmony_ci 0x0100, 0x0102, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a }; 319962306a36Sopenharmony_cistatic const u16 snd_djm_opts_750mk2_cap2[] = { 320062306a36Sopenharmony_ci 0x0200, 0x0202, 0x0203, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a }; 320162306a36Sopenharmony_cistatic const u16 snd_djm_opts_750mk2_cap3[] = { 320262306a36Sopenharmony_ci 0x0300, 0x0302, 0x0303, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a }; 320362306a36Sopenharmony_cistatic const u16 snd_djm_opts_750mk2_cap4[] = { 320462306a36Sopenharmony_ci 0x0400, 0x0402, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a }; 320562306a36Sopenharmony_cistatic const u16 snd_djm_opts_750mk2_cap5[] = { 320662306a36Sopenharmony_ci 0x0507, 0x0508, 0x0509, 0x050a, 0x0511, 0x0512, 0x0513, 0x0514 }; 320762306a36Sopenharmony_ci 320862306a36Sopenharmony_cistatic const u16 snd_djm_opts_750mk2_pb1[] = { 0x0100, 0x0101, 0x0104 }; 320962306a36Sopenharmony_cistatic const u16 snd_djm_opts_750mk2_pb2[] = { 0x0200, 0x0201, 0x0204 }; 321062306a36Sopenharmony_cistatic const u16 snd_djm_opts_750mk2_pb3[] = { 0x0300, 0x0301, 0x0304 }; 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_ci 321362306a36Sopenharmony_cistatic const struct snd_djm_ctl snd_djm_ctls_750mk2[] = { 321462306a36Sopenharmony_ci SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), 321562306a36Sopenharmony_ci SND_DJM_CTL("Ch1 Input", 750mk2_cap1, 2, SND_DJM_WINDEX_CAP), 321662306a36Sopenharmony_ci SND_DJM_CTL("Ch2 Input", 750mk2_cap2, 2, SND_DJM_WINDEX_CAP), 321762306a36Sopenharmony_ci SND_DJM_CTL("Ch3 Input", 750mk2_cap3, 2, SND_DJM_WINDEX_CAP), 321862306a36Sopenharmony_ci SND_DJM_CTL("Ch4 Input", 750mk2_cap4, 2, SND_DJM_WINDEX_CAP), 321962306a36Sopenharmony_ci SND_DJM_CTL("Ch5 Input", 750mk2_cap5, 3, SND_DJM_WINDEX_CAP), 322062306a36Sopenharmony_ci SND_DJM_CTL("Ch1 Output", 750mk2_pb1, 0, SND_DJM_WINDEX_PB), 322162306a36Sopenharmony_ci SND_DJM_CTL("Ch2 Output", 750mk2_pb2, 1, SND_DJM_WINDEX_PB), 322262306a36Sopenharmony_ci SND_DJM_CTL("Ch3 Output", 750mk2_pb3, 2, SND_DJM_WINDEX_PB) 322362306a36Sopenharmony_ci}; 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_ci 322662306a36Sopenharmony_cistatic const struct snd_djm_device snd_djm_devices[] = { 322762306a36Sopenharmony_ci [SND_DJM_250MK2_IDX] = SND_DJM_DEVICE(250mk2), 322862306a36Sopenharmony_ci [SND_DJM_750_IDX] = SND_DJM_DEVICE(750), 322962306a36Sopenharmony_ci [SND_DJM_850_IDX] = SND_DJM_DEVICE(850), 323062306a36Sopenharmony_ci [SND_DJM_900NXS2_IDX] = SND_DJM_DEVICE(900nxs2), 323162306a36Sopenharmony_ci [SND_DJM_750MK2_IDX] = SND_DJM_DEVICE(750mk2), 323262306a36Sopenharmony_ci [SND_DJM_450_IDX] = SND_DJM_DEVICE(450), 323362306a36Sopenharmony_ci}; 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_cistatic int snd_djm_controls_info(struct snd_kcontrol *kctl, 323762306a36Sopenharmony_ci struct snd_ctl_elem_info *info) 323862306a36Sopenharmony_ci{ 323962306a36Sopenharmony_ci unsigned long private_value = kctl->private_value; 324062306a36Sopenharmony_ci u8 device_idx = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT; 324162306a36Sopenharmony_ci u8 ctl_idx = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT; 324262306a36Sopenharmony_ci const struct snd_djm_device *device = &snd_djm_devices[device_idx]; 324362306a36Sopenharmony_ci const char *name; 324462306a36Sopenharmony_ci const struct snd_djm_ctl *ctl; 324562306a36Sopenharmony_ci size_t noptions; 324662306a36Sopenharmony_ci 324762306a36Sopenharmony_ci if (ctl_idx >= device->ncontrols) 324862306a36Sopenharmony_ci return -EINVAL; 324962306a36Sopenharmony_ci 325062306a36Sopenharmony_ci ctl = &device->controls[ctl_idx]; 325162306a36Sopenharmony_ci noptions = ctl->noptions; 325262306a36Sopenharmony_ci if (info->value.enumerated.item >= noptions) 325362306a36Sopenharmony_ci info->value.enumerated.item = noptions - 1; 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci name = snd_djm_get_label(device_idx, 325662306a36Sopenharmony_ci ctl->options[info->value.enumerated.item], 325762306a36Sopenharmony_ci ctl->wIndex); 325862306a36Sopenharmony_ci if (!name) 325962306a36Sopenharmony_ci return -EINVAL; 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci strscpy(info->value.enumerated.name, name, sizeof(info->value.enumerated.name)); 326262306a36Sopenharmony_ci info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 326362306a36Sopenharmony_ci info->count = 1; 326462306a36Sopenharmony_ci info->value.enumerated.items = noptions; 326562306a36Sopenharmony_ci return 0; 326662306a36Sopenharmony_ci} 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_cistatic int snd_djm_controls_update(struct usb_mixer_interface *mixer, 326962306a36Sopenharmony_ci u8 device_idx, u8 group, u16 value) 327062306a36Sopenharmony_ci{ 327162306a36Sopenharmony_ci int err; 327262306a36Sopenharmony_ci const struct snd_djm_device *device = &snd_djm_devices[device_idx]; 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_ci if ((group >= device->ncontrols) || value >= device->controls[group].noptions) 327562306a36Sopenharmony_ci return -EINVAL; 327662306a36Sopenharmony_ci 327762306a36Sopenharmony_ci err = snd_usb_lock_shutdown(mixer->chip); 327862306a36Sopenharmony_ci if (err) 327962306a36Sopenharmony_ci return err; 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_ci err = snd_usb_ctl_msg( 328262306a36Sopenharmony_ci mixer->chip->dev, usb_sndctrlpipe(mixer->chip->dev, 0), 328362306a36Sopenharmony_ci USB_REQ_SET_FEATURE, 328462306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 328562306a36Sopenharmony_ci device->controls[group].options[value], 328662306a36Sopenharmony_ci device->controls[group].wIndex, 328762306a36Sopenharmony_ci NULL, 0); 328862306a36Sopenharmony_ci 328962306a36Sopenharmony_ci snd_usb_unlock_shutdown(mixer->chip); 329062306a36Sopenharmony_ci return err; 329162306a36Sopenharmony_ci} 329262306a36Sopenharmony_ci 329362306a36Sopenharmony_cistatic int snd_djm_controls_get(struct snd_kcontrol *kctl, 329462306a36Sopenharmony_ci struct snd_ctl_elem_value *elem) 329562306a36Sopenharmony_ci{ 329662306a36Sopenharmony_ci elem->value.enumerated.item[0] = kctl->private_value & SND_DJM_VALUE_MASK; 329762306a36Sopenharmony_ci return 0; 329862306a36Sopenharmony_ci} 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_cistatic int snd_djm_controls_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *elem) 330162306a36Sopenharmony_ci{ 330262306a36Sopenharmony_ci struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl); 330362306a36Sopenharmony_ci struct usb_mixer_interface *mixer = list->mixer; 330462306a36Sopenharmony_ci unsigned long private_value = kctl->private_value; 330562306a36Sopenharmony_ci 330662306a36Sopenharmony_ci u8 device = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT; 330762306a36Sopenharmony_ci u8 group = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT; 330862306a36Sopenharmony_ci u16 value = elem->value.enumerated.item[0]; 330962306a36Sopenharmony_ci 331062306a36Sopenharmony_ci kctl->private_value = (((unsigned long)device << SND_DJM_DEVICE_SHIFT) | 331162306a36Sopenharmony_ci (group << SND_DJM_GROUP_SHIFT) | 331262306a36Sopenharmony_ci value); 331362306a36Sopenharmony_ci 331462306a36Sopenharmony_ci return snd_djm_controls_update(mixer, device, group, value); 331562306a36Sopenharmony_ci} 331662306a36Sopenharmony_ci 331762306a36Sopenharmony_cistatic int snd_djm_controls_resume(struct usb_mixer_elem_list *list) 331862306a36Sopenharmony_ci{ 331962306a36Sopenharmony_ci unsigned long private_value = list->kctl->private_value; 332062306a36Sopenharmony_ci u8 device = (private_value & SND_DJM_DEVICE_MASK) >> SND_DJM_DEVICE_SHIFT; 332162306a36Sopenharmony_ci u8 group = (private_value & SND_DJM_GROUP_MASK) >> SND_DJM_GROUP_SHIFT; 332262306a36Sopenharmony_ci u16 value = (private_value & SND_DJM_VALUE_MASK); 332362306a36Sopenharmony_ci 332462306a36Sopenharmony_ci return snd_djm_controls_update(list->mixer, device, group, value); 332562306a36Sopenharmony_ci} 332662306a36Sopenharmony_ci 332762306a36Sopenharmony_cistatic int snd_djm_controls_create(struct usb_mixer_interface *mixer, 332862306a36Sopenharmony_ci const u8 device_idx) 332962306a36Sopenharmony_ci{ 333062306a36Sopenharmony_ci int err, i; 333162306a36Sopenharmony_ci u16 value; 333262306a36Sopenharmony_ci 333362306a36Sopenharmony_ci const struct snd_djm_device *device = &snd_djm_devices[device_idx]; 333462306a36Sopenharmony_ci 333562306a36Sopenharmony_ci struct snd_kcontrol_new knew = { 333662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 333762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 333862306a36Sopenharmony_ci .index = 0, 333962306a36Sopenharmony_ci .info = snd_djm_controls_info, 334062306a36Sopenharmony_ci .get = snd_djm_controls_get, 334162306a36Sopenharmony_ci .put = snd_djm_controls_put 334262306a36Sopenharmony_ci }; 334362306a36Sopenharmony_ci 334462306a36Sopenharmony_ci for (i = 0; i < device->ncontrols; i++) { 334562306a36Sopenharmony_ci value = device->controls[i].default_value; 334662306a36Sopenharmony_ci knew.name = device->controls[i].name; 334762306a36Sopenharmony_ci knew.private_value = ( 334862306a36Sopenharmony_ci ((unsigned long)device_idx << SND_DJM_DEVICE_SHIFT) | 334962306a36Sopenharmony_ci (i << SND_DJM_GROUP_SHIFT) | 335062306a36Sopenharmony_ci value); 335162306a36Sopenharmony_ci err = snd_djm_controls_update(mixer, device_idx, i, value); 335262306a36Sopenharmony_ci if (err) 335362306a36Sopenharmony_ci return err; 335462306a36Sopenharmony_ci err = add_single_ctl_with_resume(mixer, 0, snd_djm_controls_resume, 335562306a36Sopenharmony_ci &knew, NULL); 335662306a36Sopenharmony_ci if (err) 335762306a36Sopenharmony_ci return err; 335862306a36Sopenharmony_ci } 335962306a36Sopenharmony_ci return 0; 336062306a36Sopenharmony_ci} 336162306a36Sopenharmony_ci 336262306a36Sopenharmony_ciint snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) 336362306a36Sopenharmony_ci{ 336462306a36Sopenharmony_ci int err = 0; 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ci err = snd_usb_soundblaster_remote_init(mixer); 336762306a36Sopenharmony_ci if (err < 0) 336862306a36Sopenharmony_ci return err; 336962306a36Sopenharmony_ci 337062306a36Sopenharmony_ci switch (mixer->chip->usb_id) { 337162306a36Sopenharmony_ci /* Tascam US-16x08 */ 337262306a36Sopenharmony_ci case USB_ID(0x0644, 0x8047): 337362306a36Sopenharmony_ci err = snd_us16x08_controls_create(mixer); 337462306a36Sopenharmony_ci break; 337562306a36Sopenharmony_ci case USB_ID(0x041e, 0x3020): 337662306a36Sopenharmony_ci case USB_ID(0x041e, 0x3040): 337762306a36Sopenharmony_ci case USB_ID(0x041e, 0x3042): 337862306a36Sopenharmony_ci case USB_ID(0x041e, 0x30df): 337962306a36Sopenharmony_ci case USB_ID(0x041e, 0x3048): 338062306a36Sopenharmony_ci err = snd_audigy2nx_controls_create(mixer); 338162306a36Sopenharmony_ci if (err < 0) 338262306a36Sopenharmony_ci break; 338362306a36Sopenharmony_ci snd_card_ro_proc_new(mixer->chip->card, "audigy2nx", 338462306a36Sopenharmony_ci mixer, snd_audigy2nx_proc_read); 338562306a36Sopenharmony_ci break; 338662306a36Sopenharmony_ci 338762306a36Sopenharmony_ci /* EMU0204 */ 338862306a36Sopenharmony_ci case USB_ID(0x041e, 0x3f19): 338962306a36Sopenharmony_ci err = snd_emu0204_controls_create(mixer); 339062306a36Sopenharmony_ci break; 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ 339362306a36Sopenharmony_ci case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C400 */ 339462306a36Sopenharmony_ci err = snd_c400_create_mixer(mixer); 339562306a36Sopenharmony_ci break; 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_ci case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ 339862306a36Sopenharmony_ci case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ 339962306a36Sopenharmony_ci err = snd_ftu_create_mixer(mixer); 340062306a36Sopenharmony_ci break; 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_ci case USB_ID(0x0b05, 0x1739): /* ASUS Xonar U1 */ 340362306a36Sopenharmony_ci case USB_ID(0x0b05, 0x1743): /* ASUS Xonar U1 (2) */ 340462306a36Sopenharmony_ci case USB_ID(0x0b05, 0x17a0): /* ASUS Xonar U3 */ 340562306a36Sopenharmony_ci err = snd_xonar_u1_controls_create(mixer); 340662306a36Sopenharmony_ci break; 340762306a36Sopenharmony_ci 340862306a36Sopenharmony_ci case USB_ID(0x0d8c, 0x0103): /* Audio Advantage Micro II */ 340962306a36Sopenharmony_ci err = snd_microii_controls_create(mixer); 341062306a36Sopenharmony_ci break; 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_ci case USB_ID(0x0dba, 0x1000): /* Digidesign Mbox 1 */ 341362306a36Sopenharmony_ci err = snd_mbox1_controls_create(mixer); 341462306a36Sopenharmony_ci break; 341562306a36Sopenharmony_ci 341662306a36Sopenharmony_ci case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */ 341762306a36Sopenharmony_ci err = snd_nativeinstruments_create_mixer(mixer, 341862306a36Sopenharmony_ci snd_nativeinstruments_ta6_mixers, 341962306a36Sopenharmony_ci ARRAY_SIZE(snd_nativeinstruments_ta6_mixers)); 342062306a36Sopenharmony_ci break; 342162306a36Sopenharmony_ci 342262306a36Sopenharmony_ci case USB_ID(0x17cc, 0x1021): /* Traktor Audio 10 */ 342362306a36Sopenharmony_ci err = snd_nativeinstruments_create_mixer(mixer, 342462306a36Sopenharmony_ci snd_nativeinstruments_ta10_mixers, 342562306a36Sopenharmony_ci ARRAY_SIZE(snd_nativeinstruments_ta10_mixers)); 342662306a36Sopenharmony_ci break; 342762306a36Sopenharmony_ci 342862306a36Sopenharmony_ci case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */ 342962306a36Sopenharmony_ci /* detection is disabled in mixer_maps.c */ 343062306a36Sopenharmony_ci err = snd_create_std_mono_table(mixer, ebox44_table); 343162306a36Sopenharmony_ci break; 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci case USB_ID(0x1235, 0x8012): /* Focusrite Scarlett 6i6 */ 343462306a36Sopenharmony_ci case USB_ID(0x1235, 0x8002): /* Focusrite Scarlett 8i6 */ 343562306a36Sopenharmony_ci case USB_ID(0x1235, 0x8004): /* Focusrite Scarlett 18i6 */ 343662306a36Sopenharmony_ci case USB_ID(0x1235, 0x8014): /* Focusrite Scarlett 18i8 */ 343762306a36Sopenharmony_ci case USB_ID(0x1235, 0x800c): /* Focusrite Scarlett 18i20 */ 343862306a36Sopenharmony_ci err = snd_scarlett_controls_create(mixer); 343962306a36Sopenharmony_ci break; 344062306a36Sopenharmony_ci 344162306a36Sopenharmony_ci case USB_ID(0x1235, 0x8203): /* Focusrite Scarlett 6i6 2nd Gen */ 344262306a36Sopenharmony_ci case USB_ID(0x1235, 0x8204): /* Focusrite Scarlett 18i8 2nd Gen */ 344362306a36Sopenharmony_ci case USB_ID(0x1235, 0x8201): /* Focusrite Scarlett 18i20 2nd Gen */ 344462306a36Sopenharmony_ci case USB_ID(0x1235, 0x8211): /* Focusrite Scarlett Solo 3rd Gen */ 344562306a36Sopenharmony_ci case USB_ID(0x1235, 0x8210): /* Focusrite Scarlett 2i2 3rd Gen */ 344662306a36Sopenharmony_ci case USB_ID(0x1235, 0x8212): /* Focusrite Scarlett 4i4 3rd Gen */ 344762306a36Sopenharmony_ci case USB_ID(0x1235, 0x8213): /* Focusrite Scarlett 8i6 3rd Gen */ 344862306a36Sopenharmony_ci case USB_ID(0x1235, 0x8214): /* Focusrite Scarlett 18i8 3rd Gen */ 344962306a36Sopenharmony_ci case USB_ID(0x1235, 0x8215): /* Focusrite Scarlett 18i20 3rd Gen */ 345062306a36Sopenharmony_ci case USB_ID(0x1235, 0x820c): /* Focusrite Clarett+ 8Pre */ 345162306a36Sopenharmony_ci err = snd_scarlett_gen2_init(mixer); 345262306a36Sopenharmony_ci break; 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_ci case USB_ID(0x041e, 0x323b): /* Creative Sound Blaster E1 */ 345562306a36Sopenharmony_ci err = snd_soundblaster_e1_switch_create(mixer); 345662306a36Sopenharmony_ci break; 345762306a36Sopenharmony_ci case USB_ID(0x0bda, 0x4014): /* Dell WD15 dock */ 345862306a36Sopenharmony_ci err = dell_dock_mixer_create(mixer); 345962306a36Sopenharmony_ci if (err < 0) 346062306a36Sopenharmony_ci break; 346162306a36Sopenharmony_ci err = dell_dock_mixer_init(mixer); 346262306a36Sopenharmony_ci break; 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci case USB_ID(0x2a39, 0x3fd2): /* RME ADI-2 Pro */ 346562306a36Sopenharmony_ci case USB_ID(0x2a39, 0x3fd3): /* RME ADI-2 DAC */ 346662306a36Sopenharmony_ci case USB_ID(0x2a39, 0x3fd4): /* RME */ 346762306a36Sopenharmony_ci err = snd_rme_controls_create(mixer); 346862306a36Sopenharmony_ci break; 346962306a36Sopenharmony_ci 347062306a36Sopenharmony_ci case USB_ID(0x194f, 0x010c): /* Presonus Studio 1810c */ 347162306a36Sopenharmony_ci err = snd_sc1810_init_mixer(mixer); 347262306a36Sopenharmony_ci break; 347362306a36Sopenharmony_ci case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */ 347462306a36Sopenharmony_ci err = snd_bbfpro_controls_create(mixer); 347562306a36Sopenharmony_ci break; 347662306a36Sopenharmony_ci case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */ 347762306a36Sopenharmony_ci err = snd_djm_controls_create(mixer, SND_DJM_250MK2_IDX); 347862306a36Sopenharmony_ci break; 347962306a36Sopenharmony_ci case USB_ID(0x2b73, 0x0013): /* Pioneer DJ DJM-450 */ 348062306a36Sopenharmony_ci err = snd_djm_controls_create(mixer, SND_DJM_450_IDX); 348162306a36Sopenharmony_ci break; 348262306a36Sopenharmony_ci case USB_ID(0x08e4, 0x017f): /* Pioneer DJ DJM-750 */ 348362306a36Sopenharmony_ci err = snd_djm_controls_create(mixer, SND_DJM_750_IDX); 348462306a36Sopenharmony_ci break; 348562306a36Sopenharmony_ci case USB_ID(0x2b73, 0x001b): /* Pioneer DJ DJM-750MK2 */ 348662306a36Sopenharmony_ci err = snd_djm_controls_create(mixer, SND_DJM_750MK2_IDX); 348762306a36Sopenharmony_ci break; 348862306a36Sopenharmony_ci case USB_ID(0x08e4, 0x0163): /* Pioneer DJ DJM-850 */ 348962306a36Sopenharmony_ci err = snd_djm_controls_create(mixer, SND_DJM_850_IDX); 349062306a36Sopenharmony_ci break; 349162306a36Sopenharmony_ci case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */ 349262306a36Sopenharmony_ci err = snd_djm_controls_create(mixer, SND_DJM_900NXS2_IDX); 349362306a36Sopenharmony_ci break; 349462306a36Sopenharmony_ci } 349562306a36Sopenharmony_ci 349662306a36Sopenharmony_ci return err; 349762306a36Sopenharmony_ci} 349862306a36Sopenharmony_ci 349962306a36Sopenharmony_civoid snd_usb_mixer_resume_quirk(struct usb_mixer_interface *mixer) 350062306a36Sopenharmony_ci{ 350162306a36Sopenharmony_ci switch (mixer->chip->usb_id) { 350262306a36Sopenharmony_ci case USB_ID(0x0bda, 0x4014): /* Dell WD15 dock */ 350362306a36Sopenharmony_ci dell_dock_mixer_init(mixer); 350462306a36Sopenharmony_ci break; 350562306a36Sopenharmony_ci } 350662306a36Sopenharmony_ci} 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_civoid snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, 350962306a36Sopenharmony_ci int unitid) 351062306a36Sopenharmony_ci{ 351162306a36Sopenharmony_ci if (!mixer->rc_cfg) 351262306a36Sopenharmony_ci return; 351362306a36Sopenharmony_ci /* unit ids specific to Extigy/Audigy 2 NX: */ 351462306a36Sopenharmony_ci switch (unitid) { 351562306a36Sopenharmony_ci case 0: /* remote control */ 351662306a36Sopenharmony_ci mixer->rc_urb->dev = mixer->chip->dev; 351762306a36Sopenharmony_ci usb_submit_urb(mixer->rc_urb, GFP_ATOMIC); 351862306a36Sopenharmony_ci break; 351962306a36Sopenharmony_ci case 4: /* digital in jack */ 352062306a36Sopenharmony_ci case 7: /* line in jacks */ 352162306a36Sopenharmony_ci case 19: /* speaker out jacks */ 352262306a36Sopenharmony_ci case 20: /* headphones out jack */ 352362306a36Sopenharmony_ci break; 352462306a36Sopenharmony_ci /* live24ext: 4 = line-in jack */ 352562306a36Sopenharmony_ci case 3: /* hp-out jack (may actuate Mute) */ 352662306a36Sopenharmony_ci if (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || 352762306a36Sopenharmony_ci mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) 352862306a36Sopenharmony_ci snd_usb_mixer_notify_id(mixer, mixer->rc_cfg->mute_mixer_id); 352962306a36Sopenharmony_ci break; 353062306a36Sopenharmony_ci default: 353162306a36Sopenharmony_ci usb_audio_dbg(mixer->chip, "memory change in unknown unit %d\n", unitid); 353262306a36Sopenharmony_ci break; 353362306a36Sopenharmony_ci } 353462306a36Sopenharmony_ci} 353562306a36Sopenharmony_ci 353662306a36Sopenharmony_cistatic void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer, 353762306a36Sopenharmony_ci struct usb_mixer_elem_info *cval, 353862306a36Sopenharmony_ci struct snd_kcontrol *kctl) 353962306a36Sopenharmony_ci{ 354062306a36Sopenharmony_ci /* Approximation using 10 ranges based on output measurement on hw v1.2. 354162306a36Sopenharmony_ci * This seems close to the cubic mapping e.g. alsamixer uses. */ 354262306a36Sopenharmony_ci static const DECLARE_TLV_DB_RANGE(scale, 354362306a36Sopenharmony_ci 0, 1, TLV_DB_MINMAX_ITEM(-5300, -4970), 354462306a36Sopenharmony_ci 2, 5, TLV_DB_MINMAX_ITEM(-4710, -4160), 354562306a36Sopenharmony_ci 6, 7, TLV_DB_MINMAX_ITEM(-3884, -3710), 354662306a36Sopenharmony_ci 8, 14, TLV_DB_MINMAX_ITEM(-3443, -2560), 354762306a36Sopenharmony_ci 15, 16, TLV_DB_MINMAX_ITEM(-2475, -2324), 354862306a36Sopenharmony_ci 17, 19, TLV_DB_MINMAX_ITEM(-2228, -2031), 354962306a36Sopenharmony_ci 20, 26, TLV_DB_MINMAX_ITEM(-1910, -1393), 355062306a36Sopenharmony_ci 27, 31, TLV_DB_MINMAX_ITEM(-1322, -1032), 355162306a36Sopenharmony_ci 32, 40, TLV_DB_MINMAX_ITEM(-968, -490), 355262306a36Sopenharmony_ci 41, 50, TLV_DB_MINMAX_ITEM(-441, 0), 355362306a36Sopenharmony_ci ); 355462306a36Sopenharmony_ci 355562306a36Sopenharmony_ci if (cval->min == 0 && cval->max == 50) { 355662306a36Sopenharmony_ci usb_audio_info(mixer->chip, "applying DragonFly dB scale quirk (0-50 variant)\n"); 355762306a36Sopenharmony_ci kctl->tlv.p = scale; 355862306a36Sopenharmony_ci kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; 355962306a36Sopenharmony_ci kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; 356062306a36Sopenharmony_ci 356162306a36Sopenharmony_ci } else if (cval->min == 0 && cval->max <= 1000) { 356262306a36Sopenharmony_ci /* Some other clearly broken DragonFly variant. 356362306a36Sopenharmony_ci * At least a 0..53 variant (hw v1.0) exists. 356462306a36Sopenharmony_ci */ 356562306a36Sopenharmony_ci usb_audio_info(mixer->chip, "ignoring too narrow dB range on a DragonFly device"); 356662306a36Sopenharmony_ci kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; 356762306a36Sopenharmony_ci } 356862306a36Sopenharmony_ci} 356962306a36Sopenharmony_ci 357062306a36Sopenharmony_civoid snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, 357162306a36Sopenharmony_ci struct usb_mixer_elem_info *cval, int unitid, 357262306a36Sopenharmony_ci struct snd_kcontrol *kctl) 357362306a36Sopenharmony_ci{ 357462306a36Sopenharmony_ci switch (mixer->chip->usb_id) { 357562306a36Sopenharmony_ci case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */ 357662306a36Sopenharmony_ci if (unitid == 7 && cval->control == UAC_FU_VOLUME) 357762306a36Sopenharmony_ci snd_dragonfly_quirk_db_scale(mixer, cval, kctl); 357862306a36Sopenharmony_ci break; 357962306a36Sopenharmony_ci /* lowest playback value is muted on some devices */ 358062306a36Sopenharmony_ci case USB_ID(0x0d8c, 0x000c): /* C-Media */ 358162306a36Sopenharmony_ci case USB_ID(0x0d8c, 0x0014): /* C-Media */ 358262306a36Sopenharmony_ci case USB_ID(0x19f7, 0x0003): /* RODE NT-USB */ 358362306a36Sopenharmony_ci if (strstr(kctl->id.name, "Playback")) 358462306a36Sopenharmony_ci cval->min_mute = 1; 358562306a36Sopenharmony_ci break; 358662306a36Sopenharmony_ci } 358762306a36Sopenharmony_ci} 358862306a36Sopenharmony_ci 3589