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 32eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 331da177e4SLinus Torvalds { 341da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 351da177e4SLinus Torvalds uinfo->count = 1; 361da177e4SLinus Torvalds return 0; 371da177e4SLinus Torvalds } 381da177e4SLinus Torvalds 39eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol, 40eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 411da177e4SLinus Torvalds { 42eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 431da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 441da177e4SLinus Torvalds 4574415a36SJames Courtier-Dutton /* Limit: emu->spdif_bits */ 4674415a36SJames Courtier-Dutton if (idx >= 3) 4774415a36SJames Courtier-Dutton return -EINVAL; 481da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 491da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 501da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 511da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 521da177e4SLinus Torvalds return 0; 531da177e4SLinus Torvalds } 541da177e4SLinus Torvalds 55eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, 56eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 571da177e4SLinus Torvalds { 581da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = 0xff; 591da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = 0xff; 601da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = 0xff; 611da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = 0xff; 621da177e4SLinus Torvalds return 0; 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 65*dc39bb3eSOswald Buddenhagen #define PAIR_PS(base, one, two, sfx) base " " one sfx, base " " two sfx 66*dc39bb3eSOswald Buddenhagen #define LR_PS(base, sfx) PAIR_PS(base, "Left", "Right", sfx) 679f4bd5ddSJames Courtier-Dutton 68*dc39bb3eSOswald Buddenhagen #define ADAT_PS(pfx, sfx) \ 69*dc39bb3eSOswald Buddenhagen pfx "ADAT 0" sfx, pfx "ADAT 1" sfx, pfx "ADAT 2" sfx, pfx "ADAT 3" sfx, \ 70*dc39bb3eSOswald Buddenhagen pfx "ADAT 4" sfx, pfx "ADAT 5" sfx, pfx "ADAT 6" sfx, pfx "ADAT 7" sfx 711c02e366SCtirad Fertr 72*dc39bb3eSOswald Buddenhagen #define PAIR_REGS(base, one, two) \ 73*dc39bb3eSOswald Buddenhagen base ## one ## 1, \ 74*dc39bb3eSOswald Buddenhagen base ## two ## 1 751c02e366SCtirad Fertr 76*dc39bb3eSOswald Buddenhagen #define LR_REGS(base) PAIR_REGS(base, _LEFT, _RIGHT) 77*dc39bb3eSOswald Buddenhagen 78*dc39bb3eSOswald Buddenhagen #define ADAT_REGS(base) \ 79*dc39bb3eSOswald Buddenhagen base+0, base+1, base+2, base+3, base+4, base+5, base+6, base+7 801c02e366SCtirad Fertr 8113d45709SPavel Hofman /* 8213d45709SPavel Hofman * List of data sources available for each destination 8313d45709SPavel Hofman */ 84*dc39bb3eSOswald Buddenhagen 85*dc39bb3eSOswald Buddenhagen #define DSP_TEXTS \ 86*dc39bb3eSOswald Buddenhagen "DSP 0", "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", \ 87*dc39bb3eSOswald Buddenhagen "DSP 8", "DSP 9", "DSP 10", "DSP 11", "DSP 12", "DSP 13", "DSP 14", "DSP 15", \ 88*dc39bb3eSOswald Buddenhagen "DSP 16", "DSP 17", "DSP 18", "DSP 19", "DSP 20", "DSP 21", "DSP 22", "DSP 23", \ 89*dc39bb3eSOswald Buddenhagen "DSP 24", "DSP 25", "DSP 26", "DSP 27", "DSP 28", "DSP 29", "DSP 30", "DSP 31" 90*dc39bb3eSOswald Buddenhagen 91*dc39bb3eSOswald Buddenhagen #define PAIR_TEXTS(base, one, two) PAIR_PS(base, one, two, "") 92*dc39bb3eSOswald Buddenhagen #define LR_TEXTS(base) LR_PS(base, "") 93*dc39bb3eSOswald Buddenhagen #define ADAT_TEXTS(pfx) ADAT_PS(pfx, "") 94*dc39bb3eSOswald Buddenhagen 95*dc39bb3eSOswald Buddenhagen #define EMU32_SRC_REGS \ 96*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A, \ 97*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+1, \ 98*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+2, \ 99*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+3, \ 100*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+4, \ 101*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+5, \ 102*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+6, \ 103*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+7, \ 104*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+8, \ 105*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+9, \ 106*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0xa, \ 107*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0xb, \ 108*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0xc, \ 109*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0xd, \ 110*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0xe, \ 111*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32A+0xf, \ 112*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B, \ 113*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+1, \ 114*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+2, \ 115*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+3, \ 116*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+4, \ 117*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+5, \ 118*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+6, \ 119*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+7, \ 120*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+8, \ 121*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+9, \ 122*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+0xa, \ 123*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+0xb, \ 124*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+0xc, \ 125*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+0xd, \ 126*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+0xe, \ 127*dc39bb3eSOswald Buddenhagen EMU_SRC_ALICE_EMU32B+0xf 128*dc39bb3eSOswald Buddenhagen 129*dc39bb3eSOswald Buddenhagen #define EMU1010_COMMON_TEXTS \ 130*dc39bb3eSOswald Buddenhagen "Silence", \ 131*dc39bb3eSOswald Buddenhagen PAIR_TEXTS("Dock Mic", "A", "B"), \ 132*dc39bb3eSOswald Buddenhagen LR_TEXTS("Dock ADC1"), \ 133*dc39bb3eSOswald Buddenhagen LR_TEXTS("Dock ADC2"), \ 134*dc39bb3eSOswald Buddenhagen LR_TEXTS("Dock ADC3"), \ 135*dc39bb3eSOswald Buddenhagen LR_TEXTS("0202 ADC"), \ 136*dc39bb3eSOswald Buddenhagen LR_TEXTS("1010 SPDIF"), \ 137*dc39bb3eSOswald Buddenhagen ADAT_TEXTS("1010 ") 138*dc39bb3eSOswald Buddenhagen 139*dc39bb3eSOswald Buddenhagen static const char * const emu1010_src_texts[] = { 140*dc39bb3eSOswald Buddenhagen EMU1010_COMMON_TEXTS, 141*dc39bb3eSOswald Buddenhagen DSP_TEXTS, 1429f4bd5ddSJames Courtier-Dutton }; 1439f4bd5ddSJames Courtier-Dutton 144*dc39bb3eSOswald Buddenhagen static const unsigned short emu1010_src_regs[] = { 145*dc39bb3eSOswald Buddenhagen EMU_SRC_SILENCE, 146*dc39bb3eSOswald Buddenhagen PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B), 147*dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC1), 148*dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC2), 149*dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC3), 150*dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_HAMOA_ADC), 151*dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_HANA_SPDIF), 152*dc39bb3eSOswald Buddenhagen ADAT_REGS(EMU_SRC_HANA_ADAT), 153*dc39bb3eSOswald Buddenhagen EMU32_SRC_REGS, 154*dc39bb3eSOswald Buddenhagen }; 155*dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_src_regs) == ARRAY_SIZE(emu1010_src_texts)); 156*dc39bb3eSOswald Buddenhagen 1571c02e366SCtirad Fertr /* 1616(m) cardbus */ 158*dc39bb3eSOswald Buddenhagen 159*dc39bb3eSOswald Buddenhagen #define EMU1616_COMMON_TEXTS \ 160*dc39bb3eSOswald Buddenhagen "Silence", \ 161*dc39bb3eSOswald Buddenhagen PAIR_TEXTS("Mic", "A", "B"), \ 162*dc39bb3eSOswald Buddenhagen LR_TEXTS("ADC1"), \ 163*dc39bb3eSOswald Buddenhagen LR_TEXTS("ADC2"), \ 164*dc39bb3eSOswald Buddenhagen LR_TEXTS("SPDIF"), \ 165*dc39bb3eSOswald Buddenhagen ADAT_TEXTS("") 166*dc39bb3eSOswald Buddenhagen 167*dc39bb3eSOswald Buddenhagen static const char * const emu1616_src_texts[] = { 168*dc39bb3eSOswald Buddenhagen EMU1616_COMMON_TEXTS, 169*dc39bb3eSOswald Buddenhagen DSP_TEXTS, 170*dc39bb3eSOswald Buddenhagen }; 171*dc39bb3eSOswald Buddenhagen 1729b00a1e9SOswald Buddenhagen static const unsigned short emu1616_src_regs[] = { 1731c02e366SCtirad Fertr EMU_SRC_SILENCE, 174*dc39bb3eSOswald Buddenhagen PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B), 175*dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC1), 176*dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_DOCK_ADC2), 177*dc39bb3eSOswald Buddenhagen LR_REGS(EMU_SRC_MDOCK_SPDIF), 178*dc39bb3eSOswald Buddenhagen ADAT_REGS(EMU_SRC_MDOCK_ADAT), 179*dc39bb3eSOswald Buddenhagen EMU32_SRC_REGS, 1801c02e366SCtirad Fertr }; 181*dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_src_regs) == ARRAY_SIZE(emu1616_src_texts)); 1821c02e366SCtirad Fertr 18313d45709SPavel Hofman /* 18413d45709SPavel Hofman * Data destinations - physical EMU outputs. 18513d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 18613d45709SPavel Hofman */ 1879b00a1e9SOswald Buddenhagen static const unsigned short emu1010_output_dst[] = { 1889f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC1_LEFT1, /* 0 */ 1899f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */ 1909f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC2_LEFT1, /* 2 */ 1919f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */ 1929f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC3_LEFT1, /* 4 */ 1939f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */ 1949f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC4_LEFT1, /* 6 */ 1959f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */ 1969f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_PHONES_LEFT1, /* 8 */ 1979f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */ 1989f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */ 1999f4bd5ddSJames Courtier-Dutton EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */ 2009f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_SPDIF_LEFT1, /* 12 */ 2019f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */ 2029f4bd5ddSJames Courtier-Dutton EMU_DST_HAMOA_DAC_LEFT1, /* 14 */ 2039f4bd5ddSJames Courtier-Dutton EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */ 2049f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT, /* 16 */ 2059f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+1, /* 17 */ 2069f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+2, /* 18 */ 2079f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+3, /* 19 */ 2089f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+4, /* 20 */ 2099f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+5, /* 21 */ 2109f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+6, /* 22 */ 2119f4bd5ddSJames Courtier-Dutton EMU_DST_HANA_ADAT+7, /* 23 */ 2129f4bd5ddSJames Courtier-Dutton }; 2139f4bd5ddSJames Courtier-Dutton 2141c02e366SCtirad Fertr /* 1616(m) cardbus */ 2159b00a1e9SOswald Buddenhagen static const unsigned short emu1616_output_dst[] = { 2161c02e366SCtirad Fertr EMU_DST_DOCK_DAC1_LEFT1, 2171c02e366SCtirad Fertr EMU_DST_DOCK_DAC1_RIGHT1, 2181c02e366SCtirad Fertr EMU_DST_DOCK_DAC2_LEFT1, 2191c02e366SCtirad Fertr EMU_DST_DOCK_DAC2_RIGHT1, 2201c02e366SCtirad Fertr EMU_DST_DOCK_DAC3_LEFT1, 2211c02e366SCtirad Fertr EMU_DST_DOCK_DAC3_RIGHT1, 2221c02e366SCtirad Fertr EMU_DST_MDOCK_SPDIF_LEFT1, 2231c02e366SCtirad Fertr EMU_DST_MDOCK_SPDIF_RIGHT1, 2241c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT, 2251c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+1, 2261c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+2, 2271c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+3, 2281c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+4, 2291c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+5, 2301c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+6, 2311c02e366SCtirad Fertr EMU_DST_MDOCK_ADAT+7, 2321c02e366SCtirad Fertr EMU_DST_MANA_DAC_LEFT, 2331c02e366SCtirad Fertr EMU_DST_MANA_DAC_RIGHT, 2341c02e366SCtirad Fertr }; 2351c02e366SCtirad Fertr 23613d45709SPavel Hofman /* 237a869057cSOswald Buddenhagen * Data destinations - FPGA outputs going to Alice2 (Audigy) for 23813d45709SPavel Hofman * capture (EMU32 + I2S links) 23913d45709SPavel Hofman * Each destination has an enum mixer control to choose a data source 24013d45709SPavel Hofman */ 2419b00a1e9SOswald Buddenhagen static const unsigned short emu1010_input_dst[] = { 2429f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_0, 2439f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_1, 2449f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_2, 2459f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_3, 2469f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_4, 2479f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_5, 2489f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_6, 2499f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_7, 2509f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_8, 2519f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_9, 2529f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_A, 2539f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_B, 2549f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_C, 2559f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_D, 2569f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_E, 2579f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE2_EMU32_F, 258a869057cSOswald Buddenhagen /* These exist only on rev1 EMU1010 cards. */ 2599f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_LEFT, 2609f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S0_RIGHT, 2619f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_LEFT, 2629f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S1_RIGHT, 2639f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_LEFT, 2649f4bd5ddSJames Courtier-Dutton EMU_DST_ALICE_I2S2_RIGHT, 2659f4bd5ddSJames Courtier-Dutton }; 2669f4bd5ddSJames Courtier-Dutton 2671c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, 2681c02e366SCtirad Fertr struct snd_ctl_elem_info *uinfo) 2699f4bd5ddSJames Courtier-Dutton { 2701c02e366SCtirad Fertr struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 2711c02e366SCtirad Fertr 2721541c66dSTakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 2731541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts); 2741541c66dSTakashi Iwai else 2751541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts); 2769f4bd5ddSJames Courtier-Dutton } 2779f4bd5ddSJames Courtier-Dutton 2789f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, 2799f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 2809f4bd5ddSJames Courtier-Dutton { 2819f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 28274415a36SJames Courtier-Dutton unsigned int channel; 2839f4bd5ddSJames Courtier-Dutton 2849f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 28574415a36SJames Courtier-Dutton /* Limit: emu1010_output_dst, emu->emu1010.output_source */ 2861c02e366SCtirad Fertr if (channel >= 24 || 2873839e4f1STakashi Iwai (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 2883839e4f1STakashi Iwai channel >= 18)) 28974415a36SJames Courtier-Dutton return -EINVAL; 2909f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; 2919f4bd5ddSJames Courtier-Dutton return 0; 2929f4bd5ddSJames Courtier-Dutton } 2939f4bd5ddSJames Courtier-Dutton 2949f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, 2959f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 2969f4bd5ddSJames Courtier-Dutton { 2979f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 2989f4bd5ddSJames Courtier-Dutton unsigned int val; 29974415a36SJames Courtier-Dutton unsigned int channel; 3009f4bd5ddSJames Courtier-Dutton 301aa299d01STakashi Iwai val = ucontrol->value.enumerated.item[0]; 3021c02e366SCtirad Fertr if (val >= 53 || 3033839e4f1STakashi Iwai (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 3043839e4f1STakashi Iwai val >= 49)) 305aa299d01STakashi Iwai return -EINVAL; 3069f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 30774415a36SJames Courtier-Dutton /* Limit: emu1010_output_dst, emu->emu1010.output_source */ 3081c02e366SCtirad Fertr if (channel >= 24 || 3093839e4f1STakashi Iwai (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 3103839e4f1STakashi Iwai channel >= 18)) 31174415a36SJames Courtier-Dutton return -EINVAL; 3121c02e366SCtirad Fertr if (emu->emu1010.output_source[channel] == val) 3131c02e366SCtirad Fertr return 0; 314aa299d01STakashi Iwai emu->emu1010.output_source[channel] = val; 3153839e4f1STakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 3161c02e366SCtirad Fertr snd_emu1010_fpga_link_dst_src_write(emu, 3171c02e366SCtirad Fertr emu1616_output_dst[channel], emu1616_src_regs[val]); 3181c02e366SCtirad Fertr else 3199f4bd5ddSJames Courtier-Dutton snd_emu1010_fpga_link_dst_src_write(emu, 3209f4bd5ddSJames Courtier-Dutton emu1010_output_dst[channel], emu1010_src_regs[val]); 3211c02e366SCtirad Fertr return 1; 3229f4bd5ddSJames Courtier-Dutton } 3239f4bd5ddSJames Courtier-Dutton 3249f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, 3259f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 3269f4bd5ddSJames Courtier-Dutton { 3279f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 32874415a36SJames Courtier-Dutton unsigned int channel; 3299f4bd5ddSJames Courtier-Dutton 3309f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 33174415a36SJames Courtier-Dutton /* Limit: emu1010_input_dst, emu->emu1010.input_source */ 33274415a36SJames Courtier-Dutton if (channel >= 22) 33374415a36SJames Courtier-Dutton return -EINVAL; 3349f4bd5ddSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; 3359f4bd5ddSJames Courtier-Dutton return 0; 3369f4bd5ddSJames Courtier-Dutton } 3379f4bd5ddSJames Courtier-Dutton 3389f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, 3399f4bd5ddSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 3409f4bd5ddSJames Courtier-Dutton { 3419f4bd5ddSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 3429f4bd5ddSJames Courtier-Dutton unsigned int val; 34374415a36SJames Courtier-Dutton unsigned int channel; 3449f4bd5ddSJames Courtier-Dutton 345aa299d01STakashi Iwai val = ucontrol->value.enumerated.item[0]; 3461c02e366SCtirad Fertr if (val >= 53 || 3473839e4f1STakashi Iwai (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 3483839e4f1STakashi Iwai val >= 49)) 349aa299d01STakashi Iwai return -EINVAL; 3509f4bd5ddSJames Courtier-Dutton channel = (kcontrol->private_value) & 0xff; 35174415a36SJames Courtier-Dutton /* Limit: emu1010_input_dst, emu->emu1010.input_source */ 35274415a36SJames Courtier-Dutton if (channel >= 22) 35374415a36SJames Courtier-Dutton return -EINVAL; 3541c02e366SCtirad Fertr if (emu->emu1010.input_source[channel] == val) 3551c02e366SCtirad Fertr return 0; 356aa299d01STakashi Iwai emu->emu1010.input_source[channel] = val; 3573839e4f1STakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 3581c02e366SCtirad Fertr snd_emu1010_fpga_link_dst_src_write(emu, 3591c02e366SCtirad Fertr emu1010_input_dst[channel], emu1616_src_regs[val]); 3601c02e366SCtirad Fertr else 3619f4bd5ddSJames Courtier-Dutton snd_emu1010_fpga_link_dst_src_write(emu, 3629f4bd5ddSJames Courtier-Dutton emu1010_input_dst[channel], emu1010_src_regs[val]); 3631c02e366SCtirad Fertr return 1; 3649f4bd5ddSJames Courtier-Dutton } 3659f4bd5ddSJames Courtier-Dutton 3669f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \ 3679f4bd5ddSJames Courtier-Dutton { \ 3689f4bd5ddSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 3699f4bd5ddSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 3709f4bd5ddSJames Courtier-Dutton .info = snd_emu1010_input_output_source_info, \ 3719f4bd5ddSJames Courtier-Dutton .get = snd_emu1010_output_source_get, \ 3729f4bd5ddSJames Courtier-Dutton .put = snd_emu1010_output_source_put, \ 3739f4bd5ddSJames Courtier-Dutton .private_value = chid \ 3749f4bd5ddSJames Courtier-Dutton } 3759f4bd5ddSJames Courtier-Dutton 376b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = { 3774c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), 3784c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), 3794c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), 3804c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), 3814c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), 3824c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), 3834c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6), 3844c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7), 3854c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8), 3864c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9), 3874c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa), 3884c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb), 3894c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc), 3904c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd), 3914c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe), 3924c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf), 3934c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10), 3944c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11), 3954c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12), 3964c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13), 3974c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14), 3984c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15), 3994c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16), 4004c07c818SJames Courtier-Dutton EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), 4019f4bd5ddSJames Courtier-Dutton }; 4029f4bd5ddSJames Courtier-Dutton 4031c02e366SCtirad Fertr 4041c02e366SCtirad Fertr /* 1616(m) cardbus */ 405b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = { 4061c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), 4071c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), 4081c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), 4091c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), 4101c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), 4111c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), 4121c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6), 4131c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7), 4141c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8), 4151c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9), 4161c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa), 4171c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb), 4181c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc), 4191c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd), 4201c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe), 4211c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf), 4221c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10), 4231c02e366SCtirad Fertr EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11), 4241c02e366SCtirad Fertr }; 4251c02e366SCtirad Fertr 4261c02e366SCtirad Fertr 4279f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \ 4289f4bd5ddSJames Courtier-Dutton { \ 4299f4bd5ddSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 4309f4bd5ddSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 4319f4bd5ddSJames Courtier-Dutton .info = snd_emu1010_input_output_source_info, \ 4329f4bd5ddSJames Courtier-Dutton .get = snd_emu1010_input_source_get, \ 4339f4bd5ddSJames Courtier-Dutton .put = snd_emu1010_input_source_put, \ 4349f4bd5ddSJames Courtier-Dutton .private_value = chid \ 4359f4bd5ddSJames Courtier-Dutton } 4369f4bd5ddSJames Courtier-Dutton 437b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = { 4384c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0), 4394c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1), 4404c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2), 4414c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3), 4424c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4), 4434c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5), 4444c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6), 4454c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7), 4464c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8), 4474c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9), 4484c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa), 4494c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb), 4504c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc), 4514c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd), 4524c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe), 4534c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf), 4544c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10), 4554c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11), 4564c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12), 4574c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13), 4584c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14), 4594c07c818SJames Courtier-Dutton EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15), 4609148cc50SJames Courtier-Dutton }; 4619148cc50SJames Courtier-Dutton 4629148cc50SJames Courtier-Dutton 4639148cc50SJames Courtier-Dutton 464a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info snd_ctl_boolean_mono_info 4659148cc50SJames Courtier-Dutton 4669148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4679148cc50SJames Courtier-Dutton { 4689148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4699148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 4709148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; 4719148cc50SJames Courtier-Dutton return 0; 4729148cc50SJames Courtier-Dutton } 4739148cc50SJames Courtier-Dutton 4749148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4759148cc50SJames Courtier-Dutton { 4769148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4779148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 4789148cc50SJames Courtier-Dutton unsigned int val, cache; 4799148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 4809148cc50SJames Courtier-Dutton cache = emu->emu1010.adc_pads; 4819148cc50SJames Courtier-Dutton if (val == 1) 4829148cc50SJames Courtier-Dutton cache = cache | mask; 4839148cc50SJames Courtier-Dutton else 4849148cc50SJames Courtier-Dutton cache = cache & ~mask; 4859148cc50SJames Courtier-Dutton if (cache != emu->emu1010.adc_pads) { 4869148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); 4879148cc50SJames Courtier-Dutton emu->emu1010.adc_pads = cache; 4889148cc50SJames Courtier-Dutton } 4899148cc50SJames Courtier-Dutton 4909148cc50SJames Courtier-Dutton return 0; 4919148cc50SJames Courtier-Dutton } 4929148cc50SJames Courtier-Dutton 4939148cc50SJames Courtier-Dutton 4949148cc50SJames Courtier-Dutton 4959148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \ 4969148cc50SJames Courtier-Dutton { \ 4979148cc50SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 4989148cc50SJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 4999148cc50SJames Courtier-Dutton .info = snd_emu1010_adc_pads_info, \ 5009148cc50SJames Courtier-Dutton .get = snd_emu1010_adc_pads_get, \ 5019148cc50SJames Courtier-Dutton .put = snd_emu1010_adc_pads_put, \ 5029148cc50SJames Courtier-Dutton .private_value = chid \ 5039148cc50SJames Courtier-Dutton } 5049148cc50SJames Courtier-Dutton 505b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_adc_pads[] = { 5069148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), 5079148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), 5089148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), 5099148cc50SJames Courtier-Dutton EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), 5109148cc50SJames Courtier-Dutton }; 5119148cc50SJames Courtier-Dutton 512a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info snd_ctl_boolean_mono_info 5139148cc50SJames Courtier-Dutton 5149148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5159148cc50SJames Courtier-Dutton { 5169148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 5179148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 5189148cc50SJames Courtier-Dutton ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; 5199148cc50SJames Courtier-Dutton return 0; 5209148cc50SJames Courtier-Dutton } 5219148cc50SJames Courtier-Dutton 5229148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5239148cc50SJames Courtier-Dutton { 5249148cc50SJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 5259148cc50SJames Courtier-Dutton unsigned int mask = kcontrol->private_value & 0xff; 5269148cc50SJames Courtier-Dutton unsigned int val, cache; 5279148cc50SJames Courtier-Dutton val = ucontrol->value.integer.value[0]; 5289148cc50SJames Courtier-Dutton cache = emu->emu1010.dac_pads; 5299148cc50SJames Courtier-Dutton if (val == 1) 5309148cc50SJames Courtier-Dutton cache = cache | mask; 5319148cc50SJames Courtier-Dutton else 5329148cc50SJames Courtier-Dutton cache = cache & ~mask; 5339148cc50SJames Courtier-Dutton if (cache != emu->emu1010.dac_pads) { 5349148cc50SJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); 5359148cc50SJames Courtier-Dutton emu->emu1010.dac_pads = cache; 5369148cc50SJames Courtier-Dutton } 5379148cc50SJames Courtier-Dutton 5389148cc50SJames Courtier-Dutton return 0; 5399148cc50SJames Courtier-Dutton } 5409148cc50SJames Courtier-Dutton 5419148cc50SJames Courtier-Dutton 5429148cc50SJames Courtier-Dutton 5439148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \ 5449148cc50SJames Courtier-Dutton { \ 5459148cc50SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 5469148cc50SJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 5479148cc50SJames Courtier-Dutton .info = snd_emu1010_dac_pads_info, \ 5489148cc50SJames Courtier-Dutton .get = snd_emu1010_dac_pads_get, \ 5499148cc50SJames Courtier-Dutton .put = snd_emu1010_dac_pads_put, \ 5509148cc50SJames Courtier-Dutton .private_value = chid \ 5519148cc50SJames Courtier-Dutton } 5529148cc50SJames Courtier-Dutton 553b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_dac_pads[] = { 5549148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), 5559148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), 5569148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), 5579148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4), 5589148cc50SJames Courtier-Dutton EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1), 5599f4bd5ddSJames Courtier-Dutton }; 5609f4bd5ddSJames Courtier-Dutton 561b0dbdaeaSJames Courtier-Dutton 562b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, 563b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 564b0dbdaeaSJames Courtier-Dutton { 5651541c66dSTakashi Iwai static const char * const texts[4] = { 566edec7bbbSJames Courtier-Dutton "44100", "48000", "SPDIF", "ADAT" 567b0dbdaeaSJames Courtier-Dutton }; 568b0dbdaeaSJames Courtier-Dutton 5691541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 4, texts); 570b0dbdaeaSJames Courtier-Dutton } 571b0dbdaeaSJames Courtier-Dutton 572b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, 573b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 574b0dbdaeaSJames Courtier-Dutton { 575b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 576b0dbdaeaSJames Courtier-Dutton 577b0dbdaeaSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; 578b0dbdaeaSJames Courtier-Dutton return 0; 579b0dbdaeaSJames Courtier-Dutton } 580b0dbdaeaSJames Courtier-Dutton 581b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, 582b0dbdaeaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 583b0dbdaeaSJames Courtier-Dutton { 584b0dbdaeaSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 585b0dbdaeaSJames Courtier-Dutton unsigned int val; 586b0dbdaeaSJames Courtier-Dutton int change = 0; 587b0dbdaeaSJames Courtier-Dutton 588b0dbdaeaSJames Courtier-Dutton val = ucontrol->value.enumerated.item[0] ; 58974415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 4; */ 59074415a36SJames Courtier-Dutton if (val >= 4) 59174415a36SJames Courtier-Dutton return -EINVAL; 592b0dbdaeaSJames Courtier-Dutton change = (emu->emu1010.internal_clock != val); 593b0dbdaeaSJames Courtier-Dutton if (change) { 594b0dbdaeaSJames Courtier-Dutton emu->emu1010.internal_clock = val; 595b0dbdaeaSJames Courtier-Dutton switch (val) { 596b0dbdaeaSJames Courtier-Dutton case 0: 597b0dbdaeaSJames Courtier-Dutton /* 44100 */ 598b0dbdaeaSJames Courtier-Dutton /* Mute all */ 599b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 600a869057cSOswald Buddenhagen /* Default fallback clock 44.1kHz */ 601b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); 602b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 44.1kHz x1 */ 603b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 604b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); 605b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 606b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 607b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); 608b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 609e40a0b2eSJames Courtier-Dutton msleep(10); 610b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 611b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 612b0dbdaeaSJames Courtier-Dutton break; 613b0dbdaeaSJames Courtier-Dutton case 1: 614b0dbdaeaSJames Courtier-Dutton /* 48000 */ 615b0dbdaeaSJames Courtier-Dutton /* Mute all */ 616b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 617b0dbdaeaSJames Courtier-Dutton /* Default fallback clock 48kHz */ 618b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 619b0dbdaeaSJames Courtier-Dutton /* Word Clock source, Internal 48kHz x1 */ 620b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 621b0dbdaeaSJames Courtier-Dutton EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); 622b0dbdaeaSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 623b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 624b0dbdaeaSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); 625b0dbdaeaSJames Courtier-Dutton /* Allow DLL to settle */ 626e40a0b2eSJames Courtier-Dutton msleep(10); 627b0dbdaeaSJames Courtier-Dutton /* Unmute all */ 628b0dbdaeaSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 629b0dbdaeaSJames Courtier-Dutton break; 630edec7bbbSJames Courtier-Dutton 631edec7bbbSJames Courtier-Dutton case 2: /* Take clock from S/PDIF IN */ 632edec7bbbSJames Courtier-Dutton /* Mute all */ 633edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 634edec7bbbSJames Courtier-Dutton /* Default fallback clock 48kHz */ 635edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 636edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to S/PDIF input */ 637edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 638edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); 639edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 640edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 641edec7bbbSJames Courtier-Dutton EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 642edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 643edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 644edec7bbbSJames Courtier-Dutton msleep(10); 645edec7bbbSJames Courtier-Dutton /* Unmute all */ 646edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 647edec7bbbSJames Courtier-Dutton break; 648edec7bbbSJames Courtier-Dutton 649edec7bbbSJames Courtier-Dutton case 3: 650edec7bbbSJames Courtier-Dutton /* Take clock from ADAT IN */ 651edec7bbbSJames Courtier-Dutton /* Mute all */ 652edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 653edec7bbbSJames Courtier-Dutton /* Default fallback clock 48kHz */ 654edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 655edec7bbbSJames Courtier-Dutton /* Word Clock source, sync to ADAT input */ 656edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 657edec7bbbSJames Courtier-Dutton EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); 658edec7bbbSJames Courtier-Dutton /* Set LEDs on Audio Dock */ 659edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 660edec7bbbSJames Courtier-Dutton /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 661edec7bbbSJames Courtier-Dutton /* Allow DLL to settle */ 662edec7bbbSJames Courtier-Dutton msleep(10); 663edec7bbbSJames Courtier-Dutton /* Unmute all */ 664edec7bbbSJames Courtier-Dutton snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 665edec7bbbSJames Courtier-Dutton 666edec7bbbSJames Courtier-Dutton 667edec7bbbSJames Courtier-Dutton break; 668b0dbdaeaSJames Courtier-Dutton } 669b0dbdaeaSJames Courtier-Dutton } 670b0dbdaeaSJames Courtier-Dutton return change; 671b0dbdaeaSJames Courtier-Dutton } 672b0dbdaeaSJames Courtier-Dutton 673f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock = 674b0dbdaeaSJames Courtier-Dutton { 675b0dbdaeaSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 676b0dbdaeaSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 677b0dbdaeaSJames Courtier-Dutton .name = "Clock Internal Rate", 678b0dbdaeaSJames Courtier-Dutton .count = 1, 679b0dbdaeaSJames Courtier-Dutton .info = snd_emu1010_internal_clock_info, 680b0dbdaeaSJames Courtier-Dutton .get = snd_emu1010_internal_clock_get, 681b0dbdaeaSJames Courtier-Dutton .put = snd_emu1010_internal_clock_put 682b0dbdaeaSJames Courtier-Dutton }; 683b0dbdaeaSJames Courtier-Dutton 68499dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol, 68599dcab46SMichael Gernoth struct snd_ctl_elem_info *uinfo) 68699dcab46SMichael Gernoth { 68799dcab46SMichael Gernoth static const char * const texts[2] = { 68899dcab46SMichael Gernoth "SPDIF", "ADAT" 68999dcab46SMichael Gernoth }; 69099dcab46SMichael Gernoth 69199dcab46SMichael Gernoth return snd_ctl_enum_info(uinfo, 1, 2, texts); 69299dcab46SMichael Gernoth } 69399dcab46SMichael Gernoth 69499dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol, 69599dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 69699dcab46SMichael Gernoth { 69799dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 69899dcab46SMichael Gernoth 69999dcab46SMichael Gernoth ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out; 70099dcab46SMichael Gernoth return 0; 70199dcab46SMichael Gernoth } 70299dcab46SMichael Gernoth 70399dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol, 70499dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 70599dcab46SMichael Gernoth { 70699dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 70799dcab46SMichael Gernoth unsigned int val; 70899dcab46SMichael Gernoth u32 tmp; 70999dcab46SMichael Gernoth int change = 0; 71099dcab46SMichael Gernoth 71199dcab46SMichael Gernoth val = ucontrol->value.enumerated.item[0]; 71299dcab46SMichael Gernoth /* Limit: uinfo->value.enumerated.items = 2; */ 71399dcab46SMichael Gernoth if (val >= 2) 71499dcab46SMichael Gernoth return -EINVAL; 71599dcab46SMichael Gernoth change = (emu->emu1010.optical_out != val); 71699dcab46SMichael Gernoth if (change) { 71799dcab46SMichael Gernoth emu->emu1010.optical_out = val; 7189d2f3863SOswald Buddenhagen tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) | 7199d2f3863SOswald Buddenhagen (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF); 72099dcab46SMichael Gernoth snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 72199dcab46SMichael Gernoth } 72299dcab46SMichael Gernoth return change; 72399dcab46SMichael Gernoth } 72499dcab46SMichael Gernoth 725f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = { 72699dcab46SMichael Gernoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 72799dcab46SMichael Gernoth .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 72899dcab46SMichael Gernoth .name = "Optical Output Mode", 72999dcab46SMichael Gernoth .count = 1, 73099dcab46SMichael Gernoth .info = snd_emu1010_optical_out_info, 73199dcab46SMichael Gernoth .get = snd_emu1010_optical_out_get, 73299dcab46SMichael Gernoth .put = snd_emu1010_optical_out_put 73399dcab46SMichael Gernoth }; 73499dcab46SMichael Gernoth 73599dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol, 73699dcab46SMichael Gernoth struct snd_ctl_elem_info *uinfo) 73799dcab46SMichael Gernoth { 73899dcab46SMichael Gernoth static const char * const texts[2] = { 73999dcab46SMichael Gernoth "SPDIF", "ADAT" 74099dcab46SMichael Gernoth }; 74199dcab46SMichael Gernoth 74299dcab46SMichael Gernoth return snd_ctl_enum_info(uinfo, 1, 2, texts); 74399dcab46SMichael Gernoth } 74499dcab46SMichael Gernoth 74599dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol, 74699dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 74799dcab46SMichael Gernoth { 74899dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 74999dcab46SMichael Gernoth 75099dcab46SMichael Gernoth ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in; 75199dcab46SMichael Gernoth return 0; 75299dcab46SMichael Gernoth } 75399dcab46SMichael Gernoth 75499dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol, 75599dcab46SMichael Gernoth struct snd_ctl_elem_value *ucontrol) 75699dcab46SMichael Gernoth { 75799dcab46SMichael Gernoth struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 75899dcab46SMichael Gernoth unsigned int val; 75999dcab46SMichael Gernoth u32 tmp; 76099dcab46SMichael Gernoth int change = 0; 76199dcab46SMichael Gernoth 76299dcab46SMichael Gernoth val = ucontrol->value.enumerated.item[0]; 76399dcab46SMichael Gernoth /* Limit: uinfo->value.enumerated.items = 2; */ 76499dcab46SMichael Gernoth if (val >= 2) 76599dcab46SMichael Gernoth return -EINVAL; 76699dcab46SMichael Gernoth change = (emu->emu1010.optical_in != val); 76799dcab46SMichael Gernoth if (change) { 76899dcab46SMichael Gernoth emu->emu1010.optical_in = val; 7699d2f3863SOswald Buddenhagen tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) | 7709d2f3863SOswald Buddenhagen (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF); 77199dcab46SMichael Gernoth snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 77299dcab46SMichael Gernoth } 77399dcab46SMichael Gernoth return change; 77499dcab46SMichael Gernoth } 77599dcab46SMichael Gernoth 776f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = { 77799dcab46SMichael Gernoth .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 77899dcab46SMichael Gernoth .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 77999dcab46SMichael Gernoth .name = "Optical Input Mode", 78099dcab46SMichael Gernoth .count = 1, 78199dcab46SMichael Gernoth .info = snd_emu1010_optical_in_info, 78299dcab46SMichael Gernoth .get = snd_emu1010_optical_in_get, 78399dcab46SMichael Gernoth .put = snd_emu1010_optical_in_put 78499dcab46SMichael Gernoth }; 78599dcab46SMichael Gernoth 786184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, 787184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 788184c1e2cSJames Courtier-Dutton { 789184c1e2cSJames Courtier-Dutton #if 0 7901541c66dSTakashi Iwai static const char * const texts[4] = { 791184c1e2cSJames Courtier-Dutton "Unknown1", "Unknown2", "Mic", "Line" 792184c1e2cSJames Courtier-Dutton }; 793184c1e2cSJames Courtier-Dutton #endif 7941541c66dSTakashi Iwai static const char * const texts[2] = { 795184c1e2cSJames Courtier-Dutton "Mic", "Line" 796184c1e2cSJames Courtier-Dutton }; 797184c1e2cSJames Courtier-Dutton 7981541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 2, texts); 799184c1e2cSJames Courtier-Dutton } 800184c1e2cSJames Courtier-Dutton 801184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, 802184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 803184c1e2cSJames Courtier-Dutton { 804184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 805184c1e2cSJames Courtier-Dutton 806184c1e2cSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; 807184c1e2cSJames Courtier-Dutton return 0; 808184c1e2cSJames Courtier-Dutton } 809184c1e2cSJames Courtier-Dutton 810184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, 811184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 812184c1e2cSJames Courtier-Dutton { 813184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 814184c1e2cSJames Courtier-Dutton unsigned int source_id; 815184c1e2cSJames Courtier-Dutton unsigned int ngain, ogain; 816a1c87c0bSOswald Buddenhagen u16 gpio; 817184c1e2cSJames Courtier-Dutton int change = 0; 818184c1e2cSJames Courtier-Dutton unsigned long flags; 819184c1e2cSJames Courtier-Dutton u32 source; 820184c1e2cSJames Courtier-Dutton /* If the capture source has changed, 821184c1e2cSJames Courtier-Dutton * update the capture volume from the cached value 822184c1e2cSJames Courtier-Dutton * for the particular source. 823184c1e2cSJames Courtier-Dutton */ 82474415a36SJames Courtier-Dutton source_id = ucontrol->value.enumerated.item[0]; 82574415a36SJames Courtier-Dutton /* Limit: uinfo->value.enumerated.items = 2; */ 82674415a36SJames Courtier-Dutton /* emu->i2c_capture_volume */ 82774415a36SJames Courtier-Dutton if (source_id >= 2) 82874415a36SJames Courtier-Dutton return -EINVAL; 829184c1e2cSJames Courtier-Dutton change = (emu->i2c_capture_source != source_id); 830184c1e2cSJames Courtier-Dutton if (change) { 831184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 832184c1e2cSJames Courtier-Dutton spin_lock_irqsave(&emu->emu_lock, flags); 833a1c87c0bSOswald Buddenhagen gpio = inw(emu->port + A_IOCFG); 834184c1e2cSJames Courtier-Dutton if (source_id==0) 835a1c87c0bSOswald Buddenhagen outw(gpio | 0x4, emu->port + A_IOCFG); 836184c1e2cSJames Courtier-Dutton else 837a1c87c0bSOswald Buddenhagen outw(gpio & ~0x4, emu->port + A_IOCFG); 838184c1e2cSJames Courtier-Dutton spin_unlock_irqrestore(&emu->emu_lock, flags); 839184c1e2cSJames Courtier-Dutton 840184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ 841184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ 842184c1e2cSJames Courtier-Dutton if (ngain != ogain) 843184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); 844184c1e2cSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ 845184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ 846184c1e2cSJames Courtier-Dutton if (ngain != ogain) 847184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 848184c1e2cSJames Courtier-Dutton 849184c1e2cSJames Courtier-Dutton source = 1 << (source_id + 2); 850184c1e2cSJames Courtier-Dutton snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ 851184c1e2cSJames Courtier-Dutton emu->i2c_capture_source = source_id; 852184c1e2cSJames Courtier-Dutton } 853184c1e2cSJames Courtier-Dutton return change; 854184c1e2cSJames Courtier-Dutton } 855184c1e2cSJames Courtier-Dutton 856f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source = 857184c1e2cSJames Courtier-Dutton { 858184c1e2cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 859184c1e2cSJames Courtier-Dutton .name = "Capture Source", 860184c1e2cSJames Courtier-Dutton .info = snd_audigy_i2c_capture_source_info, 861184c1e2cSJames Courtier-Dutton .get = snd_audigy_i2c_capture_source_get, 862184c1e2cSJames Courtier-Dutton .put = snd_audigy_i2c_capture_source_put 863184c1e2cSJames Courtier-Dutton }; 864184c1e2cSJames Courtier-Dutton 865184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, 866184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 867184c1e2cSJames Courtier-Dutton { 868184c1e2cSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 869184c1e2cSJames Courtier-Dutton uinfo->count = 2; 870184c1e2cSJames Courtier-Dutton uinfo->value.integer.min = 0; 871184c1e2cSJames Courtier-Dutton uinfo->value.integer.max = 255; 872184c1e2cSJames Courtier-Dutton return 0; 873184c1e2cSJames Courtier-Dutton } 874184c1e2cSJames Courtier-Dutton 875184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, 876184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 877184c1e2cSJames Courtier-Dutton { 878184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 87974415a36SJames Courtier-Dutton unsigned int source_id; 880184c1e2cSJames Courtier-Dutton 881184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 88274415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 88374415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 88474415a36SJames Courtier-Dutton if (source_id >= 2) 88574415a36SJames Courtier-Dutton return -EINVAL; 886184c1e2cSJames Courtier-Dutton 887184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; 888184c1e2cSJames Courtier-Dutton ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; 889184c1e2cSJames Courtier-Dutton return 0; 890184c1e2cSJames Courtier-Dutton } 891184c1e2cSJames Courtier-Dutton 892184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, 893184c1e2cSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 894184c1e2cSJames Courtier-Dutton { 895184c1e2cSJames Courtier-Dutton struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 896184c1e2cSJames Courtier-Dutton unsigned int ogain; 89714a29565SOswald Buddenhagen unsigned int ngain0, ngain1; 89874415a36SJames Courtier-Dutton unsigned int source_id; 899184c1e2cSJames Courtier-Dutton int change = 0; 900184c1e2cSJames Courtier-Dutton 901184c1e2cSJames Courtier-Dutton source_id = kcontrol->private_value; 90274415a36SJames Courtier-Dutton /* Limit: emu->i2c_capture_volume */ 90374415a36SJames Courtier-Dutton /* capture_source: uinfo->value.enumerated.items = 2 */ 90474415a36SJames Courtier-Dutton if (source_id >= 2) 90574415a36SJames Courtier-Dutton return -EINVAL; 90614a29565SOswald Buddenhagen ngain0 = ucontrol->value.integer.value[0]; 90714a29565SOswald Buddenhagen ngain1 = ucontrol->value.integer.value[1]; 90814a29565SOswald Buddenhagen if (ngain0 > 0xff) 90914a29565SOswald Buddenhagen return -EINVAL; 91014a29565SOswald Buddenhagen if (ngain1 > 0xff) 91114a29565SOswald Buddenhagen return -EINVAL; 912184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ 91314a29565SOswald Buddenhagen if (ogain != ngain0) { 914184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 91514a29565SOswald Buddenhagen snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0); 91614a29565SOswald Buddenhagen emu->i2c_capture_volume[source_id][0] = ngain0; 917184c1e2cSJames Courtier-Dutton change = 1; 918184c1e2cSJames Courtier-Dutton } 919184c1e2cSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ 92014a29565SOswald Buddenhagen if (ogain != ngain1) { 921184c1e2cSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 92214a29565SOswald Buddenhagen snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1); 92314a29565SOswald Buddenhagen emu->i2c_capture_volume[source_id][1] = ngain1; 924184c1e2cSJames Courtier-Dutton change = 1; 925184c1e2cSJames Courtier-Dutton } 926184c1e2cSJames Courtier-Dutton 927184c1e2cSJames Courtier-Dutton return change; 928184c1e2cSJames Courtier-Dutton } 929184c1e2cSJames Courtier-Dutton 930184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \ 931184c1e2cSJames Courtier-Dutton { \ 932184c1e2cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 933184c1e2cSJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 934184c1e2cSJames Courtier-Dutton SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 935184c1e2cSJames Courtier-Dutton .info = snd_audigy_i2c_volume_info, \ 936184c1e2cSJames Courtier-Dutton .get = snd_audigy_i2c_volume_get, \ 937184c1e2cSJames Courtier-Dutton .put = snd_audigy_i2c_volume_put, \ 938184c1e2cSJames Courtier-Dutton .tlv = { .p = snd_audigy_db_scale2 }, \ 939184c1e2cSJames Courtier-Dutton .private_value = chid \ 940184c1e2cSJames Courtier-Dutton } 941184c1e2cSJames Courtier-Dutton 942184c1e2cSJames Courtier-Dutton 943b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = { 944184c1e2cSJames Courtier-Dutton I2C_VOLUME("Mic Capture Volume", 0), 945184c1e2cSJames Courtier-Dutton I2C_VOLUME("Line Capture Volume", 0) 946184c1e2cSJames Courtier-Dutton }; 947184c1e2cSJames Courtier-Dutton 9480af68e5eSTakashi Iwai #if 0 949eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 9501da177e4SLinus Torvalds { 9511541c66dSTakashi Iwai static const char * const texts[] = {"44100", "48000", "96000"}; 9521da177e4SLinus Torvalds 9531541c66dSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 3, texts); 9541da177e4SLinus Torvalds } 9551da177e4SLinus Torvalds 956eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, 957eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 9581da177e4SLinus Torvalds { 959eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 9601da177e4SLinus Torvalds unsigned int tmp; 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 9631da177e4SLinus Torvalds switch (tmp & A_SPDIF_RATE_MASK) { 9641da177e4SLinus Torvalds case A_SPDIF_44100: 9651da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 9661da177e4SLinus Torvalds break; 9671da177e4SLinus Torvalds case A_SPDIF_48000: 9681da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 9691da177e4SLinus Torvalds break; 9701da177e4SLinus Torvalds case A_SPDIF_96000: 9711da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 9721da177e4SLinus Torvalds break; 9731da177e4SLinus Torvalds default: 9741da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 9751da177e4SLinus Torvalds } 9761da177e4SLinus Torvalds return 0; 9771da177e4SLinus Torvalds } 9781da177e4SLinus Torvalds 979eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(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 int change; 9841da177e4SLinus Torvalds unsigned int reg, val, tmp; 9851da177e4SLinus Torvalds unsigned long flags; 9861da177e4SLinus Torvalds 9871da177e4SLinus Torvalds switch(ucontrol->value.enumerated.item[0]) { 9881da177e4SLinus Torvalds case 0: 9891da177e4SLinus Torvalds val = A_SPDIF_44100; 9901da177e4SLinus Torvalds break; 9911da177e4SLinus Torvalds case 1: 9921da177e4SLinus Torvalds val = A_SPDIF_48000; 9931da177e4SLinus Torvalds break; 9941da177e4SLinus Torvalds case 2: 9951da177e4SLinus Torvalds val = A_SPDIF_96000; 9961da177e4SLinus Torvalds break; 9971da177e4SLinus Torvalds default: 9981da177e4SLinus Torvalds val = A_SPDIF_48000; 9991da177e4SLinus Torvalds break; 10001da177e4SLinus Torvalds } 10011da177e4SLinus Torvalds 10021da177e4SLinus Torvalds 10031da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 10041da177e4SLinus Torvalds reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 10051da177e4SLinus Torvalds tmp = reg & ~A_SPDIF_RATE_MASK; 10061da177e4SLinus Torvalds tmp |= val; 100712bda107STakashi Iwai change = (tmp != reg); 100812bda107STakashi Iwai if (change) 10091da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); 10101da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 10111da177e4SLinus Torvalds return change; 10121da177e4SLinus Torvalds } 10131da177e4SLinus Torvalds 1014b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate = 10151da177e4SLinus Torvalds { 10161da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 10171da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 10181da177e4SLinus Torvalds .name = "Audigy SPDIF Output Sample Rate", 10191da177e4SLinus Torvalds .count = 1, 10201da177e4SLinus Torvalds .info = snd_audigy_spdif_output_rate_info, 10211da177e4SLinus Torvalds .get = snd_audigy_spdif_output_rate_get, 10221da177e4SLinus Torvalds .put = snd_audigy_spdif_output_rate_put 10231da177e4SLinus Torvalds }; 10240af68e5eSTakashi Iwai #endif 10251da177e4SLinus Torvalds 1026eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, 1027eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 10281da177e4SLinus Torvalds { 1029eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 10301da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 10311da177e4SLinus Torvalds int change; 10321da177e4SLinus Torvalds unsigned int val; 10331da177e4SLinus Torvalds 103474415a36SJames Courtier-Dutton /* Limit: emu->spdif_bits */ 103574415a36SJames Courtier-Dutton if (idx >= 3) 103674415a36SJames Courtier-Dutton return -EINVAL; 10371da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) | 10381da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) | 10391da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) | 10401da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24); 10411da177e4SLinus Torvalds change = val != emu->spdif_bits[idx]; 10421da177e4SLinus Torvalds if (change) { 10431da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); 10441da177e4SLinus Torvalds emu->spdif_bits[idx] = val; 10451da177e4SLinus Torvalds } 10461da177e4SLinus Torvalds return change; 10471da177e4SLinus Torvalds } 10481da177e4SLinus Torvalds 1049f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = 10501da177e4SLinus Torvalds { 10511da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READ, 10525549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10531da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 10547583cb51STakashi Iwai .count = 3, 10551da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 10561da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get_mask 10571da177e4SLinus Torvalds }; 10581da177e4SLinus Torvalds 1059f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control = 10601da177e4SLinus Torvalds { 10615549d549SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10621da177e4SLinus Torvalds .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 10637583cb51STakashi Iwai .count = 3, 10641da177e4SLinus Torvalds .info = snd_emu10k1_spdif_info, 10651da177e4SLinus Torvalds .get = snd_emu10k1_spdif_get, 10661da177e4SLinus Torvalds .put = snd_emu10k1_spdif_put 10671da177e4SLinus Torvalds }; 10681da177e4SLinus Torvalds 10691da177e4SLinus Torvalds 1070eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route) 10711da177e4SLinus Torvalds { 10721da177e4SLinus Torvalds if (emu->audigy) { 10731da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT1, voice, 10741da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt1(route)); 10751da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_FXRT2, voice, 10761da177e4SLinus Torvalds snd_emu10k1_compose_audigy_fxrt2(route)); 10771da177e4SLinus Torvalds } else { 10781da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, FXRT, voice, 10791da177e4SLinus Torvalds snd_emu10k1_compose_send_routing(route)); 10801da177e4SLinus Torvalds } 10811da177e4SLinus Torvalds } 10821da177e4SLinus Torvalds 1083eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume) 10841da177e4SLinus Torvalds { 10851da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); 10861da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); 10871da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); 10881da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); 10891da177e4SLinus Torvalds if (emu->audigy) { 109051d652f4SOswald Buddenhagen snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, 109151d652f4SOswald Buddenhagen snd_emu10k1_compose_audigy_sendamounts(volume)); 10921da177e4SLinus Torvalds } 10931da177e4SLinus Torvalds } 10941da177e4SLinus Torvalds 10951da177e4SLinus Torvalds /* PCM stream controls */ 10961da177e4SLinus Torvalds 1097eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 10981da177e4SLinus Torvalds { 1099eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11001da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 11011da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 11021da177e4SLinus Torvalds uinfo->value.integer.min = 0; 11031da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 11041da177e4SLinus Torvalds return 0; 11051da177e4SLinus Torvalds } 11061da177e4SLinus Torvalds 1107eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, 1108eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11091da177e4SLinus Torvalds { 1110eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1111eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1112eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 11131da177e4SLinus Torvalds int voice, idx; 11141da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 11151da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 11161da177e4SLinus Torvalds 11171da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 11181da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 11191da177e4SLinus Torvalds ucontrol->value.integer.value[(voice * num_efx) + idx] = 11201da177e4SLinus Torvalds mix->send_routing[voice][idx] & mask; 11211da177e4SLinus Torvalds return 0; 11221da177e4SLinus Torvalds } 11231da177e4SLinus Torvalds 1124eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, 1125eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11261da177e4SLinus Torvalds { 11271da177e4SLinus Torvalds unsigned long flags; 1128eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1129eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1130eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 11311da177e4SLinus Torvalds int change = 0, voice, idx, val; 11321da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 11331da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 11341da177e4SLinus Torvalds 11351da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 11361da177e4SLinus Torvalds for (voice = 0; voice < 3; voice++) 11371da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 11381da177e4SLinus Torvalds val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; 11391da177e4SLinus Torvalds if (mix->send_routing[voice][idx] != val) { 11401da177e4SLinus Torvalds mix->send_routing[voice][idx] = val; 11411da177e4SLinus Torvalds change = 1; 11421da177e4SLinus Torvalds } 11431da177e4SLinus Torvalds } 11441da177e4SLinus Torvalds if (change && mix->epcm) { 11451da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 11461da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 11471da177e4SLinus Torvalds &mix->send_routing[1][0]); 11481da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, 11491da177e4SLinus Torvalds &mix->send_routing[2][0]); 11501da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 11511da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 11521da177e4SLinus Torvalds &mix->send_routing[0][0]); 11531da177e4SLinus Torvalds } 11541da177e4SLinus Torvalds } 11551da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 11561da177e4SLinus Torvalds return change; 11571da177e4SLinus Torvalds } 11581da177e4SLinus Torvalds 1159f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control = 11601da177e4SLinus Torvalds { 11611da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 116267ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 11631da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Routing", 11641da177e4SLinus Torvalds .count = 32, 11651da177e4SLinus Torvalds .info = snd_emu10k1_send_routing_info, 11661da177e4SLinus Torvalds .get = snd_emu10k1_send_routing_get, 11671da177e4SLinus Torvalds .put = snd_emu10k1_send_routing_put 11681da177e4SLinus Torvalds }; 11691da177e4SLinus Torvalds 1170eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 11711da177e4SLinus Torvalds { 1172eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11731da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 11741da177e4SLinus Torvalds uinfo->count = emu->audigy ? 3*8 : 3*4; 11751da177e4SLinus Torvalds uinfo->value.integer.min = 0; 11761da177e4SLinus Torvalds uinfo->value.integer.max = 255; 11771da177e4SLinus Torvalds return 0; 11781da177e4SLinus Torvalds } 11791da177e4SLinus Torvalds 1180eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, 1181eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11821da177e4SLinus Torvalds { 1183eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1184eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1185eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 11861da177e4SLinus Torvalds int idx; 11871da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 11881da177e4SLinus Torvalds 11891da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) 11901da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; 11911da177e4SLinus Torvalds return 0; 11921da177e4SLinus Torvalds } 11931da177e4SLinus Torvalds 1194eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, 1195eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 11961da177e4SLinus Torvalds { 11971da177e4SLinus Torvalds unsigned long flags; 1198eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1199eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1200eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12011da177e4SLinus Torvalds int change = 0, idx, val; 12021da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 12031da177e4SLinus Torvalds 12041da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 12051da177e4SLinus Torvalds for (idx = 0; idx < 3*num_efx; idx++) { 12061da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 12071da177e4SLinus Torvalds if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { 12081da177e4SLinus Torvalds mix->send_volume[idx/num_efx][idx%num_efx] = val; 12091da177e4SLinus Torvalds change = 1; 12101da177e4SLinus Torvalds } 12111da177e4SLinus Torvalds } 12121da177e4SLinus Torvalds if (change && mix->epcm) { 12131da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 12141da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 12151da177e4SLinus Torvalds &mix->send_volume[1][0]); 12161da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, 12171da177e4SLinus Torvalds &mix->send_volume[2][0]); 12181da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 12191da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 12201da177e4SLinus Torvalds &mix->send_volume[0][0]); 12211da177e4SLinus Torvalds } 12221da177e4SLinus Torvalds } 12231da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 12241da177e4SLinus Torvalds return change; 12251da177e4SLinus Torvalds } 12261da177e4SLinus Torvalds 1227f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control = 12281da177e4SLinus Torvalds { 12291da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 123067ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 12311da177e4SLinus Torvalds .name = "EMU10K1 PCM Send Volume", 12321da177e4SLinus Torvalds .count = 32, 12331da177e4SLinus Torvalds .info = snd_emu10k1_send_volume_info, 12341da177e4SLinus Torvalds .get = snd_emu10k1_send_volume_get, 12351da177e4SLinus Torvalds .put = snd_emu10k1_send_volume_put 12361da177e4SLinus Torvalds }; 12371da177e4SLinus Torvalds 1238eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 12391da177e4SLinus Torvalds { 12401da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 12411da177e4SLinus Torvalds uinfo->count = 3; 12421da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1243bcdbd3b7SOswald Buddenhagen uinfo->value.integer.max = 0x1fffd; 12441da177e4SLinus Torvalds return 0; 12451da177e4SLinus Torvalds } 12461da177e4SLinus Torvalds 1247eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, 1248eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12491da177e4SLinus Torvalds { 1250eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1251eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1252eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12531da177e4SLinus Torvalds int idx; 12541da177e4SLinus Torvalds 12551da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) 1256bcdbd3b7SOswald Buddenhagen ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U; 12571da177e4SLinus Torvalds return 0; 12581da177e4SLinus Torvalds } 12591da177e4SLinus Torvalds 1260eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, 1261eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 12621da177e4SLinus Torvalds { 12631da177e4SLinus Torvalds unsigned long flags; 1264eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1265eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1266eb4698f3STakashi Iwai &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12671da177e4SLinus Torvalds int change = 0, idx, val; 12681da177e4SLinus Torvalds 12691da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 12701da177e4SLinus Torvalds for (idx = 0; idx < 3; idx++) { 1271bcdbd3b7SOswald Buddenhagen unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff; 1272bcdbd3b7SOswald Buddenhagen val = uval * 0x8000U / 0xffffU; 12731da177e4SLinus Torvalds if (mix->attn[idx] != val) { 12741da177e4SLinus Torvalds mix->attn[idx] = val; 12751da177e4SLinus Torvalds change = 1; 12761da177e4SLinus Torvalds } 12771da177e4SLinus Torvalds } 12781da177e4SLinus Torvalds if (change && mix->epcm) { 12791da177e4SLinus Torvalds if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 12801da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); 12811da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]); 12821da177e4SLinus Torvalds } else if (mix->epcm->voices[0]) { 12831da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); 12841da177e4SLinus Torvalds } 12851da177e4SLinus Torvalds } 12861da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 12871da177e4SLinus Torvalds return change; 12881da177e4SLinus Torvalds } 12891da177e4SLinus Torvalds 1290f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control = 12911da177e4SLinus Torvalds { 12921da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 129367ed4161SClemens Ladisch .iface = SNDRV_CTL_ELEM_IFACE_PCM, 12941da177e4SLinus Torvalds .name = "EMU10K1 PCM Volume", 12951da177e4SLinus Torvalds .count = 32, 12961da177e4SLinus Torvalds .info = snd_emu10k1_attn_info, 12971da177e4SLinus Torvalds .get = snd_emu10k1_attn_get, 12981da177e4SLinus Torvalds .put = snd_emu10k1_attn_put 12991da177e4SLinus Torvalds }; 13001da177e4SLinus Torvalds 13011da177e4SLinus Torvalds /* Mutichannel PCM stream controls */ 13021da177e4SLinus Torvalds 1303eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13041da177e4SLinus Torvalds { 1305eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13061da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13071da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 13081da177e4SLinus Torvalds uinfo->value.integer.min = 0; 13091da177e4SLinus Torvalds uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 13101da177e4SLinus Torvalds return 0; 13111da177e4SLinus Torvalds } 13121da177e4SLinus Torvalds 1313eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, 1314eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13151da177e4SLinus Torvalds { 1316eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1317eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1318eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13191da177e4SLinus Torvalds int idx; 13201da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 13211da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 13221da177e4SLinus Torvalds 13231da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 13241da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = 13251da177e4SLinus Torvalds mix->send_routing[0][idx] & mask; 13261da177e4SLinus Torvalds return 0; 13271da177e4SLinus Torvalds } 13281da177e4SLinus Torvalds 1329eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, 1330eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13311da177e4SLinus Torvalds { 13321da177e4SLinus Torvalds unsigned long flags; 1333eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13341da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1335eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 13361da177e4SLinus Torvalds int change = 0, idx, val; 13371da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 13381da177e4SLinus Torvalds int mask = emu->audigy ? 0x3f : 0x0f; 13391da177e4SLinus Torvalds 13401da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 13411da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 13421da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & mask; 13431da177e4SLinus Torvalds if (mix->send_routing[0][idx] != val) { 13441da177e4SLinus Torvalds mix->send_routing[0][idx] = val; 13451da177e4SLinus Torvalds change = 1; 13461da177e4SLinus Torvalds } 13471da177e4SLinus Torvalds } 13481da177e4SLinus Torvalds 13491da177e4SLinus Torvalds if (change && mix->epcm) { 13501da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 13511da177e4SLinus Torvalds update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number, 13521da177e4SLinus Torvalds &mix->send_routing[0][0]); 13531da177e4SLinus Torvalds } 13541da177e4SLinus Torvalds } 13551da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 13561da177e4SLinus Torvalds return change; 13571da177e4SLinus Torvalds } 13581da177e4SLinus Torvalds 1359f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control = 13601da177e4SLinus Torvalds { 13611da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 13621da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 13631da177e4SLinus Torvalds .name = "Multichannel PCM Send Routing", 13641da177e4SLinus Torvalds .count = 16, 13651da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_routing_info, 13661da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_routing_get, 13671da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_routing_put 13681da177e4SLinus Torvalds }; 13691da177e4SLinus Torvalds 1370eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13711da177e4SLinus Torvalds { 1372eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13731da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13741da177e4SLinus Torvalds uinfo->count = emu->audigy ? 8 : 4; 13751da177e4SLinus Torvalds uinfo->value.integer.min = 0; 13761da177e4SLinus Torvalds uinfo->value.integer.max = 255; 13771da177e4SLinus Torvalds return 0; 13781da177e4SLinus Torvalds } 13791da177e4SLinus Torvalds 1380eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, 1381eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13821da177e4SLinus Torvalds { 1383eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1384eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1385eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13861da177e4SLinus Torvalds int idx; 13871da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 13881da177e4SLinus Torvalds 13891da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) 13901da177e4SLinus Torvalds ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; 13911da177e4SLinus Torvalds return 0; 13921da177e4SLinus Torvalds } 13931da177e4SLinus Torvalds 1394eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, 1395eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 13961da177e4SLinus Torvalds { 13971da177e4SLinus Torvalds unsigned long flags; 1398eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13991da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1400eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 14011da177e4SLinus Torvalds int change = 0, idx, val; 14021da177e4SLinus Torvalds int num_efx = emu->audigy ? 8 : 4; 14031da177e4SLinus Torvalds 14041da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 14051da177e4SLinus Torvalds for (idx = 0; idx < num_efx; idx++) { 14061da177e4SLinus Torvalds val = ucontrol->value.integer.value[idx] & 255; 14071da177e4SLinus Torvalds if (mix->send_volume[0][idx] != val) { 14081da177e4SLinus Torvalds mix->send_volume[0][idx] = val; 14091da177e4SLinus Torvalds change = 1; 14101da177e4SLinus Torvalds } 14111da177e4SLinus Torvalds } 14121da177e4SLinus Torvalds if (change && mix->epcm) { 14131da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 14141da177e4SLinus Torvalds update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number, 14151da177e4SLinus Torvalds &mix->send_volume[0][0]); 14161da177e4SLinus Torvalds } 14171da177e4SLinus Torvalds } 14181da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 14191da177e4SLinus Torvalds return change; 14201da177e4SLinus Torvalds } 14211da177e4SLinus Torvalds 14221da177e4SLinus Torvalds 1423f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control = 14241da177e4SLinus Torvalds { 14251da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 14261da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14271da177e4SLinus Torvalds .name = "Multichannel PCM Send Volume", 14281da177e4SLinus Torvalds .count = 16, 14291da177e4SLinus Torvalds .info = snd_emu10k1_efx_send_volume_info, 14301da177e4SLinus Torvalds .get = snd_emu10k1_efx_send_volume_get, 14311da177e4SLinus Torvalds .put = snd_emu10k1_efx_send_volume_put 14321da177e4SLinus Torvalds }; 14331da177e4SLinus Torvalds 1434eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 14351da177e4SLinus Torvalds { 14361da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 14371da177e4SLinus Torvalds uinfo->count = 1; 14381da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1439bcdbd3b7SOswald Buddenhagen uinfo->value.integer.max = 0x1fffd; 14401da177e4SLinus Torvalds return 0; 14411da177e4SLinus Torvalds } 14421da177e4SLinus Torvalds 1443eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, 1444eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14451da177e4SLinus Torvalds { 1446eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1447eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = 1448eb4698f3STakashi Iwai &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 14491da177e4SLinus Torvalds 1450bcdbd3b7SOswald Buddenhagen ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U; 14511da177e4SLinus Torvalds return 0; 14521da177e4SLinus Torvalds } 14531da177e4SLinus Torvalds 1454eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, 1455eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14561da177e4SLinus Torvalds { 14571da177e4SLinus Torvalds unsigned long flags; 1458eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14591da177e4SLinus Torvalds int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 1460eb4698f3STakashi Iwai struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 14611da177e4SLinus Torvalds int change = 0, val; 1462bcdbd3b7SOswald Buddenhagen unsigned uval; 14631da177e4SLinus Torvalds 14641da177e4SLinus Torvalds spin_lock_irqsave(&emu->reg_lock, flags); 1465bcdbd3b7SOswald Buddenhagen uval = ucontrol->value.integer.value[0] & 0x1ffff; 1466bcdbd3b7SOswald Buddenhagen val = uval * 0x8000U / 0xffffU; 14671da177e4SLinus Torvalds if (mix->attn[0] != val) { 14681da177e4SLinus Torvalds mix->attn[0] = val; 14691da177e4SLinus Torvalds change = 1; 14701da177e4SLinus Torvalds } 14711da177e4SLinus Torvalds if (change && mix->epcm) { 14721da177e4SLinus Torvalds if (mix->epcm->voices[ch]) { 14731da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); 14741da177e4SLinus Torvalds } 14751da177e4SLinus Torvalds } 14761da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->reg_lock, flags); 14771da177e4SLinus Torvalds return change; 14781da177e4SLinus Torvalds } 14791da177e4SLinus Torvalds 1480f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control = 14811da177e4SLinus Torvalds { 14821da177e4SLinus Torvalds .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 14831da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14841da177e4SLinus Torvalds .name = "Multichannel PCM Volume", 14851da177e4SLinus Torvalds .count = 16, 14861da177e4SLinus Torvalds .info = snd_emu10k1_efx_attn_info, 14871da177e4SLinus Torvalds .get = snd_emu10k1_efx_attn_get, 14881da177e4SLinus Torvalds .put = snd_emu10k1_efx_attn_put 14891da177e4SLinus Torvalds }; 14901da177e4SLinus Torvalds 1491a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info snd_ctl_boolean_mono_info 14921da177e4SLinus Torvalds 1493eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, 1494eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 14951da177e4SLinus Torvalds { 1496eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14971da177e4SLinus Torvalds 14981da177e4SLinus Torvalds if (emu->audigy) 1499a1c87c0bSOswald Buddenhagen ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; 15001da177e4SLinus Torvalds else 15011da177e4SLinus Torvalds ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; 1502d2cd74b1STakashi Iwai if (emu->card_capabilities->invert_shared_spdif) 1503d2cd74b1STakashi Iwai ucontrol->value.integer.value[0] = 1504d2cd74b1STakashi Iwai !ucontrol->value.integer.value[0]; 1505d2cd74b1STakashi Iwai 15061da177e4SLinus Torvalds return 0; 15071da177e4SLinus Torvalds } 15081da177e4SLinus Torvalds 1509eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, 1510eb4698f3STakashi Iwai struct snd_ctl_elem_value *ucontrol) 15111da177e4SLinus Torvalds { 15121da177e4SLinus Torvalds unsigned long flags; 1513eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 1514d2cd74b1STakashi Iwai unsigned int reg, val, sw; 15151da177e4SLinus Torvalds int change = 0; 15161da177e4SLinus Torvalds 1517d2cd74b1STakashi Iwai sw = ucontrol->value.integer.value[0]; 1518d2cd74b1STakashi Iwai if (emu->card_capabilities->invert_shared_spdif) 1519d2cd74b1STakashi Iwai sw = !sw; 152050164f69SOswald Buddenhagen spin_lock_irqsave(&emu->emu_lock, flags); 1521184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 1522184c1e2cSJames Courtier-Dutton /* Do nothing for Audigy 2 ZS Notebook */ 1523184c1e2cSJames Courtier-Dutton } else if (emu->audigy) { 1524a1c87c0bSOswald Buddenhagen reg = inw(emu->port + A_IOCFG); 1525d2cd74b1STakashi Iwai val = sw ? A_IOCFG_GPOUT0 : 0; 15261da177e4SLinus Torvalds change = (reg & A_IOCFG_GPOUT0) != val; 15271da177e4SLinus Torvalds if (change) { 15281da177e4SLinus Torvalds reg &= ~A_IOCFG_GPOUT0; 15291da177e4SLinus Torvalds reg |= val; 1530a1c87c0bSOswald Buddenhagen outw(reg | val, emu->port + A_IOCFG); 15311da177e4SLinus Torvalds } 15321da177e4SLinus Torvalds } 15331da177e4SLinus Torvalds reg = inl(emu->port + HCFG); 1534d2cd74b1STakashi Iwai val = sw ? HCFG_GPOUT0 : 0; 15351da177e4SLinus Torvalds change |= (reg & HCFG_GPOUT0) != val; 15361da177e4SLinus Torvalds if (change) { 15371da177e4SLinus Torvalds reg &= ~HCFG_GPOUT0; 15381da177e4SLinus Torvalds reg |= val; 15391da177e4SLinus Torvalds outl(reg | val, emu->port + HCFG); 15401da177e4SLinus Torvalds } 154150164f69SOswald Buddenhagen spin_unlock_irqrestore(&emu->emu_lock, flags); 15421da177e4SLinus Torvalds return change; 15431da177e4SLinus Torvalds } 15441da177e4SLinus Torvalds 1545f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif = 15461da177e4SLinus Torvalds { 15471da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 15481da177e4SLinus Torvalds .name = "SB Live Analog/Digital Output Jack", 15491da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 15501da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 15511da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 15521da177e4SLinus Torvalds }; 15531da177e4SLinus Torvalds 1554f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif = 15551da177e4SLinus Torvalds { 15561da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 15571da177e4SLinus Torvalds .name = "Audigy Analog/Digital Output Jack", 15581da177e4SLinus Torvalds .info = snd_emu10k1_shared_spdif_info, 15591da177e4SLinus Torvalds .get = snd_emu10k1_shared_spdif_get, 15601da177e4SLinus Torvalds .put = snd_emu10k1_shared_spdif_put 15611da177e4SLinus Torvalds }; 15621da177e4SLinus Torvalds 156316950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */ 156416950e09STakashi Iwai 156516950e09STakashi Iwai #define snd_audigy_capture_boost_info snd_ctl_boolean_mono_info 156616950e09STakashi Iwai 156716950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol, 156816950e09STakashi Iwai struct snd_ctl_elem_value *ucontrol) 156916950e09STakashi Iwai { 157016950e09STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 157116950e09STakashi Iwai unsigned int val; 157216950e09STakashi Iwai 157316950e09STakashi Iwai /* FIXME: better to use a cached version */ 157416950e09STakashi Iwai val = snd_ac97_read(emu->ac97, AC97_REC_GAIN); 157516950e09STakashi Iwai ucontrol->value.integer.value[0] = !!val; 157616950e09STakashi Iwai return 0; 157716950e09STakashi Iwai } 157816950e09STakashi Iwai 157916950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, 158016950e09STakashi Iwai struct snd_ctl_elem_value *ucontrol) 158116950e09STakashi Iwai { 158216950e09STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 158316950e09STakashi Iwai unsigned int val; 158416950e09STakashi Iwai 158516950e09STakashi Iwai if (ucontrol->value.integer.value[0]) 158616950e09STakashi Iwai val = 0x0f0f; 158716950e09STakashi Iwai else 158816950e09STakashi Iwai val = 0; 158916950e09STakashi Iwai return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); 159016950e09STakashi Iwai } 159116950e09STakashi Iwai 1592f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost = 159316950e09STakashi Iwai { 159416950e09STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 15952a52feb1SMaciej S. Szmigiero .name = "Mic Extra Boost", 159616950e09STakashi Iwai .info = snd_audigy_capture_boost_info, 159716950e09STakashi Iwai .get = snd_audigy_capture_boost_get, 159816950e09STakashi Iwai .put = snd_audigy_capture_boost_put 159916950e09STakashi Iwai }; 160016950e09STakashi Iwai 160116950e09STakashi Iwai 16021da177e4SLinus Torvalds /* 16031da177e4SLinus Torvalds */ 1604eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) 16051da177e4SLinus Torvalds { 1606eb4698f3STakashi Iwai struct snd_emu10k1 *emu = ac97->private_data; 16071da177e4SLinus Torvalds emu->ac97 = NULL; 16081da177e4SLinus Torvalds } 16091da177e4SLinus Torvalds 16101da177e4SLinus Torvalds /* 16111da177e4SLinus Torvalds */ 1612eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name) 16131da177e4SLinus Torvalds { 1614eb4698f3STakashi Iwai struct snd_ctl_elem_id id; 16151da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 16161da177e4SLinus Torvalds strcpy(id.name, name); 16171da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 16181da177e4SLinus Torvalds return snd_ctl_remove_id(card, &id); 16191da177e4SLinus Torvalds } 16201da177e4SLinus Torvalds 1621eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) 16221da177e4SLinus Torvalds { 1623eb4698f3STakashi Iwai struct snd_ctl_elem_id sid; 16241da177e4SLinus Torvalds memset(&sid, 0, sizeof(sid)); 16251da177e4SLinus Torvalds strcpy(sid.name, name); 16261da177e4SLinus Torvalds sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 16271da177e4SLinus Torvalds return snd_ctl_find_id(card, &sid); 16281da177e4SLinus Torvalds } 16291da177e4SLinus Torvalds 1630eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst) 16311da177e4SLinus Torvalds { 1632eb4698f3STakashi Iwai struct snd_kcontrol *kctl = ctl_find(card, src); 16331da177e4SLinus Torvalds if (kctl) { 163436476b81SMaciej S. Szmigiero snd_ctl_rename(card, kctl, dst); 16351da177e4SLinus Torvalds return 0; 16361da177e4SLinus Torvalds } 16371da177e4SLinus Torvalds return -ENOENT; 16381da177e4SLinus Torvalds } 16391da177e4SLinus Torvalds 1640e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu, 164167ed4161SClemens Ladisch int pcm_device, int multi_device) 16421da177e4SLinus Torvalds { 1643155e3d3bSOswald Buddenhagen int err; 1644eb4698f3STakashi Iwai struct snd_kcontrol *kctl; 1645eb4698f3STakashi Iwai struct snd_card *card = emu->card; 16466fddce26STakashi Iwai const char * const *c; 16476fddce26STakashi Iwai static const char * const emu10k1_remove_ctls[] = { 16481da177e4SLinus Torvalds /* no AC97 mono, surround, center/lfe */ 16491da177e4SLinus Torvalds "Master Mono Playback Switch", 16501da177e4SLinus Torvalds "Master Mono Playback Volume", 16511da177e4SLinus Torvalds "PCM Out Path & Mute", 16521da177e4SLinus Torvalds "Mono Output Select", 16531da177e4SLinus Torvalds "Surround Playback Switch", 16541da177e4SLinus Torvalds "Surround Playback Volume", 16551da177e4SLinus Torvalds "Center Playback Switch", 16561da177e4SLinus Torvalds "Center Playback Volume", 16571da177e4SLinus Torvalds "LFE Playback Switch", 16581da177e4SLinus Torvalds "LFE Playback Volume", 16591da177e4SLinus Torvalds NULL 16601da177e4SLinus Torvalds }; 16616fddce26STakashi Iwai static const char * const emu10k1_rename_ctls[] = { 16621da177e4SLinus Torvalds "Surround Digital Playback Volume", "Surround Playback Volume", 16631da177e4SLinus Torvalds "Center Digital Playback Volume", "Center Playback Volume", 16641da177e4SLinus Torvalds "LFE Digital Playback Volume", "LFE Playback Volume", 16651da177e4SLinus Torvalds NULL 16661da177e4SLinus Torvalds }; 16676fddce26STakashi Iwai static const char * const audigy_remove_ctls[] = { 16681da177e4SLinus Torvalds /* Master/PCM controls on ac97 of Audigy has no effect */ 166921fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 167021fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 16711da177e4SLinus Torvalds "PCM Playback Switch", 16721da177e4SLinus Torvalds "PCM Playback Volume", 16731da177e4SLinus Torvalds "Master Playback Switch", 16741da177e4SLinus Torvalds "Master Playback Volume", 16751da177e4SLinus Torvalds "PCM Out Path & Mute", 16761da177e4SLinus Torvalds "Mono Output Select", 16771da177e4SLinus Torvalds /* remove unused AC97 capture controls */ 16781da177e4SLinus Torvalds "Capture Source", 16791da177e4SLinus Torvalds "Capture Switch", 16801da177e4SLinus Torvalds "Capture Volume", 16811da177e4SLinus Torvalds "Mic Select", 1682274b2000SMaciej S. Szmigiero "Headphone Playback Switch", 1683274b2000SMaciej S. Szmigiero "Headphone Playback Volume", 1684274b2000SMaciej S. Szmigiero "3D Control - Center", 1685274b2000SMaciej S. Szmigiero "3D Control - Depth", 1686274b2000SMaciej S. Szmigiero "3D Control - Switch", 16871da177e4SLinus Torvalds "Video Playback Switch", 16881da177e4SLinus Torvalds "Video Playback Volume", 16891da177e4SLinus Torvalds "Mic Playback Switch", 16901da177e4SLinus Torvalds "Mic Playback Volume", 1691274b2000SMaciej S. Szmigiero "External Amplifier", 16921da177e4SLinus Torvalds NULL 16931da177e4SLinus Torvalds }; 16946fddce26STakashi Iwai static const char * const audigy_rename_ctls[] = { 16951da177e4SLinus Torvalds /* use conventional names */ 16961da177e4SLinus Torvalds "Wave Playback Volume", "PCM Playback Volume", 16971da177e4SLinus Torvalds /* "Wave Capture Volume", "PCM Capture Volume", */ 16981da177e4SLinus Torvalds "Wave Master Playback Volume", "Master Playback Volume", 16991da177e4SLinus Torvalds "AMic Playback Volume", "Mic Playback Volume", 170052051942SMaciej S. Szmigiero "Master Mono Playback Switch", "Phone Output Playback Switch", 170152051942SMaciej S. Szmigiero "Master Mono Playback Volume", "Phone Output Playback Volume", 17021da177e4SLinus Torvalds NULL 17031da177e4SLinus Torvalds }; 17046fddce26STakashi Iwai static const char * const audigy_rename_ctls_i2c_adc[] = { 1705184c1e2cSJames Courtier-Dutton //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", 1706184c1e2cSJames Courtier-Dutton "Line Capture Volume", "Analog Mix Capture Volume", 1707184c1e2cSJames Courtier-Dutton "Wave Playback Volume", "OLD PCM Playback Volume", 1708184c1e2cSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 1709184c1e2cSJames Courtier-Dutton "AMic Playback Volume", "Old Mic Playback Volume", 1710eb41dab6SJames Courtier-Dutton "CD Capture Volume", "IEC958 Optical Capture Volume", 1711184c1e2cSJames Courtier-Dutton NULL 1712184c1e2cSJames Courtier-Dutton }; 17136fddce26STakashi Iwai static const char * const audigy_remove_ctls_i2c_adc[] = { 1714184c1e2cSJames Courtier-Dutton /* On the Audigy2 ZS Notebook 1715184c1e2cSJames Courtier-Dutton * Capture via WM8775 */ 1716184c1e2cSJames Courtier-Dutton "Mic Capture Volume", 1717184c1e2cSJames Courtier-Dutton "Analog Mix Capture Volume", 1718184c1e2cSJames Courtier-Dutton "Aux Capture Volume", 1719eb41dab6SJames Courtier-Dutton "IEC958 Optical Capture Volume", 1720184c1e2cSJames Courtier-Dutton NULL 1721184c1e2cSJames Courtier-Dutton }; 17226fddce26STakashi Iwai static const char * const audigy_remove_ctls_1361t_adc[] = { 172321fdddeaSJames Courtier-Dutton /* On the Audigy2 the AC97 playback is piped into 172421fdddeaSJames Courtier-Dutton * the Philips ADC for 24bit capture */ 172521fdddeaSJames Courtier-Dutton "PCM Playback Switch", 172621fdddeaSJames Courtier-Dutton "PCM Playback Volume", 172721fdddeaSJames Courtier-Dutton "Capture Source", 172821fdddeaSJames Courtier-Dutton "Capture Switch", 172921fdddeaSJames Courtier-Dutton "Capture Volume", 173021fdddeaSJames Courtier-Dutton "Mic Capture Volume", 173121fdddeaSJames Courtier-Dutton "Headphone Playback Switch", 173221fdddeaSJames Courtier-Dutton "Headphone Playback Volume", 173321fdddeaSJames Courtier-Dutton "3D Control - Center", 173421fdddeaSJames Courtier-Dutton "3D Control - Depth", 173521fdddeaSJames Courtier-Dutton "3D Control - Switch", 173621fdddeaSJames Courtier-Dutton "Line2 Playback Volume", 173721fdddeaSJames Courtier-Dutton "Line2 Capture Volume", 173821fdddeaSJames Courtier-Dutton NULL 173921fdddeaSJames Courtier-Dutton }; 17406fddce26STakashi Iwai static const char * const audigy_rename_ctls_1361t_adc[] = { 174121fdddeaSJames Courtier-Dutton "Master Playback Switch", "Master Capture Switch", 174221fdddeaSJames Courtier-Dutton "Master Playback Volume", "Master Capture Volume", 174321fdddeaSJames Courtier-Dutton "Wave Master Playback Volume", "Master Playback Volume", 1744d355c82aSJaroslav Kysela "Beep Playback Switch", "Beep Capture Switch", 1745d355c82aSJaroslav Kysela "Beep Playback Volume", "Beep Capture Volume", 174621fdddeaSJames Courtier-Dutton "Phone Playback Switch", "Phone Capture Switch", 174721fdddeaSJames Courtier-Dutton "Phone Playback Volume", "Phone Capture Volume", 174821fdddeaSJames Courtier-Dutton "Mic Playback Switch", "Mic Capture Switch", 174921fdddeaSJames Courtier-Dutton "Mic Playback Volume", "Mic Capture Volume", 175021fdddeaSJames Courtier-Dutton "Line Playback Switch", "Line Capture Switch", 175121fdddeaSJames Courtier-Dutton "Line Playback Volume", "Line Capture Volume", 175221fdddeaSJames Courtier-Dutton "CD Playback Switch", "CD Capture Switch", 175321fdddeaSJames Courtier-Dutton "CD Playback Volume", "CD Capture Volume", 175421fdddeaSJames Courtier-Dutton "Aux Playback Switch", "Aux Capture Switch", 175521fdddeaSJames Courtier-Dutton "Aux Playback Volume", "Aux Capture Volume", 175621fdddeaSJames Courtier-Dutton "Video Playback Switch", "Video Capture Switch", 175721fdddeaSJames Courtier-Dutton "Video Playback Volume", "Video Capture Volume", 175852051942SMaciej S. Szmigiero "Master Mono Playback Switch", "Phone Output Playback Switch", 175952051942SMaciej S. Szmigiero "Master Mono Playback Volume", "Phone Output Playback Volume", 176021fdddeaSJames Courtier-Dutton NULL 176121fdddeaSJames Courtier-Dutton }; 17621da177e4SLinus Torvalds 17632b637da5SLee Revell if (emu->card_capabilities->ac97_chip) { 1764eb4698f3STakashi Iwai struct snd_ac97_bus *pbus; 1765eb4698f3STakashi Iwai struct snd_ac97_template ac97; 176651055da5STakashi Iwai static const struct snd_ac97_bus_ops ops = { 17671da177e4SLinus Torvalds .write = snd_emu10k1_ac97_write, 17681da177e4SLinus Torvalds .read = snd_emu10k1_ac97_read, 17691da177e4SLinus Torvalds }; 17701da177e4SLinus Torvalds 177112bda107STakashi Iwai err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus); 177212bda107STakashi Iwai if (err < 0) 17731da177e4SLinus Torvalds return err; 17741da177e4SLinus Torvalds pbus->no_vra = 1; /* we don't need VRA */ 17751da177e4SLinus Torvalds 17761da177e4SLinus Torvalds memset(&ac97, 0, sizeof(ac97)); 17771da177e4SLinus Torvalds ac97.private_data = emu; 17781da177e4SLinus Torvalds ac97.private_free = snd_emu10k1_mixer_free_ac97; 17791da177e4SLinus Torvalds ac97.scaps = AC97_SCAP_NO_SPDIF; 178012bda107STakashi Iwai err = snd_ac97_mixer(pbus, &ac97, &emu->ac97); 178112bda107STakashi Iwai if (err < 0) { 1782b1508693STakashi Iwai if (emu->card_capabilities->ac97_chip == 1) 17831da177e4SLinus Torvalds return err; 17846f002b02STakashi Iwai dev_info(emu->card->dev, 17856f002b02STakashi Iwai "AC97 is optional on this board\n"); 17866f002b02STakashi Iwai dev_info(emu->card->dev, 17876f002b02STakashi Iwai "Proceeding without ac97 mixers...\n"); 1788b1508693STakashi Iwai snd_device_free(emu->card, pbus); 1789b1508693STakashi Iwai goto no_ac97; /* FIXME: get rid of ugly gotos.. */ 1790b1508693STakashi Iwai } 17911da177e4SLinus Torvalds if (emu->audigy) { 17921da177e4SLinus Torvalds /* set master volume to 0 dB */ 17934d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); 17941da177e4SLinus Torvalds /* set capture source to mic */ 17954d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); 179652051942SMaciej S. Szmigiero /* set mono output (TAD) to mic */ 179752051942SMaciej S. Szmigiero snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE, 179852051942SMaciej S. Szmigiero 0x0200, 0x0200); 179921fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 180021fdddeaSJames Courtier-Dutton c = audigy_remove_ctls_1361t_adc; 180121fdddeaSJames Courtier-Dutton else 18021da177e4SLinus Torvalds c = audigy_remove_ctls; 18031da177e4SLinus Torvalds } else { 18041da177e4SLinus Torvalds /* 18051da177e4SLinus Torvalds * Credits for cards based on STAC9758: 18061da177e4SLinus Torvalds * James Courtier-Dutton <James@superbug.demon.co.uk> 18071da177e4SLinus Torvalds * Voluspa <voluspa@comhem.se> 18081da177e4SLinus Torvalds */ 18091da177e4SLinus Torvalds if (emu->ac97->id == AC97_ID_STAC9758) { 18101da177e4SLinus Torvalds emu->rear_ac97 = 1; 18111da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); 18122594d960SRolf Stefan Wilke snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); 1813b6a48404SRaymond Yau remove_ctl(card,"Front Playback Volume"); 1814b6a48404SRaymond Yau remove_ctl(card,"Front Playback Switch"); 18151da177e4SLinus Torvalds } 18161da177e4SLinus Torvalds /* remove unused AC97 controls */ 18174d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); 18184d7d7596STakashi Iwai snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); 18191da177e4SLinus Torvalds c = emu10k1_remove_ctls; 18201da177e4SLinus Torvalds } 18211da177e4SLinus Torvalds for (; *c; c++) 18221da177e4SLinus Torvalds remove_ctl(card, *c); 1823184c1e2cSJames Courtier-Dutton } else if (emu->card_capabilities->i2c_adc) { 1824184c1e2cSJames Courtier-Dutton c = audigy_remove_ctls_i2c_adc; 1825184c1e2cSJames Courtier-Dutton for (; *c; c++) 1826184c1e2cSJames Courtier-Dutton remove_ctl(card, *c); 18271da177e4SLinus Torvalds } else { 1828f12aa40cSTakashi Iwai no_ac97: 18292b637da5SLee Revell if (emu->card_capabilities->ecard) 18301da177e4SLinus Torvalds strcpy(emu->card->mixername, "EMU APS"); 18311da177e4SLinus Torvalds else if (emu->audigy) 18321da177e4SLinus Torvalds strcpy(emu->card->mixername, "SB Audigy"); 18331da177e4SLinus Torvalds else 18341da177e4SLinus Torvalds strcpy(emu->card->mixername, "Emu10k1"); 18351da177e4SLinus Torvalds } 18361da177e4SLinus Torvalds 18371da177e4SLinus Torvalds if (emu->audigy) 183821fdddeaSJames Courtier-Dutton if (emu->card_capabilities->adc_1361t) 183921fdddeaSJames Courtier-Dutton c = audigy_rename_ctls_1361t_adc; 1840184c1e2cSJames Courtier-Dutton else if (emu->card_capabilities->i2c_adc) 1841184c1e2cSJames Courtier-Dutton c = audigy_rename_ctls_i2c_adc; 184221fdddeaSJames Courtier-Dutton else 18431da177e4SLinus Torvalds c = audigy_rename_ctls; 18441da177e4SLinus Torvalds else 18451da177e4SLinus Torvalds c = emu10k1_rename_ctls; 18461da177e4SLinus Torvalds for (; *c; c += 2) 18471da177e4SLinus Torvalds rename_ctl(card, c[0], c[1]); 184821fdddeaSJames Courtier-Dutton 1849e217b960SRaymond Yau if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */ 1850e217b960SRaymond Yau remove_ctl(card, "Center Playback Volume"); 1851e217b960SRaymond Yau remove_ctl(card, "LFE Playback Volume"); 1852e217b960SRaymond Yau remove_ctl(card, "Wave Center Playback Volume"); 1853e217b960SRaymond Yau remove_ctl(card, "Wave LFE Playback Volume"); 1854e217b960SRaymond Yau } 1855e3b9bc0eSJames Courtier-Dutton if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ 1856e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); 1857e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); 1858e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); 1859e3b9bc0eSJames Courtier-Dutton rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); 1860e3b9bc0eSJames Courtier-Dutton } 186112bda107STakashi Iwai kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu); 186212bda107STakashi Iwai if (!kctl) 18631da177e4SLinus Torvalds return -ENOMEM; 186467ed4161SClemens Ladisch kctl->id.device = pcm_device; 186512bda107STakashi Iwai err = snd_ctl_add(card, kctl); 186612bda107STakashi Iwai if (err) 18671da177e4SLinus Torvalds return err; 186812bda107STakashi Iwai kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu); 186912bda107STakashi Iwai if (!kctl) 18701da177e4SLinus Torvalds return -ENOMEM; 187167ed4161SClemens Ladisch kctl->id.device = pcm_device; 187212bda107STakashi Iwai err = snd_ctl_add(card, kctl); 187312bda107STakashi Iwai if (err) 18741da177e4SLinus Torvalds return err; 187512bda107STakashi Iwai kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu); 187612bda107STakashi Iwai if (!kctl) 18771da177e4SLinus Torvalds return -ENOMEM; 187867ed4161SClemens Ladisch kctl->id.device = pcm_device; 187912bda107STakashi Iwai err = snd_ctl_add(card, kctl); 188012bda107STakashi Iwai if (err) 18811da177e4SLinus Torvalds return err; 18821da177e4SLinus Torvalds 188312bda107STakashi Iwai kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu); 188412bda107STakashi Iwai if (!kctl) 18851da177e4SLinus Torvalds return -ENOMEM; 188667ed4161SClemens Ladisch kctl->id.device = multi_device; 188712bda107STakashi Iwai err = snd_ctl_add(card, kctl); 188812bda107STakashi Iwai if (err) 18891da177e4SLinus Torvalds return err; 18901da177e4SLinus Torvalds 189112bda107STakashi Iwai kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu); 189212bda107STakashi Iwai if (!kctl) 18931da177e4SLinus Torvalds return -ENOMEM; 189467ed4161SClemens Ladisch kctl->id.device = multi_device; 189512bda107STakashi Iwai err = snd_ctl_add(card, kctl); 189612bda107STakashi Iwai if (err) 18971da177e4SLinus Torvalds return err; 18981da177e4SLinus Torvalds 189912bda107STakashi Iwai kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu); 190012bda107STakashi Iwai if (!kctl) 19011da177e4SLinus Torvalds return -ENOMEM; 190267ed4161SClemens Ladisch kctl->id.device = multi_device; 190312bda107STakashi Iwai err = snd_ctl_add(card, kctl); 190412bda107STakashi Iwai if (err) 19051da177e4SLinus Torvalds return err; 19061da177e4SLinus Torvalds 1907a8661af5SOswald Buddenhagen if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) { 19081da177e4SLinus Torvalds /* sb live! and audigy */ 190912bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu); 191012bda107STakashi Iwai if (!kctl) 19111da177e4SLinus Torvalds return -ENOMEM; 19125549d549SClemens Ladisch if (!emu->audigy) 19135549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 191412bda107STakashi Iwai err = snd_ctl_add(card, kctl); 191512bda107STakashi Iwai if (err) 19161da177e4SLinus Torvalds return err; 191712bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu); 191812bda107STakashi Iwai if (!kctl) 19191da177e4SLinus Torvalds return -ENOMEM; 19205549d549SClemens Ladisch if (!emu->audigy) 19215549d549SClemens Ladisch kctl->id.device = emu->pcm_efx->device; 192212bda107STakashi Iwai err = snd_ctl_add(card, kctl); 192312bda107STakashi Iwai if (err) 19241da177e4SLinus Torvalds return err; 19251da177e4SLinus Torvalds } 19261da177e4SLinus Torvalds 1927190d2c46SJames Courtier-Dutton if (emu->card_capabilities->emu_model) { 192819b99fbaSJames Courtier-Dutton ; /* Disable the snd_audigy_spdif_shared_spdif */ 192919b99fbaSJames Courtier-Dutton } else if (emu->audigy) { 193012bda107STakashi Iwai kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu); 193112bda107STakashi Iwai if (!kctl) 19321da177e4SLinus Torvalds return -ENOMEM; 193312bda107STakashi Iwai err = snd_ctl_add(card, kctl); 193412bda107STakashi Iwai if (err) 19351da177e4SLinus Torvalds return err; 1936001f7589SJames Courtier-Dutton #if 0 193712bda107STakashi Iwai kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu); 193812bda107STakashi Iwai if (!kctl) 19391da177e4SLinus Torvalds return -ENOMEM; 194012bda107STakashi Iwai err = snd_ctl_add(card, kctl); 194112bda107STakashi Iwai if (err) 19421da177e4SLinus Torvalds return err; 1943001f7589SJames Courtier-Dutton #endif 19442b637da5SLee Revell } else if (! emu->card_capabilities->ecard) { 19451da177e4SLinus Torvalds /* sb live! */ 194612bda107STakashi Iwai kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu); 194712bda107STakashi Iwai if (!kctl) 19481da177e4SLinus Torvalds return -ENOMEM; 194912bda107STakashi Iwai err = snd_ctl_add(card, kctl); 195012bda107STakashi Iwai if (err) 19511da177e4SLinus Torvalds return err; 19521da177e4SLinus Torvalds } 19532b637da5SLee Revell if (emu->card_capabilities->ca0151_chip) { /* P16V */ 195412bda107STakashi Iwai err = snd_p16v_mixer(emu); 195512bda107STakashi Iwai if (err) 19561da177e4SLinus Torvalds return err; 19571da177e4SLinus Torvalds } 19581da177e4SLinus Torvalds 19593839e4f1STakashi Iwai if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { 19601c02e366SCtirad Fertr /* 1616(m) cardbus */ 19619f4bd5ddSJames Courtier-Dutton int i; 19629f4bd5ddSJames Courtier-Dutton 19631c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) { 19641c02e366SCtirad Fertr err = snd_ctl_add(card, 19651c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1616_output_enum_ctls[i], 19661c02e366SCtirad Fertr emu)); 19679f4bd5ddSJames Courtier-Dutton if (err < 0) 19689f4bd5ddSJames Courtier-Dutton return err; 19699f4bd5ddSJames Courtier-Dutton } 19709f4bd5ddSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { 19711c02e366SCtirad Fertr err = snd_ctl_add(card, 19721c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], 19731c02e366SCtirad Fertr emu)); 19741c02e366SCtirad Fertr if (err < 0) 19751c02e366SCtirad Fertr return err; 19761c02e366SCtirad Fertr } 19771c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) { 19781c02e366SCtirad Fertr err = snd_ctl_add(card, 19791c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); 19801c02e366SCtirad Fertr if (err < 0) 19811c02e366SCtirad Fertr return err; 19821c02e366SCtirad Fertr } 19831c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) { 19841c02e366SCtirad Fertr err = snd_ctl_add(card, 19851c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); 19861c02e366SCtirad Fertr if (err < 0) 19871c02e366SCtirad Fertr return err; 19881c02e366SCtirad Fertr } 19891c02e366SCtirad Fertr err = snd_ctl_add(card, 19901c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 19911c02e366SCtirad Fertr if (err < 0) 19921c02e366SCtirad Fertr return err; 199399dcab46SMichael Gernoth err = snd_ctl_add(card, 199499dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_out, emu)); 199599dcab46SMichael Gernoth if (err < 0) 199699dcab46SMichael Gernoth return err; 199799dcab46SMichael Gernoth err = snd_ctl_add(card, 199899dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_in, emu)); 199999dcab46SMichael Gernoth if (err < 0) 200099dcab46SMichael Gernoth return err; 20011c02e366SCtirad Fertr 200288aa1390STakashi Iwai } else if (emu->card_capabilities->emu_model) { 20031c02e366SCtirad Fertr /* all other e-mu cards for now */ 20041c02e366SCtirad Fertr int i; 20051c02e366SCtirad Fertr 20061c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { 20071c02e366SCtirad Fertr err = snd_ctl_add(card, 20081c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], 20091c02e366SCtirad Fertr emu)); 20101c02e366SCtirad Fertr if (err < 0) 20111c02e366SCtirad Fertr return err; 20121c02e366SCtirad Fertr } 20131c02e366SCtirad Fertr for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { 20141c02e366SCtirad Fertr err = snd_ctl_add(card, 20151c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], 20161c02e366SCtirad Fertr emu)); 20179f4bd5ddSJames Courtier-Dutton if (err < 0) 20189f4bd5ddSJames Courtier-Dutton return err; 20199f4bd5ddSJames Courtier-Dutton } 20209148cc50SJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { 20211c02e366SCtirad Fertr err = snd_ctl_add(card, 20221c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); 20239148cc50SJames Courtier-Dutton if (err < 0) 20249148cc50SJames Courtier-Dutton return err; 20259148cc50SJames Courtier-Dutton } 20269148cc50SJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { 20271c02e366SCtirad Fertr err = snd_ctl_add(card, 20281c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); 20299148cc50SJames Courtier-Dutton if (err < 0) 20309148cc50SJames Courtier-Dutton return err; 20319148cc50SJames Courtier-Dutton } 20321c02e366SCtirad Fertr err = snd_ctl_add(card, 20331c02e366SCtirad Fertr snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 2034b0dbdaeaSJames Courtier-Dutton if (err < 0) 2035b0dbdaeaSJames Courtier-Dutton return err; 203699dcab46SMichael Gernoth err = snd_ctl_add(card, 203799dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_out, emu)); 203899dcab46SMichael Gernoth if (err < 0) 203999dcab46SMichael Gernoth return err; 204099dcab46SMichael Gernoth err = snd_ctl_add(card, 204199dcab46SMichael Gernoth snd_ctl_new1(&snd_emu1010_optical_in, emu)); 204299dcab46SMichael Gernoth if (err < 0) 204399dcab46SMichael Gernoth return err; 20449f4bd5ddSJames Courtier-Dutton } 20459f4bd5ddSJames Courtier-Dutton 2046184c1e2cSJames Courtier-Dutton if ( emu->card_capabilities->i2c_adc) { 2047184c1e2cSJames Courtier-Dutton int i; 2048184c1e2cSJames Courtier-Dutton 2049184c1e2cSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); 2050184c1e2cSJames Courtier-Dutton if (err < 0) 2051184c1e2cSJames Courtier-Dutton return err; 2052184c1e2cSJames Courtier-Dutton 2053184c1e2cSJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) { 2054184c1e2cSJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu)); 2055184c1e2cSJames Courtier-Dutton if (err < 0) 2056184c1e2cSJames Courtier-Dutton return err; 2057184c1e2cSJames Courtier-Dutton } 2058184c1e2cSJames Courtier-Dutton } 2059184c1e2cSJames Courtier-Dutton 206016950e09STakashi Iwai if (emu->card_capabilities->ac97_chip && emu->audigy) { 206116950e09STakashi Iwai err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost, 206216950e09STakashi Iwai emu)); 206316950e09STakashi Iwai if (err < 0) 206416950e09STakashi Iwai return err; 206516950e09STakashi Iwai } 206616950e09STakashi Iwai 20671da177e4SLinus Torvalds return 0; 20681da177e4SLinus Torvalds } 2069