11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 3c1017a4cSJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, 41da177e4SLinus Torvalds * Takashi Iwai <tiwai@suse.de> 51da177e4SLinus Torvalds * Creative Labs, Inc. 61da177e4SLinus Torvalds * Routines for control of EMU10K1 chips / mixer routines 71da177e4SLinus Torvalds * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> 81da177e4SLinus Torvalds * 99f4bd5ddSJames Courtier-Dutton * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> 109f4bd5ddSJames Courtier-Dutton * Added EMU 1010 support. 119f4bd5ddSJames Courtier-Dutton * 121da177e4SLinus Torvalds * BUGS: 131da177e4SLinus Torvalds * -- 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * TODO: 161da177e4SLinus Torvalds * -- 171da177e4SLinus Torvalds */ 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds #include <linux/time.h> 201da177e4SLinus Torvalds #include <linux/init.h> 211da177e4SLinus Torvalds #include <sound/core.h> 221da177e4SLinus Torvalds #include <sound/emu10k1.h> 23b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h> 24184c1e2cSJames Courtier-Dutton #include <sound/tlv.h> 25184c1e2cSJames Courtier-Dutton 26184c1e2cSJames Courtier-Dutton #include "p17v.h" 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #define AC97_ID_STAC9758 0x83847658 291da177e4SLinus Torvalds 300cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ 31184c1e2cSJames Courtier-Dutton 32536438f1SOswald Buddenhagen 33536438f1SOswald Buddenhagen static int add_ctls(struct snd_emu10k1 *emu, const struct snd_kcontrol_new *tpl, 34536438f1SOswald Buddenhagen const char * const *ctls, unsigned nctls) 35536438f1SOswald Buddenhagen { 36536438f1SOswald Buddenhagen struct snd_kcontrol_new kctl = *tpl; 37536438f1SOswald Buddenhagen int err; 38536438f1SOswald Buddenhagen 39536438f1SOswald Buddenhagen for (unsigned i = 0; i < nctls; i++) { 40536438f1SOswald Buddenhagen kctl.name = ctls[i]; 41536438f1SOswald Buddenhagen kctl.private_value = i; 42536438f1SOswald Buddenhagen err = snd_ctl_add(emu->card, snd_ctl_new1(&kctl, emu)); 43536438f1SOswald Buddenhagen if (err < 0) 44536438f1SOswald Buddenhagen return err; 45536438f1SOswald Buddenhagen } 46536438f1SOswald Buddenhagen return 0; 47536438f1SOswald Buddenhagen } 48536438f1SOswald Buddenhagen 49536438f1SOswald Buddenhagen 50eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 511da177e4SLinus Torvalds { 521da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 531da177e4SLinus Torvalds uinfo->count = 1; 541da177e4SLinus Torvalds return 0; 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds 57eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol, 58eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 591da177e4SLinus Torvalds { 60eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 611da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 621da177e4SLinus Torvalds 6374415a36SJames Courtier-Dutton /* Limit: emu->spdif_bits */ 6474415a36SJames Courtier-Dutton if (idx >= 3) 6574415a36SJames Courtier-Dutton return -EINVAL; 661da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 671da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 681da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 691da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 701da177e4SLinus Torvalds return 0; 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds 73eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, 74eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 751da177e4SLinus Torvalds { 761da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = 0xff; 771da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = 0xff; 781da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = 0xff; 791da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = 0xff; 801da177e4SLinus Torvalds return 0; 811da177e4SLinus Torvalds } 821da177e4SLinus Torvalds 83dc39bb3eSOswald Buddenhagen #define PAIR_PS(base, one, two, sfx) base " " one sfx, base " " two sfx 84dc39bb3eSOswald Buddenhagen #define LR_PS(base, sfx) PAIR_PS(base, "Left", "Right", sfx) 859f4bd5ddSJames Courtier-Dutton 86dc39bb3eSOswald Buddenhagen #define ADAT_PS(pfx, sfx) \ 87dc39bb3eSOswald Buddenhagen pfx "ADAT 0" sfx, pfx "ADAT 1" sfx, pfx "ADAT 2" sfx, pfx "ADAT 3" sfx, \ 88dc39bb3eSOswald Buddenhagen pfx "ADAT 4" sfx, pfx "ADAT 5" sfx, pfx "ADAT 6" sfx, pfx "ADAT 7" sfx 891c02e366SCtirad Fertr 90dc39bb3eSOswald Buddenhagen #define PAIR_REGS(base, one, two) \ 91dc39bb3eSOswald Buddenhagen base ## one ## 1, \ 92dc39bb3eSOswald Buddenhagen base ## two ## 1 931c02e366SCtirad Fertr 94dc39bb3eSOswald Buddenhagen #define LR_REGS(base) PAIR_REGS(base, _LEFT, _RIGHT) 95dc39bb3eSOswald Buddenhagen 96dc39bb3eSOswald Buddenhagen #define ADAT_REGS(base) \ 97dc39bb3eSOswald Buddenhagen base+0, base+1, base+2, base+3, base+4, base+5, base+6, base+7 981c02e366SCtirad Fertr 9913d45709SPavel Hofman /* 10013d45709SPavel Hofman * List of data sources available for each destination 10113d45709SPavel Hofman */ 102dc39bb3eSOswald Buddenhagen 103dc39bb3eSOswald Buddenhagen #define DSP_TEXTS \ 104dc39bb3eSOswald Buddenhagen "DSP 0", "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", \ 105dc39bb3eSOswald Buddenhagen "DSP 8", "DSP 9", "DSP 10", "DSP 11", "DSP 12", "DSP 13", "DSP 14", "DSP 15", \ 106dc39bb3eSOswald Buddenhagen "DSP 16", "DSP 17", "DSP 18", "DSP 19", "DSP 20", "DSP 21", "DSP 22", "DSP 23", \ 107dc39bb3eSOswald Buddenhagen "DSP 24", "DSP 25", "DSP 26", "DSP 27", "DSP 28", "DSP 29", "DSP 30", "DSP 31" 108dc39bb3eSOswald Buddenhagen 109dc39bb3eSOswald Buddenhagen #define PAIR_TEXTS(base, one, two) PAIR_PS(base, one, two, "") 110dc39bb3eSOswald Buddenhagen #define LR_TEXTS(base) LR_PS(base, "") 111dc39bb3eSOswald Buddenhagen #define ADAT_TEXTS(pfx) ADAT_PS(pfx, "") 112dc39bb3eSOswald Buddenhagen 113dc39bb3eSOswald Buddenhagen #define EMU32_SRC_REGS \ 114dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A, \ 115dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+1, \ 116dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+2, \ 117dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+3, \ 118dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, \ 119dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+5, \ 120dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+6, \ 121dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+7, \ 122dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+8, \ 123dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+9, \ 124dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0xa, \ 125dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0xb, \ 126dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0xc, \ 127dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0xd, \ 128dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0xe, \ 129dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0xf, \ 130dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B, \ 131dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+1, \ 132dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+2, \ 133dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+3, \ 134dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+4, \ 135dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+5, \ 136dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+6, \ 137dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+7, \ 138dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+8, \ 139dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+9, \ 140dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+0xa, \ 141dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+0xb, \ 142dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+0xc, \ 143dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+0xd, \ 144dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+0xe, \ 145dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+0xf 146dc39bb3eSOswald Buddenhagen 1476f3609f8SOswald Buddenhagen /* 1010 rev1 */ 1486f3609f8SOswald Buddenhagen 149dc39bb3eSOswald Buddenhagen #define EMU1010_COMMON_TEXTS \ 150dc39bb3eSOswald Buddenhagen "Silence", \ 151dc39bb3eSOswald Buddenhagen PAIR_TEXTS("Dock Mic", "A", "B"), \ 152dc39bb3eSOswald Buddenhagen LR_TEXTS("Dock ADC1"), \ 153dc39bb3eSOswald Buddenhagen LR_TEXTS("Dock ADC2"), \ 154dc39bb3eSOswald Buddenhagen LR_TEXTS("Dock ADC3"), \ 155dc39bb3eSOswald Buddenhagen LR_TEXTS("0202 ADC"), \ 156dc39bb3eSOswald Buddenhagen LR_TEXTS("1010 SPDIF"), \ 157dc39bb3eSOswald Buddenhagen ADAT_TEXTS("1010 ") 158dc39bb3eSOswald Buddenhagen 159dc39bb3eSOswald Buddenhagen static const char * const emu1010_src_texts[] = { 160dc39bb3eSOswald Buddenhagen EMU1010_COMMON_TEXTS, 161dc39bb3eSOswald Buddenhagen DSP_TEXTS, 1629f4bd5ddSJames Courtier-Dutton }; 1639f4bd5ddSJames Courtier-Dutton 164dc39bb3eSOswald Buddenhagen static const unsigned short emu1010_src_regs[] = { 165dc39bb3eSOswald Buddenhagen EMU_SRC_SILENCE, 166dc39bb3eSOswald Buddenhagen PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B), 167dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC1), 168dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC2), 169dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC3), 170dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_HAMOA_ADC), 171dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_HANA_SPDIF), 172dc39bb3eSOswald Buddenhagen ADAT_REGS(EMU_SRC_HANA_ADAT), 173dc39bb3eSOswald Buddenhagen EMU32_SRC_REGS, 174dc39bb3eSOswald Buddenhagen }; 175dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_src_regs) == ARRAY_SIZE(emu1010_src_texts)); 176dc39bb3eSOswald Buddenhagen 177f69d705dSOswald Buddenhagen /* 1010 rev2 */ 178f69d705dSOswald Buddenhagen 179f69d705dSOswald Buddenhagen #define EMU1010b_COMMON_TEXTS \ 180f69d705dSOswald Buddenhagen "Silence", \ 181f69d705dSOswald Buddenhagen PAIR_TEXTS("Dock Mic", "A", "B"), \ 182f69d705dSOswald Buddenhagen LR_TEXTS("Dock ADC1"), \ 183f69d705dSOswald Buddenhagen LR_TEXTS("Dock ADC2"), \ 184f69d705dSOswald Buddenhagen LR_TEXTS("0202 ADC"), \ 185f69d705dSOswald Buddenhagen LR_TEXTS("Dock SPDIF"), \ 186f69d705dSOswald Buddenhagen LR_TEXTS("1010 SPDIF"), \ 187f69d705dSOswald Buddenhagen ADAT_TEXTS("Dock "), \ 188f69d705dSOswald Buddenhagen ADAT_TEXTS("1010 ") 189f69d705dSOswald Buddenhagen 190f69d705dSOswald Buddenhagen static const char * const emu1010b_src_texts[] = { 191f69d705dSOswald Buddenhagen EMU1010b_COMMON_TEXTS, 192f69d705dSOswald Buddenhagen DSP_TEXTS, 193f69d705dSOswald Buddenhagen }; 194f69d705dSOswald Buddenhagen 195f69d705dSOswald Buddenhagen static const unsigned short emu1010b_src_regs[] = { 196f69d705dSOswald Buddenhagen EMU_SRC_SILENCE, 197f69d705dSOswald Buddenhagen PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B), 198f69d705dSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC1), 199f69d705dSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC2), 200f69d705dSOswald Buddenhagen LR_REGS(EMU_SRC_HAMOA_ADC), 201f69d705dSOswald Buddenhagen LR_REGS(EMU_SRC_MDOCK_SPDIF), 202f69d705dSOswald Buddenhagen LR_REGS(EMU_SRC_HANA_SPDIF), 203f69d705dSOswald Buddenhagen ADAT_REGS(EMU_SRC_MDOCK_ADAT), 204f69d705dSOswald Buddenhagen ADAT_REGS(EMU_SRC_HANA_ADAT), 205f69d705dSOswald Buddenhagen EMU32_SRC_REGS, 206f69d705dSOswald Buddenhagen }; 207f69d705dSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010b_src_regs) == ARRAY_SIZE(emu1010b_src_texts)); 208f69d705dSOswald Buddenhagen 2091c02e366SCtirad Fertr /* 1616(m) cardbus */ 210dc39bb3eSOswald Buddenhagen 211dc39bb3eSOswald Buddenhagen #define EMU1616_COMMON_TEXTS \ 212dc39bb3eSOswald Buddenhagen "Silence", \ 213dc39bb3eSOswald Buddenhagen PAIR_TEXTS("Mic", "A", "B"), \ 214dc39bb3eSOswald Buddenhagen LR_TEXTS("ADC1"), \ 215dc39bb3eSOswald Buddenhagen LR_TEXTS("ADC2"), \ 216dc39bb3eSOswald Buddenhagen LR_TEXTS("SPDIF"), \ 217dc39bb3eSOswald Buddenhagen ADAT_TEXTS("") 218dc39bb3eSOswald Buddenhagen 219dc39bb3eSOswald Buddenhagen static const char * const emu1616_src_texts[] = { 220dc39bb3eSOswald Buddenhagen EMU1616_COMMON_TEXTS, 221dc39bb3eSOswald Buddenhagen DSP_TEXTS, 222dc39bb3eSOswald Buddenhagen }; 223dc39bb3eSOswald Buddenhagen 2249b00a1e9SOswald Buddenhagen static const unsigned short emu1616_src_regs[] = { 2251c02e366SCtirad Fertr EMU_SRC_SILENCE, 226dc39bb3eSOswald Buddenhagen PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B), 227dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC1), 228dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC2), 229dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_MDOCK_SPDIF), 230dc39bb3eSOswald Buddenhagen ADAT_REGS(EMU_SRC_MDOCK_ADAT), 231dc39bb3eSOswald Buddenhagen EMU32_SRC_REGS, 2321c02e366SCtirad Fertr }; 233dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_src_regs) == ARRAY_SIZE(emu1616_src_texts)); 2341c02e366SCtirad Fertr 2356f3609f8SOswald Buddenhagen /* 0404 rev1 & rev2 */ 2366f3609f8SOswald Buddenhagen 2376f3609f8SOswald Buddenhagen #define EMU0404_COMMON_TEXTS \ 2386f3609f8SOswald Buddenhagen "Silence", \ 2396f3609f8SOswald Buddenhagen LR_TEXTS("ADC"), \ 2406f3609f8SOswald Buddenhagen LR_TEXTS("SPDIF") 2416f3609f8SOswald Buddenhagen 2426f3609f8SOswald Buddenhagen static const char * const emu0404_src_texts[] = { 2436f3609f8SOswald Buddenhagen EMU0404_COMMON_TEXTS, 2446f3609f8SOswald Buddenhagen DSP_TEXTS, 2456f3609f8SOswald Buddenhagen }; 2466f3609f8SOswald Buddenhagen 2476f3609f8SOswald Buddenhagen static const unsigned short emu0404_src_regs[] = { 2486f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 2496f3609f8SOswald Buddenhagen LR_REGS(EMU_SRC_HAMOA_ADC), 2506f3609f8SOswald Buddenhagen LR_REGS(EMU_SRC_HANA_SPDIF), 2516f3609f8SOswald Buddenhagen EMU32_SRC_REGS, 2526f3609f8SOswald Buddenhagen }; 2536f3609f8SOswald Buddenhagen static_assert(ARRAY_SIZE(emu0404_src_regs) == ARRAY_SIZE(emu0404_src_texts)); 2546f3609f8SOswald Buddenhagen 25513d45709SPavel Hofman /* 25613d45709SPavel Hofman * Data destinations - physical EMU outputs. 25713d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 25813d45709SPavel Hofman */ 259536438f1SOswald Buddenhagen 260536438f1SOswald Buddenhagen #define LR_CTLS(base) LR_PS(base, " Playback Enum") 261536438f1SOswald Buddenhagen #define ADAT_CTLS(pfx) ADAT_PS(pfx, " Playback Enum") 262536438f1SOswald Buddenhagen 2636f3609f8SOswald Buddenhagen /* 1010 rev1 */ 2646f3609f8SOswald Buddenhagen 265536438f1SOswald Buddenhagen static const char * const emu1010_output_texts[] = { 266536438f1SOswald Buddenhagen LR_CTLS("Dock DAC1"), 267536438f1SOswald Buddenhagen LR_CTLS("Dock DAC2"), 268536438f1SOswald Buddenhagen LR_CTLS("Dock DAC3"), 269536438f1SOswald Buddenhagen LR_CTLS("Dock DAC4"), 270536438f1SOswald Buddenhagen LR_CTLS("Dock Phones"), 271536438f1SOswald Buddenhagen LR_CTLS("Dock SPDIF"), 272536438f1SOswald Buddenhagen LR_CTLS("0202 DAC"), 273536438f1SOswald Buddenhagen LR_CTLS("1010 SPDIF"), 274536438f1SOswald Buddenhagen ADAT_CTLS("1010 "), 2759f4bd5ddSJames Courtier-Dutton }; 276216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_texts) <= NUM_OUTPUT_DESTS); 2779f4bd5ddSJames Courtier-Dutton 278536438f1SOswald Buddenhagen static const unsigned short emu1010_output_dst[] = { 279536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC1), 280536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC2), 281536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC3), 282536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC4), 283536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_PHONES), 284536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_SPDIF), 285536438f1SOswald Buddenhagen LR_REGS(EMU_DST_HAMOA_DAC), 286536438f1SOswald Buddenhagen LR_REGS(EMU_DST_HANA_SPDIF), 287536438f1SOswald Buddenhagen ADAT_REGS(EMU_DST_HANA_ADAT), 2881c02e366SCtirad Fertr }; 289536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dst) == ARRAY_SIZE(emu1010_output_texts)); 290536438f1SOswald Buddenhagen 2911fc710f0SOswald Buddenhagen static const unsigned short emu1010_output_dflt[] = { 2921fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 2931fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, 2941fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, 2951fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, 2961fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 2971fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 2981fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 2991fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 3001fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, 3011fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, 3021fc710f0SOswald Buddenhagen }; 3031fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dflt) == ARRAY_SIZE(emu1010_output_dst)); 3041fc710f0SOswald Buddenhagen 305f69d705dSOswald Buddenhagen /* 1010 rev2 */ 306f69d705dSOswald Buddenhagen 307f69d705dSOswald Buddenhagen static const char * const snd_emu1010b_output_texts[] = { 308f69d705dSOswald Buddenhagen LR_CTLS("Dock DAC1"), 309f69d705dSOswald Buddenhagen LR_CTLS("Dock DAC2"), 310f69d705dSOswald Buddenhagen LR_CTLS("Dock DAC3"), 311f69d705dSOswald Buddenhagen LR_CTLS("Dock SPDIF"), 312f69d705dSOswald Buddenhagen ADAT_CTLS("Dock "), 313f69d705dSOswald Buddenhagen LR_CTLS("0202 DAC"), 314f69d705dSOswald Buddenhagen LR_CTLS("1010 SPDIF"), 315f69d705dSOswald Buddenhagen ADAT_CTLS("1010 "), 316f69d705dSOswald Buddenhagen }; 317216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(snd_emu1010b_output_texts) <= NUM_OUTPUT_DESTS); 318f69d705dSOswald Buddenhagen 319f69d705dSOswald Buddenhagen static const unsigned short emu1010b_output_dst[] = { 320f69d705dSOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC1), 321f69d705dSOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC2), 322f69d705dSOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC3), 323f69d705dSOswald Buddenhagen LR_REGS(EMU_DST_MDOCK_SPDIF), 324f69d705dSOswald Buddenhagen ADAT_REGS(EMU_DST_MDOCK_ADAT), 325f69d705dSOswald Buddenhagen LR_REGS(EMU_DST_HAMOA_DAC), 326f69d705dSOswald Buddenhagen LR_REGS(EMU_DST_HANA_SPDIF), 327f69d705dSOswald Buddenhagen ADAT_REGS(EMU_DST_HANA_ADAT), 328f69d705dSOswald Buddenhagen }; 329f69d705dSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010b_output_dst) == ARRAY_SIZE(snd_emu1010b_output_texts)); 330f69d705dSOswald Buddenhagen 331f69d705dSOswald Buddenhagen static const unsigned short emu1010b_output_dflt[] = { 332f69d705dSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 333f69d705dSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, 334f69d705dSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, 335f69d705dSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 336f69d705dSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, 337f69d705dSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, 338f69d705dSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 339f69d705dSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 340f69d705dSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, 341f69d705dSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, 342f69d705dSOswald Buddenhagen }; 343f69d705dSOswald Buddenhagen 344536438f1SOswald Buddenhagen /* 1616(m) cardbus */ 345536438f1SOswald Buddenhagen 346536438f1SOswald Buddenhagen static const char * const snd_emu1616_output_texts[] = { 347536438f1SOswald Buddenhagen LR_CTLS("Dock DAC1"), 348536438f1SOswald Buddenhagen LR_CTLS("Dock DAC2"), 349536438f1SOswald Buddenhagen LR_CTLS("Dock DAC3"), 350536438f1SOswald Buddenhagen LR_CTLS("Dock SPDIF"), 351536438f1SOswald Buddenhagen ADAT_CTLS("Dock "), 352536438f1SOswald Buddenhagen LR_CTLS("Mana DAC"), 353536438f1SOswald Buddenhagen }; 354216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(snd_emu1616_output_texts) <= NUM_OUTPUT_DESTS); 355536438f1SOswald Buddenhagen 356536438f1SOswald Buddenhagen static const unsigned short emu1616_output_dst[] = { 357536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC1), 358536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC2), 359536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC3), 360536438f1SOswald Buddenhagen LR_REGS(EMU_DST_MDOCK_SPDIF), 361536438f1SOswald Buddenhagen ADAT_REGS(EMU_DST_MDOCK_ADAT), 362536438f1SOswald Buddenhagen EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT, 363536438f1SOswald Buddenhagen }; 364536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dst) == ARRAY_SIZE(snd_emu1616_output_texts)); 3651c02e366SCtirad Fertr 3661fc710f0SOswald Buddenhagen static const unsigned short emu1616_output_dflt[] = { 3671fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 3681fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, 3691fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, 3701fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 3711fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, 3721fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, 3731fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 3741fc710f0SOswald Buddenhagen }; 3751fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dflt) == ARRAY_SIZE(emu1616_output_dst)); 3761fc710f0SOswald Buddenhagen 3776f3609f8SOswald Buddenhagen /* 0404 rev1 & rev2 */ 3786f3609f8SOswald Buddenhagen 3796f3609f8SOswald Buddenhagen static const char * const snd_emu0404_output_texts[] = { 3806f3609f8SOswald Buddenhagen LR_CTLS("DAC"), 3816f3609f8SOswald Buddenhagen LR_CTLS("SPDIF"), 3826f3609f8SOswald Buddenhagen }; 383216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(snd_emu0404_output_texts) <= NUM_OUTPUT_DESTS); 3846f3609f8SOswald Buddenhagen 3856f3609f8SOswald Buddenhagen static const unsigned short emu0404_output_dst[] = { 3866f3609f8SOswald Buddenhagen LR_REGS(EMU_DST_HAMOA_DAC), 3876f3609f8SOswald Buddenhagen LR_REGS(EMU_DST_HANA_SPDIF), 3886f3609f8SOswald Buddenhagen }; 3896f3609f8SOswald Buddenhagen static_assert(ARRAY_SIZE(emu0404_output_dst) == ARRAY_SIZE(snd_emu0404_output_texts)); 3906f3609f8SOswald Buddenhagen 3916f3609f8SOswald Buddenhagen static const unsigned short emu0404_output_dflt[] = { 3926f3609f8SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 3936f3609f8SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 3946f3609f8SOswald Buddenhagen }; 3956f3609f8SOswald Buddenhagen static_assert(ARRAY_SIZE(emu0404_output_dflt) == ARRAY_SIZE(emu0404_output_dst)); 3966f3609f8SOswald Buddenhagen 39713d45709SPavel Hofman /* 398a869057cSOswald Buddenhagen * Data destinations - FPGA outputs going to Alice2 (Audigy) for 39913d45709SPavel Hofman * capture (EMU32 + I2S links) 40013d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 40113d45709SPavel Hofman */ 402536438f1SOswald Buddenhagen 403536438f1SOswald Buddenhagen static const char * const emu1010_input_texts[] = { 404536438f1SOswald Buddenhagen "DSP 0 Capture Enum", 405536438f1SOswald Buddenhagen "DSP 1 Capture Enum", 406536438f1SOswald Buddenhagen "DSP 2 Capture Enum", 407536438f1SOswald Buddenhagen "DSP 3 Capture Enum", 408536438f1SOswald Buddenhagen "DSP 4 Capture Enum", 409536438f1SOswald Buddenhagen "DSP 5 Capture Enum", 410536438f1SOswald Buddenhagen "DSP 6 Capture Enum", 411536438f1SOswald Buddenhagen "DSP 7 Capture Enum", 412536438f1SOswald Buddenhagen "DSP 8 Capture Enum", 413536438f1SOswald Buddenhagen "DSP 9 Capture Enum", 414536438f1SOswald Buddenhagen "DSP A Capture Enum", 415536438f1SOswald Buddenhagen "DSP B Capture Enum", 416536438f1SOswald Buddenhagen "DSP C Capture Enum", 417536438f1SOswald Buddenhagen "DSP D Capture Enum", 418536438f1SOswald Buddenhagen "DSP E Capture Enum", 419536438f1SOswald Buddenhagen "DSP F Capture Enum", 420536438f1SOswald Buddenhagen /* These exist only on rev1 EMU1010 cards. */ 421536438f1SOswald Buddenhagen "DSP 10 Capture Enum", 422536438f1SOswald Buddenhagen "DSP 11 Capture Enum", 423536438f1SOswald Buddenhagen "DSP 12 Capture Enum", 424536438f1SOswald Buddenhagen "DSP 13 Capture Enum", 425536438f1SOswald Buddenhagen "DSP 14 Capture Enum", 426536438f1SOswald Buddenhagen "DSP 15 Capture Enum", 427536438f1SOswald Buddenhagen }; 428216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_texts) <= NUM_INPUT_DESTS); 429536438f1SOswald Buddenhagen 4309b00a1e9SOswald Buddenhagen static const unsigned short emu1010_input_dst[] = { 4319f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_0, 4329f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_1, 4339f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_2, 4349f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_3, 4359f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_4, 4369f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_5, 4379f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_6, 4389f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_7, 4399f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_8, 4409f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_9, 4419f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_A, 4429f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_B, 4439f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_C, 4449f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_D, 4459f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_E, 4469f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_F, 447a869057cSOswald Buddenhagen /* These exist only on rev1 EMU1010 cards. */ 4489f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_LEFT, 4499f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_RIGHT, 4509f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_LEFT, 4519f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_RIGHT, 4529f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_LEFT, 4539f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_RIGHT, 4549f4bd5ddSJames Courtier-Dutton }; 455536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts)); 4569f4bd5ddSJames Courtier-Dutton 4571fc710f0SOswald Buddenhagen static const unsigned short emu1010_input_dflt[] = { 4581fc710f0SOswald Buddenhagen EMU_SRC_DOCK_MIC_A1, 4591fc710f0SOswald Buddenhagen EMU_SRC_DOCK_MIC_B1, 4601fc710f0SOswald Buddenhagen EMU_SRC_HAMOA_ADC_LEFT1, 4611fc710f0SOswald Buddenhagen EMU_SRC_HAMOA_ADC_RIGHT1, 4621fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC1_LEFT1, 4631fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC1_RIGHT1, 4641fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC2_LEFT1, 4651fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC2_RIGHT1, 4661fc710f0SOswald Buddenhagen /* Pavel Hofman - setting defaults for all capture channels. 4671fc710f0SOswald Buddenhagen * Defaults only, users will set their own values anyways, let's 4681fc710f0SOswald Buddenhagen * just copy/paste. */ 4691fc710f0SOswald Buddenhagen EMU_SRC_DOCK_MIC_A1, 4701fc710f0SOswald Buddenhagen EMU_SRC_DOCK_MIC_B1, 4711fc710f0SOswald Buddenhagen EMU_SRC_HAMOA_ADC_LEFT1, 4721fc710f0SOswald Buddenhagen EMU_SRC_HAMOA_ADC_RIGHT1, 4731fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC1_LEFT1, 4741fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC1_RIGHT1, 4751fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC2_LEFT1, 4761fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC2_RIGHT1, 4771fc710f0SOswald Buddenhagen 4781fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC1_LEFT1, 4791fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC1_RIGHT1, 4801fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC2_LEFT1, 4811fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC2_RIGHT1, 4821fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC3_LEFT1, 4831fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC3_RIGHT1, 4841fc710f0SOswald Buddenhagen }; 4851fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dflt) == ARRAY_SIZE(emu1010_input_dst)); 4861fc710f0SOswald Buddenhagen 4876f3609f8SOswald Buddenhagen static const unsigned short emu0404_input_dflt[] = { 4886f3609f8SOswald Buddenhagen EMU_SRC_HAMOA_ADC_LEFT1, 4896f3609f8SOswald Buddenhagen EMU_SRC_HAMOA_ADC_RIGHT1, 4906f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 4916f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 4926f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 4936f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 4946f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 4956f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 4966f3609f8SOswald Buddenhagen EMU_SRC_HANA_SPDIF_LEFT1, 4976f3609f8SOswald Buddenhagen EMU_SRC_HANA_SPDIF_RIGHT1, 4986f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 4996f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 5006f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 5016f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 5026f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 5036f3609f8SOswald Buddenhagen EMU_SRC_SILENCE, 5046f3609f8SOswald Buddenhagen }; 5056f3609f8SOswald Buddenhagen 506511cbe8fSOswald Buddenhagen struct snd_emu1010_routing_info { 507511cbe8fSOswald Buddenhagen const char * const *src_texts; 50897f1582eSOswald Buddenhagen const char * const *out_texts; 509511cbe8fSOswald Buddenhagen const unsigned short *src_regs; 510511cbe8fSOswald Buddenhagen const unsigned short *out_regs; 511511cbe8fSOswald Buddenhagen const unsigned short *in_regs; 5121fc710f0SOswald Buddenhagen const unsigned short *out_dflts; 5131fc710f0SOswald Buddenhagen const unsigned short *in_dflts; 514511cbe8fSOswald Buddenhagen unsigned n_srcs; 515511cbe8fSOswald Buddenhagen unsigned n_outs; 516511cbe8fSOswald Buddenhagen unsigned n_ins; 517511cbe8fSOswald Buddenhagen }; 518511cbe8fSOswald Buddenhagen 519816967d5STom Rix static const struct snd_emu1010_routing_info emu1010_routing_info[] = { 520511cbe8fSOswald Buddenhagen { 5216f3609f8SOswald Buddenhagen /* rev1 1010 */ 522511cbe8fSOswald Buddenhagen .src_regs = emu1010_src_regs, 523511cbe8fSOswald Buddenhagen .src_texts = emu1010_src_texts, 524511cbe8fSOswald Buddenhagen .n_srcs = ARRAY_SIZE(emu1010_src_texts), 525511cbe8fSOswald Buddenhagen 5261fc710f0SOswald Buddenhagen .out_dflts = emu1010_output_dflt, 527511cbe8fSOswald Buddenhagen .out_regs = emu1010_output_dst, 52897f1582eSOswald Buddenhagen .out_texts = emu1010_output_texts, 529511cbe8fSOswald Buddenhagen .n_outs = ARRAY_SIZE(emu1010_output_dst), 530511cbe8fSOswald Buddenhagen 5311fc710f0SOswald Buddenhagen .in_dflts = emu1010_input_dflt, 532511cbe8fSOswald Buddenhagen .in_regs = emu1010_input_dst, 533511cbe8fSOswald Buddenhagen .n_ins = ARRAY_SIZE(emu1010_input_dst), 534511cbe8fSOswald Buddenhagen }, 535511cbe8fSOswald Buddenhagen { 536f69d705dSOswald Buddenhagen /* rev2 1010 */ 537f69d705dSOswald Buddenhagen .src_regs = emu1010b_src_regs, 538f69d705dSOswald Buddenhagen .src_texts = emu1010b_src_texts, 539f69d705dSOswald Buddenhagen .n_srcs = ARRAY_SIZE(emu1010b_src_texts), 540f69d705dSOswald Buddenhagen 541f69d705dSOswald Buddenhagen .out_dflts = emu1010b_output_dflt, 542f69d705dSOswald Buddenhagen .out_regs = emu1010b_output_dst, 543f69d705dSOswald Buddenhagen .out_texts = snd_emu1010b_output_texts, 544f69d705dSOswald Buddenhagen .n_outs = ARRAY_SIZE(emu1010b_output_dst), 545f69d705dSOswald Buddenhagen 546f69d705dSOswald Buddenhagen .in_dflts = emu1010_input_dflt, 547f69d705dSOswald Buddenhagen .in_regs = emu1010_input_dst, 548f69d705dSOswald Buddenhagen .n_ins = ARRAY_SIZE(emu1010_input_dst) - 6, 549f69d705dSOswald Buddenhagen }, 550f69d705dSOswald Buddenhagen { 551511cbe8fSOswald Buddenhagen /* 1616(m) cardbus */ 552511cbe8fSOswald Buddenhagen .src_regs = emu1616_src_regs, 553511cbe8fSOswald Buddenhagen .src_texts = emu1616_src_texts, 554511cbe8fSOswald Buddenhagen .n_srcs = ARRAY_SIZE(emu1616_src_texts), 555511cbe8fSOswald Buddenhagen 5561fc710f0SOswald Buddenhagen .out_dflts = emu1616_output_dflt, 557511cbe8fSOswald Buddenhagen .out_regs = emu1616_output_dst, 55897f1582eSOswald Buddenhagen .out_texts = snd_emu1616_output_texts, 559511cbe8fSOswald Buddenhagen .n_outs = ARRAY_SIZE(emu1616_output_dst), 560511cbe8fSOswald Buddenhagen 5611fc710f0SOswald Buddenhagen .in_dflts = emu1010_input_dflt, 562511cbe8fSOswald Buddenhagen .in_regs = emu1010_input_dst, 563511cbe8fSOswald Buddenhagen .n_ins = ARRAY_SIZE(emu1010_input_dst) - 6, 564511cbe8fSOswald Buddenhagen }, 5656f3609f8SOswald Buddenhagen { 5666f3609f8SOswald Buddenhagen /* 0404 */ 5676f3609f8SOswald Buddenhagen .src_regs = emu0404_src_regs, 5686f3609f8SOswald Buddenhagen .src_texts = emu0404_src_texts, 5696f3609f8SOswald Buddenhagen .n_srcs = ARRAY_SIZE(emu0404_src_texts), 5706f3609f8SOswald Buddenhagen 5716f3609f8SOswald Buddenhagen .out_dflts = emu0404_output_dflt, 5726f3609f8SOswald Buddenhagen .out_regs = emu0404_output_dst, 5736f3609f8SOswald Buddenhagen .out_texts = snd_emu0404_output_texts, 5746f3609f8SOswald Buddenhagen .n_outs = ARRAY_SIZE(emu0404_output_dflt), 5756f3609f8SOswald Buddenhagen 5766f3609f8SOswald Buddenhagen .in_dflts = emu0404_input_dflt, 5776f3609f8SOswald Buddenhagen .in_regs = emu1010_input_dst, 5786f3609f8SOswald Buddenhagen .n_ins = ARRAY_SIZE(emu1010_input_dst) - 6, 5796f3609f8SOswald Buddenhagen }, 580511cbe8fSOswald Buddenhagen }; 581511cbe8fSOswald Buddenhagen 582511cbe8fSOswald Buddenhagen static unsigned emu1010_idx(struct snd_emu10k1 *emu) 583511cbe8fSOswald Buddenhagen { 5846f3609f8SOswald Buddenhagen return emu->card_capabilities->emu_model - 1; 585511cbe8fSOswald Buddenhagen } 586511cbe8fSOswald Buddenhagen 587511cbe8fSOswald Buddenhagen static void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu, 588511cbe8fSOswald Buddenhagen int channel, int src) 589511cbe8fSOswald Buddenhagen { 590511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 591511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 592511cbe8fSOswald Buddenhagen 593511cbe8fSOswald Buddenhagen snd_emu1010_fpga_link_dst_src_write(emu, 594511cbe8fSOswald Buddenhagen emu_ri->out_regs[channel], emu_ri->src_regs[src]); 595511cbe8fSOswald Buddenhagen } 596511cbe8fSOswald Buddenhagen 597511cbe8fSOswald Buddenhagen static void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu, 598511cbe8fSOswald Buddenhagen int channel, int src) 599511cbe8fSOswald Buddenhagen { 600511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 601511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 602511cbe8fSOswald Buddenhagen 603511cbe8fSOswald Buddenhagen snd_emu1010_fpga_link_dst_src_write(emu, 604511cbe8fSOswald Buddenhagen emu_ri->in_regs[channel], emu_ri->src_regs[src]); 605511cbe8fSOswald Buddenhagen } 606511cbe8fSOswald Buddenhagen 6071fc710f0SOswald Buddenhagen static void snd_emu1010_apply_sources(struct snd_emu10k1 *emu) 6081fc710f0SOswald Buddenhagen { 6091fc710f0SOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 6101fc710f0SOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 6111fc710f0SOswald Buddenhagen 6121fc710f0SOswald Buddenhagen for (unsigned i = 0; i < emu_ri->n_outs; i++) 6131fc710f0SOswald Buddenhagen snd_emu1010_output_source_apply( 6141fc710f0SOswald Buddenhagen emu, i, emu->emu1010.output_source[i]); 6151fc710f0SOswald Buddenhagen for (unsigned i = 0; i < emu_ri->n_ins; i++) 6161fc710f0SOswald Buddenhagen snd_emu1010_input_source_apply( 6171fc710f0SOswald Buddenhagen emu, i, emu->emu1010.input_source[i]); 6181fc710f0SOswald Buddenhagen } 6191fc710f0SOswald Buddenhagen 6201fc710f0SOswald Buddenhagen static u8 emu1010_map_source(const struct snd_emu1010_routing_info *emu_ri, 6211fc710f0SOswald Buddenhagen unsigned val) 6221fc710f0SOswald Buddenhagen { 6231fc710f0SOswald Buddenhagen for (unsigned i = 0; i < emu_ri->n_srcs; i++) 6241fc710f0SOswald Buddenhagen if (val == emu_ri->src_regs[i]) 6251fc710f0SOswald Buddenhagen return i; 6261fc710f0SOswald Buddenhagen return 0; 6271fc710f0SOswald Buddenhagen } 6281fc710f0SOswald Buddenhagen 6291c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, 6301c02e366SCtirad Fertr struct snd_ctl_elem_info *uinfo) 6319f4bd5ddSJames Courtier-Dutton { 6321c02e366SCtirad Fertr struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 633511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 634511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 6351c02e366SCtirad Fertr 636511cbe8fSOswald Buddenhagen return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts); 6379f4bd5ddSJames Courtier-Dutton } 6389f4bd5ddSJames Courtier-Dutton 6399f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, 6409f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 6419f4bd5ddSJames Courtier-Dutton { 6429f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 643511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 644511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 645511cbe8fSOswald Buddenhagen unsigned channel = kcontrol->private_value; 6469f4bd5ddSJames Courtier-Dutton 647511cbe8fSOswald Buddenhagen if (channel >= emu_ri->n_outs) 64874415a36SJames Courtier-Dutton return -EINVAL; 6499f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; 6509f4bd5ddSJames Courtier-Dutton return 0; 6519f4bd5ddSJames Courtier-Dutton } 6529f4bd5ddSJames Courtier-Dutton 6539f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, 6549f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 6559f4bd5ddSJames Courtier-Dutton { 6569f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 657511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 658511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 659511cbe8fSOswald Buddenhagen unsigned val = ucontrol->value.enumerated.item[0]; 660511cbe8fSOswald Buddenhagen unsigned channel = kcontrol->private_value; 661511cbe8fSOswald Buddenhagen int change; 6629f4bd5ddSJames Courtier-Dutton 663511cbe8fSOswald Buddenhagen if (val >= emu_ri->n_srcs) 664aa299d01STakashi Iwai return -EINVAL; 665511cbe8fSOswald Buddenhagen if (channel >= emu_ri->n_outs) 66674415a36SJames Courtier-Dutton return -EINVAL; 667511cbe8fSOswald Buddenhagen change = (emu->emu1010.output_source[channel] != val); 668511cbe8fSOswald Buddenhagen if (change) { 669aa299d01STakashi Iwai emu->emu1010.output_source[channel] = val; 670511cbe8fSOswald Buddenhagen snd_emu1010_output_source_apply(emu, channel, val); 671511cbe8fSOswald Buddenhagen } 672511cbe8fSOswald Buddenhagen return change; 6739f4bd5ddSJames Courtier-Dutton } 6749f4bd5ddSJames Courtier-Dutton 675536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_output_source_ctl = { 676536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 677536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 678536438f1SOswald Buddenhagen .info = snd_emu1010_input_output_source_info, 679536438f1SOswald Buddenhagen .get = snd_emu1010_output_source_get, 680536438f1SOswald Buddenhagen .put = snd_emu1010_output_source_put 681536438f1SOswald Buddenhagen }; 682536438f1SOswald Buddenhagen 6839f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, 6849f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 6859f4bd5ddSJames Courtier-Dutton { 6869f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 687511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 688511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 689511cbe8fSOswald Buddenhagen unsigned channel = kcontrol->private_value; 6909f4bd5ddSJames Courtier-Dutton 691511cbe8fSOswald Buddenhagen if (channel >= emu_ri->n_ins) 69274415a36SJames Courtier-Dutton return -EINVAL; 6939f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; 6949f4bd5ddSJames Courtier-Dutton return 0; 6959f4bd5ddSJames Courtier-Dutton } 6969f4bd5ddSJames Courtier-Dutton 6979f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, 6989f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 6999f4bd5ddSJames Courtier-Dutton { 7009f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 701511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 702511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 703511cbe8fSOswald Buddenhagen unsigned val = ucontrol->value.enumerated.item[0]; 704511cbe8fSOswald Buddenhagen unsigned channel = kcontrol->private_value; 705511cbe8fSOswald Buddenhagen int change; 7069f4bd5ddSJames Courtier-Dutton 707511cbe8fSOswald Buddenhagen if (val >= emu_ri->n_srcs) 708aa299d01STakashi Iwai return -EINVAL; 709511cbe8fSOswald Buddenhagen if (channel >= emu_ri->n_ins) 71074415a36SJames Courtier-Dutton return -EINVAL; 711511cbe8fSOswald Buddenhagen change = (emu->emu1010.input_source[channel] != val); 712511cbe8fSOswald Buddenhagen if (change) { 713aa299d01STakashi Iwai emu->emu1010.input_source[channel] = val; 714511cbe8fSOswald Buddenhagen snd_emu1010_input_source_apply(emu, channel, val); 715511cbe8fSOswald Buddenhagen } 716511cbe8fSOswald Buddenhagen return change; 7179f4bd5ddSJames Courtier-Dutton } 7189f4bd5ddSJames Courtier-Dutton 719536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_input_source_ctl = { 720536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 721536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 722536438f1SOswald Buddenhagen .info = snd_emu1010_input_output_source_info, 723536438f1SOswald Buddenhagen .get = snd_emu1010_input_source_get, 724536438f1SOswald Buddenhagen .put = snd_emu1010_input_source_put 7259f4bd5ddSJames Courtier-Dutton }; 7269f4bd5ddSJames Courtier-Dutton 72797f1582eSOswald Buddenhagen static int add_emu1010_source_mixers(struct snd_emu10k1 *emu) 72897f1582eSOswald Buddenhagen { 72997f1582eSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 73097f1582eSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 73197f1582eSOswald Buddenhagen int err; 73297f1582eSOswald Buddenhagen 73397f1582eSOswald Buddenhagen err = add_ctls(emu, &emu1010_output_source_ctl, 73497f1582eSOswald Buddenhagen emu_ri->out_texts, emu_ri->n_outs); 73597f1582eSOswald Buddenhagen if (err < 0) 73697f1582eSOswald Buddenhagen return err; 73797f1582eSOswald Buddenhagen err = add_ctls(emu, &emu1010_input_source_ctl, 73897f1582eSOswald Buddenhagen emu1010_input_texts, emu_ri->n_ins); 73997f1582eSOswald Buddenhagen return err; 74097f1582eSOswald Buddenhagen } 74197f1582eSOswald Buddenhagen 7421c02e366SCtirad Fertr 743536438f1SOswald Buddenhagen static const char * const snd_emu1010_adc_pads[] = { 744f69d705dSOswald Buddenhagen "ADC1 14dB PAD 0202 Capture Switch", 745536438f1SOswald Buddenhagen "ADC1 14dB PAD Audio Dock Capture Switch", 746536438f1SOswald Buddenhagen "ADC2 14dB PAD Audio Dock Capture Switch", 747536438f1SOswald Buddenhagen "ADC3 14dB PAD Audio Dock Capture Switch", 7481c02e366SCtirad Fertr }; 7491c02e366SCtirad Fertr 750536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_adc_pad_regs[] = { 751f69d705dSOswald Buddenhagen EMU_HANA_0202_ADC_PAD1, 752536438f1SOswald Buddenhagen EMU_HANA_DOCK_ADC_PAD1, 753536438f1SOswald Buddenhagen EMU_HANA_DOCK_ADC_PAD2, 754536438f1SOswald Buddenhagen EMU_HANA_DOCK_ADC_PAD3, 7559148cc50SJames Courtier-Dutton }; 7569148cc50SJames Courtier-Dutton 757a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info snd_ctl_boolean_mono_info 7589148cc50SJames Courtier-Dutton 7599148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 7609148cc50SJames Courtier-Dutton { 7619148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 762536438f1SOswald Buddenhagen unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value]; 763536438f1SOswald Buddenhagen 7649148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; 7659148cc50SJames Courtier-Dutton return 0; 7669148cc50SJames Courtier-Dutton } 7679148cc50SJames Courtier-Dutton 7689148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 7699148cc50SJames Courtier-Dutton { 7709148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 771536438f1SOswald Buddenhagen unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value]; 7729148cc50SJames Courtier-Dutton unsigned int val, cache; 7739148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 7749148cc50SJames Courtier-Dutton cache = emu->emu1010.adc_pads; 7759148cc50SJames Courtier-Dutton if (val == 1) 7769148cc50SJames Courtier-Dutton cache = cache | mask; 7779148cc50SJames Courtier-Dutton else 7789148cc50SJames Courtier-Dutton cache = cache & ~mask; 7799148cc50SJames Courtier-Dutton if (cache != emu->emu1010.adc_pads) { 7809148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); 7819148cc50SJames Courtier-Dutton emu->emu1010.adc_pads = cache; 7829148cc50SJames Courtier-Dutton } 7839148cc50SJames Courtier-Dutton 7849148cc50SJames Courtier-Dutton return 0; 7859148cc50SJames Courtier-Dutton } 7869148cc50SJames Courtier-Dutton 787536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_adc_pads_ctl = { 788536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 789536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 790536438f1SOswald Buddenhagen .info = snd_emu1010_adc_pads_info, 791536438f1SOswald Buddenhagen .get = snd_emu1010_adc_pads_get, 792536438f1SOswald Buddenhagen .put = snd_emu1010_adc_pads_put 793536438f1SOswald Buddenhagen }; 7949148cc50SJames Courtier-Dutton 7959148cc50SJames Courtier-Dutton 796536438f1SOswald Buddenhagen static const char * const snd_emu1010_dac_pads[] = { 797f69d705dSOswald Buddenhagen "DAC1 0202 14dB PAD Playback Switch", 798536438f1SOswald Buddenhagen "DAC1 Audio Dock 14dB PAD Playback Switch", 799536438f1SOswald Buddenhagen "DAC2 Audio Dock 14dB PAD Playback Switch", 800536438f1SOswald Buddenhagen "DAC3 Audio Dock 14dB PAD Playback Switch", 801536438f1SOswald Buddenhagen "DAC4 Audio Dock 14dB PAD Playback Switch", 802536438f1SOswald Buddenhagen }; 8039148cc50SJames Courtier-Dutton 804536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_dac_regs[] = { 805f69d705dSOswald Buddenhagen EMU_HANA_0202_DAC_PAD1, 806536438f1SOswald Buddenhagen EMU_HANA_DOCK_DAC_PAD1, 807536438f1SOswald Buddenhagen EMU_HANA_DOCK_DAC_PAD2, 808536438f1SOswald Buddenhagen EMU_HANA_DOCK_DAC_PAD3, 809536438f1SOswald Buddenhagen EMU_HANA_DOCK_DAC_PAD4, 8109148cc50SJames Courtier-Dutton }; 8119148cc50SJames Courtier-Dutton 812a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info snd_ctl_boolean_mono_info 8139148cc50SJames Courtier-Dutton 8149148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 8159148cc50SJames Courtier-Dutton { 8169148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 817536438f1SOswald Buddenhagen unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value]; 818536438f1SOswald Buddenhagen 8199148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; 8209148cc50SJames Courtier-Dutton return 0; 8219148cc50SJames Courtier-Dutton } 8229148cc50SJames Courtier-Dutton 8239148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 8249148cc50SJames Courtier-Dutton { 8259148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 826536438f1SOswald Buddenhagen unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value]; 8279148cc50SJames Courtier-Dutton unsigned int val, cache; 828cc766807SOswald Buddenhagen int change; 829cc766807SOswald Buddenhagen 8309148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 8319148cc50SJames Courtier-Dutton cache = emu->emu1010.dac_pads; 8329148cc50SJames Courtier-Dutton if (val == 1) 8339148cc50SJames Courtier-Dutton cache = cache | mask; 8349148cc50SJames Courtier-Dutton else 8359148cc50SJames Courtier-Dutton cache = cache & ~mask; 836cc766807SOswald Buddenhagen change = (cache != emu->emu1010.dac_pads); 837cc766807SOswald Buddenhagen if (change) { 8389148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); 8399148cc50SJames Courtier-Dutton emu->emu1010.dac_pads = cache; 8409148cc50SJames Courtier-Dutton } 8419148cc50SJames Courtier-Dutton 842cc766807SOswald Buddenhagen return change; 8439148cc50SJames Courtier-Dutton } 8449148cc50SJames Courtier-Dutton 845536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_dac_pads_ctl = { 846536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 847536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 848536438f1SOswald Buddenhagen .info = snd_emu1010_dac_pads_info, 849536438f1SOswald Buddenhagen .get = snd_emu1010_dac_pads_get, 850536438f1SOswald Buddenhagen .put = snd_emu1010_dac_pads_put 8519f4bd5ddSJames Courtier-Dutton }; 8529f4bd5ddSJames Courtier-Dutton 853b0dbdaeaSJames Courtier-Dutton 85497f1582eSOswald Buddenhagen struct snd_emu1010_pads_info { 85597f1582eSOswald Buddenhagen const char * const *adc_ctls, * const *dac_ctls; 85697f1582eSOswald Buddenhagen unsigned n_adc_ctls, n_dac_ctls; 85797f1582eSOswald Buddenhagen }; 85897f1582eSOswald Buddenhagen 859816967d5STom Rix static const struct snd_emu1010_pads_info emu1010_pads_info[] = { 86097f1582eSOswald Buddenhagen { 8616f3609f8SOswald Buddenhagen /* rev1 1010 */ 86297f1582eSOswald Buddenhagen .adc_ctls = snd_emu1010_adc_pads, 86397f1582eSOswald Buddenhagen .n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads), 86497f1582eSOswald Buddenhagen .dac_ctls = snd_emu1010_dac_pads, 86597f1582eSOswald Buddenhagen .n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads), 86697f1582eSOswald Buddenhagen }, 86797f1582eSOswald Buddenhagen { 868f69d705dSOswald Buddenhagen /* rev2 1010 */ 86997f1582eSOswald Buddenhagen .adc_ctls = snd_emu1010_adc_pads, 870f69d705dSOswald Buddenhagen .n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 1, 87197f1582eSOswald Buddenhagen .dac_ctls = snd_emu1010_dac_pads, 872f69d705dSOswald Buddenhagen .n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 1, 873f69d705dSOswald Buddenhagen }, 874f69d705dSOswald Buddenhagen { 875f69d705dSOswald Buddenhagen /* 1616(m) cardbus */ 876f69d705dSOswald Buddenhagen .adc_ctls = snd_emu1010_adc_pads + 1, 877f69d705dSOswald Buddenhagen .n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 2, 878f69d705dSOswald Buddenhagen .dac_ctls = snd_emu1010_dac_pads + 1, 87997f1582eSOswald Buddenhagen .n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 2, 88097f1582eSOswald Buddenhagen }, 8816f3609f8SOswald Buddenhagen { 8826f3609f8SOswald Buddenhagen /* 0404 */ 8836f3609f8SOswald Buddenhagen .adc_ctls = NULL, 8846f3609f8SOswald Buddenhagen .n_adc_ctls = 0, 8856f3609f8SOswald Buddenhagen .dac_ctls = NULL, 8866f3609f8SOswald Buddenhagen .n_dac_ctls = 0, 8876f3609f8SOswald Buddenhagen }, 88897f1582eSOswald Buddenhagen }; 88997f1582eSOswald Buddenhagen 89097f1582eSOswald Buddenhagen 891*13598862SOswald Buddenhagen static int snd_emu1010_clock_source_info(struct snd_kcontrol *kcontrol, 892b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 893b0dbdaeaSJames Courtier-Dutton { 8941541c66dSTakashi Iwai static const char * const texts[4] = { 895edec7bbbSJames Courtier-Dutton "44100", "48000", "SPDIF", "ADAT" 896b0dbdaeaSJames Courtier-Dutton }; 897b0dbdaeaSJames Courtier-Dutton 8981541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 4, texts); 899b0dbdaeaSJames Courtier-Dutton } 900b0dbdaeaSJames Courtier-Dutton 901*13598862SOswald Buddenhagen static int snd_emu1010_clock_source_get(struct snd_kcontrol *kcontrol, 902b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 903b0dbdaeaSJames Courtier-Dutton { 904b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 905b0dbdaeaSJames Courtier-Dutton 906*13598862SOswald Buddenhagen ucontrol->value.enumerated.item[0] = emu->emu1010.clock_source; 907b0dbdaeaSJames Courtier-Dutton return 0; 908b0dbdaeaSJames Courtier-Dutton } 909b0dbdaeaSJames Courtier-Dutton 910*13598862SOswald Buddenhagen static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol, 911b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 912b0dbdaeaSJames Courtier-Dutton { 913b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 914b0dbdaeaSJames Courtier-Dutton unsigned int val; 915b0dbdaeaSJames Courtier-Dutton int change = 0; 916b0dbdaeaSJames Courtier-Dutton 917b0dbdaeaSJames Courtier-Dutton val = ucontrol->value.enumerated.item[0] ; 91874415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 4; */ 91974415a36SJames Courtier-Dutton if (val >= 4) 92074415a36SJames Courtier-Dutton return -EINVAL; 921*13598862SOswald Buddenhagen change = (emu->emu1010.clock_source != val); 922b0dbdaeaSJames Courtier-Dutton if (change) { 923*13598862SOswald Buddenhagen emu->emu1010.clock_source = val; 924b0dbdaeaSJames Courtier-Dutton switch (val) { 925b0dbdaeaSJames Courtier-Dutton case 0: 926b0dbdaeaSJames Courtier-Dutton /* 44100 */ 927b0dbdaeaSJames Courtier-Dutton /* Mute all */ 928b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 929b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 44.1kHz x1 */ 930b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 931b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); 932b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 933b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 934b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); 935b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 936e40a0b2eSJames Courtier-Dutton msleep(10); 937b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 938b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 939b0dbdaeaSJames Courtier-Dutton break; 940b0dbdaeaSJames Courtier-Dutton case 1: 941b0dbdaeaSJames Courtier-Dutton /* 48000 */ 942b0dbdaeaSJames Courtier-Dutton /* Mute all */ 943b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 944b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 48kHz x1 */ 945b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 946b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); 947b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 948b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 949b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); 950b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 951e40a0b2eSJames Courtier-Dutton msleep(10); 952b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 953b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 954b0dbdaeaSJames Courtier-Dutton break; 955edec7bbbSJames Courtier-Dutton 956edec7bbbSJames Courtier-Dutton case 2: /* Take clock from S/PDIF IN */ 957edec7bbbSJames Courtier-Dutton /* Mute all */ 958edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 959edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to S/PDIF input */ 960edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 961edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); 962edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 963edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 964edec7bbbSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 965edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 966edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 967edec7bbbSJames Courtier-Dutton msleep(10); 968edec7bbbSJames Courtier-Dutton /* Unmute all */ 969edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 970edec7bbbSJames Courtier-Dutton break; 971edec7bbbSJames Courtier-Dutton 972edec7bbbSJames Courtier-Dutton case 3: 973edec7bbbSJames Courtier-Dutton /* Take clock from ADAT IN */ 974edec7bbbSJames Courtier-Dutton /* Mute all */ 975edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 976edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to ADAT input */ 977edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 978edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); 979edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 980edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 981edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 982edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 983edec7bbbSJames Courtier-Dutton msleep(10); 984edec7bbbSJames Courtier-Dutton /* Unmute all */ 985edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 986edec7bbbSJames Courtier-Dutton 987edec7bbbSJames Courtier-Dutton 988edec7bbbSJames Courtier-Dutton break; 989b0dbdaeaSJames Courtier-Dutton } 990b0dbdaeaSJames Courtier-Dutton } 991b0dbdaeaSJames Courtier-Dutton return change; 992b0dbdaeaSJames Courtier-Dutton } 993b0dbdaeaSJames Courtier-Dutton 994*13598862SOswald Buddenhagen static const struct snd_kcontrol_new snd_emu1010_clock_source = 995b0dbdaeaSJames Courtier-Dutton { 996b0dbdaeaSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 997b0dbdaeaSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 998*13598862SOswald Buddenhagen .name = "Clock Source", 999b0dbdaeaSJames Courtier-Dutton .count = 1, 1000*13598862SOswald Buddenhagen .info = snd_emu1010_clock_source_info, 1001*13598862SOswald Buddenhagen .get = snd_emu1010_clock_source_get, 1002*13598862SOswald Buddenhagen .put = snd_emu1010_clock_source_put 1003*13598862SOswald Buddenhagen }; 1004*13598862SOswald Buddenhagen 1005*13598862SOswald Buddenhagen static int snd_emu1010_clock_fallback_info(struct snd_kcontrol *kcontrol, 1006*13598862SOswald Buddenhagen struct snd_ctl_elem_info *uinfo) 1007*13598862SOswald Buddenhagen { 1008*13598862SOswald Buddenhagen static const char * const texts[2] = { 1009*13598862SOswald Buddenhagen "44100", "48000" 1010*13598862SOswald Buddenhagen }; 1011*13598862SOswald Buddenhagen 1012*13598862SOswald Buddenhagen return snd_ctl_enum_info(uinfo, 1, 2, texts); 1013*13598862SOswald Buddenhagen } 1014*13598862SOswald Buddenhagen 1015*13598862SOswald Buddenhagen static int snd_emu1010_clock_fallback_get(struct snd_kcontrol *kcontrol, 1016*13598862SOswald Buddenhagen struct snd_ctl_elem_value *ucontrol) 1017*13598862SOswald Buddenhagen { 1018*13598862SOswald Buddenhagen struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1019*13598862SOswald Buddenhagen 1020*13598862SOswald Buddenhagen ucontrol->value.enumerated.item[0] = emu->emu1010.clock_fallback; 1021*13598862SOswald Buddenhagen return 0; 1022*13598862SOswald Buddenhagen } 1023*13598862SOswald Buddenhagen 1024*13598862SOswald Buddenhagen static int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol, 1025*13598862SOswald Buddenhagen struct snd_ctl_elem_value *ucontrol) 1026*13598862SOswald Buddenhagen { 1027*13598862SOswald Buddenhagen struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1028*13598862SOswald Buddenhagen unsigned int val = ucontrol->value.enumerated.item[0]; 1029*13598862SOswald Buddenhagen int change; 1030*13598862SOswald Buddenhagen 1031*13598862SOswald Buddenhagen if (val >= 2) 1032*13598862SOswald Buddenhagen return -EINVAL; 1033*13598862SOswald Buddenhagen change = (emu->emu1010.clock_fallback != val); 1034*13598862SOswald Buddenhagen if (change) { 1035*13598862SOswald Buddenhagen emu->emu1010.clock_fallback = val; 1036*13598862SOswald Buddenhagen snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 1 - val); 1037*13598862SOswald Buddenhagen } 1038*13598862SOswald Buddenhagen return change; 1039*13598862SOswald Buddenhagen } 1040*13598862SOswald Buddenhagen 1041*13598862SOswald Buddenhagen static const struct snd_kcontrol_new snd_emu1010_clock_fallback = 1042*13598862SOswald Buddenhagen { 1043*13598862SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 1044*13598862SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1045*13598862SOswald Buddenhagen .name = "Clock Fallback", 1046*13598862SOswald Buddenhagen .count = 1, 1047*13598862SOswald Buddenhagen .info = snd_emu1010_clock_fallback_info, 1048*13598862SOswald Buddenhagen .get = snd_emu1010_clock_fallback_get, 1049*13598862SOswald Buddenhagen .put = snd_emu1010_clock_fallback_put 1050b0dbdaeaSJames Courtier-Dutton }; 1051b0dbdaeaSJames Courtier-Dutton 105299dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol, 105399dcab46SMichael Gernoth struct snd_ctl_elem_info *uinfo) 105499dcab46SMichael Gernoth { 105599dcab46SMichael Gernoth static const char * const texts[2] = { 105699dcab46SMichael Gernoth "SPDIF", "ADAT" 105799dcab46SMichael Gernoth }; 105899dcab46SMichael Gernoth 105999dcab46SMichael Gernoth return snd_ctl_enum_info(uinfo, 1, 2, texts); 106099dcab46SMichael Gernoth } 106199dcab46SMichael Gernoth 106299dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol, 106399dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 106499dcab46SMichael Gernoth { 106599dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 106699dcab46SMichael Gernoth 106799dcab46SMichael Gernoth ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out; 106899dcab46SMichael Gernoth return 0; 106999dcab46SMichael Gernoth } 107099dcab46SMichael Gernoth 107199dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol, 107299dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 107399dcab46SMichael Gernoth { 107499dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 107599dcab46SMichael Gernoth unsigned int val; 107699dcab46SMichael Gernoth u32 tmp; 107799dcab46SMichael Gernoth int change = 0; 107899dcab46SMichael Gernoth 107999dcab46SMichael Gernoth val = ucontrol->value.enumerated.item[0]; 108099dcab46SMichael Gernoth /* Limit: uinfo->value.enumerated.items = 2; */ 108199dcab46SMichael Gernoth if (val >= 2) 108299dcab46SMichael Gernoth return -EINVAL; 108399dcab46SMichael Gernoth change = (emu->emu1010.optical_out != val); 108499dcab46SMichael Gernoth if (change) { 108599dcab46SMichael Gernoth emu->emu1010.optical_out = val; 10869d2f3863SOswald Buddenhagen tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) | 10879d2f3863SOswald Buddenhagen (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF); 108899dcab46SMichael Gernoth snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 108999dcab46SMichael Gernoth } 109099dcab46SMichael Gernoth return change; 109199dcab46SMichael Gernoth } 109299dcab46SMichael Gernoth 1093f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = { 109499dcab46SMichael Gernoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 109599dcab46SMichael Gernoth .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 109699dcab46SMichael Gernoth .name = "Optical Output Mode", 109799dcab46SMichael Gernoth .count = 1, 109899dcab46SMichael Gernoth .info = snd_emu1010_optical_out_info, 109999dcab46SMichael Gernoth .get = snd_emu1010_optical_out_get, 110099dcab46SMichael Gernoth .put = snd_emu1010_optical_out_put 110199dcab46SMichael Gernoth }; 110299dcab46SMichael Gernoth 110399dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol, 110499dcab46SMichael Gernoth struct snd_ctl_elem_info *uinfo) 110599dcab46SMichael Gernoth { 110699dcab46SMichael Gernoth static const char * const texts[2] = { 110799dcab46SMichael Gernoth "SPDIF", "ADAT" 110899dcab46SMichael Gernoth }; 110999dcab46SMichael Gernoth 111099dcab46SMichael Gernoth return snd_ctl_enum_info(uinfo, 1, 2, texts); 111199dcab46SMichael Gernoth } 111299dcab46SMichael Gernoth 111399dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol, 111499dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 111599dcab46SMichael Gernoth { 111699dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 111799dcab46SMichael Gernoth 111899dcab46SMichael Gernoth ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in; 111999dcab46SMichael Gernoth return 0; 112099dcab46SMichael Gernoth } 112199dcab46SMichael Gernoth 112299dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol, 112399dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 112499dcab46SMichael Gernoth { 112599dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 112699dcab46SMichael Gernoth unsigned int val; 112799dcab46SMichael Gernoth u32 tmp; 112899dcab46SMichael Gernoth int change = 0; 112999dcab46SMichael Gernoth 113099dcab46SMichael Gernoth val = ucontrol->value.enumerated.item[0]; 113199dcab46SMichael Gernoth /* Limit: uinfo->value.enumerated.items = 2; */ 113299dcab46SMichael Gernoth if (val >= 2) 113399dcab46SMichael Gernoth return -EINVAL; 113499dcab46SMichael Gernoth change = (emu->emu1010.optical_in != val); 113599dcab46SMichael Gernoth if (change) { 113699dcab46SMichael Gernoth emu->emu1010.optical_in = val; 11379d2f3863SOswald Buddenhagen tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) | 11389d2f3863SOswald Buddenhagen (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF); 113999dcab46SMichael Gernoth snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 114099dcab46SMichael Gernoth } 114199dcab46SMichael Gernoth return change; 114299dcab46SMichael Gernoth } 114399dcab46SMichael Gernoth 1144f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = { 114599dcab46SMichael Gernoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 114699dcab46SMichael Gernoth .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 114799dcab46SMichael Gernoth .name = "Optical Input Mode", 114899dcab46SMichael Gernoth .count = 1, 114999dcab46SMichael Gernoth .info = snd_emu1010_optical_in_info, 115099dcab46SMichael Gernoth .get = snd_emu1010_optical_in_get, 115199dcab46SMichael Gernoth .put = snd_emu1010_optical_in_put 115299dcab46SMichael Gernoth }; 115399dcab46SMichael Gernoth 1154184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, 1155184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 1156184c1e2cSJames Courtier-Dutton { 1157184c1e2cSJames Courtier-Dutton #if 0 11581541c66dSTakashi Iwai static const char * const texts[4] = { 1159184c1e2cSJames Courtier-Dutton "Unknown1", "Unknown2", "Mic", "Line" 1160184c1e2cSJames Courtier-Dutton }; 1161184c1e2cSJames Courtier-Dutton #endif 11621541c66dSTakashi Iwai static const char * const texts[2] = { 1163184c1e2cSJames Courtier-Dutton "Mic", "Line" 1164184c1e2cSJames Courtier-Dutton }; 1165184c1e2cSJames Courtier-Dutton 11661541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 2, texts); 1167184c1e2cSJames Courtier-Dutton } 1168184c1e2cSJames Courtier-Dutton 1169184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, 1170184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 1171184c1e2cSJames Courtier-Dutton { 1172184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1173184c1e2cSJames Courtier-Dutton 1174184c1e2cSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; 1175184c1e2cSJames Courtier-Dutton return 0; 1176184c1e2cSJames Courtier-Dutton } 1177184c1e2cSJames Courtier-Dutton 1178184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, 1179184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 1180184c1e2cSJames Courtier-Dutton { 1181184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1182184c1e2cSJames Courtier-Dutton unsigned int source_id; 1183184c1e2cSJames Courtier-Dutton unsigned int ngain, ogain; 1184a1c87c0bSOswald Buddenhagen u16 gpio; 1185184c1e2cSJames Courtier-Dutton int change = 0; 1186184c1e2cSJames Courtier-Dutton unsigned long flags; 1187184c1e2cSJames Courtier-Dutton u32 source; 1188184c1e2cSJames Courtier-Dutton /* If the capture source has changed, 1189184c1e2cSJames Courtier-Dutton * update the capture volume from the cached value 1190184c1e2cSJames Courtier-Dutton * for the particular source. 1191184c1e2cSJames Courtier-Dutton */ 119274415a36SJames Courtier-Dutton source_id = ucontrol->value.enumerated.item[0]; 119374415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 2; */ 119474415a36SJames Courtier-Dutton /* emu->i2c_capture_volume */ 119574415a36SJames Courtier-Dutton if (source_id >= 2) 119674415a36SJames Courtier-Dutton return -EINVAL; 1197184c1e2cSJames Courtier-Dutton change = (emu->i2c_capture_source != source_id); 1198184c1e2cSJames Courtier-Dutton if (change) { 1199184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 1200184c1e2cSJames Courtier-Dutton spin_lock_irqsave(&emu->emu_lock, flags); 1201a1c87c0bSOswald Buddenhagen gpio = inw(emu->port + A_IOCFG); 1202184c1e2cSJames Courtier-Dutton if (source_id==0) 1203a1c87c0bSOswald Buddenhagen outw(gpio | 0x4, emu->port + A_IOCFG); 1204184c1e2cSJames Courtier-Dutton else 1205a1c87c0bSOswald Buddenhagen outw(gpio & ~0x4, emu->port + A_IOCFG); 1206184c1e2cSJames Courtier-Dutton spin_unlock_irqrestore(&emu->emu_lock, flags); 1207184c1e2cSJames Courtier-Dutton 1208184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ 1209184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ 1210184c1e2cSJames Courtier-Dutton if (ngain != ogain) 1211184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); 1212184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ 1213184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ 1214184c1e2cSJames Courtier-Dutton if (ngain != ogain) 1215184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 1216184c1e2cSJames Courtier-Dutton 1217184c1e2cSJames Courtier-Dutton source = 1 << (source_id + 2); 1218184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ 1219184c1e2cSJames Courtier-Dutton emu->i2c_capture_source = source_id; 1220184c1e2cSJames Courtier-Dutton } 1221184c1e2cSJames Courtier-Dutton return change; 1222184c1e2cSJames Courtier-Dutton } 1223184c1e2cSJames Courtier-Dutton 1224f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source = 1225184c1e2cSJames Courtier-Dutton { 1226184c1e2cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1227184c1e2cSJames Courtier-Dutton .name = "Capture Source", 1228184c1e2cSJames Courtier-Dutton .info = snd_audigy_i2c_capture_source_info, 1229184c1e2cSJames Courtier-Dutton .get = snd_audigy_i2c_capture_source_get, 1230184c1e2cSJames Courtier-Dutton .put = snd_audigy_i2c_capture_source_put 1231184c1e2cSJames Courtier-Dutton }; 1232184c1e2cSJames Courtier-Dutton 1233184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, 1234184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 1235184c1e2cSJames Courtier-Dutton { 1236184c1e2cSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1237184c1e2cSJames Courtier-Dutton uinfo->count = 2; 1238184c1e2cSJames Courtier-Dutton uinfo->value.integer.min = 0; 1239184c1e2cSJames Courtier-Dutton uinfo->value.integer.max = 255; 1240184c1e2cSJames Courtier-Dutton return 0; 1241184c1e2cSJames Courtier-Dutton } 1242184c1e2cSJames Courtier-Dutton 1243184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, 1244184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 1245184c1e2cSJames Courtier-Dutton { 1246184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 124774415a36SJames Courtier-Dutton unsigned int source_id; 1248184c1e2cSJames Courtier-Dutton 1249184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 125074415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 125174415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 125274415a36SJames Courtier-Dutton if (source_id >= 2) 125374415a36SJames Courtier-Dutton return -EINVAL; 1254184c1e2cSJames Courtier-Dutton 1255184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; 1256184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; 1257184c1e2cSJames Courtier-Dutton return 0; 1258184c1e2cSJames Courtier-Dutton } 1259184c1e2cSJames Courtier-Dutton 1260184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, 1261184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 1262184c1e2cSJames Courtier-Dutton { 1263184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1264184c1e2cSJames Courtier-Dutton unsigned int ogain; 126514a29565SOswald Buddenhagen unsigned int ngain0, ngain1; 126674415a36SJames Courtier-Dutton unsigned int source_id; 1267184c1e2cSJames Courtier-Dutton int change = 0; 1268184c1e2cSJames Courtier-Dutton 1269184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 127074415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 127174415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 127274415a36SJames Courtier-Dutton if (source_id >= 2) 127374415a36SJames Courtier-Dutton return -EINVAL; 127414a29565SOswald Buddenhagen ngain0 = ucontrol->value.integer.value[0]; 127514a29565SOswald Buddenhagen ngain1 = ucontrol->value.integer.value[1]; 127614a29565SOswald Buddenhagen if (ngain0 > 0xff) 127714a29565SOswald Buddenhagen return -EINVAL; 127814a29565SOswald Buddenhagen if (ngain1 > 0xff) 127914a29565SOswald Buddenhagen return -EINVAL; 1280184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ 128114a29565SOswald Buddenhagen if (ogain != ngain0) { 1282184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 128314a29565SOswald Buddenhagen snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0); 128414a29565SOswald Buddenhagen emu->i2c_capture_volume[source_id][0] = ngain0; 1285184c1e2cSJames Courtier-Dutton change = 1; 1286184c1e2cSJames Courtier-Dutton } 1287184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ 128814a29565SOswald Buddenhagen if (ogain != ngain1) { 1289184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 129014a29565SOswald Buddenhagen snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1); 129114a29565SOswald Buddenhagen emu->i2c_capture_volume[source_id][1] = ngain1; 1292184c1e2cSJames Courtier-Dutton change = 1; 1293184c1e2cSJames Courtier-Dutton } 1294184c1e2cSJames Courtier-Dutton 1295184c1e2cSJames Courtier-Dutton return change; 1296184c1e2cSJames Courtier-Dutton } 1297184c1e2cSJames Courtier-Dutton 1298536438f1SOswald Buddenhagen static const struct snd_kcontrol_new i2c_volume_ctl = { 1299536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1300536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 1301536438f1SOswald Buddenhagen SNDRV_CTL_ELEM_ACCESS_TLV_READ, 1302536438f1SOswald Buddenhagen .info = snd_audigy_i2c_volume_info, 1303536438f1SOswald Buddenhagen .get = snd_audigy_i2c_volume_get, 1304536438f1SOswald Buddenhagen .put = snd_audigy_i2c_volume_put, 1305536438f1SOswald Buddenhagen .tlv = { .p = snd_audigy_db_scale2 } 1306536438f1SOswald Buddenhagen }; 1307184c1e2cSJames Courtier-Dutton 1308536438f1SOswald Buddenhagen static const char * const snd_audigy_i2c_volume_ctls[] = { 1309536438f1SOswald Buddenhagen "Mic Capture Volume", 1310536438f1SOswald Buddenhagen "Line Capture Volume", 1311184c1e2cSJames Courtier-Dutton }; 1312184c1e2cSJames Courtier-Dutton 13130af68e5eSTakashi Iwai #if 0 1314eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13151da177e4SLinus Torvalds { 13161541c66dSTakashi Iwai static const char * const texts[] = {"44100", "48000", "96000"}; 13171da177e4SLinus Torvalds 13181541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 3, texts); 13191da177e4SLinus Torvalds } 13201da177e4SLinus Torvalds 1321eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, 1322eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13231da177e4SLinus Torvalds { 1324eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13251da177e4SLinus Torvalds unsigned int tmp; 13261da177e4SLinus Torvalds 13271da177e4SLinus Torvalds tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 13281da177e4SLinus Torvalds switch (tmp & A_SPDIF_RATE_MASK) { 13291da177e4SLinus Torvalds case A_SPDIF_44100: 13301da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 13311da177e4SLinus Torvalds break; 13321da177e4SLinus Torvalds case A_SPDIF_48000: 13331da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 13341da177e4SLinus Torvalds break; 13351da177e4SLinus Torvalds case A_SPDIF_96000: 13361da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 13371da177e4SLinus Torvalds break; 13381da177e4SLinus Torvalds default: 13391da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 13401da177e4SLinus Torvalds } 13411da177e4SLinus Torvalds return 0; 13421da177e4SLinus Torvalds } 13431da177e4SLinus Torvalds 1344eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, 1345eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13461da177e4SLinus Torvalds { 1347eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13481da177e4SLinus Torvalds int change; 13491da177e4SLinus Torvalds unsigned int reg, val, tmp; 13501da177e4SLinus Torvalds unsigned long flags; 13511da177e4SLinus Torvalds 13521da177e4SLinus Torvalds switch(ucontrol->value.enumerated.item[0]) { 13531da177e4SLinus Torvalds case 0: 13541da177e4SLinus Torvalds val = A_SPDIF_44100; 13551da177e4SLinus Torvalds break; 13561da177e4SLinus Torvalds case 1: 13571da177e4SLinus Torvalds val = A_SPDIF_48000; 13581da177e4SLinus Torvalds break; 13591da177e4SLinus Torvalds case 2: 13601da177e4SLinus Torvalds val = A_SPDIF_96000; 13611da177e4SLinus Torvalds break; 13621da177e4SLinus Torvalds default: 13631da177e4SLinus Torvalds val = A_SPDIF_48000; 13641da177e4SLinus Torvalds break; 13651da177e4SLinus Torvalds } 13661da177e4SLinus Torvalds 13671da177e4SLinus Torvalds 13681da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13691da177e4SLinus Torvalds reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 13701da177e4SLinus Torvalds tmp = reg & ~A_SPDIF_RATE_MASK; 13711da177e4SLinus Torvalds tmp |= val; 137212bda107STakashi Iwai change = (tmp != reg); 137312bda107STakashi Iwai if (change) 13741da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); 13751da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13761da177e4SLinus Torvalds return change; 13771da177e4SLinus Torvalds } 13781da177e4SLinus Torvalds 1379b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate = 13801da177e4SLinus Torvalds { 13811da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 13821da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 13831da177e4SLinus Torvalds .name = "Audigy SPDIF Output Sample Rate", 13841da177e4SLinus Torvalds .count = 1, 13851da177e4SLinus Torvalds .info = snd_audigy_spdif_output_rate_info, 13861da177e4SLinus Torvalds .get = snd_audigy_spdif_output_rate_get, 13871da177e4SLinus Torvalds .put = snd_audigy_spdif_output_rate_put 13881da177e4SLinus Torvalds }; 13890af68e5eSTakashi Iwai #endif 13901da177e4SLinus Torvalds 1391eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, 1392eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13931da177e4SLinus Torvalds { 1394eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13951da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 13961da177e4SLinus Torvalds int change; 13971da177e4SLinus Torvalds unsigned int val; 13981da177e4SLinus Torvalds 139974415a36SJames Courtier-Dutton /* Limit: emu->spdif_bits */ 140074415a36SJames Courtier-Dutton if (idx >= 3) 140174415a36SJames Courtier-Dutton return -EINVAL; 14021da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) | 14031da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) | 14041da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) | 14051da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24); 14061da177e4SLinus Torvalds change = val != emu->spdif_bits[idx]; 14071da177e4SLinus Torvalds if (change) { 14081da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); 14091da177e4SLinus Torvalds emu->spdif_bits[idx] = val; 14101da177e4SLinus Torvalds } 14111da177e4SLinus Torvalds return change; 14121da177e4SLinus Torvalds } 14131da177e4SLinus Torvalds 1414f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = 14151da177e4SLinus Torvalds { 14161da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 14175549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14181da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 14197583cb51STakashi Iwai .count = 3, 14201da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 14211da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get_mask 14221da177e4SLinus Torvalds }; 14231da177e4SLinus Torvalds 1424f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control = 14251da177e4SLinus Torvalds { 14265549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14271da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 14287583cb51STakashi Iwai .count = 3, 14291da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 14301da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get, 14311da177e4SLinus Torvalds .put = snd_emu10k1_spdif_put 14321da177e4SLinus Torvalds }; 14331da177e4SLinus Torvalds 14341da177e4SLinus Torvalds 1435eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route) 14361da177e4SLinus Torvalds { 14371da177e4SLinus Torvalds if (emu->audigy) { 143846055699SOswald Buddenhagen snd_emu10k1_ptr_write_multiple(emu, voice, 143946055699SOswald Buddenhagen A_FXRT1, snd_emu10k1_compose_audigy_fxrt1(route), 144046055699SOswald Buddenhagen A_FXRT2, snd_emu10k1_compose_audigy_fxrt2(route), 144146055699SOswald Buddenhagen REGLIST_END); 14421da177e4SLinus Torvalds } else { 14431da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXRT, voice, 14441da177e4SLinus Torvalds snd_emu10k1_compose_send_routing(route)); 14451da177e4SLinus Torvalds } 14461da177e4SLinus Torvalds } 14471da177e4SLinus Torvalds 1448eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume) 14491da177e4SLinus Torvalds { 14501da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); 14511da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); 14521da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); 14531da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); 14541da177e4SLinus Torvalds if (emu->audigy) { 145551d652f4SOswald Buddenhagen snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, 145651d652f4SOswald Buddenhagen snd_emu10k1_compose_audigy_sendamounts(volume)); 14571da177e4SLinus Torvalds } 14581da177e4SLinus Torvalds } 14591da177e4SLinus Torvalds 14601da177e4SLinus Torvalds /* PCM stream controls */ 14611da177e4SLinus Torvalds 1462eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 14631da177e4SLinus Torvalds { 1464eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14651da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 14661da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 14671da177e4SLinus Torvalds uinfo->value.integer.min = 0; 14681da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 14691da177e4SLinus Torvalds return 0; 14701da177e4SLinus Torvalds } 14711da177e4SLinus Torvalds 1472eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, 1473eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14741da177e4SLinus Torvalds { 1475eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1476eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1477eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 14781da177e4SLinus Torvalds int voice, idx; 14791da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 14801da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 14811da177e4SLinus Torvalds 14821da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 14831da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 14841da177e4SLinus Torvalds ucontrol->value.integer.value[(voice * num_efx) + idx] = 14851da177e4SLinus Torvalds mix->send_routing[voice][idx] & mask; 14861da177e4SLinus Torvalds return 0; 14871da177e4SLinus Torvalds } 14881da177e4SLinus Torvalds 1489eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, 1490eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14911da177e4SLinus Torvalds { 14921da177e4SLinus Torvalds unsigned long flags; 1493eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1494eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1495eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 14961da177e4SLinus Torvalds int change = 0, voice, idx, val; 14971da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 14981da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 14991da177e4SLinus Torvalds 15001da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 15011da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 15021da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 15031da177e4SLinus Torvalds val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; 15041da177e4SLinus Torvalds if (mix->send_routing[voice][idx] != val) { 15051da177e4SLinus Torvalds mix->send_routing[voice][idx] = val; 15061da177e4SLinus Torvalds change = 1; 15071da177e4SLinus Torvalds } 15081da177e4SLinus Torvalds } 1509a915d604SOswald Buddenhagen if (change && mix->epcm && mix->epcm->voices[0]) { 1510a915d604SOswald Buddenhagen if (!mix->epcm->voices[0]->last) { 15111da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 15121da177e4SLinus Torvalds &mix->send_routing[1][0]); 1513a915d604SOswald Buddenhagen update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number + 1, 15141da177e4SLinus Torvalds &mix->send_routing[2][0]); 1515a915d604SOswald Buddenhagen } else { 15161da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 15171da177e4SLinus Torvalds &mix->send_routing[0][0]); 15181da177e4SLinus Torvalds } 15191da177e4SLinus Torvalds } 15201da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 15211da177e4SLinus Torvalds return change; 15221da177e4SLinus Torvalds } 15231da177e4SLinus Torvalds 1524f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control = 15251da177e4SLinus Torvalds { 15261da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 152767ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 15281da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Routing", 15291da177e4SLinus Torvalds .count = 32, 15301da177e4SLinus Torvalds .info = snd_emu10k1_send_routing_info, 15311da177e4SLinus Torvalds .get = snd_emu10k1_send_routing_get, 15321da177e4SLinus Torvalds .put = snd_emu10k1_send_routing_put 15331da177e4SLinus Torvalds }; 15341da177e4SLinus Torvalds 1535eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 15361da177e4SLinus Torvalds { 1537eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15381da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 15391da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 15401da177e4SLinus Torvalds uinfo->value.integer.min = 0; 15411da177e4SLinus Torvalds uinfo->value.integer.max = 255; 15421da177e4SLinus Torvalds return 0; 15431da177e4SLinus Torvalds } 15441da177e4SLinus Torvalds 1545eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, 1546eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15471da177e4SLinus Torvalds { 1548eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1549eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1550eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 15511da177e4SLinus Torvalds int idx; 15521da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 15531da177e4SLinus Torvalds 15541da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) 15551da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; 15561da177e4SLinus Torvalds return 0; 15571da177e4SLinus Torvalds } 15581da177e4SLinus Torvalds 1559eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, 1560eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15611da177e4SLinus Torvalds { 15621da177e4SLinus Torvalds unsigned long flags; 1563eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1564eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1565eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 15661da177e4SLinus Torvalds int change = 0, idx, val; 15671da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 15681da177e4SLinus Torvalds 15691da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 15701da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) { 15711da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 15721da177e4SLinus Torvalds if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { 15731da177e4SLinus Torvalds mix->send_volume[idx/num_efx][idx%num_efx] = val; 15741da177e4SLinus Torvalds change = 1; 15751da177e4SLinus Torvalds } 15761da177e4SLinus Torvalds } 1577a915d604SOswald Buddenhagen if (change && mix->epcm && mix->epcm->voices[0]) { 1578a915d604SOswald Buddenhagen if (!mix->epcm->voices[0]->last) { 15791da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 15801da177e4SLinus Torvalds &mix->send_volume[1][0]); 1581a915d604SOswald Buddenhagen update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number + 1, 15821da177e4SLinus Torvalds &mix->send_volume[2][0]); 1583a915d604SOswald Buddenhagen } else { 15841da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 15851da177e4SLinus Torvalds &mix->send_volume[0][0]); 15861da177e4SLinus Torvalds } 15871da177e4SLinus Torvalds } 15881da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 15891da177e4SLinus Torvalds return change; 15901da177e4SLinus Torvalds } 15911da177e4SLinus Torvalds 1592f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control = 15931da177e4SLinus Torvalds { 15941da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 159567ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 15961da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Volume", 15971da177e4SLinus Torvalds .count = 32, 15981da177e4SLinus Torvalds .info = snd_emu10k1_send_volume_info, 15991da177e4SLinus Torvalds .get = snd_emu10k1_send_volume_get, 16001da177e4SLinus Torvalds .put = snd_emu10k1_send_volume_put 16011da177e4SLinus Torvalds }; 16021da177e4SLinus Torvalds 1603eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 16041da177e4SLinus Torvalds { 16051da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 16061da177e4SLinus Torvalds uinfo->count = 3; 16071da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1608bcdbd3b7SOswald Buddenhagen uinfo->value.integer.max = 0x1fffd; 16091da177e4SLinus Torvalds return 0; 16101da177e4SLinus Torvalds } 16111da177e4SLinus Torvalds 1612eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, 1613eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16141da177e4SLinus Torvalds { 1615eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1616eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1617eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 16181da177e4SLinus Torvalds int idx; 16191da177e4SLinus Torvalds 16201da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) 1621bcdbd3b7SOswald Buddenhagen ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U; 16221da177e4SLinus Torvalds return 0; 16231da177e4SLinus Torvalds } 16241da177e4SLinus Torvalds 1625eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, 1626eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16271da177e4SLinus Torvalds { 16281da177e4SLinus Torvalds unsigned long flags; 1629eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1630eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1631eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 16321da177e4SLinus Torvalds int change = 0, idx, val; 16331da177e4SLinus Torvalds 16341da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 16351da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) { 1636bcdbd3b7SOswald Buddenhagen unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff; 1637bcdbd3b7SOswald Buddenhagen val = uval * 0x8000U / 0xffffU; 16381da177e4SLinus Torvalds if (mix->attn[idx] != val) { 16391da177e4SLinus Torvalds mix->attn[idx] = val; 16401da177e4SLinus Torvalds change = 1; 16411da177e4SLinus Torvalds } 16421da177e4SLinus Torvalds } 1643a915d604SOswald Buddenhagen if (change && mix->epcm && mix->epcm->voices[0]) { 1644a915d604SOswald Buddenhagen if (!mix->epcm->voices[0]->last) { 16451da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); 1646a915d604SOswald Buddenhagen snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number + 1, mix->attn[2]); 1647a915d604SOswald Buddenhagen } else { 16481da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); 16491da177e4SLinus Torvalds } 16501da177e4SLinus Torvalds } 16511da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 16521da177e4SLinus Torvalds return change; 16531da177e4SLinus Torvalds } 16541da177e4SLinus Torvalds 1655f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control = 16561da177e4SLinus Torvalds { 16571da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 165867ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 16591da177e4SLinus Torvalds .name = "EMU10K1 PCM Volume", 16601da177e4SLinus Torvalds .count = 32, 16611da177e4SLinus Torvalds .info = snd_emu10k1_attn_info, 16621da177e4SLinus Torvalds .get = snd_emu10k1_attn_get, 16631da177e4SLinus Torvalds .put = snd_emu10k1_attn_put 16641da177e4SLinus Torvalds }; 16651da177e4SLinus Torvalds 16661da177e4SLinus Torvalds /* Mutichannel PCM stream controls */ 16671da177e4SLinus Torvalds 1668eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 16691da177e4SLinus Torvalds { 1670eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 16711da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 16721da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 16731da177e4SLinus Torvalds uinfo->value.integer.min = 0; 16741da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 16751da177e4SLinus Torvalds return 0; 16761da177e4SLinus Torvalds } 16771da177e4SLinus Torvalds 1678eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, 1679eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16801da177e4SLinus Torvalds { 1681eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1682eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1683eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 16841da177e4SLinus Torvalds int idx; 16851da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 16861da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 16871da177e4SLinus Torvalds 16881da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 16891da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = 16901da177e4SLinus Torvalds mix->send_routing[0][idx] & mask; 16911da177e4SLinus Torvalds return 0; 16921da177e4SLinus Torvalds } 16931da177e4SLinus Torvalds 1694eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, 1695eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16961da177e4SLinus Torvalds { 16971da177e4SLinus Torvalds unsigned long flags; 1698eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 16991da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1700eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 17011da177e4SLinus Torvalds int change = 0, idx, val; 17021da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 17031da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 17041da177e4SLinus Torvalds 17051da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 17061da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 17071da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & mask; 17081da177e4SLinus Torvalds if (mix->send_routing[0][idx] != val) { 17091da177e4SLinus Torvalds mix->send_routing[0][idx] = val; 17101da177e4SLinus Torvalds change = 1; 17111da177e4SLinus Torvalds } 17121da177e4SLinus Torvalds } 17131da177e4SLinus Torvalds 17141da177e4SLinus Torvalds if (change && mix->epcm) { 17151da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 17161da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number, 17171da177e4SLinus Torvalds &mix->send_routing[0][0]); 17181da177e4SLinus Torvalds } 17191da177e4SLinus Torvalds } 17201da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 17211da177e4SLinus Torvalds return change; 17221da177e4SLinus Torvalds } 17231da177e4SLinus Torvalds 1724f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control = 17251da177e4SLinus Torvalds { 17261da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 17271da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 17281da177e4SLinus Torvalds .name = "Multichannel PCM Send Routing", 17291da177e4SLinus Torvalds .count = 16, 17301da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_routing_info, 17311da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_routing_get, 17321da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_routing_put 17331da177e4SLinus Torvalds }; 17341da177e4SLinus Torvalds 1735eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 17361da177e4SLinus Torvalds { 1737eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 17381da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 17391da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 17401da177e4SLinus Torvalds uinfo->value.integer.min = 0; 17411da177e4SLinus Torvalds uinfo->value.integer.max = 255; 17421da177e4SLinus Torvalds return 0; 17431da177e4SLinus Torvalds } 17441da177e4SLinus Torvalds 1745eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, 1746eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 17471da177e4SLinus Torvalds { 1748eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1749eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1750eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 17511da177e4SLinus Torvalds int idx; 17521da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 17531da177e4SLinus Torvalds 17541da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 17551da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; 17561da177e4SLinus Torvalds return 0; 17571da177e4SLinus Torvalds } 17581da177e4SLinus Torvalds 1759eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, 1760eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 17611da177e4SLinus Torvalds { 17621da177e4SLinus Torvalds unsigned long flags; 1763eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 17641da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1765eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 17661da177e4SLinus Torvalds int change = 0, idx, val; 17671da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 17681da177e4SLinus Torvalds 17691da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 17701da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 17711da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 17721da177e4SLinus Torvalds if (mix->send_volume[0][idx] != val) { 17731da177e4SLinus Torvalds mix->send_volume[0][idx] = val; 17741da177e4SLinus Torvalds change = 1; 17751da177e4SLinus Torvalds } 17761da177e4SLinus Torvalds } 17771da177e4SLinus Torvalds if (change && mix->epcm) { 17781da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 17791da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number, 17801da177e4SLinus Torvalds &mix->send_volume[0][0]); 17811da177e4SLinus Torvalds } 17821da177e4SLinus Torvalds } 17831da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 17841da177e4SLinus Torvalds return change; 17851da177e4SLinus Torvalds } 17861da177e4SLinus Torvalds 17871da177e4SLinus Torvalds 1788f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control = 17891da177e4SLinus Torvalds { 17901da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 17911da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 17921da177e4SLinus Torvalds .name = "Multichannel PCM Send Volume", 17931da177e4SLinus Torvalds .count = 16, 17941da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_volume_info, 17951da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_volume_get, 17961da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_volume_put 17971da177e4SLinus Torvalds }; 17981da177e4SLinus Torvalds 1799eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 18001da177e4SLinus Torvalds { 18011da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 18021da177e4SLinus Torvalds uinfo->count = 1; 18031da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1804bcdbd3b7SOswald Buddenhagen uinfo->value.integer.max = 0x1fffd; 18051da177e4SLinus Torvalds return 0; 18061da177e4SLinus Torvalds } 18071da177e4SLinus Torvalds 1808eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, 1809eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 18101da177e4SLinus Torvalds { 1811eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1812eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1813eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 18141da177e4SLinus Torvalds 1815bcdbd3b7SOswald Buddenhagen ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U; 18161da177e4SLinus Torvalds return 0; 18171da177e4SLinus Torvalds } 18181da177e4SLinus Torvalds 1819eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, 1820eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 18211da177e4SLinus Torvalds { 18221da177e4SLinus Torvalds unsigned long flags; 1823eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 18241da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1825eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 18261da177e4SLinus Torvalds int change = 0, val; 1827bcdbd3b7SOswald Buddenhagen unsigned uval; 18281da177e4SLinus Torvalds 18291da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 1830bcdbd3b7SOswald Buddenhagen uval = ucontrol->value.integer.value[0] & 0x1ffff; 1831bcdbd3b7SOswald Buddenhagen val = uval * 0x8000U / 0xffffU; 18321da177e4SLinus Torvalds if (mix->attn[0] != val) { 18331da177e4SLinus Torvalds mix->attn[0] = val; 18341da177e4SLinus Torvalds change = 1; 18351da177e4SLinus Torvalds } 18361da177e4SLinus Torvalds if (change && mix->epcm) { 18371da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 18381da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); 18391da177e4SLinus Torvalds } 18401da177e4SLinus Torvalds } 18411da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 18421da177e4SLinus Torvalds return change; 18431da177e4SLinus Torvalds } 18441da177e4SLinus Torvalds 1845f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control = 18461da177e4SLinus Torvalds { 18471da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 18481da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 18491da177e4SLinus Torvalds .name = "Multichannel PCM Volume", 18501da177e4SLinus Torvalds .count = 16, 18511da177e4SLinus Torvalds .info = snd_emu10k1_efx_attn_info, 18521da177e4SLinus Torvalds .get = snd_emu10k1_efx_attn_get, 18531da177e4SLinus Torvalds .put = snd_emu10k1_efx_attn_put 18541da177e4SLinus Torvalds }; 18551da177e4SLinus Torvalds 1856a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info snd_ctl_boolean_mono_info 18571da177e4SLinus Torvalds 1858eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, 1859eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 18601da177e4SLinus Torvalds { 1861eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 18621da177e4SLinus Torvalds 18631da177e4SLinus Torvalds if (emu->audigy) 1864a1c87c0bSOswald Buddenhagen ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; 18651da177e4SLinus Torvalds else 18661da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; 1867d2cd74b1STakashi Iwai if (emu->card_capabilities->invert_shared_spdif) 1868d2cd74b1STakashi Iwai ucontrol->value.integer.value[0] = 1869d2cd74b1STakashi Iwai !ucontrol->value.integer.value[0]; 1870d2cd74b1STakashi Iwai 18711da177e4SLinus Torvalds return 0; 18721da177e4SLinus Torvalds } 18731da177e4SLinus Torvalds 1874eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, 1875eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 18761da177e4SLinus Torvalds { 18771da177e4SLinus Torvalds unsigned long flags; 1878eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1879d2cd74b1STakashi Iwai unsigned int reg, val, sw; 18801da177e4SLinus Torvalds int change = 0; 18811da177e4SLinus Torvalds 1882d2cd74b1STakashi Iwai sw = ucontrol->value.integer.value[0]; 1883d2cd74b1STakashi Iwai if (emu->card_capabilities->invert_shared_spdif) 1884d2cd74b1STakashi Iwai sw = !sw; 188550164f69SOswald Buddenhagen spin_lock_irqsave(&emu->emu_lock, flags); 1886184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 1887184c1e2cSJames Courtier-Dutton /* Do nothing for Audigy 2 ZS Notebook */ 1888184c1e2cSJames Courtier-Dutton } else if (emu->audigy) { 1889a1c87c0bSOswald Buddenhagen reg = inw(emu->port + A_IOCFG); 1890d2cd74b1STakashi Iwai val = sw ? A_IOCFG_GPOUT0 : 0; 18911da177e4SLinus Torvalds change = (reg & A_IOCFG_GPOUT0) != val; 18921da177e4SLinus Torvalds if (change) { 18931da177e4SLinus Torvalds reg &= ~A_IOCFG_GPOUT0; 18941da177e4SLinus Torvalds reg |= val; 1895a1c87c0bSOswald Buddenhagen outw(reg | val, emu->port + A_IOCFG); 18961da177e4SLinus Torvalds } 18971da177e4SLinus Torvalds } 18981da177e4SLinus Torvalds reg = inl(emu->port + HCFG); 1899d2cd74b1STakashi Iwai val = sw ? HCFG_GPOUT0 : 0; 19001da177e4SLinus Torvalds change |= (reg & HCFG_GPOUT0) != val; 19011da177e4SLinus Torvalds if (change) { 19021da177e4SLinus Torvalds reg &= ~HCFG_GPOUT0; 19031da177e4SLinus Torvalds reg |= val; 19041da177e4SLinus Torvalds outl(reg | val, emu->port + HCFG); 19051da177e4SLinus Torvalds } 190650164f69SOswald Buddenhagen spin_unlock_irqrestore(&emu->emu_lock, flags); 19071da177e4SLinus Torvalds return change; 19081da177e4SLinus Torvalds } 19091da177e4SLinus Torvalds 1910f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif = 19111da177e4SLinus Torvalds { 19121da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 19131da177e4SLinus Torvalds .name = "SB Live Analog/Digital Output Jack", 19141da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 19151da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 19161da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 19171da177e4SLinus Torvalds }; 19181da177e4SLinus Torvalds 1919f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif = 19201da177e4SLinus Torvalds { 19211da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 19221da177e4SLinus Torvalds .name = "Audigy Analog/Digital Output Jack", 19231da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 19241da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 19251da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 19261da177e4SLinus Torvalds }; 19271da177e4SLinus Torvalds 192816950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */ 192916950e09STakashi Iwai 193016950e09STakashi Iwai #define snd_audigy_capture_boost_info snd_ctl_boolean_mono_info 193116950e09STakashi Iwai 193216950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol, 193316950e09STakashi Iwai struct snd_ctl_elem_value *ucontrol) 193416950e09STakashi Iwai { 193516950e09STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 193616950e09STakashi Iwai unsigned int val; 193716950e09STakashi Iwai 193816950e09STakashi Iwai /* FIXME: better to use a cached version */ 193916950e09STakashi Iwai val = snd_ac97_read(emu->ac97, AC97_REC_GAIN); 194016950e09STakashi Iwai ucontrol->value.integer.value[0] = !!val; 194116950e09STakashi Iwai return 0; 194216950e09STakashi Iwai } 194316950e09STakashi Iwai 194416950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, 194516950e09STakashi Iwai struct snd_ctl_elem_value *ucontrol) 194616950e09STakashi Iwai { 194716950e09STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 194816950e09STakashi Iwai unsigned int val; 194916950e09STakashi Iwai 195016950e09STakashi Iwai if (ucontrol->value.integer.value[0]) 195116950e09STakashi Iwai val = 0x0f0f; 195216950e09STakashi Iwai else 195316950e09STakashi Iwai val = 0; 195416950e09STakashi Iwai return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); 195516950e09STakashi Iwai } 195616950e09STakashi Iwai 1957f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost = 195816950e09STakashi Iwai { 195916950e09STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 19602a52feb1SMaciej S. Szmigiero .name = "Mic Extra Boost", 196116950e09STakashi Iwai .info = snd_audigy_capture_boost_info, 196216950e09STakashi Iwai .get = snd_audigy_capture_boost_get, 196316950e09STakashi Iwai .put = snd_audigy_capture_boost_put 196416950e09STakashi Iwai }; 196516950e09STakashi Iwai 196616950e09STakashi Iwai 19671da177e4SLinus Torvalds /* 19681da177e4SLinus Torvalds */ 1969eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) 19701da177e4SLinus Torvalds { 1971eb4698f3STakashi Iwai struct snd_emu10k1 *emu = ac97->private_data; 19721da177e4SLinus Torvalds emu->ac97 = NULL; 19731da177e4SLinus Torvalds } 19741da177e4SLinus Torvalds 19751da177e4SLinus Torvalds /* 19761da177e4SLinus Torvalds */ 1977eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name) 19781da177e4SLinus Torvalds { 1979eb4698f3STakashi Iwai struct snd_ctl_elem_id id; 19801da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 19811da177e4SLinus Torvalds strcpy(id.name, name); 19821da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 19831da177e4SLinus Torvalds return snd_ctl_remove_id(card, &id); 19841da177e4SLinus Torvalds } 19851da177e4SLinus Torvalds 1986eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) 19871da177e4SLinus Torvalds { 1988eb4698f3STakashi Iwai struct snd_ctl_elem_id sid; 19891da177e4SLinus Torvalds memset(&sid, 0, sizeof(sid)); 19901da177e4SLinus Torvalds strcpy(sid.name, name); 19911da177e4SLinus Torvalds sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 19921da177e4SLinus Torvalds return snd_ctl_find_id(card, &sid); 19931da177e4SLinus Torvalds } 19941da177e4SLinus Torvalds 1995eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst) 19961da177e4SLinus Torvalds { 1997eb4698f3STakashi Iwai struct snd_kcontrol *kctl = ctl_find(card, src); 19981da177e4SLinus Torvalds if (kctl) { 199936476b81SMaciej S. Szmigiero snd_ctl_rename(card, kctl, dst); 20001da177e4SLinus Torvalds return 0; 20011da177e4SLinus Torvalds } 20021da177e4SLinus Torvalds return -ENOENT; 20031da177e4SLinus Torvalds } 20041da177e4SLinus Torvalds 2005e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu, 200667ed4161SClemens Ladisch int pcm_device, int multi_device) 20071da177e4SLinus Torvalds { 2008155e3d3bSOswald Buddenhagen int err; 2009eb4698f3STakashi Iwai struct snd_kcontrol *kctl; 2010eb4698f3STakashi Iwai struct snd_card *card = emu->card; 20116fddce26STakashi Iwai const char * const *c; 20126fddce26STakashi Iwai static const char * const emu10k1_remove_ctls[] = { 20131da177e4SLinus Torvalds /* no AC97 mono, surround, center/lfe */ 20141da177e4SLinus Torvalds "Master Mono Playback Switch", 20151da177e4SLinus Torvalds "Master Mono Playback Volume", 20161da177e4SLinus Torvalds "PCM Out Path & Mute", 20171da177e4SLinus Torvalds "Mono Output Select", 20181da177e4SLinus Torvalds "Surround Playback Switch", 20191da177e4SLinus Torvalds "Surround Playback Volume", 20201da177e4SLinus Torvalds "Center Playback Switch", 20211da177e4SLinus Torvalds "Center Playback Volume", 20221da177e4SLinus Torvalds "LFE Playback Switch", 20231da177e4SLinus Torvalds "LFE Playback Volume", 20241da177e4SLinus Torvalds NULL 20251da177e4SLinus Torvalds }; 20266fddce26STakashi Iwai static const char * const emu10k1_rename_ctls[] = { 20271da177e4SLinus Torvalds "Surround Digital Playback Volume", "Surround Playback Volume", 20281da177e4SLinus Torvalds "Center Digital Playback Volume", "Center Playback Volume", 20291da177e4SLinus Torvalds "LFE Digital Playback Volume", "LFE Playback Volume", 20301da177e4SLinus Torvalds NULL 20311da177e4SLinus Torvalds }; 20326fddce26STakashi Iwai static const char * const audigy_remove_ctls[] = { 20331da177e4SLinus Torvalds /* Master/PCM controls on ac97 of Audigy has no effect */ 203421fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 203521fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 20361da177e4SLinus Torvalds "PCM Playback Switch", 20371da177e4SLinus Torvalds "PCM Playback Volume", 20381da177e4SLinus Torvalds "Master Playback Switch", 20391da177e4SLinus Torvalds "Master Playback Volume", 20401da177e4SLinus Torvalds "PCM Out Path & Mute", 20411da177e4SLinus Torvalds "Mono Output Select", 20421da177e4SLinus Torvalds /* remove unused AC97 capture controls */ 20431da177e4SLinus Torvalds "Capture Source", 20441da177e4SLinus Torvalds "Capture Switch", 20451da177e4SLinus Torvalds "Capture Volume", 20461da177e4SLinus Torvalds "Mic Select", 2047274b2000SMaciej S. Szmigiero "Headphone Playback Switch", 2048274b2000SMaciej S. Szmigiero "Headphone Playback Volume", 2049274b2000SMaciej S. Szmigiero "3D Control - Center", 2050274b2000SMaciej S. Szmigiero "3D Control - Depth", 2051274b2000SMaciej S. Szmigiero "3D Control - Switch", 20521da177e4SLinus Torvalds "Video Playback Switch", 20531da177e4SLinus Torvalds "Video Playback Volume", 20541da177e4SLinus Torvalds "Mic Playback Switch", 20551da177e4SLinus Torvalds "Mic Playback Volume", 2056274b2000SMaciej S. Szmigiero "External Amplifier", 20571da177e4SLinus Torvalds NULL 20581da177e4SLinus Torvalds }; 20596fddce26STakashi Iwai static const char * const audigy_rename_ctls[] = { 20601da177e4SLinus Torvalds /* use conventional names */ 20611da177e4SLinus Torvalds "Wave Playback Volume", "PCM Playback Volume", 20621da177e4SLinus Torvalds /* "Wave Capture Volume", "PCM Capture Volume", */ 20631da177e4SLinus Torvalds "Wave Master Playback Volume", "Master Playback Volume", 20641da177e4SLinus Torvalds "AMic Playback Volume", "Mic Playback Volume", 206552051942SMaciej S. Szmigiero "Master Mono Playback Switch", "Phone Output Playback Switch", 206652051942SMaciej S. Szmigiero "Master Mono Playback Volume", "Phone Output Playback Volume", 20671da177e4SLinus Torvalds NULL 20681da177e4SLinus Torvalds }; 20696fddce26STakashi Iwai static const char * const audigy_rename_ctls_i2c_adc[] = { 2070184c1e2cSJames Courtier-Dutton //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", 2071184c1e2cSJames Courtier-Dutton "Line Capture Volume", "Analog Mix Capture Volume", 2072184c1e2cSJames Courtier-Dutton "Wave Playback Volume", "OLD PCM Playback Volume", 2073184c1e2cSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 2074184c1e2cSJames Courtier-Dutton "AMic Playback Volume", "Old Mic Playback Volume", 2075eb41dab6SJames Courtier-Dutton "CD Capture Volume", "IEC958 Optical Capture Volume", 2076184c1e2cSJames Courtier-Dutton NULL 2077184c1e2cSJames Courtier-Dutton }; 20786fddce26STakashi Iwai static const char * const audigy_remove_ctls_i2c_adc[] = { 2079184c1e2cSJames Courtier-Dutton /* On the Audigy2 ZS Notebook 2080184c1e2cSJames Courtier-Dutton * Capture via WM8775 */ 2081184c1e2cSJames Courtier-Dutton "Mic Capture Volume", 2082184c1e2cSJames Courtier-Dutton "Analog Mix Capture Volume", 2083184c1e2cSJames Courtier-Dutton "Aux Capture Volume", 2084eb41dab6SJames Courtier-Dutton "IEC958 Optical Capture Volume", 2085184c1e2cSJames Courtier-Dutton NULL 2086184c1e2cSJames Courtier-Dutton }; 20876fddce26STakashi Iwai static const char * const audigy_remove_ctls_1361t_adc[] = { 208821fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 208921fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 209021fdddeaSJames Courtier-Dutton "PCM Playback Switch", 209121fdddeaSJames Courtier-Dutton "PCM Playback Volume", 209221fdddeaSJames Courtier-Dutton "Capture Source", 209321fdddeaSJames Courtier-Dutton "Capture Switch", 209421fdddeaSJames Courtier-Dutton "Capture Volume", 209521fdddeaSJames Courtier-Dutton "Mic Capture Volume", 209621fdddeaSJames Courtier-Dutton "Headphone Playback Switch", 209721fdddeaSJames Courtier-Dutton "Headphone Playback Volume", 209821fdddeaSJames Courtier-Dutton "3D Control - Center", 209921fdddeaSJames Courtier-Dutton "3D Control - Depth", 210021fdddeaSJames Courtier-Dutton "3D Control - Switch", 210121fdddeaSJames Courtier-Dutton "Line2 Playback Volume", 210221fdddeaSJames Courtier-Dutton "Line2 Capture Volume", 210321fdddeaSJames Courtier-Dutton NULL 210421fdddeaSJames Courtier-Dutton }; 21056fddce26STakashi Iwai static const char * const audigy_rename_ctls_1361t_adc[] = { 210621fdddeaSJames Courtier-Dutton "Master Playback Switch", "Master Capture Switch", 210721fdddeaSJames Courtier-Dutton "Master Playback Volume", "Master Capture Volume", 210821fdddeaSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 2109d355c82aSJaroslav Kysela "Beep Playback Switch", "Beep Capture Switch", 2110d355c82aSJaroslav Kysela "Beep Playback Volume", "Beep Capture Volume", 211121fdddeaSJames Courtier-Dutton "Phone Playback Switch", "Phone Capture Switch", 211221fdddeaSJames Courtier-Dutton "Phone Playback Volume", "Phone Capture Volume", 211321fdddeaSJames Courtier-Dutton "Mic Playback Switch", "Mic Capture Switch", 211421fdddeaSJames Courtier-Dutton "Mic Playback Volume", "Mic Capture Volume", 211521fdddeaSJames Courtier-Dutton "Line Playback Switch", "Line Capture Switch", 211621fdddeaSJames Courtier-Dutton "Line Playback Volume", "Line Capture Volume", 211721fdddeaSJames Courtier-Dutton "CD Playback Switch", "CD Capture Switch", 211821fdddeaSJames Courtier-Dutton "CD Playback Volume", "CD Capture Volume", 211921fdddeaSJames Courtier-Dutton "Aux Playback Switch", "Aux Capture Switch", 212021fdddeaSJames Courtier-Dutton "Aux Playback Volume", "Aux Capture Volume", 212121fdddeaSJames Courtier-Dutton "Video Playback Switch", "Video Capture Switch", 212221fdddeaSJames Courtier-Dutton "Video Playback Volume", "Video Capture Volume", 212352051942SMaciej S. Szmigiero "Master Mono Playback Switch", "Phone Output Playback Switch", 212452051942SMaciej S. Szmigiero "Master Mono Playback Volume", "Phone Output Playback Volume", 212521fdddeaSJames Courtier-Dutton NULL 212621fdddeaSJames Courtier-Dutton }; 21271da177e4SLinus Torvalds 21282b637da5SLee Revell if (emu->card_capabilities->ac97_chip) { 2129eb4698f3STakashi Iwai struct snd_ac97_bus *pbus; 2130eb4698f3STakashi Iwai struct snd_ac97_template ac97; 213151055da5STakashi Iwai static const struct snd_ac97_bus_ops ops = { 21321da177e4SLinus Torvalds .write = snd_emu10k1_ac97_write, 21331da177e4SLinus Torvalds .read = snd_emu10k1_ac97_read, 21341da177e4SLinus Torvalds }; 21351da177e4SLinus Torvalds 213612bda107STakashi Iwai err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus); 213712bda107STakashi Iwai if (err < 0) 21381da177e4SLinus Torvalds return err; 21391da177e4SLinus Torvalds pbus->no_vra = 1; /* we don't need VRA */ 21401da177e4SLinus Torvalds 21411da177e4SLinus Torvalds memset(&ac97, 0, sizeof(ac97)); 21421da177e4SLinus Torvalds ac97.private_data = emu; 21431da177e4SLinus Torvalds ac97.private_free = snd_emu10k1_mixer_free_ac97; 21441da177e4SLinus Torvalds ac97.scaps = AC97_SCAP_NO_SPDIF; 214512bda107STakashi Iwai err = snd_ac97_mixer(pbus, &ac97, &emu->ac97); 214612bda107STakashi Iwai if (err < 0) { 2147b1508693STakashi Iwai if (emu->card_capabilities->ac97_chip == 1) 21481da177e4SLinus Torvalds return err; 21496f002b02STakashi Iwai dev_info(emu->card->dev, 21506f002b02STakashi Iwai "AC97 is optional on this board\n"); 21516f002b02STakashi Iwai dev_info(emu->card->dev, 21526f002b02STakashi Iwai "Proceeding without ac97 mixers...\n"); 2153b1508693STakashi Iwai snd_device_free(emu->card, pbus); 2154b1508693STakashi Iwai goto no_ac97; /* FIXME: get rid of ugly gotos.. */ 2155b1508693STakashi Iwai } 21561da177e4SLinus Torvalds if (emu->audigy) { 21571da177e4SLinus Torvalds /* set master volume to 0 dB */ 21584d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); 21591da177e4SLinus Torvalds /* set capture source to mic */ 21604d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); 216152051942SMaciej S. Szmigiero /* set mono output (TAD) to mic */ 216252051942SMaciej S. Szmigiero snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE, 216352051942SMaciej S. Szmigiero 0x0200, 0x0200); 216421fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 216521fdddeaSJames Courtier-Dutton c = audigy_remove_ctls_1361t_adc; 216621fdddeaSJames Courtier-Dutton else 21671da177e4SLinus Torvalds c = audigy_remove_ctls; 21681da177e4SLinus Torvalds } else { 21691da177e4SLinus Torvalds /* 21701da177e4SLinus Torvalds * Credits for cards based on STAC9758: 21711da177e4SLinus Torvalds * James Courtier-Dutton <James@superbug.demon.co.uk> 21721da177e4SLinus Torvalds * Voluspa <voluspa@comhem.se> 21731da177e4SLinus Torvalds */ 21741da177e4SLinus Torvalds if (emu->ac97->id == AC97_ID_STAC9758) { 21751da177e4SLinus Torvalds emu->rear_ac97 = 1; 21761da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); 21772594d960SRolf Stefan Wilke snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); 2178b6a48404SRaymond Yau remove_ctl(card,"Front Playback Volume"); 2179b6a48404SRaymond Yau remove_ctl(card,"Front Playback Switch"); 21801da177e4SLinus Torvalds } 21811da177e4SLinus Torvalds /* remove unused AC97 controls */ 21824d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); 21834d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); 21841da177e4SLinus Torvalds c = emu10k1_remove_ctls; 21851da177e4SLinus Torvalds } 21861da177e4SLinus Torvalds for (; *c; c++) 21871da177e4SLinus Torvalds remove_ctl(card, *c); 2188184c1e2cSJames Courtier-Dutton } else if (emu->card_capabilities->i2c_adc) { 2189184c1e2cSJames Courtier-Dutton c = audigy_remove_ctls_i2c_adc; 2190184c1e2cSJames Courtier-Dutton for (; *c; c++) 2191184c1e2cSJames Courtier-Dutton remove_ctl(card, *c); 21921da177e4SLinus Torvalds } else { 2193f12aa40cSTakashi Iwai no_ac97: 21942b637da5SLee Revell if (emu->card_capabilities->ecard) 21951da177e4SLinus Torvalds strcpy(emu->card->mixername, "EMU APS"); 21961da177e4SLinus Torvalds else if (emu->audigy) 21971da177e4SLinus Torvalds strcpy(emu->card->mixername, "SB Audigy"); 21981da177e4SLinus Torvalds else 21991da177e4SLinus Torvalds strcpy(emu->card->mixername, "Emu10k1"); 22001da177e4SLinus Torvalds } 22011da177e4SLinus Torvalds 22021da177e4SLinus Torvalds if (emu->audigy) 220321fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 220421fdddeaSJames Courtier-Dutton c = audigy_rename_ctls_1361t_adc; 2205184c1e2cSJames Courtier-Dutton else if (emu->card_capabilities->i2c_adc) 2206184c1e2cSJames Courtier-Dutton c = audigy_rename_ctls_i2c_adc; 220721fdddeaSJames Courtier-Dutton else 22081da177e4SLinus Torvalds c = audigy_rename_ctls; 22091da177e4SLinus Torvalds else 22101da177e4SLinus Torvalds c = emu10k1_rename_ctls; 22111da177e4SLinus Torvalds for (; *c; c += 2) 22121da177e4SLinus Torvalds rename_ctl(card, c[0], c[1]); 221321fdddeaSJames Courtier-Dutton 2214e217b960SRaymond Yau if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */ 2215e217b960SRaymond Yau remove_ctl(card, "Center Playback Volume"); 2216e217b960SRaymond Yau remove_ctl(card, "LFE Playback Volume"); 2217e217b960SRaymond Yau remove_ctl(card, "Wave Center Playback Volume"); 2218e217b960SRaymond Yau remove_ctl(card, "Wave LFE Playback Volume"); 2219e217b960SRaymond Yau } 2220e3b9bc0eSJames Courtier-Dutton if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ 2221e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); 2222e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); 2223e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); 2224e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); 2225e3b9bc0eSJames Courtier-Dutton } 222612bda107STakashi Iwai kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu); 222712bda107STakashi Iwai if (!kctl) 22281da177e4SLinus Torvalds return -ENOMEM; 222967ed4161SClemens Ladisch kctl->id.device = pcm_device; 223012bda107STakashi Iwai err = snd_ctl_add(card, kctl); 223112bda107STakashi Iwai if (err) 22321da177e4SLinus Torvalds return err; 223312bda107STakashi Iwai kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu); 223412bda107STakashi Iwai if (!kctl) 22351da177e4SLinus Torvalds return -ENOMEM; 223667ed4161SClemens Ladisch kctl->id.device = pcm_device; 223712bda107STakashi Iwai err = snd_ctl_add(card, kctl); 223812bda107STakashi Iwai if (err) 22391da177e4SLinus Torvalds return err; 224012bda107STakashi Iwai kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu); 224112bda107STakashi Iwai if (!kctl) 22421da177e4SLinus Torvalds return -ENOMEM; 224367ed4161SClemens Ladisch kctl->id.device = pcm_device; 224412bda107STakashi Iwai err = snd_ctl_add(card, kctl); 224512bda107STakashi Iwai if (err) 22461da177e4SLinus Torvalds return err; 22471da177e4SLinus Torvalds 224812bda107STakashi Iwai kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu); 224912bda107STakashi Iwai if (!kctl) 22501da177e4SLinus Torvalds return -ENOMEM; 225167ed4161SClemens Ladisch kctl->id.device = multi_device; 225212bda107STakashi Iwai err = snd_ctl_add(card, kctl); 225312bda107STakashi Iwai if (err) 22541da177e4SLinus Torvalds return err; 22551da177e4SLinus Torvalds 225612bda107STakashi Iwai kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu); 225712bda107STakashi Iwai if (!kctl) 22581da177e4SLinus Torvalds return -ENOMEM; 225967ed4161SClemens Ladisch kctl->id.device = multi_device; 226012bda107STakashi Iwai err = snd_ctl_add(card, kctl); 226112bda107STakashi Iwai if (err) 22621da177e4SLinus Torvalds return err; 22631da177e4SLinus Torvalds 226412bda107STakashi Iwai kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu); 226512bda107STakashi Iwai if (!kctl) 22661da177e4SLinus Torvalds return -ENOMEM; 226767ed4161SClemens Ladisch kctl->id.device = multi_device; 226812bda107STakashi Iwai err = snd_ctl_add(card, kctl); 226912bda107STakashi Iwai if (err) 22701da177e4SLinus Torvalds return err; 22711da177e4SLinus Torvalds 2272a8661af5SOswald Buddenhagen if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) { 22731da177e4SLinus Torvalds /* sb live! and audigy */ 227412bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu); 227512bda107STakashi Iwai if (!kctl) 22761da177e4SLinus Torvalds return -ENOMEM; 22775549d549SClemens Ladisch if (!emu->audigy) 22785549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 227912bda107STakashi Iwai err = snd_ctl_add(card, kctl); 228012bda107STakashi Iwai if (err) 22811da177e4SLinus Torvalds return err; 228212bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu); 228312bda107STakashi Iwai if (!kctl) 22841da177e4SLinus Torvalds return -ENOMEM; 22855549d549SClemens Ladisch if (!emu->audigy) 22865549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 228712bda107STakashi Iwai err = snd_ctl_add(card, kctl); 228812bda107STakashi Iwai if (err) 22891da177e4SLinus Torvalds return err; 22901da177e4SLinus Torvalds } 22911da177e4SLinus Torvalds 2292190d2c46SJames Courtier-Dutton if (emu->card_capabilities->emu_model) { 229319b99fbaSJames Courtier-Dutton ; /* Disable the snd_audigy_spdif_shared_spdif */ 229419b99fbaSJames Courtier-Dutton } else if (emu->audigy) { 229512bda107STakashi Iwai kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu); 229612bda107STakashi Iwai if (!kctl) 22971da177e4SLinus Torvalds return -ENOMEM; 229812bda107STakashi Iwai err = snd_ctl_add(card, kctl); 229912bda107STakashi Iwai if (err) 23001da177e4SLinus Torvalds return err; 2301001f7589SJames Courtier-Dutton #if 0 230212bda107STakashi Iwai kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu); 230312bda107STakashi Iwai if (!kctl) 23041da177e4SLinus Torvalds return -ENOMEM; 230512bda107STakashi Iwai err = snd_ctl_add(card, kctl); 230612bda107STakashi Iwai if (err) 23071da177e4SLinus Torvalds return err; 2308001f7589SJames Courtier-Dutton #endif 23092b637da5SLee Revell } else if (! emu->card_capabilities->ecard) { 23101da177e4SLinus Torvalds /* sb live! */ 231112bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu); 231212bda107STakashi Iwai if (!kctl) 23131da177e4SLinus Torvalds return -ENOMEM; 231412bda107STakashi Iwai err = snd_ctl_add(card, kctl); 231512bda107STakashi Iwai if (err) 23161da177e4SLinus Torvalds return err; 23171da177e4SLinus Torvalds } 23182b637da5SLee Revell if (emu->card_capabilities->ca0151_chip) { /* P16V */ 231912bda107STakashi Iwai err = snd_p16v_mixer(emu); 232012bda107STakashi Iwai if (err) 23211da177e4SLinus Torvalds return err; 23221da177e4SLinus Torvalds } 23231da177e4SLinus Torvalds 23241fc710f0SOswald Buddenhagen if (emu->card_capabilities->emu_model) { 23251fc710f0SOswald Buddenhagen unsigned i, emu_idx = emu1010_idx(emu); 23261fc710f0SOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 23271fc710f0SOswald Buddenhagen &emu1010_routing_info[emu_idx]; 232897f1582eSOswald Buddenhagen const struct snd_emu1010_pads_info *emu_pi = &emu1010_pads_info[emu_idx]; 23291fc710f0SOswald Buddenhagen 23301fc710f0SOswald Buddenhagen for (i = 0; i < emu_ri->n_ins; i++) 23311fc710f0SOswald Buddenhagen emu->emu1010.input_source[i] = 23321fc710f0SOswald Buddenhagen emu1010_map_source(emu_ri, emu_ri->in_dflts[i]); 23331fc710f0SOswald Buddenhagen for (i = 0; i < emu_ri->n_outs; i++) 23341fc710f0SOswald Buddenhagen emu->emu1010.output_source[i] = 23351fc710f0SOswald Buddenhagen emu1010_map_source(emu_ri, emu_ri->out_dflts[i]); 23361fc710f0SOswald Buddenhagen snd_emu1010_apply_sources(emu); 23371fc710f0SOswald Buddenhagen 23381c02e366SCtirad Fertr err = snd_ctl_add(card, 2339*13598862SOswald Buddenhagen snd_ctl_new1(&snd_emu1010_clock_source, emu)); 2340*13598862SOswald Buddenhagen if (err < 0) 2341*13598862SOswald Buddenhagen return err; 2342*13598862SOswald Buddenhagen err = snd_ctl_add(card, 2343*13598862SOswald Buddenhagen snd_ctl_new1(&snd_emu1010_clock_fallback, emu)); 23441c02e366SCtirad Fertr if (err < 0) 23451c02e366SCtirad Fertr return err; 234697f1582eSOswald Buddenhagen 234797f1582eSOswald Buddenhagen err = add_ctls(emu, &emu1010_adc_pads_ctl, 234897f1582eSOswald Buddenhagen emu_pi->adc_ctls, emu_pi->n_adc_ctls); 234997f1582eSOswald Buddenhagen if (err < 0) 235097f1582eSOswald Buddenhagen return err; 235197f1582eSOswald Buddenhagen err = add_ctls(emu, &emu1010_dac_pads_ctl, 235297f1582eSOswald Buddenhagen emu_pi->dac_ctls, emu_pi->n_dac_ctls); 235397f1582eSOswald Buddenhagen if (err < 0) 235497f1582eSOswald Buddenhagen return err; 235597f1582eSOswald Buddenhagen 23566f3609f8SOswald Buddenhagen if (!emu->card_capabilities->no_adat) { 235799dcab46SMichael Gernoth err = snd_ctl_add(card, 235899dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_out, emu)); 235999dcab46SMichael Gernoth if (err < 0) 236099dcab46SMichael Gernoth return err; 236199dcab46SMichael Gernoth err = snd_ctl_add(card, 236299dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_in, emu)); 236399dcab46SMichael Gernoth if (err < 0) 236499dcab46SMichael Gernoth return err; 23656f3609f8SOswald Buddenhagen } 23661c02e366SCtirad Fertr 236797f1582eSOswald Buddenhagen err = add_emu1010_source_mixers(emu); 236899dcab46SMichael Gernoth if (err < 0) 236999dcab46SMichael Gernoth return err; 23709f4bd5ddSJames Courtier-Dutton } 23719f4bd5ddSJames Courtier-Dutton 2372184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 2373184c1e2cSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); 2374184c1e2cSJames Courtier-Dutton if (err < 0) 2375184c1e2cSJames Courtier-Dutton return err; 2376184c1e2cSJames Courtier-Dutton 2377536438f1SOswald Buddenhagen err = add_ctls(emu, &i2c_volume_ctl, 2378536438f1SOswald Buddenhagen snd_audigy_i2c_volume_ctls, 2379536438f1SOswald Buddenhagen ARRAY_SIZE(snd_audigy_i2c_volume_ctls)); 2380184c1e2cSJames Courtier-Dutton if (err < 0) 2381184c1e2cSJames Courtier-Dutton return err; 2382184c1e2cSJames Courtier-Dutton } 2383184c1e2cSJames Courtier-Dutton 238416950e09STakashi Iwai if (emu->card_capabilities->ac97_chip && emu->audigy) { 238516950e09STakashi Iwai err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost, 238616950e09STakashi Iwai emu)); 238716950e09STakashi Iwai if (err < 0) 238816950e09STakashi Iwai return err; 238916950e09STakashi Iwai } 239016950e09STakashi Iwai 23911da177e4SLinus Torvalds return 0; 23921da177e4SLinus Torvalds } 2393