xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision 60985241bfc61c6d6d85a78e0f29c866c546c7f5)
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 
1476f3609f8SOswald Buddenhagen /* 1010 rev1 */
1486f3609f8SOswald 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 
2356f3609f8SOswald Buddenhagen /* 0404 rev1 & rev2 */
2366f3609f8SOswald Buddenhagen 
2376f3609f8SOswald Buddenhagen #define EMU0404_COMMON_TEXTS \
2386f3609f8SOswald Buddenhagen 	"Silence", \
2396f3609f8SOswald Buddenhagen 	LR_TEXTS("ADC"), \
2406f3609f8SOswald Buddenhagen 	LR_TEXTS("SPDIF")
2416f3609f8SOswald Buddenhagen 
2426f3609f8SOswald Buddenhagen static const char * const emu0404_src_texts[] = {
2436f3609f8SOswald Buddenhagen 	EMU0404_COMMON_TEXTS,
2446f3609f8SOswald Buddenhagen 	DSP_TEXTS,
2456f3609f8SOswald Buddenhagen };
2466f3609f8SOswald Buddenhagen 
2476f3609f8SOswald Buddenhagen static const unsigned short emu0404_src_regs[] = {
2486f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
2496f3609f8SOswald Buddenhagen 	LR_REGS(EMU_SRC_HAMOA_ADC),
2506f3609f8SOswald Buddenhagen 	LR_REGS(EMU_SRC_HANA_SPDIF),
2516f3609f8SOswald Buddenhagen 	EMU32_SRC_REGS,
2526f3609f8SOswald Buddenhagen };
2536f3609f8SOswald Buddenhagen static_assert(ARRAY_SIZE(emu0404_src_regs) == ARRAY_SIZE(emu0404_src_texts));
2546f3609f8SOswald 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 
2636f3609f8SOswald Buddenhagen /* 1010 rev1 */
2646f3609f8SOswald 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 };
276216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_texts) <= NUM_OUTPUT_DESTS);
2779f4bd5ddSJames Courtier-Dutton 
278536438f1SOswald Buddenhagen static const unsigned short emu1010_output_dst[] = {
279536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
280536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
281536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
282536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC4),
283536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_PHONES),
284536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_SPDIF),
285536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
286536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
287536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_HANA_ADAT),
2881c02e366SCtirad Fertr };
289536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dst) == ARRAY_SIZE(emu1010_output_texts));
290536438f1SOswald Buddenhagen 
2911fc710f0SOswald Buddenhagen static const unsigned short emu1010_output_dflt[] = {
2921fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2931fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
2941fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
2951fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
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,
3001fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
3011fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
3021fc710f0SOswald Buddenhagen };
3031fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dflt) == ARRAY_SIZE(emu1010_output_dst));
3041fc710f0SOswald Buddenhagen 
305f69d705dSOswald Buddenhagen /* 1010 rev2 */
306f69d705dSOswald Buddenhagen 
307f69d705dSOswald Buddenhagen static const char * const snd_emu1010b_output_texts[] = {
308f69d705dSOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
309f69d705dSOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
310f69d705dSOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
311f69d705dSOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
312f69d705dSOswald Buddenhagen 	ADAT_CTLS("Dock "),
313f69d705dSOswald Buddenhagen 	LR_CTLS("0202 DAC"),
314f69d705dSOswald Buddenhagen 	LR_CTLS("1010 SPDIF"),
315f69d705dSOswald Buddenhagen 	ADAT_CTLS("1010 "),
316f69d705dSOswald Buddenhagen };
317216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(snd_emu1010b_output_texts) <= NUM_OUTPUT_DESTS);
318f69d705dSOswald Buddenhagen 
319f69d705dSOswald Buddenhagen static const unsigned short emu1010b_output_dst[] = {
320f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
321f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
322f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
323f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_MDOCK_SPDIF),
324f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_DST_MDOCK_ADAT),
325f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
326f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
327f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_DST_HANA_ADAT),
328f69d705dSOswald Buddenhagen };
329f69d705dSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010b_output_dst) == ARRAY_SIZE(snd_emu1010b_output_texts));
330f69d705dSOswald Buddenhagen 
331f69d705dSOswald Buddenhagen static const unsigned short emu1010b_output_dflt[] = {
332f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
333f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
334f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
335f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
336f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
337f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
338f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
339f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
340f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
341f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
342f69d705dSOswald Buddenhagen };
343f69d705dSOswald Buddenhagen 
344536438f1SOswald Buddenhagen /* 1616(m) cardbus */
345536438f1SOswald Buddenhagen 
346536438f1SOswald Buddenhagen static const char * const snd_emu1616_output_texts[] = {
347536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
348536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
349536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
350536438f1SOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
351536438f1SOswald Buddenhagen 	ADAT_CTLS("Dock "),
352536438f1SOswald Buddenhagen 	LR_CTLS("Mana DAC"),
353536438f1SOswald Buddenhagen };
354216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(snd_emu1616_output_texts) <= NUM_OUTPUT_DESTS);
355536438f1SOswald Buddenhagen 
356536438f1SOswald Buddenhagen static const unsigned short emu1616_output_dst[] = {
357536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
358536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
359536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
360536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_MDOCK_SPDIF),
361536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_MDOCK_ADAT),
362536438f1SOswald Buddenhagen 	EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT,
363536438f1SOswald Buddenhagen };
364536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dst) == ARRAY_SIZE(snd_emu1616_output_texts));
3651c02e366SCtirad Fertr 
3661fc710f0SOswald Buddenhagen static const unsigned short emu1616_output_dflt[] = {
3671fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3681fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
3691fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
3701fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3711fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
3721fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
3731fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3741fc710f0SOswald Buddenhagen };
3751fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dflt) == ARRAY_SIZE(emu1616_output_dst));
3761fc710f0SOswald Buddenhagen 
3776f3609f8SOswald Buddenhagen /* 0404 rev1 & rev2 */
3786f3609f8SOswald Buddenhagen 
3796f3609f8SOswald Buddenhagen static const char * const snd_emu0404_output_texts[] = {
3806f3609f8SOswald Buddenhagen 	LR_CTLS("DAC"),
3816f3609f8SOswald Buddenhagen 	LR_CTLS("SPDIF"),
3826f3609f8SOswald Buddenhagen };
383216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(snd_emu0404_output_texts) <= NUM_OUTPUT_DESTS);
3846f3609f8SOswald Buddenhagen 
3856f3609f8SOswald Buddenhagen static const unsigned short emu0404_output_dst[] = {
3866f3609f8SOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
3876f3609f8SOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
3886f3609f8SOswald Buddenhagen };
3896f3609f8SOswald Buddenhagen static_assert(ARRAY_SIZE(emu0404_output_dst) == ARRAY_SIZE(snd_emu0404_output_texts));
3906f3609f8SOswald Buddenhagen 
3916f3609f8SOswald Buddenhagen static const unsigned short emu0404_output_dflt[] = {
3926f3609f8SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3936f3609f8SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3946f3609f8SOswald Buddenhagen };
3956f3609f8SOswald Buddenhagen static_assert(ARRAY_SIZE(emu0404_output_dflt) == ARRAY_SIZE(emu0404_output_dst));
3966f3609f8SOswald Buddenhagen 
39713d45709SPavel Hofman /*
398a869057cSOswald Buddenhagen  * Data destinations - FPGA outputs going to Alice2 (Audigy) for
39913d45709SPavel Hofman  *   capture (EMU32 + I2S links)
40013d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
40113d45709SPavel Hofman  */
402536438f1SOswald Buddenhagen 
403536438f1SOswald Buddenhagen static const char * const emu1010_input_texts[] = {
404536438f1SOswald Buddenhagen 	"DSP 0 Capture Enum",
405536438f1SOswald Buddenhagen 	"DSP 1 Capture Enum",
406536438f1SOswald Buddenhagen 	"DSP 2 Capture Enum",
407536438f1SOswald Buddenhagen 	"DSP 3 Capture Enum",
408536438f1SOswald Buddenhagen 	"DSP 4 Capture Enum",
409536438f1SOswald Buddenhagen 	"DSP 5 Capture Enum",
410536438f1SOswald Buddenhagen 	"DSP 6 Capture Enum",
411536438f1SOswald Buddenhagen 	"DSP 7 Capture Enum",
412536438f1SOswald Buddenhagen 	"DSP 8 Capture Enum",
413536438f1SOswald Buddenhagen 	"DSP 9 Capture Enum",
414536438f1SOswald Buddenhagen 	"DSP A Capture Enum",
415536438f1SOswald Buddenhagen 	"DSP B Capture Enum",
416536438f1SOswald Buddenhagen 	"DSP C Capture Enum",
417536438f1SOswald Buddenhagen 	"DSP D Capture Enum",
418536438f1SOswald Buddenhagen 	"DSP E Capture Enum",
419536438f1SOswald Buddenhagen 	"DSP F Capture Enum",
420536438f1SOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
421536438f1SOswald Buddenhagen 	"DSP 10 Capture Enum",
422536438f1SOswald Buddenhagen 	"DSP 11 Capture Enum",
423536438f1SOswald Buddenhagen 	"DSP 12 Capture Enum",
424536438f1SOswald Buddenhagen 	"DSP 13 Capture Enum",
425536438f1SOswald Buddenhagen 	"DSP 14 Capture Enum",
426536438f1SOswald Buddenhagen 	"DSP 15 Capture Enum",
427536438f1SOswald Buddenhagen };
428216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_texts) <= NUM_INPUT_DESTS);
429536438f1SOswald Buddenhagen 
4309b00a1e9SOswald Buddenhagen static const unsigned short emu1010_input_dst[] = {
4319f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_0,
4329f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_1,
4339f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_2,
4349f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_3,
4359f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_4,
4369f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_5,
4379f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_6,
4389f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_7,
4399f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_8,
4409f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_9,
4419f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_A,
4429f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_B,
4439f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_C,
4449f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_D,
4459f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_E,
4469f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_F,
447a869057cSOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
4489f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_LEFT,
4499f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_RIGHT,
4509f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_LEFT,
4519f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_RIGHT,
4529f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_LEFT,
4539f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_RIGHT,
4549f4bd5ddSJames Courtier-Dutton };
455536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts));
4569f4bd5ddSJames Courtier-Dutton 
4571fc710f0SOswald Buddenhagen static const unsigned short emu1010_input_dflt[] = {
4581fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_A1,
4591fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_B1,
4601fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
4611fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
4621fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
4631fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
4641fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
4651fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
4661fc710f0SOswald Buddenhagen 	/* Pavel Hofman - setting defaults for all capture channels.
4671fc710f0SOswald Buddenhagen 	 * Defaults only, users will set their own values anyways, let's
4681fc710f0SOswald Buddenhagen 	 * just copy/paste. */
4691fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_A1,
4701fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_B1,
4711fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
4721fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
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 
4781fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
4791fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
4801fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
4811fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
4821fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC3_LEFT1,
4831fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC3_RIGHT1,
4841fc710f0SOswald Buddenhagen };
4851fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dflt) == ARRAY_SIZE(emu1010_input_dst));
4861fc710f0SOswald Buddenhagen 
4876f3609f8SOswald Buddenhagen static const unsigned short emu0404_input_dflt[] = {
4886f3609f8SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
4896f3609f8SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
4906f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4916f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4926f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4936f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4946f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4956f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4966f3609f8SOswald Buddenhagen 	EMU_SRC_HANA_SPDIF_LEFT1,
4976f3609f8SOswald Buddenhagen 	EMU_SRC_HANA_SPDIF_RIGHT1,
4986f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4996f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
5006f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
5016f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
5026f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
5036f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
5046f3609f8SOswald Buddenhagen };
5056f3609f8SOswald Buddenhagen 
506511cbe8fSOswald Buddenhagen struct snd_emu1010_routing_info {
507511cbe8fSOswald Buddenhagen 	const char * const *src_texts;
50897f1582eSOswald Buddenhagen 	const char * const *out_texts;
509511cbe8fSOswald Buddenhagen 	const unsigned short *src_regs;
510511cbe8fSOswald Buddenhagen 	const unsigned short *out_regs;
511511cbe8fSOswald Buddenhagen 	const unsigned short *in_regs;
5121fc710f0SOswald Buddenhagen 	const unsigned short *out_dflts;
5131fc710f0SOswald Buddenhagen 	const unsigned short *in_dflts;
514511cbe8fSOswald Buddenhagen 	unsigned n_srcs;
515511cbe8fSOswald Buddenhagen 	unsigned n_outs;
516511cbe8fSOswald Buddenhagen 	unsigned n_ins;
517511cbe8fSOswald Buddenhagen };
518511cbe8fSOswald Buddenhagen 
519816967d5STom Rix static const struct snd_emu1010_routing_info emu1010_routing_info[] = {
520511cbe8fSOswald Buddenhagen 	{
5216f3609f8SOswald Buddenhagen 		/* rev1 1010 */
522511cbe8fSOswald Buddenhagen 		.src_regs = emu1010_src_regs,
523511cbe8fSOswald Buddenhagen 		.src_texts = emu1010_src_texts,
524511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1010_src_texts),
525511cbe8fSOswald Buddenhagen 
5261fc710f0SOswald Buddenhagen 		.out_dflts = emu1010_output_dflt,
527511cbe8fSOswald Buddenhagen 		.out_regs = emu1010_output_dst,
52897f1582eSOswald Buddenhagen 		.out_texts = emu1010_output_texts,
529511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1010_output_dst),
530511cbe8fSOswald Buddenhagen 
5311fc710f0SOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
532511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
533511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst),
534511cbe8fSOswald Buddenhagen 	},
535511cbe8fSOswald Buddenhagen 	{
536f69d705dSOswald Buddenhagen 		/* rev2 1010 */
537f69d705dSOswald Buddenhagen 		.src_regs = emu1010b_src_regs,
538f69d705dSOswald Buddenhagen 		.src_texts = emu1010b_src_texts,
539f69d705dSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1010b_src_texts),
540f69d705dSOswald Buddenhagen 
541f69d705dSOswald Buddenhagen 		.out_dflts = emu1010b_output_dflt,
542f69d705dSOswald Buddenhagen 		.out_regs = emu1010b_output_dst,
543f69d705dSOswald Buddenhagen 		.out_texts = snd_emu1010b_output_texts,
544f69d705dSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1010b_output_dst),
545f69d705dSOswald Buddenhagen 
546f69d705dSOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
547f69d705dSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
548f69d705dSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
549f69d705dSOswald Buddenhagen 	},
550f69d705dSOswald Buddenhagen 	{
551511cbe8fSOswald Buddenhagen 		/* 1616(m) cardbus */
552511cbe8fSOswald Buddenhagen 		.src_regs = emu1616_src_regs,
553511cbe8fSOswald Buddenhagen 		.src_texts = emu1616_src_texts,
554511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1616_src_texts),
555511cbe8fSOswald Buddenhagen 
5561fc710f0SOswald Buddenhagen 		.out_dflts = emu1616_output_dflt,
557511cbe8fSOswald Buddenhagen 		.out_regs = emu1616_output_dst,
55897f1582eSOswald Buddenhagen 		.out_texts = snd_emu1616_output_texts,
559511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1616_output_dst),
560511cbe8fSOswald Buddenhagen 
5611fc710f0SOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
562511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
563511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
564511cbe8fSOswald Buddenhagen 	},
5656f3609f8SOswald Buddenhagen 	{
5666f3609f8SOswald Buddenhagen 		/* 0404 */
5676f3609f8SOswald Buddenhagen 		.src_regs = emu0404_src_regs,
5686f3609f8SOswald Buddenhagen 		.src_texts = emu0404_src_texts,
5696f3609f8SOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu0404_src_texts),
5706f3609f8SOswald Buddenhagen 
5716f3609f8SOswald Buddenhagen 		.out_dflts = emu0404_output_dflt,
5726f3609f8SOswald Buddenhagen 		.out_regs = emu0404_output_dst,
5736f3609f8SOswald Buddenhagen 		.out_texts = snd_emu0404_output_texts,
5746f3609f8SOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu0404_output_dflt),
5756f3609f8SOswald Buddenhagen 
5766f3609f8SOswald Buddenhagen 		.in_dflts = emu0404_input_dflt,
5776f3609f8SOswald Buddenhagen 		.in_regs = emu1010_input_dst,
5786f3609f8SOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
5796f3609f8SOswald Buddenhagen 	},
580511cbe8fSOswald Buddenhagen };
581511cbe8fSOswald Buddenhagen 
582511cbe8fSOswald Buddenhagen static unsigned emu1010_idx(struct snd_emu10k1 *emu)
583511cbe8fSOswald Buddenhagen {
5846f3609f8SOswald Buddenhagen 	return emu->card_capabilities->emu_model - 1;
585511cbe8fSOswald Buddenhagen }
586511cbe8fSOswald Buddenhagen 
587511cbe8fSOswald Buddenhagen static void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu,
588511cbe8fSOswald Buddenhagen 					    int channel, int src)
589511cbe8fSOswald Buddenhagen {
590511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
591511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
592511cbe8fSOswald Buddenhagen 
593511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
594511cbe8fSOswald Buddenhagen 		emu_ri->out_regs[channel], emu_ri->src_regs[src]);
595511cbe8fSOswald Buddenhagen }
596511cbe8fSOswald Buddenhagen 
597511cbe8fSOswald Buddenhagen static void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu,
598511cbe8fSOswald Buddenhagen 					   int channel, int src)
599511cbe8fSOswald Buddenhagen {
600511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
601511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
602511cbe8fSOswald Buddenhagen 
603511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
604511cbe8fSOswald Buddenhagen 		emu_ri->in_regs[channel], emu_ri->src_regs[src]);
605511cbe8fSOswald Buddenhagen }
606511cbe8fSOswald Buddenhagen 
6071fc710f0SOswald Buddenhagen static void snd_emu1010_apply_sources(struct snd_emu10k1 *emu)
6081fc710f0SOswald Buddenhagen {
6091fc710f0SOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
6101fc710f0SOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
6111fc710f0SOswald Buddenhagen 
6121fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_outs; i++)
6131fc710f0SOswald Buddenhagen 		snd_emu1010_output_source_apply(
6141fc710f0SOswald Buddenhagen 			emu, i, emu->emu1010.output_source[i]);
6151fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_ins; i++)
6161fc710f0SOswald Buddenhagen 		snd_emu1010_input_source_apply(
6171fc710f0SOswald Buddenhagen 			emu, i, emu->emu1010.input_source[i]);
6181fc710f0SOswald Buddenhagen }
6191fc710f0SOswald Buddenhagen 
6201fc710f0SOswald Buddenhagen static u8 emu1010_map_source(const struct snd_emu1010_routing_info *emu_ri,
6211fc710f0SOswald Buddenhagen 			     unsigned val)
6221fc710f0SOswald Buddenhagen {
6231fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_srcs; i++)
6241fc710f0SOswald Buddenhagen 		if (val == emu_ri->src_regs[i])
6251fc710f0SOswald Buddenhagen 			return i;
6261fc710f0SOswald Buddenhagen 	return 0;
6271fc710f0SOswald Buddenhagen }
6281fc710f0SOswald Buddenhagen 
6291c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
6301c02e366SCtirad Fertr 						struct snd_ctl_elem_info *uinfo)
6319f4bd5ddSJames Courtier-Dutton {
6321c02e366SCtirad Fertr 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
633511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
634511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
6351c02e366SCtirad Fertr 
636511cbe8fSOswald Buddenhagen 	return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts);
6379f4bd5ddSJames Courtier-Dutton }
6389f4bd5ddSJames Courtier-Dutton 
6399f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
6409f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6419f4bd5ddSJames Courtier-Dutton {
6429f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
643511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
644511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
645511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
6469f4bd5ddSJames Courtier-Dutton 
647511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
64874415a36SJames Courtier-Dutton 		return -EINVAL;
6499f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
6509f4bd5ddSJames Courtier-Dutton 	return 0;
6519f4bd5ddSJames Courtier-Dutton }
6529f4bd5ddSJames Courtier-Dutton 
6539f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
6549f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6559f4bd5ddSJames Courtier-Dutton {
6569f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
657511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
658511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
659511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
660511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
661511cbe8fSOswald Buddenhagen 	int change;
6629f4bd5ddSJames Courtier-Dutton 
663511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
664aa299d01STakashi Iwai 		return -EINVAL;
665511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
66674415a36SJames Courtier-Dutton 		return -EINVAL;
667511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.output_source[channel] != val);
668511cbe8fSOswald Buddenhagen 	if (change) {
669aa299d01STakashi Iwai 		emu->emu1010.output_source[channel] = val;
670511cbe8fSOswald Buddenhagen 		snd_emu1010_output_source_apply(emu, channel, val);
671511cbe8fSOswald Buddenhagen 	}
672511cbe8fSOswald Buddenhagen 	return change;
6739f4bd5ddSJames Courtier-Dutton }
6749f4bd5ddSJames Courtier-Dutton 
675536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_output_source_ctl = {
676536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
677536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
678536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
679536438f1SOswald Buddenhagen 	.get = snd_emu1010_output_source_get,
680536438f1SOswald Buddenhagen 	.put = snd_emu1010_output_source_put
681536438f1SOswald Buddenhagen };
682536438f1SOswald Buddenhagen 
6839f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
6849f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6859f4bd5ddSJames Courtier-Dutton {
6869f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
687511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
688511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
689511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
6909f4bd5ddSJames Courtier-Dutton 
691511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
69274415a36SJames Courtier-Dutton 		return -EINVAL;
6939f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
6949f4bd5ddSJames Courtier-Dutton 	return 0;
6959f4bd5ddSJames Courtier-Dutton }
6969f4bd5ddSJames Courtier-Dutton 
6979f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
6989f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6999f4bd5ddSJames Courtier-Dutton {
7009f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
701511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
702511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
703511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
704511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
705511cbe8fSOswald Buddenhagen 	int change;
7069f4bd5ddSJames Courtier-Dutton 
707511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
708aa299d01STakashi Iwai 		return -EINVAL;
709511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
71074415a36SJames Courtier-Dutton 		return -EINVAL;
711511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.input_source[channel] != val);
712511cbe8fSOswald Buddenhagen 	if (change) {
713aa299d01STakashi Iwai 		emu->emu1010.input_source[channel] = val;
714511cbe8fSOswald Buddenhagen 		snd_emu1010_input_source_apply(emu, channel, val);
715511cbe8fSOswald Buddenhagen 	}
716511cbe8fSOswald Buddenhagen 	return change;
7179f4bd5ddSJames Courtier-Dutton }
7189f4bd5ddSJames Courtier-Dutton 
719536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_input_source_ctl = {
720536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
721536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
722536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
723536438f1SOswald Buddenhagen 	.get = snd_emu1010_input_source_get,
724536438f1SOswald Buddenhagen 	.put = snd_emu1010_input_source_put
7259f4bd5ddSJames Courtier-Dutton };
7269f4bd5ddSJames Courtier-Dutton 
72797f1582eSOswald Buddenhagen static int add_emu1010_source_mixers(struct snd_emu10k1 *emu)
72897f1582eSOswald Buddenhagen {
72997f1582eSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
73097f1582eSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
73197f1582eSOswald Buddenhagen 	int err;
73297f1582eSOswald Buddenhagen 
73397f1582eSOswald Buddenhagen 	err = add_ctls(emu, &emu1010_output_source_ctl,
73497f1582eSOswald Buddenhagen 		       emu_ri->out_texts, emu_ri->n_outs);
73597f1582eSOswald Buddenhagen 	if (err < 0)
73697f1582eSOswald Buddenhagen 		return err;
73797f1582eSOswald Buddenhagen 	err = add_ctls(emu, &emu1010_input_source_ctl,
73897f1582eSOswald Buddenhagen 		       emu1010_input_texts, emu_ri->n_ins);
73997f1582eSOswald Buddenhagen 	return err;
74097f1582eSOswald Buddenhagen }
74197f1582eSOswald Buddenhagen 
7421c02e366SCtirad Fertr 
743536438f1SOswald Buddenhagen static const char * const snd_emu1010_adc_pads[] = {
744f69d705dSOswald Buddenhagen 	"ADC1 14dB PAD 0202 Capture Switch",
745536438f1SOswald Buddenhagen 	"ADC1 14dB PAD Audio Dock Capture Switch",
746536438f1SOswald Buddenhagen 	"ADC2 14dB PAD Audio Dock Capture Switch",
747536438f1SOswald Buddenhagen 	"ADC3 14dB PAD Audio Dock Capture Switch",
7481c02e366SCtirad Fertr };
7491c02e366SCtirad Fertr 
750536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_adc_pad_regs[] = {
751f69d705dSOswald Buddenhagen 	EMU_HANA_0202_ADC_PAD1,
752536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD1,
753536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD2,
754536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD3,
7559148cc50SJames Courtier-Dutton };
7569148cc50SJames Courtier-Dutton 
757a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
7589148cc50SJames Courtier-Dutton 
7599148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
7609148cc50SJames Courtier-Dutton {
7619148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
762536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
763536438f1SOswald Buddenhagen 
7649148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
7659148cc50SJames Courtier-Dutton 	return 0;
7669148cc50SJames Courtier-Dutton }
7679148cc50SJames Courtier-Dutton 
7689148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
7699148cc50SJames Courtier-Dutton {
7709148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
771536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
7729148cc50SJames Courtier-Dutton 	unsigned int val, cache;
7739148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
7749148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
7759148cc50SJames Courtier-Dutton 	if (val == 1)
7769148cc50SJames Courtier-Dutton 		cache = cache | mask;
7779148cc50SJames Courtier-Dutton 	else
7789148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
7799148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
7809148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
7819148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
7829148cc50SJames Courtier-Dutton 	}
7839148cc50SJames Courtier-Dutton 
7849148cc50SJames Courtier-Dutton 	return 0;
7859148cc50SJames Courtier-Dutton }
7869148cc50SJames Courtier-Dutton 
787536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_adc_pads_ctl = {
788536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
789536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
790536438f1SOswald Buddenhagen 	.info = snd_emu1010_adc_pads_info,
791536438f1SOswald Buddenhagen 	.get = snd_emu1010_adc_pads_get,
792536438f1SOswald Buddenhagen 	.put = snd_emu1010_adc_pads_put
793536438f1SOswald Buddenhagen };
7949148cc50SJames Courtier-Dutton 
7959148cc50SJames Courtier-Dutton 
796536438f1SOswald Buddenhagen static const char * const snd_emu1010_dac_pads[] = {
797f69d705dSOswald Buddenhagen 	"DAC1 0202 14dB PAD Playback Switch",
798536438f1SOswald Buddenhagen 	"DAC1 Audio Dock 14dB PAD Playback Switch",
799536438f1SOswald Buddenhagen 	"DAC2 Audio Dock 14dB PAD Playback Switch",
800536438f1SOswald Buddenhagen 	"DAC3 Audio Dock 14dB PAD Playback Switch",
801536438f1SOswald Buddenhagen 	"DAC4 Audio Dock 14dB PAD Playback Switch",
802536438f1SOswald Buddenhagen };
8039148cc50SJames Courtier-Dutton 
804536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_dac_regs[] = {
805f69d705dSOswald Buddenhagen 	EMU_HANA_0202_DAC_PAD1,
806536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD1,
807536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD2,
808536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD3,
809536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD4,
8109148cc50SJames Courtier-Dutton };
8119148cc50SJames Courtier-Dutton 
812a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
8139148cc50SJames Courtier-Dutton 
8149148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
8159148cc50SJames Courtier-Dutton {
8169148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
817536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
818536438f1SOswald Buddenhagen 
8199148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
8209148cc50SJames Courtier-Dutton 	return 0;
8219148cc50SJames Courtier-Dutton }
8229148cc50SJames Courtier-Dutton 
8239148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
8249148cc50SJames Courtier-Dutton {
8259148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
826536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
8279148cc50SJames Courtier-Dutton 	unsigned int val, cache;
828cc766807SOswald Buddenhagen 	int change;
829cc766807SOswald Buddenhagen 
8309148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
8319148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
8329148cc50SJames Courtier-Dutton 	if (val == 1)
8339148cc50SJames Courtier-Dutton 		cache = cache | mask;
8349148cc50SJames Courtier-Dutton 	else
8359148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
836cc766807SOswald Buddenhagen 	change = (cache != emu->emu1010.dac_pads);
837cc766807SOswald Buddenhagen 	if (change) {
8389148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
8399148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
8409148cc50SJames Courtier-Dutton 	}
8419148cc50SJames Courtier-Dutton 
842cc766807SOswald Buddenhagen 	return change;
8439148cc50SJames Courtier-Dutton }
8449148cc50SJames Courtier-Dutton 
845536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_dac_pads_ctl = {
846536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
847536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
848536438f1SOswald Buddenhagen 	.info = snd_emu1010_dac_pads_info,
849536438f1SOswald Buddenhagen 	.get = snd_emu1010_dac_pads_get,
850536438f1SOswald Buddenhagen 	.put = snd_emu1010_dac_pads_put
8519f4bd5ddSJames Courtier-Dutton };
8529f4bd5ddSJames Courtier-Dutton 
853b0dbdaeaSJames Courtier-Dutton 
85497f1582eSOswald Buddenhagen struct snd_emu1010_pads_info {
85597f1582eSOswald Buddenhagen 	const char * const *adc_ctls, * const *dac_ctls;
85697f1582eSOswald Buddenhagen 	unsigned n_adc_ctls, n_dac_ctls;
85797f1582eSOswald Buddenhagen };
85897f1582eSOswald Buddenhagen 
859816967d5STom Rix static const struct snd_emu1010_pads_info emu1010_pads_info[] = {
86097f1582eSOswald Buddenhagen 	{
8616f3609f8SOswald Buddenhagen 		/* rev1 1010 */
86297f1582eSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads,
86397f1582eSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads),
86497f1582eSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads,
86597f1582eSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads),
86697f1582eSOswald Buddenhagen 	},
86797f1582eSOswald Buddenhagen 	{
868f69d705dSOswald Buddenhagen 		/* rev2 1010 */
86997f1582eSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads,
870f69d705dSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 1,
87197f1582eSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads,
872f69d705dSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 1,
873f69d705dSOswald Buddenhagen 	},
874f69d705dSOswald Buddenhagen 	{
875f69d705dSOswald Buddenhagen 		/* 1616(m) cardbus */
876f69d705dSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads + 1,
877f69d705dSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 2,
878f69d705dSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads + 1,
87997f1582eSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 2,
88097f1582eSOswald Buddenhagen 	},
8816f3609f8SOswald Buddenhagen 	{
8826f3609f8SOswald Buddenhagen 		/* 0404 */
8836f3609f8SOswald Buddenhagen 		.adc_ctls = NULL,
8846f3609f8SOswald Buddenhagen 		.n_adc_ctls = 0,
8856f3609f8SOswald Buddenhagen 		.dac_ctls = NULL,
8866f3609f8SOswald Buddenhagen 		.n_dac_ctls = 0,
8876f3609f8SOswald Buddenhagen 	},
88897f1582eSOswald Buddenhagen };
88997f1582eSOswald Buddenhagen 
890*60985241SOswald Buddenhagen static const char * const emu1010_clock_texts[] = {
891*60985241SOswald Buddenhagen 	"44100", "48000", "SPDIF", "ADAT", "Dock", "BNC"
892*60985241SOswald Buddenhagen };
893*60985241SOswald Buddenhagen 
894*60985241SOswald Buddenhagen static const u8 emu1010_clock_vals[] = {
895*60985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_INT_44_1K,
896*60985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_INT_48K,
897*60985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_HANA_SPDIF_IN,
898*60985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_HANA_ADAT_IN,
899*60985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_2ND_HANA,
900*60985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_SYNC_BNC,
901*60985241SOswald Buddenhagen };
902*60985241SOswald Buddenhagen 
903*60985241SOswald Buddenhagen static const char * const emu0404_clock_texts[] = {
904*60985241SOswald Buddenhagen 	"44100", "48000", "SPDIF", "BNC"
905*60985241SOswald Buddenhagen };
906*60985241SOswald Buddenhagen 
907*60985241SOswald Buddenhagen static const u8 emu0404_clock_vals[] = {
908*60985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_INT_44_1K,
909*60985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_INT_48K,
910*60985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_HANA_SPDIF_IN,
911*60985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_SYNC_BNC,
912*60985241SOswald Buddenhagen };
913*60985241SOswald Buddenhagen 
914*60985241SOswald Buddenhagen struct snd_emu1010_clock_info {
915*60985241SOswald Buddenhagen 	const char * const *texts;
916*60985241SOswald Buddenhagen 	const u8 *vals;
917*60985241SOswald Buddenhagen 	unsigned num;
918*60985241SOswald Buddenhagen };
919*60985241SOswald Buddenhagen 
920*60985241SOswald Buddenhagen static const struct snd_emu1010_clock_info emu1010_clock_info[] = {
921*60985241SOswald Buddenhagen 	{
922*60985241SOswald Buddenhagen 		// rev1 1010
923*60985241SOswald Buddenhagen 		.texts = emu1010_clock_texts,
924*60985241SOswald Buddenhagen 		.vals = emu1010_clock_vals,
925*60985241SOswald Buddenhagen 		.num = ARRAY_SIZE(emu1010_clock_vals),
926*60985241SOswald Buddenhagen 	},
927*60985241SOswald Buddenhagen 	{
928*60985241SOswald Buddenhagen 		// rev2 1010
929*60985241SOswald Buddenhagen 		.texts = emu1010_clock_texts,
930*60985241SOswald Buddenhagen 		.vals = emu1010_clock_vals,
931*60985241SOswald Buddenhagen 		.num = ARRAY_SIZE(emu1010_clock_vals) - 1,
932*60985241SOswald Buddenhagen 	},
933*60985241SOswald Buddenhagen 	{
934*60985241SOswald Buddenhagen 		// 1616(m) CardBus
935*60985241SOswald Buddenhagen 		.texts = emu1010_clock_texts,
936*60985241SOswald Buddenhagen 		// TODO: determine what is actually available.
937*60985241SOswald Buddenhagen 		// Pedantically, *every* source comes from the 2nd FPGA, as the
938*60985241SOswald Buddenhagen 		// card itself has no own (digital) audio ports. The user manual
939*60985241SOswald Buddenhagen 		// claims that ADAT and S/PDIF clock sources are separate, which
940*60985241SOswald Buddenhagen 		// can mean two things: either E-MU mapped the dock's sources to
941*60985241SOswald Buddenhagen 		// the primary ones, or they determine the meaning of the "Dock"
942*60985241SOswald Buddenhagen 		// source depending on how the ports are actually configured
943*60985241SOswald Buddenhagen 		// (which the 2nd FPGA must be doing anyway).
944*60985241SOswald Buddenhagen 		.vals = emu1010_clock_vals,
945*60985241SOswald Buddenhagen 		.num = ARRAY_SIZE(emu1010_clock_vals),
946*60985241SOswald Buddenhagen 	},
947*60985241SOswald Buddenhagen 	{
948*60985241SOswald Buddenhagen 		// 0404
949*60985241SOswald Buddenhagen 		.texts = emu0404_clock_texts,
950*60985241SOswald Buddenhagen 		.vals = emu0404_clock_vals,
951*60985241SOswald Buddenhagen 		.num = ARRAY_SIZE(emu0404_clock_vals),
952*60985241SOswald Buddenhagen 	},
953*60985241SOswald Buddenhagen };
95497f1582eSOswald Buddenhagen 
95513598862SOswald Buddenhagen static int snd_emu1010_clock_source_info(struct snd_kcontrol *kcontrol,
956b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
957b0dbdaeaSJames Courtier-Dutton {
958*60985241SOswald Buddenhagen 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
959*60985241SOswald Buddenhagen 	const struct snd_emu1010_clock_info *emu_ci =
960*60985241SOswald Buddenhagen 		&emu1010_clock_info[emu1010_idx(emu)];
961b0dbdaeaSJames Courtier-Dutton 
962*60985241SOswald Buddenhagen 	return snd_ctl_enum_info(uinfo, 1, emu_ci->num, emu_ci->texts);
963b0dbdaeaSJames Courtier-Dutton }
964b0dbdaeaSJames Courtier-Dutton 
96513598862SOswald Buddenhagen static int snd_emu1010_clock_source_get(struct snd_kcontrol *kcontrol,
966b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
967b0dbdaeaSJames Courtier-Dutton {
968b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
969b0dbdaeaSJames Courtier-Dutton 
97013598862SOswald Buddenhagen 	ucontrol->value.enumerated.item[0] = emu->emu1010.clock_source;
971b0dbdaeaSJames Courtier-Dutton 	return 0;
972b0dbdaeaSJames Courtier-Dutton }
973b0dbdaeaSJames Courtier-Dutton 
97413598862SOswald Buddenhagen static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
975b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
976b0dbdaeaSJames Courtier-Dutton {
977b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
978*60985241SOswald Buddenhagen 	const struct snd_emu1010_clock_info *emu_ci =
979*60985241SOswald Buddenhagen 		&emu1010_clock_info[emu1010_idx(emu)];
980b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
981b0dbdaeaSJames Courtier-Dutton 	int change = 0;
982b0dbdaeaSJames Courtier-Dutton 
983b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
984*60985241SOswald Buddenhagen 	if (val >= emu_ci->num)
98574415a36SJames Courtier-Dutton 		return -EINVAL;
98613598862SOswald Buddenhagen 	change = (emu->emu1010.clock_source != val);
987b0dbdaeaSJames Courtier-Dutton 	if (change) {
98813598862SOswald Buddenhagen 		emu->emu1010.clock_source = val;
989*60985241SOswald Buddenhagen 		emu->emu1010.wclock = emu_ci->vals[val];
990edec7bbbSJames Courtier-Dutton 
991edec7bbbSJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE);
992*60985241SOswald Buddenhagen 		snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, emu->emu1010.wclock);
993*60985241SOswald Buddenhagen 		msleep(10);  // Allow DLL to settle
994edec7bbbSJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
995edec7bbbSJames Courtier-Dutton 
996*60985241SOswald Buddenhagen 		snd_emu1010_update_clock(emu);
997b0dbdaeaSJames Courtier-Dutton 	}
998b0dbdaeaSJames Courtier-Dutton 	return change;
999b0dbdaeaSJames Courtier-Dutton }
1000b0dbdaeaSJames Courtier-Dutton 
100113598862SOswald Buddenhagen static const struct snd_kcontrol_new snd_emu1010_clock_source =
1002b0dbdaeaSJames Courtier-Dutton {
1003b0dbdaeaSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1004b0dbdaeaSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
100513598862SOswald Buddenhagen 	.name = "Clock Source",
1006b0dbdaeaSJames Courtier-Dutton 	.count = 1,
100713598862SOswald Buddenhagen 	.info = snd_emu1010_clock_source_info,
100813598862SOswald Buddenhagen 	.get = snd_emu1010_clock_source_get,
100913598862SOswald Buddenhagen 	.put = snd_emu1010_clock_source_put
101013598862SOswald Buddenhagen };
101113598862SOswald Buddenhagen 
101213598862SOswald Buddenhagen static int snd_emu1010_clock_fallback_info(struct snd_kcontrol *kcontrol,
101313598862SOswald Buddenhagen 					  struct snd_ctl_elem_info *uinfo)
101413598862SOswald Buddenhagen {
101513598862SOswald Buddenhagen 	static const char * const texts[2] = {
101613598862SOswald Buddenhagen 		"44100", "48000"
101713598862SOswald Buddenhagen 	};
101813598862SOswald Buddenhagen 
101913598862SOswald Buddenhagen 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
102013598862SOswald Buddenhagen }
102113598862SOswald Buddenhagen 
102213598862SOswald Buddenhagen static int snd_emu1010_clock_fallback_get(struct snd_kcontrol *kcontrol,
102313598862SOswald Buddenhagen 					  struct snd_ctl_elem_value *ucontrol)
102413598862SOswald Buddenhagen {
102513598862SOswald Buddenhagen 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
102613598862SOswald Buddenhagen 
102713598862SOswald Buddenhagen 	ucontrol->value.enumerated.item[0] = emu->emu1010.clock_fallback;
102813598862SOswald Buddenhagen 	return 0;
102913598862SOswald Buddenhagen }
103013598862SOswald Buddenhagen 
103113598862SOswald Buddenhagen static int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol,
103213598862SOswald Buddenhagen 					  struct snd_ctl_elem_value *ucontrol)
103313598862SOswald Buddenhagen {
103413598862SOswald Buddenhagen 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
103513598862SOswald Buddenhagen 	unsigned int val = ucontrol->value.enumerated.item[0];
103613598862SOswald Buddenhagen 	int change;
103713598862SOswald Buddenhagen 
103813598862SOswald Buddenhagen 	if (val >= 2)
103913598862SOswald Buddenhagen 		return -EINVAL;
104013598862SOswald Buddenhagen 	change = (emu->emu1010.clock_fallback != val);
104113598862SOswald Buddenhagen 	if (change) {
104213598862SOswald Buddenhagen 		emu->emu1010.clock_fallback = val;
104313598862SOswald Buddenhagen 		snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 1 - val);
104413598862SOswald Buddenhagen 	}
104513598862SOswald Buddenhagen 	return change;
104613598862SOswald Buddenhagen }
104713598862SOswald Buddenhagen 
104813598862SOswald Buddenhagen static const struct snd_kcontrol_new snd_emu1010_clock_fallback =
104913598862SOswald Buddenhagen {
105013598862SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
105113598862SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
105213598862SOswald Buddenhagen 	.name = "Clock Fallback",
105313598862SOswald Buddenhagen 	.count = 1,
105413598862SOswald Buddenhagen 	.info = snd_emu1010_clock_fallback_info,
105513598862SOswald Buddenhagen 	.get = snd_emu1010_clock_fallback_get,
105613598862SOswald Buddenhagen 	.put = snd_emu1010_clock_fallback_put
1057b0dbdaeaSJames Courtier-Dutton };
1058b0dbdaeaSJames Courtier-Dutton 
105999dcab46SMichael Gernoth static int snd_emu1010_optical_out_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_out_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_out;
107599dcab46SMichael Gernoth 	return 0;
107699dcab46SMichael Gernoth }
107799dcab46SMichael Gernoth 
107899dcab46SMichael Gernoth static int snd_emu1010_optical_out_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_out != val);
109199dcab46SMichael Gernoth 	if (change) {
109299dcab46SMichael Gernoth 		emu->emu1010.optical_out = 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_out = {
110199dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
110299dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
110399dcab46SMichael Gernoth 	.name =         "Optical Output Mode",
110499dcab46SMichael Gernoth 	.count =	1,
110599dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_out_info,
110699dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_out_get,
110799dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_out_put
110899dcab46SMichael Gernoth };
110999dcab46SMichael Gernoth 
111099dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
111199dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
111299dcab46SMichael Gernoth {
111399dcab46SMichael Gernoth 	static const char * const texts[2] = {
111499dcab46SMichael Gernoth 		"SPDIF", "ADAT"
111599dcab46SMichael Gernoth 	};
111699dcab46SMichael Gernoth 
111799dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
111899dcab46SMichael Gernoth }
111999dcab46SMichael Gernoth 
112099dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
112199dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
112299dcab46SMichael Gernoth {
112399dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
112499dcab46SMichael Gernoth 
112599dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
112699dcab46SMichael Gernoth 	return 0;
112799dcab46SMichael Gernoth }
112899dcab46SMichael Gernoth 
112999dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
113099dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
113199dcab46SMichael Gernoth {
113299dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
113399dcab46SMichael Gernoth 	unsigned int val;
113499dcab46SMichael Gernoth 	u32 tmp;
113599dcab46SMichael Gernoth 	int change = 0;
113699dcab46SMichael Gernoth 
113799dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
113899dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
113999dcab46SMichael Gernoth 	if (val >= 2)
114099dcab46SMichael Gernoth 		return -EINVAL;
114199dcab46SMichael Gernoth 	change = (emu->emu1010.optical_in != val);
114299dcab46SMichael Gernoth 	if (change) {
114399dcab46SMichael Gernoth 		emu->emu1010.optical_in = val;
11449d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
11459d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
114699dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
114799dcab46SMichael Gernoth 	}
114899dcab46SMichael Gernoth 	return change;
114999dcab46SMichael Gernoth }
115099dcab46SMichael Gernoth 
1151f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = {
115299dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
115399dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
115499dcab46SMichael Gernoth 	.name =         "Optical Input Mode",
115599dcab46SMichael Gernoth 	.count =	1,
115699dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_in_info,
115799dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_in_get,
115899dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_in_put
115999dcab46SMichael Gernoth };
116099dcab46SMichael Gernoth 
1161184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
1162184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
1163184c1e2cSJames Courtier-Dutton {
1164184c1e2cSJames Courtier-Dutton #if 0
11651541c66dSTakashi Iwai 	static const char * const texts[4] = {
1166184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
1167184c1e2cSJames Courtier-Dutton 	};
1168184c1e2cSJames Courtier-Dutton #endif
11691541c66dSTakashi Iwai 	static const char * const texts[2] = {
1170184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
1171184c1e2cSJames Courtier-Dutton 	};
1172184c1e2cSJames Courtier-Dutton 
11731541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
1174184c1e2cSJames Courtier-Dutton }
1175184c1e2cSJames Courtier-Dutton 
1176184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
1177184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
1178184c1e2cSJames Courtier-Dutton {
1179184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1180184c1e2cSJames Courtier-Dutton 
1181184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
1182184c1e2cSJames Courtier-Dutton 	return 0;
1183184c1e2cSJames Courtier-Dutton }
1184184c1e2cSJames Courtier-Dutton 
1185184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
1186184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
1187184c1e2cSJames Courtier-Dutton {
1188184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1189184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
1190184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
1191a1c87c0bSOswald Buddenhagen 	u16 gpio;
1192184c1e2cSJames Courtier-Dutton 	int change = 0;
1193184c1e2cSJames Courtier-Dutton 	unsigned long flags;
1194184c1e2cSJames Courtier-Dutton 	u32 source;
1195184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
1196184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
1197184c1e2cSJames Courtier-Dutton 	 * for the particular source.
1198184c1e2cSJames Courtier-Dutton 	 */
119974415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
120074415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
120174415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
120274415a36SJames Courtier-Dutton 	if (source_id >= 2)
120374415a36SJames Courtier-Dutton 		return -EINVAL;
1204184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
1205184c1e2cSJames Courtier-Dutton 	if (change) {
1206184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
1207184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
1208a1c87c0bSOswald Buddenhagen 		gpio = inw(emu->port + A_IOCFG);
1209184c1e2cSJames Courtier-Dutton 		if (source_id==0)
1210a1c87c0bSOswald Buddenhagen 			outw(gpio | 0x4, emu->port + A_IOCFG);
1211184c1e2cSJames Courtier-Dutton 		else
1212a1c87c0bSOswald Buddenhagen 			outw(gpio & ~0x4, emu->port + A_IOCFG);
1213184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
1214184c1e2cSJames Courtier-Dutton 
1215184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
1216184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
1217184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
1218184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
1219184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
1220184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
1221184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
1222184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
1223184c1e2cSJames Courtier-Dutton 
1224184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
1225184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
1226184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
1227184c1e2cSJames Courtier-Dutton 	}
1228184c1e2cSJames Courtier-Dutton         return change;
1229184c1e2cSJames Courtier-Dutton }
1230184c1e2cSJames Courtier-Dutton 
1231f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source =
1232184c1e2cSJames Courtier-Dutton {
1233184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
1234184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
1235184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
1236184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
1237184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
1238184c1e2cSJames Courtier-Dutton };
1239184c1e2cSJames Courtier-Dutton 
1240184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
1241184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
1242184c1e2cSJames Courtier-Dutton {
1243184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1244184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
1245184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
1246184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
1247184c1e2cSJames Courtier-Dutton 	return 0;
1248184c1e2cSJames Courtier-Dutton }
1249184c1e2cSJames Courtier-Dutton 
1250184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
1251184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
1252184c1e2cSJames Courtier-Dutton {
1253184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
125474415a36SJames Courtier-Dutton 	unsigned int source_id;
1255184c1e2cSJames Courtier-Dutton 
1256184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
125774415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
125874415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
125974415a36SJames Courtier-Dutton 	if (source_id >= 2)
126074415a36SJames Courtier-Dutton 		return -EINVAL;
1261184c1e2cSJames Courtier-Dutton 
1262184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
1263184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
1264184c1e2cSJames Courtier-Dutton 	return 0;
1265184c1e2cSJames Courtier-Dutton }
1266184c1e2cSJames Courtier-Dutton 
1267184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
1268184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
1269184c1e2cSJames Courtier-Dutton {
1270184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1271184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
127214a29565SOswald Buddenhagen 	unsigned int ngain0, ngain1;
127374415a36SJames Courtier-Dutton 	unsigned int source_id;
1274184c1e2cSJames Courtier-Dutton 	int change = 0;
1275184c1e2cSJames Courtier-Dutton 
1276184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
127774415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
127874415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
127974415a36SJames Courtier-Dutton 	if (source_id >= 2)
128074415a36SJames Courtier-Dutton 		return -EINVAL;
128114a29565SOswald Buddenhagen 	ngain0 = ucontrol->value.integer.value[0];
128214a29565SOswald Buddenhagen 	ngain1 = ucontrol->value.integer.value[1];
128314a29565SOswald Buddenhagen 	if (ngain0 > 0xff)
128414a29565SOswald Buddenhagen 		return -EINVAL;
128514a29565SOswald Buddenhagen 	if (ngain1 > 0xff)
128614a29565SOswald Buddenhagen 		return -EINVAL;
1287184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
128814a29565SOswald Buddenhagen 	if (ogain != ngain0) {
1289184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
129014a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0);
129114a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][0] = ngain0;
1292184c1e2cSJames Courtier-Dutton 		change = 1;
1293184c1e2cSJames Courtier-Dutton 	}
1294184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
129514a29565SOswald Buddenhagen 	if (ogain != ngain1) {
1296184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
129714a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1);
129814a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][1] = ngain1;
1299184c1e2cSJames Courtier-Dutton 		change = 1;
1300184c1e2cSJames Courtier-Dutton 	}
1301184c1e2cSJames Courtier-Dutton 
1302184c1e2cSJames Courtier-Dutton 	return change;
1303184c1e2cSJames Courtier-Dutton }
1304184c1e2cSJames Courtier-Dutton 
1305536438f1SOswald Buddenhagen static const struct snd_kcontrol_new i2c_volume_ctl = {
1306536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1307536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1308536438f1SOswald Buddenhagen 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,
1309536438f1SOswald Buddenhagen 	.info = snd_audigy_i2c_volume_info,
1310536438f1SOswald Buddenhagen 	.get = snd_audigy_i2c_volume_get,
1311536438f1SOswald Buddenhagen 	.put = snd_audigy_i2c_volume_put,
1312536438f1SOswald Buddenhagen 	.tlv = { .p = snd_audigy_db_scale2 }
1313536438f1SOswald Buddenhagen };
1314184c1e2cSJames Courtier-Dutton 
1315536438f1SOswald Buddenhagen static const char * const snd_audigy_i2c_volume_ctls[] = {
1316536438f1SOswald Buddenhagen 	"Mic Capture Volume",
1317536438f1SOswald Buddenhagen 	"Line Capture Volume",
1318184c1e2cSJames Courtier-Dutton };
1319184c1e2cSJames Courtier-Dutton 
13200af68e5eSTakashi Iwai #if 0
1321eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13221da177e4SLinus Torvalds {
13231541c66dSTakashi Iwai 	static const char * const texts[] = {"44100", "48000", "96000"};
13241da177e4SLinus Torvalds 
13251541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 3, texts);
13261da177e4SLinus Torvalds }
13271da177e4SLinus Torvalds 
1328eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
1329eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
13301da177e4SLinus Torvalds {
1331eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13321da177e4SLinus Torvalds 	unsigned int tmp;
13331da177e4SLinus Torvalds 
13341da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
13351da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
13361da177e4SLinus Torvalds 	case A_SPDIF_44100:
13371da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
13381da177e4SLinus Torvalds 		break;
13391da177e4SLinus Torvalds 	case A_SPDIF_48000:
13401da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
13411da177e4SLinus Torvalds 		break;
13421da177e4SLinus Torvalds 	case A_SPDIF_96000:
13431da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
13441da177e4SLinus Torvalds 		break;
13451da177e4SLinus Torvalds 	default:
13461da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
13471da177e4SLinus Torvalds 	}
13481da177e4SLinus Torvalds 	return 0;
13491da177e4SLinus Torvalds }
13501da177e4SLinus Torvalds 
1351eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
1352eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
13531da177e4SLinus Torvalds {
1354eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13551da177e4SLinus Torvalds 	int change;
13561da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
13571da177e4SLinus Torvalds 	unsigned long flags;
13581da177e4SLinus Torvalds 
13591da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
13601da177e4SLinus Torvalds 	case 0:
13611da177e4SLinus Torvalds 		val = A_SPDIF_44100;
13621da177e4SLinus Torvalds 		break;
13631da177e4SLinus Torvalds 	case 1:
13641da177e4SLinus Torvalds 		val = A_SPDIF_48000;
13651da177e4SLinus Torvalds 		break;
13661da177e4SLinus Torvalds 	case 2:
13671da177e4SLinus Torvalds 		val = A_SPDIF_96000;
13681da177e4SLinus Torvalds 		break;
13691da177e4SLinus Torvalds 	default:
13701da177e4SLinus Torvalds 		val = A_SPDIF_48000;
13711da177e4SLinus Torvalds 		break;
13721da177e4SLinus Torvalds 	}
13731da177e4SLinus Torvalds 
13741da177e4SLinus Torvalds 
13751da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13761da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
13771da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
13781da177e4SLinus Torvalds 	tmp |= val;
137912bda107STakashi Iwai 	change = (tmp != reg);
138012bda107STakashi Iwai 	if (change)
13811da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
13821da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13831da177e4SLinus Torvalds 	return change;
13841da177e4SLinus Torvalds }
13851da177e4SLinus Torvalds 
1386b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate =
13871da177e4SLinus Torvalds {
13881da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
13891da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
13901da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
13911da177e4SLinus Torvalds 	.count =	1,
13921da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
13931da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
13941da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
13951da177e4SLinus Torvalds };
13960af68e5eSTakashi Iwai #endif
13971da177e4SLinus Torvalds 
1398eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1399eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
14001da177e4SLinus Torvalds {
1401eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14021da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
14031da177e4SLinus Torvalds 	int change;
14041da177e4SLinus Torvalds 	unsigned int val;
14051da177e4SLinus Torvalds 
140674415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
140774415a36SJames Courtier-Dutton 	if (idx >= 3)
140874415a36SJames Courtier-Dutton 		return -EINVAL;
14091da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
14101da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
14111da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
14121da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
14131da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
14141da177e4SLinus Torvalds 	if (change) {
14151da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
14161da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
14171da177e4SLinus Torvalds 	}
14181da177e4SLinus Torvalds 	return change;
14191da177e4SLinus Torvalds }
14201da177e4SLinus Torvalds 
1421f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
14221da177e4SLinus Torvalds {
14231da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
14245549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14251da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
14267583cb51STakashi Iwai 	.count =	3,
14271da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
14281da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
14291da177e4SLinus Torvalds };
14301da177e4SLinus Torvalds 
1431f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
14321da177e4SLinus Torvalds {
14335549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
14341da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
14357583cb51STakashi Iwai 	.count =	3,
14361da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
14371da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
14381da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
14391da177e4SLinus Torvalds };
14401da177e4SLinus Torvalds 
14411da177e4SLinus Torvalds 
1442eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
14431da177e4SLinus Torvalds {
14441da177e4SLinus Torvalds 	if (emu->audigy) {
144546055699SOswald Buddenhagen 		snd_emu10k1_ptr_write_multiple(emu, voice,
144646055699SOswald Buddenhagen 			A_FXRT1, snd_emu10k1_compose_audigy_fxrt1(route),
144746055699SOswald Buddenhagen 			A_FXRT2, snd_emu10k1_compose_audigy_fxrt2(route),
144846055699SOswald Buddenhagen 			REGLIST_END);
14491da177e4SLinus Torvalds 	} else {
14501da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
14511da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
14521da177e4SLinus Torvalds 	}
14531da177e4SLinus Torvalds }
14541da177e4SLinus Torvalds 
1455eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
14561da177e4SLinus Torvalds {
14571da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
14581da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
14591da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
14601da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
14611da177e4SLinus Torvalds 	if (emu->audigy) {
146251d652f4SOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice,
146351d652f4SOswald Buddenhagen 				      snd_emu10k1_compose_audigy_sendamounts(volume));
14641da177e4SLinus Torvalds 	}
14651da177e4SLinus Torvalds }
14661da177e4SLinus Torvalds 
14671da177e4SLinus Torvalds /* PCM stream controls */
14681da177e4SLinus Torvalds 
1469eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14701da177e4SLinus Torvalds {
1471eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14721da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14731da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
14741da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14751da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
14761da177e4SLinus Torvalds 	return 0;
14771da177e4SLinus Torvalds }
14781da177e4SLinus Torvalds 
1479eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1480eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14811da177e4SLinus Torvalds {
1482eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1483eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1484eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14851da177e4SLinus Torvalds 	int voice, idx;
14861da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14871da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14881da177e4SLinus Torvalds 
14891da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
14901da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
14911da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
14921da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
14931da177e4SLinus Torvalds 	return 0;
14941da177e4SLinus Torvalds }
14951da177e4SLinus Torvalds 
1496eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1497eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14981da177e4SLinus Torvalds {
14991da177e4SLinus Torvalds 	unsigned long flags;
1500eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1501eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1502eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15031da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
15041da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15051da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
15061da177e4SLinus Torvalds 
15071da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15081da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
15091da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
15101da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
15111da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
15121da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
15131da177e4SLinus Torvalds 				change = 1;
15141da177e4SLinus Torvalds 			}
15151da177e4SLinus Torvalds 		}
1516a915d604SOswald Buddenhagen 	if (change && mix->epcm && mix->epcm->voices[0]) {
1517a915d604SOswald Buddenhagen 		if (!mix->epcm->voices[0]->last) {
15181da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
15191da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
1520a915d604SOswald Buddenhagen 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number + 1,
15211da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
1522a915d604SOswald Buddenhagen 		} else {
15231da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
15241da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
15251da177e4SLinus Torvalds 		}
15261da177e4SLinus Torvalds 	}
15271da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15281da177e4SLinus Torvalds 	return change;
15291da177e4SLinus Torvalds }
15301da177e4SLinus Torvalds 
1531f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control =
15321da177e4SLinus Torvalds {
15331da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
153467ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15351da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
15361da177e4SLinus Torvalds 	.count =	32,
15371da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
15381da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
15391da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
15401da177e4SLinus Torvalds };
15411da177e4SLinus Torvalds 
1542eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15431da177e4SLinus Torvalds {
1544eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15451da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15461da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
15471da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
15481da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
15491da177e4SLinus Torvalds 	return 0;
15501da177e4SLinus Torvalds }
15511da177e4SLinus Torvalds 
1552eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1553eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
15541da177e4SLinus Torvalds {
1555eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1556eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1557eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15581da177e4SLinus Torvalds 	int idx;
15591da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15601da177e4SLinus Torvalds 
15611da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
15621da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
15631da177e4SLinus Torvalds 	return 0;
15641da177e4SLinus Torvalds }
15651da177e4SLinus Torvalds 
1566eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1567eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
15681da177e4SLinus Torvalds {
15691da177e4SLinus Torvalds 	unsigned long flags;
1570eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1571eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1572eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15731da177e4SLinus Torvalds 	int change = 0, idx, val;
15741da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15751da177e4SLinus Torvalds 
15761da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15771da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
15781da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
15791da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
15801da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
15811da177e4SLinus Torvalds 			change = 1;
15821da177e4SLinus Torvalds 		}
15831da177e4SLinus Torvalds 	}
1584a915d604SOswald Buddenhagen 	if (change && mix->epcm && mix->epcm->voices[0]) {
1585a915d604SOswald Buddenhagen 		if (!mix->epcm->voices[0]->last) {
15861da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
15871da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
1588a915d604SOswald Buddenhagen 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number + 1,
15891da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
1590a915d604SOswald Buddenhagen 		} else {
15911da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
15921da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
15931da177e4SLinus Torvalds 		}
15941da177e4SLinus Torvalds 	}
15951da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15961da177e4SLinus Torvalds 	return change;
15971da177e4SLinus Torvalds }
15981da177e4SLinus Torvalds 
1599f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
16001da177e4SLinus Torvalds {
16011da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
160267ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
16031da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
16041da177e4SLinus Torvalds 	.count =	32,
16051da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
16061da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
16071da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
16081da177e4SLinus Torvalds };
16091da177e4SLinus Torvalds 
1610eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
16111da177e4SLinus Torvalds {
16121da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
16131da177e4SLinus Torvalds 	uinfo->count = 3;
16141da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1615bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
16161da177e4SLinus Torvalds 	return 0;
16171da177e4SLinus Torvalds }
16181da177e4SLinus Torvalds 
1619eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1620eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
16211da177e4SLinus Torvalds {
1622eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1623eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1624eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
16251da177e4SLinus Torvalds 	int idx;
16261da177e4SLinus Torvalds 
16271da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
1628bcdbd3b7SOswald Buddenhagen 		ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U;
16291da177e4SLinus Torvalds 	return 0;
16301da177e4SLinus Torvalds }
16311da177e4SLinus Torvalds 
1632eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1633eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
16341da177e4SLinus Torvalds {
16351da177e4SLinus Torvalds 	unsigned long flags;
1636eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1637eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1638eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
16391da177e4SLinus Torvalds 	int change = 0, idx, val;
16401da177e4SLinus Torvalds 
16411da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
16421da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
1643bcdbd3b7SOswald Buddenhagen 		unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff;
1644bcdbd3b7SOswald Buddenhagen 		val = uval * 0x8000U / 0xffffU;
16451da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
16461da177e4SLinus Torvalds 			mix->attn[idx] = val;
16471da177e4SLinus Torvalds 			change = 1;
16481da177e4SLinus Torvalds 		}
16491da177e4SLinus Torvalds 	}
1650a915d604SOswald Buddenhagen 	if (change && mix->epcm && mix->epcm->voices[0]) {
1651a915d604SOswald Buddenhagen 		if (!mix->epcm->voices[0]->last) {
16521da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
1653a915d604SOswald Buddenhagen 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number + 1, mix->attn[2]);
1654a915d604SOswald Buddenhagen 		} else {
16551da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
16561da177e4SLinus Torvalds 		}
16571da177e4SLinus Torvalds 	}
16581da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
16591da177e4SLinus Torvalds 	return change;
16601da177e4SLinus Torvalds }
16611da177e4SLinus Torvalds 
1662f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control =
16631da177e4SLinus Torvalds {
16641da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
166567ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
16661da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
16671da177e4SLinus Torvalds 	.count =	32,
16681da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
16691da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
16701da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
16711da177e4SLinus Torvalds };
16721da177e4SLinus Torvalds 
16731da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
16741da177e4SLinus Torvalds 
1675eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
16761da177e4SLinus Torvalds {
1677eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
16781da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
16791da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
16801da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
16811da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
16821da177e4SLinus Torvalds 	return 0;
16831da177e4SLinus Torvalds }
16841da177e4SLinus Torvalds 
1685eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1686eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
16871da177e4SLinus Torvalds {
1688eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1689eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1690eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
16911da177e4SLinus Torvalds 	int idx;
16921da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
16931da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
16941da177e4SLinus Torvalds 
16951da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
16961da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
16971da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
16981da177e4SLinus Torvalds 	return 0;
16991da177e4SLinus Torvalds }
17001da177e4SLinus Torvalds 
1701eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1702eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
17031da177e4SLinus Torvalds {
17041da177e4SLinus Torvalds 	unsigned long flags;
1705eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
17061da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1707eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
17081da177e4SLinus Torvalds 	int change = 0, idx, val;
17091da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
17101da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
17111da177e4SLinus Torvalds 
17121da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
17131da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
17141da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
17151da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
17161da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
17171da177e4SLinus Torvalds 			change = 1;
17181da177e4SLinus Torvalds 		}
17191da177e4SLinus Torvalds 	}
17201da177e4SLinus Torvalds 
17211da177e4SLinus Torvalds 	if (change && mix->epcm) {
17221da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
17231da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
17241da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
17251da177e4SLinus Torvalds 		}
17261da177e4SLinus Torvalds 	}
17271da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
17281da177e4SLinus Torvalds 	return change;
17291da177e4SLinus Torvalds }
17301da177e4SLinus Torvalds 
1731f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
17321da177e4SLinus Torvalds {
17331da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
17341da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
17351da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
17361da177e4SLinus Torvalds 	.count =	16,
17371da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
17381da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
17391da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
17401da177e4SLinus Torvalds };
17411da177e4SLinus Torvalds 
1742eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
17431da177e4SLinus Torvalds {
1744eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
17451da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
17461da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
17471da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
17481da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
17491da177e4SLinus Torvalds 	return 0;
17501da177e4SLinus Torvalds }
17511da177e4SLinus Torvalds 
1752eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1753eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
17541da177e4SLinus Torvalds {
1755eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1756eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1757eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
17581da177e4SLinus Torvalds 	int idx;
17591da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
17601da177e4SLinus Torvalds 
17611da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
17621da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
17631da177e4SLinus Torvalds 	return 0;
17641da177e4SLinus Torvalds }
17651da177e4SLinus Torvalds 
1766eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1767eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
17681da177e4SLinus Torvalds {
17691da177e4SLinus Torvalds 	unsigned long flags;
1770eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
17711da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1772eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
17731da177e4SLinus Torvalds 	int change = 0, idx, val;
17741da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
17751da177e4SLinus Torvalds 
17761da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
17771da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
17781da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
17791da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
17801da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
17811da177e4SLinus Torvalds 			change = 1;
17821da177e4SLinus Torvalds 		}
17831da177e4SLinus Torvalds 	}
17841da177e4SLinus Torvalds 	if (change && mix->epcm) {
17851da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
17861da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
17871da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
17881da177e4SLinus Torvalds 		}
17891da177e4SLinus Torvalds 	}
17901da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
17911da177e4SLinus Torvalds 	return change;
17921da177e4SLinus Torvalds }
17931da177e4SLinus Torvalds 
17941da177e4SLinus Torvalds 
1795f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
17961da177e4SLinus Torvalds {
17971da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
17981da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
17991da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
18001da177e4SLinus Torvalds 	.count =	16,
18011da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
18021da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
18031da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
18041da177e4SLinus Torvalds };
18051da177e4SLinus Torvalds 
1806eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
18071da177e4SLinus Torvalds {
18081da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
18091da177e4SLinus Torvalds 	uinfo->count = 1;
18101da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1811bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
18121da177e4SLinus Torvalds 	return 0;
18131da177e4SLinus Torvalds }
18141da177e4SLinus Torvalds 
1815eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1816eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
18171da177e4SLinus Torvalds {
1818eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1819eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1820eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
18211da177e4SLinus Torvalds 
1822bcdbd3b7SOswald Buddenhagen 	ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U;
18231da177e4SLinus Torvalds 	return 0;
18241da177e4SLinus Torvalds }
18251da177e4SLinus Torvalds 
1826eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1827eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
18281da177e4SLinus Torvalds {
18291da177e4SLinus Torvalds 	unsigned long flags;
1830eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
18311da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1832eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
18331da177e4SLinus Torvalds 	int change = 0, val;
1834bcdbd3b7SOswald Buddenhagen 	unsigned uval;
18351da177e4SLinus Torvalds 
18361da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1837bcdbd3b7SOswald Buddenhagen 	uval = ucontrol->value.integer.value[0] & 0x1ffff;
1838bcdbd3b7SOswald Buddenhagen 	val = uval * 0x8000U / 0xffffU;
18391da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
18401da177e4SLinus Torvalds 		mix->attn[0] = val;
18411da177e4SLinus Torvalds 		change = 1;
18421da177e4SLinus Torvalds 	}
18431da177e4SLinus Torvalds 	if (change && mix->epcm) {
18441da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
18451da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
18461da177e4SLinus Torvalds 		}
18471da177e4SLinus Torvalds 	}
18481da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
18491da177e4SLinus Torvalds 	return change;
18501da177e4SLinus Torvalds }
18511da177e4SLinus Torvalds 
1852f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
18531da177e4SLinus Torvalds {
18541da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
18551da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
18561da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
18571da177e4SLinus Torvalds 	.count =	16,
18581da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
18591da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
18601da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
18611da177e4SLinus Torvalds };
18621da177e4SLinus Torvalds 
1863a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
18641da177e4SLinus Torvalds 
1865eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1866eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
18671da177e4SLinus Torvalds {
1868eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
18691da177e4SLinus Torvalds 
18701da177e4SLinus Torvalds 	if (emu->audigy)
1871a1c87c0bSOswald Buddenhagen 		ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
18721da177e4SLinus Torvalds 	else
18731da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1874d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1875d2cd74b1STakashi Iwai 		ucontrol->value.integer.value[0] =
1876d2cd74b1STakashi Iwai 			!ucontrol->value.integer.value[0];
1877d2cd74b1STakashi Iwai 
18781da177e4SLinus Torvalds 	return 0;
18791da177e4SLinus Torvalds }
18801da177e4SLinus Torvalds 
1881eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1882eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
18831da177e4SLinus Torvalds {
18841da177e4SLinus Torvalds 	unsigned long flags;
1885eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1886d2cd74b1STakashi Iwai 	unsigned int reg, val, sw;
18871da177e4SLinus Torvalds 	int change = 0;
18881da177e4SLinus Torvalds 
1889d2cd74b1STakashi Iwai 	sw = ucontrol->value.integer.value[0];
1890d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1891d2cd74b1STakashi Iwai 		sw = !sw;
189250164f69SOswald Buddenhagen 	spin_lock_irqsave(&emu->emu_lock, flags);
1893184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1894184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1895184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
1896a1c87c0bSOswald Buddenhagen 		reg = inw(emu->port + A_IOCFG);
1897d2cd74b1STakashi Iwai 		val = sw ? A_IOCFG_GPOUT0 : 0;
18981da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
18991da177e4SLinus Torvalds 		if (change) {
19001da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
19011da177e4SLinus Torvalds 			reg |= val;
1902a1c87c0bSOswald Buddenhagen 			outw(reg | val, emu->port + A_IOCFG);
19031da177e4SLinus Torvalds 		}
19041da177e4SLinus Torvalds 	}
19051da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
1906d2cd74b1STakashi Iwai 	val = sw ? HCFG_GPOUT0 : 0;
19071da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
19081da177e4SLinus Torvalds 	if (change) {
19091da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
19101da177e4SLinus Torvalds 		reg |= val;
19111da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
19121da177e4SLinus Torvalds 	}
191350164f69SOswald Buddenhagen 	spin_unlock_irqrestore(&emu->emu_lock, flags);
19141da177e4SLinus Torvalds 	return change;
19151da177e4SLinus Torvalds }
19161da177e4SLinus Torvalds 
1917f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
19181da177e4SLinus Torvalds {
19191da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
19201da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
19211da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
19221da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
19231da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
19241da177e4SLinus Torvalds };
19251da177e4SLinus Torvalds 
1926f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif =
19271da177e4SLinus Torvalds {
19281da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
19291da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
19301da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
19311da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
19321da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
19331da177e4SLinus Torvalds };
19341da177e4SLinus Torvalds 
193516950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
193616950e09STakashi Iwai 
193716950e09STakashi Iwai #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
193816950e09STakashi Iwai 
193916950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
194016950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
194116950e09STakashi Iwai {
194216950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
194316950e09STakashi Iwai 	unsigned int val;
194416950e09STakashi Iwai 
194516950e09STakashi Iwai 	/* FIXME: better to use a cached version */
194616950e09STakashi Iwai 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
194716950e09STakashi Iwai 	ucontrol->value.integer.value[0] = !!val;
194816950e09STakashi Iwai 	return 0;
194916950e09STakashi Iwai }
195016950e09STakashi Iwai 
195116950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
195216950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
195316950e09STakashi Iwai {
195416950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
195516950e09STakashi Iwai 	unsigned int val;
195616950e09STakashi Iwai 
195716950e09STakashi Iwai 	if (ucontrol->value.integer.value[0])
195816950e09STakashi Iwai 		val = 0x0f0f;
195916950e09STakashi Iwai 	else
196016950e09STakashi Iwai 		val = 0;
196116950e09STakashi Iwai 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
196216950e09STakashi Iwai }
196316950e09STakashi Iwai 
1964f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost =
196516950e09STakashi Iwai {
196616950e09STakashi Iwai 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
19672a52feb1SMaciej S. Szmigiero 	.name =		"Mic Extra Boost",
196816950e09STakashi Iwai 	.info =		snd_audigy_capture_boost_info,
196916950e09STakashi Iwai 	.get =		snd_audigy_capture_boost_get,
197016950e09STakashi Iwai 	.put =		snd_audigy_capture_boost_put
197116950e09STakashi Iwai };
197216950e09STakashi Iwai 
197316950e09STakashi Iwai 
19741da177e4SLinus Torvalds /*
19751da177e4SLinus Torvalds  */
1976eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
19771da177e4SLinus Torvalds {
1978eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
19791da177e4SLinus Torvalds 	emu->ac97 = NULL;
19801da177e4SLinus Torvalds }
19811da177e4SLinus Torvalds 
19821da177e4SLinus Torvalds /*
19831da177e4SLinus Torvalds  */
1984eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
19851da177e4SLinus Torvalds {
1986eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
19871da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
19881da177e4SLinus Torvalds 	strcpy(id.name, name);
19891da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
19901da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
19911da177e4SLinus Torvalds }
19921da177e4SLinus Torvalds 
1993eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
19941da177e4SLinus Torvalds {
1995eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
19961da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
19971da177e4SLinus Torvalds 	strcpy(sid.name, name);
19981da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
19991da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
20001da177e4SLinus Torvalds }
20011da177e4SLinus Torvalds 
2002eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
20031da177e4SLinus Torvalds {
2004eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
20051da177e4SLinus Torvalds 	if (kctl) {
200636476b81SMaciej S. Szmigiero 		snd_ctl_rename(card, kctl, dst);
20071da177e4SLinus Torvalds 		return 0;
20081da177e4SLinus Torvalds 	}
20091da177e4SLinus Torvalds 	return -ENOENT;
20101da177e4SLinus Torvalds }
20111da177e4SLinus Torvalds 
2012e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
201367ed4161SClemens Ladisch 		      int pcm_device, int multi_device)
20141da177e4SLinus Torvalds {
2015155e3d3bSOswald Buddenhagen 	int err;
2016eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
2017eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
20186fddce26STakashi Iwai 	const char * const *c;
20196fddce26STakashi Iwai 	static const char * const emu10k1_remove_ctls[] = {
20201da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
20211da177e4SLinus Torvalds 		"Master Mono Playback Switch",
20221da177e4SLinus Torvalds 		"Master Mono Playback Volume",
20231da177e4SLinus Torvalds 		"PCM Out Path & Mute",
20241da177e4SLinus Torvalds 		"Mono Output Select",
20251da177e4SLinus Torvalds 		"Surround Playback Switch",
20261da177e4SLinus Torvalds 		"Surround Playback Volume",
20271da177e4SLinus Torvalds 		"Center Playback Switch",
20281da177e4SLinus Torvalds 		"Center Playback Volume",
20291da177e4SLinus Torvalds 		"LFE Playback Switch",
20301da177e4SLinus Torvalds 		"LFE Playback Volume",
20311da177e4SLinus Torvalds 		NULL
20321da177e4SLinus Torvalds 	};
20336fddce26STakashi Iwai 	static const char * const emu10k1_rename_ctls[] = {
20341da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
20351da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
20361da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
20371da177e4SLinus Torvalds 		NULL
20381da177e4SLinus Torvalds 	};
20396fddce26STakashi Iwai 	static const char * const audigy_remove_ctls[] = {
20401da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
204121fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
204221fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
20431da177e4SLinus Torvalds 		"PCM Playback Switch",
20441da177e4SLinus Torvalds 		"PCM Playback Volume",
20451da177e4SLinus Torvalds 		"Master Playback Switch",
20461da177e4SLinus Torvalds 		"Master Playback Volume",
20471da177e4SLinus Torvalds 		"PCM Out Path & Mute",
20481da177e4SLinus Torvalds 		"Mono Output Select",
20491da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
20501da177e4SLinus Torvalds 		"Capture Source",
20511da177e4SLinus Torvalds 		"Capture Switch",
20521da177e4SLinus Torvalds 		"Capture Volume",
20531da177e4SLinus Torvalds 		"Mic Select",
2054274b2000SMaciej S. Szmigiero 		"Headphone Playback Switch",
2055274b2000SMaciej S. Szmigiero 		"Headphone Playback Volume",
2056274b2000SMaciej S. Szmigiero 		"3D Control - Center",
2057274b2000SMaciej S. Szmigiero 		"3D Control - Depth",
2058274b2000SMaciej S. Szmigiero 		"3D Control - Switch",
20591da177e4SLinus Torvalds 		"Video Playback Switch",
20601da177e4SLinus Torvalds 		"Video Playback Volume",
20611da177e4SLinus Torvalds 		"Mic Playback Switch",
20621da177e4SLinus Torvalds 		"Mic Playback Volume",
2063274b2000SMaciej S. Szmigiero 		"External Amplifier",
20641da177e4SLinus Torvalds 		NULL
20651da177e4SLinus Torvalds 	};
20666fddce26STakashi Iwai 	static const char * const audigy_rename_ctls[] = {
20671da177e4SLinus Torvalds 		/* use conventional names */
20681da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
20691da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
20701da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
20711da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
207252051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
207352051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
20741da177e4SLinus Torvalds 		NULL
20751da177e4SLinus Torvalds 	};
20766fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_i2c_adc[] = {
2077184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
2078184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
2079184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
2080184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
2081184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
2082eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
2083184c1e2cSJames Courtier-Dutton 		NULL
2084184c1e2cSJames Courtier-Dutton 	};
20856fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_i2c_adc[] = {
2086184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
2087184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
2088184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
2089184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
2090184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
2091eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
2092184c1e2cSJames Courtier-Dutton 		NULL
2093184c1e2cSJames Courtier-Dutton 	};
20946fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_1361t_adc[] = {
209521fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
209621fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
209721fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
209821fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
209921fdddeaSJames Courtier-Dutton 		"Capture Source",
210021fdddeaSJames Courtier-Dutton 		"Capture Switch",
210121fdddeaSJames Courtier-Dutton 		"Capture Volume",
210221fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
210321fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
210421fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
210521fdddeaSJames Courtier-Dutton 		"3D Control - Center",
210621fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
210721fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
210821fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
210921fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
211021fdddeaSJames Courtier-Dutton 		NULL
211121fdddeaSJames Courtier-Dutton 	};
21126fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_1361t_adc[] = {
211321fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
211421fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
211521fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
2116d355c82aSJaroslav Kysela 		"Beep Playback Switch", "Beep Capture Switch",
2117d355c82aSJaroslav Kysela 		"Beep Playback Volume", "Beep Capture Volume",
211821fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
211921fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
212021fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
212121fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
212221fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
212321fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
212421fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
212521fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
212621fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
212721fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
212821fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
212921fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
213052051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
213152051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
213221fdddeaSJames Courtier-Dutton 		NULL
213321fdddeaSJames Courtier-Dutton 	};
21341da177e4SLinus Torvalds 
21352b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
2136eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
2137eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
213851055da5STakashi Iwai 		static const struct snd_ac97_bus_ops ops = {
21391da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
21401da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
21411da177e4SLinus Torvalds 		};
21421da177e4SLinus Torvalds 
214312bda107STakashi Iwai 		err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus);
214412bda107STakashi Iwai 		if (err < 0)
21451da177e4SLinus Torvalds 			return err;
21461da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
21471da177e4SLinus Torvalds 
21481da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
21491da177e4SLinus Torvalds 		ac97.private_data = emu;
21501da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
21511da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
215212bda107STakashi Iwai 		err = snd_ac97_mixer(pbus, &ac97, &emu->ac97);
215312bda107STakashi Iwai 		if (err < 0) {
2154b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
21551da177e4SLinus Torvalds 				return err;
21566f002b02STakashi Iwai 			dev_info(emu->card->dev,
21576f002b02STakashi Iwai 				 "AC97 is optional on this board\n");
21586f002b02STakashi Iwai 			dev_info(emu->card->dev,
21596f002b02STakashi Iwai 				 "Proceeding without ac97 mixers...\n");
2160b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
2161b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
2162b1508693STakashi Iwai 		}
21631da177e4SLinus Torvalds 		if (emu->audigy) {
21641da177e4SLinus Torvalds 			/* set master volume to 0 dB */
21654d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
21661da177e4SLinus Torvalds 			/* set capture source to mic */
21674d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
216852051942SMaciej S. Szmigiero 			/* set mono output (TAD) to mic */
216952051942SMaciej S. Szmigiero 			snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE,
217052051942SMaciej S. Szmigiero 				0x0200, 0x0200);
217121fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
217221fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
217321fdddeaSJames Courtier-Dutton 			else
21741da177e4SLinus Torvalds 				c = audigy_remove_ctls;
21751da177e4SLinus Torvalds 		} else {
21761da177e4SLinus Torvalds 			/*
21771da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
21781da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
21791da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
21801da177e4SLinus Torvalds 			 */
21811da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
21821da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
21831da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
21842594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
2185b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Volume");
2186b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Switch");
21871da177e4SLinus Torvalds 			}
21881da177e4SLinus Torvalds 			/* remove unused AC97 controls */
21894d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
21904d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
21911da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
21921da177e4SLinus Torvalds 		}
21931da177e4SLinus Torvalds 		for (; *c; c++)
21941da177e4SLinus Torvalds 			remove_ctl(card, *c);
2195184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
2196184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
2197184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
2198184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
21991da177e4SLinus Torvalds 	} else {
2200f12aa40cSTakashi Iwai 	no_ac97:
22012b637da5SLee Revell 		if (emu->card_capabilities->ecard)
22021da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
22031da177e4SLinus Torvalds 		else if (emu->audigy)
22041da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
22051da177e4SLinus Torvalds 		else
22061da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
22071da177e4SLinus Torvalds 	}
22081da177e4SLinus Torvalds 
22091da177e4SLinus Torvalds 	if (emu->audigy)
221021fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
221121fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
2212184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
2213184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
221421fdddeaSJames Courtier-Dutton 		else
22151da177e4SLinus Torvalds 			c = audigy_rename_ctls;
22161da177e4SLinus Torvalds 	else
22171da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
22181da177e4SLinus Torvalds 	for (; *c; c += 2)
22191da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
222021fdddeaSJames Courtier-Dutton 
2221e217b960SRaymond Yau 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
2222e217b960SRaymond Yau 		remove_ctl(card, "Center Playback Volume");
2223e217b960SRaymond Yau 		remove_ctl(card, "LFE Playback Volume");
2224e217b960SRaymond Yau 		remove_ctl(card, "Wave Center Playback Volume");
2225e217b960SRaymond Yau 		remove_ctl(card, "Wave LFE Playback Volume");
2226e217b960SRaymond Yau 	}
2227e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
2228e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
2229e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
2230e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
2231e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
2232e3b9bc0eSJames Courtier-Dutton 	}
223312bda107STakashi Iwai 	kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu);
223412bda107STakashi Iwai 	if (!kctl)
22351da177e4SLinus Torvalds 		return -ENOMEM;
223667ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
223712bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
223812bda107STakashi Iwai 	if (err)
22391da177e4SLinus Torvalds 		return err;
224012bda107STakashi Iwai 	kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu);
224112bda107STakashi Iwai 	if (!kctl)
22421da177e4SLinus Torvalds 		return -ENOMEM;
224367ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
224412bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
224512bda107STakashi Iwai 	if (err)
22461da177e4SLinus Torvalds 		return err;
224712bda107STakashi Iwai 	kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu);
224812bda107STakashi Iwai 	if (!kctl)
22491da177e4SLinus Torvalds 		return -ENOMEM;
225067ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
225112bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
225212bda107STakashi Iwai 	if (err)
22531da177e4SLinus Torvalds 		return err;
22541da177e4SLinus Torvalds 
225512bda107STakashi Iwai 	kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu);
225612bda107STakashi Iwai 	if (!kctl)
22571da177e4SLinus Torvalds 		return -ENOMEM;
225867ed4161SClemens Ladisch 	kctl->id.device = multi_device;
225912bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
226012bda107STakashi Iwai 	if (err)
22611da177e4SLinus Torvalds 		return err;
22621da177e4SLinus Torvalds 
226312bda107STakashi Iwai 	kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu);
226412bda107STakashi Iwai 	if (!kctl)
22651da177e4SLinus Torvalds 		return -ENOMEM;
226667ed4161SClemens Ladisch 	kctl->id.device = multi_device;
226712bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
226812bda107STakashi Iwai 	if (err)
22691da177e4SLinus Torvalds 		return err;
22701da177e4SLinus Torvalds 
227112bda107STakashi Iwai 	kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu);
227212bda107STakashi Iwai 	if (!kctl)
22731da177e4SLinus Torvalds 		return -ENOMEM;
227467ed4161SClemens Ladisch 	kctl->id.device = multi_device;
227512bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
227612bda107STakashi Iwai 	if (err)
22771da177e4SLinus Torvalds 		return err;
22781da177e4SLinus Torvalds 
2279a8661af5SOswald Buddenhagen 	if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) {
22801da177e4SLinus Torvalds 		/* sb live! and audigy */
228112bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu);
228212bda107STakashi Iwai 		if (!kctl)
22831da177e4SLinus Torvalds 			return -ENOMEM;
22845549d549SClemens Ladisch 		if (!emu->audigy)
22855549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
228612bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
228712bda107STakashi Iwai 		if (err)
22881da177e4SLinus Torvalds 			return err;
228912bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu);
229012bda107STakashi Iwai 		if (!kctl)
22911da177e4SLinus Torvalds 			return -ENOMEM;
22925549d549SClemens Ladisch 		if (!emu->audigy)
22935549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
229412bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
229512bda107STakashi Iwai 		if (err)
22961da177e4SLinus Torvalds 			return err;
22971da177e4SLinus Torvalds 	}
22981da177e4SLinus Torvalds 
2299190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
230019b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
230119b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
230212bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu);
230312bda107STakashi Iwai 		if (!kctl)
23041da177e4SLinus Torvalds 			return -ENOMEM;
230512bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
230612bda107STakashi Iwai 		if (err)
23071da177e4SLinus Torvalds 			return err;
2308001f7589SJames Courtier-Dutton #if 0
230912bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu);
231012bda107STakashi Iwai 		if (!kctl)
23111da177e4SLinus Torvalds 			return -ENOMEM;
231212bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
231312bda107STakashi Iwai 		if (err)
23141da177e4SLinus Torvalds 			return err;
2315001f7589SJames Courtier-Dutton #endif
23162b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
23171da177e4SLinus Torvalds 		/* sb live! */
231812bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu);
231912bda107STakashi Iwai 		if (!kctl)
23201da177e4SLinus Torvalds 			return -ENOMEM;
232112bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
232212bda107STakashi Iwai 		if (err)
23231da177e4SLinus Torvalds 			return err;
23241da177e4SLinus Torvalds 	}
23252b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
232612bda107STakashi Iwai 		err = snd_p16v_mixer(emu);
232712bda107STakashi Iwai 		if (err)
23281da177e4SLinus Torvalds 			return err;
23291da177e4SLinus Torvalds 	}
23301da177e4SLinus Torvalds 
23311fc710f0SOswald Buddenhagen 	if (emu->card_capabilities->emu_model) {
23321fc710f0SOswald Buddenhagen 		unsigned i, emu_idx = emu1010_idx(emu);
23331fc710f0SOswald Buddenhagen 		const struct snd_emu1010_routing_info *emu_ri =
23341fc710f0SOswald Buddenhagen 			&emu1010_routing_info[emu_idx];
233597f1582eSOswald Buddenhagen 		const struct snd_emu1010_pads_info *emu_pi = &emu1010_pads_info[emu_idx];
23361fc710f0SOswald Buddenhagen 
23371fc710f0SOswald Buddenhagen 		for (i = 0; i < emu_ri->n_ins; i++)
23381fc710f0SOswald Buddenhagen 			emu->emu1010.input_source[i] =
23391fc710f0SOswald Buddenhagen 				emu1010_map_source(emu_ri, emu_ri->in_dflts[i]);
23401fc710f0SOswald Buddenhagen 		for (i = 0; i < emu_ri->n_outs; i++)
23411fc710f0SOswald Buddenhagen 			emu->emu1010.output_source[i] =
23421fc710f0SOswald Buddenhagen 				emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
23431fc710f0SOswald Buddenhagen 		snd_emu1010_apply_sources(emu);
23441fc710f0SOswald Buddenhagen 
23451c02e366SCtirad Fertr 		err = snd_ctl_add(card,
234613598862SOswald Buddenhagen 			snd_ctl_new1(&snd_emu1010_clock_source, emu));
234713598862SOswald Buddenhagen 		if (err < 0)
234813598862SOswald Buddenhagen 			return err;
234913598862SOswald Buddenhagen 		err = snd_ctl_add(card,
235013598862SOswald Buddenhagen 			snd_ctl_new1(&snd_emu1010_clock_fallback, emu));
23511c02e366SCtirad Fertr 		if (err < 0)
23521c02e366SCtirad Fertr 			return err;
235397f1582eSOswald Buddenhagen 
235497f1582eSOswald Buddenhagen 		err = add_ctls(emu, &emu1010_adc_pads_ctl,
235597f1582eSOswald Buddenhagen 			       emu_pi->adc_ctls, emu_pi->n_adc_ctls);
235697f1582eSOswald Buddenhagen 		if (err < 0)
235797f1582eSOswald Buddenhagen 			return err;
235897f1582eSOswald Buddenhagen 		err = add_ctls(emu, &emu1010_dac_pads_ctl,
235997f1582eSOswald Buddenhagen 			       emu_pi->dac_ctls, emu_pi->n_dac_ctls);
236097f1582eSOswald Buddenhagen 		if (err < 0)
236197f1582eSOswald Buddenhagen 			return err;
236297f1582eSOswald Buddenhagen 
23636f3609f8SOswald Buddenhagen 		if (!emu->card_capabilities->no_adat) {
236499dcab46SMichael Gernoth 			err = snd_ctl_add(card,
236599dcab46SMichael Gernoth 				snd_ctl_new1(&snd_emu1010_optical_out, emu));
236699dcab46SMichael Gernoth 			if (err < 0)
236799dcab46SMichael Gernoth 				return err;
236899dcab46SMichael Gernoth 			err = snd_ctl_add(card,
236999dcab46SMichael Gernoth 				snd_ctl_new1(&snd_emu1010_optical_in, emu));
237099dcab46SMichael Gernoth 			if (err < 0)
237199dcab46SMichael Gernoth 				return err;
23726f3609f8SOswald Buddenhagen 		}
23731c02e366SCtirad Fertr 
237497f1582eSOswald Buddenhagen 		err = add_emu1010_source_mixers(emu);
237599dcab46SMichael Gernoth 		if (err < 0)
237699dcab46SMichael Gernoth 			return err;
23779f4bd5ddSJames Courtier-Dutton 	}
23789f4bd5ddSJames Courtier-Dutton 
2379184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2380184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2381184c1e2cSJames Courtier-Dutton 		if (err < 0)
2382184c1e2cSJames Courtier-Dutton 			return err;
2383184c1e2cSJames Courtier-Dutton 
2384536438f1SOswald Buddenhagen 		err = add_ctls(emu, &i2c_volume_ctl,
2385536438f1SOswald Buddenhagen 			       snd_audigy_i2c_volume_ctls,
2386536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_audigy_i2c_volume_ctls));
2387184c1e2cSJames Courtier-Dutton 		if (err < 0)
2388184c1e2cSJames Courtier-Dutton 			return err;
2389184c1e2cSJames Courtier-Dutton 	}
2390184c1e2cSJames Courtier-Dutton 
239116950e09STakashi Iwai 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
239216950e09STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
239316950e09STakashi Iwai 						     emu));
239416950e09STakashi Iwai 		if (err < 0)
239516950e09STakashi Iwai 			return err;
239616950e09STakashi Iwai 	}
239716950e09STakashi Iwai 
23981da177e4SLinus Torvalds 	return 0;
23991da177e4SLinus Torvalds }
2400