xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision aa9e9180)
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>
56d68d9cbSOswald Buddenhagen  *                   Lee Revell <rlrevell@joe-job.com>
66d68d9cbSOswald Buddenhagen  *                   James Courtier-Dutton <James@superbug.co.uk>
76d68d9cbSOswald Buddenhagen  *                   Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
81da177e4SLinus Torvalds  *                   Creative Labs, Inc.
91da177e4SLinus Torvalds  *
106d68d9cbSOswald Buddenhagen  *  Routines for control of EMU10K1 chips / mixer routines
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds #include <linux/time.h>
141da177e4SLinus Torvalds #include <linux/init.h>
151da177e4SLinus Torvalds #include <sound/core.h>
161da177e4SLinus Torvalds #include <sound/emu10k1.h>
17b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h>
18184c1e2cSJames Courtier-Dutton #include <sound/tlv.h>
19184c1e2cSJames Courtier-Dutton 
20184c1e2cSJames Courtier-Dutton #include "p17v.h"
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds #define AC97_ID_STAC9758	0x83847658
231da177e4SLinus Torvalds 
240cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
25184c1e2cSJames Courtier-Dutton 
26536438f1SOswald Buddenhagen 
add_ctls(struct snd_emu10k1 * emu,const struct snd_kcontrol_new * tpl,const char * const * ctls,unsigned nctls)27536438f1SOswald Buddenhagen static int add_ctls(struct snd_emu10k1 *emu, const struct snd_kcontrol_new *tpl,
28536438f1SOswald Buddenhagen 		    const char * const *ctls, unsigned nctls)
29536438f1SOswald Buddenhagen {
30536438f1SOswald Buddenhagen 	struct snd_kcontrol_new kctl = *tpl;
31536438f1SOswald Buddenhagen 	int err;
32536438f1SOswald Buddenhagen 
33536438f1SOswald Buddenhagen 	for (unsigned i = 0; i < nctls; i++) {
34536438f1SOswald Buddenhagen 		kctl.name = ctls[i];
35536438f1SOswald Buddenhagen 		kctl.private_value = i;
36536438f1SOswald Buddenhagen 		err = snd_ctl_add(emu->card, snd_ctl_new1(&kctl, emu));
37536438f1SOswald Buddenhagen 		if (err < 0)
38536438f1SOswald Buddenhagen 			return err;
39536438f1SOswald Buddenhagen 	}
40536438f1SOswald Buddenhagen 	return 0;
41536438f1SOswald Buddenhagen }
42536438f1SOswald Buddenhagen 
43536438f1SOswald Buddenhagen 
snd_emu10k1_spdif_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)44eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
451da177e4SLinus Torvalds {
461da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
471da177e4SLinus Torvalds 	uinfo->count = 1;
481da177e4SLinus Torvalds 	return 0;
491da177e4SLinus Torvalds }
501da177e4SLinus Torvalds 
snd_emu10k1_spdif_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)51eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
52eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
531da177e4SLinus Torvalds {
54eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
551da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
561da177e4SLinus Torvalds 
5774415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
5874415a36SJames Courtier-Dutton 	if (idx >= 3)
5974415a36SJames Courtier-Dutton 		return -EINVAL;
601da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
611da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
621da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
631da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
641da177e4SLinus Torvalds 	return 0;
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds 
snd_emu10k1_spdif_get_mask(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)67eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
68eb4698f3STakashi Iwai 				      struct snd_ctl_elem_value *ucontrol)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
711da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
721da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
731da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
741da177e4SLinus Torvalds 	return 0;
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds 
77dc39bb3eSOswald Buddenhagen #define PAIR_PS(base, one, two, sfx) base " " one sfx, base " " two sfx
78dc39bb3eSOswald Buddenhagen #define LR_PS(base, sfx) PAIR_PS(base, "Left", "Right", sfx)
799f4bd5ddSJames Courtier-Dutton 
80dc39bb3eSOswald Buddenhagen #define ADAT_PS(pfx, sfx) \
81dc39bb3eSOswald Buddenhagen 	pfx "ADAT 0" sfx, pfx "ADAT 1" sfx, pfx "ADAT 2" sfx, pfx "ADAT 3" sfx, \
82dc39bb3eSOswald Buddenhagen 	pfx "ADAT 4" sfx, pfx "ADAT 5" sfx, pfx "ADAT 6" sfx, pfx "ADAT 7" sfx
831c02e366SCtirad Fertr 
84dc39bb3eSOswald Buddenhagen #define PAIR_REGS(base, one, two) \
85dc39bb3eSOswald Buddenhagen 	base ## one ## 1, \
86dc39bb3eSOswald Buddenhagen 	base ## two ## 1
871c02e366SCtirad Fertr 
88dc39bb3eSOswald Buddenhagen #define LR_REGS(base) PAIR_REGS(base, _LEFT, _RIGHT)
89dc39bb3eSOswald Buddenhagen 
90dc39bb3eSOswald Buddenhagen #define ADAT_REGS(base) \
91dc39bb3eSOswald Buddenhagen 	base+0, base+1, base+2, base+3, base+4, base+5, base+6, base+7
921c02e366SCtirad Fertr 
9313d45709SPavel Hofman /*
9413d45709SPavel Hofman  * List of data sources available for each destination
9513d45709SPavel Hofman  */
96dc39bb3eSOswald Buddenhagen 
97dc39bb3eSOswald Buddenhagen #define DSP_TEXTS \
98dc39bb3eSOswald Buddenhagen 	"DSP 0", "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", \
99dc39bb3eSOswald Buddenhagen 	"DSP 8", "DSP 9", "DSP 10", "DSP 11", "DSP 12", "DSP 13", "DSP 14", "DSP 15", \
100dc39bb3eSOswald Buddenhagen 	"DSP 16", "DSP 17", "DSP 18", "DSP 19", "DSP 20", "DSP 21", "DSP 22", "DSP 23", \
101dc39bb3eSOswald Buddenhagen 	"DSP 24", "DSP 25", "DSP 26", "DSP 27", "DSP 28", "DSP 29", "DSP 30", "DSP 31"
102dc39bb3eSOswald Buddenhagen 
103dc39bb3eSOswald Buddenhagen #define PAIR_TEXTS(base, one, two) PAIR_PS(base, one, two, "")
104dc39bb3eSOswald Buddenhagen #define LR_TEXTS(base) LR_PS(base, "")
105dc39bb3eSOswald Buddenhagen #define ADAT_TEXTS(pfx) ADAT_PS(pfx, "")
106dc39bb3eSOswald Buddenhagen 
107dc39bb3eSOswald Buddenhagen #define EMU32_SRC_REGS \
108dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A, \
109dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+1, \
110dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, \
111dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+3, \
112dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, \
113dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+5, \
114dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+6, \
115dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+7, \
116dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+8, \
117dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+9, \
118dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xa, \
119dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xb, \
120dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xc, \
121dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xd, \
122dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xe, \
123dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xf, \
124dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B, \
125dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+1, \
126dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+2, \
127dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+3, \
128dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+4, \
129dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+5, \
130dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+6, \
131dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+7, \
132dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+8, \
133dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+9, \
134dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xa, \
135dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xb, \
136dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xc, \
137dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xd, \
138dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xe, \
139dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xf
140dc39bb3eSOswald Buddenhagen 
1416f3609f8SOswald Buddenhagen /* 1010 rev1 */
1426f3609f8SOswald Buddenhagen 
143dc39bb3eSOswald Buddenhagen #define EMU1010_COMMON_TEXTS \
144dc39bb3eSOswald Buddenhagen 	"Silence", \
145dc39bb3eSOswald Buddenhagen 	PAIR_TEXTS("Dock Mic", "A", "B"), \
146dc39bb3eSOswald Buddenhagen 	LR_TEXTS("Dock ADC1"), \
147dc39bb3eSOswald Buddenhagen 	LR_TEXTS("Dock ADC2"), \
148dc39bb3eSOswald Buddenhagen 	LR_TEXTS("Dock ADC3"), \
149dc39bb3eSOswald Buddenhagen 	LR_TEXTS("0202 ADC"), \
150dc39bb3eSOswald Buddenhagen 	LR_TEXTS("1010 SPDIF"), \
151dc39bb3eSOswald Buddenhagen 	ADAT_TEXTS("1010 ")
152dc39bb3eSOswald Buddenhagen 
153dc39bb3eSOswald Buddenhagen static const char * const emu1010_src_texts[] = {
154dc39bb3eSOswald Buddenhagen 	EMU1010_COMMON_TEXTS,
155dc39bb3eSOswald Buddenhagen 	DSP_TEXTS,
1569f4bd5ddSJames Courtier-Dutton };
1579f4bd5ddSJames Courtier-Dutton 
158dc39bb3eSOswald Buddenhagen static const unsigned short emu1010_src_regs[] = {
159dc39bb3eSOswald Buddenhagen 	EMU_SRC_SILENCE,
160dc39bb3eSOswald Buddenhagen 	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
161dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC1),
162dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC2),
163dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC3),
164dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_HAMOA_ADC),
165dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_HANA_SPDIF),
166dc39bb3eSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_HANA_ADAT),
167dc39bb3eSOswald Buddenhagen 	EMU32_SRC_REGS,
168dc39bb3eSOswald Buddenhagen };
169dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_src_regs) == ARRAY_SIZE(emu1010_src_texts));
170dc39bb3eSOswald Buddenhagen 
171f69d705dSOswald Buddenhagen /* 1010 rev2 */
172f69d705dSOswald Buddenhagen 
173f69d705dSOswald Buddenhagen #define EMU1010b_COMMON_TEXTS \
174f69d705dSOswald Buddenhagen 	"Silence", \
175f69d705dSOswald Buddenhagen 	PAIR_TEXTS("Dock Mic", "A", "B"), \
176f69d705dSOswald Buddenhagen 	LR_TEXTS("Dock ADC1"), \
177f69d705dSOswald Buddenhagen 	LR_TEXTS("Dock ADC2"), \
178f69d705dSOswald Buddenhagen 	LR_TEXTS("0202 ADC"), \
179f69d705dSOswald Buddenhagen 	LR_TEXTS("Dock SPDIF"), \
180f69d705dSOswald Buddenhagen 	LR_TEXTS("1010 SPDIF"), \
181f69d705dSOswald Buddenhagen 	ADAT_TEXTS("Dock "), \
182f69d705dSOswald Buddenhagen 	ADAT_TEXTS("1010 ")
183f69d705dSOswald Buddenhagen 
184f69d705dSOswald Buddenhagen static const char * const emu1010b_src_texts[] = {
185f69d705dSOswald Buddenhagen 	EMU1010b_COMMON_TEXTS,
186f69d705dSOswald Buddenhagen 	DSP_TEXTS,
187f69d705dSOswald Buddenhagen };
188f69d705dSOswald Buddenhagen 
189f69d705dSOswald Buddenhagen static const unsigned short emu1010b_src_regs[] = {
190f69d705dSOswald Buddenhagen 	EMU_SRC_SILENCE,
191f69d705dSOswald Buddenhagen 	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
192f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC1),
193f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC2),
194f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_HAMOA_ADC),
195f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_MDOCK_SPDIF),
196f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_HANA_SPDIF),
197f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_MDOCK_ADAT),
198f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_HANA_ADAT),
199f69d705dSOswald Buddenhagen 	EMU32_SRC_REGS,
200f69d705dSOswald Buddenhagen };
201f69d705dSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010b_src_regs) == ARRAY_SIZE(emu1010b_src_texts));
202f69d705dSOswald Buddenhagen 
2031c02e366SCtirad Fertr /* 1616(m) cardbus */
204dc39bb3eSOswald Buddenhagen 
205dc39bb3eSOswald Buddenhagen #define EMU1616_COMMON_TEXTS \
206dc39bb3eSOswald Buddenhagen 	"Silence", \
207dc39bb3eSOswald Buddenhagen 	PAIR_TEXTS("Mic", "A", "B"), \
208dc39bb3eSOswald Buddenhagen 	LR_TEXTS("ADC1"), \
209dc39bb3eSOswald Buddenhagen 	LR_TEXTS("ADC2"), \
210dc39bb3eSOswald Buddenhagen 	LR_TEXTS("SPDIF"), \
211dc39bb3eSOswald Buddenhagen 	ADAT_TEXTS("")
212dc39bb3eSOswald Buddenhagen 
213dc39bb3eSOswald Buddenhagen static const char * const emu1616_src_texts[] = {
214dc39bb3eSOswald Buddenhagen 	EMU1616_COMMON_TEXTS,
215dc39bb3eSOswald Buddenhagen 	DSP_TEXTS,
216dc39bb3eSOswald Buddenhagen };
217dc39bb3eSOswald Buddenhagen 
2189b00a1e9SOswald Buddenhagen static const unsigned short emu1616_src_regs[] = {
2191c02e366SCtirad Fertr 	EMU_SRC_SILENCE,
220dc39bb3eSOswald Buddenhagen 	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
221dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC1),
222dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC2),
223dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_MDOCK_SPDIF),
224dc39bb3eSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_MDOCK_ADAT),
225dc39bb3eSOswald Buddenhagen 	EMU32_SRC_REGS,
2261c02e366SCtirad Fertr };
227dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_src_regs) == ARRAY_SIZE(emu1616_src_texts));
2281c02e366SCtirad Fertr 
2296f3609f8SOswald Buddenhagen /* 0404 rev1 & rev2 */
2306f3609f8SOswald Buddenhagen 
2316f3609f8SOswald Buddenhagen #define EMU0404_COMMON_TEXTS \
2326f3609f8SOswald Buddenhagen 	"Silence", \
2336f3609f8SOswald Buddenhagen 	LR_TEXTS("ADC"), \
2346f3609f8SOswald Buddenhagen 	LR_TEXTS("SPDIF")
2356f3609f8SOswald Buddenhagen 
2366f3609f8SOswald Buddenhagen static const char * const emu0404_src_texts[] = {
2376f3609f8SOswald Buddenhagen 	EMU0404_COMMON_TEXTS,
2386f3609f8SOswald Buddenhagen 	DSP_TEXTS,
2396f3609f8SOswald Buddenhagen };
2406f3609f8SOswald Buddenhagen 
2416f3609f8SOswald Buddenhagen static const unsigned short emu0404_src_regs[] = {
2426f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
2436f3609f8SOswald Buddenhagen 	LR_REGS(EMU_SRC_HAMOA_ADC),
2446f3609f8SOswald Buddenhagen 	LR_REGS(EMU_SRC_HANA_SPDIF),
2456f3609f8SOswald Buddenhagen 	EMU32_SRC_REGS,
2466f3609f8SOswald Buddenhagen };
2476f3609f8SOswald Buddenhagen static_assert(ARRAY_SIZE(emu0404_src_regs) == ARRAY_SIZE(emu0404_src_texts));
2486f3609f8SOswald Buddenhagen 
24913d45709SPavel Hofman /*
25013d45709SPavel Hofman  * Data destinations - physical EMU outputs.
25113d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
25213d45709SPavel Hofman  */
253536438f1SOswald Buddenhagen 
254536438f1SOswald Buddenhagen #define LR_CTLS(base) LR_PS(base, " Playback Enum")
255536438f1SOswald Buddenhagen #define ADAT_CTLS(pfx) ADAT_PS(pfx, " Playback Enum")
256536438f1SOswald Buddenhagen 
2576f3609f8SOswald Buddenhagen /* 1010 rev1 */
2586f3609f8SOswald Buddenhagen 
259536438f1SOswald Buddenhagen static const char * const emu1010_output_texts[] = {
260536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
261536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
262536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
263536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC4"),
264536438f1SOswald Buddenhagen 	LR_CTLS("Dock Phones"),
265536438f1SOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
266536438f1SOswald Buddenhagen 	LR_CTLS("0202 DAC"),
267536438f1SOswald Buddenhagen 	LR_CTLS("1010 SPDIF"),
268536438f1SOswald Buddenhagen 	ADAT_CTLS("1010 "),
2699f4bd5ddSJames Courtier-Dutton };
270216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_texts) <= NUM_OUTPUT_DESTS);
2719f4bd5ddSJames Courtier-Dutton 
272536438f1SOswald Buddenhagen static const unsigned short emu1010_output_dst[] = {
273536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
274536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
275536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
276536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC4),
277536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_PHONES),
278536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_SPDIF),
279536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
280536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
281536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_HANA_ADAT),
2821c02e366SCtirad Fertr };
283536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dst) == ARRAY_SIZE(emu1010_output_texts));
284536438f1SOswald Buddenhagen 
2851fc710f0SOswald Buddenhagen static const unsigned short emu1010_output_dflt[] = {
2861fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2871fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
2881fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
2891fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
2901fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2911fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2921fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2931fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2941fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
2951fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
2961fc710f0SOswald Buddenhagen };
2971fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dflt) == ARRAY_SIZE(emu1010_output_dst));
2981fc710f0SOswald Buddenhagen 
299f69d705dSOswald Buddenhagen /* 1010 rev2 */
300f69d705dSOswald Buddenhagen 
301f69d705dSOswald Buddenhagen static const char * const snd_emu1010b_output_texts[] = {
302f69d705dSOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
303f69d705dSOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
304f69d705dSOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
305f69d705dSOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
306f69d705dSOswald Buddenhagen 	ADAT_CTLS("Dock "),
307f69d705dSOswald Buddenhagen 	LR_CTLS("0202 DAC"),
308f69d705dSOswald Buddenhagen 	LR_CTLS("1010 SPDIF"),
309f69d705dSOswald Buddenhagen 	ADAT_CTLS("1010 "),
310f69d705dSOswald Buddenhagen };
311216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(snd_emu1010b_output_texts) <= NUM_OUTPUT_DESTS);
312f69d705dSOswald Buddenhagen 
313f69d705dSOswald Buddenhagen static const unsigned short emu1010b_output_dst[] = {
314f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
315f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
316f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
317f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_MDOCK_SPDIF),
318f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_DST_MDOCK_ADAT),
319f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
320f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
321f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_DST_HANA_ADAT),
322f69d705dSOswald Buddenhagen };
323f69d705dSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010b_output_dst) == ARRAY_SIZE(snd_emu1010b_output_texts));
324f69d705dSOswald Buddenhagen 
325f69d705dSOswald Buddenhagen static const unsigned short emu1010b_output_dflt[] = {
326f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
327f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
328f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
329f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
330f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
331f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
332f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
333f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
334f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
335f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
336f69d705dSOswald Buddenhagen };
337f69d705dSOswald Buddenhagen 
338536438f1SOswald Buddenhagen /* 1616(m) cardbus */
339536438f1SOswald Buddenhagen 
340536438f1SOswald Buddenhagen static const char * const snd_emu1616_output_texts[] = {
341536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
342536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
343536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
344536438f1SOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
345536438f1SOswald Buddenhagen 	ADAT_CTLS("Dock "),
346536438f1SOswald Buddenhagen 	LR_CTLS("Mana DAC"),
347536438f1SOswald Buddenhagen };
348216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(snd_emu1616_output_texts) <= NUM_OUTPUT_DESTS);
349536438f1SOswald Buddenhagen 
350536438f1SOswald Buddenhagen static const unsigned short emu1616_output_dst[] = {
351536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
352536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
353536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
354536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_MDOCK_SPDIF),
355536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_MDOCK_ADAT),
356536438f1SOswald Buddenhagen 	EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT,
357536438f1SOswald Buddenhagen };
358536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dst) == ARRAY_SIZE(snd_emu1616_output_texts));
3591c02e366SCtirad Fertr 
3601fc710f0SOswald Buddenhagen static const unsigned short emu1616_output_dflt[] = {
3611fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3621fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
3631fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
3641fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3651fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
3661fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
3671fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3681fc710f0SOswald Buddenhagen };
3691fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dflt) == ARRAY_SIZE(emu1616_output_dst));
3701fc710f0SOswald Buddenhagen 
3716f3609f8SOswald Buddenhagen /* 0404 rev1 & rev2 */
3726f3609f8SOswald Buddenhagen 
3736f3609f8SOswald Buddenhagen static const char * const snd_emu0404_output_texts[] = {
3746f3609f8SOswald Buddenhagen 	LR_CTLS("DAC"),
3756f3609f8SOswald Buddenhagen 	LR_CTLS("SPDIF"),
3766f3609f8SOswald Buddenhagen };
377216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(snd_emu0404_output_texts) <= NUM_OUTPUT_DESTS);
3786f3609f8SOswald Buddenhagen 
3796f3609f8SOswald Buddenhagen static const unsigned short emu0404_output_dst[] = {
3806f3609f8SOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
3816f3609f8SOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
3826f3609f8SOswald Buddenhagen };
3836f3609f8SOswald Buddenhagen static_assert(ARRAY_SIZE(emu0404_output_dst) == ARRAY_SIZE(snd_emu0404_output_texts));
3846f3609f8SOswald Buddenhagen 
3856f3609f8SOswald Buddenhagen static const unsigned short emu0404_output_dflt[] = {
3866f3609f8SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3876f3609f8SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3886f3609f8SOswald Buddenhagen };
3896f3609f8SOswald Buddenhagen static_assert(ARRAY_SIZE(emu0404_output_dflt) == ARRAY_SIZE(emu0404_output_dst));
3906f3609f8SOswald Buddenhagen 
39113d45709SPavel Hofman /*
392a869057cSOswald Buddenhagen  * Data destinations - FPGA outputs going to Alice2 (Audigy) for
39313d45709SPavel Hofman  *   capture (EMU32 + I2S links)
39413d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
39513d45709SPavel Hofman  */
396536438f1SOswald Buddenhagen 
397536438f1SOswald Buddenhagen static const char * const emu1010_input_texts[] = {
398536438f1SOswald Buddenhagen 	"DSP 0 Capture Enum",
399536438f1SOswald Buddenhagen 	"DSP 1 Capture Enum",
400536438f1SOswald Buddenhagen 	"DSP 2 Capture Enum",
401536438f1SOswald Buddenhagen 	"DSP 3 Capture Enum",
402536438f1SOswald Buddenhagen 	"DSP 4 Capture Enum",
403536438f1SOswald Buddenhagen 	"DSP 5 Capture Enum",
404536438f1SOswald Buddenhagen 	"DSP 6 Capture Enum",
405536438f1SOswald Buddenhagen 	"DSP 7 Capture Enum",
406536438f1SOswald Buddenhagen 	"DSP 8 Capture Enum",
407536438f1SOswald Buddenhagen 	"DSP 9 Capture Enum",
408536438f1SOswald Buddenhagen 	"DSP A Capture Enum",
409536438f1SOswald Buddenhagen 	"DSP B Capture Enum",
410536438f1SOswald Buddenhagen 	"DSP C Capture Enum",
411536438f1SOswald Buddenhagen 	"DSP D Capture Enum",
412536438f1SOswald Buddenhagen 	"DSP E Capture Enum",
413536438f1SOswald Buddenhagen 	"DSP F Capture Enum",
414536438f1SOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
415536438f1SOswald Buddenhagen 	"DSP 10 Capture Enum",
416536438f1SOswald Buddenhagen 	"DSP 11 Capture Enum",
417536438f1SOswald Buddenhagen 	"DSP 12 Capture Enum",
418536438f1SOswald Buddenhagen 	"DSP 13 Capture Enum",
419536438f1SOswald Buddenhagen 	"DSP 14 Capture Enum",
420536438f1SOswald Buddenhagen 	"DSP 15 Capture Enum",
421536438f1SOswald Buddenhagen };
422216abe45SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_texts) <= NUM_INPUT_DESTS);
423536438f1SOswald Buddenhagen 
4249b00a1e9SOswald Buddenhagen static const unsigned short emu1010_input_dst[] = {
4259f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_0,
4269f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_1,
4279f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_2,
4289f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_3,
4299f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_4,
4309f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_5,
4319f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_6,
4329f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_7,
4339f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_8,
4349f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_9,
4359f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_A,
4369f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_B,
4379f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_C,
4389f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_D,
4399f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_E,
4409f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_F,
441a869057cSOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
4429f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_LEFT,
4439f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_RIGHT,
4449f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_LEFT,
4459f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_RIGHT,
4469f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_LEFT,
4479f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_RIGHT,
4489f4bd5ddSJames Courtier-Dutton };
449536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts));
4509f4bd5ddSJames Courtier-Dutton 
4511fc710f0SOswald Buddenhagen static const unsigned short emu1010_input_dflt[] = {
4521fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_A1,
4531fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_B1,
4541fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
4551fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
4561fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
4571fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
4581fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
4591fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
4601fc710f0SOswald Buddenhagen 	/* Pavel Hofman - setting defaults for all capture channels.
4611fc710f0SOswald Buddenhagen 	 * Defaults only, users will set their own values anyways, let's
4621fc710f0SOswald Buddenhagen 	 * just copy/paste. */
4631fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_A1,
4641fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_B1,
4651fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
4661fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
4671fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
4681fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
4691fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
4701fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
4711fc710f0SOswald Buddenhagen 
4721fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
4731fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
4741fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
4751fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
4761fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC3_LEFT1,
4771fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC3_RIGHT1,
4781fc710f0SOswald Buddenhagen };
4791fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dflt) == ARRAY_SIZE(emu1010_input_dst));
4801fc710f0SOswald Buddenhagen 
4816f3609f8SOswald Buddenhagen static const unsigned short emu0404_input_dflt[] = {
4826f3609f8SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
4836f3609f8SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
4846f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4856f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4866f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4876f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4886f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4896f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4906f3609f8SOswald Buddenhagen 	EMU_SRC_HANA_SPDIF_LEFT1,
4916f3609f8SOswald Buddenhagen 	EMU_SRC_HANA_SPDIF_RIGHT1,
4926f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4936f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4946f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4956f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4966f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4976f3609f8SOswald Buddenhagen 	EMU_SRC_SILENCE,
4986f3609f8SOswald Buddenhagen };
4996f3609f8SOswald Buddenhagen 
500511cbe8fSOswald Buddenhagen struct snd_emu1010_routing_info {
501511cbe8fSOswald Buddenhagen 	const char * const *src_texts;
50297f1582eSOswald Buddenhagen 	const char * const *out_texts;
503511cbe8fSOswald Buddenhagen 	const unsigned short *src_regs;
504511cbe8fSOswald Buddenhagen 	const unsigned short *out_regs;
505511cbe8fSOswald Buddenhagen 	const unsigned short *in_regs;
5061fc710f0SOswald Buddenhagen 	const unsigned short *out_dflts;
5071fc710f0SOswald Buddenhagen 	const unsigned short *in_dflts;
508511cbe8fSOswald Buddenhagen 	unsigned n_srcs;
509511cbe8fSOswald Buddenhagen 	unsigned n_outs;
510511cbe8fSOswald Buddenhagen 	unsigned n_ins;
511511cbe8fSOswald Buddenhagen };
512511cbe8fSOswald Buddenhagen 
513816967d5STom Rix static const struct snd_emu1010_routing_info emu1010_routing_info[] = {
514511cbe8fSOswald Buddenhagen 	{
5156f3609f8SOswald Buddenhagen 		/* rev1 1010 */
516511cbe8fSOswald Buddenhagen 		.src_regs = emu1010_src_regs,
517511cbe8fSOswald Buddenhagen 		.src_texts = emu1010_src_texts,
518511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1010_src_texts),
519511cbe8fSOswald Buddenhagen 
5201fc710f0SOswald Buddenhagen 		.out_dflts = emu1010_output_dflt,
521511cbe8fSOswald Buddenhagen 		.out_regs = emu1010_output_dst,
52297f1582eSOswald Buddenhagen 		.out_texts = emu1010_output_texts,
523511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1010_output_dst),
524511cbe8fSOswald Buddenhagen 
5251fc710f0SOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
526511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
527511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst),
528511cbe8fSOswald Buddenhagen 	},
529511cbe8fSOswald Buddenhagen 	{
530f69d705dSOswald Buddenhagen 		/* rev2 1010 */
531f69d705dSOswald Buddenhagen 		.src_regs = emu1010b_src_regs,
532f69d705dSOswald Buddenhagen 		.src_texts = emu1010b_src_texts,
533f69d705dSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1010b_src_texts),
534f69d705dSOswald Buddenhagen 
535f69d705dSOswald Buddenhagen 		.out_dflts = emu1010b_output_dflt,
536f69d705dSOswald Buddenhagen 		.out_regs = emu1010b_output_dst,
537f69d705dSOswald Buddenhagen 		.out_texts = snd_emu1010b_output_texts,
538f69d705dSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1010b_output_dst),
539f69d705dSOswald Buddenhagen 
540f69d705dSOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
541f69d705dSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
542f69d705dSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
543f69d705dSOswald Buddenhagen 	},
544f69d705dSOswald Buddenhagen 	{
545511cbe8fSOswald Buddenhagen 		/* 1616(m) cardbus */
546511cbe8fSOswald Buddenhagen 		.src_regs = emu1616_src_regs,
547511cbe8fSOswald Buddenhagen 		.src_texts = emu1616_src_texts,
548511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1616_src_texts),
549511cbe8fSOswald Buddenhagen 
5501fc710f0SOswald Buddenhagen 		.out_dflts = emu1616_output_dflt,
551511cbe8fSOswald Buddenhagen 		.out_regs = emu1616_output_dst,
55297f1582eSOswald Buddenhagen 		.out_texts = snd_emu1616_output_texts,
553511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1616_output_dst),
554511cbe8fSOswald Buddenhagen 
5551fc710f0SOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
556511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
557511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
558511cbe8fSOswald Buddenhagen 	},
5596f3609f8SOswald Buddenhagen 	{
5606f3609f8SOswald Buddenhagen 		/* 0404 */
5616f3609f8SOswald Buddenhagen 		.src_regs = emu0404_src_regs,
5626f3609f8SOswald Buddenhagen 		.src_texts = emu0404_src_texts,
5636f3609f8SOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu0404_src_texts),
5646f3609f8SOswald Buddenhagen 
5656f3609f8SOswald Buddenhagen 		.out_dflts = emu0404_output_dflt,
5666f3609f8SOswald Buddenhagen 		.out_regs = emu0404_output_dst,
5676f3609f8SOswald Buddenhagen 		.out_texts = snd_emu0404_output_texts,
5686f3609f8SOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu0404_output_dflt),
5696f3609f8SOswald Buddenhagen 
5706f3609f8SOswald Buddenhagen 		.in_dflts = emu0404_input_dflt,
5716f3609f8SOswald Buddenhagen 		.in_regs = emu1010_input_dst,
5726f3609f8SOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
5736f3609f8SOswald Buddenhagen 	},
574511cbe8fSOswald Buddenhagen };
575511cbe8fSOswald Buddenhagen 
emu1010_idx(struct snd_emu10k1 * emu)576511cbe8fSOswald Buddenhagen static unsigned emu1010_idx(struct snd_emu10k1 *emu)
577511cbe8fSOswald Buddenhagen {
5786f3609f8SOswald Buddenhagen 	return emu->card_capabilities->emu_model - 1;
579511cbe8fSOswald Buddenhagen }
580511cbe8fSOswald Buddenhagen 
snd_emu1010_output_source_apply(struct snd_emu10k1 * emu,int channel,int src)581511cbe8fSOswald Buddenhagen static void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu,
582511cbe8fSOswald Buddenhagen 					    int channel, int src)
583511cbe8fSOswald Buddenhagen {
584511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
585511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
586511cbe8fSOswald Buddenhagen 
587511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
588511cbe8fSOswald Buddenhagen 		emu_ri->out_regs[channel], emu_ri->src_regs[src]);
589511cbe8fSOswald Buddenhagen }
590511cbe8fSOswald Buddenhagen 
snd_emu1010_input_source_apply(struct snd_emu10k1 * emu,int channel,int src)591511cbe8fSOswald Buddenhagen static void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu,
592511cbe8fSOswald Buddenhagen 					   int channel, int src)
593511cbe8fSOswald Buddenhagen {
594511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
595511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
596511cbe8fSOswald Buddenhagen 
597511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
598511cbe8fSOswald Buddenhagen 		emu_ri->in_regs[channel], emu_ri->src_regs[src]);
599511cbe8fSOswald Buddenhagen }
600511cbe8fSOswald Buddenhagen 
snd_emu1010_apply_sources(struct snd_emu10k1 * emu)6011fc710f0SOswald Buddenhagen static void snd_emu1010_apply_sources(struct snd_emu10k1 *emu)
6021fc710f0SOswald Buddenhagen {
6031fc710f0SOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
6041fc710f0SOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
6051fc710f0SOswald Buddenhagen 
6061fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_outs; i++)
6071fc710f0SOswald Buddenhagen 		snd_emu1010_output_source_apply(
6081fc710f0SOswald Buddenhagen 			emu, i, emu->emu1010.output_source[i]);
6091fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_ins; i++)
6101fc710f0SOswald Buddenhagen 		snd_emu1010_input_source_apply(
6111fc710f0SOswald Buddenhagen 			emu, i, emu->emu1010.input_source[i]);
6121fc710f0SOswald Buddenhagen }
6131fc710f0SOswald Buddenhagen 
emu1010_map_source(const struct snd_emu1010_routing_info * emu_ri,unsigned val)6141fc710f0SOswald Buddenhagen static u8 emu1010_map_source(const struct snd_emu1010_routing_info *emu_ri,
6151fc710f0SOswald Buddenhagen 			     unsigned val)
6161fc710f0SOswald Buddenhagen {
6171fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_srcs; i++)
6181fc710f0SOswald Buddenhagen 		if (val == emu_ri->src_regs[i])
6191fc710f0SOswald Buddenhagen 			return i;
6201fc710f0SOswald Buddenhagen 	return 0;
6211fc710f0SOswald Buddenhagen }
6221fc710f0SOswald Buddenhagen 
snd_emu1010_input_output_source_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)6231c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
6241c02e366SCtirad Fertr 						struct snd_ctl_elem_info *uinfo)
6259f4bd5ddSJames Courtier-Dutton {
6261c02e366SCtirad Fertr 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
627511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
628511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
6291c02e366SCtirad Fertr 
630511cbe8fSOswald Buddenhagen 	return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts);
6319f4bd5ddSJames Courtier-Dutton }
6329f4bd5ddSJames Courtier-Dutton 
snd_emu1010_output_source_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6339f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
6349f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6359f4bd5ddSJames Courtier-Dutton {
6369f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
637511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
638511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
639511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
6409f4bd5ddSJames Courtier-Dutton 
641511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
64274415a36SJames Courtier-Dutton 		return -EINVAL;
6439f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
6449f4bd5ddSJames Courtier-Dutton 	return 0;
6459f4bd5ddSJames Courtier-Dutton }
6469f4bd5ddSJames Courtier-Dutton 
snd_emu1010_output_source_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6479f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
6489f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6499f4bd5ddSJames Courtier-Dutton {
6509f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
651511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
652511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
653511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
654511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
655511cbe8fSOswald Buddenhagen 	int change;
6569f4bd5ddSJames Courtier-Dutton 
657511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
658aa299d01STakashi Iwai 		return -EINVAL;
659511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
66074415a36SJames Courtier-Dutton 		return -EINVAL;
661511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.output_source[channel] != val);
662511cbe8fSOswald Buddenhagen 	if (change) {
663aa299d01STakashi Iwai 		emu->emu1010.output_source[channel] = val;
664511cbe8fSOswald Buddenhagen 		snd_emu1010_output_source_apply(emu, channel, val);
665511cbe8fSOswald Buddenhagen 	}
666511cbe8fSOswald Buddenhagen 	return change;
6679f4bd5ddSJames Courtier-Dutton }
6689f4bd5ddSJames Courtier-Dutton 
669536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_output_source_ctl = {
670536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
671536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
672536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
673536438f1SOswald Buddenhagen 	.get = snd_emu1010_output_source_get,
674536438f1SOswald Buddenhagen 	.put = snd_emu1010_output_source_put
675536438f1SOswald Buddenhagen };
676536438f1SOswald Buddenhagen 
snd_emu1010_input_source_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6779f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
6789f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6799f4bd5ddSJames Courtier-Dutton {
6809f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
681511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
682511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
683511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
6849f4bd5ddSJames Courtier-Dutton 
685511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
68674415a36SJames Courtier-Dutton 		return -EINVAL;
6879f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
6889f4bd5ddSJames Courtier-Dutton 	return 0;
6899f4bd5ddSJames Courtier-Dutton }
6909f4bd5ddSJames Courtier-Dutton 
snd_emu1010_input_source_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6919f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
6929f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6939f4bd5ddSJames Courtier-Dutton {
6949f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
695511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
696511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
697511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
698511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
699511cbe8fSOswald Buddenhagen 	int change;
7009f4bd5ddSJames Courtier-Dutton 
701511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
702aa299d01STakashi Iwai 		return -EINVAL;
703511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
70474415a36SJames Courtier-Dutton 		return -EINVAL;
705511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.input_source[channel] != val);
706511cbe8fSOswald Buddenhagen 	if (change) {
707aa299d01STakashi Iwai 		emu->emu1010.input_source[channel] = val;
708511cbe8fSOswald Buddenhagen 		snd_emu1010_input_source_apply(emu, channel, val);
709511cbe8fSOswald Buddenhagen 	}
710511cbe8fSOswald Buddenhagen 	return change;
7119f4bd5ddSJames Courtier-Dutton }
7129f4bd5ddSJames Courtier-Dutton 
713536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_input_source_ctl = {
714536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
715536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
716536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
717536438f1SOswald Buddenhagen 	.get = snd_emu1010_input_source_get,
718536438f1SOswald Buddenhagen 	.put = snd_emu1010_input_source_put
7199f4bd5ddSJames Courtier-Dutton };
7209f4bd5ddSJames Courtier-Dutton 
add_emu1010_source_mixers(struct snd_emu10k1 * emu)72197f1582eSOswald Buddenhagen static int add_emu1010_source_mixers(struct snd_emu10k1 *emu)
72297f1582eSOswald Buddenhagen {
72397f1582eSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
72497f1582eSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
72597f1582eSOswald Buddenhagen 	int err;
72697f1582eSOswald Buddenhagen 
72797f1582eSOswald Buddenhagen 	err = add_ctls(emu, &emu1010_output_source_ctl,
72897f1582eSOswald Buddenhagen 		       emu_ri->out_texts, emu_ri->n_outs);
72997f1582eSOswald Buddenhagen 	if (err < 0)
73097f1582eSOswald Buddenhagen 		return err;
73197f1582eSOswald Buddenhagen 	err = add_ctls(emu, &emu1010_input_source_ctl,
73297f1582eSOswald Buddenhagen 		       emu1010_input_texts, emu_ri->n_ins);
73397f1582eSOswald Buddenhagen 	return err;
73497f1582eSOswald Buddenhagen }
73597f1582eSOswald Buddenhagen 
7361c02e366SCtirad Fertr 
737536438f1SOswald Buddenhagen static const char * const snd_emu1010_adc_pads[] = {
738f69d705dSOswald Buddenhagen 	"ADC1 14dB PAD 0202 Capture Switch",
739536438f1SOswald Buddenhagen 	"ADC1 14dB PAD Audio Dock Capture Switch",
740536438f1SOswald Buddenhagen 	"ADC2 14dB PAD Audio Dock Capture Switch",
741536438f1SOswald Buddenhagen 	"ADC3 14dB PAD Audio Dock Capture Switch",
7421c02e366SCtirad Fertr };
7431c02e366SCtirad Fertr 
744536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_adc_pad_regs[] = {
745f69d705dSOswald Buddenhagen 	EMU_HANA_0202_ADC_PAD1,
746536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD1,
747536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD2,
748536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD3,
7499148cc50SJames Courtier-Dutton };
7509148cc50SJames Courtier-Dutton 
751a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
7529148cc50SJames Courtier-Dutton 
snd_emu1010_adc_pads_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)7539148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
7549148cc50SJames Courtier-Dutton {
7559148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
756536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
757536438f1SOswald Buddenhagen 
7589148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
7599148cc50SJames Courtier-Dutton 	return 0;
7609148cc50SJames Courtier-Dutton }
7619148cc50SJames Courtier-Dutton 
snd_emu1010_adc_pads_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)7629148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
7639148cc50SJames Courtier-Dutton {
7649148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
765536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
7669148cc50SJames Courtier-Dutton 	unsigned int val, cache;
767deb1200fSOswald Buddenhagen 	int change;
768deb1200fSOswald Buddenhagen 
7699148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
7709148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
7719148cc50SJames Courtier-Dutton 	if (val == 1)
7729148cc50SJames Courtier-Dutton 		cache = cache | mask;
7739148cc50SJames Courtier-Dutton 	else
7749148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
775deb1200fSOswald Buddenhagen 	change = (cache != emu->emu1010.adc_pads);
776deb1200fSOswald Buddenhagen 	if (change) {
7779148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
7789148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
7799148cc50SJames Courtier-Dutton 	}
7809148cc50SJames Courtier-Dutton 
781deb1200fSOswald Buddenhagen 	return change;
7829148cc50SJames Courtier-Dutton }
7839148cc50SJames Courtier-Dutton 
784536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_adc_pads_ctl = {
785536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
786536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
787536438f1SOswald Buddenhagen 	.info = snd_emu1010_adc_pads_info,
788536438f1SOswald Buddenhagen 	.get = snd_emu1010_adc_pads_get,
789536438f1SOswald Buddenhagen 	.put = snd_emu1010_adc_pads_put
790536438f1SOswald Buddenhagen };
7919148cc50SJames Courtier-Dutton 
7929148cc50SJames Courtier-Dutton 
793536438f1SOswald Buddenhagen static const char * const snd_emu1010_dac_pads[] = {
794f69d705dSOswald Buddenhagen 	"DAC1 0202 14dB PAD Playback Switch",
795536438f1SOswald Buddenhagen 	"DAC1 Audio Dock 14dB PAD Playback Switch",
796536438f1SOswald Buddenhagen 	"DAC2 Audio Dock 14dB PAD Playback Switch",
797536438f1SOswald Buddenhagen 	"DAC3 Audio Dock 14dB PAD Playback Switch",
798536438f1SOswald Buddenhagen 	"DAC4 Audio Dock 14dB PAD Playback Switch",
799536438f1SOswald Buddenhagen };
8009148cc50SJames Courtier-Dutton 
801536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_dac_regs[] = {
802f69d705dSOswald Buddenhagen 	EMU_HANA_0202_DAC_PAD1,
803536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD1,
804536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD2,
805536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD3,
806536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD4,
8079148cc50SJames Courtier-Dutton };
8089148cc50SJames Courtier-Dutton 
809a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
8109148cc50SJames Courtier-Dutton 
snd_emu1010_dac_pads_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)8119148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
8129148cc50SJames Courtier-Dutton {
8139148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
814536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
815536438f1SOswald Buddenhagen 
8169148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
8179148cc50SJames Courtier-Dutton 	return 0;
8189148cc50SJames Courtier-Dutton }
8199148cc50SJames Courtier-Dutton 
snd_emu1010_dac_pads_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)8209148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
8219148cc50SJames Courtier-Dutton {
8229148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
823536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
8249148cc50SJames Courtier-Dutton 	unsigned int val, cache;
825cc766807SOswald Buddenhagen 	int change;
826cc766807SOswald Buddenhagen 
8279148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
8289148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
8299148cc50SJames Courtier-Dutton 	if (val == 1)
8309148cc50SJames Courtier-Dutton 		cache = cache | mask;
8319148cc50SJames Courtier-Dutton 	else
8329148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
833cc766807SOswald Buddenhagen 	change = (cache != emu->emu1010.dac_pads);
834cc766807SOswald Buddenhagen 	if (change) {
8359148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
8369148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
8379148cc50SJames Courtier-Dutton 	}
8389148cc50SJames Courtier-Dutton 
839cc766807SOswald Buddenhagen 	return change;
8409148cc50SJames Courtier-Dutton }
8419148cc50SJames Courtier-Dutton 
842536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_dac_pads_ctl = {
843536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
844536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
845536438f1SOswald Buddenhagen 	.info = snd_emu1010_dac_pads_info,
846536438f1SOswald Buddenhagen 	.get = snd_emu1010_dac_pads_get,
847536438f1SOswald Buddenhagen 	.put = snd_emu1010_dac_pads_put
8489f4bd5ddSJames Courtier-Dutton };
8499f4bd5ddSJames Courtier-Dutton 
850b0dbdaeaSJames Courtier-Dutton 
85197f1582eSOswald Buddenhagen struct snd_emu1010_pads_info {
85297f1582eSOswald Buddenhagen 	const char * const *adc_ctls, * const *dac_ctls;
85397f1582eSOswald Buddenhagen 	unsigned n_adc_ctls, n_dac_ctls;
85497f1582eSOswald Buddenhagen };
85597f1582eSOswald Buddenhagen 
856816967d5STom Rix static const struct snd_emu1010_pads_info emu1010_pads_info[] = {
85797f1582eSOswald Buddenhagen 	{
8586f3609f8SOswald Buddenhagen 		/* rev1 1010 */
85997f1582eSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads,
86097f1582eSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads),
86197f1582eSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads,
86297f1582eSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads),
86397f1582eSOswald Buddenhagen 	},
86497f1582eSOswald Buddenhagen 	{
865f69d705dSOswald Buddenhagen 		/* rev2 1010 */
86697f1582eSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads,
867f69d705dSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 1,
86897f1582eSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads,
869f69d705dSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 1,
870f69d705dSOswald Buddenhagen 	},
871f69d705dSOswald Buddenhagen 	{
872f69d705dSOswald Buddenhagen 		/* 1616(m) cardbus */
873f69d705dSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads + 1,
874f69d705dSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 2,
875f69d705dSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads + 1,
87697f1582eSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 2,
87797f1582eSOswald Buddenhagen 	},
8786f3609f8SOswald Buddenhagen 	{
8796f3609f8SOswald Buddenhagen 		/* 0404 */
8806f3609f8SOswald Buddenhagen 		.adc_ctls = NULL,
8816f3609f8SOswald Buddenhagen 		.n_adc_ctls = 0,
8826f3609f8SOswald Buddenhagen 		.dac_ctls = NULL,
8836f3609f8SOswald Buddenhagen 		.n_dac_ctls = 0,
8846f3609f8SOswald Buddenhagen 	},
88597f1582eSOswald Buddenhagen };
88697f1582eSOswald Buddenhagen 
88760985241SOswald Buddenhagen static const char * const emu1010_clock_texts[] = {
88860985241SOswald Buddenhagen 	"44100", "48000", "SPDIF", "ADAT", "Dock", "BNC"
88960985241SOswald Buddenhagen };
89060985241SOswald Buddenhagen 
89160985241SOswald Buddenhagen static const u8 emu1010_clock_vals[] = {
89260985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_INT_44_1K,
89360985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_INT_48K,
89460985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_HANA_SPDIF_IN,
89560985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_HANA_ADAT_IN,
89660985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_2ND_HANA,
89760985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_SYNC_BNC,
89860985241SOswald Buddenhagen };
89960985241SOswald Buddenhagen 
90060985241SOswald Buddenhagen static const char * const emu0404_clock_texts[] = {
90160985241SOswald Buddenhagen 	"44100", "48000", "SPDIF", "BNC"
90260985241SOswald Buddenhagen };
90360985241SOswald Buddenhagen 
90460985241SOswald Buddenhagen static const u8 emu0404_clock_vals[] = {
90560985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_INT_44_1K,
90660985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_INT_48K,
90760985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_HANA_SPDIF_IN,
90860985241SOswald Buddenhagen 	EMU_HANA_WCLOCK_SYNC_BNC,
90960985241SOswald Buddenhagen };
91060985241SOswald Buddenhagen 
91160985241SOswald Buddenhagen struct snd_emu1010_clock_info {
91260985241SOswald Buddenhagen 	const char * const *texts;
91360985241SOswald Buddenhagen 	const u8 *vals;
91460985241SOswald Buddenhagen 	unsigned num;
91560985241SOswald Buddenhagen };
91660985241SOswald Buddenhagen 
91760985241SOswald Buddenhagen static const struct snd_emu1010_clock_info emu1010_clock_info[] = {
91860985241SOswald Buddenhagen 	{
91960985241SOswald Buddenhagen 		// rev1 1010
92060985241SOswald Buddenhagen 		.texts = emu1010_clock_texts,
92160985241SOswald Buddenhagen 		.vals = emu1010_clock_vals,
92260985241SOswald Buddenhagen 		.num = ARRAY_SIZE(emu1010_clock_vals),
92360985241SOswald Buddenhagen 	},
92460985241SOswald Buddenhagen 	{
92560985241SOswald Buddenhagen 		// rev2 1010
92660985241SOswald Buddenhagen 		.texts = emu1010_clock_texts,
92760985241SOswald Buddenhagen 		.vals = emu1010_clock_vals,
92860985241SOswald Buddenhagen 		.num = ARRAY_SIZE(emu1010_clock_vals) - 1,
92960985241SOswald Buddenhagen 	},
93060985241SOswald Buddenhagen 	{
93160985241SOswald Buddenhagen 		// 1616(m) CardBus
93260985241SOswald Buddenhagen 		.texts = emu1010_clock_texts,
93360985241SOswald Buddenhagen 		// TODO: determine what is actually available.
93460985241SOswald Buddenhagen 		// Pedantically, *every* source comes from the 2nd FPGA, as the
93560985241SOswald Buddenhagen 		// card itself has no own (digital) audio ports. The user manual
93660985241SOswald Buddenhagen 		// claims that ADAT and S/PDIF clock sources are separate, which
93760985241SOswald Buddenhagen 		// can mean two things: either E-MU mapped the dock's sources to
93860985241SOswald Buddenhagen 		// the primary ones, or they determine the meaning of the "Dock"
93960985241SOswald Buddenhagen 		// source depending on how the ports are actually configured
94060985241SOswald Buddenhagen 		// (which the 2nd FPGA must be doing anyway).
94160985241SOswald Buddenhagen 		.vals = emu1010_clock_vals,
94260985241SOswald Buddenhagen 		.num = ARRAY_SIZE(emu1010_clock_vals),
94360985241SOswald Buddenhagen 	},
94460985241SOswald Buddenhagen 	{
94560985241SOswald Buddenhagen 		// 0404
94660985241SOswald Buddenhagen 		.texts = emu0404_clock_texts,
94760985241SOswald Buddenhagen 		.vals = emu0404_clock_vals,
94860985241SOswald Buddenhagen 		.num = ARRAY_SIZE(emu0404_clock_vals),
94960985241SOswald Buddenhagen 	},
95060985241SOswald Buddenhagen };
95197f1582eSOswald Buddenhagen 
snd_emu1010_clock_source_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)95213598862SOswald Buddenhagen static int snd_emu1010_clock_source_info(struct snd_kcontrol *kcontrol,
953b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
954b0dbdaeaSJames Courtier-Dutton {
95560985241SOswald Buddenhagen 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
95660985241SOswald Buddenhagen 	const struct snd_emu1010_clock_info *emu_ci =
95760985241SOswald Buddenhagen 		&emu1010_clock_info[emu1010_idx(emu)];
958b0dbdaeaSJames Courtier-Dutton 
95960985241SOswald Buddenhagen 	return snd_ctl_enum_info(uinfo, 1, emu_ci->num, emu_ci->texts);
960b0dbdaeaSJames Courtier-Dutton }
961b0dbdaeaSJames Courtier-Dutton 
snd_emu1010_clock_source_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)96213598862SOswald Buddenhagen static int snd_emu1010_clock_source_get(struct snd_kcontrol *kcontrol,
963b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
964b0dbdaeaSJames Courtier-Dutton {
965b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
966b0dbdaeaSJames Courtier-Dutton 
96713598862SOswald Buddenhagen 	ucontrol->value.enumerated.item[0] = emu->emu1010.clock_source;
968b0dbdaeaSJames Courtier-Dutton 	return 0;
969b0dbdaeaSJames Courtier-Dutton }
970b0dbdaeaSJames Courtier-Dutton 
snd_emu1010_clock_source_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)97113598862SOswald Buddenhagen static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
972b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
973b0dbdaeaSJames Courtier-Dutton {
974b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
97560985241SOswald Buddenhagen 	const struct snd_emu1010_clock_info *emu_ci =
97660985241SOswald Buddenhagen 		&emu1010_clock_info[emu1010_idx(emu)];
977b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
978b0dbdaeaSJames Courtier-Dutton 	int change = 0;
979b0dbdaeaSJames Courtier-Dutton 
980b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
98160985241SOswald Buddenhagen 	if (val >= emu_ci->num)
98274415a36SJames Courtier-Dutton 		return -EINVAL;
983c960b012SOswald Buddenhagen 	spin_lock_irq(&emu->reg_lock);
98413598862SOswald Buddenhagen 	change = (emu->emu1010.clock_source != val);
985b0dbdaeaSJames Courtier-Dutton 	if (change) {
98613598862SOswald Buddenhagen 		emu->emu1010.clock_source = val;
98760985241SOswald Buddenhagen 		emu->emu1010.wclock = emu_ci->vals[val];
988c960b012SOswald Buddenhagen 		snd_emu1010_update_clock(emu);
989edec7bbbSJames Courtier-Dutton 
990edec7bbbSJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE);
99160985241SOswald Buddenhagen 		snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, emu->emu1010.wclock);
992c960b012SOswald Buddenhagen 		spin_unlock_irq(&emu->reg_lock);
993c960b012SOswald Buddenhagen 
99460985241SOswald Buddenhagen 		msleep(10);  // Allow DLL to settle
995edec7bbbSJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
996c960b012SOswald Buddenhagen 	} else {
997c960b012SOswald Buddenhagen 		spin_unlock_irq(&emu->reg_lock);
998b0dbdaeaSJames Courtier-Dutton 	}
999b0dbdaeaSJames Courtier-Dutton 	return change;
1000b0dbdaeaSJames Courtier-Dutton }
1001b0dbdaeaSJames Courtier-Dutton 
100213598862SOswald Buddenhagen static const struct snd_kcontrol_new snd_emu1010_clock_source =
1003b0dbdaeaSJames Courtier-Dutton {
1004b0dbdaeaSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1005b0dbdaeaSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
100613598862SOswald Buddenhagen 	.name = "Clock Source",
1007b0dbdaeaSJames Courtier-Dutton 	.count = 1,
100813598862SOswald Buddenhagen 	.info = snd_emu1010_clock_source_info,
100913598862SOswald Buddenhagen 	.get = snd_emu1010_clock_source_get,
101013598862SOswald Buddenhagen 	.put = snd_emu1010_clock_source_put
101113598862SOswald Buddenhagen };
101213598862SOswald Buddenhagen 
snd_emu1010_clock_fallback_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)101313598862SOswald Buddenhagen static int snd_emu1010_clock_fallback_info(struct snd_kcontrol *kcontrol,
101413598862SOswald Buddenhagen 					  struct snd_ctl_elem_info *uinfo)
101513598862SOswald Buddenhagen {
101613598862SOswald Buddenhagen 	static const char * const texts[2] = {
101713598862SOswald Buddenhagen 		"44100", "48000"
101813598862SOswald Buddenhagen 	};
101913598862SOswald Buddenhagen 
102013598862SOswald Buddenhagen 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
102113598862SOswald Buddenhagen }
102213598862SOswald Buddenhagen 
snd_emu1010_clock_fallback_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)102313598862SOswald Buddenhagen static int snd_emu1010_clock_fallback_get(struct snd_kcontrol *kcontrol,
102413598862SOswald Buddenhagen 					  struct snd_ctl_elem_value *ucontrol)
102513598862SOswald Buddenhagen {
102613598862SOswald Buddenhagen 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
102713598862SOswald Buddenhagen 
102813598862SOswald Buddenhagen 	ucontrol->value.enumerated.item[0] = emu->emu1010.clock_fallback;
102913598862SOswald Buddenhagen 	return 0;
103013598862SOswald Buddenhagen }
103113598862SOswald Buddenhagen 
snd_emu1010_clock_fallback_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)103213598862SOswald Buddenhagen static int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol,
103313598862SOswald Buddenhagen 					  struct snd_ctl_elem_value *ucontrol)
103413598862SOswald Buddenhagen {
103513598862SOswald Buddenhagen 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
103613598862SOswald Buddenhagen 	unsigned int val = ucontrol->value.enumerated.item[0];
103713598862SOswald Buddenhagen 	int change;
103813598862SOswald Buddenhagen 
103913598862SOswald Buddenhagen 	if (val >= 2)
104013598862SOswald Buddenhagen 		return -EINVAL;
104113598862SOswald Buddenhagen 	change = (emu->emu1010.clock_fallback != val);
104213598862SOswald Buddenhagen 	if (change) {
104313598862SOswald Buddenhagen 		emu->emu1010.clock_fallback = val;
104413598862SOswald Buddenhagen 		snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 1 - val);
104513598862SOswald Buddenhagen 	}
104613598862SOswald Buddenhagen 	return change;
104713598862SOswald Buddenhagen }
104813598862SOswald Buddenhagen 
104913598862SOswald Buddenhagen static const struct snd_kcontrol_new snd_emu1010_clock_fallback =
105013598862SOswald Buddenhagen {
105113598862SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
105213598862SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
105313598862SOswald Buddenhagen 	.name = "Clock Fallback",
105413598862SOswald Buddenhagen 	.count = 1,
105513598862SOswald Buddenhagen 	.info = snd_emu1010_clock_fallback_info,
105613598862SOswald Buddenhagen 	.get = snd_emu1010_clock_fallback_get,
105713598862SOswald Buddenhagen 	.put = snd_emu1010_clock_fallback_put
1058b0dbdaeaSJames Courtier-Dutton };
1059b0dbdaeaSJames Courtier-Dutton 
snd_emu1010_optical_out_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)106099dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
106199dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
106299dcab46SMichael Gernoth {
106399dcab46SMichael Gernoth 	static const char * const texts[2] = {
106499dcab46SMichael Gernoth 		"SPDIF", "ADAT"
106599dcab46SMichael Gernoth 	};
106699dcab46SMichael Gernoth 
106799dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
106899dcab46SMichael Gernoth }
106999dcab46SMichael Gernoth 
snd_emu1010_optical_out_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)107099dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol,
107199dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
107299dcab46SMichael Gernoth {
107399dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
107499dcab46SMichael Gernoth 
107599dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out;
107699dcab46SMichael Gernoth 	return 0;
107799dcab46SMichael Gernoth }
107899dcab46SMichael Gernoth 
snd_emu1010_optical_out_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)107999dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
108099dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
108199dcab46SMichael Gernoth {
108299dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
108399dcab46SMichael Gernoth 	unsigned int val;
108499dcab46SMichael Gernoth 	u32 tmp;
108599dcab46SMichael Gernoth 	int change = 0;
108699dcab46SMichael Gernoth 
108799dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
108899dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
108999dcab46SMichael Gernoth 	if (val >= 2)
109099dcab46SMichael Gernoth 		return -EINVAL;
109199dcab46SMichael Gernoth 	change = (emu->emu1010.optical_out != val);
109299dcab46SMichael Gernoth 	if (change) {
109399dcab46SMichael Gernoth 		emu->emu1010.optical_out = val;
10949d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
10959d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
109699dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
109799dcab46SMichael Gernoth 	}
109899dcab46SMichael Gernoth 	return change;
109999dcab46SMichael Gernoth }
110099dcab46SMichael Gernoth 
1101f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = {
110299dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
110399dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
110499dcab46SMichael Gernoth 	.name =         "Optical Output Mode",
110599dcab46SMichael Gernoth 	.count =	1,
110699dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_out_info,
110799dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_out_get,
110899dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_out_put
110999dcab46SMichael Gernoth };
111099dcab46SMichael Gernoth 
snd_emu1010_optical_in_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)111199dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
111299dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
111399dcab46SMichael Gernoth {
111499dcab46SMichael Gernoth 	static const char * const texts[2] = {
111599dcab46SMichael Gernoth 		"SPDIF", "ADAT"
111699dcab46SMichael Gernoth 	};
111799dcab46SMichael Gernoth 
111899dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
111999dcab46SMichael Gernoth }
112099dcab46SMichael Gernoth 
snd_emu1010_optical_in_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)112199dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
112299dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
112399dcab46SMichael Gernoth {
112499dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
112599dcab46SMichael Gernoth 
112699dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
112799dcab46SMichael Gernoth 	return 0;
112899dcab46SMichael Gernoth }
112999dcab46SMichael Gernoth 
snd_emu1010_optical_in_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)113099dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
113199dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
113299dcab46SMichael Gernoth {
113399dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
113499dcab46SMichael Gernoth 	unsigned int val;
113599dcab46SMichael Gernoth 	u32 tmp;
113699dcab46SMichael Gernoth 	int change = 0;
113799dcab46SMichael Gernoth 
113899dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
113999dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
114099dcab46SMichael Gernoth 	if (val >= 2)
114199dcab46SMichael Gernoth 		return -EINVAL;
114299dcab46SMichael Gernoth 	change = (emu->emu1010.optical_in != val);
114399dcab46SMichael Gernoth 	if (change) {
114499dcab46SMichael Gernoth 		emu->emu1010.optical_in = val;
11459d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
11469d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
114799dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
114899dcab46SMichael Gernoth 	}
114999dcab46SMichael Gernoth 	return change;
115099dcab46SMichael Gernoth }
115199dcab46SMichael Gernoth 
1152f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = {
115399dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
115499dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
115599dcab46SMichael Gernoth 	.name =         "Optical Input Mode",
115699dcab46SMichael Gernoth 	.count =	1,
115799dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_in_info,
115899dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_in_get,
115999dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_in_put
116099dcab46SMichael Gernoth };
116199dcab46SMichael Gernoth 
snd_audigy_i2c_capture_source_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1162184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
1163184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
1164184c1e2cSJames Courtier-Dutton {
1165184c1e2cSJames Courtier-Dutton #if 0
11661541c66dSTakashi Iwai 	static const char * const texts[4] = {
1167184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
1168184c1e2cSJames Courtier-Dutton 	};
1169184c1e2cSJames Courtier-Dutton #endif
11701541c66dSTakashi Iwai 	static const char * const texts[2] = {
1171184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
1172184c1e2cSJames Courtier-Dutton 	};
1173184c1e2cSJames Courtier-Dutton 
11741541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
1175184c1e2cSJames Courtier-Dutton }
1176184c1e2cSJames Courtier-Dutton 
snd_audigy_i2c_capture_source_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1177184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
1178184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
1179184c1e2cSJames Courtier-Dutton {
1180184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1181184c1e2cSJames Courtier-Dutton 
1182184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
1183184c1e2cSJames Courtier-Dutton 	return 0;
1184184c1e2cSJames Courtier-Dutton }
1185184c1e2cSJames Courtier-Dutton 
snd_audigy_i2c_capture_source_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1186184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
1187184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
1188184c1e2cSJames Courtier-Dutton {
1189184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1190184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
1191184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
1192a1c87c0bSOswald Buddenhagen 	u16 gpio;
1193184c1e2cSJames Courtier-Dutton 	int change = 0;
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 */
120767192cc0SOswald Buddenhagen 		spin_lock_irq(&emu->emu_lock);
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);
121367192cc0SOswald Buddenhagen 		spin_unlock_irq(&emu->emu_lock);
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 
snd_audigy_i2c_volume_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)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 
snd_audigy_i2c_volume_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)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 
snd_audigy_i2c_volume_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)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 
13581da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
13591da177e4SLinus Torvalds 	case 0:
13601da177e4SLinus Torvalds 		val = A_SPDIF_44100;
13611da177e4SLinus Torvalds 		break;
13621da177e4SLinus Torvalds 	case 1:
13631da177e4SLinus Torvalds 		val = A_SPDIF_48000;
13641da177e4SLinus Torvalds 		break;
13651da177e4SLinus Torvalds 	case 2:
13661da177e4SLinus Torvalds 		val = A_SPDIF_96000;
13671da177e4SLinus Torvalds 		break;
13681da177e4SLinus Torvalds 	default:
13691da177e4SLinus Torvalds 		val = A_SPDIF_48000;
13701da177e4SLinus Torvalds 		break;
13711da177e4SLinus Torvalds 	}
13721da177e4SLinus Torvalds 
13731da177e4SLinus Torvalds 
137467192cc0SOswald Buddenhagen 	spin_lock_irq(&emu->reg_lock);
13751da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
13761da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
13771da177e4SLinus Torvalds 	tmp |= val;
137812bda107STakashi Iwai 	change = (tmp != reg);
137912bda107STakashi Iwai 	if (change)
13801da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
138167192cc0SOswald Buddenhagen 	spin_unlock_irq(&emu->reg_lock);
13821da177e4SLinus Torvalds 	return change;
13831da177e4SLinus Torvalds }
13841da177e4SLinus Torvalds 
1385b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate =
13861da177e4SLinus Torvalds {
13871da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
13881da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
13891da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
13901da177e4SLinus Torvalds 	.count =	1,
13911da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
13921da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
13931da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
13941da177e4SLinus Torvalds };
13950af68e5eSTakashi Iwai #endif
13961da177e4SLinus Torvalds 
snd_emu10k1_spdif_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1397eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1398eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
13991da177e4SLinus Torvalds {
1400eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14011da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
14021da177e4SLinus Torvalds 	int change;
14031da177e4SLinus Torvalds 	unsigned int val;
14041da177e4SLinus Torvalds 
140574415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
140674415a36SJames Courtier-Dutton 	if (idx >= 3)
140774415a36SJames Courtier-Dutton 		return -EINVAL;
14081da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
14091da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
14101da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
14111da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
14121da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
14131da177e4SLinus Torvalds 	if (change) {
14141da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
14151da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
14161da177e4SLinus Torvalds 	}
14171da177e4SLinus Torvalds 	return change;
14181da177e4SLinus Torvalds }
14191da177e4SLinus Torvalds 
1420f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
14211da177e4SLinus Torvalds {
14221da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
14235549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14241da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
14257583cb51STakashi Iwai 	.count =	3,
14261da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
14271da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
14281da177e4SLinus Torvalds };
14291da177e4SLinus Torvalds 
1430f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
14311da177e4SLinus Torvalds {
14325549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
14331da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
14347583cb51STakashi Iwai 	.count =	3,
14351da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
14361da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
14371da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
14381da177e4SLinus Torvalds };
14391da177e4SLinus Torvalds 
14401da177e4SLinus Torvalds 
update_emu10k1_fxrt(struct snd_emu10k1 * emu,int voice,unsigned char * route)1441eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
14421da177e4SLinus Torvalds {
14431da177e4SLinus Torvalds 	if (emu->audigy) {
144446055699SOswald Buddenhagen 		snd_emu10k1_ptr_write_multiple(emu, voice,
144546055699SOswald Buddenhagen 			A_FXRT1, snd_emu10k1_compose_audigy_fxrt1(route),
144646055699SOswald Buddenhagen 			A_FXRT2, snd_emu10k1_compose_audigy_fxrt2(route),
144746055699SOswald Buddenhagen 			REGLIST_END);
14481da177e4SLinus Torvalds 	} else {
14491da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
14501da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
14511da177e4SLinus Torvalds 	}
14521da177e4SLinus Torvalds }
14531da177e4SLinus Torvalds 
update_emu10k1_send_volume(struct snd_emu10k1 * emu,int voice,unsigned char * volume)1454eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
14551da177e4SLinus Torvalds {
14561da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
14571da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
14581da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
14591da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
14601da177e4SLinus Torvalds 	if (emu->audigy) {
146151d652f4SOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice,
146251d652f4SOswald Buddenhagen 				      snd_emu10k1_compose_audigy_sendamounts(volume));
14631da177e4SLinus Torvalds 	}
14641da177e4SLinus Torvalds }
14651da177e4SLinus Torvalds 
14661da177e4SLinus Torvalds /* PCM stream controls */
14671da177e4SLinus Torvalds 
snd_emu10k1_send_routing_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1468eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14691da177e4SLinus Torvalds {
1470eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14711da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14721da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
14731da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14741da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
14751da177e4SLinus Torvalds 	return 0;
14761da177e4SLinus Torvalds }
14771da177e4SLinus Torvalds 
snd_emu10k1_send_routing_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1478eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1479eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14801da177e4SLinus Torvalds {
1481eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1482eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1483eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14841da177e4SLinus Torvalds 	int voice, idx;
14851da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14861da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14871da177e4SLinus Torvalds 
14881da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
14891da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
14901da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
14911da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
14921da177e4SLinus Torvalds 	return 0;
14931da177e4SLinus Torvalds }
14941da177e4SLinus Torvalds 
snd_emu10k1_send_routing_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1495eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1496eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14971da177e4SLinus Torvalds {
1498eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1499eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1500eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15011da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
15021da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15031da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
15041da177e4SLinus Torvalds 
150567192cc0SOswald Buddenhagen 	spin_lock_irq(&emu->reg_lock);
15061da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
15071da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
15081da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
15091da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
15101da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
15111da177e4SLinus Torvalds 				change = 1;
15121da177e4SLinus Torvalds 			}
15131da177e4SLinus Torvalds 		}
1514a915d604SOswald Buddenhagen 	if (change && mix->epcm && mix->epcm->voices[0]) {
1515a915d604SOswald Buddenhagen 		if (!mix->epcm->voices[0]->last) {
15161da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
15171da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
1518a915d604SOswald Buddenhagen 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number + 1,
15191da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
1520a915d604SOswald Buddenhagen 		} else {
15211da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
15221da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
15231da177e4SLinus Torvalds 		}
15241da177e4SLinus Torvalds 	}
152567192cc0SOswald Buddenhagen 	spin_unlock_irq(&emu->reg_lock);
15261da177e4SLinus Torvalds 	return change;
15271da177e4SLinus Torvalds }
15281da177e4SLinus Torvalds 
1529f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control =
15301da177e4SLinus Torvalds {
15311da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
153267ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15331da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
15341da177e4SLinus Torvalds 	.count =	32,
15351da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
15361da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
15371da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
15381da177e4SLinus Torvalds };
15391da177e4SLinus Torvalds 
snd_emu10k1_send_volume_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1540eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15411da177e4SLinus Torvalds {
1542eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15431da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15441da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
15451da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
15461da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
15471da177e4SLinus Torvalds 	return 0;
15481da177e4SLinus Torvalds }
15491da177e4SLinus Torvalds 
snd_emu10k1_send_volume_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1550eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1551eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
15521da177e4SLinus Torvalds {
1553eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1554eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1555eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15561da177e4SLinus Torvalds 	int idx;
15571da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15581da177e4SLinus Torvalds 
15591da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
15601da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
15611da177e4SLinus Torvalds 	return 0;
15621da177e4SLinus Torvalds }
15631da177e4SLinus Torvalds 
snd_emu10k1_send_volume_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1564eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1565eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
15661da177e4SLinus Torvalds {
1567eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1568eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1569eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15701da177e4SLinus Torvalds 	int change = 0, idx, val;
15711da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15721da177e4SLinus Torvalds 
157367192cc0SOswald Buddenhagen 	spin_lock_irq(&emu->reg_lock);
15741da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
15751da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
15761da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
15771da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
15781da177e4SLinus Torvalds 			change = 1;
15791da177e4SLinus Torvalds 		}
15801da177e4SLinus Torvalds 	}
1581a915d604SOswald Buddenhagen 	if (change && mix->epcm && mix->epcm->voices[0]) {
1582a915d604SOswald Buddenhagen 		if (!mix->epcm->voices[0]->last) {
15831da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
15841da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
1585a915d604SOswald Buddenhagen 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number + 1,
15861da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
1587a915d604SOswald Buddenhagen 		} else {
15881da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
15891da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
15901da177e4SLinus Torvalds 		}
15911da177e4SLinus Torvalds 	}
159267192cc0SOswald Buddenhagen 	spin_unlock_irq(&emu->reg_lock);
15931da177e4SLinus Torvalds 	return change;
15941da177e4SLinus Torvalds }
15951da177e4SLinus Torvalds 
1596f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
15971da177e4SLinus Torvalds {
15981da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
159967ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
16001da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
16011da177e4SLinus Torvalds 	.count =	32,
16021da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
16031da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
16041da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
16051da177e4SLinus Torvalds };
16061da177e4SLinus Torvalds 
snd_emu10k1_attn_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1607eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
16081da177e4SLinus Torvalds {
16091da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
16101da177e4SLinus Torvalds 	uinfo->count = 3;
16111da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1612bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
16131da177e4SLinus Torvalds 	return 0;
16141da177e4SLinus Torvalds }
16151da177e4SLinus Torvalds 
snd_emu10k1_attn_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1616eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1617eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
16181da177e4SLinus Torvalds {
1619eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1620eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1621eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
16221da177e4SLinus Torvalds 	int idx;
16231da177e4SLinus Torvalds 
16241da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
1625bcdbd3b7SOswald Buddenhagen 		ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U;
16261da177e4SLinus Torvalds 	return 0;
16271da177e4SLinus Torvalds }
16281da177e4SLinus Torvalds 
snd_emu10k1_attn_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1629eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1630eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
16311da177e4SLinus Torvalds {
1632eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1633eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1634eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
16351da177e4SLinus Torvalds 	int change = 0, idx, val;
16361da177e4SLinus Torvalds 
163767192cc0SOswald Buddenhagen 	spin_lock_irq(&emu->reg_lock);
16381da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
1639bcdbd3b7SOswald Buddenhagen 		unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff;
1640bcdbd3b7SOswald Buddenhagen 		val = uval * 0x8000U / 0xffffU;
16411da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
16421da177e4SLinus Torvalds 			mix->attn[idx] = val;
16431da177e4SLinus Torvalds 			change = 1;
16441da177e4SLinus Torvalds 		}
16451da177e4SLinus Torvalds 	}
1646a915d604SOswald Buddenhagen 	if (change && mix->epcm && mix->epcm->voices[0]) {
1647a915d604SOswald Buddenhagen 		if (!mix->epcm->voices[0]->last) {
16481da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
1649a915d604SOswald Buddenhagen 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number + 1, mix->attn[2]);
1650a915d604SOswald Buddenhagen 		} else {
16511da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
16521da177e4SLinus Torvalds 		}
16531da177e4SLinus Torvalds 	}
165467192cc0SOswald Buddenhagen 	spin_unlock_irq(&emu->reg_lock);
16551da177e4SLinus Torvalds 	return change;
16561da177e4SLinus Torvalds }
16571da177e4SLinus Torvalds 
1658f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control =
16591da177e4SLinus Torvalds {
16601da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
166167ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
16621da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
16631da177e4SLinus Torvalds 	.count =	32,
16641da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
16651da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
16661da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
16671da177e4SLinus Torvalds };
16681da177e4SLinus Torvalds 
16691da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
16701da177e4SLinus Torvalds 
snd_emu10k1_efx_send_routing_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1671eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
16721da177e4SLinus Torvalds {
1673eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
16741da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
16751da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
16761da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
16771da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
16781da177e4SLinus Torvalds 	return 0;
16791da177e4SLinus Torvalds }
16801da177e4SLinus Torvalds 
snd_emu10k1_efx_send_routing_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1681eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1682eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
16831da177e4SLinus Torvalds {
1684eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1685eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1686eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
16871da177e4SLinus Torvalds 	int idx;
16881da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
16891da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
16901da177e4SLinus Torvalds 
16911da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
16921da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
16931da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
16941da177e4SLinus Torvalds 	return 0;
16951da177e4SLinus Torvalds }
16961da177e4SLinus Torvalds 
snd_emu10k1_efx_send_routing_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1697eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1698eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
16991da177e4SLinus Torvalds {
1700eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
17011da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1702eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
17031da177e4SLinus Torvalds 	int change = 0, idx, val;
17041da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
17051da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
17061da177e4SLinus Torvalds 
170767192cc0SOswald Buddenhagen 	spin_lock_irq(&emu->reg_lock);
17081da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
17091da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
17101da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
17111da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
17121da177e4SLinus Torvalds 			change = 1;
17131da177e4SLinus Torvalds 		}
17141da177e4SLinus Torvalds 	}
17151da177e4SLinus Torvalds 
17161da177e4SLinus Torvalds 	if (change && mix->epcm) {
17171da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
17181da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
17191da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
17201da177e4SLinus Torvalds 		}
17211da177e4SLinus Torvalds 	}
172267192cc0SOswald Buddenhagen 	spin_unlock_irq(&emu->reg_lock);
17231da177e4SLinus Torvalds 	return change;
17241da177e4SLinus Torvalds }
17251da177e4SLinus Torvalds 
1726f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
17271da177e4SLinus Torvalds {
17281da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
17291da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
17301da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
17311da177e4SLinus Torvalds 	.count =	16,
17321da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
17331da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
17341da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
17351da177e4SLinus Torvalds };
17361da177e4SLinus Torvalds 
snd_emu10k1_efx_send_volume_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1737eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
17381da177e4SLinus Torvalds {
1739eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
17401da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
17411da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
17421da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
17431da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
17441da177e4SLinus Torvalds 	return 0;
17451da177e4SLinus Torvalds }
17461da177e4SLinus Torvalds 
snd_emu10k1_efx_send_volume_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1747eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1748eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
17491da177e4SLinus Torvalds {
1750eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1751eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1752eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
17531da177e4SLinus Torvalds 	int idx;
17541da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
17551da177e4SLinus Torvalds 
17561da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
17571da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
17581da177e4SLinus Torvalds 	return 0;
17591da177e4SLinus Torvalds }
17601da177e4SLinus Torvalds 
snd_emu10k1_efx_send_volume_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1761eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1762eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
17631da177e4SLinus Torvalds {
1764eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
17651da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1766eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
17671da177e4SLinus Torvalds 	int change = 0, idx, val;
17681da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
17691da177e4SLinus Torvalds 
177067192cc0SOswald Buddenhagen 	spin_lock_irq(&emu->reg_lock);
17711da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
17721da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
17731da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
17741da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
17751da177e4SLinus Torvalds 			change = 1;
17761da177e4SLinus Torvalds 		}
17771da177e4SLinus Torvalds 	}
17781da177e4SLinus Torvalds 	if (change && mix->epcm) {
17791da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
17801da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
17811da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
17821da177e4SLinus Torvalds 		}
17831da177e4SLinus Torvalds 	}
178467192cc0SOswald Buddenhagen 	spin_unlock_irq(&emu->reg_lock);
17851da177e4SLinus Torvalds 	return change;
17861da177e4SLinus Torvalds }
17871da177e4SLinus Torvalds 
17881da177e4SLinus Torvalds 
1789f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
17901da177e4SLinus Torvalds {
17911da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
17921da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
17931da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
17941da177e4SLinus Torvalds 	.count =	16,
17951da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
17961da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
17971da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
17981da177e4SLinus Torvalds };
17991da177e4SLinus Torvalds 
snd_emu10k1_efx_attn_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1800eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
18011da177e4SLinus Torvalds {
18021da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
18031da177e4SLinus Torvalds 	uinfo->count = 1;
18041da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1805bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
18061da177e4SLinus Torvalds 	return 0;
18071da177e4SLinus Torvalds }
18081da177e4SLinus Torvalds 
snd_emu10k1_efx_attn_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1809eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1810eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
18111da177e4SLinus Torvalds {
1812eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1813eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1814eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
18151da177e4SLinus Torvalds 
1816bcdbd3b7SOswald Buddenhagen 	ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U;
18171da177e4SLinus Torvalds 	return 0;
18181da177e4SLinus Torvalds }
18191da177e4SLinus Torvalds 
snd_emu10k1_efx_attn_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1820eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1821eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
18221da177e4SLinus Torvalds {
1823eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
18241da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1825eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
18261da177e4SLinus Torvalds 	int change = 0, val;
1827bcdbd3b7SOswald Buddenhagen 	unsigned uval;
18281da177e4SLinus Torvalds 
182967192cc0SOswald Buddenhagen 	spin_lock_irq(&emu->reg_lock);
1830bcdbd3b7SOswald Buddenhagen 	uval = ucontrol->value.integer.value[0] & 0x1ffff;
1831bcdbd3b7SOswald Buddenhagen 	val = uval * 0x8000U / 0xffffU;
18321da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
18331da177e4SLinus Torvalds 		mix->attn[0] = val;
18341da177e4SLinus Torvalds 		change = 1;
18351da177e4SLinus Torvalds 	}
18361da177e4SLinus Torvalds 	if (change && mix->epcm) {
18371da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
18381da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
18391da177e4SLinus Torvalds 		}
18401da177e4SLinus Torvalds 	}
184167192cc0SOswald Buddenhagen 	spin_unlock_irq(&emu->reg_lock);
18421da177e4SLinus Torvalds 	return change;
18431da177e4SLinus Torvalds }
18441da177e4SLinus Torvalds 
1845f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
18461da177e4SLinus Torvalds {
18471da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
18481da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
18491da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
18501da177e4SLinus Torvalds 	.count =	16,
18511da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
18521da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
18531da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
18541da177e4SLinus Torvalds };
18551da177e4SLinus Torvalds 
1856a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
18571da177e4SLinus Torvalds 
snd_emu10k1_shared_spdif_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1858eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1859eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
18601da177e4SLinus Torvalds {
1861eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
18621da177e4SLinus Torvalds 
18631da177e4SLinus Torvalds 	if (emu->audigy)
1864a1c87c0bSOswald Buddenhagen 		ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
18651da177e4SLinus Torvalds 	else
18661da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1867d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1868d2cd74b1STakashi Iwai 		ucontrol->value.integer.value[0] =
1869d2cd74b1STakashi Iwai 			!ucontrol->value.integer.value[0];
1870d2cd74b1STakashi Iwai 
18711da177e4SLinus Torvalds 	return 0;
18721da177e4SLinus Torvalds }
18731da177e4SLinus Torvalds 
snd_emu10k1_shared_spdif_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1874eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1875eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
18761da177e4SLinus Torvalds {
1877eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1878d2cd74b1STakashi Iwai 	unsigned int reg, val, sw;
18791da177e4SLinus Torvalds 	int change = 0;
18801da177e4SLinus Torvalds 
1881d2cd74b1STakashi Iwai 	sw = ucontrol->value.integer.value[0];
1882d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1883d2cd74b1STakashi Iwai 		sw = !sw;
188467192cc0SOswald Buddenhagen 	spin_lock_irq(&emu->emu_lock);
1885184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1886184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1887184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
1888a1c87c0bSOswald Buddenhagen 		reg = inw(emu->port + A_IOCFG);
1889d2cd74b1STakashi Iwai 		val = sw ? A_IOCFG_GPOUT0 : 0;
18901da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
18911da177e4SLinus Torvalds 		if (change) {
18921da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
18931da177e4SLinus Torvalds 			reg |= val;
1894a1c87c0bSOswald Buddenhagen 			outw(reg | val, emu->port + A_IOCFG);
18951da177e4SLinus Torvalds 		}
18961da177e4SLinus Torvalds 	}
18971da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
1898d2cd74b1STakashi Iwai 	val = sw ? HCFG_GPOUT0 : 0;
18991da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
19001da177e4SLinus Torvalds 	if (change) {
19011da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
19021da177e4SLinus Torvalds 		reg |= val;
19031da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
19041da177e4SLinus Torvalds 	}
190567192cc0SOswald Buddenhagen 	spin_unlock_irq(&emu->emu_lock);
19061da177e4SLinus Torvalds 	return change;
19071da177e4SLinus Torvalds }
19081da177e4SLinus Torvalds 
1909f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
19101da177e4SLinus Torvalds {
19111da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
19121da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
19131da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
19141da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
19151da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
19161da177e4SLinus Torvalds };
19171da177e4SLinus Torvalds 
1918f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif =
19191da177e4SLinus Torvalds {
19201da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
19211da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
19221da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
19231da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
19241da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
19251da177e4SLinus Torvalds };
19261da177e4SLinus Torvalds 
192716950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
192816950e09STakashi Iwai 
192916950e09STakashi Iwai #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
193016950e09STakashi Iwai 
snd_audigy_capture_boost_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)193116950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
193216950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
193316950e09STakashi Iwai {
193416950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
193516950e09STakashi Iwai 	unsigned int val;
193616950e09STakashi Iwai 
193716950e09STakashi Iwai 	/* FIXME: better to use a cached version */
193816950e09STakashi Iwai 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
193916950e09STakashi Iwai 	ucontrol->value.integer.value[0] = !!val;
194016950e09STakashi Iwai 	return 0;
194116950e09STakashi Iwai }
194216950e09STakashi Iwai 
snd_audigy_capture_boost_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)194316950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
194416950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
194516950e09STakashi Iwai {
194616950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
194716950e09STakashi Iwai 	unsigned int val;
194816950e09STakashi Iwai 
194916950e09STakashi Iwai 	if (ucontrol->value.integer.value[0])
195016950e09STakashi Iwai 		val = 0x0f0f;
195116950e09STakashi Iwai 	else
195216950e09STakashi Iwai 		val = 0;
195316950e09STakashi Iwai 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
195416950e09STakashi Iwai }
195516950e09STakashi Iwai 
1956f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost =
195716950e09STakashi Iwai {
195816950e09STakashi Iwai 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
19592a52feb1SMaciej S. Szmigiero 	.name =		"Mic Extra Boost",
196016950e09STakashi Iwai 	.info =		snd_audigy_capture_boost_info,
196116950e09STakashi Iwai 	.get =		snd_audigy_capture_boost_get,
196216950e09STakashi Iwai 	.put =		snd_audigy_capture_boost_put
196316950e09STakashi Iwai };
196416950e09STakashi Iwai 
196516950e09STakashi Iwai 
19661da177e4SLinus Torvalds /*
19671da177e4SLinus Torvalds  */
snd_emu10k1_mixer_free_ac97(struct snd_ac97 * ac97)1968eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
19691da177e4SLinus Torvalds {
1970eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
19711da177e4SLinus Torvalds 	emu->ac97 = NULL;
19721da177e4SLinus Torvalds }
19731da177e4SLinus Torvalds 
19741da177e4SLinus Torvalds /*
19751da177e4SLinus Torvalds  */
remove_ctl(struct snd_card * card,const char * name)1976eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
19771da177e4SLinus Torvalds {
1978eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
19791da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
19801da177e4SLinus Torvalds 	strcpy(id.name, name);
19811da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
19821da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
19831da177e4SLinus Torvalds }
19841da177e4SLinus Torvalds 
rename_ctl(struct snd_card * card,const char * src,const char * dst)1985eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
19861da177e4SLinus Torvalds {
1987*aa9e9180STakashi Iwai 	struct snd_kcontrol *kctl = snd_ctl_find_id_mixer(card, src);
19881da177e4SLinus Torvalds 	if (kctl) {
198936476b81SMaciej S. Szmigiero 		snd_ctl_rename(card, kctl, dst);
19901da177e4SLinus Torvalds 		return 0;
19911da177e4SLinus Torvalds 	}
19921da177e4SLinus Torvalds 	return -ENOENT;
19931da177e4SLinus Torvalds }
19941da177e4SLinus Torvalds 
snd_emu10k1_mixer(struct snd_emu10k1 * emu,int pcm_device,int multi_device)1995e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
199667ed4161SClemens Ladisch 		      int pcm_device, int multi_device)
19971da177e4SLinus Torvalds {
1998155e3d3bSOswald Buddenhagen 	int err;
1999eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
2000eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
20016fddce26STakashi Iwai 	const char * const *c;
20026fddce26STakashi Iwai 	static const char * const emu10k1_remove_ctls[] = {
20031da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
20041da177e4SLinus Torvalds 		"Master Mono Playback Switch",
20051da177e4SLinus Torvalds 		"Master Mono Playback Volume",
20061da177e4SLinus Torvalds 		"PCM Out Path & Mute",
20071da177e4SLinus Torvalds 		"Mono Output Select",
20081da177e4SLinus Torvalds 		"Surround Playback Switch",
20091da177e4SLinus Torvalds 		"Surround Playback Volume",
20101da177e4SLinus Torvalds 		"Center Playback Switch",
20111da177e4SLinus Torvalds 		"Center Playback Volume",
20121da177e4SLinus Torvalds 		"LFE Playback Switch",
20131da177e4SLinus Torvalds 		"LFE Playback Volume",
20141da177e4SLinus Torvalds 		NULL
20151da177e4SLinus Torvalds 	};
20166fddce26STakashi Iwai 	static const char * const emu10k1_rename_ctls[] = {
20171da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
20181da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
20191da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
20201da177e4SLinus Torvalds 		NULL
20211da177e4SLinus Torvalds 	};
20226fddce26STakashi Iwai 	static const char * const audigy_remove_ctls[] = {
20231da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
202421fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
202521fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
20261da177e4SLinus Torvalds 		"PCM Playback Switch",
20271da177e4SLinus Torvalds 		"PCM Playback Volume",
20281da177e4SLinus Torvalds 		"Master Playback Switch",
20291da177e4SLinus Torvalds 		"Master Playback Volume",
20301da177e4SLinus Torvalds 		"PCM Out Path & Mute",
20311da177e4SLinus Torvalds 		"Mono Output Select",
20321da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
20331da177e4SLinus Torvalds 		"Capture Source",
20341da177e4SLinus Torvalds 		"Capture Switch",
20351da177e4SLinus Torvalds 		"Capture Volume",
20361da177e4SLinus Torvalds 		"Mic Select",
2037274b2000SMaciej S. Szmigiero 		"Headphone Playback Switch",
2038274b2000SMaciej S. Szmigiero 		"Headphone Playback Volume",
2039274b2000SMaciej S. Szmigiero 		"3D Control - Center",
2040274b2000SMaciej S. Szmigiero 		"3D Control - Depth",
2041274b2000SMaciej S. Szmigiero 		"3D Control - Switch",
20421da177e4SLinus Torvalds 		"Video Playback Switch",
20431da177e4SLinus Torvalds 		"Video Playback Volume",
20441da177e4SLinus Torvalds 		"Mic Playback Switch",
20451da177e4SLinus Torvalds 		"Mic Playback Volume",
2046274b2000SMaciej S. Szmigiero 		"External Amplifier",
20471da177e4SLinus Torvalds 		NULL
20481da177e4SLinus Torvalds 	};
20496fddce26STakashi Iwai 	static const char * const audigy_rename_ctls[] = {
20501da177e4SLinus Torvalds 		/* use conventional names */
20511da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
20521da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
20531da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
20541da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
205552051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
205652051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
20571da177e4SLinus Torvalds 		NULL
20581da177e4SLinus Torvalds 	};
20596fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_i2c_adc[] = {
2060184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
2061184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
2062184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
2063184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
2064184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
2065eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
2066184c1e2cSJames Courtier-Dutton 		NULL
2067184c1e2cSJames Courtier-Dutton 	};
20686fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_i2c_adc[] = {
2069184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
2070184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
2071184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
2072184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
2073184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
2074eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
2075184c1e2cSJames Courtier-Dutton 		NULL
2076184c1e2cSJames Courtier-Dutton 	};
20776fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_1361t_adc[] = {
207821fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
207921fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
208021fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
208121fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
208221fdddeaSJames Courtier-Dutton 		"Capture Source",
208321fdddeaSJames Courtier-Dutton 		"Capture Switch",
208421fdddeaSJames Courtier-Dutton 		"Capture Volume",
208521fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
208621fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
208721fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
208821fdddeaSJames Courtier-Dutton 		"3D Control - Center",
208921fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
209021fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
209121fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
209221fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
209321fdddeaSJames Courtier-Dutton 		NULL
209421fdddeaSJames Courtier-Dutton 	};
20956fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_1361t_adc[] = {
209621fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
209721fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
209821fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
2099d355c82aSJaroslav Kysela 		"Beep Playback Switch", "Beep Capture Switch",
2100d355c82aSJaroslav Kysela 		"Beep Playback Volume", "Beep Capture Volume",
210121fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
210221fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
210321fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
210421fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
210521fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
210621fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
210721fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
210821fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
210921fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
211021fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
211121fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
211221fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
211352051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
211452051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
211521fdddeaSJames Courtier-Dutton 		NULL
211621fdddeaSJames Courtier-Dutton 	};
21171da177e4SLinus Torvalds 
21182b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
2119eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
2120eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
212151055da5STakashi Iwai 		static const struct snd_ac97_bus_ops ops = {
21221da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
21231da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
21241da177e4SLinus Torvalds 		};
21251da177e4SLinus Torvalds 
212612bda107STakashi Iwai 		err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus);
212712bda107STakashi Iwai 		if (err < 0)
21281da177e4SLinus Torvalds 			return err;
21291da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
21301da177e4SLinus Torvalds 
21311da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
21321da177e4SLinus Torvalds 		ac97.private_data = emu;
21331da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
21341da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
213512bda107STakashi Iwai 		err = snd_ac97_mixer(pbus, &ac97, &emu->ac97);
213612bda107STakashi Iwai 		if (err < 0) {
2137b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
21381da177e4SLinus Torvalds 				return err;
21396f002b02STakashi Iwai 			dev_info(emu->card->dev,
21406f002b02STakashi Iwai 				 "AC97 is optional on this board\n");
21416f002b02STakashi Iwai 			dev_info(emu->card->dev,
21426f002b02STakashi Iwai 				 "Proceeding without ac97 mixers...\n");
2143b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
2144b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
2145b1508693STakashi Iwai 		}
21461da177e4SLinus Torvalds 		if (emu->audigy) {
21471da177e4SLinus Torvalds 			/* set master volume to 0 dB */
21484d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
21491da177e4SLinus Torvalds 			/* set capture source to mic */
21504d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
215152051942SMaciej S. Szmigiero 			/* set mono output (TAD) to mic */
215252051942SMaciej S. Szmigiero 			snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE,
215352051942SMaciej S. Szmigiero 				0x0200, 0x0200);
215421fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
215521fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
215621fdddeaSJames Courtier-Dutton 			else
21571da177e4SLinus Torvalds 				c = audigy_remove_ctls;
21581da177e4SLinus Torvalds 		} else {
21591da177e4SLinus Torvalds 			/*
21601da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
21611da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
21621da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
21631da177e4SLinus Torvalds 			 */
21641da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
21651da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
21661da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
21672594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
2168b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Volume");
2169b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Switch");
21701da177e4SLinus Torvalds 			}
21711da177e4SLinus Torvalds 			/* remove unused AC97 controls */
21724d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
21734d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
21741da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
21751da177e4SLinus Torvalds 		}
21761da177e4SLinus Torvalds 		for (; *c; c++)
21771da177e4SLinus Torvalds 			remove_ctl(card, *c);
2178184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
2179184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
2180184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
2181184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
21821da177e4SLinus Torvalds 	} else {
2183f12aa40cSTakashi Iwai 	no_ac97:
21842b637da5SLee Revell 		if (emu->card_capabilities->ecard)
21851da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
21861da177e4SLinus Torvalds 		else if (emu->audigy)
21871da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
21881da177e4SLinus Torvalds 		else
21891da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
21901da177e4SLinus Torvalds 	}
21911da177e4SLinus Torvalds 
21921da177e4SLinus Torvalds 	if (emu->audigy)
219321fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
219421fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
2195184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
2196184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
219721fdddeaSJames Courtier-Dutton 		else
21981da177e4SLinus Torvalds 			c = audigy_rename_ctls;
21991da177e4SLinus Torvalds 	else
22001da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
22011da177e4SLinus Torvalds 	for (; *c; c += 2)
22021da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
220321fdddeaSJames Courtier-Dutton 
2204e217b960SRaymond Yau 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
2205e217b960SRaymond Yau 		remove_ctl(card, "Center Playback Volume");
2206e217b960SRaymond Yau 		remove_ctl(card, "LFE Playback Volume");
2207e217b960SRaymond Yau 		remove_ctl(card, "Wave Center Playback Volume");
2208e217b960SRaymond Yau 		remove_ctl(card, "Wave LFE Playback Volume");
2209e217b960SRaymond Yau 	}
2210e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
2211e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
2212e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
2213e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
2214e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
2215e3b9bc0eSJames Courtier-Dutton 	}
221612bda107STakashi Iwai 	kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu);
221712bda107STakashi Iwai 	if (!kctl)
22181da177e4SLinus Torvalds 		return -ENOMEM;
221967ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
222012bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
222112bda107STakashi Iwai 	if (err)
22221da177e4SLinus Torvalds 		return err;
222312bda107STakashi Iwai 	kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu);
222412bda107STakashi Iwai 	if (!kctl)
22251da177e4SLinus Torvalds 		return -ENOMEM;
222667ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
222712bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
222812bda107STakashi Iwai 	if (err)
22291da177e4SLinus Torvalds 		return err;
223012bda107STakashi Iwai 	kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu);
223112bda107STakashi Iwai 	if (!kctl)
22321da177e4SLinus Torvalds 		return -ENOMEM;
223367ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
223412bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
223512bda107STakashi Iwai 	if (err)
22361da177e4SLinus Torvalds 		return err;
22371da177e4SLinus Torvalds 
223812bda107STakashi Iwai 	kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu);
223912bda107STakashi Iwai 	if (!kctl)
22401da177e4SLinus Torvalds 		return -ENOMEM;
224167ed4161SClemens Ladisch 	kctl->id.device = multi_device;
224212bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
224312bda107STakashi Iwai 	if (err)
22441da177e4SLinus Torvalds 		return err;
22451da177e4SLinus Torvalds 
224612bda107STakashi Iwai 	kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu);
224712bda107STakashi Iwai 	if (!kctl)
22481da177e4SLinus Torvalds 		return -ENOMEM;
224967ed4161SClemens Ladisch 	kctl->id.device = multi_device;
225012bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
225112bda107STakashi Iwai 	if (err)
22521da177e4SLinus Torvalds 		return err;
22531da177e4SLinus Torvalds 
225412bda107STakashi Iwai 	kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu);
225512bda107STakashi Iwai 	if (!kctl)
22561da177e4SLinus Torvalds 		return -ENOMEM;
225767ed4161SClemens Ladisch 	kctl->id.device = multi_device;
225812bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
225912bda107STakashi Iwai 	if (err)
22601da177e4SLinus Torvalds 		return err;
22611da177e4SLinus Torvalds 
2262a8661af5SOswald Buddenhagen 	if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) {
22631da177e4SLinus Torvalds 		/* sb live! and audigy */
226412bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu);
226512bda107STakashi Iwai 		if (!kctl)
22661da177e4SLinus Torvalds 			return -ENOMEM;
22675549d549SClemens Ladisch 		if (!emu->audigy)
22685549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
226912bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
227012bda107STakashi Iwai 		if (err)
22711da177e4SLinus Torvalds 			return err;
227212bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu);
227312bda107STakashi Iwai 		if (!kctl)
22741da177e4SLinus Torvalds 			return -ENOMEM;
22755549d549SClemens Ladisch 		if (!emu->audigy)
22765549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
227712bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
227812bda107STakashi Iwai 		if (err)
22791da177e4SLinus Torvalds 			return err;
22801da177e4SLinus Torvalds 	}
22811da177e4SLinus Torvalds 
2282190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
228319b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
228419b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
228512bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu);
228612bda107STakashi Iwai 		if (!kctl)
22871da177e4SLinus Torvalds 			return -ENOMEM;
228812bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
228912bda107STakashi Iwai 		if (err)
22901da177e4SLinus Torvalds 			return err;
2291001f7589SJames Courtier-Dutton #if 0
229212bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu);
229312bda107STakashi Iwai 		if (!kctl)
22941da177e4SLinus Torvalds 			return -ENOMEM;
229512bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
229612bda107STakashi Iwai 		if (err)
22971da177e4SLinus Torvalds 			return err;
2298001f7589SJames Courtier-Dutton #endif
22992b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
23001da177e4SLinus Torvalds 		/* sb live! */
230112bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu);
230212bda107STakashi Iwai 		if (!kctl)
23031da177e4SLinus Torvalds 			return -ENOMEM;
230412bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
230512bda107STakashi Iwai 		if (err)
23061da177e4SLinus Torvalds 			return err;
23071da177e4SLinus Torvalds 	}
23082b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
230912bda107STakashi Iwai 		err = snd_p16v_mixer(emu);
231012bda107STakashi Iwai 		if (err)
23111da177e4SLinus Torvalds 			return err;
23121da177e4SLinus Torvalds 	}
23131da177e4SLinus Torvalds 
23141fc710f0SOswald Buddenhagen 	if (emu->card_capabilities->emu_model) {
23151fc710f0SOswald Buddenhagen 		unsigned i, emu_idx = emu1010_idx(emu);
23161fc710f0SOswald Buddenhagen 		const struct snd_emu1010_routing_info *emu_ri =
23171fc710f0SOswald Buddenhagen 			&emu1010_routing_info[emu_idx];
231897f1582eSOswald Buddenhagen 		const struct snd_emu1010_pads_info *emu_pi = &emu1010_pads_info[emu_idx];
23191fc710f0SOswald Buddenhagen 
23201fc710f0SOswald Buddenhagen 		for (i = 0; i < emu_ri->n_ins; i++)
23211fc710f0SOswald Buddenhagen 			emu->emu1010.input_source[i] =
23221fc710f0SOswald Buddenhagen 				emu1010_map_source(emu_ri, emu_ri->in_dflts[i]);
23231fc710f0SOswald Buddenhagen 		for (i = 0; i < emu_ri->n_outs; i++)
23241fc710f0SOswald Buddenhagen 			emu->emu1010.output_source[i] =
23251fc710f0SOswald Buddenhagen 				emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
23261fc710f0SOswald Buddenhagen 		snd_emu1010_apply_sources(emu);
23271fc710f0SOswald Buddenhagen 
2328c960b012SOswald Buddenhagen 		kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu);
2329c960b012SOswald Buddenhagen 		err = snd_ctl_add(card, kctl);
233013598862SOswald Buddenhagen 		if (err < 0)
233113598862SOswald Buddenhagen 			return err;
233213598862SOswald Buddenhagen 		err = snd_ctl_add(card,
233313598862SOswald Buddenhagen 			snd_ctl_new1(&snd_emu1010_clock_fallback, emu));
23341c02e366SCtirad Fertr 		if (err < 0)
23351c02e366SCtirad Fertr 			return err;
233697f1582eSOswald Buddenhagen 
233797f1582eSOswald Buddenhagen 		err = add_ctls(emu, &emu1010_adc_pads_ctl,
233897f1582eSOswald Buddenhagen 			       emu_pi->adc_ctls, emu_pi->n_adc_ctls);
233997f1582eSOswald Buddenhagen 		if (err < 0)
234097f1582eSOswald Buddenhagen 			return err;
234197f1582eSOswald Buddenhagen 		err = add_ctls(emu, &emu1010_dac_pads_ctl,
234297f1582eSOswald Buddenhagen 			       emu_pi->dac_ctls, emu_pi->n_dac_ctls);
234397f1582eSOswald Buddenhagen 		if (err < 0)
234497f1582eSOswald Buddenhagen 			return err;
234597f1582eSOswald Buddenhagen 
23466f3609f8SOswald Buddenhagen 		if (!emu->card_capabilities->no_adat) {
234799dcab46SMichael Gernoth 			err = snd_ctl_add(card,
234899dcab46SMichael Gernoth 				snd_ctl_new1(&snd_emu1010_optical_out, emu));
234999dcab46SMichael Gernoth 			if (err < 0)
235099dcab46SMichael Gernoth 				return err;
235199dcab46SMichael Gernoth 			err = snd_ctl_add(card,
235299dcab46SMichael Gernoth 				snd_ctl_new1(&snd_emu1010_optical_in, emu));
235399dcab46SMichael Gernoth 			if (err < 0)
235499dcab46SMichael Gernoth 				return err;
23556f3609f8SOswald Buddenhagen 		}
23561c02e366SCtirad Fertr 
235797f1582eSOswald Buddenhagen 		err = add_emu1010_source_mixers(emu);
235899dcab46SMichael Gernoth 		if (err < 0)
235999dcab46SMichael Gernoth 			return err;
23609f4bd5ddSJames Courtier-Dutton 	}
23619f4bd5ddSJames Courtier-Dutton 
2362184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2363184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2364184c1e2cSJames Courtier-Dutton 		if (err < 0)
2365184c1e2cSJames Courtier-Dutton 			return err;
2366184c1e2cSJames Courtier-Dutton 
2367536438f1SOswald Buddenhagen 		err = add_ctls(emu, &i2c_volume_ctl,
2368536438f1SOswald Buddenhagen 			       snd_audigy_i2c_volume_ctls,
2369536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_audigy_i2c_volume_ctls));
2370184c1e2cSJames Courtier-Dutton 		if (err < 0)
2371184c1e2cSJames Courtier-Dutton 			return err;
2372184c1e2cSJames Courtier-Dutton 	}
2373184c1e2cSJames Courtier-Dutton 
237416950e09STakashi Iwai 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
237516950e09STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
237616950e09STakashi Iwai 						     emu));
237716950e09STakashi Iwai 		if (err < 0)
237816950e09STakashi Iwai 			return err;
237916950e09STakashi Iwai 	}
238016950e09STakashi Iwai 
23811da177e4SLinus Torvalds 	return 0;
23821da177e4SLinus Torvalds }
2383