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 147dc39bb3eSOswald Buddenhagen #define EMU1010_COMMON_TEXTS \ 148dc39bb3eSOswald Buddenhagen "Silence", \ 149dc39bb3eSOswald Buddenhagen PAIR_TEXTS("Dock Mic", "A", "B"), \ 150dc39bb3eSOswald Buddenhagen LR_TEXTS("Dock ADC1"), \ 151dc39bb3eSOswald Buddenhagen LR_TEXTS("Dock ADC2"), \ 152dc39bb3eSOswald Buddenhagen LR_TEXTS("Dock ADC3"), \ 153dc39bb3eSOswald Buddenhagen LR_TEXTS("0202 ADC"), \ 154dc39bb3eSOswald Buddenhagen LR_TEXTS("1010 SPDIF"), \ 155dc39bb3eSOswald Buddenhagen ADAT_TEXTS("1010 ") 156dc39bb3eSOswald Buddenhagen 157dc39bb3eSOswald Buddenhagen static const char * const emu1010_src_texts[] = { 158dc39bb3eSOswald Buddenhagen EMU1010_COMMON_TEXTS, 159dc39bb3eSOswald Buddenhagen DSP_TEXTS, 1609f4bd5ddSJames Courtier-Dutton }; 1619f4bd5ddSJames Courtier-Dutton 162dc39bb3eSOswald Buddenhagen static const unsigned short emu1010_src_regs[] = { 163dc39bb3eSOswald Buddenhagen EMU_SRC_SILENCE, 164dc39bb3eSOswald Buddenhagen PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B), 165dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC1), 166dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC2), 167dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC3), 168dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_HAMOA_ADC), 169dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_HANA_SPDIF), 170dc39bb3eSOswald Buddenhagen ADAT_REGS(EMU_SRC_HANA_ADAT), 171dc39bb3eSOswald Buddenhagen EMU32_SRC_REGS, 172dc39bb3eSOswald Buddenhagen }; 173dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_src_regs) == ARRAY_SIZE(emu1010_src_texts)); 174dc39bb3eSOswald Buddenhagen 1751c02e366SCtirad Fertr /* 1616(m) cardbus */ 176dc39bb3eSOswald Buddenhagen 177dc39bb3eSOswald Buddenhagen #define EMU1616_COMMON_TEXTS \ 178dc39bb3eSOswald Buddenhagen "Silence", \ 179dc39bb3eSOswald Buddenhagen PAIR_TEXTS("Mic", "A", "B"), \ 180dc39bb3eSOswald Buddenhagen LR_TEXTS("ADC1"), \ 181dc39bb3eSOswald Buddenhagen LR_TEXTS("ADC2"), \ 182dc39bb3eSOswald Buddenhagen LR_TEXTS("SPDIF"), \ 183dc39bb3eSOswald Buddenhagen ADAT_TEXTS("") 184dc39bb3eSOswald Buddenhagen 185dc39bb3eSOswald Buddenhagen static const char * const emu1616_src_texts[] = { 186dc39bb3eSOswald Buddenhagen EMU1616_COMMON_TEXTS, 187dc39bb3eSOswald Buddenhagen DSP_TEXTS, 188dc39bb3eSOswald Buddenhagen }; 189dc39bb3eSOswald Buddenhagen 1909b00a1e9SOswald Buddenhagen static const unsigned short emu1616_src_regs[] = { 1911c02e366SCtirad Fertr EMU_SRC_SILENCE, 192dc39bb3eSOswald Buddenhagen PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B), 193dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC1), 194dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC2), 195dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_MDOCK_SPDIF), 196dc39bb3eSOswald Buddenhagen ADAT_REGS(EMU_SRC_MDOCK_ADAT), 197dc39bb3eSOswald Buddenhagen EMU32_SRC_REGS, 1981c02e366SCtirad Fertr }; 199dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_src_regs) == ARRAY_SIZE(emu1616_src_texts)); 2001c02e366SCtirad Fertr 20113d45709SPavel Hofman /* 20213d45709SPavel Hofman * Data destinations - physical EMU outputs. 20313d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 20413d45709SPavel Hofman */ 205536438f1SOswald Buddenhagen 206536438f1SOswald Buddenhagen #define LR_CTLS(base) LR_PS(base, " Playback Enum") 207536438f1SOswald Buddenhagen #define ADAT_CTLS(pfx) ADAT_PS(pfx, " Playback Enum") 208536438f1SOswald Buddenhagen 209536438f1SOswald Buddenhagen static const char * const emu1010_output_texts[] = { 210536438f1SOswald Buddenhagen LR_CTLS("Dock DAC1"), 211536438f1SOswald Buddenhagen LR_CTLS("Dock DAC2"), 212536438f1SOswald Buddenhagen LR_CTLS("Dock DAC3"), 213536438f1SOswald Buddenhagen LR_CTLS("Dock DAC4"), 214536438f1SOswald Buddenhagen LR_CTLS("Dock Phones"), 215536438f1SOswald Buddenhagen LR_CTLS("Dock SPDIF"), 216536438f1SOswald Buddenhagen LR_CTLS("0202 DAC"), 217536438f1SOswald Buddenhagen LR_CTLS("1010 SPDIF"), 218536438f1SOswald Buddenhagen ADAT_CTLS("1010 "), 2199f4bd5ddSJames Courtier-Dutton }; 2209f4bd5ddSJames Courtier-Dutton 221536438f1SOswald Buddenhagen static const unsigned short emu1010_output_dst[] = { 222536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC1), 223536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC2), 224536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC3), 225536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC4), 226536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_PHONES), 227536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_SPDIF), 228536438f1SOswald Buddenhagen LR_REGS(EMU_DST_HAMOA_DAC), 229536438f1SOswald Buddenhagen LR_REGS(EMU_DST_HANA_SPDIF), 230536438f1SOswald Buddenhagen ADAT_REGS(EMU_DST_HANA_ADAT), 2311c02e366SCtirad Fertr }; 232536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dst) == ARRAY_SIZE(emu1010_output_texts)); 233536438f1SOswald Buddenhagen 2341fc710f0SOswald Buddenhagen static const unsigned short emu1010_output_dflt[] = { 2351fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 2361fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, 2371fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, 2381fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, 2391fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 2401fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 2411fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 2421fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 2431fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, 2441fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, 2451fc710f0SOswald Buddenhagen }; 2461fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dflt) == ARRAY_SIZE(emu1010_output_dst)); 2471fc710f0SOswald Buddenhagen 248536438f1SOswald Buddenhagen /* 1616(m) cardbus */ 249536438f1SOswald Buddenhagen 250536438f1SOswald Buddenhagen static const char * const snd_emu1616_output_texts[] = { 251536438f1SOswald Buddenhagen LR_CTLS("Dock DAC1"), 252536438f1SOswald Buddenhagen LR_CTLS("Dock DAC2"), 253536438f1SOswald Buddenhagen LR_CTLS("Dock DAC3"), 254536438f1SOswald Buddenhagen LR_CTLS("Dock SPDIF"), 255536438f1SOswald Buddenhagen ADAT_CTLS("Dock "), 256536438f1SOswald Buddenhagen LR_CTLS("Mana DAC"), 257536438f1SOswald Buddenhagen }; 258536438f1SOswald Buddenhagen 259536438f1SOswald Buddenhagen static const unsigned short emu1616_output_dst[] = { 260536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC1), 261536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC2), 262536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC3), 263536438f1SOswald Buddenhagen LR_REGS(EMU_DST_MDOCK_SPDIF), 264536438f1SOswald Buddenhagen ADAT_REGS(EMU_DST_MDOCK_ADAT), 265536438f1SOswald Buddenhagen EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT, 266536438f1SOswald Buddenhagen }; 267536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dst) == ARRAY_SIZE(snd_emu1616_output_texts)); 2681c02e366SCtirad Fertr 2691fc710f0SOswald Buddenhagen static const unsigned short emu1616_output_dflt[] = { 2701fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 2711fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, 2721fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, 2731fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 2741fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, 2751fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, 2761fc710f0SOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, 2771fc710f0SOswald Buddenhagen }; 2781fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dflt) == ARRAY_SIZE(emu1616_output_dst)); 2791fc710f0SOswald Buddenhagen 28013d45709SPavel Hofman /* 281a869057cSOswald Buddenhagen * Data destinations - FPGA outputs going to Alice2 (Audigy) for 28213d45709SPavel Hofman * capture (EMU32 + I2S links) 28313d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 28413d45709SPavel Hofman */ 285536438f1SOswald Buddenhagen 286536438f1SOswald Buddenhagen static const char * const emu1010_input_texts[] = { 287536438f1SOswald Buddenhagen "DSP 0 Capture Enum", 288536438f1SOswald Buddenhagen "DSP 1 Capture Enum", 289536438f1SOswald Buddenhagen "DSP 2 Capture Enum", 290536438f1SOswald Buddenhagen "DSP 3 Capture Enum", 291536438f1SOswald Buddenhagen "DSP 4 Capture Enum", 292536438f1SOswald Buddenhagen "DSP 5 Capture Enum", 293536438f1SOswald Buddenhagen "DSP 6 Capture Enum", 294536438f1SOswald Buddenhagen "DSP 7 Capture Enum", 295536438f1SOswald Buddenhagen "DSP 8 Capture Enum", 296536438f1SOswald Buddenhagen "DSP 9 Capture Enum", 297536438f1SOswald Buddenhagen "DSP A Capture Enum", 298536438f1SOswald Buddenhagen "DSP B Capture Enum", 299536438f1SOswald Buddenhagen "DSP C Capture Enum", 300536438f1SOswald Buddenhagen "DSP D Capture Enum", 301536438f1SOswald Buddenhagen "DSP E Capture Enum", 302536438f1SOswald Buddenhagen "DSP F Capture Enum", 303536438f1SOswald Buddenhagen /* These exist only on rev1 EMU1010 cards. */ 304536438f1SOswald Buddenhagen "DSP 10 Capture Enum", 305536438f1SOswald Buddenhagen "DSP 11 Capture Enum", 306536438f1SOswald Buddenhagen "DSP 12 Capture Enum", 307536438f1SOswald Buddenhagen "DSP 13 Capture Enum", 308536438f1SOswald Buddenhagen "DSP 14 Capture Enum", 309536438f1SOswald Buddenhagen "DSP 15 Capture Enum", 310536438f1SOswald Buddenhagen }; 311536438f1SOswald Buddenhagen 3129b00a1e9SOswald Buddenhagen static const unsigned short emu1010_input_dst[] = { 3139f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_0, 3149f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_1, 3159f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_2, 3169f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_3, 3179f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_4, 3189f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_5, 3199f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_6, 3209f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_7, 3219f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_8, 3229f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_9, 3239f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_A, 3249f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_B, 3259f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_C, 3269f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_D, 3279f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_E, 3289f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_F, 329a869057cSOswald Buddenhagen /* These exist only on rev1 EMU1010 cards. */ 3309f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_LEFT, 3319f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_RIGHT, 3329f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_LEFT, 3339f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_RIGHT, 3349f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_LEFT, 3359f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_RIGHT, 3369f4bd5ddSJames Courtier-Dutton }; 337536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts)); 3389f4bd5ddSJames Courtier-Dutton 3391fc710f0SOswald Buddenhagen static const unsigned short emu1010_input_dflt[] = { 3401fc710f0SOswald Buddenhagen EMU_SRC_DOCK_MIC_A1, 3411fc710f0SOswald Buddenhagen EMU_SRC_DOCK_MIC_B1, 3421fc710f0SOswald Buddenhagen EMU_SRC_HAMOA_ADC_LEFT1, 3431fc710f0SOswald Buddenhagen EMU_SRC_HAMOA_ADC_RIGHT1, 3441fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC1_LEFT1, 3451fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC1_RIGHT1, 3461fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC2_LEFT1, 3471fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC2_RIGHT1, 3481fc710f0SOswald Buddenhagen /* Pavel Hofman - setting defaults for all capture channels. 3491fc710f0SOswald Buddenhagen * Defaults only, users will set their own values anyways, let's 3501fc710f0SOswald Buddenhagen * just copy/paste. */ 3511fc710f0SOswald Buddenhagen EMU_SRC_DOCK_MIC_A1, 3521fc710f0SOswald Buddenhagen EMU_SRC_DOCK_MIC_B1, 3531fc710f0SOswald Buddenhagen EMU_SRC_HAMOA_ADC_LEFT1, 3541fc710f0SOswald Buddenhagen EMU_SRC_HAMOA_ADC_RIGHT1, 3551fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC1_LEFT1, 3561fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC1_RIGHT1, 3571fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC2_LEFT1, 3581fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC2_RIGHT1, 3591fc710f0SOswald Buddenhagen 3601fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC1_LEFT1, 3611fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC1_RIGHT1, 3621fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC2_LEFT1, 3631fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC2_RIGHT1, 3641fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC3_LEFT1, 3651fc710f0SOswald Buddenhagen EMU_SRC_DOCK_ADC3_RIGHT1, 3661fc710f0SOswald Buddenhagen }; 3671fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dflt) == ARRAY_SIZE(emu1010_input_dst)); 3681fc710f0SOswald Buddenhagen 369511cbe8fSOswald Buddenhagen struct snd_emu1010_routing_info { 370511cbe8fSOswald Buddenhagen const char * const *src_texts; 371*97f1582eSOswald Buddenhagen const char * const *out_texts; 372511cbe8fSOswald Buddenhagen const unsigned short *src_regs; 373511cbe8fSOswald Buddenhagen const unsigned short *out_regs; 374511cbe8fSOswald Buddenhagen const unsigned short *in_regs; 3751fc710f0SOswald Buddenhagen const unsigned short *out_dflts; 3761fc710f0SOswald Buddenhagen const unsigned short *in_dflts; 377511cbe8fSOswald Buddenhagen unsigned n_srcs; 378511cbe8fSOswald Buddenhagen unsigned n_outs; 379511cbe8fSOswald Buddenhagen unsigned n_ins; 380511cbe8fSOswald Buddenhagen }; 381511cbe8fSOswald Buddenhagen 382511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info emu1010_routing_info[] = { 383511cbe8fSOswald Buddenhagen { 384511cbe8fSOswald Buddenhagen .src_regs = emu1010_src_regs, 385511cbe8fSOswald Buddenhagen .src_texts = emu1010_src_texts, 386511cbe8fSOswald Buddenhagen .n_srcs = ARRAY_SIZE(emu1010_src_texts), 387511cbe8fSOswald Buddenhagen 3881fc710f0SOswald Buddenhagen .out_dflts = emu1010_output_dflt, 389511cbe8fSOswald Buddenhagen .out_regs = emu1010_output_dst, 390*97f1582eSOswald Buddenhagen .out_texts = emu1010_output_texts, 391511cbe8fSOswald Buddenhagen .n_outs = ARRAY_SIZE(emu1010_output_dst), 392511cbe8fSOswald Buddenhagen 3931fc710f0SOswald Buddenhagen .in_dflts = emu1010_input_dflt, 394511cbe8fSOswald Buddenhagen .in_regs = emu1010_input_dst, 395511cbe8fSOswald Buddenhagen .n_ins = ARRAY_SIZE(emu1010_input_dst), 396511cbe8fSOswald Buddenhagen }, 397511cbe8fSOswald Buddenhagen { 398511cbe8fSOswald Buddenhagen /* 1616(m) cardbus */ 399511cbe8fSOswald Buddenhagen .src_regs = emu1616_src_regs, 400511cbe8fSOswald Buddenhagen .src_texts = emu1616_src_texts, 401511cbe8fSOswald Buddenhagen .n_srcs = ARRAY_SIZE(emu1616_src_texts), 402511cbe8fSOswald Buddenhagen 4031fc710f0SOswald Buddenhagen .out_dflts = emu1616_output_dflt, 404511cbe8fSOswald Buddenhagen .out_regs = emu1616_output_dst, 405*97f1582eSOswald Buddenhagen .out_texts = snd_emu1616_output_texts, 406511cbe8fSOswald Buddenhagen .n_outs = ARRAY_SIZE(emu1616_output_dst), 407511cbe8fSOswald Buddenhagen 4081fc710f0SOswald Buddenhagen .in_dflts = emu1010_input_dflt, 409511cbe8fSOswald Buddenhagen .in_regs = emu1010_input_dst, 410511cbe8fSOswald Buddenhagen .n_ins = ARRAY_SIZE(emu1010_input_dst) - 6, 411511cbe8fSOswald Buddenhagen }, 412511cbe8fSOswald Buddenhagen }; 413511cbe8fSOswald Buddenhagen 414511cbe8fSOswald Buddenhagen static unsigned emu1010_idx(struct snd_emu10k1 *emu) 415511cbe8fSOswald Buddenhagen { 416511cbe8fSOswald Buddenhagen if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 417511cbe8fSOswald Buddenhagen return 1; 418511cbe8fSOswald Buddenhagen else 419511cbe8fSOswald Buddenhagen return 0; 420511cbe8fSOswald Buddenhagen } 421511cbe8fSOswald Buddenhagen 422511cbe8fSOswald Buddenhagen static void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu, 423511cbe8fSOswald Buddenhagen int channel, int src) 424511cbe8fSOswald Buddenhagen { 425511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 426511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 427511cbe8fSOswald Buddenhagen 428511cbe8fSOswald Buddenhagen snd_emu1010_fpga_link_dst_src_write(emu, 429511cbe8fSOswald Buddenhagen emu_ri->out_regs[channel], emu_ri->src_regs[src]); 430511cbe8fSOswald Buddenhagen } 431511cbe8fSOswald Buddenhagen 432511cbe8fSOswald Buddenhagen static void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu, 433511cbe8fSOswald Buddenhagen int channel, int src) 434511cbe8fSOswald Buddenhagen { 435511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 436511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 437511cbe8fSOswald Buddenhagen 438511cbe8fSOswald Buddenhagen snd_emu1010_fpga_link_dst_src_write(emu, 439511cbe8fSOswald Buddenhagen emu_ri->in_regs[channel], emu_ri->src_regs[src]); 440511cbe8fSOswald Buddenhagen } 441511cbe8fSOswald Buddenhagen 4421fc710f0SOswald Buddenhagen static void snd_emu1010_apply_sources(struct snd_emu10k1 *emu) 4431fc710f0SOswald Buddenhagen { 4441fc710f0SOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 4451fc710f0SOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 4461fc710f0SOswald Buddenhagen 4471fc710f0SOswald Buddenhagen for (unsigned i = 0; i < emu_ri->n_outs; i++) 4481fc710f0SOswald Buddenhagen snd_emu1010_output_source_apply( 4491fc710f0SOswald Buddenhagen emu, i, emu->emu1010.output_source[i]); 4501fc710f0SOswald Buddenhagen for (unsigned i = 0; i < emu_ri->n_ins; i++) 4511fc710f0SOswald Buddenhagen snd_emu1010_input_source_apply( 4521fc710f0SOswald Buddenhagen emu, i, emu->emu1010.input_source[i]); 4531fc710f0SOswald Buddenhagen } 4541fc710f0SOswald Buddenhagen 4551fc710f0SOswald Buddenhagen static u8 emu1010_map_source(const struct snd_emu1010_routing_info *emu_ri, 4561fc710f0SOswald Buddenhagen unsigned val) 4571fc710f0SOswald Buddenhagen { 4581fc710f0SOswald Buddenhagen for (unsigned i = 0; i < emu_ri->n_srcs; i++) 4591fc710f0SOswald Buddenhagen if (val == emu_ri->src_regs[i]) 4601fc710f0SOswald Buddenhagen return i; 4611fc710f0SOswald Buddenhagen return 0; 4621fc710f0SOswald Buddenhagen } 4631fc710f0SOswald Buddenhagen 4641c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, 4651c02e366SCtirad Fertr struct snd_ctl_elem_info *uinfo) 4669f4bd5ddSJames Courtier-Dutton { 4671c02e366SCtirad Fertr struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 468511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 469511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 4701c02e366SCtirad Fertr 471511cbe8fSOswald Buddenhagen return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts); 4729f4bd5ddSJames Courtier-Dutton } 4739f4bd5ddSJames Courtier-Dutton 4749f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, 4759f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4769f4bd5ddSJames Courtier-Dutton { 4779f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 478511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 479511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 480511cbe8fSOswald Buddenhagen unsigned channel = kcontrol->private_value; 4819f4bd5ddSJames Courtier-Dutton 482511cbe8fSOswald Buddenhagen if (channel >= emu_ri->n_outs) 48374415a36SJames Courtier-Dutton return -EINVAL; 4849f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; 4859f4bd5ddSJames Courtier-Dutton return 0; 4869f4bd5ddSJames Courtier-Dutton } 4879f4bd5ddSJames Courtier-Dutton 4889f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, 4899f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4909f4bd5ddSJames Courtier-Dutton { 4919f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 492511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 493511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 494511cbe8fSOswald Buddenhagen unsigned val = ucontrol->value.enumerated.item[0]; 495511cbe8fSOswald Buddenhagen unsigned channel = kcontrol->private_value; 496511cbe8fSOswald Buddenhagen int change; 4979f4bd5ddSJames Courtier-Dutton 498511cbe8fSOswald Buddenhagen if (val >= emu_ri->n_srcs) 499aa299d01STakashi Iwai return -EINVAL; 500511cbe8fSOswald Buddenhagen if (channel >= emu_ri->n_outs) 50174415a36SJames Courtier-Dutton return -EINVAL; 502511cbe8fSOswald Buddenhagen change = (emu->emu1010.output_source[channel] != val); 503511cbe8fSOswald Buddenhagen if (change) { 504aa299d01STakashi Iwai emu->emu1010.output_source[channel] = val; 505511cbe8fSOswald Buddenhagen snd_emu1010_output_source_apply(emu, channel, val); 506511cbe8fSOswald Buddenhagen } 507511cbe8fSOswald Buddenhagen return change; 5089f4bd5ddSJames Courtier-Dutton } 5099f4bd5ddSJames Courtier-Dutton 510536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_output_source_ctl = { 511536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 512536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 513536438f1SOswald Buddenhagen .info = snd_emu1010_input_output_source_info, 514536438f1SOswald Buddenhagen .get = snd_emu1010_output_source_get, 515536438f1SOswald Buddenhagen .put = snd_emu1010_output_source_put 516536438f1SOswald Buddenhagen }; 517536438f1SOswald Buddenhagen 5189f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, 5199f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 5209f4bd5ddSJames Courtier-Dutton { 5219f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 522511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 523511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 524511cbe8fSOswald Buddenhagen unsigned channel = kcontrol->private_value; 5259f4bd5ddSJames Courtier-Dutton 526511cbe8fSOswald Buddenhagen if (channel >= emu_ri->n_ins) 52774415a36SJames Courtier-Dutton return -EINVAL; 5289f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; 5299f4bd5ddSJames Courtier-Dutton return 0; 5309f4bd5ddSJames Courtier-Dutton } 5319f4bd5ddSJames Courtier-Dutton 5329f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, 5339f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 5349f4bd5ddSJames Courtier-Dutton { 5359f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 536511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 537511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 538511cbe8fSOswald Buddenhagen unsigned val = ucontrol->value.enumerated.item[0]; 539511cbe8fSOswald Buddenhagen unsigned channel = kcontrol->private_value; 540511cbe8fSOswald Buddenhagen int change; 5419f4bd5ddSJames Courtier-Dutton 542511cbe8fSOswald Buddenhagen if (val >= emu_ri->n_srcs) 543aa299d01STakashi Iwai return -EINVAL; 544511cbe8fSOswald Buddenhagen if (channel >= emu_ri->n_ins) 54574415a36SJames Courtier-Dutton return -EINVAL; 546511cbe8fSOswald Buddenhagen change = (emu->emu1010.input_source[channel] != val); 547511cbe8fSOswald Buddenhagen if (change) { 548aa299d01STakashi Iwai emu->emu1010.input_source[channel] = val; 549511cbe8fSOswald Buddenhagen snd_emu1010_input_source_apply(emu, channel, val); 550511cbe8fSOswald Buddenhagen } 551511cbe8fSOswald Buddenhagen return change; 5529f4bd5ddSJames Courtier-Dutton } 5539f4bd5ddSJames Courtier-Dutton 554536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_input_source_ctl = { 555536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 556536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 557536438f1SOswald Buddenhagen .info = snd_emu1010_input_output_source_info, 558536438f1SOswald Buddenhagen .get = snd_emu1010_input_source_get, 559536438f1SOswald Buddenhagen .put = snd_emu1010_input_source_put 5609f4bd5ddSJames Courtier-Dutton }; 5619f4bd5ddSJames Courtier-Dutton 562*97f1582eSOswald Buddenhagen static int add_emu1010_source_mixers(struct snd_emu10k1 *emu) 563*97f1582eSOswald Buddenhagen { 564*97f1582eSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 565*97f1582eSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 566*97f1582eSOswald Buddenhagen int err; 567*97f1582eSOswald Buddenhagen 568*97f1582eSOswald Buddenhagen err = add_ctls(emu, &emu1010_output_source_ctl, 569*97f1582eSOswald Buddenhagen emu_ri->out_texts, emu_ri->n_outs); 570*97f1582eSOswald Buddenhagen if (err < 0) 571*97f1582eSOswald Buddenhagen return err; 572*97f1582eSOswald Buddenhagen err = add_ctls(emu, &emu1010_input_source_ctl, 573*97f1582eSOswald Buddenhagen emu1010_input_texts, emu_ri->n_ins); 574*97f1582eSOswald Buddenhagen return err; 575*97f1582eSOswald Buddenhagen } 576*97f1582eSOswald Buddenhagen 5771c02e366SCtirad Fertr 578536438f1SOswald Buddenhagen static const char * const snd_emu1010_adc_pads[] = { 579536438f1SOswald Buddenhagen "ADC1 14dB PAD Audio Dock Capture Switch", 580536438f1SOswald Buddenhagen "ADC2 14dB PAD Audio Dock Capture Switch", 581536438f1SOswald Buddenhagen "ADC3 14dB PAD Audio Dock Capture Switch", 582536438f1SOswald Buddenhagen "ADC1 14dB PAD 0202 Capture Switch", 5831c02e366SCtirad Fertr }; 5841c02e366SCtirad Fertr 585536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_adc_pad_regs[] = { 586536438f1SOswald Buddenhagen EMU_HANA_DOCK_ADC_PAD1, 587536438f1SOswald Buddenhagen EMU_HANA_DOCK_ADC_PAD2, 588536438f1SOswald Buddenhagen EMU_HANA_DOCK_ADC_PAD3, 589536438f1SOswald Buddenhagen EMU_HANA_0202_ADC_PAD1, 5909148cc50SJames Courtier-Dutton }; 5919148cc50SJames Courtier-Dutton 592a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info snd_ctl_boolean_mono_info 5939148cc50SJames Courtier-Dutton 5949148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5959148cc50SJames Courtier-Dutton { 5969148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 597536438f1SOswald Buddenhagen unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value]; 598536438f1SOswald Buddenhagen 5999148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; 6009148cc50SJames Courtier-Dutton return 0; 6019148cc50SJames Courtier-Dutton } 6029148cc50SJames Courtier-Dutton 6039148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6049148cc50SJames Courtier-Dutton { 6059148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 606536438f1SOswald Buddenhagen unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value]; 6079148cc50SJames Courtier-Dutton unsigned int val, cache; 6089148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 6099148cc50SJames Courtier-Dutton cache = emu->emu1010.adc_pads; 6109148cc50SJames Courtier-Dutton if (val == 1) 6119148cc50SJames Courtier-Dutton cache = cache | mask; 6129148cc50SJames Courtier-Dutton else 6139148cc50SJames Courtier-Dutton cache = cache & ~mask; 6149148cc50SJames Courtier-Dutton if (cache != emu->emu1010.adc_pads) { 6159148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); 6169148cc50SJames Courtier-Dutton emu->emu1010.adc_pads = cache; 6179148cc50SJames Courtier-Dutton } 6189148cc50SJames Courtier-Dutton 6199148cc50SJames Courtier-Dutton return 0; 6209148cc50SJames Courtier-Dutton } 6219148cc50SJames Courtier-Dutton 622536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_adc_pads_ctl = { 623536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 624536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 625536438f1SOswald Buddenhagen .info = snd_emu1010_adc_pads_info, 626536438f1SOswald Buddenhagen .get = snd_emu1010_adc_pads_get, 627536438f1SOswald Buddenhagen .put = snd_emu1010_adc_pads_put 628536438f1SOswald Buddenhagen }; 6299148cc50SJames Courtier-Dutton 6309148cc50SJames Courtier-Dutton 631536438f1SOswald Buddenhagen static const char * const snd_emu1010_dac_pads[] = { 632536438f1SOswald Buddenhagen "DAC1 Audio Dock 14dB PAD Playback Switch", 633536438f1SOswald Buddenhagen "DAC2 Audio Dock 14dB PAD Playback Switch", 634536438f1SOswald Buddenhagen "DAC3 Audio Dock 14dB PAD Playback Switch", 635536438f1SOswald Buddenhagen "DAC4 Audio Dock 14dB PAD Playback Switch", 636536438f1SOswald Buddenhagen "DAC1 0202 14dB PAD Playback Switch", 637536438f1SOswald Buddenhagen }; 6389148cc50SJames Courtier-Dutton 639536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_dac_regs[] = { 640536438f1SOswald Buddenhagen EMU_HANA_DOCK_DAC_PAD1, 641536438f1SOswald Buddenhagen EMU_HANA_DOCK_DAC_PAD2, 642536438f1SOswald Buddenhagen EMU_HANA_DOCK_DAC_PAD3, 643536438f1SOswald Buddenhagen EMU_HANA_DOCK_DAC_PAD4, 644536438f1SOswald Buddenhagen EMU_HANA_0202_DAC_PAD1, 6459148cc50SJames Courtier-Dutton }; 6469148cc50SJames Courtier-Dutton 647a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info snd_ctl_boolean_mono_info 6489148cc50SJames Courtier-Dutton 6499148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6509148cc50SJames Courtier-Dutton { 6519148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 652536438f1SOswald Buddenhagen unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value]; 653536438f1SOswald Buddenhagen 6549148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; 6559148cc50SJames Courtier-Dutton return 0; 6569148cc50SJames Courtier-Dutton } 6579148cc50SJames Courtier-Dutton 6589148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6599148cc50SJames Courtier-Dutton { 6609148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 661536438f1SOswald Buddenhagen unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value]; 6629148cc50SJames Courtier-Dutton unsigned int val, cache; 663cc766807SOswald Buddenhagen int change; 664cc766807SOswald Buddenhagen 6659148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 6669148cc50SJames Courtier-Dutton cache = emu->emu1010.dac_pads; 6679148cc50SJames Courtier-Dutton if (val == 1) 6689148cc50SJames Courtier-Dutton cache = cache | mask; 6699148cc50SJames Courtier-Dutton else 6709148cc50SJames Courtier-Dutton cache = cache & ~mask; 671cc766807SOswald Buddenhagen change = (cache != emu->emu1010.dac_pads); 672cc766807SOswald Buddenhagen if (change) { 6739148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); 6749148cc50SJames Courtier-Dutton emu->emu1010.dac_pads = cache; 6759148cc50SJames Courtier-Dutton } 6769148cc50SJames Courtier-Dutton 677cc766807SOswald Buddenhagen return change; 6789148cc50SJames Courtier-Dutton } 6799148cc50SJames Courtier-Dutton 680536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_dac_pads_ctl = { 681536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 682536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 683536438f1SOswald Buddenhagen .info = snd_emu1010_dac_pads_info, 684536438f1SOswald Buddenhagen .get = snd_emu1010_dac_pads_get, 685536438f1SOswald Buddenhagen .put = snd_emu1010_dac_pads_put 6869f4bd5ddSJames Courtier-Dutton }; 6879f4bd5ddSJames Courtier-Dutton 688b0dbdaeaSJames Courtier-Dutton 689*97f1582eSOswald Buddenhagen struct snd_emu1010_pads_info { 690*97f1582eSOswald Buddenhagen const char * const *adc_ctls, * const *dac_ctls; 691*97f1582eSOswald Buddenhagen unsigned n_adc_ctls, n_dac_ctls; 692*97f1582eSOswald Buddenhagen }; 693*97f1582eSOswald Buddenhagen 694*97f1582eSOswald Buddenhagen const struct snd_emu1010_pads_info emu1010_pads_info[] = { 695*97f1582eSOswald Buddenhagen { 696*97f1582eSOswald Buddenhagen /* all other e-mu cards for now */ 697*97f1582eSOswald Buddenhagen .adc_ctls = snd_emu1010_adc_pads, 698*97f1582eSOswald Buddenhagen .n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads), 699*97f1582eSOswald Buddenhagen .dac_ctls = snd_emu1010_dac_pads, 700*97f1582eSOswald Buddenhagen .n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads), 701*97f1582eSOswald Buddenhagen }, 702*97f1582eSOswald Buddenhagen { 703*97f1582eSOswald Buddenhagen /* 1616(m) cardbus */ 704*97f1582eSOswald Buddenhagen .adc_ctls = snd_emu1010_adc_pads, 705*97f1582eSOswald Buddenhagen .n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 2, 706*97f1582eSOswald Buddenhagen .dac_ctls = snd_emu1010_dac_pads, 707*97f1582eSOswald Buddenhagen .n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 2, 708*97f1582eSOswald Buddenhagen }, 709*97f1582eSOswald Buddenhagen }; 710*97f1582eSOswald Buddenhagen 711*97f1582eSOswald Buddenhagen 712b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, 713b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 714b0dbdaeaSJames Courtier-Dutton { 7151541c66dSTakashi Iwai static const char * const texts[4] = { 716edec7bbbSJames Courtier-Dutton "44100", "48000", "SPDIF", "ADAT" 717b0dbdaeaSJames Courtier-Dutton }; 718b0dbdaeaSJames Courtier-Dutton 7191541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 4, texts); 720b0dbdaeaSJames Courtier-Dutton } 721b0dbdaeaSJames Courtier-Dutton 722b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, 723b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 724b0dbdaeaSJames Courtier-Dutton { 725b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 726b0dbdaeaSJames Courtier-Dutton 727b0dbdaeaSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; 728b0dbdaeaSJames Courtier-Dutton return 0; 729b0dbdaeaSJames Courtier-Dutton } 730b0dbdaeaSJames Courtier-Dutton 731b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, 732b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 733b0dbdaeaSJames Courtier-Dutton { 734b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 735b0dbdaeaSJames Courtier-Dutton unsigned int val; 736b0dbdaeaSJames Courtier-Dutton int change = 0; 737b0dbdaeaSJames Courtier-Dutton 738b0dbdaeaSJames Courtier-Dutton val = ucontrol->value.enumerated.item[0] ; 73974415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 4; */ 74074415a36SJames Courtier-Dutton if (val >= 4) 74174415a36SJames Courtier-Dutton return -EINVAL; 742b0dbdaeaSJames Courtier-Dutton change = (emu->emu1010.internal_clock != val); 743b0dbdaeaSJames Courtier-Dutton if (change) { 744b0dbdaeaSJames Courtier-Dutton emu->emu1010.internal_clock = val; 745b0dbdaeaSJames Courtier-Dutton switch (val) { 746b0dbdaeaSJames Courtier-Dutton case 0: 747b0dbdaeaSJames Courtier-Dutton /* 44100 */ 748b0dbdaeaSJames Courtier-Dutton /* Mute all */ 749b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 750a869057cSOswald Buddenhagen /* Default fallback clock 44.1kHz */ 751b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); 752b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 44.1kHz x1 */ 753b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 754b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); 755b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 756b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 757b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); 758b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 759e40a0b2eSJames Courtier-Dutton msleep(10); 760b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 761b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 762b0dbdaeaSJames Courtier-Dutton break; 763b0dbdaeaSJames Courtier-Dutton case 1: 764b0dbdaeaSJames Courtier-Dutton /* 48000 */ 765b0dbdaeaSJames Courtier-Dutton /* Mute all */ 766b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 767b0dbdaeaSJames Courtier-Dutton /* Default fallback clock 48kHz */ 768b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 769b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 48kHz x1 */ 770b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 771b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); 772b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 773b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 774b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); 775b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 776e40a0b2eSJames Courtier-Dutton msleep(10); 777b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 778b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 779b0dbdaeaSJames Courtier-Dutton break; 780edec7bbbSJames Courtier-Dutton 781edec7bbbSJames Courtier-Dutton case 2: /* Take clock from S/PDIF IN */ 782edec7bbbSJames Courtier-Dutton /* Mute all */ 783edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 784edec7bbbSJames Courtier-Dutton /* Default fallback clock 48kHz */ 785edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 786edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to S/PDIF input */ 787edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 788edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); 789edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 790edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 791edec7bbbSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 792edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 793edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 794edec7bbbSJames Courtier-Dutton msleep(10); 795edec7bbbSJames Courtier-Dutton /* Unmute all */ 796edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 797edec7bbbSJames Courtier-Dutton break; 798edec7bbbSJames Courtier-Dutton 799edec7bbbSJames Courtier-Dutton case 3: 800edec7bbbSJames Courtier-Dutton /* Take clock from ADAT IN */ 801edec7bbbSJames Courtier-Dutton /* Mute all */ 802edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 803edec7bbbSJames Courtier-Dutton /* Default fallback clock 48kHz */ 804edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 805edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to ADAT input */ 806edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 807edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); 808edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 809edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 810edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 811edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 812edec7bbbSJames Courtier-Dutton msleep(10); 813edec7bbbSJames Courtier-Dutton /* Unmute all */ 814edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 815edec7bbbSJames Courtier-Dutton 816edec7bbbSJames Courtier-Dutton 817edec7bbbSJames Courtier-Dutton break; 818b0dbdaeaSJames Courtier-Dutton } 819b0dbdaeaSJames Courtier-Dutton } 820b0dbdaeaSJames Courtier-Dutton return change; 821b0dbdaeaSJames Courtier-Dutton } 822b0dbdaeaSJames Courtier-Dutton 823f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock = 824b0dbdaeaSJames Courtier-Dutton { 825b0dbdaeaSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 826b0dbdaeaSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 827b0dbdaeaSJames Courtier-Dutton .name = "Clock Internal Rate", 828b0dbdaeaSJames Courtier-Dutton .count = 1, 829b0dbdaeaSJames Courtier-Dutton .info = snd_emu1010_internal_clock_info, 830b0dbdaeaSJames Courtier-Dutton .get = snd_emu1010_internal_clock_get, 831b0dbdaeaSJames Courtier-Dutton .put = snd_emu1010_internal_clock_put 832b0dbdaeaSJames Courtier-Dutton }; 833b0dbdaeaSJames Courtier-Dutton 83499dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol, 83599dcab46SMichael Gernoth struct snd_ctl_elem_info *uinfo) 83699dcab46SMichael Gernoth { 83799dcab46SMichael Gernoth static const char * const texts[2] = { 83899dcab46SMichael Gernoth "SPDIF", "ADAT" 83999dcab46SMichael Gernoth }; 84099dcab46SMichael Gernoth 84199dcab46SMichael Gernoth return snd_ctl_enum_info(uinfo, 1, 2, texts); 84299dcab46SMichael Gernoth } 84399dcab46SMichael Gernoth 84499dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol, 84599dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 84699dcab46SMichael Gernoth { 84799dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 84899dcab46SMichael Gernoth 84999dcab46SMichael Gernoth ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out; 85099dcab46SMichael Gernoth return 0; 85199dcab46SMichael Gernoth } 85299dcab46SMichael Gernoth 85399dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol, 85499dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 85599dcab46SMichael Gernoth { 85699dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 85799dcab46SMichael Gernoth unsigned int val; 85899dcab46SMichael Gernoth u32 tmp; 85999dcab46SMichael Gernoth int change = 0; 86099dcab46SMichael Gernoth 86199dcab46SMichael Gernoth val = ucontrol->value.enumerated.item[0]; 86299dcab46SMichael Gernoth /* Limit: uinfo->value.enumerated.items = 2; */ 86399dcab46SMichael Gernoth if (val >= 2) 86499dcab46SMichael Gernoth return -EINVAL; 86599dcab46SMichael Gernoth change = (emu->emu1010.optical_out != val); 86699dcab46SMichael Gernoth if (change) { 86799dcab46SMichael Gernoth emu->emu1010.optical_out = val; 8689d2f3863SOswald Buddenhagen tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) | 8699d2f3863SOswald Buddenhagen (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF); 87099dcab46SMichael Gernoth snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 87199dcab46SMichael Gernoth } 87299dcab46SMichael Gernoth return change; 87399dcab46SMichael Gernoth } 87499dcab46SMichael Gernoth 875f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = { 87699dcab46SMichael Gernoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 87799dcab46SMichael Gernoth .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 87899dcab46SMichael Gernoth .name = "Optical Output Mode", 87999dcab46SMichael Gernoth .count = 1, 88099dcab46SMichael Gernoth .info = snd_emu1010_optical_out_info, 88199dcab46SMichael Gernoth .get = snd_emu1010_optical_out_get, 88299dcab46SMichael Gernoth .put = snd_emu1010_optical_out_put 88399dcab46SMichael Gernoth }; 88499dcab46SMichael Gernoth 88599dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol, 88699dcab46SMichael Gernoth struct snd_ctl_elem_info *uinfo) 88799dcab46SMichael Gernoth { 88899dcab46SMichael Gernoth static const char * const texts[2] = { 88999dcab46SMichael Gernoth "SPDIF", "ADAT" 89099dcab46SMichael Gernoth }; 89199dcab46SMichael Gernoth 89299dcab46SMichael Gernoth return snd_ctl_enum_info(uinfo, 1, 2, texts); 89399dcab46SMichael Gernoth } 89499dcab46SMichael Gernoth 89599dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol, 89699dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 89799dcab46SMichael Gernoth { 89899dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 89999dcab46SMichael Gernoth 90099dcab46SMichael Gernoth ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in; 90199dcab46SMichael Gernoth return 0; 90299dcab46SMichael Gernoth } 90399dcab46SMichael Gernoth 90499dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol, 90599dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 90699dcab46SMichael Gernoth { 90799dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 90899dcab46SMichael Gernoth unsigned int val; 90999dcab46SMichael Gernoth u32 tmp; 91099dcab46SMichael Gernoth int change = 0; 91199dcab46SMichael Gernoth 91299dcab46SMichael Gernoth val = ucontrol->value.enumerated.item[0]; 91399dcab46SMichael Gernoth /* Limit: uinfo->value.enumerated.items = 2; */ 91499dcab46SMichael Gernoth if (val >= 2) 91599dcab46SMichael Gernoth return -EINVAL; 91699dcab46SMichael Gernoth change = (emu->emu1010.optical_in != val); 91799dcab46SMichael Gernoth if (change) { 91899dcab46SMichael Gernoth emu->emu1010.optical_in = val; 9199d2f3863SOswald Buddenhagen tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) | 9209d2f3863SOswald Buddenhagen (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF); 92199dcab46SMichael Gernoth snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 92299dcab46SMichael Gernoth } 92399dcab46SMichael Gernoth return change; 92499dcab46SMichael Gernoth } 92599dcab46SMichael Gernoth 926f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = { 92799dcab46SMichael Gernoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 92899dcab46SMichael Gernoth .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 92999dcab46SMichael Gernoth .name = "Optical Input Mode", 93099dcab46SMichael Gernoth .count = 1, 93199dcab46SMichael Gernoth .info = snd_emu1010_optical_in_info, 93299dcab46SMichael Gernoth .get = snd_emu1010_optical_in_get, 93399dcab46SMichael Gernoth .put = snd_emu1010_optical_in_put 93499dcab46SMichael Gernoth }; 93599dcab46SMichael Gernoth 936184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, 937184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 938184c1e2cSJames Courtier-Dutton { 939184c1e2cSJames Courtier-Dutton #if 0 9401541c66dSTakashi Iwai static const char * const texts[4] = { 941184c1e2cSJames Courtier-Dutton "Unknown1", "Unknown2", "Mic", "Line" 942184c1e2cSJames Courtier-Dutton }; 943184c1e2cSJames Courtier-Dutton #endif 9441541c66dSTakashi Iwai static const char * const texts[2] = { 945184c1e2cSJames Courtier-Dutton "Mic", "Line" 946184c1e2cSJames Courtier-Dutton }; 947184c1e2cSJames Courtier-Dutton 9481541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 2, texts); 949184c1e2cSJames Courtier-Dutton } 950184c1e2cSJames Courtier-Dutton 951184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, 952184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 953184c1e2cSJames Courtier-Dutton { 954184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 955184c1e2cSJames Courtier-Dutton 956184c1e2cSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; 957184c1e2cSJames Courtier-Dutton return 0; 958184c1e2cSJames Courtier-Dutton } 959184c1e2cSJames Courtier-Dutton 960184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, 961184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 962184c1e2cSJames Courtier-Dutton { 963184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 964184c1e2cSJames Courtier-Dutton unsigned int source_id; 965184c1e2cSJames Courtier-Dutton unsigned int ngain, ogain; 966a1c87c0bSOswald Buddenhagen u16 gpio; 967184c1e2cSJames Courtier-Dutton int change = 0; 968184c1e2cSJames Courtier-Dutton unsigned long flags; 969184c1e2cSJames Courtier-Dutton u32 source; 970184c1e2cSJames Courtier-Dutton /* If the capture source has changed, 971184c1e2cSJames Courtier-Dutton * update the capture volume from the cached value 972184c1e2cSJames Courtier-Dutton * for the particular source. 973184c1e2cSJames Courtier-Dutton */ 97474415a36SJames Courtier-Dutton source_id = ucontrol->value.enumerated.item[0]; 97574415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 2; */ 97674415a36SJames Courtier-Dutton /* emu->i2c_capture_volume */ 97774415a36SJames Courtier-Dutton if (source_id >= 2) 97874415a36SJames Courtier-Dutton return -EINVAL; 979184c1e2cSJames Courtier-Dutton change = (emu->i2c_capture_source != source_id); 980184c1e2cSJames Courtier-Dutton if (change) { 981184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 982184c1e2cSJames Courtier-Dutton spin_lock_irqsave(&emu->emu_lock, flags); 983a1c87c0bSOswald Buddenhagen gpio = inw(emu->port + A_IOCFG); 984184c1e2cSJames Courtier-Dutton if (source_id==0) 985a1c87c0bSOswald Buddenhagen outw(gpio | 0x4, emu->port + A_IOCFG); 986184c1e2cSJames Courtier-Dutton else 987a1c87c0bSOswald Buddenhagen outw(gpio & ~0x4, emu->port + A_IOCFG); 988184c1e2cSJames Courtier-Dutton spin_unlock_irqrestore(&emu->emu_lock, flags); 989184c1e2cSJames Courtier-Dutton 990184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ 991184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ 992184c1e2cSJames Courtier-Dutton if (ngain != ogain) 993184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); 994184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ 995184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ 996184c1e2cSJames Courtier-Dutton if (ngain != ogain) 997184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 998184c1e2cSJames Courtier-Dutton 999184c1e2cSJames Courtier-Dutton source = 1 << (source_id + 2); 1000184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ 1001184c1e2cSJames Courtier-Dutton emu->i2c_capture_source = source_id; 1002184c1e2cSJames Courtier-Dutton } 1003184c1e2cSJames Courtier-Dutton return change; 1004184c1e2cSJames Courtier-Dutton } 1005184c1e2cSJames Courtier-Dutton 1006f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source = 1007184c1e2cSJames Courtier-Dutton { 1008184c1e2cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1009184c1e2cSJames Courtier-Dutton .name = "Capture Source", 1010184c1e2cSJames Courtier-Dutton .info = snd_audigy_i2c_capture_source_info, 1011184c1e2cSJames Courtier-Dutton .get = snd_audigy_i2c_capture_source_get, 1012184c1e2cSJames Courtier-Dutton .put = snd_audigy_i2c_capture_source_put 1013184c1e2cSJames Courtier-Dutton }; 1014184c1e2cSJames Courtier-Dutton 1015184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, 1016184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 1017184c1e2cSJames Courtier-Dutton { 1018184c1e2cSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1019184c1e2cSJames Courtier-Dutton uinfo->count = 2; 1020184c1e2cSJames Courtier-Dutton uinfo->value.integer.min = 0; 1021184c1e2cSJames Courtier-Dutton uinfo->value.integer.max = 255; 1022184c1e2cSJames Courtier-Dutton return 0; 1023184c1e2cSJames Courtier-Dutton } 1024184c1e2cSJames Courtier-Dutton 1025184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, 1026184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 1027184c1e2cSJames Courtier-Dutton { 1028184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 102974415a36SJames Courtier-Dutton unsigned int source_id; 1030184c1e2cSJames Courtier-Dutton 1031184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 103274415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 103374415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 103474415a36SJames Courtier-Dutton if (source_id >= 2) 103574415a36SJames Courtier-Dutton return -EINVAL; 1036184c1e2cSJames Courtier-Dutton 1037184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; 1038184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; 1039184c1e2cSJames Courtier-Dutton return 0; 1040184c1e2cSJames Courtier-Dutton } 1041184c1e2cSJames Courtier-Dutton 1042184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, 1043184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 1044184c1e2cSJames Courtier-Dutton { 1045184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1046184c1e2cSJames Courtier-Dutton unsigned int ogain; 104714a29565SOswald Buddenhagen unsigned int ngain0, ngain1; 104874415a36SJames Courtier-Dutton unsigned int source_id; 1049184c1e2cSJames Courtier-Dutton int change = 0; 1050184c1e2cSJames Courtier-Dutton 1051184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 105274415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 105374415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 105474415a36SJames Courtier-Dutton if (source_id >= 2) 105574415a36SJames Courtier-Dutton return -EINVAL; 105614a29565SOswald Buddenhagen ngain0 = ucontrol->value.integer.value[0]; 105714a29565SOswald Buddenhagen ngain1 = ucontrol->value.integer.value[1]; 105814a29565SOswald Buddenhagen if (ngain0 > 0xff) 105914a29565SOswald Buddenhagen return -EINVAL; 106014a29565SOswald Buddenhagen if (ngain1 > 0xff) 106114a29565SOswald Buddenhagen return -EINVAL; 1062184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ 106314a29565SOswald Buddenhagen if (ogain != ngain0) { 1064184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 106514a29565SOswald Buddenhagen snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0); 106614a29565SOswald Buddenhagen emu->i2c_capture_volume[source_id][0] = ngain0; 1067184c1e2cSJames Courtier-Dutton change = 1; 1068184c1e2cSJames Courtier-Dutton } 1069184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ 107014a29565SOswald Buddenhagen if (ogain != ngain1) { 1071184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 107214a29565SOswald Buddenhagen snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1); 107314a29565SOswald Buddenhagen emu->i2c_capture_volume[source_id][1] = ngain1; 1074184c1e2cSJames Courtier-Dutton change = 1; 1075184c1e2cSJames Courtier-Dutton } 1076184c1e2cSJames Courtier-Dutton 1077184c1e2cSJames Courtier-Dutton return change; 1078184c1e2cSJames Courtier-Dutton } 1079184c1e2cSJames Courtier-Dutton 1080536438f1SOswald Buddenhagen static const struct snd_kcontrol_new i2c_volume_ctl = { 1081536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1082536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 1083536438f1SOswald Buddenhagen SNDRV_CTL_ELEM_ACCESS_TLV_READ, 1084536438f1SOswald Buddenhagen .info = snd_audigy_i2c_volume_info, 1085536438f1SOswald Buddenhagen .get = snd_audigy_i2c_volume_get, 1086536438f1SOswald Buddenhagen .put = snd_audigy_i2c_volume_put, 1087536438f1SOswald Buddenhagen .tlv = { .p = snd_audigy_db_scale2 } 1088536438f1SOswald Buddenhagen }; 1089184c1e2cSJames Courtier-Dutton 1090536438f1SOswald Buddenhagen static const char * const snd_audigy_i2c_volume_ctls[] = { 1091536438f1SOswald Buddenhagen "Mic Capture Volume", 1092536438f1SOswald Buddenhagen "Line Capture Volume", 1093184c1e2cSJames Courtier-Dutton }; 1094184c1e2cSJames Courtier-Dutton 10950af68e5eSTakashi Iwai #if 0 1096eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 10971da177e4SLinus Torvalds { 10981541c66dSTakashi Iwai static const char * const texts[] = {"44100", "48000", "96000"}; 10991da177e4SLinus Torvalds 11001541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 3, texts); 11011da177e4SLinus Torvalds } 11021da177e4SLinus Torvalds 1103eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, 1104eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11051da177e4SLinus Torvalds { 1106eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11071da177e4SLinus Torvalds unsigned int tmp; 11081da177e4SLinus Torvalds 11091da177e4SLinus Torvalds tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 11101da177e4SLinus Torvalds switch (tmp & A_SPDIF_RATE_MASK) { 11111da177e4SLinus Torvalds case A_SPDIF_44100: 11121da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 11131da177e4SLinus Torvalds break; 11141da177e4SLinus Torvalds case A_SPDIF_48000: 11151da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 11161da177e4SLinus Torvalds break; 11171da177e4SLinus Torvalds case A_SPDIF_96000: 11181da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 11191da177e4SLinus Torvalds break; 11201da177e4SLinus Torvalds default: 11211da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 11221da177e4SLinus Torvalds } 11231da177e4SLinus Torvalds return 0; 11241da177e4SLinus Torvalds } 11251da177e4SLinus Torvalds 1126eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, 1127eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11281da177e4SLinus Torvalds { 1129eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11301da177e4SLinus Torvalds int change; 11311da177e4SLinus Torvalds unsigned int reg, val, tmp; 11321da177e4SLinus Torvalds unsigned long flags; 11331da177e4SLinus Torvalds 11341da177e4SLinus Torvalds switch(ucontrol->value.enumerated.item[0]) { 11351da177e4SLinus Torvalds case 0: 11361da177e4SLinus Torvalds val = A_SPDIF_44100; 11371da177e4SLinus Torvalds break; 11381da177e4SLinus Torvalds case 1: 11391da177e4SLinus Torvalds val = A_SPDIF_48000; 11401da177e4SLinus Torvalds break; 11411da177e4SLinus Torvalds case 2: 11421da177e4SLinus Torvalds val = A_SPDIF_96000; 11431da177e4SLinus Torvalds break; 11441da177e4SLinus Torvalds default: 11451da177e4SLinus Torvalds val = A_SPDIF_48000; 11461da177e4SLinus Torvalds break; 11471da177e4SLinus Torvalds } 11481da177e4SLinus Torvalds 11491da177e4SLinus Torvalds 11501da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 11511da177e4SLinus Torvalds reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 11521da177e4SLinus Torvalds tmp = reg & ~A_SPDIF_RATE_MASK; 11531da177e4SLinus Torvalds tmp |= val; 115412bda107STakashi Iwai change = (tmp != reg); 115512bda107STakashi Iwai if (change) 11561da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); 11571da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11581da177e4SLinus Torvalds return change; 11591da177e4SLinus Torvalds } 11601da177e4SLinus Torvalds 1161b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate = 11621da177e4SLinus Torvalds { 11631da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 11641da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 11651da177e4SLinus Torvalds .name = "Audigy SPDIF Output Sample Rate", 11661da177e4SLinus Torvalds .count = 1, 11671da177e4SLinus Torvalds .info = snd_audigy_spdif_output_rate_info, 11681da177e4SLinus Torvalds .get = snd_audigy_spdif_output_rate_get, 11691da177e4SLinus Torvalds .put = snd_audigy_spdif_output_rate_put 11701da177e4SLinus Torvalds }; 11710af68e5eSTakashi Iwai #endif 11721da177e4SLinus Torvalds 1173eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, 1174eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11751da177e4SLinus Torvalds { 1176eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11771da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 11781da177e4SLinus Torvalds int change; 11791da177e4SLinus Torvalds unsigned int val; 11801da177e4SLinus Torvalds 118174415a36SJames Courtier-Dutton /* Limit: emu->spdif_bits */ 118274415a36SJames Courtier-Dutton if (idx >= 3) 118374415a36SJames Courtier-Dutton return -EINVAL; 11841da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) | 11851da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) | 11861da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) | 11871da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24); 11881da177e4SLinus Torvalds change = val != emu->spdif_bits[idx]; 11891da177e4SLinus Torvalds if (change) { 11901da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); 11911da177e4SLinus Torvalds emu->spdif_bits[idx] = val; 11921da177e4SLinus Torvalds } 11931da177e4SLinus Torvalds return change; 11941da177e4SLinus Torvalds } 11951da177e4SLinus Torvalds 1196f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = 11971da177e4SLinus Torvalds { 11981da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 11995549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 12001da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 12017583cb51STakashi Iwai .count = 3, 12021da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 12031da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get_mask 12041da177e4SLinus Torvalds }; 12051da177e4SLinus Torvalds 1206f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control = 12071da177e4SLinus Torvalds { 12085549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 12091da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 12107583cb51STakashi Iwai .count = 3, 12111da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 12121da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get, 12131da177e4SLinus Torvalds .put = snd_emu10k1_spdif_put 12141da177e4SLinus Torvalds }; 12151da177e4SLinus Torvalds 12161da177e4SLinus Torvalds 1217eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route) 12181da177e4SLinus Torvalds { 12191da177e4SLinus Torvalds if (emu->audigy) { 12201da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT1, voice, 12211da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt1(route)); 12221da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT2, voice, 12231da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt2(route)); 12241da177e4SLinus Torvalds } else { 12251da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXRT, voice, 12261da177e4SLinus Torvalds snd_emu10k1_compose_send_routing(route)); 12271da177e4SLinus Torvalds } 12281da177e4SLinus Torvalds } 12291da177e4SLinus Torvalds 1230eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume) 12311da177e4SLinus Torvalds { 12321da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); 12331da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); 12341da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); 12351da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); 12361da177e4SLinus Torvalds if (emu->audigy) { 123751d652f4SOswald Buddenhagen snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, 123851d652f4SOswald Buddenhagen snd_emu10k1_compose_audigy_sendamounts(volume)); 12391da177e4SLinus Torvalds } 12401da177e4SLinus Torvalds } 12411da177e4SLinus Torvalds 12421da177e4SLinus Torvalds /* PCM stream controls */ 12431da177e4SLinus Torvalds 1244eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 12451da177e4SLinus Torvalds { 1246eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 12471da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 12481da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 12491da177e4SLinus Torvalds uinfo->value.integer.min = 0; 12501da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 12511da177e4SLinus Torvalds return 0; 12521da177e4SLinus Torvalds } 12531da177e4SLinus Torvalds 1254eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, 1255eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12561da177e4SLinus Torvalds { 1257eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1258eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1259eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12601da177e4SLinus Torvalds int voice, idx; 12611da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 12621da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 12631da177e4SLinus Torvalds 12641da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 12651da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 12661da177e4SLinus Torvalds ucontrol->value.integer.value[(voice * num_efx) + idx] = 12671da177e4SLinus Torvalds mix->send_routing[voice][idx] & mask; 12681da177e4SLinus Torvalds return 0; 12691da177e4SLinus Torvalds } 12701da177e4SLinus Torvalds 1271eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, 1272eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12731da177e4SLinus Torvalds { 12741da177e4SLinus Torvalds unsigned long flags; 1275eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1276eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1277eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12781da177e4SLinus Torvalds int change = 0, voice, idx, val; 12791da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 12801da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 12811da177e4SLinus Torvalds 12821da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 12831da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 12841da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 12851da177e4SLinus Torvalds val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; 12861da177e4SLinus Torvalds if (mix->send_routing[voice][idx] != val) { 12871da177e4SLinus Torvalds mix->send_routing[voice][idx] = val; 12881da177e4SLinus Torvalds change = 1; 12891da177e4SLinus Torvalds } 12901da177e4SLinus Torvalds } 12911da177e4SLinus Torvalds if (change && mix->epcm) { 12921da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 12931da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 12941da177e4SLinus Torvalds &mix->send_routing[1][0]); 12951da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, 12961da177e4SLinus Torvalds &mix->send_routing[2][0]); 12971da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 12981da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 12991da177e4SLinus Torvalds &mix->send_routing[0][0]); 13001da177e4SLinus Torvalds } 13011da177e4SLinus Torvalds } 13021da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13031da177e4SLinus Torvalds return change; 13041da177e4SLinus Torvalds } 13051da177e4SLinus Torvalds 1306f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control = 13071da177e4SLinus Torvalds { 13081da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 130967ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 13101da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Routing", 13111da177e4SLinus Torvalds .count = 32, 13121da177e4SLinus Torvalds .info = snd_emu10k1_send_routing_info, 13131da177e4SLinus Torvalds .get = snd_emu10k1_send_routing_get, 13141da177e4SLinus Torvalds .put = snd_emu10k1_send_routing_put 13151da177e4SLinus Torvalds }; 13161da177e4SLinus Torvalds 1317eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13181da177e4SLinus Torvalds { 1319eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13201da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13211da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 13221da177e4SLinus Torvalds uinfo->value.integer.min = 0; 13231da177e4SLinus Torvalds uinfo->value.integer.max = 255; 13241da177e4SLinus Torvalds return 0; 13251da177e4SLinus Torvalds } 13261da177e4SLinus Torvalds 1327eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, 1328eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13291da177e4SLinus Torvalds { 1330eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1331eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1332eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13331da177e4SLinus Torvalds int idx; 13341da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 13351da177e4SLinus Torvalds 13361da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) 13371da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; 13381da177e4SLinus Torvalds return 0; 13391da177e4SLinus Torvalds } 13401da177e4SLinus Torvalds 1341eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, 1342eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13431da177e4SLinus Torvalds { 13441da177e4SLinus Torvalds unsigned long flags; 1345eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1346eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1347eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13481da177e4SLinus Torvalds int change = 0, idx, val; 13491da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 13501da177e4SLinus Torvalds 13511da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13521da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) { 13531da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 13541da177e4SLinus Torvalds if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { 13551da177e4SLinus Torvalds mix->send_volume[idx/num_efx][idx%num_efx] = val; 13561da177e4SLinus Torvalds change = 1; 13571da177e4SLinus Torvalds } 13581da177e4SLinus Torvalds } 13591da177e4SLinus Torvalds if (change && mix->epcm) { 13601da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 13611da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 13621da177e4SLinus Torvalds &mix->send_volume[1][0]); 13631da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, 13641da177e4SLinus Torvalds &mix->send_volume[2][0]); 13651da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 13661da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 13671da177e4SLinus Torvalds &mix->send_volume[0][0]); 13681da177e4SLinus Torvalds } 13691da177e4SLinus Torvalds } 13701da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13711da177e4SLinus Torvalds return change; 13721da177e4SLinus Torvalds } 13731da177e4SLinus Torvalds 1374f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control = 13751da177e4SLinus Torvalds { 13761da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 137767ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 13781da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Volume", 13791da177e4SLinus Torvalds .count = 32, 13801da177e4SLinus Torvalds .info = snd_emu10k1_send_volume_info, 13811da177e4SLinus Torvalds .get = snd_emu10k1_send_volume_get, 13821da177e4SLinus Torvalds .put = snd_emu10k1_send_volume_put 13831da177e4SLinus Torvalds }; 13841da177e4SLinus Torvalds 1385eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13861da177e4SLinus Torvalds { 13871da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13881da177e4SLinus Torvalds uinfo->count = 3; 13891da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1390bcdbd3b7SOswald Buddenhagen uinfo->value.integer.max = 0x1fffd; 13911da177e4SLinus Torvalds return 0; 13921da177e4SLinus Torvalds } 13931da177e4SLinus Torvalds 1394eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, 1395eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13961da177e4SLinus Torvalds { 1397eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1398eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1399eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 14001da177e4SLinus Torvalds int idx; 14011da177e4SLinus Torvalds 14021da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) 1403bcdbd3b7SOswald Buddenhagen ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U; 14041da177e4SLinus Torvalds return 0; 14051da177e4SLinus Torvalds } 14061da177e4SLinus Torvalds 1407eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, 1408eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14091da177e4SLinus Torvalds { 14101da177e4SLinus Torvalds unsigned long flags; 1411eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1412eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1413eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 14141da177e4SLinus Torvalds int change = 0, idx, val; 14151da177e4SLinus Torvalds 14161da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 14171da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) { 1418bcdbd3b7SOswald Buddenhagen unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff; 1419bcdbd3b7SOswald Buddenhagen val = uval * 0x8000U / 0xffffU; 14201da177e4SLinus Torvalds if (mix->attn[idx] != val) { 14211da177e4SLinus Torvalds mix->attn[idx] = val; 14221da177e4SLinus Torvalds change = 1; 14231da177e4SLinus Torvalds } 14241da177e4SLinus Torvalds } 14251da177e4SLinus Torvalds if (change && mix->epcm) { 14261da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 14271da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); 14281da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]); 14291da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 14301da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); 14311da177e4SLinus Torvalds } 14321da177e4SLinus Torvalds } 14331da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 14341da177e4SLinus Torvalds return change; 14351da177e4SLinus Torvalds } 14361da177e4SLinus Torvalds 1437f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control = 14381da177e4SLinus Torvalds { 14391da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 144067ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14411da177e4SLinus Torvalds .name = "EMU10K1 PCM Volume", 14421da177e4SLinus Torvalds .count = 32, 14431da177e4SLinus Torvalds .info = snd_emu10k1_attn_info, 14441da177e4SLinus Torvalds .get = snd_emu10k1_attn_get, 14451da177e4SLinus Torvalds .put = snd_emu10k1_attn_put 14461da177e4SLinus Torvalds }; 14471da177e4SLinus Torvalds 14481da177e4SLinus Torvalds /* Mutichannel PCM stream controls */ 14491da177e4SLinus Torvalds 1450eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 14511da177e4SLinus Torvalds { 1452eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14531da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 14541da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 14551da177e4SLinus Torvalds uinfo->value.integer.min = 0; 14561da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 14571da177e4SLinus Torvalds return 0; 14581da177e4SLinus Torvalds } 14591da177e4SLinus Torvalds 1460eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, 1461eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14621da177e4SLinus Torvalds { 1463eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1464eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1465eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 14661da177e4SLinus Torvalds int idx; 14671da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 14681da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 14691da177e4SLinus Torvalds 14701da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 14711da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = 14721da177e4SLinus Torvalds mix->send_routing[0][idx] & mask; 14731da177e4SLinus Torvalds return 0; 14741da177e4SLinus Torvalds } 14751da177e4SLinus Torvalds 1476eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, 1477eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14781da177e4SLinus Torvalds { 14791da177e4SLinus Torvalds unsigned long flags; 1480eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14811da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1482eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 14831da177e4SLinus Torvalds int change = 0, idx, val; 14841da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 14851da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 14861da177e4SLinus Torvalds 14871da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 14881da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 14891da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & mask; 14901da177e4SLinus Torvalds if (mix->send_routing[0][idx] != val) { 14911da177e4SLinus Torvalds mix->send_routing[0][idx] = val; 14921da177e4SLinus Torvalds change = 1; 14931da177e4SLinus Torvalds } 14941da177e4SLinus Torvalds } 14951da177e4SLinus Torvalds 14961da177e4SLinus Torvalds if (change && mix->epcm) { 14971da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 14981da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number, 14991da177e4SLinus Torvalds &mix->send_routing[0][0]); 15001da177e4SLinus Torvalds } 15011da177e4SLinus Torvalds } 15021da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 15031da177e4SLinus Torvalds return change; 15041da177e4SLinus Torvalds } 15051da177e4SLinus Torvalds 1506f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control = 15071da177e4SLinus Torvalds { 15081da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 15091da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 15101da177e4SLinus Torvalds .name = "Multichannel PCM Send Routing", 15111da177e4SLinus Torvalds .count = 16, 15121da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_routing_info, 15131da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_routing_get, 15141da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_routing_put 15151da177e4SLinus Torvalds }; 15161da177e4SLinus Torvalds 1517eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 15181da177e4SLinus Torvalds { 1519eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15201da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 15211da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 15221da177e4SLinus Torvalds uinfo->value.integer.min = 0; 15231da177e4SLinus Torvalds uinfo->value.integer.max = 255; 15241da177e4SLinus Torvalds return 0; 15251da177e4SLinus Torvalds } 15261da177e4SLinus Torvalds 1527eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, 1528eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15291da177e4SLinus Torvalds { 1530eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1531eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1532eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 15331da177e4SLinus Torvalds int idx; 15341da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 15351da177e4SLinus Torvalds 15361da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 15371da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; 15381da177e4SLinus Torvalds return 0; 15391da177e4SLinus Torvalds } 15401da177e4SLinus Torvalds 1541eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, 1542eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15431da177e4SLinus Torvalds { 15441da177e4SLinus Torvalds unsigned long flags; 1545eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15461da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1547eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 15481da177e4SLinus Torvalds int change = 0, idx, val; 15491da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 15501da177e4SLinus Torvalds 15511da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 15521da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 15531da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 15541da177e4SLinus Torvalds if (mix->send_volume[0][idx] != val) { 15551da177e4SLinus Torvalds mix->send_volume[0][idx] = val; 15561da177e4SLinus Torvalds change = 1; 15571da177e4SLinus Torvalds } 15581da177e4SLinus Torvalds } 15591da177e4SLinus Torvalds if (change && mix->epcm) { 15601da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 15611da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number, 15621da177e4SLinus Torvalds &mix->send_volume[0][0]); 15631da177e4SLinus Torvalds } 15641da177e4SLinus Torvalds } 15651da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 15661da177e4SLinus Torvalds return change; 15671da177e4SLinus Torvalds } 15681da177e4SLinus Torvalds 15691da177e4SLinus Torvalds 1570f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control = 15711da177e4SLinus Torvalds { 15721da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 15731da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 15741da177e4SLinus Torvalds .name = "Multichannel PCM Send Volume", 15751da177e4SLinus Torvalds .count = 16, 15761da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_volume_info, 15771da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_volume_get, 15781da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_volume_put 15791da177e4SLinus Torvalds }; 15801da177e4SLinus Torvalds 1581eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 15821da177e4SLinus Torvalds { 15831da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 15841da177e4SLinus Torvalds uinfo->count = 1; 15851da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1586bcdbd3b7SOswald Buddenhagen uinfo->value.integer.max = 0x1fffd; 15871da177e4SLinus Torvalds return 0; 15881da177e4SLinus Torvalds } 15891da177e4SLinus Torvalds 1590eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, 1591eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15921da177e4SLinus Torvalds { 1593eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1594eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1595eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 15961da177e4SLinus Torvalds 1597bcdbd3b7SOswald Buddenhagen ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U; 15981da177e4SLinus Torvalds return 0; 15991da177e4SLinus Torvalds } 16001da177e4SLinus Torvalds 1601eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, 1602eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16031da177e4SLinus Torvalds { 16041da177e4SLinus Torvalds unsigned long flags; 1605eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 16061da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1607eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 16081da177e4SLinus Torvalds int change = 0, val; 1609bcdbd3b7SOswald Buddenhagen unsigned uval; 16101da177e4SLinus Torvalds 16111da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 1612bcdbd3b7SOswald Buddenhagen uval = ucontrol->value.integer.value[0] & 0x1ffff; 1613bcdbd3b7SOswald Buddenhagen val = uval * 0x8000U / 0xffffU; 16141da177e4SLinus Torvalds if (mix->attn[0] != val) { 16151da177e4SLinus Torvalds mix->attn[0] = val; 16161da177e4SLinus Torvalds change = 1; 16171da177e4SLinus Torvalds } 16181da177e4SLinus Torvalds if (change && mix->epcm) { 16191da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 16201da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); 16211da177e4SLinus Torvalds } 16221da177e4SLinus Torvalds } 16231da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 16241da177e4SLinus Torvalds return change; 16251da177e4SLinus Torvalds } 16261da177e4SLinus Torvalds 1627f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control = 16281da177e4SLinus Torvalds { 16291da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 16301da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 16311da177e4SLinus Torvalds .name = "Multichannel PCM Volume", 16321da177e4SLinus Torvalds .count = 16, 16331da177e4SLinus Torvalds .info = snd_emu10k1_efx_attn_info, 16341da177e4SLinus Torvalds .get = snd_emu10k1_efx_attn_get, 16351da177e4SLinus Torvalds .put = snd_emu10k1_efx_attn_put 16361da177e4SLinus Torvalds }; 16371da177e4SLinus Torvalds 1638a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info snd_ctl_boolean_mono_info 16391da177e4SLinus Torvalds 1640eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, 1641eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16421da177e4SLinus Torvalds { 1643eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 16441da177e4SLinus Torvalds 16451da177e4SLinus Torvalds if (emu->audigy) 1646a1c87c0bSOswald Buddenhagen ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; 16471da177e4SLinus Torvalds else 16481da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; 1649d2cd74b1STakashi Iwai if (emu->card_capabilities->invert_shared_spdif) 1650d2cd74b1STakashi Iwai ucontrol->value.integer.value[0] = 1651d2cd74b1STakashi Iwai !ucontrol->value.integer.value[0]; 1652d2cd74b1STakashi Iwai 16531da177e4SLinus Torvalds return 0; 16541da177e4SLinus Torvalds } 16551da177e4SLinus Torvalds 1656eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, 1657eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 16581da177e4SLinus Torvalds { 16591da177e4SLinus Torvalds unsigned long flags; 1660eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1661d2cd74b1STakashi Iwai unsigned int reg, val, sw; 16621da177e4SLinus Torvalds int change = 0; 16631da177e4SLinus Torvalds 1664d2cd74b1STakashi Iwai sw = ucontrol->value.integer.value[0]; 1665d2cd74b1STakashi Iwai if (emu->card_capabilities->invert_shared_spdif) 1666d2cd74b1STakashi Iwai sw = !sw; 166750164f69SOswald Buddenhagen spin_lock_irqsave(&emu->emu_lock, flags); 1668184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 1669184c1e2cSJames Courtier-Dutton /* Do nothing for Audigy 2 ZS Notebook */ 1670184c1e2cSJames Courtier-Dutton } else if (emu->audigy) { 1671a1c87c0bSOswald Buddenhagen reg = inw(emu->port + A_IOCFG); 1672d2cd74b1STakashi Iwai val = sw ? A_IOCFG_GPOUT0 : 0; 16731da177e4SLinus Torvalds change = (reg & A_IOCFG_GPOUT0) != val; 16741da177e4SLinus Torvalds if (change) { 16751da177e4SLinus Torvalds reg &= ~A_IOCFG_GPOUT0; 16761da177e4SLinus Torvalds reg |= val; 1677a1c87c0bSOswald Buddenhagen outw(reg | val, emu->port + A_IOCFG); 16781da177e4SLinus Torvalds } 16791da177e4SLinus Torvalds } 16801da177e4SLinus Torvalds reg = inl(emu->port + HCFG); 1681d2cd74b1STakashi Iwai val = sw ? HCFG_GPOUT0 : 0; 16821da177e4SLinus Torvalds change |= (reg & HCFG_GPOUT0) != val; 16831da177e4SLinus Torvalds if (change) { 16841da177e4SLinus Torvalds reg &= ~HCFG_GPOUT0; 16851da177e4SLinus Torvalds reg |= val; 16861da177e4SLinus Torvalds outl(reg | val, emu->port + HCFG); 16871da177e4SLinus Torvalds } 168850164f69SOswald Buddenhagen spin_unlock_irqrestore(&emu->emu_lock, flags); 16891da177e4SLinus Torvalds return change; 16901da177e4SLinus Torvalds } 16911da177e4SLinus Torvalds 1692f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif = 16931da177e4SLinus Torvalds { 16941da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 16951da177e4SLinus Torvalds .name = "SB Live Analog/Digital Output Jack", 16961da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 16971da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 16981da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 16991da177e4SLinus Torvalds }; 17001da177e4SLinus Torvalds 1701f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif = 17021da177e4SLinus Torvalds { 17031da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 17041da177e4SLinus Torvalds .name = "Audigy Analog/Digital Output Jack", 17051da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 17061da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 17071da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 17081da177e4SLinus Torvalds }; 17091da177e4SLinus Torvalds 171016950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */ 171116950e09STakashi Iwai 171216950e09STakashi Iwai #define snd_audigy_capture_boost_info snd_ctl_boolean_mono_info 171316950e09STakashi Iwai 171416950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol, 171516950e09STakashi Iwai struct snd_ctl_elem_value *ucontrol) 171616950e09STakashi Iwai { 171716950e09STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 171816950e09STakashi Iwai unsigned int val; 171916950e09STakashi Iwai 172016950e09STakashi Iwai /* FIXME: better to use a cached version */ 172116950e09STakashi Iwai val = snd_ac97_read(emu->ac97, AC97_REC_GAIN); 172216950e09STakashi Iwai ucontrol->value.integer.value[0] = !!val; 172316950e09STakashi Iwai return 0; 172416950e09STakashi Iwai } 172516950e09STakashi Iwai 172616950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, 172716950e09STakashi Iwai struct snd_ctl_elem_value *ucontrol) 172816950e09STakashi Iwai { 172916950e09STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 173016950e09STakashi Iwai unsigned int val; 173116950e09STakashi Iwai 173216950e09STakashi Iwai if (ucontrol->value.integer.value[0]) 173316950e09STakashi Iwai val = 0x0f0f; 173416950e09STakashi Iwai else 173516950e09STakashi Iwai val = 0; 173616950e09STakashi Iwai return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); 173716950e09STakashi Iwai } 173816950e09STakashi Iwai 1739f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost = 174016950e09STakashi Iwai { 174116950e09STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 17422a52feb1SMaciej S. Szmigiero .name = "Mic Extra Boost", 174316950e09STakashi Iwai .info = snd_audigy_capture_boost_info, 174416950e09STakashi Iwai .get = snd_audigy_capture_boost_get, 174516950e09STakashi Iwai .put = snd_audigy_capture_boost_put 174616950e09STakashi Iwai }; 174716950e09STakashi Iwai 174816950e09STakashi Iwai 17491da177e4SLinus Torvalds /* 17501da177e4SLinus Torvalds */ 1751eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) 17521da177e4SLinus Torvalds { 1753eb4698f3STakashi Iwai struct snd_emu10k1 *emu = ac97->private_data; 17541da177e4SLinus Torvalds emu->ac97 = NULL; 17551da177e4SLinus Torvalds } 17561da177e4SLinus Torvalds 17571da177e4SLinus Torvalds /* 17581da177e4SLinus Torvalds */ 1759eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name) 17601da177e4SLinus Torvalds { 1761eb4698f3STakashi Iwai struct snd_ctl_elem_id id; 17621da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 17631da177e4SLinus Torvalds strcpy(id.name, name); 17641da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 17651da177e4SLinus Torvalds return snd_ctl_remove_id(card, &id); 17661da177e4SLinus Torvalds } 17671da177e4SLinus Torvalds 1768eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) 17691da177e4SLinus Torvalds { 1770eb4698f3STakashi Iwai struct snd_ctl_elem_id sid; 17711da177e4SLinus Torvalds memset(&sid, 0, sizeof(sid)); 17721da177e4SLinus Torvalds strcpy(sid.name, name); 17731da177e4SLinus Torvalds sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 17741da177e4SLinus Torvalds return snd_ctl_find_id(card, &sid); 17751da177e4SLinus Torvalds } 17761da177e4SLinus Torvalds 1777eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst) 17781da177e4SLinus Torvalds { 1779eb4698f3STakashi Iwai struct snd_kcontrol *kctl = ctl_find(card, src); 17801da177e4SLinus Torvalds if (kctl) { 178136476b81SMaciej S. Szmigiero snd_ctl_rename(card, kctl, dst); 17821da177e4SLinus Torvalds return 0; 17831da177e4SLinus Torvalds } 17841da177e4SLinus Torvalds return -ENOENT; 17851da177e4SLinus Torvalds } 17861da177e4SLinus Torvalds 1787e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu, 178867ed4161SClemens Ladisch int pcm_device, int multi_device) 17891da177e4SLinus Torvalds { 1790155e3d3bSOswald Buddenhagen int err; 1791eb4698f3STakashi Iwai struct snd_kcontrol *kctl; 1792eb4698f3STakashi Iwai struct snd_card *card = emu->card; 17936fddce26STakashi Iwai const char * const *c; 17946fddce26STakashi Iwai static const char * const emu10k1_remove_ctls[] = { 17951da177e4SLinus Torvalds /* no AC97 mono, surround, center/lfe */ 17961da177e4SLinus Torvalds "Master Mono Playback Switch", 17971da177e4SLinus Torvalds "Master Mono Playback Volume", 17981da177e4SLinus Torvalds "PCM Out Path & Mute", 17991da177e4SLinus Torvalds "Mono Output Select", 18001da177e4SLinus Torvalds "Surround Playback Switch", 18011da177e4SLinus Torvalds "Surround Playback Volume", 18021da177e4SLinus Torvalds "Center Playback Switch", 18031da177e4SLinus Torvalds "Center Playback Volume", 18041da177e4SLinus Torvalds "LFE Playback Switch", 18051da177e4SLinus Torvalds "LFE Playback Volume", 18061da177e4SLinus Torvalds NULL 18071da177e4SLinus Torvalds }; 18086fddce26STakashi Iwai static const char * const emu10k1_rename_ctls[] = { 18091da177e4SLinus Torvalds "Surround Digital Playback Volume", "Surround Playback Volume", 18101da177e4SLinus Torvalds "Center Digital Playback Volume", "Center Playback Volume", 18111da177e4SLinus Torvalds "LFE Digital Playback Volume", "LFE Playback Volume", 18121da177e4SLinus Torvalds NULL 18131da177e4SLinus Torvalds }; 18146fddce26STakashi Iwai static const char * const audigy_remove_ctls[] = { 18151da177e4SLinus Torvalds /* Master/PCM controls on ac97 of Audigy has no effect */ 181621fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 181721fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 18181da177e4SLinus Torvalds "PCM Playback Switch", 18191da177e4SLinus Torvalds "PCM Playback Volume", 18201da177e4SLinus Torvalds "Master Playback Switch", 18211da177e4SLinus Torvalds "Master Playback Volume", 18221da177e4SLinus Torvalds "PCM Out Path & Mute", 18231da177e4SLinus Torvalds "Mono Output Select", 18241da177e4SLinus Torvalds /* remove unused AC97 capture controls */ 18251da177e4SLinus Torvalds "Capture Source", 18261da177e4SLinus Torvalds "Capture Switch", 18271da177e4SLinus Torvalds "Capture Volume", 18281da177e4SLinus Torvalds "Mic Select", 1829274b2000SMaciej S. Szmigiero "Headphone Playback Switch", 1830274b2000SMaciej S. Szmigiero "Headphone Playback Volume", 1831274b2000SMaciej S. Szmigiero "3D Control - Center", 1832274b2000SMaciej S. Szmigiero "3D Control - Depth", 1833274b2000SMaciej S. Szmigiero "3D Control - Switch", 18341da177e4SLinus Torvalds "Video Playback Switch", 18351da177e4SLinus Torvalds "Video Playback Volume", 18361da177e4SLinus Torvalds "Mic Playback Switch", 18371da177e4SLinus Torvalds "Mic Playback Volume", 1838274b2000SMaciej S. Szmigiero "External Amplifier", 18391da177e4SLinus Torvalds NULL 18401da177e4SLinus Torvalds }; 18416fddce26STakashi Iwai static const char * const audigy_rename_ctls[] = { 18421da177e4SLinus Torvalds /* use conventional names */ 18431da177e4SLinus Torvalds "Wave Playback Volume", "PCM Playback Volume", 18441da177e4SLinus Torvalds /* "Wave Capture Volume", "PCM Capture Volume", */ 18451da177e4SLinus Torvalds "Wave Master Playback Volume", "Master Playback Volume", 18461da177e4SLinus Torvalds "AMic Playback Volume", "Mic Playback Volume", 184752051942SMaciej S. Szmigiero "Master Mono Playback Switch", "Phone Output Playback Switch", 184852051942SMaciej S. Szmigiero "Master Mono Playback Volume", "Phone Output Playback Volume", 18491da177e4SLinus Torvalds NULL 18501da177e4SLinus Torvalds }; 18516fddce26STakashi Iwai static const char * const audigy_rename_ctls_i2c_adc[] = { 1852184c1e2cSJames Courtier-Dutton //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", 1853184c1e2cSJames Courtier-Dutton "Line Capture Volume", "Analog Mix Capture Volume", 1854184c1e2cSJames Courtier-Dutton "Wave Playback Volume", "OLD PCM Playback Volume", 1855184c1e2cSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 1856184c1e2cSJames Courtier-Dutton "AMic Playback Volume", "Old Mic Playback Volume", 1857eb41dab6SJames Courtier-Dutton "CD Capture Volume", "IEC958 Optical Capture Volume", 1858184c1e2cSJames Courtier-Dutton NULL 1859184c1e2cSJames Courtier-Dutton }; 18606fddce26STakashi Iwai static const char * const audigy_remove_ctls_i2c_adc[] = { 1861184c1e2cSJames Courtier-Dutton /* On the Audigy2 ZS Notebook 1862184c1e2cSJames Courtier-Dutton * Capture via WM8775 */ 1863184c1e2cSJames Courtier-Dutton "Mic Capture Volume", 1864184c1e2cSJames Courtier-Dutton "Analog Mix Capture Volume", 1865184c1e2cSJames Courtier-Dutton "Aux Capture Volume", 1866eb41dab6SJames Courtier-Dutton "IEC958 Optical Capture Volume", 1867184c1e2cSJames Courtier-Dutton NULL 1868184c1e2cSJames Courtier-Dutton }; 18696fddce26STakashi Iwai static const char * const audigy_remove_ctls_1361t_adc[] = { 187021fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 187121fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 187221fdddeaSJames Courtier-Dutton "PCM Playback Switch", 187321fdddeaSJames Courtier-Dutton "PCM Playback Volume", 187421fdddeaSJames Courtier-Dutton "Capture Source", 187521fdddeaSJames Courtier-Dutton "Capture Switch", 187621fdddeaSJames Courtier-Dutton "Capture Volume", 187721fdddeaSJames Courtier-Dutton "Mic Capture Volume", 187821fdddeaSJames Courtier-Dutton "Headphone Playback Switch", 187921fdddeaSJames Courtier-Dutton "Headphone Playback Volume", 188021fdddeaSJames Courtier-Dutton "3D Control - Center", 188121fdddeaSJames Courtier-Dutton "3D Control - Depth", 188221fdddeaSJames Courtier-Dutton "3D Control - Switch", 188321fdddeaSJames Courtier-Dutton "Line2 Playback Volume", 188421fdddeaSJames Courtier-Dutton "Line2 Capture Volume", 188521fdddeaSJames Courtier-Dutton NULL 188621fdddeaSJames Courtier-Dutton }; 18876fddce26STakashi Iwai static const char * const audigy_rename_ctls_1361t_adc[] = { 188821fdddeaSJames Courtier-Dutton "Master Playback Switch", "Master Capture Switch", 188921fdddeaSJames Courtier-Dutton "Master Playback Volume", "Master Capture Volume", 189021fdddeaSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 1891d355c82aSJaroslav Kysela "Beep Playback Switch", "Beep Capture Switch", 1892d355c82aSJaroslav Kysela "Beep Playback Volume", "Beep Capture Volume", 189321fdddeaSJames Courtier-Dutton "Phone Playback Switch", "Phone Capture Switch", 189421fdddeaSJames Courtier-Dutton "Phone Playback Volume", "Phone Capture Volume", 189521fdddeaSJames Courtier-Dutton "Mic Playback Switch", "Mic Capture Switch", 189621fdddeaSJames Courtier-Dutton "Mic Playback Volume", "Mic Capture Volume", 189721fdddeaSJames Courtier-Dutton "Line Playback Switch", "Line Capture Switch", 189821fdddeaSJames Courtier-Dutton "Line Playback Volume", "Line Capture Volume", 189921fdddeaSJames Courtier-Dutton "CD Playback Switch", "CD Capture Switch", 190021fdddeaSJames Courtier-Dutton "CD Playback Volume", "CD Capture Volume", 190121fdddeaSJames Courtier-Dutton "Aux Playback Switch", "Aux Capture Switch", 190221fdddeaSJames Courtier-Dutton "Aux Playback Volume", "Aux Capture Volume", 190321fdddeaSJames Courtier-Dutton "Video Playback Switch", "Video Capture Switch", 190421fdddeaSJames Courtier-Dutton "Video Playback Volume", "Video Capture Volume", 190552051942SMaciej S. Szmigiero "Master Mono Playback Switch", "Phone Output Playback Switch", 190652051942SMaciej S. Szmigiero "Master Mono Playback Volume", "Phone Output Playback Volume", 190721fdddeaSJames Courtier-Dutton NULL 190821fdddeaSJames Courtier-Dutton }; 19091da177e4SLinus Torvalds 19102b637da5SLee Revell if (emu->card_capabilities->ac97_chip) { 1911eb4698f3STakashi Iwai struct snd_ac97_bus *pbus; 1912eb4698f3STakashi Iwai struct snd_ac97_template ac97; 191351055da5STakashi Iwai static const struct snd_ac97_bus_ops ops = { 19141da177e4SLinus Torvalds .write = snd_emu10k1_ac97_write, 19151da177e4SLinus Torvalds .read = snd_emu10k1_ac97_read, 19161da177e4SLinus Torvalds }; 19171da177e4SLinus Torvalds 191812bda107STakashi Iwai err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus); 191912bda107STakashi Iwai if (err < 0) 19201da177e4SLinus Torvalds return err; 19211da177e4SLinus Torvalds pbus->no_vra = 1; /* we don't need VRA */ 19221da177e4SLinus Torvalds 19231da177e4SLinus Torvalds memset(&ac97, 0, sizeof(ac97)); 19241da177e4SLinus Torvalds ac97.private_data = emu; 19251da177e4SLinus Torvalds ac97.private_free = snd_emu10k1_mixer_free_ac97; 19261da177e4SLinus Torvalds ac97.scaps = AC97_SCAP_NO_SPDIF; 192712bda107STakashi Iwai err = snd_ac97_mixer(pbus, &ac97, &emu->ac97); 192812bda107STakashi Iwai if (err < 0) { 1929b1508693STakashi Iwai if (emu->card_capabilities->ac97_chip == 1) 19301da177e4SLinus Torvalds return err; 19316f002b02STakashi Iwai dev_info(emu->card->dev, 19326f002b02STakashi Iwai "AC97 is optional on this board\n"); 19336f002b02STakashi Iwai dev_info(emu->card->dev, 19346f002b02STakashi Iwai "Proceeding without ac97 mixers...\n"); 1935b1508693STakashi Iwai snd_device_free(emu->card, pbus); 1936b1508693STakashi Iwai goto no_ac97; /* FIXME: get rid of ugly gotos.. */ 1937b1508693STakashi Iwai } 19381da177e4SLinus Torvalds if (emu->audigy) { 19391da177e4SLinus Torvalds /* set master volume to 0 dB */ 19404d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); 19411da177e4SLinus Torvalds /* set capture source to mic */ 19424d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); 194352051942SMaciej S. Szmigiero /* set mono output (TAD) to mic */ 194452051942SMaciej S. Szmigiero snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE, 194552051942SMaciej S. Szmigiero 0x0200, 0x0200); 194621fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 194721fdddeaSJames Courtier-Dutton c = audigy_remove_ctls_1361t_adc; 194821fdddeaSJames Courtier-Dutton else 19491da177e4SLinus Torvalds c = audigy_remove_ctls; 19501da177e4SLinus Torvalds } else { 19511da177e4SLinus Torvalds /* 19521da177e4SLinus Torvalds * Credits for cards based on STAC9758: 19531da177e4SLinus Torvalds * James Courtier-Dutton <James@superbug.demon.co.uk> 19541da177e4SLinus Torvalds * Voluspa <voluspa@comhem.se> 19551da177e4SLinus Torvalds */ 19561da177e4SLinus Torvalds if (emu->ac97->id == AC97_ID_STAC9758) { 19571da177e4SLinus Torvalds emu->rear_ac97 = 1; 19581da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); 19592594d960SRolf Stefan Wilke snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); 1960b6a48404SRaymond Yau remove_ctl(card,"Front Playback Volume"); 1961b6a48404SRaymond Yau remove_ctl(card,"Front Playback Switch"); 19621da177e4SLinus Torvalds } 19631da177e4SLinus Torvalds /* remove unused AC97 controls */ 19644d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); 19654d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); 19661da177e4SLinus Torvalds c = emu10k1_remove_ctls; 19671da177e4SLinus Torvalds } 19681da177e4SLinus Torvalds for (; *c; c++) 19691da177e4SLinus Torvalds remove_ctl(card, *c); 1970184c1e2cSJames Courtier-Dutton } else if (emu->card_capabilities->i2c_adc) { 1971184c1e2cSJames Courtier-Dutton c = audigy_remove_ctls_i2c_adc; 1972184c1e2cSJames Courtier-Dutton for (; *c; c++) 1973184c1e2cSJames Courtier-Dutton remove_ctl(card, *c); 19741da177e4SLinus Torvalds } else { 1975f12aa40cSTakashi Iwai no_ac97: 19762b637da5SLee Revell if (emu->card_capabilities->ecard) 19771da177e4SLinus Torvalds strcpy(emu->card->mixername, "EMU APS"); 19781da177e4SLinus Torvalds else if (emu->audigy) 19791da177e4SLinus Torvalds strcpy(emu->card->mixername, "SB Audigy"); 19801da177e4SLinus Torvalds else 19811da177e4SLinus Torvalds strcpy(emu->card->mixername, "Emu10k1"); 19821da177e4SLinus Torvalds } 19831da177e4SLinus Torvalds 19841da177e4SLinus Torvalds if (emu->audigy) 198521fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 198621fdddeaSJames Courtier-Dutton c = audigy_rename_ctls_1361t_adc; 1987184c1e2cSJames Courtier-Dutton else if (emu->card_capabilities->i2c_adc) 1988184c1e2cSJames Courtier-Dutton c = audigy_rename_ctls_i2c_adc; 198921fdddeaSJames Courtier-Dutton else 19901da177e4SLinus Torvalds c = audigy_rename_ctls; 19911da177e4SLinus Torvalds else 19921da177e4SLinus Torvalds c = emu10k1_rename_ctls; 19931da177e4SLinus Torvalds for (; *c; c += 2) 19941da177e4SLinus Torvalds rename_ctl(card, c[0], c[1]); 199521fdddeaSJames Courtier-Dutton 1996e217b960SRaymond Yau if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */ 1997e217b960SRaymond Yau remove_ctl(card, "Center Playback Volume"); 1998e217b960SRaymond Yau remove_ctl(card, "LFE Playback Volume"); 1999e217b960SRaymond Yau remove_ctl(card, "Wave Center Playback Volume"); 2000e217b960SRaymond Yau remove_ctl(card, "Wave LFE Playback Volume"); 2001e217b960SRaymond Yau } 2002e3b9bc0eSJames Courtier-Dutton if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ 2003e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); 2004e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); 2005e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); 2006e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); 2007e3b9bc0eSJames Courtier-Dutton } 200812bda107STakashi Iwai kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu); 200912bda107STakashi Iwai if (!kctl) 20101da177e4SLinus Torvalds return -ENOMEM; 201167ed4161SClemens Ladisch kctl->id.device = pcm_device; 201212bda107STakashi Iwai err = snd_ctl_add(card, kctl); 201312bda107STakashi Iwai if (err) 20141da177e4SLinus Torvalds return err; 201512bda107STakashi Iwai kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu); 201612bda107STakashi Iwai if (!kctl) 20171da177e4SLinus Torvalds return -ENOMEM; 201867ed4161SClemens Ladisch kctl->id.device = pcm_device; 201912bda107STakashi Iwai err = snd_ctl_add(card, kctl); 202012bda107STakashi Iwai if (err) 20211da177e4SLinus Torvalds return err; 202212bda107STakashi Iwai kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu); 202312bda107STakashi Iwai if (!kctl) 20241da177e4SLinus Torvalds return -ENOMEM; 202567ed4161SClemens Ladisch kctl->id.device = pcm_device; 202612bda107STakashi Iwai err = snd_ctl_add(card, kctl); 202712bda107STakashi Iwai if (err) 20281da177e4SLinus Torvalds return err; 20291da177e4SLinus Torvalds 203012bda107STakashi Iwai kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu); 203112bda107STakashi Iwai if (!kctl) 20321da177e4SLinus Torvalds return -ENOMEM; 203367ed4161SClemens Ladisch kctl->id.device = multi_device; 203412bda107STakashi Iwai err = snd_ctl_add(card, kctl); 203512bda107STakashi Iwai if (err) 20361da177e4SLinus Torvalds return err; 20371da177e4SLinus Torvalds 203812bda107STakashi Iwai kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu); 203912bda107STakashi Iwai if (!kctl) 20401da177e4SLinus Torvalds return -ENOMEM; 204167ed4161SClemens Ladisch kctl->id.device = multi_device; 204212bda107STakashi Iwai err = snd_ctl_add(card, kctl); 204312bda107STakashi Iwai if (err) 20441da177e4SLinus Torvalds return err; 20451da177e4SLinus Torvalds 204612bda107STakashi Iwai kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu); 204712bda107STakashi Iwai if (!kctl) 20481da177e4SLinus Torvalds return -ENOMEM; 204967ed4161SClemens Ladisch kctl->id.device = multi_device; 205012bda107STakashi Iwai err = snd_ctl_add(card, kctl); 205112bda107STakashi Iwai if (err) 20521da177e4SLinus Torvalds return err; 20531da177e4SLinus Torvalds 2054a8661af5SOswald Buddenhagen if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) { 20551da177e4SLinus Torvalds /* sb live! and audigy */ 205612bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu); 205712bda107STakashi Iwai if (!kctl) 20581da177e4SLinus Torvalds return -ENOMEM; 20595549d549SClemens Ladisch if (!emu->audigy) 20605549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 206112bda107STakashi Iwai err = snd_ctl_add(card, kctl); 206212bda107STakashi Iwai if (err) 20631da177e4SLinus Torvalds return err; 206412bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu); 206512bda107STakashi Iwai if (!kctl) 20661da177e4SLinus Torvalds return -ENOMEM; 20675549d549SClemens Ladisch if (!emu->audigy) 20685549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 206912bda107STakashi Iwai err = snd_ctl_add(card, kctl); 207012bda107STakashi Iwai if (err) 20711da177e4SLinus Torvalds return err; 20721da177e4SLinus Torvalds } 20731da177e4SLinus Torvalds 2074190d2c46SJames Courtier-Dutton if (emu->card_capabilities->emu_model) { 207519b99fbaSJames Courtier-Dutton ; /* Disable the snd_audigy_spdif_shared_spdif */ 207619b99fbaSJames Courtier-Dutton } else if (emu->audigy) { 207712bda107STakashi Iwai kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu); 207812bda107STakashi Iwai if (!kctl) 20791da177e4SLinus Torvalds return -ENOMEM; 208012bda107STakashi Iwai err = snd_ctl_add(card, kctl); 208112bda107STakashi Iwai if (err) 20821da177e4SLinus Torvalds return err; 2083001f7589SJames Courtier-Dutton #if 0 208412bda107STakashi Iwai kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu); 208512bda107STakashi Iwai if (!kctl) 20861da177e4SLinus Torvalds return -ENOMEM; 208712bda107STakashi Iwai err = snd_ctl_add(card, kctl); 208812bda107STakashi Iwai if (err) 20891da177e4SLinus Torvalds return err; 2090001f7589SJames Courtier-Dutton #endif 20912b637da5SLee Revell } else if (! emu->card_capabilities->ecard) { 20921da177e4SLinus Torvalds /* sb live! */ 209312bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu); 209412bda107STakashi Iwai if (!kctl) 20951da177e4SLinus Torvalds return -ENOMEM; 209612bda107STakashi Iwai err = snd_ctl_add(card, kctl); 209712bda107STakashi Iwai if (err) 20981da177e4SLinus Torvalds return err; 20991da177e4SLinus Torvalds } 21002b637da5SLee Revell if (emu->card_capabilities->ca0151_chip) { /* P16V */ 210112bda107STakashi Iwai err = snd_p16v_mixer(emu); 210212bda107STakashi Iwai if (err) 21031da177e4SLinus Torvalds return err; 21041da177e4SLinus Torvalds } 21051da177e4SLinus Torvalds 21061fc710f0SOswald Buddenhagen if (emu->card_capabilities->emu_model) { 21071fc710f0SOswald Buddenhagen unsigned i, emu_idx = emu1010_idx(emu); 21081fc710f0SOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 21091fc710f0SOswald Buddenhagen &emu1010_routing_info[emu_idx]; 2110*97f1582eSOswald Buddenhagen const struct snd_emu1010_pads_info *emu_pi = &emu1010_pads_info[emu_idx]; 21111fc710f0SOswald Buddenhagen 21121fc710f0SOswald Buddenhagen for (i = 0; i < emu_ri->n_ins; i++) 21131fc710f0SOswald Buddenhagen emu->emu1010.input_source[i] = 21141fc710f0SOswald Buddenhagen emu1010_map_source(emu_ri, emu_ri->in_dflts[i]); 21151fc710f0SOswald Buddenhagen for (i = 0; i < emu_ri->n_outs; i++) 21161fc710f0SOswald Buddenhagen emu->emu1010.output_source[i] = 21171fc710f0SOswald Buddenhagen emu1010_map_source(emu_ri, emu_ri->out_dflts[i]); 21181fc710f0SOswald Buddenhagen snd_emu1010_apply_sources(emu); 21191fc710f0SOswald Buddenhagen 21201c02e366SCtirad Fertr err = snd_ctl_add(card, 21211c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 21221c02e366SCtirad Fertr if (err < 0) 21231c02e366SCtirad Fertr return err; 2124*97f1582eSOswald Buddenhagen 2125*97f1582eSOswald Buddenhagen err = add_ctls(emu, &emu1010_adc_pads_ctl, 2126*97f1582eSOswald Buddenhagen emu_pi->adc_ctls, emu_pi->n_adc_ctls); 2127*97f1582eSOswald Buddenhagen if (err < 0) 2128*97f1582eSOswald Buddenhagen return err; 2129*97f1582eSOswald Buddenhagen err = add_ctls(emu, &emu1010_dac_pads_ctl, 2130*97f1582eSOswald Buddenhagen emu_pi->dac_ctls, emu_pi->n_dac_ctls); 2131*97f1582eSOswald Buddenhagen if (err < 0) 2132*97f1582eSOswald Buddenhagen return err; 2133*97f1582eSOswald Buddenhagen 213499dcab46SMichael Gernoth err = snd_ctl_add(card, 213599dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_out, emu)); 213699dcab46SMichael Gernoth if (err < 0) 213799dcab46SMichael Gernoth return err; 213899dcab46SMichael Gernoth err = snd_ctl_add(card, 213999dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_in, emu)); 214099dcab46SMichael Gernoth if (err < 0) 214199dcab46SMichael Gernoth return err; 21421c02e366SCtirad Fertr 2143*97f1582eSOswald Buddenhagen err = add_emu1010_source_mixers(emu); 214499dcab46SMichael Gernoth if (err < 0) 214599dcab46SMichael Gernoth return err; 21469f4bd5ddSJames Courtier-Dutton } 21479f4bd5ddSJames Courtier-Dutton 2148184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 2149184c1e2cSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); 2150184c1e2cSJames Courtier-Dutton if (err < 0) 2151184c1e2cSJames Courtier-Dutton return err; 2152184c1e2cSJames Courtier-Dutton 2153536438f1SOswald Buddenhagen err = add_ctls(emu, &i2c_volume_ctl, 2154536438f1SOswald Buddenhagen snd_audigy_i2c_volume_ctls, 2155536438f1SOswald Buddenhagen ARRAY_SIZE(snd_audigy_i2c_volume_ctls)); 2156184c1e2cSJames Courtier-Dutton if (err < 0) 2157184c1e2cSJames Courtier-Dutton return err; 2158184c1e2cSJames Courtier-Dutton } 2159184c1e2cSJames Courtier-Dutton 216016950e09STakashi Iwai if (emu->card_capabilities->ac97_chip && emu->audigy) { 216116950e09STakashi Iwai err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost, 216216950e09STakashi Iwai emu)); 216316950e09STakashi Iwai if (err < 0) 216416950e09STakashi Iwai return err; 216516950e09STakashi Iwai } 216616950e09STakashi Iwai 21671da177e4SLinus Torvalds return 0; 21681da177e4SLinus Torvalds } 2169