xref: /linux/sound/pci/emu10k1/emumixer.c (revision dc39bb3e4c25b784899cce572e539055898b2c73)
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