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 234536438f1SOswald Buddenhagen /* 1616(m) cardbus */ 235536438f1SOswald Buddenhagen 236536438f1SOswald Buddenhagen static const char * const snd_emu1616_output_texts[] = { 237536438f1SOswald Buddenhagen LR_CTLS("Dock DAC1"), 238536438f1SOswald Buddenhagen LR_CTLS("Dock DAC2"), 239536438f1SOswald Buddenhagen LR_CTLS("Dock DAC3"), 240536438f1SOswald Buddenhagen LR_CTLS("Dock SPDIF"), 241536438f1SOswald Buddenhagen ADAT_CTLS("Dock "), 242536438f1SOswald Buddenhagen LR_CTLS("Mana DAC"), 243536438f1SOswald Buddenhagen }; 244536438f1SOswald Buddenhagen 245536438f1SOswald Buddenhagen static const unsigned short emu1616_output_dst[] = { 246536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC1), 247536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC2), 248536438f1SOswald Buddenhagen LR_REGS(EMU_DST_DOCK_DAC3), 249536438f1SOswald Buddenhagen LR_REGS(EMU_DST_MDOCK_SPDIF), 250536438f1SOswald Buddenhagen ADAT_REGS(EMU_DST_MDOCK_ADAT), 251536438f1SOswald Buddenhagen EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT, 252536438f1SOswald Buddenhagen }; 253536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dst) == ARRAY_SIZE(snd_emu1616_output_texts)); 2541c02e366SCtirad Fertr 25513d45709SPavel Hofman /* 256a869057cSOswald Buddenhagen * Data destinations - FPGA outputs going to Alice2 (Audigy) for 25713d45709SPavel Hofman * capture (EMU32 + I2S links) 25813d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 25913d45709SPavel Hofman */ 260536438f1SOswald Buddenhagen 261536438f1SOswald Buddenhagen static const char * const emu1010_input_texts[] = { 262536438f1SOswald Buddenhagen "DSP 0 Capture Enum", 263536438f1SOswald Buddenhagen "DSP 1 Capture Enum", 264536438f1SOswald Buddenhagen "DSP 2 Capture Enum", 265536438f1SOswald Buddenhagen "DSP 3 Capture Enum", 266536438f1SOswald Buddenhagen "DSP 4 Capture Enum", 267536438f1SOswald Buddenhagen "DSP 5 Capture Enum", 268536438f1SOswald Buddenhagen "DSP 6 Capture Enum", 269536438f1SOswald Buddenhagen "DSP 7 Capture Enum", 270536438f1SOswald Buddenhagen "DSP 8 Capture Enum", 271536438f1SOswald Buddenhagen "DSP 9 Capture Enum", 272536438f1SOswald Buddenhagen "DSP A Capture Enum", 273536438f1SOswald Buddenhagen "DSP B Capture Enum", 274536438f1SOswald Buddenhagen "DSP C Capture Enum", 275536438f1SOswald Buddenhagen "DSP D Capture Enum", 276536438f1SOswald Buddenhagen "DSP E Capture Enum", 277536438f1SOswald Buddenhagen "DSP F Capture Enum", 278536438f1SOswald Buddenhagen /* These exist only on rev1 EMU1010 cards. */ 279536438f1SOswald Buddenhagen "DSP 10 Capture Enum", 280536438f1SOswald Buddenhagen "DSP 11 Capture Enum", 281536438f1SOswald Buddenhagen "DSP 12 Capture Enum", 282536438f1SOswald Buddenhagen "DSP 13 Capture Enum", 283536438f1SOswald Buddenhagen "DSP 14 Capture Enum", 284536438f1SOswald Buddenhagen "DSP 15 Capture Enum", 285536438f1SOswald Buddenhagen }; 286536438f1SOswald Buddenhagen 2879b00a1e9SOswald Buddenhagen static const unsigned short emu1010_input_dst[] = { 2889f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_0, 2899f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_1, 2909f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_2, 2919f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_3, 2929f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_4, 2939f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_5, 2949f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_6, 2959f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_7, 2969f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_8, 2979f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_9, 2989f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_A, 2999f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_B, 3009f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_C, 3019f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_D, 3029f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_E, 3039f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_F, 304a869057cSOswald Buddenhagen /* These exist only on rev1 EMU1010 cards. */ 3059f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_LEFT, 3069f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_RIGHT, 3079f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_LEFT, 3089f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_RIGHT, 3099f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_LEFT, 3109f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_RIGHT, 3119f4bd5ddSJames Courtier-Dutton }; 312536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts)); 3139f4bd5ddSJames Courtier-Dutton 314511cbe8fSOswald Buddenhagen struct snd_emu1010_routing_info { 315511cbe8fSOswald Buddenhagen const char * const *src_texts; 316511cbe8fSOswald Buddenhagen const unsigned short *src_regs; 317511cbe8fSOswald Buddenhagen const unsigned short *out_regs; 318511cbe8fSOswald Buddenhagen const unsigned short *in_regs; 319511cbe8fSOswald Buddenhagen unsigned n_srcs; 320511cbe8fSOswald Buddenhagen unsigned n_outs; 321511cbe8fSOswald Buddenhagen unsigned n_ins; 322511cbe8fSOswald Buddenhagen }; 323511cbe8fSOswald Buddenhagen 324511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info emu1010_routing_info[] = { 325511cbe8fSOswald Buddenhagen { 326511cbe8fSOswald Buddenhagen .src_regs = emu1010_src_regs, 327511cbe8fSOswald Buddenhagen .src_texts = emu1010_src_texts, 328511cbe8fSOswald Buddenhagen .n_srcs = ARRAY_SIZE(emu1010_src_texts), 329511cbe8fSOswald Buddenhagen 330511cbe8fSOswald Buddenhagen .out_regs = emu1010_output_dst, 331511cbe8fSOswald Buddenhagen .n_outs = ARRAY_SIZE(emu1010_output_dst), 332511cbe8fSOswald Buddenhagen 333511cbe8fSOswald Buddenhagen .in_regs = emu1010_input_dst, 334511cbe8fSOswald Buddenhagen .n_ins = ARRAY_SIZE(emu1010_input_dst), 335511cbe8fSOswald Buddenhagen }, 336511cbe8fSOswald Buddenhagen { 337511cbe8fSOswald Buddenhagen /* 1616(m) cardbus */ 338511cbe8fSOswald Buddenhagen .src_regs = emu1616_src_regs, 339511cbe8fSOswald Buddenhagen .src_texts = emu1616_src_texts, 340511cbe8fSOswald Buddenhagen .n_srcs = ARRAY_SIZE(emu1616_src_texts), 341511cbe8fSOswald Buddenhagen 342511cbe8fSOswald Buddenhagen .out_regs = emu1616_output_dst, 343511cbe8fSOswald Buddenhagen .n_outs = ARRAY_SIZE(emu1616_output_dst), 344511cbe8fSOswald Buddenhagen 345511cbe8fSOswald Buddenhagen .in_regs = emu1010_input_dst, 346511cbe8fSOswald Buddenhagen .n_ins = ARRAY_SIZE(emu1010_input_dst) - 6, 347511cbe8fSOswald Buddenhagen }, 348511cbe8fSOswald Buddenhagen }; 349511cbe8fSOswald Buddenhagen 350511cbe8fSOswald Buddenhagen static unsigned emu1010_idx(struct snd_emu10k1 *emu) 351511cbe8fSOswald Buddenhagen { 352511cbe8fSOswald Buddenhagen if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 353511cbe8fSOswald Buddenhagen return 1; 354511cbe8fSOswald Buddenhagen else 355511cbe8fSOswald Buddenhagen return 0; 356511cbe8fSOswald Buddenhagen } 357511cbe8fSOswald Buddenhagen 358511cbe8fSOswald Buddenhagen static void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu, 359511cbe8fSOswald Buddenhagen int channel, int src) 360511cbe8fSOswald Buddenhagen { 361511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 362511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 363511cbe8fSOswald Buddenhagen 364511cbe8fSOswald Buddenhagen snd_emu1010_fpga_link_dst_src_write(emu, 365511cbe8fSOswald Buddenhagen emu_ri->out_regs[channel], emu_ri->src_regs[src]); 366511cbe8fSOswald Buddenhagen } 367511cbe8fSOswald Buddenhagen 368511cbe8fSOswald Buddenhagen static void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu, 369511cbe8fSOswald Buddenhagen int channel, int src) 370511cbe8fSOswald Buddenhagen { 371511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 372511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 373511cbe8fSOswald Buddenhagen 374511cbe8fSOswald Buddenhagen snd_emu1010_fpga_link_dst_src_write(emu, 375511cbe8fSOswald Buddenhagen emu_ri->in_regs[channel], emu_ri->src_regs[src]); 376511cbe8fSOswald Buddenhagen } 377511cbe8fSOswald Buddenhagen 3781c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, 3791c02e366SCtirad Fertr struct snd_ctl_elem_info *uinfo) 3809f4bd5ddSJames Courtier-Dutton { 3811c02e366SCtirad Fertr struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 382511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 383511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 3841c02e366SCtirad Fertr 385511cbe8fSOswald Buddenhagen return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts); 3869f4bd5ddSJames Courtier-Dutton } 3879f4bd5ddSJames Courtier-Dutton 3889f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, 3899f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 3909f4bd5ddSJames Courtier-Dutton { 3919f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 392511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 393511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 394511cbe8fSOswald Buddenhagen unsigned channel = kcontrol->private_value; 3959f4bd5ddSJames Courtier-Dutton 396511cbe8fSOswald Buddenhagen if (channel >= emu_ri->n_outs) 39774415a36SJames Courtier-Dutton return -EINVAL; 3989f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; 3999f4bd5ddSJames Courtier-Dutton return 0; 4009f4bd5ddSJames Courtier-Dutton } 4019f4bd5ddSJames Courtier-Dutton 4029f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, 4039f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4049f4bd5ddSJames Courtier-Dutton { 4059f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 406511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 407511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 408511cbe8fSOswald Buddenhagen unsigned val = ucontrol->value.enumerated.item[0]; 409511cbe8fSOswald Buddenhagen unsigned channel = kcontrol->private_value; 410511cbe8fSOswald Buddenhagen int change; 4119f4bd5ddSJames Courtier-Dutton 412511cbe8fSOswald Buddenhagen if (val >= emu_ri->n_srcs) 413aa299d01STakashi Iwai return -EINVAL; 414511cbe8fSOswald Buddenhagen if (channel >= emu_ri->n_outs) 41574415a36SJames Courtier-Dutton return -EINVAL; 416511cbe8fSOswald Buddenhagen change = (emu->emu1010.output_source[channel] != val); 417511cbe8fSOswald Buddenhagen if (change) { 418aa299d01STakashi Iwai emu->emu1010.output_source[channel] = val; 419511cbe8fSOswald Buddenhagen snd_emu1010_output_source_apply(emu, channel, val); 420511cbe8fSOswald Buddenhagen } 421511cbe8fSOswald Buddenhagen return change; 4229f4bd5ddSJames Courtier-Dutton } 4239f4bd5ddSJames Courtier-Dutton 424536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_output_source_ctl = { 425536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 426536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 427536438f1SOswald Buddenhagen .info = snd_emu1010_input_output_source_info, 428536438f1SOswald Buddenhagen .get = snd_emu1010_output_source_get, 429536438f1SOswald Buddenhagen .put = snd_emu1010_output_source_put 430536438f1SOswald Buddenhagen }; 431536438f1SOswald Buddenhagen 4329f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, 4339f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4349f4bd5ddSJames Courtier-Dutton { 4359f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 436511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 437511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 438511cbe8fSOswald Buddenhagen unsigned channel = kcontrol->private_value; 4399f4bd5ddSJames Courtier-Dutton 440511cbe8fSOswald Buddenhagen if (channel >= emu_ri->n_ins) 44174415a36SJames Courtier-Dutton return -EINVAL; 4429f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; 4439f4bd5ddSJames Courtier-Dutton return 0; 4449f4bd5ddSJames Courtier-Dutton } 4459f4bd5ddSJames Courtier-Dutton 4469f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, 4479f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4489f4bd5ddSJames Courtier-Dutton { 4499f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 450511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info *emu_ri = 451511cbe8fSOswald Buddenhagen &emu1010_routing_info[emu1010_idx(emu)]; 452511cbe8fSOswald Buddenhagen unsigned val = ucontrol->value.enumerated.item[0]; 453511cbe8fSOswald Buddenhagen unsigned channel = kcontrol->private_value; 454511cbe8fSOswald Buddenhagen int change; 4559f4bd5ddSJames Courtier-Dutton 456511cbe8fSOswald Buddenhagen if (val >= emu_ri->n_srcs) 457aa299d01STakashi Iwai return -EINVAL; 458511cbe8fSOswald Buddenhagen if (channel >= emu_ri->n_ins) 45974415a36SJames Courtier-Dutton return -EINVAL; 460511cbe8fSOswald Buddenhagen change = (emu->emu1010.input_source[channel] != val); 461511cbe8fSOswald Buddenhagen if (change) { 462aa299d01STakashi Iwai emu->emu1010.input_source[channel] = val; 463511cbe8fSOswald Buddenhagen snd_emu1010_input_source_apply(emu, channel, val); 464511cbe8fSOswald Buddenhagen } 465511cbe8fSOswald Buddenhagen return change; 4669f4bd5ddSJames Courtier-Dutton } 4679f4bd5ddSJames Courtier-Dutton 468536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_input_source_ctl = { 469536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 470536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 471536438f1SOswald Buddenhagen .info = snd_emu1010_input_output_source_info, 472536438f1SOswald Buddenhagen .get = snd_emu1010_input_source_get, 473536438f1SOswald Buddenhagen .put = snd_emu1010_input_source_put 4749f4bd5ddSJames Courtier-Dutton }; 4759f4bd5ddSJames Courtier-Dutton 4761c02e366SCtirad Fertr 477536438f1SOswald Buddenhagen static const char * const snd_emu1010_adc_pads[] = { 478536438f1SOswald Buddenhagen "ADC1 14dB PAD Audio Dock Capture Switch", 479536438f1SOswald Buddenhagen "ADC2 14dB PAD Audio Dock Capture Switch", 480536438f1SOswald Buddenhagen "ADC3 14dB PAD Audio Dock Capture Switch", 481536438f1SOswald Buddenhagen "ADC1 14dB PAD 0202 Capture Switch", 4821c02e366SCtirad Fertr }; 4831c02e366SCtirad Fertr 484536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_adc_pad_regs[] = { 485536438f1SOswald Buddenhagen EMU_HANA_DOCK_ADC_PAD1, 486536438f1SOswald Buddenhagen EMU_HANA_DOCK_ADC_PAD2, 487536438f1SOswald Buddenhagen EMU_HANA_DOCK_ADC_PAD3, 488536438f1SOswald Buddenhagen EMU_HANA_0202_ADC_PAD1, 4899148cc50SJames Courtier-Dutton }; 4909148cc50SJames Courtier-Dutton 491a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info snd_ctl_boolean_mono_info 4929148cc50SJames Courtier-Dutton 4939148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4949148cc50SJames Courtier-Dutton { 4959148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 496536438f1SOswald Buddenhagen unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value]; 497536438f1SOswald Buddenhagen 4989148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; 4999148cc50SJames Courtier-Dutton return 0; 5009148cc50SJames Courtier-Dutton } 5019148cc50SJames Courtier-Dutton 5029148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5039148cc50SJames Courtier-Dutton { 5049148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 505536438f1SOswald Buddenhagen unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value]; 5069148cc50SJames Courtier-Dutton unsigned int val, cache; 5079148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 5089148cc50SJames Courtier-Dutton cache = emu->emu1010.adc_pads; 5099148cc50SJames Courtier-Dutton if (val == 1) 5109148cc50SJames Courtier-Dutton cache = cache | mask; 5119148cc50SJames Courtier-Dutton else 5129148cc50SJames Courtier-Dutton cache = cache & ~mask; 5139148cc50SJames Courtier-Dutton if (cache != emu->emu1010.adc_pads) { 5149148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); 5159148cc50SJames Courtier-Dutton emu->emu1010.adc_pads = cache; 5169148cc50SJames Courtier-Dutton } 5179148cc50SJames Courtier-Dutton 5189148cc50SJames Courtier-Dutton return 0; 5199148cc50SJames Courtier-Dutton } 5209148cc50SJames Courtier-Dutton 521536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_adc_pads_ctl = { 522536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 523536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 524536438f1SOswald Buddenhagen .info = snd_emu1010_adc_pads_info, 525536438f1SOswald Buddenhagen .get = snd_emu1010_adc_pads_get, 526536438f1SOswald Buddenhagen .put = snd_emu1010_adc_pads_put 527536438f1SOswald Buddenhagen }; 5289148cc50SJames Courtier-Dutton 5299148cc50SJames Courtier-Dutton 530536438f1SOswald Buddenhagen static const char * const snd_emu1010_dac_pads[] = { 531536438f1SOswald Buddenhagen "DAC1 Audio Dock 14dB PAD Playback Switch", 532536438f1SOswald Buddenhagen "DAC2 Audio Dock 14dB PAD Playback Switch", 533536438f1SOswald Buddenhagen "DAC3 Audio Dock 14dB PAD Playback Switch", 534536438f1SOswald Buddenhagen "DAC4 Audio Dock 14dB PAD Playback Switch", 535536438f1SOswald Buddenhagen "DAC1 0202 14dB PAD Playback Switch", 536536438f1SOswald Buddenhagen }; 5379148cc50SJames Courtier-Dutton 538536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_dac_regs[] = { 539536438f1SOswald Buddenhagen EMU_HANA_DOCK_DAC_PAD1, 540536438f1SOswald Buddenhagen EMU_HANA_DOCK_DAC_PAD2, 541536438f1SOswald Buddenhagen EMU_HANA_DOCK_DAC_PAD3, 542536438f1SOswald Buddenhagen EMU_HANA_DOCK_DAC_PAD4, 543536438f1SOswald Buddenhagen EMU_HANA_0202_DAC_PAD1, 5449148cc50SJames Courtier-Dutton }; 5459148cc50SJames Courtier-Dutton 546a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info snd_ctl_boolean_mono_info 5479148cc50SJames Courtier-Dutton 5489148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5499148cc50SJames Courtier-Dutton { 5509148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 551536438f1SOswald Buddenhagen unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value]; 552536438f1SOswald Buddenhagen 5539148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; 5549148cc50SJames Courtier-Dutton return 0; 5559148cc50SJames Courtier-Dutton } 5569148cc50SJames Courtier-Dutton 5579148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5589148cc50SJames Courtier-Dutton { 5599148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 560536438f1SOswald Buddenhagen unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value]; 5619148cc50SJames Courtier-Dutton unsigned int val, cache; 562*cc766807SOswald Buddenhagen int change; 563*cc766807SOswald Buddenhagen 5649148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 5659148cc50SJames Courtier-Dutton cache = emu->emu1010.dac_pads; 5669148cc50SJames Courtier-Dutton if (val == 1) 5679148cc50SJames Courtier-Dutton cache = cache | mask; 5689148cc50SJames Courtier-Dutton else 5699148cc50SJames Courtier-Dutton cache = cache & ~mask; 570*cc766807SOswald Buddenhagen change = (cache != emu->emu1010.dac_pads); 571*cc766807SOswald Buddenhagen if (change) { 5729148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); 5739148cc50SJames Courtier-Dutton emu->emu1010.dac_pads = cache; 5749148cc50SJames Courtier-Dutton } 5759148cc50SJames Courtier-Dutton 576*cc766807SOswald Buddenhagen return change; 5779148cc50SJames Courtier-Dutton } 5789148cc50SJames Courtier-Dutton 579536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_dac_pads_ctl = { 580536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 581536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 582536438f1SOswald Buddenhagen .info = snd_emu1010_dac_pads_info, 583536438f1SOswald Buddenhagen .get = snd_emu1010_dac_pads_get, 584536438f1SOswald Buddenhagen .put = snd_emu1010_dac_pads_put 5859f4bd5ddSJames Courtier-Dutton }; 5869f4bd5ddSJames Courtier-Dutton 587b0dbdaeaSJames Courtier-Dutton 588b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, 589b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 590b0dbdaeaSJames Courtier-Dutton { 5911541c66dSTakashi Iwai static const char * const texts[4] = { 592edec7bbbSJames Courtier-Dutton "44100", "48000", "SPDIF", "ADAT" 593b0dbdaeaSJames Courtier-Dutton }; 594b0dbdaeaSJames Courtier-Dutton 5951541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 4, texts); 596b0dbdaeaSJames Courtier-Dutton } 597b0dbdaeaSJames Courtier-Dutton 598b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, 599b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 600b0dbdaeaSJames Courtier-Dutton { 601b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 602b0dbdaeaSJames Courtier-Dutton 603b0dbdaeaSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; 604b0dbdaeaSJames Courtier-Dutton return 0; 605b0dbdaeaSJames Courtier-Dutton } 606b0dbdaeaSJames Courtier-Dutton 607b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, 608b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 609b0dbdaeaSJames Courtier-Dutton { 610b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 611b0dbdaeaSJames Courtier-Dutton unsigned int val; 612b0dbdaeaSJames Courtier-Dutton int change = 0; 613b0dbdaeaSJames Courtier-Dutton 614b0dbdaeaSJames Courtier-Dutton val = ucontrol->value.enumerated.item[0] ; 61574415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 4; */ 61674415a36SJames Courtier-Dutton if (val >= 4) 61774415a36SJames Courtier-Dutton return -EINVAL; 618b0dbdaeaSJames Courtier-Dutton change = (emu->emu1010.internal_clock != val); 619b0dbdaeaSJames Courtier-Dutton if (change) { 620b0dbdaeaSJames Courtier-Dutton emu->emu1010.internal_clock = val; 621b0dbdaeaSJames Courtier-Dutton switch (val) { 622b0dbdaeaSJames Courtier-Dutton case 0: 623b0dbdaeaSJames Courtier-Dutton /* 44100 */ 624b0dbdaeaSJames Courtier-Dutton /* Mute all */ 625b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 626a869057cSOswald Buddenhagen /* Default fallback clock 44.1kHz */ 627b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); 628b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 44.1kHz x1 */ 629b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 630b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); 631b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 632b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 633b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); 634b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 635e40a0b2eSJames Courtier-Dutton msleep(10); 636b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 637b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 638b0dbdaeaSJames Courtier-Dutton break; 639b0dbdaeaSJames Courtier-Dutton case 1: 640b0dbdaeaSJames Courtier-Dutton /* 48000 */ 641b0dbdaeaSJames Courtier-Dutton /* Mute all */ 642b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 643b0dbdaeaSJames Courtier-Dutton /* Default fallback clock 48kHz */ 644b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 645b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 48kHz x1 */ 646b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 647b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); 648b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 649b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 650b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); 651b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 652e40a0b2eSJames Courtier-Dutton msleep(10); 653b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 654b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 655b0dbdaeaSJames Courtier-Dutton break; 656edec7bbbSJames Courtier-Dutton 657edec7bbbSJames Courtier-Dutton case 2: /* Take clock from S/PDIF IN */ 658edec7bbbSJames Courtier-Dutton /* Mute all */ 659edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 660edec7bbbSJames Courtier-Dutton /* Default fallback clock 48kHz */ 661edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 662edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to S/PDIF input */ 663edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 664edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); 665edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 666edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 667edec7bbbSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 668edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 669edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 670edec7bbbSJames Courtier-Dutton msleep(10); 671edec7bbbSJames Courtier-Dutton /* Unmute all */ 672edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 673edec7bbbSJames Courtier-Dutton break; 674edec7bbbSJames Courtier-Dutton 675edec7bbbSJames Courtier-Dutton case 3: 676edec7bbbSJames Courtier-Dutton /* Take clock from ADAT IN */ 677edec7bbbSJames Courtier-Dutton /* Mute all */ 678edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 679edec7bbbSJames Courtier-Dutton /* Default fallback clock 48kHz */ 680edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 681edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to ADAT input */ 682edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 683edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); 684edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 685edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 686edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 687edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 688edec7bbbSJames Courtier-Dutton msleep(10); 689edec7bbbSJames Courtier-Dutton /* Unmute all */ 690edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 691edec7bbbSJames Courtier-Dutton 692edec7bbbSJames Courtier-Dutton 693edec7bbbSJames Courtier-Dutton break; 694b0dbdaeaSJames Courtier-Dutton } 695b0dbdaeaSJames Courtier-Dutton } 696b0dbdaeaSJames Courtier-Dutton return change; 697b0dbdaeaSJames Courtier-Dutton } 698b0dbdaeaSJames Courtier-Dutton 699f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock = 700b0dbdaeaSJames Courtier-Dutton { 701b0dbdaeaSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 702b0dbdaeaSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 703b0dbdaeaSJames Courtier-Dutton .name = "Clock Internal Rate", 704b0dbdaeaSJames Courtier-Dutton .count = 1, 705b0dbdaeaSJames Courtier-Dutton .info = snd_emu1010_internal_clock_info, 706b0dbdaeaSJames Courtier-Dutton .get = snd_emu1010_internal_clock_get, 707b0dbdaeaSJames Courtier-Dutton .put = snd_emu1010_internal_clock_put 708b0dbdaeaSJames Courtier-Dutton }; 709b0dbdaeaSJames Courtier-Dutton 71099dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol, 71199dcab46SMichael Gernoth struct snd_ctl_elem_info *uinfo) 71299dcab46SMichael Gernoth { 71399dcab46SMichael Gernoth static const char * const texts[2] = { 71499dcab46SMichael Gernoth "SPDIF", "ADAT" 71599dcab46SMichael Gernoth }; 71699dcab46SMichael Gernoth 71799dcab46SMichael Gernoth return snd_ctl_enum_info(uinfo, 1, 2, texts); 71899dcab46SMichael Gernoth } 71999dcab46SMichael Gernoth 72099dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol, 72199dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 72299dcab46SMichael Gernoth { 72399dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 72499dcab46SMichael Gernoth 72599dcab46SMichael Gernoth ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out; 72699dcab46SMichael Gernoth return 0; 72799dcab46SMichael Gernoth } 72899dcab46SMichael Gernoth 72999dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol, 73099dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 73199dcab46SMichael Gernoth { 73299dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 73399dcab46SMichael Gernoth unsigned int val; 73499dcab46SMichael Gernoth u32 tmp; 73599dcab46SMichael Gernoth int change = 0; 73699dcab46SMichael Gernoth 73799dcab46SMichael Gernoth val = ucontrol->value.enumerated.item[0]; 73899dcab46SMichael Gernoth /* Limit: uinfo->value.enumerated.items = 2; */ 73999dcab46SMichael Gernoth if (val >= 2) 74099dcab46SMichael Gernoth return -EINVAL; 74199dcab46SMichael Gernoth change = (emu->emu1010.optical_out != val); 74299dcab46SMichael Gernoth if (change) { 74399dcab46SMichael Gernoth emu->emu1010.optical_out = val; 7449d2f3863SOswald Buddenhagen tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) | 7459d2f3863SOswald Buddenhagen (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF); 74699dcab46SMichael Gernoth snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 74799dcab46SMichael Gernoth } 74899dcab46SMichael Gernoth return change; 74999dcab46SMichael Gernoth } 75099dcab46SMichael Gernoth 751f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = { 75299dcab46SMichael Gernoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 75399dcab46SMichael Gernoth .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 75499dcab46SMichael Gernoth .name = "Optical Output Mode", 75599dcab46SMichael Gernoth .count = 1, 75699dcab46SMichael Gernoth .info = snd_emu1010_optical_out_info, 75799dcab46SMichael Gernoth .get = snd_emu1010_optical_out_get, 75899dcab46SMichael Gernoth .put = snd_emu1010_optical_out_put 75999dcab46SMichael Gernoth }; 76099dcab46SMichael Gernoth 76199dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol, 76299dcab46SMichael Gernoth struct snd_ctl_elem_info *uinfo) 76399dcab46SMichael Gernoth { 76499dcab46SMichael Gernoth static const char * const texts[2] = { 76599dcab46SMichael Gernoth "SPDIF", "ADAT" 76699dcab46SMichael Gernoth }; 76799dcab46SMichael Gernoth 76899dcab46SMichael Gernoth return snd_ctl_enum_info(uinfo, 1, 2, texts); 76999dcab46SMichael Gernoth } 77099dcab46SMichael Gernoth 77199dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol, 77299dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 77399dcab46SMichael Gernoth { 77499dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 77599dcab46SMichael Gernoth 77699dcab46SMichael Gernoth ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in; 77799dcab46SMichael Gernoth return 0; 77899dcab46SMichael Gernoth } 77999dcab46SMichael Gernoth 78099dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol, 78199dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 78299dcab46SMichael Gernoth { 78399dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 78499dcab46SMichael Gernoth unsigned int val; 78599dcab46SMichael Gernoth u32 tmp; 78699dcab46SMichael Gernoth int change = 0; 78799dcab46SMichael Gernoth 78899dcab46SMichael Gernoth val = ucontrol->value.enumerated.item[0]; 78999dcab46SMichael Gernoth /* Limit: uinfo->value.enumerated.items = 2; */ 79099dcab46SMichael Gernoth if (val >= 2) 79199dcab46SMichael Gernoth return -EINVAL; 79299dcab46SMichael Gernoth change = (emu->emu1010.optical_in != val); 79399dcab46SMichael Gernoth if (change) { 79499dcab46SMichael Gernoth emu->emu1010.optical_in = val; 7959d2f3863SOswald Buddenhagen tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) | 7969d2f3863SOswald Buddenhagen (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF); 79799dcab46SMichael Gernoth snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 79899dcab46SMichael Gernoth } 79999dcab46SMichael Gernoth return change; 80099dcab46SMichael Gernoth } 80199dcab46SMichael Gernoth 802f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = { 80399dcab46SMichael Gernoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 80499dcab46SMichael Gernoth .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 80599dcab46SMichael Gernoth .name = "Optical Input Mode", 80699dcab46SMichael Gernoth .count = 1, 80799dcab46SMichael Gernoth .info = snd_emu1010_optical_in_info, 80899dcab46SMichael Gernoth .get = snd_emu1010_optical_in_get, 80999dcab46SMichael Gernoth .put = snd_emu1010_optical_in_put 81099dcab46SMichael Gernoth }; 81199dcab46SMichael Gernoth 812184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, 813184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 814184c1e2cSJames Courtier-Dutton { 815184c1e2cSJames Courtier-Dutton #if 0 8161541c66dSTakashi Iwai static const char * const texts[4] = { 817184c1e2cSJames Courtier-Dutton "Unknown1", "Unknown2", "Mic", "Line" 818184c1e2cSJames Courtier-Dutton }; 819184c1e2cSJames Courtier-Dutton #endif 8201541c66dSTakashi Iwai static const char * const texts[2] = { 821184c1e2cSJames Courtier-Dutton "Mic", "Line" 822184c1e2cSJames Courtier-Dutton }; 823184c1e2cSJames Courtier-Dutton 8241541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 2, texts); 825184c1e2cSJames Courtier-Dutton } 826184c1e2cSJames Courtier-Dutton 827184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, 828184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 829184c1e2cSJames Courtier-Dutton { 830184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 831184c1e2cSJames Courtier-Dutton 832184c1e2cSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; 833184c1e2cSJames Courtier-Dutton return 0; 834184c1e2cSJames Courtier-Dutton } 835184c1e2cSJames Courtier-Dutton 836184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, 837184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 838184c1e2cSJames Courtier-Dutton { 839184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 840184c1e2cSJames Courtier-Dutton unsigned int source_id; 841184c1e2cSJames Courtier-Dutton unsigned int ngain, ogain; 842a1c87c0bSOswald Buddenhagen u16 gpio; 843184c1e2cSJames Courtier-Dutton int change = 0; 844184c1e2cSJames Courtier-Dutton unsigned long flags; 845184c1e2cSJames Courtier-Dutton u32 source; 846184c1e2cSJames Courtier-Dutton /* If the capture source has changed, 847184c1e2cSJames Courtier-Dutton * update the capture volume from the cached value 848184c1e2cSJames Courtier-Dutton * for the particular source. 849184c1e2cSJames Courtier-Dutton */ 85074415a36SJames Courtier-Dutton source_id = ucontrol->value.enumerated.item[0]; 85174415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 2; */ 85274415a36SJames Courtier-Dutton /* emu->i2c_capture_volume */ 85374415a36SJames Courtier-Dutton if (source_id >= 2) 85474415a36SJames Courtier-Dutton return -EINVAL; 855184c1e2cSJames Courtier-Dutton change = (emu->i2c_capture_source != source_id); 856184c1e2cSJames Courtier-Dutton if (change) { 857184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 858184c1e2cSJames Courtier-Dutton spin_lock_irqsave(&emu->emu_lock, flags); 859a1c87c0bSOswald Buddenhagen gpio = inw(emu->port + A_IOCFG); 860184c1e2cSJames Courtier-Dutton if (source_id==0) 861a1c87c0bSOswald Buddenhagen outw(gpio | 0x4, emu->port + A_IOCFG); 862184c1e2cSJames Courtier-Dutton else 863a1c87c0bSOswald Buddenhagen outw(gpio & ~0x4, emu->port + A_IOCFG); 864184c1e2cSJames Courtier-Dutton spin_unlock_irqrestore(&emu->emu_lock, flags); 865184c1e2cSJames Courtier-Dutton 866184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ 867184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ 868184c1e2cSJames Courtier-Dutton if (ngain != ogain) 869184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); 870184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ 871184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ 872184c1e2cSJames Courtier-Dutton if (ngain != ogain) 873184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 874184c1e2cSJames Courtier-Dutton 875184c1e2cSJames Courtier-Dutton source = 1 << (source_id + 2); 876184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ 877184c1e2cSJames Courtier-Dutton emu->i2c_capture_source = source_id; 878184c1e2cSJames Courtier-Dutton } 879184c1e2cSJames Courtier-Dutton return change; 880184c1e2cSJames Courtier-Dutton } 881184c1e2cSJames Courtier-Dutton 882f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source = 883184c1e2cSJames Courtier-Dutton { 884184c1e2cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 885184c1e2cSJames Courtier-Dutton .name = "Capture Source", 886184c1e2cSJames Courtier-Dutton .info = snd_audigy_i2c_capture_source_info, 887184c1e2cSJames Courtier-Dutton .get = snd_audigy_i2c_capture_source_get, 888184c1e2cSJames Courtier-Dutton .put = snd_audigy_i2c_capture_source_put 889184c1e2cSJames Courtier-Dutton }; 890184c1e2cSJames Courtier-Dutton 891184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, 892184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 893184c1e2cSJames Courtier-Dutton { 894184c1e2cSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 895184c1e2cSJames Courtier-Dutton uinfo->count = 2; 896184c1e2cSJames Courtier-Dutton uinfo->value.integer.min = 0; 897184c1e2cSJames Courtier-Dutton uinfo->value.integer.max = 255; 898184c1e2cSJames Courtier-Dutton return 0; 899184c1e2cSJames Courtier-Dutton } 900184c1e2cSJames Courtier-Dutton 901184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, 902184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 903184c1e2cSJames Courtier-Dutton { 904184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 90574415a36SJames Courtier-Dutton unsigned int source_id; 906184c1e2cSJames Courtier-Dutton 907184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 90874415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 90974415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 91074415a36SJames Courtier-Dutton if (source_id >= 2) 91174415a36SJames Courtier-Dutton return -EINVAL; 912184c1e2cSJames Courtier-Dutton 913184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; 914184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; 915184c1e2cSJames Courtier-Dutton return 0; 916184c1e2cSJames Courtier-Dutton } 917184c1e2cSJames Courtier-Dutton 918184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, 919184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 920184c1e2cSJames Courtier-Dutton { 921184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 922184c1e2cSJames Courtier-Dutton unsigned int ogain; 92314a29565SOswald Buddenhagen unsigned int ngain0, ngain1; 92474415a36SJames Courtier-Dutton unsigned int source_id; 925184c1e2cSJames Courtier-Dutton int change = 0; 926184c1e2cSJames Courtier-Dutton 927184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 92874415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 92974415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 93074415a36SJames Courtier-Dutton if (source_id >= 2) 93174415a36SJames Courtier-Dutton return -EINVAL; 93214a29565SOswald Buddenhagen ngain0 = ucontrol->value.integer.value[0]; 93314a29565SOswald Buddenhagen ngain1 = ucontrol->value.integer.value[1]; 93414a29565SOswald Buddenhagen if (ngain0 > 0xff) 93514a29565SOswald Buddenhagen return -EINVAL; 93614a29565SOswald Buddenhagen if (ngain1 > 0xff) 93714a29565SOswald Buddenhagen return -EINVAL; 938184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ 93914a29565SOswald Buddenhagen if (ogain != ngain0) { 940184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 94114a29565SOswald Buddenhagen snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0); 94214a29565SOswald Buddenhagen emu->i2c_capture_volume[source_id][0] = ngain0; 943184c1e2cSJames Courtier-Dutton change = 1; 944184c1e2cSJames Courtier-Dutton } 945184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ 94614a29565SOswald Buddenhagen if (ogain != ngain1) { 947184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 94814a29565SOswald Buddenhagen snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1); 94914a29565SOswald Buddenhagen emu->i2c_capture_volume[source_id][1] = ngain1; 950184c1e2cSJames Courtier-Dutton change = 1; 951184c1e2cSJames Courtier-Dutton } 952184c1e2cSJames Courtier-Dutton 953184c1e2cSJames Courtier-Dutton return change; 954184c1e2cSJames Courtier-Dutton } 955184c1e2cSJames Courtier-Dutton 956536438f1SOswald Buddenhagen static const struct snd_kcontrol_new i2c_volume_ctl = { 957536438f1SOswald Buddenhagen .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 958536438f1SOswald Buddenhagen .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 959536438f1SOswald Buddenhagen SNDRV_CTL_ELEM_ACCESS_TLV_READ, 960536438f1SOswald Buddenhagen .info = snd_audigy_i2c_volume_info, 961536438f1SOswald Buddenhagen .get = snd_audigy_i2c_volume_get, 962536438f1SOswald Buddenhagen .put = snd_audigy_i2c_volume_put, 963536438f1SOswald Buddenhagen .tlv = { .p = snd_audigy_db_scale2 } 964536438f1SOswald Buddenhagen }; 965184c1e2cSJames Courtier-Dutton 966536438f1SOswald Buddenhagen static const char * const snd_audigy_i2c_volume_ctls[] = { 967536438f1SOswald Buddenhagen "Mic Capture Volume", 968536438f1SOswald Buddenhagen "Line Capture Volume", 969184c1e2cSJames Courtier-Dutton }; 970184c1e2cSJames Courtier-Dutton 9710af68e5eSTakashi Iwai #if 0 972eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 9731da177e4SLinus Torvalds { 9741541c66dSTakashi Iwai static const char * const texts[] = {"44100", "48000", "96000"}; 9751da177e4SLinus Torvalds 9761541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 3, texts); 9771da177e4SLinus Torvalds } 9781da177e4SLinus Torvalds 979eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, 980eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9811da177e4SLinus Torvalds { 982eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 9831da177e4SLinus Torvalds unsigned int tmp; 9841da177e4SLinus Torvalds 9851da177e4SLinus Torvalds tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 9861da177e4SLinus Torvalds switch (tmp & A_SPDIF_RATE_MASK) { 9871da177e4SLinus Torvalds case A_SPDIF_44100: 9881da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 9891da177e4SLinus Torvalds break; 9901da177e4SLinus Torvalds case A_SPDIF_48000: 9911da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 9921da177e4SLinus Torvalds break; 9931da177e4SLinus Torvalds case A_SPDIF_96000: 9941da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 9951da177e4SLinus Torvalds break; 9961da177e4SLinus Torvalds default: 9971da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 9981da177e4SLinus Torvalds } 9991da177e4SLinus Torvalds return 0; 10001da177e4SLinus Torvalds } 10011da177e4SLinus Torvalds 1002eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, 1003eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10041da177e4SLinus Torvalds { 1005eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 10061da177e4SLinus Torvalds int change; 10071da177e4SLinus Torvalds unsigned int reg, val, tmp; 10081da177e4SLinus Torvalds unsigned long flags; 10091da177e4SLinus Torvalds 10101da177e4SLinus Torvalds switch(ucontrol->value.enumerated.item[0]) { 10111da177e4SLinus Torvalds case 0: 10121da177e4SLinus Torvalds val = A_SPDIF_44100; 10131da177e4SLinus Torvalds break; 10141da177e4SLinus Torvalds case 1: 10151da177e4SLinus Torvalds val = A_SPDIF_48000; 10161da177e4SLinus Torvalds break; 10171da177e4SLinus Torvalds case 2: 10181da177e4SLinus Torvalds val = A_SPDIF_96000; 10191da177e4SLinus Torvalds break; 10201da177e4SLinus Torvalds default: 10211da177e4SLinus Torvalds val = A_SPDIF_48000; 10221da177e4SLinus Torvalds break; 10231da177e4SLinus Torvalds } 10241da177e4SLinus Torvalds 10251da177e4SLinus Torvalds 10261da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 10271da177e4SLinus Torvalds reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 10281da177e4SLinus Torvalds tmp = reg & ~A_SPDIF_RATE_MASK; 10291da177e4SLinus Torvalds tmp |= val; 103012bda107STakashi Iwai change = (tmp != reg); 103112bda107STakashi Iwai if (change) 10321da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); 10331da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 10341da177e4SLinus Torvalds return change; 10351da177e4SLinus Torvalds } 10361da177e4SLinus Torvalds 1037b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate = 10381da177e4SLinus Torvalds { 10391da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 10401da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 10411da177e4SLinus Torvalds .name = "Audigy SPDIF Output Sample Rate", 10421da177e4SLinus Torvalds .count = 1, 10431da177e4SLinus Torvalds .info = snd_audigy_spdif_output_rate_info, 10441da177e4SLinus Torvalds .get = snd_audigy_spdif_output_rate_get, 10451da177e4SLinus Torvalds .put = snd_audigy_spdif_output_rate_put 10461da177e4SLinus Torvalds }; 10470af68e5eSTakashi Iwai #endif 10481da177e4SLinus Torvalds 1049eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, 1050eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10511da177e4SLinus Torvalds { 1052eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 10531da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 10541da177e4SLinus Torvalds int change; 10551da177e4SLinus Torvalds unsigned int val; 10561da177e4SLinus Torvalds 105774415a36SJames Courtier-Dutton /* Limit: emu->spdif_bits */ 105874415a36SJames Courtier-Dutton if (idx >= 3) 105974415a36SJames Courtier-Dutton return -EINVAL; 10601da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) | 10611da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) | 10621da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) | 10631da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24); 10641da177e4SLinus Torvalds change = val != emu->spdif_bits[idx]; 10651da177e4SLinus Torvalds if (change) { 10661da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); 10671da177e4SLinus Torvalds emu->spdif_bits[idx] = val; 10681da177e4SLinus Torvalds } 10691da177e4SLinus Torvalds return change; 10701da177e4SLinus Torvalds } 10711da177e4SLinus Torvalds 1072f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = 10731da177e4SLinus Torvalds { 10741da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 10755549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10761da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 10777583cb51STakashi Iwai .count = 3, 10781da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 10791da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get_mask 10801da177e4SLinus Torvalds }; 10811da177e4SLinus Torvalds 1082f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control = 10831da177e4SLinus Torvalds { 10845549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10851da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 10867583cb51STakashi Iwai .count = 3, 10871da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 10881da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get, 10891da177e4SLinus Torvalds .put = snd_emu10k1_spdif_put 10901da177e4SLinus Torvalds }; 10911da177e4SLinus Torvalds 10921da177e4SLinus Torvalds 1093eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route) 10941da177e4SLinus Torvalds { 10951da177e4SLinus Torvalds if (emu->audigy) { 10961da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT1, voice, 10971da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt1(route)); 10981da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT2, voice, 10991da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt2(route)); 11001da177e4SLinus Torvalds } else { 11011da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXRT, voice, 11021da177e4SLinus Torvalds snd_emu10k1_compose_send_routing(route)); 11031da177e4SLinus Torvalds } 11041da177e4SLinus Torvalds } 11051da177e4SLinus Torvalds 1106eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume) 11071da177e4SLinus Torvalds { 11081da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); 11091da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); 11101da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); 11111da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); 11121da177e4SLinus Torvalds if (emu->audigy) { 111351d652f4SOswald Buddenhagen snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, 111451d652f4SOswald Buddenhagen snd_emu10k1_compose_audigy_sendamounts(volume)); 11151da177e4SLinus Torvalds } 11161da177e4SLinus Torvalds } 11171da177e4SLinus Torvalds 11181da177e4SLinus Torvalds /* PCM stream controls */ 11191da177e4SLinus Torvalds 1120eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 11211da177e4SLinus Torvalds { 1122eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11231da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 11241da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 11251da177e4SLinus Torvalds uinfo->value.integer.min = 0; 11261da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 11271da177e4SLinus Torvalds return 0; 11281da177e4SLinus Torvalds } 11291da177e4SLinus Torvalds 1130eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, 1131eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11321da177e4SLinus Torvalds { 1133eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1134eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1135eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 11361da177e4SLinus Torvalds int voice, idx; 11371da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 11381da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 11391da177e4SLinus Torvalds 11401da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 11411da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 11421da177e4SLinus Torvalds ucontrol->value.integer.value[(voice * num_efx) + idx] = 11431da177e4SLinus Torvalds mix->send_routing[voice][idx] & mask; 11441da177e4SLinus Torvalds return 0; 11451da177e4SLinus Torvalds } 11461da177e4SLinus Torvalds 1147eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, 1148eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11491da177e4SLinus Torvalds { 11501da177e4SLinus Torvalds unsigned long flags; 1151eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1152eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1153eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 11541da177e4SLinus Torvalds int change = 0, voice, idx, val; 11551da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 11561da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 11571da177e4SLinus Torvalds 11581da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 11591da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 11601da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 11611da177e4SLinus Torvalds val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; 11621da177e4SLinus Torvalds if (mix->send_routing[voice][idx] != val) { 11631da177e4SLinus Torvalds mix->send_routing[voice][idx] = val; 11641da177e4SLinus Torvalds change = 1; 11651da177e4SLinus Torvalds } 11661da177e4SLinus Torvalds } 11671da177e4SLinus Torvalds if (change && mix->epcm) { 11681da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 11691da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 11701da177e4SLinus Torvalds &mix->send_routing[1][0]); 11711da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, 11721da177e4SLinus Torvalds &mix->send_routing[2][0]); 11731da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 11741da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 11751da177e4SLinus Torvalds &mix->send_routing[0][0]); 11761da177e4SLinus Torvalds } 11771da177e4SLinus Torvalds } 11781da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11791da177e4SLinus Torvalds return change; 11801da177e4SLinus Torvalds } 11811da177e4SLinus Torvalds 1182f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control = 11831da177e4SLinus Torvalds { 11841da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 118567ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 11861da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Routing", 11871da177e4SLinus Torvalds .count = 32, 11881da177e4SLinus Torvalds .info = snd_emu10k1_send_routing_info, 11891da177e4SLinus Torvalds .get = snd_emu10k1_send_routing_get, 11901da177e4SLinus Torvalds .put = snd_emu10k1_send_routing_put 11911da177e4SLinus Torvalds }; 11921da177e4SLinus Torvalds 1193eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 11941da177e4SLinus Torvalds { 1195eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11961da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 11971da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 11981da177e4SLinus Torvalds uinfo->value.integer.min = 0; 11991da177e4SLinus Torvalds uinfo->value.integer.max = 255; 12001da177e4SLinus Torvalds return 0; 12011da177e4SLinus Torvalds } 12021da177e4SLinus Torvalds 1203eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, 1204eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12051da177e4SLinus Torvalds { 1206eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1207eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1208eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12091da177e4SLinus Torvalds int idx; 12101da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 12111da177e4SLinus Torvalds 12121da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) 12131da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; 12141da177e4SLinus Torvalds return 0; 12151da177e4SLinus Torvalds } 12161da177e4SLinus Torvalds 1217eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, 1218eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12191da177e4SLinus Torvalds { 12201da177e4SLinus Torvalds unsigned long flags; 1221eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1222eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1223eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12241da177e4SLinus Torvalds int change = 0, idx, val; 12251da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 12261da177e4SLinus Torvalds 12271da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 12281da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) { 12291da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 12301da177e4SLinus Torvalds if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { 12311da177e4SLinus Torvalds mix->send_volume[idx/num_efx][idx%num_efx] = val; 12321da177e4SLinus Torvalds change = 1; 12331da177e4SLinus Torvalds } 12341da177e4SLinus Torvalds } 12351da177e4SLinus Torvalds if (change && mix->epcm) { 12361da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 12371da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 12381da177e4SLinus Torvalds &mix->send_volume[1][0]); 12391da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, 12401da177e4SLinus Torvalds &mix->send_volume[2][0]); 12411da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 12421da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 12431da177e4SLinus Torvalds &mix->send_volume[0][0]); 12441da177e4SLinus Torvalds } 12451da177e4SLinus Torvalds } 12461da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 12471da177e4SLinus Torvalds return change; 12481da177e4SLinus Torvalds } 12491da177e4SLinus Torvalds 1250f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control = 12511da177e4SLinus Torvalds { 12521da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 125367ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 12541da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Volume", 12551da177e4SLinus Torvalds .count = 32, 12561da177e4SLinus Torvalds .info = snd_emu10k1_send_volume_info, 12571da177e4SLinus Torvalds .get = snd_emu10k1_send_volume_get, 12581da177e4SLinus Torvalds .put = snd_emu10k1_send_volume_put 12591da177e4SLinus Torvalds }; 12601da177e4SLinus Torvalds 1261eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 12621da177e4SLinus Torvalds { 12631da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 12641da177e4SLinus Torvalds uinfo->count = 3; 12651da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1266bcdbd3b7SOswald Buddenhagen uinfo->value.integer.max = 0x1fffd; 12671da177e4SLinus Torvalds return 0; 12681da177e4SLinus Torvalds } 12691da177e4SLinus Torvalds 1270eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, 1271eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12721da177e4SLinus Torvalds { 1273eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1274eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1275eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12761da177e4SLinus Torvalds int idx; 12771da177e4SLinus Torvalds 12781da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) 1279bcdbd3b7SOswald Buddenhagen ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U; 12801da177e4SLinus Torvalds return 0; 12811da177e4SLinus Torvalds } 12821da177e4SLinus Torvalds 1283eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, 1284eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12851da177e4SLinus Torvalds { 12861da177e4SLinus Torvalds unsigned long flags; 1287eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1288eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1289eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12901da177e4SLinus Torvalds int change = 0, idx, val; 12911da177e4SLinus Torvalds 12921da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 12931da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) { 1294bcdbd3b7SOswald Buddenhagen unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff; 1295bcdbd3b7SOswald Buddenhagen val = uval * 0x8000U / 0xffffU; 12961da177e4SLinus Torvalds if (mix->attn[idx] != val) { 12971da177e4SLinus Torvalds mix->attn[idx] = val; 12981da177e4SLinus Torvalds change = 1; 12991da177e4SLinus Torvalds } 13001da177e4SLinus Torvalds } 13011da177e4SLinus Torvalds if (change && mix->epcm) { 13021da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 13031da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); 13041da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]); 13051da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 13061da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); 13071da177e4SLinus Torvalds } 13081da177e4SLinus Torvalds } 13091da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13101da177e4SLinus Torvalds return change; 13111da177e4SLinus Torvalds } 13121da177e4SLinus Torvalds 1313f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control = 13141da177e4SLinus Torvalds { 13151da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 131667ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 13171da177e4SLinus Torvalds .name = "EMU10K1 PCM Volume", 13181da177e4SLinus Torvalds .count = 32, 13191da177e4SLinus Torvalds .info = snd_emu10k1_attn_info, 13201da177e4SLinus Torvalds .get = snd_emu10k1_attn_get, 13211da177e4SLinus Torvalds .put = snd_emu10k1_attn_put 13221da177e4SLinus Torvalds }; 13231da177e4SLinus Torvalds 13241da177e4SLinus Torvalds /* Mutichannel PCM stream controls */ 13251da177e4SLinus Torvalds 1326eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13271da177e4SLinus Torvalds { 1328eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13291da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13301da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 13311da177e4SLinus Torvalds uinfo->value.integer.min = 0; 13321da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 13331da177e4SLinus Torvalds return 0; 13341da177e4SLinus Torvalds } 13351da177e4SLinus Torvalds 1336eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, 1337eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13381da177e4SLinus Torvalds { 1339eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1340eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1341eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13421da177e4SLinus Torvalds int idx; 13431da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 13441da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 13451da177e4SLinus Torvalds 13461da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 13471da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = 13481da177e4SLinus Torvalds mix->send_routing[0][idx] & mask; 13491da177e4SLinus Torvalds return 0; 13501da177e4SLinus Torvalds } 13511da177e4SLinus Torvalds 1352eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, 1353eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13541da177e4SLinus Torvalds { 13551da177e4SLinus Torvalds unsigned long flags; 1356eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13571da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1358eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 13591da177e4SLinus Torvalds int change = 0, idx, val; 13601da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 13611da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 13621da177e4SLinus Torvalds 13631da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13641da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 13651da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & mask; 13661da177e4SLinus Torvalds if (mix->send_routing[0][idx] != val) { 13671da177e4SLinus Torvalds mix->send_routing[0][idx] = val; 13681da177e4SLinus Torvalds change = 1; 13691da177e4SLinus Torvalds } 13701da177e4SLinus Torvalds } 13711da177e4SLinus Torvalds 13721da177e4SLinus Torvalds if (change && mix->epcm) { 13731da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 13741da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number, 13751da177e4SLinus Torvalds &mix->send_routing[0][0]); 13761da177e4SLinus Torvalds } 13771da177e4SLinus Torvalds } 13781da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13791da177e4SLinus Torvalds return change; 13801da177e4SLinus Torvalds } 13811da177e4SLinus Torvalds 1382f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control = 13831da177e4SLinus Torvalds { 13841da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 13851da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 13861da177e4SLinus Torvalds .name = "Multichannel PCM Send Routing", 13871da177e4SLinus Torvalds .count = 16, 13881da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_routing_info, 13891da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_routing_get, 13901da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_routing_put 13911da177e4SLinus Torvalds }; 13921da177e4SLinus Torvalds 1393eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13941da177e4SLinus Torvalds { 1395eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13961da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13971da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 13981da177e4SLinus Torvalds uinfo->value.integer.min = 0; 13991da177e4SLinus Torvalds uinfo->value.integer.max = 255; 14001da177e4SLinus Torvalds return 0; 14011da177e4SLinus Torvalds } 14021da177e4SLinus Torvalds 1403eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, 1404eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14051da177e4SLinus Torvalds { 1406eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1407eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1408eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 14091da177e4SLinus Torvalds int idx; 14101da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 14111da177e4SLinus Torvalds 14121da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 14131da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; 14141da177e4SLinus Torvalds return 0; 14151da177e4SLinus Torvalds } 14161da177e4SLinus Torvalds 1417eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, 1418eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14191da177e4SLinus Torvalds { 14201da177e4SLinus Torvalds unsigned long flags; 1421eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14221da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1423eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 14241da177e4SLinus Torvalds int change = 0, idx, val; 14251da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 14261da177e4SLinus Torvalds 14271da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 14281da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 14291da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 14301da177e4SLinus Torvalds if (mix->send_volume[0][idx] != val) { 14311da177e4SLinus Torvalds mix->send_volume[0][idx] = val; 14321da177e4SLinus Torvalds change = 1; 14331da177e4SLinus Torvalds } 14341da177e4SLinus Torvalds } 14351da177e4SLinus Torvalds if (change && mix->epcm) { 14361da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 14371da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number, 14381da177e4SLinus Torvalds &mix->send_volume[0][0]); 14391da177e4SLinus Torvalds } 14401da177e4SLinus Torvalds } 14411da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 14421da177e4SLinus Torvalds return change; 14431da177e4SLinus Torvalds } 14441da177e4SLinus Torvalds 14451da177e4SLinus Torvalds 1446f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control = 14471da177e4SLinus Torvalds { 14481da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 14491da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14501da177e4SLinus Torvalds .name = "Multichannel PCM Send Volume", 14511da177e4SLinus Torvalds .count = 16, 14521da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_volume_info, 14531da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_volume_get, 14541da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_volume_put 14551da177e4SLinus Torvalds }; 14561da177e4SLinus Torvalds 1457eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 14581da177e4SLinus Torvalds { 14591da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 14601da177e4SLinus Torvalds uinfo->count = 1; 14611da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1462bcdbd3b7SOswald Buddenhagen uinfo->value.integer.max = 0x1fffd; 14631da177e4SLinus Torvalds return 0; 14641da177e4SLinus Torvalds } 14651da177e4SLinus Torvalds 1466eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, 1467eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14681da177e4SLinus Torvalds { 1469eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1470eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1471eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 14721da177e4SLinus Torvalds 1473bcdbd3b7SOswald Buddenhagen ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U; 14741da177e4SLinus Torvalds return 0; 14751da177e4SLinus Torvalds } 14761da177e4SLinus Torvalds 1477eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, 1478eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14791da177e4SLinus Torvalds { 14801da177e4SLinus Torvalds unsigned long flags; 1481eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14821da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1483eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 14841da177e4SLinus Torvalds int change = 0, val; 1485bcdbd3b7SOswald Buddenhagen unsigned uval; 14861da177e4SLinus Torvalds 14871da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 1488bcdbd3b7SOswald Buddenhagen uval = ucontrol->value.integer.value[0] & 0x1ffff; 1489bcdbd3b7SOswald Buddenhagen val = uval * 0x8000U / 0xffffU; 14901da177e4SLinus Torvalds if (mix->attn[0] != val) { 14911da177e4SLinus Torvalds mix->attn[0] = val; 14921da177e4SLinus Torvalds change = 1; 14931da177e4SLinus Torvalds } 14941da177e4SLinus Torvalds if (change && mix->epcm) { 14951da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 14961da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); 14971da177e4SLinus Torvalds } 14981da177e4SLinus Torvalds } 14991da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 15001da177e4SLinus Torvalds return change; 15011da177e4SLinus Torvalds } 15021da177e4SLinus Torvalds 1503f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control = 15041da177e4SLinus Torvalds { 15051da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 15061da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 15071da177e4SLinus Torvalds .name = "Multichannel PCM Volume", 15081da177e4SLinus Torvalds .count = 16, 15091da177e4SLinus Torvalds .info = snd_emu10k1_efx_attn_info, 15101da177e4SLinus Torvalds .get = snd_emu10k1_efx_attn_get, 15111da177e4SLinus Torvalds .put = snd_emu10k1_efx_attn_put 15121da177e4SLinus Torvalds }; 15131da177e4SLinus Torvalds 1514a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info snd_ctl_boolean_mono_info 15151da177e4SLinus Torvalds 1516eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, 1517eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15181da177e4SLinus Torvalds { 1519eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15201da177e4SLinus Torvalds 15211da177e4SLinus Torvalds if (emu->audigy) 1522a1c87c0bSOswald Buddenhagen ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; 15231da177e4SLinus Torvalds else 15241da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; 1525d2cd74b1STakashi Iwai if (emu->card_capabilities->invert_shared_spdif) 1526d2cd74b1STakashi Iwai ucontrol->value.integer.value[0] = 1527d2cd74b1STakashi Iwai !ucontrol->value.integer.value[0]; 1528d2cd74b1STakashi Iwai 15291da177e4SLinus Torvalds return 0; 15301da177e4SLinus Torvalds } 15311da177e4SLinus Torvalds 1532eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, 1533eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15341da177e4SLinus Torvalds { 15351da177e4SLinus Torvalds unsigned long flags; 1536eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1537d2cd74b1STakashi Iwai unsigned int reg, val, sw; 15381da177e4SLinus Torvalds int change = 0; 15391da177e4SLinus Torvalds 1540d2cd74b1STakashi Iwai sw = ucontrol->value.integer.value[0]; 1541d2cd74b1STakashi Iwai if (emu->card_capabilities->invert_shared_spdif) 1542d2cd74b1STakashi Iwai sw = !sw; 154350164f69SOswald Buddenhagen spin_lock_irqsave(&emu->emu_lock, flags); 1544184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 1545184c1e2cSJames Courtier-Dutton /* Do nothing for Audigy 2 ZS Notebook */ 1546184c1e2cSJames Courtier-Dutton } else if (emu->audigy) { 1547a1c87c0bSOswald Buddenhagen reg = inw(emu->port + A_IOCFG); 1548d2cd74b1STakashi Iwai val = sw ? A_IOCFG_GPOUT0 : 0; 15491da177e4SLinus Torvalds change = (reg & A_IOCFG_GPOUT0) != val; 15501da177e4SLinus Torvalds if (change) { 15511da177e4SLinus Torvalds reg &= ~A_IOCFG_GPOUT0; 15521da177e4SLinus Torvalds reg |= val; 1553a1c87c0bSOswald Buddenhagen outw(reg | val, emu->port + A_IOCFG); 15541da177e4SLinus Torvalds } 15551da177e4SLinus Torvalds } 15561da177e4SLinus Torvalds reg = inl(emu->port + HCFG); 1557d2cd74b1STakashi Iwai val = sw ? HCFG_GPOUT0 : 0; 15581da177e4SLinus Torvalds change |= (reg & HCFG_GPOUT0) != val; 15591da177e4SLinus Torvalds if (change) { 15601da177e4SLinus Torvalds reg &= ~HCFG_GPOUT0; 15611da177e4SLinus Torvalds reg |= val; 15621da177e4SLinus Torvalds outl(reg | val, emu->port + HCFG); 15631da177e4SLinus Torvalds } 156450164f69SOswald Buddenhagen spin_unlock_irqrestore(&emu->emu_lock, flags); 15651da177e4SLinus Torvalds return change; 15661da177e4SLinus Torvalds } 15671da177e4SLinus Torvalds 1568f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif = 15691da177e4SLinus Torvalds { 15701da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 15711da177e4SLinus Torvalds .name = "SB Live Analog/Digital Output Jack", 15721da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 15731da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 15741da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 15751da177e4SLinus Torvalds }; 15761da177e4SLinus Torvalds 1577f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif = 15781da177e4SLinus Torvalds { 15791da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 15801da177e4SLinus Torvalds .name = "Audigy Analog/Digital Output Jack", 15811da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 15821da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 15831da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 15841da177e4SLinus Torvalds }; 15851da177e4SLinus Torvalds 158616950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */ 158716950e09STakashi Iwai 158816950e09STakashi Iwai #define snd_audigy_capture_boost_info snd_ctl_boolean_mono_info 158916950e09STakashi Iwai 159016950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol, 159116950e09STakashi Iwai struct snd_ctl_elem_value *ucontrol) 159216950e09STakashi Iwai { 159316950e09STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 159416950e09STakashi Iwai unsigned int val; 159516950e09STakashi Iwai 159616950e09STakashi Iwai /* FIXME: better to use a cached version */ 159716950e09STakashi Iwai val = snd_ac97_read(emu->ac97, AC97_REC_GAIN); 159816950e09STakashi Iwai ucontrol->value.integer.value[0] = !!val; 159916950e09STakashi Iwai return 0; 160016950e09STakashi Iwai } 160116950e09STakashi Iwai 160216950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, 160316950e09STakashi Iwai struct snd_ctl_elem_value *ucontrol) 160416950e09STakashi Iwai { 160516950e09STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 160616950e09STakashi Iwai unsigned int val; 160716950e09STakashi Iwai 160816950e09STakashi Iwai if (ucontrol->value.integer.value[0]) 160916950e09STakashi Iwai val = 0x0f0f; 161016950e09STakashi Iwai else 161116950e09STakashi Iwai val = 0; 161216950e09STakashi Iwai return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); 161316950e09STakashi Iwai } 161416950e09STakashi Iwai 1615f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost = 161616950e09STakashi Iwai { 161716950e09STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 16182a52feb1SMaciej S. Szmigiero .name = "Mic Extra Boost", 161916950e09STakashi Iwai .info = snd_audigy_capture_boost_info, 162016950e09STakashi Iwai .get = snd_audigy_capture_boost_get, 162116950e09STakashi Iwai .put = snd_audigy_capture_boost_put 162216950e09STakashi Iwai }; 162316950e09STakashi Iwai 162416950e09STakashi Iwai 16251da177e4SLinus Torvalds /* 16261da177e4SLinus Torvalds */ 1627eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) 16281da177e4SLinus Torvalds { 1629eb4698f3STakashi Iwai struct snd_emu10k1 *emu = ac97->private_data; 16301da177e4SLinus Torvalds emu->ac97 = NULL; 16311da177e4SLinus Torvalds } 16321da177e4SLinus Torvalds 16331da177e4SLinus Torvalds /* 16341da177e4SLinus Torvalds */ 1635eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name) 16361da177e4SLinus Torvalds { 1637eb4698f3STakashi Iwai struct snd_ctl_elem_id id; 16381da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 16391da177e4SLinus Torvalds strcpy(id.name, name); 16401da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 16411da177e4SLinus Torvalds return snd_ctl_remove_id(card, &id); 16421da177e4SLinus Torvalds } 16431da177e4SLinus Torvalds 1644eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) 16451da177e4SLinus Torvalds { 1646eb4698f3STakashi Iwai struct snd_ctl_elem_id sid; 16471da177e4SLinus Torvalds memset(&sid, 0, sizeof(sid)); 16481da177e4SLinus Torvalds strcpy(sid.name, name); 16491da177e4SLinus Torvalds sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 16501da177e4SLinus Torvalds return snd_ctl_find_id(card, &sid); 16511da177e4SLinus Torvalds } 16521da177e4SLinus Torvalds 1653eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst) 16541da177e4SLinus Torvalds { 1655eb4698f3STakashi Iwai struct snd_kcontrol *kctl = ctl_find(card, src); 16561da177e4SLinus Torvalds if (kctl) { 165736476b81SMaciej S. Szmigiero snd_ctl_rename(card, kctl, dst); 16581da177e4SLinus Torvalds return 0; 16591da177e4SLinus Torvalds } 16601da177e4SLinus Torvalds return -ENOENT; 16611da177e4SLinus Torvalds } 16621da177e4SLinus Torvalds 1663e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu, 166467ed4161SClemens Ladisch int pcm_device, int multi_device) 16651da177e4SLinus Torvalds { 1666155e3d3bSOswald Buddenhagen int err; 1667eb4698f3STakashi Iwai struct snd_kcontrol *kctl; 1668eb4698f3STakashi Iwai struct snd_card *card = emu->card; 16696fddce26STakashi Iwai const char * const *c; 16706fddce26STakashi Iwai static const char * const emu10k1_remove_ctls[] = { 16711da177e4SLinus Torvalds /* no AC97 mono, surround, center/lfe */ 16721da177e4SLinus Torvalds "Master Mono Playback Switch", 16731da177e4SLinus Torvalds "Master Mono Playback Volume", 16741da177e4SLinus Torvalds "PCM Out Path & Mute", 16751da177e4SLinus Torvalds "Mono Output Select", 16761da177e4SLinus Torvalds "Surround Playback Switch", 16771da177e4SLinus Torvalds "Surround Playback Volume", 16781da177e4SLinus Torvalds "Center Playback Switch", 16791da177e4SLinus Torvalds "Center Playback Volume", 16801da177e4SLinus Torvalds "LFE Playback Switch", 16811da177e4SLinus Torvalds "LFE Playback Volume", 16821da177e4SLinus Torvalds NULL 16831da177e4SLinus Torvalds }; 16846fddce26STakashi Iwai static const char * const emu10k1_rename_ctls[] = { 16851da177e4SLinus Torvalds "Surround Digital Playback Volume", "Surround Playback Volume", 16861da177e4SLinus Torvalds "Center Digital Playback Volume", "Center Playback Volume", 16871da177e4SLinus Torvalds "LFE Digital Playback Volume", "LFE Playback Volume", 16881da177e4SLinus Torvalds NULL 16891da177e4SLinus Torvalds }; 16906fddce26STakashi Iwai static const char * const audigy_remove_ctls[] = { 16911da177e4SLinus Torvalds /* Master/PCM controls on ac97 of Audigy has no effect */ 169221fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 169321fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 16941da177e4SLinus Torvalds "PCM Playback Switch", 16951da177e4SLinus Torvalds "PCM Playback Volume", 16961da177e4SLinus Torvalds "Master Playback Switch", 16971da177e4SLinus Torvalds "Master Playback Volume", 16981da177e4SLinus Torvalds "PCM Out Path & Mute", 16991da177e4SLinus Torvalds "Mono Output Select", 17001da177e4SLinus Torvalds /* remove unused AC97 capture controls */ 17011da177e4SLinus Torvalds "Capture Source", 17021da177e4SLinus Torvalds "Capture Switch", 17031da177e4SLinus Torvalds "Capture Volume", 17041da177e4SLinus Torvalds "Mic Select", 1705274b2000SMaciej S. Szmigiero "Headphone Playback Switch", 1706274b2000SMaciej S. Szmigiero "Headphone Playback Volume", 1707274b2000SMaciej S. Szmigiero "3D Control - Center", 1708274b2000SMaciej S. Szmigiero "3D Control - Depth", 1709274b2000SMaciej S. Szmigiero "3D Control - Switch", 17101da177e4SLinus Torvalds "Video Playback Switch", 17111da177e4SLinus Torvalds "Video Playback Volume", 17121da177e4SLinus Torvalds "Mic Playback Switch", 17131da177e4SLinus Torvalds "Mic Playback Volume", 1714274b2000SMaciej S. Szmigiero "External Amplifier", 17151da177e4SLinus Torvalds NULL 17161da177e4SLinus Torvalds }; 17176fddce26STakashi Iwai static const char * const audigy_rename_ctls[] = { 17181da177e4SLinus Torvalds /* use conventional names */ 17191da177e4SLinus Torvalds "Wave Playback Volume", "PCM Playback Volume", 17201da177e4SLinus Torvalds /* "Wave Capture Volume", "PCM Capture Volume", */ 17211da177e4SLinus Torvalds "Wave Master Playback Volume", "Master Playback Volume", 17221da177e4SLinus Torvalds "AMic Playback Volume", "Mic Playback Volume", 172352051942SMaciej S. Szmigiero "Master Mono Playback Switch", "Phone Output Playback Switch", 172452051942SMaciej S. Szmigiero "Master Mono Playback Volume", "Phone Output Playback Volume", 17251da177e4SLinus Torvalds NULL 17261da177e4SLinus Torvalds }; 17276fddce26STakashi Iwai static const char * const audigy_rename_ctls_i2c_adc[] = { 1728184c1e2cSJames Courtier-Dutton //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", 1729184c1e2cSJames Courtier-Dutton "Line Capture Volume", "Analog Mix Capture Volume", 1730184c1e2cSJames Courtier-Dutton "Wave Playback Volume", "OLD PCM Playback Volume", 1731184c1e2cSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 1732184c1e2cSJames Courtier-Dutton "AMic Playback Volume", "Old Mic Playback Volume", 1733eb41dab6SJames Courtier-Dutton "CD Capture Volume", "IEC958 Optical Capture Volume", 1734184c1e2cSJames Courtier-Dutton NULL 1735184c1e2cSJames Courtier-Dutton }; 17366fddce26STakashi Iwai static const char * const audigy_remove_ctls_i2c_adc[] = { 1737184c1e2cSJames Courtier-Dutton /* On the Audigy2 ZS Notebook 1738184c1e2cSJames Courtier-Dutton * Capture via WM8775 */ 1739184c1e2cSJames Courtier-Dutton "Mic Capture Volume", 1740184c1e2cSJames Courtier-Dutton "Analog Mix Capture Volume", 1741184c1e2cSJames Courtier-Dutton "Aux Capture Volume", 1742eb41dab6SJames Courtier-Dutton "IEC958 Optical Capture Volume", 1743184c1e2cSJames Courtier-Dutton NULL 1744184c1e2cSJames Courtier-Dutton }; 17456fddce26STakashi Iwai static const char * const audigy_remove_ctls_1361t_adc[] = { 174621fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 174721fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 174821fdddeaSJames Courtier-Dutton "PCM Playback Switch", 174921fdddeaSJames Courtier-Dutton "PCM Playback Volume", 175021fdddeaSJames Courtier-Dutton "Capture Source", 175121fdddeaSJames Courtier-Dutton "Capture Switch", 175221fdddeaSJames Courtier-Dutton "Capture Volume", 175321fdddeaSJames Courtier-Dutton "Mic Capture Volume", 175421fdddeaSJames Courtier-Dutton "Headphone Playback Switch", 175521fdddeaSJames Courtier-Dutton "Headphone Playback Volume", 175621fdddeaSJames Courtier-Dutton "3D Control - Center", 175721fdddeaSJames Courtier-Dutton "3D Control - Depth", 175821fdddeaSJames Courtier-Dutton "3D Control - Switch", 175921fdddeaSJames Courtier-Dutton "Line2 Playback Volume", 176021fdddeaSJames Courtier-Dutton "Line2 Capture Volume", 176121fdddeaSJames Courtier-Dutton NULL 176221fdddeaSJames Courtier-Dutton }; 17636fddce26STakashi Iwai static const char * const audigy_rename_ctls_1361t_adc[] = { 176421fdddeaSJames Courtier-Dutton "Master Playback Switch", "Master Capture Switch", 176521fdddeaSJames Courtier-Dutton "Master Playback Volume", "Master Capture Volume", 176621fdddeaSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 1767d355c82aSJaroslav Kysela "Beep Playback Switch", "Beep Capture Switch", 1768d355c82aSJaroslav Kysela "Beep Playback Volume", "Beep Capture Volume", 176921fdddeaSJames Courtier-Dutton "Phone Playback Switch", "Phone Capture Switch", 177021fdddeaSJames Courtier-Dutton "Phone Playback Volume", "Phone Capture Volume", 177121fdddeaSJames Courtier-Dutton "Mic Playback Switch", "Mic Capture Switch", 177221fdddeaSJames Courtier-Dutton "Mic Playback Volume", "Mic Capture Volume", 177321fdddeaSJames Courtier-Dutton "Line Playback Switch", "Line Capture Switch", 177421fdddeaSJames Courtier-Dutton "Line Playback Volume", "Line Capture Volume", 177521fdddeaSJames Courtier-Dutton "CD Playback Switch", "CD Capture Switch", 177621fdddeaSJames Courtier-Dutton "CD Playback Volume", "CD Capture Volume", 177721fdddeaSJames Courtier-Dutton "Aux Playback Switch", "Aux Capture Switch", 177821fdddeaSJames Courtier-Dutton "Aux Playback Volume", "Aux Capture Volume", 177921fdddeaSJames Courtier-Dutton "Video Playback Switch", "Video Capture Switch", 178021fdddeaSJames Courtier-Dutton "Video Playback Volume", "Video Capture Volume", 178152051942SMaciej S. Szmigiero "Master Mono Playback Switch", "Phone Output Playback Switch", 178252051942SMaciej S. Szmigiero "Master Mono Playback Volume", "Phone Output Playback Volume", 178321fdddeaSJames Courtier-Dutton NULL 178421fdddeaSJames Courtier-Dutton }; 17851da177e4SLinus Torvalds 17862b637da5SLee Revell if (emu->card_capabilities->ac97_chip) { 1787eb4698f3STakashi Iwai struct snd_ac97_bus *pbus; 1788eb4698f3STakashi Iwai struct snd_ac97_template ac97; 178951055da5STakashi Iwai static const struct snd_ac97_bus_ops ops = { 17901da177e4SLinus Torvalds .write = snd_emu10k1_ac97_write, 17911da177e4SLinus Torvalds .read = snd_emu10k1_ac97_read, 17921da177e4SLinus Torvalds }; 17931da177e4SLinus Torvalds 179412bda107STakashi Iwai err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus); 179512bda107STakashi Iwai if (err < 0) 17961da177e4SLinus Torvalds return err; 17971da177e4SLinus Torvalds pbus->no_vra = 1; /* we don't need VRA */ 17981da177e4SLinus Torvalds 17991da177e4SLinus Torvalds memset(&ac97, 0, sizeof(ac97)); 18001da177e4SLinus Torvalds ac97.private_data = emu; 18011da177e4SLinus Torvalds ac97.private_free = snd_emu10k1_mixer_free_ac97; 18021da177e4SLinus Torvalds ac97.scaps = AC97_SCAP_NO_SPDIF; 180312bda107STakashi Iwai err = snd_ac97_mixer(pbus, &ac97, &emu->ac97); 180412bda107STakashi Iwai if (err < 0) { 1805b1508693STakashi Iwai if (emu->card_capabilities->ac97_chip == 1) 18061da177e4SLinus Torvalds return err; 18076f002b02STakashi Iwai dev_info(emu->card->dev, 18086f002b02STakashi Iwai "AC97 is optional on this board\n"); 18096f002b02STakashi Iwai dev_info(emu->card->dev, 18106f002b02STakashi Iwai "Proceeding without ac97 mixers...\n"); 1811b1508693STakashi Iwai snd_device_free(emu->card, pbus); 1812b1508693STakashi Iwai goto no_ac97; /* FIXME: get rid of ugly gotos.. */ 1813b1508693STakashi Iwai } 18141da177e4SLinus Torvalds if (emu->audigy) { 18151da177e4SLinus Torvalds /* set master volume to 0 dB */ 18164d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); 18171da177e4SLinus Torvalds /* set capture source to mic */ 18184d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); 181952051942SMaciej S. Szmigiero /* set mono output (TAD) to mic */ 182052051942SMaciej S. Szmigiero snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE, 182152051942SMaciej S. Szmigiero 0x0200, 0x0200); 182221fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 182321fdddeaSJames Courtier-Dutton c = audigy_remove_ctls_1361t_adc; 182421fdddeaSJames Courtier-Dutton else 18251da177e4SLinus Torvalds c = audigy_remove_ctls; 18261da177e4SLinus Torvalds } else { 18271da177e4SLinus Torvalds /* 18281da177e4SLinus Torvalds * Credits for cards based on STAC9758: 18291da177e4SLinus Torvalds * James Courtier-Dutton <James@superbug.demon.co.uk> 18301da177e4SLinus Torvalds * Voluspa <voluspa@comhem.se> 18311da177e4SLinus Torvalds */ 18321da177e4SLinus Torvalds if (emu->ac97->id == AC97_ID_STAC9758) { 18331da177e4SLinus Torvalds emu->rear_ac97 = 1; 18341da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); 18352594d960SRolf Stefan Wilke snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); 1836b6a48404SRaymond Yau remove_ctl(card,"Front Playback Volume"); 1837b6a48404SRaymond Yau remove_ctl(card,"Front Playback Switch"); 18381da177e4SLinus Torvalds } 18391da177e4SLinus Torvalds /* remove unused AC97 controls */ 18404d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); 18414d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); 18421da177e4SLinus Torvalds c = emu10k1_remove_ctls; 18431da177e4SLinus Torvalds } 18441da177e4SLinus Torvalds for (; *c; c++) 18451da177e4SLinus Torvalds remove_ctl(card, *c); 1846184c1e2cSJames Courtier-Dutton } else if (emu->card_capabilities->i2c_adc) { 1847184c1e2cSJames Courtier-Dutton c = audigy_remove_ctls_i2c_adc; 1848184c1e2cSJames Courtier-Dutton for (; *c; c++) 1849184c1e2cSJames Courtier-Dutton remove_ctl(card, *c); 18501da177e4SLinus Torvalds } else { 1851f12aa40cSTakashi Iwai no_ac97: 18522b637da5SLee Revell if (emu->card_capabilities->ecard) 18531da177e4SLinus Torvalds strcpy(emu->card->mixername, "EMU APS"); 18541da177e4SLinus Torvalds else if (emu->audigy) 18551da177e4SLinus Torvalds strcpy(emu->card->mixername, "SB Audigy"); 18561da177e4SLinus Torvalds else 18571da177e4SLinus Torvalds strcpy(emu->card->mixername, "Emu10k1"); 18581da177e4SLinus Torvalds } 18591da177e4SLinus Torvalds 18601da177e4SLinus Torvalds if (emu->audigy) 186121fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 186221fdddeaSJames Courtier-Dutton c = audigy_rename_ctls_1361t_adc; 1863184c1e2cSJames Courtier-Dutton else if (emu->card_capabilities->i2c_adc) 1864184c1e2cSJames Courtier-Dutton c = audigy_rename_ctls_i2c_adc; 186521fdddeaSJames Courtier-Dutton else 18661da177e4SLinus Torvalds c = audigy_rename_ctls; 18671da177e4SLinus Torvalds else 18681da177e4SLinus Torvalds c = emu10k1_rename_ctls; 18691da177e4SLinus Torvalds for (; *c; c += 2) 18701da177e4SLinus Torvalds rename_ctl(card, c[0], c[1]); 187121fdddeaSJames Courtier-Dutton 1872e217b960SRaymond Yau if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */ 1873e217b960SRaymond Yau remove_ctl(card, "Center Playback Volume"); 1874e217b960SRaymond Yau remove_ctl(card, "LFE Playback Volume"); 1875e217b960SRaymond Yau remove_ctl(card, "Wave Center Playback Volume"); 1876e217b960SRaymond Yau remove_ctl(card, "Wave LFE Playback Volume"); 1877e217b960SRaymond Yau } 1878e3b9bc0eSJames Courtier-Dutton if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ 1879e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); 1880e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); 1881e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); 1882e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); 1883e3b9bc0eSJames Courtier-Dutton } 188412bda107STakashi Iwai kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu); 188512bda107STakashi Iwai if (!kctl) 18861da177e4SLinus Torvalds return -ENOMEM; 188767ed4161SClemens Ladisch kctl->id.device = pcm_device; 188812bda107STakashi Iwai err = snd_ctl_add(card, kctl); 188912bda107STakashi Iwai if (err) 18901da177e4SLinus Torvalds return err; 189112bda107STakashi Iwai kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu); 189212bda107STakashi Iwai if (!kctl) 18931da177e4SLinus Torvalds return -ENOMEM; 189467ed4161SClemens Ladisch kctl->id.device = pcm_device; 189512bda107STakashi Iwai err = snd_ctl_add(card, kctl); 189612bda107STakashi Iwai if (err) 18971da177e4SLinus Torvalds return err; 189812bda107STakashi Iwai kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu); 189912bda107STakashi Iwai if (!kctl) 19001da177e4SLinus Torvalds return -ENOMEM; 190167ed4161SClemens Ladisch kctl->id.device = pcm_device; 190212bda107STakashi Iwai err = snd_ctl_add(card, kctl); 190312bda107STakashi Iwai if (err) 19041da177e4SLinus Torvalds return err; 19051da177e4SLinus Torvalds 190612bda107STakashi Iwai kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu); 190712bda107STakashi Iwai if (!kctl) 19081da177e4SLinus Torvalds return -ENOMEM; 190967ed4161SClemens Ladisch kctl->id.device = multi_device; 191012bda107STakashi Iwai err = snd_ctl_add(card, kctl); 191112bda107STakashi Iwai if (err) 19121da177e4SLinus Torvalds return err; 19131da177e4SLinus Torvalds 191412bda107STakashi Iwai kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu); 191512bda107STakashi Iwai if (!kctl) 19161da177e4SLinus Torvalds return -ENOMEM; 191767ed4161SClemens Ladisch kctl->id.device = multi_device; 191812bda107STakashi Iwai err = snd_ctl_add(card, kctl); 191912bda107STakashi Iwai if (err) 19201da177e4SLinus Torvalds return err; 19211da177e4SLinus Torvalds 192212bda107STakashi Iwai kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu); 192312bda107STakashi Iwai if (!kctl) 19241da177e4SLinus Torvalds return -ENOMEM; 192567ed4161SClemens Ladisch kctl->id.device = multi_device; 192612bda107STakashi Iwai err = snd_ctl_add(card, kctl); 192712bda107STakashi Iwai if (err) 19281da177e4SLinus Torvalds return err; 19291da177e4SLinus Torvalds 1930a8661af5SOswald Buddenhagen if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) { 19311da177e4SLinus Torvalds /* sb live! and audigy */ 193212bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu); 193312bda107STakashi Iwai if (!kctl) 19341da177e4SLinus Torvalds return -ENOMEM; 19355549d549SClemens Ladisch if (!emu->audigy) 19365549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 193712bda107STakashi Iwai err = snd_ctl_add(card, kctl); 193812bda107STakashi Iwai if (err) 19391da177e4SLinus Torvalds return err; 194012bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu); 194112bda107STakashi Iwai if (!kctl) 19421da177e4SLinus Torvalds return -ENOMEM; 19435549d549SClemens Ladisch if (!emu->audigy) 19445549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 194512bda107STakashi Iwai err = snd_ctl_add(card, kctl); 194612bda107STakashi Iwai if (err) 19471da177e4SLinus Torvalds return err; 19481da177e4SLinus Torvalds } 19491da177e4SLinus Torvalds 1950190d2c46SJames Courtier-Dutton if (emu->card_capabilities->emu_model) { 195119b99fbaSJames Courtier-Dutton ; /* Disable the snd_audigy_spdif_shared_spdif */ 195219b99fbaSJames Courtier-Dutton } else if (emu->audigy) { 195312bda107STakashi Iwai kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu); 195412bda107STakashi Iwai if (!kctl) 19551da177e4SLinus Torvalds return -ENOMEM; 195612bda107STakashi Iwai err = snd_ctl_add(card, kctl); 195712bda107STakashi Iwai if (err) 19581da177e4SLinus Torvalds return err; 1959001f7589SJames Courtier-Dutton #if 0 196012bda107STakashi Iwai kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu); 196112bda107STakashi Iwai if (!kctl) 19621da177e4SLinus Torvalds return -ENOMEM; 196312bda107STakashi Iwai err = snd_ctl_add(card, kctl); 196412bda107STakashi Iwai if (err) 19651da177e4SLinus Torvalds return err; 1966001f7589SJames Courtier-Dutton #endif 19672b637da5SLee Revell } else if (! emu->card_capabilities->ecard) { 19681da177e4SLinus Torvalds /* sb live! */ 196912bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu); 197012bda107STakashi Iwai if (!kctl) 19711da177e4SLinus Torvalds return -ENOMEM; 197212bda107STakashi Iwai err = snd_ctl_add(card, kctl); 197312bda107STakashi Iwai if (err) 19741da177e4SLinus Torvalds return err; 19751da177e4SLinus Torvalds } 19762b637da5SLee Revell if (emu->card_capabilities->ca0151_chip) { /* P16V */ 197712bda107STakashi Iwai err = snd_p16v_mixer(emu); 197812bda107STakashi Iwai if (err) 19791da177e4SLinus Torvalds return err; 19801da177e4SLinus Torvalds } 19811da177e4SLinus Torvalds 19823839e4f1STakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { 19831c02e366SCtirad Fertr /* 1616(m) cardbus */ 1984536438f1SOswald Buddenhagen err = add_ctls(emu, &emu1010_output_source_ctl, 1985536438f1SOswald Buddenhagen snd_emu1616_output_texts, 1986536438f1SOswald Buddenhagen ARRAY_SIZE(snd_emu1616_output_texts)); 19879f4bd5ddSJames Courtier-Dutton if (err < 0) 19889f4bd5ddSJames Courtier-Dutton return err; 1989536438f1SOswald Buddenhagen err = add_ctls(emu, &emu1010_input_source_ctl, 1990536438f1SOswald Buddenhagen emu1010_input_texts, 1991536438f1SOswald Buddenhagen ARRAY_SIZE(emu1010_input_texts)); 19921c02e366SCtirad Fertr if (err < 0) 19931c02e366SCtirad Fertr return err; 1994536438f1SOswald Buddenhagen err = add_ctls(emu, &emu1010_adc_pads_ctl, 1995536438f1SOswald Buddenhagen snd_emu1010_adc_pads, 1996536438f1SOswald Buddenhagen ARRAY_SIZE(snd_emu1010_adc_pads) - 2); 19971c02e366SCtirad Fertr if (err < 0) 19981c02e366SCtirad Fertr return err; 1999536438f1SOswald Buddenhagen err = add_ctls(emu, &emu1010_dac_pads_ctl, 2000536438f1SOswald Buddenhagen snd_emu1010_dac_pads, 2001536438f1SOswald Buddenhagen ARRAY_SIZE(snd_emu1010_dac_pads) - 2); 20021c02e366SCtirad Fertr if (err < 0) 20031c02e366SCtirad Fertr return err; 20041c02e366SCtirad Fertr err = snd_ctl_add(card, 20051c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 20061c02e366SCtirad Fertr if (err < 0) 20071c02e366SCtirad Fertr return err; 200899dcab46SMichael Gernoth err = snd_ctl_add(card, 200999dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_out, emu)); 201099dcab46SMichael Gernoth if (err < 0) 201199dcab46SMichael Gernoth return err; 201299dcab46SMichael Gernoth err = snd_ctl_add(card, 201399dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_in, emu)); 201499dcab46SMichael Gernoth if (err < 0) 201599dcab46SMichael Gernoth return err; 20161c02e366SCtirad Fertr 201788aa1390STakashi Iwai } else if (emu->card_capabilities->emu_model) { 20181c02e366SCtirad Fertr /* all other e-mu cards for now */ 2019536438f1SOswald Buddenhagen err = add_ctls(emu, &emu1010_output_source_ctl, 2020536438f1SOswald Buddenhagen emu1010_output_texts, 2021536438f1SOswald Buddenhagen ARRAY_SIZE(emu1010_output_texts)); 20221c02e366SCtirad Fertr if (err < 0) 20231c02e366SCtirad Fertr return err; 2024536438f1SOswald Buddenhagen err = add_ctls(emu, &emu1010_input_source_ctl, 2025536438f1SOswald Buddenhagen emu1010_input_texts, 2026536438f1SOswald Buddenhagen ARRAY_SIZE(emu1010_input_texts)); 20279f4bd5ddSJames Courtier-Dutton if (err < 0) 20289f4bd5ddSJames Courtier-Dutton return err; 2029536438f1SOswald Buddenhagen err = add_ctls(emu, &emu1010_adc_pads_ctl, 2030536438f1SOswald Buddenhagen snd_emu1010_adc_pads, 2031536438f1SOswald Buddenhagen ARRAY_SIZE(snd_emu1010_adc_pads)); 20329148cc50SJames Courtier-Dutton if (err < 0) 20339148cc50SJames Courtier-Dutton return err; 2034536438f1SOswald Buddenhagen err = add_ctls(emu, &emu1010_dac_pads_ctl, 2035536438f1SOswald Buddenhagen snd_emu1010_dac_pads, 2036536438f1SOswald Buddenhagen ARRAY_SIZE(snd_emu1010_dac_pads)); 20379148cc50SJames Courtier-Dutton if (err < 0) 20389148cc50SJames Courtier-Dutton return err; 20391c02e366SCtirad Fertr err = snd_ctl_add(card, 20401c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 2041b0dbdaeaSJames Courtier-Dutton if (err < 0) 2042b0dbdaeaSJames Courtier-Dutton return err; 204399dcab46SMichael Gernoth err = snd_ctl_add(card, 204499dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_out, emu)); 204599dcab46SMichael Gernoth if (err < 0) 204699dcab46SMichael Gernoth return err; 204799dcab46SMichael Gernoth err = snd_ctl_add(card, 204899dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_in, emu)); 204999dcab46SMichael Gernoth if (err < 0) 205099dcab46SMichael Gernoth return err; 20519f4bd5ddSJames Courtier-Dutton } 20529f4bd5ddSJames Courtier-Dutton 2053184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 2054184c1e2cSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); 2055184c1e2cSJames Courtier-Dutton if (err < 0) 2056184c1e2cSJames Courtier-Dutton return err; 2057184c1e2cSJames Courtier-Dutton 2058536438f1SOswald Buddenhagen err = add_ctls(emu, &i2c_volume_ctl, 2059536438f1SOswald Buddenhagen snd_audigy_i2c_volume_ctls, 2060536438f1SOswald Buddenhagen ARRAY_SIZE(snd_audigy_i2c_volume_ctls)); 2061184c1e2cSJames Courtier-Dutton if (err < 0) 2062184c1e2cSJames Courtier-Dutton return err; 2063184c1e2cSJames Courtier-Dutton } 2064184c1e2cSJames Courtier-Dutton 206516950e09STakashi Iwai if (emu->card_capabilities->ac97_chip && emu->audigy) { 206616950e09STakashi Iwai err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost, 206716950e09STakashi Iwai emu)); 206816950e09STakashi Iwai if (err < 0) 206916950e09STakashi Iwai return err; 207016950e09STakashi Iwai } 207116950e09STakashi Iwai 20721da177e4SLinus Torvalds return 0; 20731da177e4SLinus Torvalds } 2074