xref: /linux/sound/pci/emu10k1/emumixer.c (revision 6f3609f8a3da1214cd78f8a8a2ee2dab8fcc4505)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
3c1017a4cSJaroslav Kysela  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
41da177e4SLinus Torvalds  *                   Takashi Iwai <tiwai@suse.de>
51da177e4SLinus Torvalds  *                   Creative Labs, Inc.
61da177e4SLinus Torvalds  *  Routines for control of EMU10K1 chips / mixer routines
71da177e4SLinus Torvalds  *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
81da177e4SLinus Torvalds  *
99f4bd5ddSJames Courtier-Dutton  *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
109f4bd5ddSJames Courtier-Dutton  *  	Added EMU 1010 support.
119f4bd5ddSJames Courtier-Dutton  *
121da177e4SLinus Torvalds  *  BUGS:
131da177e4SLinus Torvalds  *    --
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  *  TODO:
161da177e4SLinus Torvalds  *    --
171da177e4SLinus Torvalds  */
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds #include <linux/time.h>
201da177e4SLinus Torvalds #include <linux/init.h>
211da177e4SLinus Torvalds #include <sound/core.h>
221da177e4SLinus Torvalds #include <sound/emu10k1.h>
23b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h>
24184c1e2cSJames Courtier-Dutton #include <sound/tlv.h>
25184c1e2cSJames Courtier-Dutton 
26184c1e2cSJames Courtier-Dutton #include "p17v.h"
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #define AC97_ID_STAC9758	0x83847658
291da177e4SLinus Torvalds 
300cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
31184c1e2cSJames Courtier-Dutton 
32536438f1SOswald Buddenhagen 
33536438f1SOswald Buddenhagen static int add_ctls(struct snd_emu10k1 *emu, const struct snd_kcontrol_new *tpl,
34536438f1SOswald Buddenhagen 		    const char * const *ctls, unsigned nctls)
35536438f1SOswald Buddenhagen {
36536438f1SOswald Buddenhagen 	struct snd_kcontrol_new kctl = *tpl;
37536438f1SOswald Buddenhagen 	int err;
38536438f1SOswald Buddenhagen 
39536438f1SOswald Buddenhagen 	for (unsigned i = 0; i < nctls; i++) {
40536438f1SOswald Buddenhagen 		kctl.name = ctls[i];
41536438f1SOswald Buddenhagen 		kctl.private_value = i;
42536438f1SOswald Buddenhagen 		err = snd_ctl_add(emu->card, snd_ctl_new1(&kctl, emu));
43536438f1SOswald Buddenhagen 		if (err < 0)
44536438f1SOswald Buddenhagen 			return err;
45536438f1SOswald Buddenhagen 	}
46536438f1SOswald Buddenhagen 	return 0;
47536438f1SOswald Buddenhagen }
48536438f1SOswald Buddenhagen 
49536438f1SOswald Buddenhagen 
50eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
511da177e4SLinus Torvalds {
521da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
531da177e4SLinus Torvalds 	uinfo->count = 1;
541da177e4SLinus Torvalds 	return 0;
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds 
57eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
58eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
591da177e4SLinus Torvalds {
60eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
611da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
621da177e4SLinus Torvalds 
6374415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
6474415a36SJames Courtier-Dutton 	if (idx >= 3)
6574415a36SJames Courtier-Dutton 		return -EINVAL;
661da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
671da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
681da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
691da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
701da177e4SLinus Torvalds 	return 0;
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds 
73eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
74eb4698f3STakashi Iwai 				      struct snd_ctl_elem_value *ucontrol)
751da177e4SLinus Torvalds {
761da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
771da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
781da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
791da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
801da177e4SLinus Torvalds 	return 0;
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds 
83dc39bb3eSOswald Buddenhagen #define PAIR_PS(base, one, two, sfx) base " " one sfx, base " " two sfx
84dc39bb3eSOswald Buddenhagen #define LR_PS(base, sfx) PAIR_PS(base, "Left", "Right", sfx)
859f4bd5ddSJames Courtier-Dutton 
86dc39bb3eSOswald Buddenhagen #define ADAT_PS(pfx, sfx) \
87dc39bb3eSOswald Buddenhagen 	pfx "ADAT 0" sfx, pfx "ADAT 1" sfx, pfx "ADAT 2" sfx, pfx "ADAT 3" sfx, \
88dc39bb3eSOswald Buddenhagen 	pfx "ADAT 4" sfx, pfx "ADAT 5" sfx, pfx "ADAT 6" sfx, pfx "ADAT 7" sfx
891c02e366SCtirad Fertr 
90dc39bb3eSOswald Buddenhagen #define PAIR_REGS(base, one, two) \
91dc39bb3eSOswald Buddenhagen 	base ## one ## 1, \
92dc39bb3eSOswald Buddenhagen 	base ## two ## 1
931c02e366SCtirad Fertr 
94dc39bb3eSOswald Buddenhagen #define LR_REGS(base) PAIR_REGS(base, _LEFT, _RIGHT)
95dc39bb3eSOswald Buddenhagen 
96dc39bb3eSOswald Buddenhagen #define ADAT_REGS(base) \
97dc39bb3eSOswald Buddenhagen 	base+0, base+1, base+2, base+3, base+4, base+5, base+6, base+7
981c02e366SCtirad Fertr 
9913d45709SPavel Hofman /*
10013d45709SPavel Hofman  * List of data sources available for each destination
10113d45709SPavel Hofman  */
102dc39bb3eSOswald Buddenhagen 
103dc39bb3eSOswald Buddenhagen #define DSP_TEXTS \
104dc39bb3eSOswald Buddenhagen 	"DSP 0", "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", \
105dc39bb3eSOswald Buddenhagen 	"DSP 8", "DSP 9", "DSP 10", "DSP 11", "DSP 12", "DSP 13", "DSP 14", "DSP 15", \
106dc39bb3eSOswald Buddenhagen 	"DSP 16", "DSP 17", "DSP 18", "DSP 19", "DSP 20", "DSP 21", "DSP 22", "DSP 23", \
107dc39bb3eSOswald Buddenhagen 	"DSP 24", "DSP 25", "DSP 26", "DSP 27", "DSP 28", "DSP 29", "DSP 30", "DSP 31"
108dc39bb3eSOswald Buddenhagen 
109dc39bb3eSOswald Buddenhagen #define PAIR_TEXTS(base, one, two) PAIR_PS(base, one, two, "")
110dc39bb3eSOswald Buddenhagen #define LR_TEXTS(base) LR_PS(base, "")
111dc39bb3eSOswald Buddenhagen #define ADAT_TEXTS(pfx) ADAT_PS(pfx, "")
112dc39bb3eSOswald Buddenhagen 
113dc39bb3eSOswald Buddenhagen #define EMU32_SRC_REGS \
114dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A, \
115dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+1, \
116dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, \
117dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+3, \
118dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, \
119dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+5, \
120dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+6, \
121dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+7, \
122dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+8, \
123dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+9, \
124dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xa, \
125dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xb, \
126dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xc, \
127dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xd, \
128dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xe, \
129dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xf, \
130dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B, \
131dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+1, \
132dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+2, \
133dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+3, \
134dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+4, \
135dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+5, \
136dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+6, \
137dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+7, \
138dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+8, \
139dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+9, \
140dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xa, \
141dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xb, \
142dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xc, \
143dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xd, \
144dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xe, \
145dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xf
146dc39bb3eSOswald Buddenhagen 
147*6f3609f8SOswald Buddenhagen /* 1010 rev1 */
148*6f3609f8SOswald Buddenhagen 
149dc39bb3eSOswald Buddenhagen #define EMU1010_COMMON_TEXTS \
150dc39bb3eSOswald Buddenhagen 	"Silence", \
151dc39bb3eSOswald Buddenhagen 	PAIR_TEXTS("Dock Mic", "A", "B"), \
152dc39bb3eSOswald Buddenhagen 	LR_TEXTS("Dock ADC1"), \
153dc39bb3eSOswald Buddenhagen 	LR_TEXTS("Dock ADC2"), \
154dc39bb3eSOswald Buddenhagen 	LR_TEXTS("Dock ADC3"), \
155dc39bb3eSOswald Buddenhagen 	LR_TEXTS("0202 ADC"), \
156dc39bb3eSOswald Buddenhagen 	LR_TEXTS("1010 SPDIF"), \
157dc39bb3eSOswald Buddenhagen 	ADAT_TEXTS("1010 ")
158dc39bb3eSOswald Buddenhagen 
159dc39bb3eSOswald Buddenhagen static const char * const emu1010_src_texts[] = {
160dc39bb3eSOswald Buddenhagen 	EMU1010_COMMON_TEXTS,
161dc39bb3eSOswald Buddenhagen 	DSP_TEXTS,
1629f4bd5ddSJames Courtier-Dutton };
1639f4bd5ddSJames Courtier-Dutton 
164dc39bb3eSOswald Buddenhagen static const unsigned short emu1010_src_regs[] = {
165dc39bb3eSOswald Buddenhagen 	EMU_SRC_SILENCE,
166dc39bb3eSOswald Buddenhagen 	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
167dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC1),
168dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC2),
169dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC3),
170dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_HAMOA_ADC),
171dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_HANA_SPDIF),
172dc39bb3eSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_HANA_ADAT),
173dc39bb3eSOswald Buddenhagen 	EMU32_SRC_REGS,
174dc39bb3eSOswald Buddenhagen };
175dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_src_regs) == ARRAY_SIZE(emu1010_src_texts));
176dc39bb3eSOswald Buddenhagen 
177f69d705dSOswald Buddenhagen /* 1010 rev2 */
178f69d705dSOswald Buddenhagen 
179f69d705dSOswald Buddenhagen #define EMU1010b_COMMON_TEXTS \
180f69d705dSOswald Buddenhagen 	"Silence", \
181f69d705dSOswald Buddenhagen 	PAIR_TEXTS("Dock Mic", "A", "B"), \
182f69d705dSOswald Buddenhagen 	LR_TEXTS("Dock ADC1"), \
183f69d705dSOswald Buddenhagen 	LR_TEXTS("Dock ADC2"), \
184f69d705dSOswald Buddenhagen 	LR_TEXTS("0202 ADC"), \
185f69d705dSOswald Buddenhagen 	LR_TEXTS("Dock SPDIF"), \
186f69d705dSOswald Buddenhagen 	LR_TEXTS("1010 SPDIF"), \
187f69d705dSOswald Buddenhagen 	ADAT_TEXTS("Dock "), \
188f69d705dSOswald Buddenhagen 	ADAT_TEXTS("1010 ")
189f69d705dSOswald Buddenhagen 
190f69d705dSOswald Buddenhagen static const char * const emu1010b_src_texts[] = {
191f69d705dSOswald Buddenhagen 	EMU1010b_COMMON_TEXTS,
192f69d705dSOswald Buddenhagen 	DSP_TEXTS,
193f69d705dSOswald Buddenhagen };
194f69d705dSOswald Buddenhagen 
195f69d705dSOswald Buddenhagen static const unsigned short emu1010b_src_regs[] = {
196f69d705dSOswald Buddenhagen 	EMU_SRC_SILENCE,
197f69d705dSOswald Buddenhagen 	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
198f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC1),
199f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC2),
200f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_HAMOA_ADC),
201f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_MDOCK_SPDIF),
202f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_HANA_SPDIF),
203f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_MDOCK_ADAT),
204f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_HANA_ADAT),
205f69d705dSOswald Buddenhagen 	EMU32_SRC_REGS,
206f69d705dSOswald Buddenhagen };
207f69d705dSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010b_src_regs) == ARRAY_SIZE(emu1010b_src_texts));
208f69d705dSOswald Buddenhagen 
2091c02e366SCtirad Fertr /* 1616(m) cardbus */
210dc39bb3eSOswald Buddenhagen 
211dc39bb3eSOswald Buddenhagen #define EMU1616_COMMON_TEXTS \
212dc39bb3eSOswald Buddenhagen 	"Silence", \
213dc39bb3eSOswald Buddenhagen 	PAIR_TEXTS("Mic", "A", "B"), \
214dc39bb3eSOswald Buddenhagen 	LR_TEXTS("ADC1"), \
215dc39bb3eSOswald Buddenhagen 	LR_TEXTS("ADC2"), \
216dc39bb3eSOswald Buddenhagen 	LR_TEXTS("SPDIF"), \
217dc39bb3eSOswald Buddenhagen 	ADAT_TEXTS("")
218dc39bb3eSOswald Buddenhagen 
219dc39bb3eSOswald Buddenhagen static const char * const emu1616_src_texts[] = {
220dc39bb3eSOswald Buddenhagen 	EMU1616_COMMON_TEXTS,
221dc39bb3eSOswald Buddenhagen 	DSP_TEXTS,
222dc39bb3eSOswald Buddenhagen };
223dc39bb3eSOswald Buddenhagen 
2249b00a1e9SOswald Buddenhagen static const unsigned short emu1616_src_regs[] = {
2251c02e366SCtirad Fertr 	EMU_SRC_SILENCE,
226dc39bb3eSOswald Buddenhagen 	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
227dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC1),
228dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC2),
229dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_MDOCK_SPDIF),
230dc39bb3eSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_MDOCK_ADAT),
231dc39bb3eSOswald Buddenhagen 	EMU32_SRC_REGS,
2321c02e366SCtirad Fertr };
233dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_src_regs) == ARRAY_SIZE(emu1616_src_texts));
2341c02e366SCtirad Fertr 
235*6f3609f8SOswald Buddenhagen /* 0404 rev1 & rev2 */
236*6f3609f8SOswald Buddenhagen 
237*6f3609f8SOswald Buddenhagen #define EMU0404_COMMON_TEXTS \
238*6f3609f8SOswald Buddenhagen 	"Silence", \
239*6f3609f8SOswald Buddenhagen 	LR_TEXTS("ADC"), \
240*6f3609f8SOswald Buddenhagen 	LR_TEXTS("SPDIF")
241*6f3609f8SOswald Buddenhagen 
242*6f3609f8SOswald Buddenhagen static const char * const emu0404_src_texts[] = {
243*6f3609f8SOswald Buddenhagen 	EMU0404_COMMON_TEXTS,
244*6f3609f8SOswald Buddenhagen 	DSP_TEXTS,
245*6f3609f8SOswald Buddenhagen };
246*6f3609f8SOswald Buddenhagen 
247*6f3609f8SOswald Buddenhagen static const unsigned short emu0404_src_regs[] = {
248*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
249*6f3609f8SOswald Buddenhagen 	LR_REGS(EMU_SRC_HAMOA_ADC),
250*6f3609f8SOswald Buddenhagen 	LR_REGS(EMU_SRC_HANA_SPDIF),
251*6f3609f8SOswald Buddenhagen 	EMU32_SRC_REGS,
252*6f3609f8SOswald Buddenhagen };
253*6f3609f8SOswald Buddenhagen static_assert(ARRAY_SIZE(emu0404_src_regs) == ARRAY_SIZE(emu0404_src_texts));
254*6f3609f8SOswald Buddenhagen 
25513d45709SPavel Hofman /*
25613d45709SPavel Hofman  * Data destinations - physical EMU outputs.
25713d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
25813d45709SPavel Hofman  */
259536438f1SOswald Buddenhagen 
260536438f1SOswald Buddenhagen #define LR_CTLS(base) LR_PS(base, " Playback Enum")
261536438f1SOswald Buddenhagen #define ADAT_CTLS(pfx) ADAT_PS(pfx, " Playback Enum")
262536438f1SOswald Buddenhagen 
263*6f3609f8SOswald Buddenhagen /* 1010 rev1 */
264*6f3609f8SOswald Buddenhagen 
265536438f1SOswald Buddenhagen static const char * const emu1010_output_texts[] = {
266536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
267536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
268536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
269536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC4"),
270536438f1SOswald Buddenhagen 	LR_CTLS("Dock Phones"),
271536438f1SOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
272536438f1SOswald Buddenhagen 	LR_CTLS("0202 DAC"),
273536438f1SOswald Buddenhagen 	LR_CTLS("1010 SPDIF"),
274536438f1SOswald Buddenhagen 	ADAT_CTLS("1010 "),
2759f4bd5ddSJames Courtier-Dutton };
2769f4bd5ddSJames Courtier-Dutton 
277536438f1SOswald Buddenhagen static const unsigned short emu1010_output_dst[] = {
278536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
279536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
280536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
281536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC4),
282536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_PHONES),
283536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_SPDIF),
284536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
285536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
286536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_HANA_ADAT),
2871c02e366SCtirad Fertr };
288536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dst) == ARRAY_SIZE(emu1010_output_texts));
289536438f1SOswald Buddenhagen 
2901fc710f0SOswald Buddenhagen static const unsigned short emu1010_output_dflt[] = {
2911fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2921fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
2931fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
2941fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
2951fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2961fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2971fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2981fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2991fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
3001fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
3011fc710f0SOswald Buddenhagen };
3021fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dflt) == ARRAY_SIZE(emu1010_output_dst));
3031fc710f0SOswald Buddenhagen 
304f69d705dSOswald Buddenhagen /* 1010 rev2 */
305f69d705dSOswald Buddenhagen 
306f69d705dSOswald Buddenhagen static const char * const snd_emu1010b_output_texts[] = {
307f69d705dSOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
308f69d705dSOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
309f69d705dSOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
310f69d705dSOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
311f69d705dSOswald Buddenhagen 	ADAT_CTLS("Dock "),
312f69d705dSOswald Buddenhagen 	LR_CTLS("0202 DAC"),
313f69d705dSOswald Buddenhagen 	LR_CTLS("1010 SPDIF"),
314f69d705dSOswald Buddenhagen 	ADAT_CTLS("1010 "),
315f69d705dSOswald Buddenhagen };
316f69d705dSOswald Buddenhagen 
317f69d705dSOswald Buddenhagen static const unsigned short emu1010b_output_dst[] = {
318f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
319f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
320f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
321f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_MDOCK_SPDIF),
322f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_DST_MDOCK_ADAT),
323f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
324f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
325f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_DST_HANA_ADAT),
326f69d705dSOswald Buddenhagen };
327f69d705dSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010b_output_dst) == ARRAY_SIZE(snd_emu1010b_output_texts));
328f69d705dSOswald Buddenhagen 
329f69d705dSOswald Buddenhagen static const unsigned short emu1010b_output_dflt[] = {
330f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
331f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
332f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
333f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
334f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
335f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
336f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
337f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
338f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
339f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
340f69d705dSOswald Buddenhagen };
341f69d705dSOswald Buddenhagen 
342536438f1SOswald Buddenhagen /* 1616(m) cardbus */
343536438f1SOswald Buddenhagen 
344536438f1SOswald Buddenhagen static const char * const snd_emu1616_output_texts[] = {
345536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
346536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
347536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
348536438f1SOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
349536438f1SOswald Buddenhagen 	ADAT_CTLS("Dock "),
350536438f1SOswald Buddenhagen 	LR_CTLS("Mana DAC"),
351536438f1SOswald Buddenhagen };
352536438f1SOswald Buddenhagen 
353536438f1SOswald Buddenhagen static const unsigned short emu1616_output_dst[] = {
354536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
355536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
356536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
357536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_MDOCK_SPDIF),
358536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_MDOCK_ADAT),
359536438f1SOswald Buddenhagen 	EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT,
360536438f1SOswald Buddenhagen };
361536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dst) == ARRAY_SIZE(snd_emu1616_output_texts));
3621c02e366SCtirad Fertr 
3631fc710f0SOswald Buddenhagen static const unsigned short emu1616_output_dflt[] = {
3641fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3651fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
3661fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
3671fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3681fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
3691fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
3701fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3711fc710f0SOswald Buddenhagen };
3721fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dflt) == ARRAY_SIZE(emu1616_output_dst));
3731fc710f0SOswald Buddenhagen 
374*6f3609f8SOswald Buddenhagen /* 0404 rev1 & rev2 */
375*6f3609f8SOswald Buddenhagen 
376*6f3609f8SOswald Buddenhagen static const char * const snd_emu0404_output_texts[] = {
377*6f3609f8SOswald Buddenhagen 	LR_CTLS("DAC"),
378*6f3609f8SOswald Buddenhagen 	LR_CTLS("SPDIF"),
379*6f3609f8SOswald Buddenhagen };
380*6f3609f8SOswald Buddenhagen 
381*6f3609f8SOswald Buddenhagen static const unsigned short emu0404_output_dst[] = {
382*6f3609f8SOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
383*6f3609f8SOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
384*6f3609f8SOswald Buddenhagen };
385*6f3609f8SOswald Buddenhagen static_assert(ARRAY_SIZE(emu0404_output_dst) == ARRAY_SIZE(snd_emu0404_output_texts));
386*6f3609f8SOswald Buddenhagen 
387*6f3609f8SOswald Buddenhagen static const unsigned short emu0404_output_dflt[] = {
388*6f3609f8SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
389*6f3609f8SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
390*6f3609f8SOswald Buddenhagen };
391*6f3609f8SOswald Buddenhagen static_assert(ARRAY_SIZE(emu0404_output_dflt) == ARRAY_SIZE(emu0404_output_dst));
392*6f3609f8SOswald Buddenhagen 
39313d45709SPavel Hofman /*
394a869057cSOswald Buddenhagen  * Data destinations - FPGA outputs going to Alice2 (Audigy) for
39513d45709SPavel Hofman  *   capture (EMU32 + I2S links)
39613d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
39713d45709SPavel Hofman  */
398536438f1SOswald Buddenhagen 
399536438f1SOswald Buddenhagen static const char * const emu1010_input_texts[] = {
400536438f1SOswald Buddenhagen 	"DSP 0 Capture Enum",
401536438f1SOswald Buddenhagen 	"DSP 1 Capture Enum",
402536438f1SOswald Buddenhagen 	"DSP 2 Capture Enum",
403536438f1SOswald Buddenhagen 	"DSP 3 Capture Enum",
404536438f1SOswald Buddenhagen 	"DSP 4 Capture Enum",
405536438f1SOswald Buddenhagen 	"DSP 5 Capture Enum",
406536438f1SOswald Buddenhagen 	"DSP 6 Capture Enum",
407536438f1SOswald Buddenhagen 	"DSP 7 Capture Enum",
408536438f1SOswald Buddenhagen 	"DSP 8 Capture Enum",
409536438f1SOswald Buddenhagen 	"DSP 9 Capture Enum",
410536438f1SOswald Buddenhagen 	"DSP A Capture Enum",
411536438f1SOswald Buddenhagen 	"DSP B Capture Enum",
412536438f1SOswald Buddenhagen 	"DSP C Capture Enum",
413536438f1SOswald Buddenhagen 	"DSP D Capture Enum",
414536438f1SOswald Buddenhagen 	"DSP E Capture Enum",
415536438f1SOswald Buddenhagen 	"DSP F Capture Enum",
416536438f1SOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
417536438f1SOswald Buddenhagen 	"DSP 10 Capture Enum",
418536438f1SOswald Buddenhagen 	"DSP 11 Capture Enum",
419536438f1SOswald Buddenhagen 	"DSP 12 Capture Enum",
420536438f1SOswald Buddenhagen 	"DSP 13 Capture Enum",
421536438f1SOswald Buddenhagen 	"DSP 14 Capture Enum",
422536438f1SOswald Buddenhagen 	"DSP 15 Capture Enum",
423536438f1SOswald Buddenhagen };
424536438f1SOswald Buddenhagen 
4259b00a1e9SOswald Buddenhagen static const unsigned short emu1010_input_dst[] = {
4269f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_0,
4279f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_1,
4289f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_2,
4299f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_3,
4309f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_4,
4319f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_5,
4329f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_6,
4339f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_7,
4349f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_8,
4359f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_9,
4369f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_A,
4379f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_B,
4389f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_C,
4399f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_D,
4409f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_E,
4419f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_F,
442a869057cSOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
4439f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_LEFT,
4449f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_RIGHT,
4459f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_LEFT,
4469f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_RIGHT,
4479f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_LEFT,
4489f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_RIGHT,
4499f4bd5ddSJames Courtier-Dutton };
450536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts));
4519f4bd5ddSJames Courtier-Dutton 
4521fc710f0SOswald Buddenhagen static const unsigned short emu1010_input_dflt[] = {
4531fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_A1,
4541fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_B1,
4551fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
4561fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
4571fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
4581fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
4591fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
4601fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
4611fc710f0SOswald Buddenhagen 	/* Pavel Hofman - setting defaults for all capture channels.
4621fc710f0SOswald Buddenhagen 	 * Defaults only, users will set their own values anyways, let's
4631fc710f0SOswald Buddenhagen 	 * just copy/paste. */
4641fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_A1,
4651fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_B1,
4661fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
4671fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
4681fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
4691fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
4701fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
4711fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
4721fc710f0SOswald Buddenhagen 
4731fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
4741fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
4751fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
4761fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
4771fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC3_LEFT1,
4781fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC3_RIGHT1,
4791fc710f0SOswald Buddenhagen };
4801fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dflt) == ARRAY_SIZE(emu1010_input_dst));
4811fc710f0SOswald Buddenhagen 
482*6f3609f8SOswald Buddenhagen static const unsigned short emu0404_input_dflt[] = {
483*6f3609f8SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
484*6f3609f8SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
485*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
486*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
487*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
488*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
489*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
490*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
491*6f3609f8SOswald Buddenhagen 	EMU_SRC_HANA_SPDIF_LEFT1,
492*6f3609f8SOswald Buddenhagen 	EMU_SRC_HANA_SPDIF_RIGHT1,
493*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
494*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
495*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
496*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
497*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
498*6f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
499*6f3609f8SOswald Buddenhagen };
500*6f3609f8SOswald Buddenhagen 
501511cbe8fSOswald Buddenhagen struct snd_emu1010_routing_info {
502511cbe8fSOswald Buddenhagen 	const char * const *src_texts;
50397f1582eSOswald Buddenhagen 	const char * const *out_texts;
504511cbe8fSOswald Buddenhagen 	const unsigned short *src_regs;
505511cbe8fSOswald Buddenhagen 	const unsigned short *out_regs;
506511cbe8fSOswald Buddenhagen 	const unsigned short *in_regs;
5071fc710f0SOswald Buddenhagen 	const unsigned short *out_dflts;
5081fc710f0SOswald Buddenhagen 	const unsigned short *in_dflts;
509511cbe8fSOswald Buddenhagen 	unsigned n_srcs;
510511cbe8fSOswald Buddenhagen 	unsigned n_outs;
511511cbe8fSOswald Buddenhagen 	unsigned n_ins;
512511cbe8fSOswald Buddenhagen };
513511cbe8fSOswald Buddenhagen 
514511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info emu1010_routing_info[] = {
515511cbe8fSOswald Buddenhagen 	{
516*6f3609f8SOswald Buddenhagen 		/* rev1 1010 */
517511cbe8fSOswald Buddenhagen 		.src_regs = emu1010_src_regs,
518511cbe8fSOswald Buddenhagen 		.src_texts = emu1010_src_texts,
519511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1010_src_texts),
520511cbe8fSOswald Buddenhagen 
5211fc710f0SOswald Buddenhagen 		.out_dflts = emu1010_output_dflt,
522511cbe8fSOswald Buddenhagen 		.out_regs = emu1010_output_dst,
52397f1582eSOswald Buddenhagen 		.out_texts = emu1010_output_texts,
524511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1010_output_dst),
525511cbe8fSOswald Buddenhagen 
5261fc710f0SOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
527511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
528511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst),
529511cbe8fSOswald Buddenhagen 	},
530511cbe8fSOswald Buddenhagen 	{
531f69d705dSOswald Buddenhagen 		/* rev2 1010 */
532f69d705dSOswald Buddenhagen 		.src_regs = emu1010b_src_regs,
533f69d705dSOswald Buddenhagen 		.src_texts = emu1010b_src_texts,
534f69d705dSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1010b_src_texts),
535f69d705dSOswald Buddenhagen 
536f69d705dSOswald Buddenhagen 		.out_dflts = emu1010b_output_dflt,
537f69d705dSOswald Buddenhagen 		.out_regs = emu1010b_output_dst,
538f69d705dSOswald Buddenhagen 		.out_texts = snd_emu1010b_output_texts,
539f69d705dSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1010b_output_dst),
540f69d705dSOswald Buddenhagen 
541f69d705dSOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
542f69d705dSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
543f69d705dSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
544f69d705dSOswald Buddenhagen 	},
545f69d705dSOswald Buddenhagen 	{
546511cbe8fSOswald Buddenhagen 		/* 1616(m) cardbus */
547511cbe8fSOswald Buddenhagen 		.src_regs = emu1616_src_regs,
548511cbe8fSOswald Buddenhagen 		.src_texts = emu1616_src_texts,
549511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1616_src_texts),
550511cbe8fSOswald Buddenhagen 
5511fc710f0SOswald Buddenhagen 		.out_dflts = emu1616_output_dflt,
552511cbe8fSOswald Buddenhagen 		.out_regs = emu1616_output_dst,
55397f1582eSOswald Buddenhagen 		.out_texts = snd_emu1616_output_texts,
554511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1616_output_dst),
555511cbe8fSOswald Buddenhagen 
5561fc710f0SOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
557511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
558511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
559511cbe8fSOswald Buddenhagen 	},
560*6f3609f8SOswald Buddenhagen 	{
561*6f3609f8SOswald Buddenhagen 		/* 0404 */
562*6f3609f8SOswald Buddenhagen 		.src_regs = emu0404_src_regs,
563*6f3609f8SOswald Buddenhagen 		.src_texts = emu0404_src_texts,
564*6f3609f8SOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu0404_src_texts),
565*6f3609f8SOswald Buddenhagen 
566*6f3609f8SOswald Buddenhagen 		.out_dflts = emu0404_output_dflt,
567*6f3609f8SOswald Buddenhagen 		.out_regs = emu0404_output_dst,
568*6f3609f8SOswald Buddenhagen 		.out_texts = snd_emu0404_output_texts,
569*6f3609f8SOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu0404_output_dflt),
570*6f3609f8SOswald Buddenhagen 
571*6f3609f8SOswald Buddenhagen 		.in_dflts = emu0404_input_dflt,
572*6f3609f8SOswald Buddenhagen 		.in_regs = emu1010_input_dst,
573*6f3609f8SOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
574*6f3609f8SOswald Buddenhagen 	},
575511cbe8fSOswald Buddenhagen };
576511cbe8fSOswald Buddenhagen 
577511cbe8fSOswald Buddenhagen static unsigned emu1010_idx(struct snd_emu10k1 *emu)
578511cbe8fSOswald Buddenhagen {
579*6f3609f8SOswald Buddenhagen 	return emu->card_capabilities->emu_model - 1;
580511cbe8fSOswald Buddenhagen }
581511cbe8fSOswald Buddenhagen 
582511cbe8fSOswald Buddenhagen static void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu,
583511cbe8fSOswald Buddenhagen 					    int channel, int src)
584511cbe8fSOswald Buddenhagen {
585511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
586511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
587511cbe8fSOswald Buddenhagen 
588511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
589511cbe8fSOswald Buddenhagen 		emu_ri->out_regs[channel], emu_ri->src_regs[src]);
590511cbe8fSOswald Buddenhagen }
591511cbe8fSOswald Buddenhagen 
592511cbe8fSOswald Buddenhagen static void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu,
593511cbe8fSOswald Buddenhagen 					   int channel, int src)
594511cbe8fSOswald Buddenhagen {
595511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
596511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
597511cbe8fSOswald Buddenhagen 
598511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
599511cbe8fSOswald Buddenhagen 		emu_ri->in_regs[channel], emu_ri->src_regs[src]);
600511cbe8fSOswald Buddenhagen }
601511cbe8fSOswald Buddenhagen 
6021fc710f0SOswald Buddenhagen static void snd_emu1010_apply_sources(struct snd_emu10k1 *emu)
6031fc710f0SOswald Buddenhagen {
6041fc710f0SOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
6051fc710f0SOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
6061fc710f0SOswald Buddenhagen 
6071fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_outs; i++)
6081fc710f0SOswald Buddenhagen 		snd_emu1010_output_source_apply(
6091fc710f0SOswald Buddenhagen 			emu, i, emu->emu1010.output_source[i]);
6101fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_ins; i++)
6111fc710f0SOswald Buddenhagen 		snd_emu1010_input_source_apply(
6121fc710f0SOswald Buddenhagen 			emu, i, emu->emu1010.input_source[i]);
6131fc710f0SOswald Buddenhagen }
6141fc710f0SOswald Buddenhagen 
6151fc710f0SOswald Buddenhagen static u8 emu1010_map_source(const struct snd_emu1010_routing_info *emu_ri,
6161fc710f0SOswald Buddenhagen 			     unsigned val)
6171fc710f0SOswald Buddenhagen {
6181fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_srcs; i++)
6191fc710f0SOswald Buddenhagen 		if (val == emu_ri->src_regs[i])
6201fc710f0SOswald Buddenhagen 			return i;
6211fc710f0SOswald Buddenhagen 	return 0;
6221fc710f0SOswald Buddenhagen }
6231fc710f0SOswald Buddenhagen 
6241c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
6251c02e366SCtirad Fertr 						struct snd_ctl_elem_info *uinfo)
6269f4bd5ddSJames Courtier-Dutton {
6271c02e366SCtirad Fertr 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
628511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
629511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
6301c02e366SCtirad Fertr 
631511cbe8fSOswald Buddenhagen 	return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts);
6329f4bd5ddSJames Courtier-Dutton }
6339f4bd5ddSJames Courtier-Dutton 
6349f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
6359f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6369f4bd5ddSJames Courtier-Dutton {
6379f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
638511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
639511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
640511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
6419f4bd5ddSJames Courtier-Dutton 
642511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
64374415a36SJames Courtier-Dutton 		return -EINVAL;
6449f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
6459f4bd5ddSJames Courtier-Dutton 	return 0;
6469f4bd5ddSJames Courtier-Dutton }
6479f4bd5ddSJames Courtier-Dutton 
6489f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
6499f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6509f4bd5ddSJames Courtier-Dutton {
6519f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
652511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
653511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
654511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
655511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
656511cbe8fSOswald Buddenhagen 	int change;
6579f4bd5ddSJames Courtier-Dutton 
658511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
659aa299d01STakashi Iwai 		return -EINVAL;
660511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
66174415a36SJames Courtier-Dutton 		return -EINVAL;
662511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.output_source[channel] != val);
663511cbe8fSOswald Buddenhagen 	if (change) {
664aa299d01STakashi Iwai 		emu->emu1010.output_source[channel] = val;
665511cbe8fSOswald Buddenhagen 		snd_emu1010_output_source_apply(emu, channel, val);
666511cbe8fSOswald Buddenhagen 	}
667511cbe8fSOswald Buddenhagen 	return change;
6689f4bd5ddSJames Courtier-Dutton }
6699f4bd5ddSJames Courtier-Dutton 
670536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_output_source_ctl = {
671536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
672536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
673536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
674536438f1SOswald Buddenhagen 	.get = snd_emu1010_output_source_get,
675536438f1SOswald Buddenhagen 	.put = snd_emu1010_output_source_put
676536438f1SOswald Buddenhagen };
677536438f1SOswald Buddenhagen 
6789f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
6799f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6809f4bd5ddSJames Courtier-Dutton {
6819f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
682511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
683511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
684511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
6859f4bd5ddSJames Courtier-Dutton 
686511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
68774415a36SJames Courtier-Dutton 		return -EINVAL;
6889f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
6899f4bd5ddSJames Courtier-Dutton 	return 0;
6909f4bd5ddSJames Courtier-Dutton }
6919f4bd5ddSJames Courtier-Dutton 
6929f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
6939f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6949f4bd5ddSJames Courtier-Dutton {
6959f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
696511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
697511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
698511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
699511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
700511cbe8fSOswald Buddenhagen 	int change;
7019f4bd5ddSJames Courtier-Dutton 
702511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
703aa299d01STakashi Iwai 		return -EINVAL;
704511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
70574415a36SJames Courtier-Dutton 		return -EINVAL;
706511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.input_source[channel] != val);
707511cbe8fSOswald Buddenhagen 	if (change) {
708aa299d01STakashi Iwai 		emu->emu1010.input_source[channel] = val;
709511cbe8fSOswald Buddenhagen 		snd_emu1010_input_source_apply(emu, channel, val);
710511cbe8fSOswald Buddenhagen 	}
711511cbe8fSOswald Buddenhagen 	return change;
7129f4bd5ddSJames Courtier-Dutton }
7139f4bd5ddSJames Courtier-Dutton 
714536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_input_source_ctl = {
715536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
716536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
717536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
718536438f1SOswald Buddenhagen 	.get = snd_emu1010_input_source_get,
719536438f1SOswald Buddenhagen 	.put = snd_emu1010_input_source_put
7209f4bd5ddSJames Courtier-Dutton };
7219f4bd5ddSJames Courtier-Dutton 
72297f1582eSOswald Buddenhagen static int add_emu1010_source_mixers(struct snd_emu10k1 *emu)
72397f1582eSOswald Buddenhagen {
72497f1582eSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
72597f1582eSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
72697f1582eSOswald Buddenhagen 	int err;
72797f1582eSOswald Buddenhagen 
72897f1582eSOswald Buddenhagen 	err = add_ctls(emu, &emu1010_output_source_ctl,
72997f1582eSOswald Buddenhagen 		       emu_ri->out_texts, emu_ri->n_outs);
73097f1582eSOswald Buddenhagen 	if (err < 0)
73197f1582eSOswald Buddenhagen 		return err;
73297f1582eSOswald Buddenhagen 	err = add_ctls(emu, &emu1010_input_source_ctl,
73397f1582eSOswald Buddenhagen 		       emu1010_input_texts, emu_ri->n_ins);
73497f1582eSOswald Buddenhagen 	return err;
73597f1582eSOswald Buddenhagen }
73697f1582eSOswald Buddenhagen 
7371c02e366SCtirad Fertr 
738536438f1SOswald Buddenhagen static const char * const snd_emu1010_adc_pads[] = {
739f69d705dSOswald Buddenhagen 	"ADC1 14dB PAD 0202 Capture Switch",
740536438f1SOswald Buddenhagen 	"ADC1 14dB PAD Audio Dock Capture Switch",
741536438f1SOswald Buddenhagen 	"ADC2 14dB PAD Audio Dock Capture Switch",
742536438f1SOswald Buddenhagen 	"ADC3 14dB PAD Audio Dock Capture Switch",
7431c02e366SCtirad Fertr };
7441c02e366SCtirad Fertr 
745536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_adc_pad_regs[] = {
746f69d705dSOswald Buddenhagen 	EMU_HANA_0202_ADC_PAD1,
747536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD1,
748536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD2,
749536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD3,
7509148cc50SJames Courtier-Dutton };
7519148cc50SJames Courtier-Dutton 
752a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
7539148cc50SJames Courtier-Dutton 
7549148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
7559148cc50SJames Courtier-Dutton {
7569148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
757536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
758536438f1SOswald Buddenhagen 
7599148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
7609148cc50SJames Courtier-Dutton 	return 0;
7619148cc50SJames Courtier-Dutton }
7629148cc50SJames Courtier-Dutton 
7639148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
7649148cc50SJames Courtier-Dutton {
7659148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
766536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
7679148cc50SJames Courtier-Dutton 	unsigned int val, cache;
7689148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
7699148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
7709148cc50SJames Courtier-Dutton 	if (val == 1)
7719148cc50SJames Courtier-Dutton 		cache = cache | mask;
7729148cc50SJames Courtier-Dutton 	else
7739148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
7749148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
7759148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
7769148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
7779148cc50SJames Courtier-Dutton 	}
7789148cc50SJames Courtier-Dutton 
7799148cc50SJames Courtier-Dutton 	return 0;
7809148cc50SJames Courtier-Dutton }
7819148cc50SJames Courtier-Dutton 
782536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_adc_pads_ctl = {
783536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
784536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
785536438f1SOswald Buddenhagen 	.info = snd_emu1010_adc_pads_info,
786536438f1SOswald Buddenhagen 	.get = snd_emu1010_adc_pads_get,
787536438f1SOswald Buddenhagen 	.put = snd_emu1010_adc_pads_put
788536438f1SOswald Buddenhagen };
7899148cc50SJames Courtier-Dutton 
7909148cc50SJames Courtier-Dutton 
791536438f1SOswald Buddenhagen static const char * const snd_emu1010_dac_pads[] = {
792f69d705dSOswald Buddenhagen 	"DAC1 0202 14dB PAD Playback Switch",
793536438f1SOswald Buddenhagen 	"DAC1 Audio Dock 14dB PAD Playback Switch",
794536438f1SOswald Buddenhagen 	"DAC2 Audio Dock 14dB PAD Playback Switch",
795536438f1SOswald Buddenhagen 	"DAC3 Audio Dock 14dB PAD Playback Switch",
796536438f1SOswald Buddenhagen 	"DAC4 Audio Dock 14dB PAD Playback Switch",
797536438f1SOswald Buddenhagen };
7989148cc50SJames Courtier-Dutton 
799536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_dac_regs[] = {
800f69d705dSOswald Buddenhagen 	EMU_HANA_0202_DAC_PAD1,
801536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD1,
802536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD2,
803536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD3,
804536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD4,
8059148cc50SJames Courtier-Dutton };
8069148cc50SJames Courtier-Dutton 
807a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
8089148cc50SJames Courtier-Dutton 
8099148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
8109148cc50SJames Courtier-Dutton {
8119148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
812536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
813536438f1SOswald Buddenhagen 
8149148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
8159148cc50SJames Courtier-Dutton 	return 0;
8169148cc50SJames Courtier-Dutton }
8179148cc50SJames Courtier-Dutton 
8189148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
8199148cc50SJames Courtier-Dutton {
8209148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
821536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
8229148cc50SJames Courtier-Dutton 	unsigned int val, cache;
823cc766807SOswald Buddenhagen 	int change;
824cc766807SOswald Buddenhagen 
8259148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
8269148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
8279148cc50SJames Courtier-Dutton 	if (val == 1)
8289148cc50SJames Courtier-Dutton 		cache = cache | mask;
8299148cc50SJames Courtier-Dutton 	else
8309148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
831cc766807SOswald Buddenhagen 	change = (cache != emu->emu1010.dac_pads);
832cc766807SOswald Buddenhagen 	if (change) {
8339148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
8349148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
8359148cc50SJames Courtier-Dutton 	}
8369148cc50SJames Courtier-Dutton 
837cc766807SOswald Buddenhagen 	return change;
8389148cc50SJames Courtier-Dutton }
8399148cc50SJames Courtier-Dutton 
840536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_dac_pads_ctl = {
841536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
842536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
843536438f1SOswald Buddenhagen 	.info = snd_emu1010_dac_pads_info,
844536438f1SOswald Buddenhagen 	.get = snd_emu1010_dac_pads_get,
845536438f1SOswald Buddenhagen 	.put = snd_emu1010_dac_pads_put
8469f4bd5ddSJames Courtier-Dutton };
8479f4bd5ddSJames Courtier-Dutton 
848b0dbdaeaSJames Courtier-Dutton 
84997f1582eSOswald Buddenhagen struct snd_emu1010_pads_info {
85097f1582eSOswald Buddenhagen 	const char * const *adc_ctls, * const *dac_ctls;
85197f1582eSOswald Buddenhagen 	unsigned n_adc_ctls, n_dac_ctls;
85297f1582eSOswald Buddenhagen };
85397f1582eSOswald Buddenhagen 
85497f1582eSOswald Buddenhagen const struct snd_emu1010_pads_info emu1010_pads_info[] = {
85597f1582eSOswald Buddenhagen 	{
856*6f3609f8SOswald Buddenhagen 		/* rev1 1010 */
85797f1582eSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads,
85897f1582eSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads),
85997f1582eSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads,
86097f1582eSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads),
86197f1582eSOswald Buddenhagen 	},
86297f1582eSOswald Buddenhagen 	{
863f69d705dSOswald Buddenhagen 		/* rev2 1010 */
86497f1582eSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads,
865f69d705dSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 1,
86697f1582eSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads,
867f69d705dSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 1,
868f69d705dSOswald Buddenhagen 	},
869f69d705dSOswald Buddenhagen 	{
870f69d705dSOswald Buddenhagen 		/* 1616(m) cardbus */
871f69d705dSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads + 1,
872f69d705dSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 2,
873f69d705dSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads + 1,
87497f1582eSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 2,
87597f1582eSOswald Buddenhagen 	},
876*6f3609f8SOswald Buddenhagen 	{
877*6f3609f8SOswald Buddenhagen 		/* 0404 */
878*6f3609f8SOswald Buddenhagen 		.adc_ctls = NULL,
879*6f3609f8SOswald Buddenhagen 		.n_adc_ctls = 0,
880*6f3609f8SOswald Buddenhagen 		.dac_ctls = NULL,
881*6f3609f8SOswald Buddenhagen 		.n_dac_ctls = 0,
882*6f3609f8SOswald Buddenhagen 	},
88397f1582eSOswald Buddenhagen };
88497f1582eSOswald Buddenhagen 
88597f1582eSOswald Buddenhagen 
886b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
887b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
888b0dbdaeaSJames Courtier-Dutton {
8891541c66dSTakashi Iwai 	static const char * const texts[4] = {
890edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
891b0dbdaeaSJames Courtier-Dutton 	};
892b0dbdaeaSJames Courtier-Dutton 
8931541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 4, texts);
894b0dbdaeaSJames Courtier-Dutton }
895b0dbdaeaSJames Courtier-Dutton 
896b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
897b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
898b0dbdaeaSJames Courtier-Dutton {
899b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
900b0dbdaeaSJames Courtier-Dutton 
901b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
902b0dbdaeaSJames Courtier-Dutton 	return 0;
903b0dbdaeaSJames Courtier-Dutton }
904b0dbdaeaSJames Courtier-Dutton 
905b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
906b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
907b0dbdaeaSJames Courtier-Dutton {
908b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
909b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
910b0dbdaeaSJames Courtier-Dutton 	int change = 0;
911b0dbdaeaSJames Courtier-Dutton 
912b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
91374415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 4; */
91474415a36SJames Courtier-Dutton 	if (val >= 4)
91574415a36SJames Courtier-Dutton 		return -EINVAL;
916b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
917b0dbdaeaSJames Courtier-Dutton 	if (change) {
918b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
919b0dbdaeaSJames Courtier-Dutton 		switch (val) {
920b0dbdaeaSJames Courtier-Dutton 		case 0:
921b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
922b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
923b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
924a869057cSOswald Buddenhagen 			/* Default fallback clock 44.1kHz */
925b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
926b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
927b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
928b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
929b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
930b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
931b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
932b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
933e40a0b2eSJames Courtier-Dutton 			msleep(10);
934b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
935b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
936b0dbdaeaSJames Courtier-Dutton 			break;
937b0dbdaeaSJames Courtier-Dutton 		case 1:
938b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
939b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
940b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
941b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
942b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
943b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
944b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
945b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
946b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
947b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
948b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
949b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
950e40a0b2eSJames Courtier-Dutton 			msleep(10);
951b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
952b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
953b0dbdaeaSJames Courtier-Dutton 			break;
954edec7bbbSJames Courtier-Dutton 
955edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
956edec7bbbSJames Courtier-Dutton 			/* Mute all */
957edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
958edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
959edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
960edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
961edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
962edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
963edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
964edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
965edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
966edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
967edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
968edec7bbbSJames Courtier-Dutton 			msleep(10);
969edec7bbbSJames Courtier-Dutton 			/* Unmute all */
970edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
971edec7bbbSJames Courtier-Dutton 			break;
972edec7bbbSJames Courtier-Dutton 
973edec7bbbSJames Courtier-Dutton 		case 3:
974edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
975edec7bbbSJames Courtier-Dutton 			/* Mute all */
976edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
977edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
978edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
979edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
980edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
981edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
982edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
983edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
984edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
985edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
986edec7bbbSJames Courtier-Dutton 			msleep(10);
987edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
988edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
989edec7bbbSJames Courtier-Dutton 
990edec7bbbSJames Courtier-Dutton 
991edec7bbbSJames Courtier-Dutton 			break;
992b0dbdaeaSJames Courtier-Dutton 		}
993b0dbdaeaSJames Courtier-Dutton 	}
994b0dbdaeaSJames Courtier-Dutton         return change;
995b0dbdaeaSJames Courtier-Dutton }
996b0dbdaeaSJames Courtier-Dutton 
997f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock =
998b0dbdaeaSJames Courtier-Dutton {
999b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
1000b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
1001b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
1002b0dbdaeaSJames Courtier-Dutton 	.count =	1,
1003b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
1004b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
1005b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
1006b0dbdaeaSJames Courtier-Dutton };
1007b0dbdaeaSJames Courtier-Dutton 
100899dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
100999dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
101099dcab46SMichael Gernoth {
101199dcab46SMichael Gernoth 	static const char * const texts[2] = {
101299dcab46SMichael Gernoth 		"SPDIF", "ADAT"
101399dcab46SMichael Gernoth 	};
101499dcab46SMichael Gernoth 
101599dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
101699dcab46SMichael Gernoth }
101799dcab46SMichael Gernoth 
101899dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol,
101999dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
102099dcab46SMichael Gernoth {
102199dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
102299dcab46SMichael Gernoth 
102399dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out;
102499dcab46SMichael Gernoth 	return 0;
102599dcab46SMichael Gernoth }
102699dcab46SMichael Gernoth 
102799dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
102899dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
102999dcab46SMichael Gernoth {
103099dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
103199dcab46SMichael Gernoth 	unsigned int val;
103299dcab46SMichael Gernoth 	u32 tmp;
103399dcab46SMichael Gernoth 	int change = 0;
103499dcab46SMichael Gernoth 
103599dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
103699dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
103799dcab46SMichael Gernoth 	if (val >= 2)
103899dcab46SMichael Gernoth 		return -EINVAL;
103999dcab46SMichael Gernoth 	change = (emu->emu1010.optical_out != val);
104099dcab46SMichael Gernoth 	if (change) {
104199dcab46SMichael Gernoth 		emu->emu1010.optical_out = val;
10429d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
10439d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
104499dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
104599dcab46SMichael Gernoth 	}
104699dcab46SMichael Gernoth 	return change;
104799dcab46SMichael Gernoth }
104899dcab46SMichael Gernoth 
1049f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = {
105099dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
105199dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
105299dcab46SMichael Gernoth 	.name =         "Optical Output Mode",
105399dcab46SMichael Gernoth 	.count =	1,
105499dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_out_info,
105599dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_out_get,
105699dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_out_put
105799dcab46SMichael Gernoth };
105899dcab46SMichael Gernoth 
105999dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
106099dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
106199dcab46SMichael Gernoth {
106299dcab46SMichael Gernoth 	static const char * const texts[2] = {
106399dcab46SMichael Gernoth 		"SPDIF", "ADAT"
106499dcab46SMichael Gernoth 	};
106599dcab46SMichael Gernoth 
106699dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
106799dcab46SMichael Gernoth }
106899dcab46SMichael Gernoth 
106999dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
107099dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
107199dcab46SMichael Gernoth {
107299dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
107399dcab46SMichael Gernoth 
107499dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
107599dcab46SMichael Gernoth 	return 0;
107699dcab46SMichael Gernoth }
107799dcab46SMichael Gernoth 
107899dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
107999dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
108099dcab46SMichael Gernoth {
108199dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
108299dcab46SMichael Gernoth 	unsigned int val;
108399dcab46SMichael Gernoth 	u32 tmp;
108499dcab46SMichael Gernoth 	int change = 0;
108599dcab46SMichael Gernoth 
108699dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
108799dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
108899dcab46SMichael Gernoth 	if (val >= 2)
108999dcab46SMichael Gernoth 		return -EINVAL;
109099dcab46SMichael Gernoth 	change = (emu->emu1010.optical_in != val);
109199dcab46SMichael Gernoth 	if (change) {
109299dcab46SMichael Gernoth 		emu->emu1010.optical_in = val;
10939d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
10949d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
109599dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
109699dcab46SMichael Gernoth 	}
109799dcab46SMichael Gernoth 	return change;
109899dcab46SMichael Gernoth }
109999dcab46SMichael Gernoth 
1100f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = {
110199dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
110299dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
110399dcab46SMichael Gernoth 	.name =         "Optical Input Mode",
110499dcab46SMichael Gernoth 	.count =	1,
110599dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_in_info,
110699dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_in_get,
110799dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_in_put
110899dcab46SMichael Gernoth };
110999dcab46SMichael Gernoth 
1110184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
1111184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
1112184c1e2cSJames Courtier-Dutton {
1113184c1e2cSJames Courtier-Dutton #if 0
11141541c66dSTakashi Iwai 	static const char * const texts[4] = {
1115184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
1116184c1e2cSJames Courtier-Dutton 	};
1117184c1e2cSJames Courtier-Dutton #endif
11181541c66dSTakashi Iwai 	static const char * const texts[2] = {
1119184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
1120184c1e2cSJames Courtier-Dutton 	};
1121184c1e2cSJames Courtier-Dutton 
11221541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
1123184c1e2cSJames Courtier-Dutton }
1124184c1e2cSJames Courtier-Dutton 
1125184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
1126184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
1127184c1e2cSJames Courtier-Dutton {
1128184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1129184c1e2cSJames Courtier-Dutton 
1130184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
1131184c1e2cSJames Courtier-Dutton 	return 0;
1132184c1e2cSJames Courtier-Dutton }
1133184c1e2cSJames Courtier-Dutton 
1134184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
1135184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
1136184c1e2cSJames Courtier-Dutton {
1137184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1138184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
1139184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
1140a1c87c0bSOswald Buddenhagen 	u16 gpio;
1141184c1e2cSJames Courtier-Dutton 	int change = 0;
1142184c1e2cSJames Courtier-Dutton 	unsigned long flags;
1143184c1e2cSJames Courtier-Dutton 	u32 source;
1144184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
1145184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
1146184c1e2cSJames Courtier-Dutton 	 * for the particular source.
1147184c1e2cSJames Courtier-Dutton 	 */
114874415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
114974415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
115074415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
115174415a36SJames Courtier-Dutton 	if (source_id >= 2)
115274415a36SJames Courtier-Dutton 		return -EINVAL;
1153184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
1154184c1e2cSJames Courtier-Dutton 	if (change) {
1155184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
1156184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
1157a1c87c0bSOswald Buddenhagen 		gpio = inw(emu->port + A_IOCFG);
1158184c1e2cSJames Courtier-Dutton 		if (source_id==0)
1159a1c87c0bSOswald Buddenhagen 			outw(gpio | 0x4, emu->port + A_IOCFG);
1160184c1e2cSJames Courtier-Dutton 		else
1161a1c87c0bSOswald Buddenhagen 			outw(gpio & ~0x4, emu->port + A_IOCFG);
1162184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
1163184c1e2cSJames Courtier-Dutton 
1164184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
1165184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
1166184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
1167184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
1168184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
1169184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
1170184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
1171184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
1172184c1e2cSJames Courtier-Dutton 
1173184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
1174184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
1175184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
1176184c1e2cSJames Courtier-Dutton 	}
1177184c1e2cSJames Courtier-Dutton         return change;
1178184c1e2cSJames Courtier-Dutton }
1179184c1e2cSJames Courtier-Dutton 
1180f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source =
1181184c1e2cSJames Courtier-Dutton {
1182184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
1183184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
1184184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
1185184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
1186184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
1187184c1e2cSJames Courtier-Dutton };
1188184c1e2cSJames Courtier-Dutton 
1189184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
1190184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
1191184c1e2cSJames Courtier-Dutton {
1192184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1193184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
1194184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
1195184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
1196184c1e2cSJames Courtier-Dutton 	return 0;
1197184c1e2cSJames Courtier-Dutton }
1198184c1e2cSJames Courtier-Dutton 
1199184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
1200184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
1201184c1e2cSJames Courtier-Dutton {
1202184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
120374415a36SJames Courtier-Dutton 	unsigned int source_id;
1204184c1e2cSJames Courtier-Dutton 
1205184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
120674415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
120774415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
120874415a36SJames Courtier-Dutton 	if (source_id >= 2)
120974415a36SJames Courtier-Dutton 		return -EINVAL;
1210184c1e2cSJames Courtier-Dutton 
1211184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
1212184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
1213184c1e2cSJames Courtier-Dutton 	return 0;
1214184c1e2cSJames Courtier-Dutton }
1215184c1e2cSJames Courtier-Dutton 
1216184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
1217184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
1218184c1e2cSJames Courtier-Dutton {
1219184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1220184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
122114a29565SOswald Buddenhagen 	unsigned int ngain0, ngain1;
122274415a36SJames Courtier-Dutton 	unsigned int source_id;
1223184c1e2cSJames Courtier-Dutton 	int change = 0;
1224184c1e2cSJames Courtier-Dutton 
1225184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
122674415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
122774415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
122874415a36SJames Courtier-Dutton 	if (source_id >= 2)
122974415a36SJames Courtier-Dutton 		return -EINVAL;
123014a29565SOswald Buddenhagen 	ngain0 = ucontrol->value.integer.value[0];
123114a29565SOswald Buddenhagen 	ngain1 = ucontrol->value.integer.value[1];
123214a29565SOswald Buddenhagen 	if (ngain0 > 0xff)
123314a29565SOswald Buddenhagen 		return -EINVAL;
123414a29565SOswald Buddenhagen 	if (ngain1 > 0xff)
123514a29565SOswald Buddenhagen 		return -EINVAL;
1236184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
123714a29565SOswald Buddenhagen 	if (ogain != ngain0) {
1238184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
123914a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0);
124014a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][0] = ngain0;
1241184c1e2cSJames Courtier-Dutton 		change = 1;
1242184c1e2cSJames Courtier-Dutton 	}
1243184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
124414a29565SOswald Buddenhagen 	if (ogain != ngain1) {
1245184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
124614a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1);
124714a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][1] = ngain1;
1248184c1e2cSJames Courtier-Dutton 		change = 1;
1249184c1e2cSJames Courtier-Dutton 	}
1250184c1e2cSJames Courtier-Dutton 
1251184c1e2cSJames Courtier-Dutton 	return change;
1252184c1e2cSJames Courtier-Dutton }
1253184c1e2cSJames Courtier-Dutton 
1254536438f1SOswald Buddenhagen static const struct snd_kcontrol_new i2c_volume_ctl = {
1255536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1256536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1257536438f1SOswald Buddenhagen 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,
1258536438f1SOswald Buddenhagen 	.info = snd_audigy_i2c_volume_info,
1259536438f1SOswald Buddenhagen 	.get = snd_audigy_i2c_volume_get,
1260536438f1SOswald Buddenhagen 	.put = snd_audigy_i2c_volume_put,
1261536438f1SOswald Buddenhagen 	.tlv = { .p = snd_audigy_db_scale2 }
1262536438f1SOswald Buddenhagen };
1263184c1e2cSJames Courtier-Dutton 
1264536438f1SOswald Buddenhagen static const char * const snd_audigy_i2c_volume_ctls[] = {
1265536438f1SOswald Buddenhagen 	"Mic Capture Volume",
1266536438f1SOswald Buddenhagen 	"Line Capture Volume",
1267184c1e2cSJames Courtier-Dutton };
1268184c1e2cSJames Courtier-Dutton 
12690af68e5eSTakashi Iwai #if 0
1270eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12711da177e4SLinus Torvalds {
12721541c66dSTakashi Iwai 	static const char * const texts[] = {"44100", "48000", "96000"};
12731da177e4SLinus Torvalds 
12741541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 3, texts);
12751da177e4SLinus Torvalds }
12761da177e4SLinus Torvalds 
1277eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
1278eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
12791da177e4SLinus Torvalds {
1280eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12811da177e4SLinus Torvalds 	unsigned int tmp;
12821da177e4SLinus Torvalds 
12831da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
12841da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
12851da177e4SLinus Torvalds 	case A_SPDIF_44100:
12861da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
12871da177e4SLinus Torvalds 		break;
12881da177e4SLinus Torvalds 	case A_SPDIF_48000:
12891da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
12901da177e4SLinus Torvalds 		break;
12911da177e4SLinus Torvalds 	case A_SPDIF_96000:
12921da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
12931da177e4SLinus Torvalds 		break;
12941da177e4SLinus Torvalds 	default:
12951da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
12961da177e4SLinus Torvalds 	}
12971da177e4SLinus Torvalds 	return 0;
12981da177e4SLinus Torvalds }
12991da177e4SLinus Torvalds 
1300eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
1301eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
13021da177e4SLinus Torvalds {
1303eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13041da177e4SLinus Torvalds 	int change;
13051da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
13061da177e4SLinus Torvalds 	unsigned long flags;
13071da177e4SLinus Torvalds 
13081da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
13091da177e4SLinus Torvalds 	case 0:
13101da177e4SLinus Torvalds 		val = A_SPDIF_44100;
13111da177e4SLinus Torvalds 		break;
13121da177e4SLinus Torvalds 	case 1:
13131da177e4SLinus Torvalds 		val = A_SPDIF_48000;
13141da177e4SLinus Torvalds 		break;
13151da177e4SLinus Torvalds 	case 2:
13161da177e4SLinus Torvalds 		val = A_SPDIF_96000;
13171da177e4SLinus Torvalds 		break;
13181da177e4SLinus Torvalds 	default:
13191da177e4SLinus Torvalds 		val = A_SPDIF_48000;
13201da177e4SLinus Torvalds 		break;
13211da177e4SLinus Torvalds 	}
13221da177e4SLinus Torvalds 
13231da177e4SLinus Torvalds 
13241da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13251da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
13261da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
13271da177e4SLinus Torvalds 	tmp |= val;
132812bda107STakashi Iwai 	change = (tmp != reg);
132912bda107STakashi Iwai 	if (change)
13301da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
13311da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13321da177e4SLinus Torvalds 	return change;
13331da177e4SLinus Torvalds }
13341da177e4SLinus Torvalds 
1335b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate =
13361da177e4SLinus Torvalds {
13371da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
13381da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
13391da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
13401da177e4SLinus Torvalds 	.count =	1,
13411da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
13421da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
13431da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
13441da177e4SLinus Torvalds };
13450af68e5eSTakashi Iwai #endif
13461da177e4SLinus Torvalds 
1347eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1348eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
13491da177e4SLinus Torvalds {
1350eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13511da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
13521da177e4SLinus Torvalds 	int change;
13531da177e4SLinus Torvalds 	unsigned int val;
13541da177e4SLinus Torvalds 
135574415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
135674415a36SJames Courtier-Dutton 	if (idx >= 3)
135774415a36SJames Courtier-Dutton 		return -EINVAL;
13581da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
13591da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
13601da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
13611da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
13621da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
13631da177e4SLinus Torvalds 	if (change) {
13641da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
13651da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
13661da177e4SLinus Torvalds 	}
13671da177e4SLinus Torvalds 	return change;
13681da177e4SLinus Torvalds }
13691da177e4SLinus Torvalds 
1370f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
13711da177e4SLinus Torvalds {
13721da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
13735549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13741da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
13757583cb51STakashi Iwai 	.count =	3,
13761da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
13771da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
13781da177e4SLinus Torvalds };
13791da177e4SLinus Torvalds 
1380f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
13811da177e4SLinus Torvalds {
13825549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
13831da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
13847583cb51STakashi Iwai 	.count =	3,
13851da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
13861da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
13871da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
13881da177e4SLinus Torvalds };
13891da177e4SLinus Torvalds 
13901da177e4SLinus Torvalds 
1391eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
13921da177e4SLinus Torvalds {
13931da177e4SLinus Torvalds 	if (emu->audigy) {
13941da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
13951da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
13961da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
13971da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
13981da177e4SLinus Torvalds 	} else {
13991da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
14001da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
14011da177e4SLinus Torvalds 	}
14021da177e4SLinus Torvalds }
14031da177e4SLinus Torvalds 
1404eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
14051da177e4SLinus Torvalds {
14061da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
14071da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
14081da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
14091da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
14101da177e4SLinus Torvalds 	if (emu->audigy) {
141151d652f4SOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice,
141251d652f4SOswald Buddenhagen 				      snd_emu10k1_compose_audigy_sendamounts(volume));
14131da177e4SLinus Torvalds 	}
14141da177e4SLinus Torvalds }
14151da177e4SLinus Torvalds 
14161da177e4SLinus Torvalds /* PCM stream controls */
14171da177e4SLinus Torvalds 
1418eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14191da177e4SLinus Torvalds {
1420eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14211da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14221da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
14231da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14241da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
14251da177e4SLinus Torvalds 	return 0;
14261da177e4SLinus Torvalds }
14271da177e4SLinus Torvalds 
1428eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1429eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14301da177e4SLinus Torvalds {
1431eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1432eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1433eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14341da177e4SLinus Torvalds 	int voice, idx;
14351da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14361da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14371da177e4SLinus Torvalds 
14381da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
14391da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
14401da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
14411da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
14421da177e4SLinus Torvalds 	return 0;
14431da177e4SLinus Torvalds }
14441da177e4SLinus Torvalds 
1445eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1446eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14471da177e4SLinus Torvalds {
14481da177e4SLinus Torvalds 	unsigned long flags;
1449eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1450eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1451eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14521da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
14531da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14541da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14551da177e4SLinus Torvalds 
14561da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14571da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
14581da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
14591da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
14601da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
14611da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
14621da177e4SLinus Torvalds 				change = 1;
14631da177e4SLinus Torvalds 			}
14641da177e4SLinus Torvalds 		}
14651da177e4SLinus Torvalds 	if (change && mix->epcm) {
14661da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
14671da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
14681da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
14691da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
14701da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
14711da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
14721da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
14731da177e4SLinus Torvalds 					    &mix->send_routing[0][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_send_routing_control =
14811da177e4SLinus Torvalds {
14821da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
148367ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14841da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
14851da177e4SLinus Torvalds 	.count =	32,
14861da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
14871da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
14881da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
14891da177e4SLinus Torvalds };
14901da177e4SLinus Torvalds 
1491eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14921da177e4SLinus Torvalds {
1493eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14941da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14951da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
14961da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14971da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
14981da177e4SLinus Torvalds 	return 0;
14991da177e4SLinus Torvalds }
15001da177e4SLinus Torvalds 
1501eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1502eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
15031da177e4SLinus Torvalds {
1504eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1505eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1506eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15071da177e4SLinus Torvalds 	int idx;
15081da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15091da177e4SLinus Torvalds 
15101da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
15111da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
15121da177e4SLinus Torvalds 	return 0;
15131da177e4SLinus Torvalds }
15141da177e4SLinus Torvalds 
1515eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1516eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
15171da177e4SLinus Torvalds {
15181da177e4SLinus Torvalds 	unsigned long flags;
1519eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1520eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1521eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15221da177e4SLinus Torvalds 	int change = 0, idx, val;
15231da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15241da177e4SLinus Torvalds 
15251da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15261da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
15271da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
15281da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
15291da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
15301da177e4SLinus Torvalds 			change = 1;
15311da177e4SLinus Torvalds 		}
15321da177e4SLinus Torvalds 	}
15331da177e4SLinus Torvalds 	if (change && mix->epcm) {
15341da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
15351da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
15361da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
15371da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
15381da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
15391da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
15401da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
15411da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
15421da177e4SLinus Torvalds 		}
15431da177e4SLinus Torvalds 	}
15441da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15451da177e4SLinus Torvalds 	return change;
15461da177e4SLinus Torvalds }
15471da177e4SLinus Torvalds 
1548f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
15491da177e4SLinus Torvalds {
15501da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
155167ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15521da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
15531da177e4SLinus Torvalds 	.count =	32,
15541da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
15551da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
15561da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
15571da177e4SLinus Torvalds };
15581da177e4SLinus Torvalds 
1559eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15601da177e4SLinus Torvalds {
15611da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15621da177e4SLinus Torvalds 	uinfo->count = 3;
15631da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1564bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
15651da177e4SLinus Torvalds 	return 0;
15661da177e4SLinus Torvalds }
15671da177e4SLinus Torvalds 
1568eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1569eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
15701da177e4SLinus Torvalds {
1571eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1572eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1573eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15741da177e4SLinus Torvalds 	int idx;
15751da177e4SLinus Torvalds 
15761da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
1577bcdbd3b7SOswald Buddenhagen 		ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U;
15781da177e4SLinus Torvalds 	return 0;
15791da177e4SLinus Torvalds }
15801da177e4SLinus Torvalds 
1581eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1582eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
15831da177e4SLinus Torvalds {
15841da177e4SLinus Torvalds 	unsigned long flags;
1585eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1586eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1587eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15881da177e4SLinus Torvalds 	int change = 0, idx, val;
15891da177e4SLinus Torvalds 
15901da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15911da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
1592bcdbd3b7SOswald Buddenhagen 		unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff;
1593bcdbd3b7SOswald Buddenhagen 		val = uval * 0x8000U / 0xffffU;
15941da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
15951da177e4SLinus Torvalds 			mix->attn[idx] = val;
15961da177e4SLinus Torvalds 			change = 1;
15971da177e4SLinus Torvalds 		}
15981da177e4SLinus Torvalds 	}
15991da177e4SLinus Torvalds 	if (change && mix->epcm) {
16001da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
16011da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
16021da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
16031da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
16041da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
16051da177e4SLinus Torvalds 		}
16061da177e4SLinus Torvalds 	}
16071da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
16081da177e4SLinus Torvalds 	return change;
16091da177e4SLinus Torvalds }
16101da177e4SLinus Torvalds 
1611f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control =
16121da177e4SLinus Torvalds {
16131da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
161467ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
16151da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
16161da177e4SLinus Torvalds 	.count =	32,
16171da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
16181da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
16191da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
16201da177e4SLinus Torvalds };
16211da177e4SLinus Torvalds 
16221da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
16231da177e4SLinus Torvalds 
1624eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
16251da177e4SLinus Torvalds {
1626eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
16271da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
16281da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
16291da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
16301da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
16311da177e4SLinus Torvalds 	return 0;
16321da177e4SLinus Torvalds }
16331da177e4SLinus Torvalds 
1634eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1635eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
16361da177e4SLinus Torvalds {
1637eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1638eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1639eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
16401da177e4SLinus Torvalds 	int idx;
16411da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
16421da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
16431da177e4SLinus Torvalds 
16441da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
16451da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
16461da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
16471da177e4SLinus Torvalds 	return 0;
16481da177e4SLinus Torvalds }
16491da177e4SLinus Torvalds 
1650eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1651eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
16521da177e4SLinus Torvalds {
16531da177e4SLinus Torvalds 	unsigned long flags;
1654eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
16551da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1656eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
16571da177e4SLinus Torvalds 	int change = 0, idx, val;
16581da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
16591da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
16601da177e4SLinus Torvalds 
16611da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
16621da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
16631da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
16641da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
16651da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
16661da177e4SLinus Torvalds 			change = 1;
16671da177e4SLinus Torvalds 		}
16681da177e4SLinus Torvalds 	}
16691da177e4SLinus Torvalds 
16701da177e4SLinus Torvalds 	if (change && mix->epcm) {
16711da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
16721da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
16731da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
16741da177e4SLinus Torvalds 		}
16751da177e4SLinus Torvalds 	}
16761da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
16771da177e4SLinus Torvalds 	return change;
16781da177e4SLinus Torvalds }
16791da177e4SLinus Torvalds 
1680f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
16811da177e4SLinus Torvalds {
16821da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
16831da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
16841da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
16851da177e4SLinus Torvalds 	.count =	16,
16861da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
16871da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
16881da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
16891da177e4SLinus Torvalds };
16901da177e4SLinus Torvalds 
1691eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
16921da177e4SLinus Torvalds {
1693eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
16941da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
16951da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
16961da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
16971da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
16981da177e4SLinus Torvalds 	return 0;
16991da177e4SLinus Torvalds }
17001da177e4SLinus Torvalds 
1701eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1702eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
17031da177e4SLinus Torvalds {
1704eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1705eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1706eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
17071da177e4SLinus Torvalds 	int idx;
17081da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
17091da177e4SLinus Torvalds 
17101da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
17111da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
17121da177e4SLinus Torvalds 	return 0;
17131da177e4SLinus Torvalds }
17141da177e4SLinus Torvalds 
1715eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1716eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
17171da177e4SLinus Torvalds {
17181da177e4SLinus Torvalds 	unsigned long flags;
1719eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
17201da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1721eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
17221da177e4SLinus Torvalds 	int change = 0, idx, val;
17231da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
17241da177e4SLinus Torvalds 
17251da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
17261da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
17271da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
17281da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
17291da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
17301da177e4SLinus Torvalds 			change = 1;
17311da177e4SLinus Torvalds 		}
17321da177e4SLinus Torvalds 	}
17331da177e4SLinus Torvalds 	if (change && mix->epcm) {
17341da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
17351da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
17361da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
17371da177e4SLinus Torvalds 		}
17381da177e4SLinus Torvalds 	}
17391da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
17401da177e4SLinus Torvalds 	return change;
17411da177e4SLinus Torvalds }
17421da177e4SLinus Torvalds 
17431da177e4SLinus Torvalds 
1744f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
17451da177e4SLinus Torvalds {
17461da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
17471da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
17481da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
17491da177e4SLinus Torvalds 	.count =	16,
17501da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
17511da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
17521da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
17531da177e4SLinus Torvalds };
17541da177e4SLinus Torvalds 
1755eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
17561da177e4SLinus Torvalds {
17571da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
17581da177e4SLinus Torvalds 	uinfo->count = 1;
17591da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1760bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
17611da177e4SLinus Torvalds 	return 0;
17621da177e4SLinus Torvalds }
17631da177e4SLinus Torvalds 
1764eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1765eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
17661da177e4SLinus Torvalds {
1767eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1768eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1769eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
17701da177e4SLinus Torvalds 
1771bcdbd3b7SOswald Buddenhagen 	ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U;
17721da177e4SLinus Torvalds 	return 0;
17731da177e4SLinus Torvalds }
17741da177e4SLinus Torvalds 
1775eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1776eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
17771da177e4SLinus Torvalds {
17781da177e4SLinus Torvalds 	unsigned long flags;
1779eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
17801da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1781eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
17821da177e4SLinus Torvalds 	int change = 0, val;
1783bcdbd3b7SOswald Buddenhagen 	unsigned uval;
17841da177e4SLinus Torvalds 
17851da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1786bcdbd3b7SOswald Buddenhagen 	uval = ucontrol->value.integer.value[0] & 0x1ffff;
1787bcdbd3b7SOswald Buddenhagen 	val = uval * 0x8000U / 0xffffU;
17881da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
17891da177e4SLinus Torvalds 		mix->attn[0] = val;
17901da177e4SLinus Torvalds 		change = 1;
17911da177e4SLinus Torvalds 	}
17921da177e4SLinus Torvalds 	if (change && mix->epcm) {
17931da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
17941da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
17951da177e4SLinus Torvalds 		}
17961da177e4SLinus Torvalds 	}
17971da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
17981da177e4SLinus Torvalds 	return change;
17991da177e4SLinus Torvalds }
18001da177e4SLinus Torvalds 
1801f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
18021da177e4SLinus Torvalds {
18031da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
18041da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
18051da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
18061da177e4SLinus Torvalds 	.count =	16,
18071da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
18081da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
18091da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
18101da177e4SLinus Torvalds };
18111da177e4SLinus Torvalds 
1812a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
18131da177e4SLinus Torvalds 
1814eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1815eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
18161da177e4SLinus Torvalds {
1817eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
18181da177e4SLinus Torvalds 
18191da177e4SLinus Torvalds 	if (emu->audigy)
1820a1c87c0bSOswald Buddenhagen 		ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
18211da177e4SLinus Torvalds 	else
18221da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1823d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1824d2cd74b1STakashi Iwai 		ucontrol->value.integer.value[0] =
1825d2cd74b1STakashi Iwai 			!ucontrol->value.integer.value[0];
1826d2cd74b1STakashi Iwai 
18271da177e4SLinus Torvalds 	return 0;
18281da177e4SLinus Torvalds }
18291da177e4SLinus Torvalds 
1830eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1831eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
18321da177e4SLinus Torvalds {
18331da177e4SLinus Torvalds 	unsigned long flags;
1834eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1835d2cd74b1STakashi Iwai 	unsigned int reg, val, sw;
18361da177e4SLinus Torvalds 	int change = 0;
18371da177e4SLinus Torvalds 
1838d2cd74b1STakashi Iwai 	sw = ucontrol->value.integer.value[0];
1839d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1840d2cd74b1STakashi Iwai 		sw = !sw;
184150164f69SOswald Buddenhagen 	spin_lock_irqsave(&emu->emu_lock, flags);
1842184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1843184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1844184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
1845a1c87c0bSOswald Buddenhagen 		reg = inw(emu->port + A_IOCFG);
1846d2cd74b1STakashi Iwai 		val = sw ? A_IOCFG_GPOUT0 : 0;
18471da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
18481da177e4SLinus Torvalds 		if (change) {
18491da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
18501da177e4SLinus Torvalds 			reg |= val;
1851a1c87c0bSOswald Buddenhagen 			outw(reg | val, emu->port + A_IOCFG);
18521da177e4SLinus Torvalds 		}
18531da177e4SLinus Torvalds 	}
18541da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
1855d2cd74b1STakashi Iwai 	val = sw ? HCFG_GPOUT0 : 0;
18561da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
18571da177e4SLinus Torvalds 	if (change) {
18581da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
18591da177e4SLinus Torvalds 		reg |= val;
18601da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
18611da177e4SLinus Torvalds 	}
186250164f69SOswald Buddenhagen 	spin_unlock_irqrestore(&emu->emu_lock, flags);
18631da177e4SLinus Torvalds 	return change;
18641da177e4SLinus Torvalds }
18651da177e4SLinus Torvalds 
1866f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
18671da177e4SLinus Torvalds {
18681da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
18691da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
18701da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
18711da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
18721da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
18731da177e4SLinus Torvalds };
18741da177e4SLinus Torvalds 
1875f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif =
18761da177e4SLinus Torvalds {
18771da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
18781da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
18791da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
18801da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
18811da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
18821da177e4SLinus Torvalds };
18831da177e4SLinus Torvalds 
188416950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
188516950e09STakashi Iwai 
188616950e09STakashi Iwai #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
188716950e09STakashi Iwai 
188816950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
188916950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
189016950e09STakashi Iwai {
189116950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
189216950e09STakashi Iwai 	unsigned int val;
189316950e09STakashi Iwai 
189416950e09STakashi Iwai 	/* FIXME: better to use a cached version */
189516950e09STakashi Iwai 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
189616950e09STakashi Iwai 	ucontrol->value.integer.value[0] = !!val;
189716950e09STakashi Iwai 	return 0;
189816950e09STakashi Iwai }
189916950e09STakashi Iwai 
190016950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
190116950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
190216950e09STakashi Iwai {
190316950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
190416950e09STakashi Iwai 	unsigned int val;
190516950e09STakashi Iwai 
190616950e09STakashi Iwai 	if (ucontrol->value.integer.value[0])
190716950e09STakashi Iwai 		val = 0x0f0f;
190816950e09STakashi Iwai 	else
190916950e09STakashi Iwai 		val = 0;
191016950e09STakashi Iwai 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
191116950e09STakashi Iwai }
191216950e09STakashi Iwai 
1913f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost =
191416950e09STakashi Iwai {
191516950e09STakashi Iwai 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
19162a52feb1SMaciej S. Szmigiero 	.name =		"Mic Extra Boost",
191716950e09STakashi Iwai 	.info =		snd_audigy_capture_boost_info,
191816950e09STakashi Iwai 	.get =		snd_audigy_capture_boost_get,
191916950e09STakashi Iwai 	.put =		snd_audigy_capture_boost_put
192016950e09STakashi Iwai };
192116950e09STakashi Iwai 
192216950e09STakashi Iwai 
19231da177e4SLinus Torvalds /*
19241da177e4SLinus Torvalds  */
1925eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
19261da177e4SLinus Torvalds {
1927eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
19281da177e4SLinus Torvalds 	emu->ac97 = NULL;
19291da177e4SLinus Torvalds }
19301da177e4SLinus Torvalds 
19311da177e4SLinus Torvalds /*
19321da177e4SLinus Torvalds  */
1933eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
19341da177e4SLinus Torvalds {
1935eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
19361da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
19371da177e4SLinus Torvalds 	strcpy(id.name, name);
19381da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
19391da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
19401da177e4SLinus Torvalds }
19411da177e4SLinus Torvalds 
1942eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
19431da177e4SLinus Torvalds {
1944eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
19451da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
19461da177e4SLinus Torvalds 	strcpy(sid.name, name);
19471da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
19481da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
19491da177e4SLinus Torvalds }
19501da177e4SLinus Torvalds 
1951eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
19521da177e4SLinus Torvalds {
1953eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
19541da177e4SLinus Torvalds 	if (kctl) {
195536476b81SMaciej S. Szmigiero 		snd_ctl_rename(card, kctl, dst);
19561da177e4SLinus Torvalds 		return 0;
19571da177e4SLinus Torvalds 	}
19581da177e4SLinus Torvalds 	return -ENOENT;
19591da177e4SLinus Torvalds }
19601da177e4SLinus Torvalds 
1961e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
196267ed4161SClemens Ladisch 		      int pcm_device, int multi_device)
19631da177e4SLinus Torvalds {
1964155e3d3bSOswald Buddenhagen 	int err;
1965eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1966eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
19676fddce26STakashi Iwai 	const char * const *c;
19686fddce26STakashi Iwai 	static const char * const emu10k1_remove_ctls[] = {
19691da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
19701da177e4SLinus Torvalds 		"Master Mono Playback Switch",
19711da177e4SLinus Torvalds 		"Master Mono Playback Volume",
19721da177e4SLinus Torvalds 		"PCM Out Path & Mute",
19731da177e4SLinus Torvalds 		"Mono Output Select",
19741da177e4SLinus Torvalds 		"Surround Playback Switch",
19751da177e4SLinus Torvalds 		"Surround Playback Volume",
19761da177e4SLinus Torvalds 		"Center Playback Switch",
19771da177e4SLinus Torvalds 		"Center Playback Volume",
19781da177e4SLinus Torvalds 		"LFE Playback Switch",
19791da177e4SLinus Torvalds 		"LFE Playback Volume",
19801da177e4SLinus Torvalds 		NULL
19811da177e4SLinus Torvalds 	};
19826fddce26STakashi Iwai 	static const char * const emu10k1_rename_ctls[] = {
19831da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
19841da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
19851da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
19861da177e4SLinus Torvalds 		NULL
19871da177e4SLinus Torvalds 	};
19886fddce26STakashi Iwai 	static const char * const audigy_remove_ctls[] = {
19891da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
199021fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
199121fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
19921da177e4SLinus Torvalds 		"PCM Playback Switch",
19931da177e4SLinus Torvalds 		"PCM Playback Volume",
19941da177e4SLinus Torvalds 		"Master Playback Switch",
19951da177e4SLinus Torvalds 		"Master Playback Volume",
19961da177e4SLinus Torvalds 		"PCM Out Path & Mute",
19971da177e4SLinus Torvalds 		"Mono Output Select",
19981da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
19991da177e4SLinus Torvalds 		"Capture Source",
20001da177e4SLinus Torvalds 		"Capture Switch",
20011da177e4SLinus Torvalds 		"Capture Volume",
20021da177e4SLinus Torvalds 		"Mic Select",
2003274b2000SMaciej S. Szmigiero 		"Headphone Playback Switch",
2004274b2000SMaciej S. Szmigiero 		"Headphone Playback Volume",
2005274b2000SMaciej S. Szmigiero 		"3D Control - Center",
2006274b2000SMaciej S. Szmigiero 		"3D Control - Depth",
2007274b2000SMaciej S. Szmigiero 		"3D Control - Switch",
20081da177e4SLinus Torvalds 		"Video Playback Switch",
20091da177e4SLinus Torvalds 		"Video Playback Volume",
20101da177e4SLinus Torvalds 		"Mic Playback Switch",
20111da177e4SLinus Torvalds 		"Mic Playback Volume",
2012274b2000SMaciej S. Szmigiero 		"External Amplifier",
20131da177e4SLinus Torvalds 		NULL
20141da177e4SLinus Torvalds 	};
20156fddce26STakashi Iwai 	static const char * const audigy_rename_ctls[] = {
20161da177e4SLinus Torvalds 		/* use conventional names */
20171da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
20181da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
20191da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
20201da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
202152051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
202252051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
20231da177e4SLinus Torvalds 		NULL
20241da177e4SLinus Torvalds 	};
20256fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_i2c_adc[] = {
2026184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
2027184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
2028184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
2029184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
2030184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
2031eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
2032184c1e2cSJames Courtier-Dutton 		NULL
2033184c1e2cSJames Courtier-Dutton 	};
20346fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_i2c_adc[] = {
2035184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
2036184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
2037184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
2038184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
2039184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
2040eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
2041184c1e2cSJames Courtier-Dutton 		NULL
2042184c1e2cSJames Courtier-Dutton 	};
20436fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_1361t_adc[] = {
204421fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
204521fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
204621fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
204721fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
204821fdddeaSJames Courtier-Dutton 		"Capture Source",
204921fdddeaSJames Courtier-Dutton 		"Capture Switch",
205021fdddeaSJames Courtier-Dutton 		"Capture Volume",
205121fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
205221fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
205321fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
205421fdddeaSJames Courtier-Dutton 		"3D Control - Center",
205521fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
205621fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
205721fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
205821fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
205921fdddeaSJames Courtier-Dutton 		NULL
206021fdddeaSJames Courtier-Dutton 	};
20616fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_1361t_adc[] = {
206221fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
206321fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
206421fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
2065d355c82aSJaroslav Kysela 		"Beep Playback Switch", "Beep Capture Switch",
2066d355c82aSJaroslav Kysela 		"Beep Playback Volume", "Beep Capture Volume",
206721fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
206821fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
206921fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
207021fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
207121fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
207221fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
207321fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
207421fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
207521fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
207621fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
207721fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
207821fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
207952051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
208052051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
208121fdddeaSJames Courtier-Dutton 		NULL
208221fdddeaSJames Courtier-Dutton 	};
20831da177e4SLinus Torvalds 
20842b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
2085eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
2086eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
208751055da5STakashi Iwai 		static const struct snd_ac97_bus_ops ops = {
20881da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
20891da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
20901da177e4SLinus Torvalds 		};
20911da177e4SLinus Torvalds 
209212bda107STakashi Iwai 		err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus);
209312bda107STakashi Iwai 		if (err < 0)
20941da177e4SLinus Torvalds 			return err;
20951da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
20961da177e4SLinus Torvalds 
20971da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
20981da177e4SLinus Torvalds 		ac97.private_data = emu;
20991da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
21001da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
210112bda107STakashi Iwai 		err = snd_ac97_mixer(pbus, &ac97, &emu->ac97);
210212bda107STakashi Iwai 		if (err < 0) {
2103b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
21041da177e4SLinus Torvalds 				return err;
21056f002b02STakashi Iwai 			dev_info(emu->card->dev,
21066f002b02STakashi Iwai 				 "AC97 is optional on this board\n");
21076f002b02STakashi Iwai 			dev_info(emu->card->dev,
21086f002b02STakashi Iwai 				 "Proceeding without ac97 mixers...\n");
2109b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
2110b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
2111b1508693STakashi Iwai 		}
21121da177e4SLinus Torvalds 		if (emu->audigy) {
21131da177e4SLinus Torvalds 			/* set master volume to 0 dB */
21144d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
21151da177e4SLinus Torvalds 			/* set capture source to mic */
21164d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
211752051942SMaciej S. Szmigiero 			/* set mono output (TAD) to mic */
211852051942SMaciej S. Szmigiero 			snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE,
211952051942SMaciej S. Szmigiero 				0x0200, 0x0200);
212021fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
212121fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
212221fdddeaSJames Courtier-Dutton 			else
21231da177e4SLinus Torvalds 				c = audigy_remove_ctls;
21241da177e4SLinus Torvalds 		} else {
21251da177e4SLinus Torvalds 			/*
21261da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
21271da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
21281da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
21291da177e4SLinus Torvalds 			 */
21301da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
21311da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
21321da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
21332594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
2134b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Volume");
2135b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Switch");
21361da177e4SLinus Torvalds 			}
21371da177e4SLinus Torvalds 			/* remove unused AC97 controls */
21384d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
21394d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
21401da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
21411da177e4SLinus Torvalds 		}
21421da177e4SLinus Torvalds 		for (; *c; c++)
21431da177e4SLinus Torvalds 			remove_ctl(card, *c);
2144184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
2145184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
2146184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
2147184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
21481da177e4SLinus Torvalds 	} else {
2149f12aa40cSTakashi Iwai 	no_ac97:
21502b637da5SLee Revell 		if (emu->card_capabilities->ecard)
21511da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
21521da177e4SLinus Torvalds 		else if (emu->audigy)
21531da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
21541da177e4SLinus Torvalds 		else
21551da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
21561da177e4SLinus Torvalds 	}
21571da177e4SLinus Torvalds 
21581da177e4SLinus Torvalds 	if (emu->audigy)
215921fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
216021fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
2161184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
2162184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
216321fdddeaSJames Courtier-Dutton 		else
21641da177e4SLinus Torvalds 			c = audigy_rename_ctls;
21651da177e4SLinus Torvalds 	else
21661da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
21671da177e4SLinus Torvalds 	for (; *c; c += 2)
21681da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
216921fdddeaSJames Courtier-Dutton 
2170e217b960SRaymond Yau 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
2171e217b960SRaymond Yau 		remove_ctl(card, "Center Playback Volume");
2172e217b960SRaymond Yau 		remove_ctl(card, "LFE Playback Volume");
2173e217b960SRaymond Yau 		remove_ctl(card, "Wave Center Playback Volume");
2174e217b960SRaymond Yau 		remove_ctl(card, "Wave LFE Playback Volume");
2175e217b960SRaymond Yau 	}
2176e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
2177e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
2178e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
2179e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
2180e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
2181e3b9bc0eSJames Courtier-Dutton 	}
218212bda107STakashi Iwai 	kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu);
218312bda107STakashi Iwai 	if (!kctl)
21841da177e4SLinus Torvalds 		return -ENOMEM;
218567ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
218612bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
218712bda107STakashi Iwai 	if (err)
21881da177e4SLinus Torvalds 		return err;
218912bda107STakashi Iwai 	kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu);
219012bda107STakashi Iwai 	if (!kctl)
21911da177e4SLinus Torvalds 		return -ENOMEM;
219267ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
219312bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
219412bda107STakashi Iwai 	if (err)
21951da177e4SLinus Torvalds 		return err;
219612bda107STakashi Iwai 	kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu);
219712bda107STakashi Iwai 	if (!kctl)
21981da177e4SLinus Torvalds 		return -ENOMEM;
219967ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
220012bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
220112bda107STakashi Iwai 	if (err)
22021da177e4SLinus Torvalds 		return err;
22031da177e4SLinus Torvalds 
220412bda107STakashi Iwai 	kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu);
220512bda107STakashi Iwai 	if (!kctl)
22061da177e4SLinus Torvalds 		return -ENOMEM;
220767ed4161SClemens Ladisch 	kctl->id.device = multi_device;
220812bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
220912bda107STakashi Iwai 	if (err)
22101da177e4SLinus Torvalds 		return err;
22111da177e4SLinus Torvalds 
221212bda107STakashi Iwai 	kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu);
221312bda107STakashi Iwai 	if (!kctl)
22141da177e4SLinus Torvalds 		return -ENOMEM;
221567ed4161SClemens Ladisch 	kctl->id.device = multi_device;
221612bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
221712bda107STakashi Iwai 	if (err)
22181da177e4SLinus Torvalds 		return err;
22191da177e4SLinus Torvalds 
222012bda107STakashi Iwai 	kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu);
222112bda107STakashi Iwai 	if (!kctl)
22221da177e4SLinus Torvalds 		return -ENOMEM;
222367ed4161SClemens Ladisch 	kctl->id.device = multi_device;
222412bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
222512bda107STakashi Iwai 	if (err)
22261da177e4SLinus Torvalds 		return err;
22271da177e4SLinus Torvalds 
2228a8661af5SOswald Buddenhagen 	if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) {
22291da177e4SLinus Torvalds 		/* sb live! and audigy */
223012bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu);
223112bda107STakashi Iwai 		if (!kctl)
22321da177e4SLinus Torvalds 			return -ENOMEM;
22335549d549SClemens Ladisch 		if (!emu->audigy)
22345549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
223512bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
223612bda107STakashi Iwai 		if (err)
22371da177e4SLinus Torvalds 			return err;
223812bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu);
223912bda107STakashi Iwai 		if (!kctl)
22401da177e4SLinus Torvalds 			return -ENOMEM;
22415549d549SClemens Ladisch 		if (!emu->audigy)
22425549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
224312bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
224412bda107STakashi Iwai 		if (err)
22451da177e4SLinus Torvalds 			return err;
22461da177e4SLinus Torvalds 	}
22471da177e4SLinus Torvalds 
2248190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
224919b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
225019b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
225112bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu);
225212bda107STakashi Iwai 		if (!kctl)
22531da177e4SLinus Torvalds 			return -ENOMEM;
225412bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
225512bda107STakashi Iwai 		if (err)
22561da177e4SLinus Torvalds 			return err;
2257001f7589SJames Courtier-Dutton #if 0
225812bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu);
225912bda107STakashi Iwai 		if (!kctl)
22601da177e4SLinus Torvalds 			return -ENOMEM;
226112bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
226212bda107STakashi Iwai 		if (err)
22631da177e4SLinus Torvalds 			return err;
2264001f7589SJames Courtier-Dutton #endif
22652b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
22661da177e4SLinus Torvalds 		/* sb live! */
226712bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu);
226812bda107STakashi Iwai 		if (!kctl)
22691da177e4SLinus Torvalds 			return -ENOMEM;
227012bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
227112bda107STakashi Iwai 		if (err)
22721da177e4SLinus Torvalds 			return err;
22731da177e4SLinus Torvalds 	}
22742b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
227512bda107STakashi Iwai 		err = snd_p16v_mixer(emu);
227612bda107STakashi Iwai 		if (err)
22771da177e4SLinus Torvalds 			return err;
22781da177e4SLinus Torvalds 	}
22791da177e4SLinus Torvalds 
22801fc710f0SOswald Buddenhagen 	if (emu->card_capabilities->emu_model) {
22811fc710f0SOswald Buddenhagen 		unsigned i, emu_idx = emu1010_idx(emu);
22821fc710f0SOswald Buddenhagen 		const struct snd_emu1010_routing_info *emu_ri =
22831fc710f0SOswald Buddenhagen 			&emu1010_routing_info[emu_idx];
228497f1582eSOswald Buddenhagen 		const struct snd_emu1010_pads_info *emu_pi = &emu1010_pads_info[emu_idx];
22851fc710f0SOswald Buddenhagen 
22861fc710f0SOswald Buddenhagen 		for (i = 0; i < emu_ri->n_ins; i++)
22871fc710f0SOswald Buddenhagen 			emu->emu1010.input_source[i] =
22881fc710f0SOswald Buddenhagen 				emu1010_map_source(emu_ri, emu_ri->in_dflts[i]);
22891fc710f0SOswald Buddenhagen 		for (i = 0; i < emu_ri->n_outs; i++)
22901fc710f0SOswald Buddenhagen 			emu->emu1010.output_source[i] =
22911fc710f0SOswald Buddenhagen 				emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
22921fc710f0SOswald Buddenhagen 		snd_emu1010_apply_sources(emu);
22931fc710f0SOswald Buddenhagen 
22941c02e366SCtirad Fertr 		err = snd_ctl_add(card,
22951c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
22961c02e366SCtirad Fertr 		if (err < 0)
22971c02e366SCtirad Fertr 			return err;
229897f1582eSOswald Buddenhagen 
229997f1582eSOswald Buddenhagen 		err = add_ctls(emu, &emu1010_adc_pads_ctl,
230097f1582eSOswald Buddenhagen 			       emu_pi->adc_ctls, emu_pi->n_adc_ctls);
230197f1582eSOswald Buddenhagen 		if (err < 0)
230297f1582eSOswald Buddenhagen 			return err;
230397f1582eSOswald Buddenhagen 		err = add_ctls(emu, &emu1010_dac_pads_ctl,
230497f1582eSOswald Buddenhagen 			       emu_pi->dac_ctls, emu_pi->n_dac_ctls);
230597f1582eSOswald Buddenhagen 		if (err < 0)
230697f1582eSOswald Buddenhagen 			return err;
230797f1582eSOswald Buddenhagen 
2308*6f3609f8SOswald Buddenhagen 		if (!emu->card_capabilities->no_adat) {
230999dcab46SMichael Gernoth 			err = snd_ctl_add(card,
231099dcab46SMichael Gernoth 				snd_ctl_new1(&snd_emu1010_optical_out, emu));
231199dcab46SMichael Gernoth 			if (err < 0)
231299dcab46SMichael Gernoth 				return err;
231399dcab46SMichael Gernoth 			err = snd_ctl_add(card,
231499dcab46SMichael Gernoth 				snd_ctl_new1(&snd_emu1010_optical_in, emu));
231599dcab46SMichael Gernoth 			if (err < 0)
231699dcab46SMichael Gernoth 				return err;
2317*6f3609f8SOswald Buddenhagen 		}
23181c02e366SCtirad Fertr 
231997f1582eSOswald Buddenhagen 		err = add_emu1010_source_mixers(emu);
232099dcab46SMichael Gernoth 		if (err < 0)
232199dcab46SMichael Gernoth 			return err;
23229f4bd5ddSJames Courtier-Dutton 	}
23239f4bd5ddSJames Courtier-Dutton 
2324184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2325184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2326184c1e2cSJames Courtier-Dutton 		if (err < 0)
2327184c1e2cSJames Courtier-Dutton 			return err;
2328184c1e2cSJames Courtier-Dutton 
2329536438f1SOswald Buddenhagen 		err = add_ctls(emu, &i2c_volume_ctl,
2330536438f1SOswald Buddenhagen 			       snd_audigy_i2c_volume_ctls,
2331536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_audigy_i2c_volume_ctls));
2332184c1e2cSJames Courtier-Dutton 		if (err < 0)
2333184c1e2cSJames Courtier-Dutton 			return err;
2334184c1e2cSJames Courtier-Dutton 	}
2335184c1e2cSJames Courtier-Dutton 
233616950e09STakashi Iwai 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
233716950e09STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
233816950e09STakashi Iwai 						     emu));
233916950e09STakashi Iwai 		if (err < 0)
234016950e09STakashi Iwai 			return err;
234116950e09STakashi Iwai 	}
234216950e09STakashi Iwai 
23431da177e4SLinus Torvalds 	return 0;
23441da177e4SLinus Torvalds }
2345