xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision f69d705d3972fae19b4b00c7643efdd3d2953f25)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
3c1017a4cSJaroslav Kysela  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
41da177e4SLinus Torvalds  *                   Takashi Iwai <tiwai@suse.de>
51da177e4SLinus Torvalds  *                   Creative Labs, Inc.
61da177e4SLinus Torvalds  *  Routines for control of EMU10K1 chips / mixer routines
71da177e4SLinus Torvalds  *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
81da177e4SLinus Torvalds  *
99f4bd5ddSJames Courtier-Dutton  *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
109f4bd5ddSJames Courtier-Dutton  *  	Added EMU 1010 support.
119f4bd5ddSJames Courtier-Dutton  *
121da177e4SLinus Torvalds  *  BUGS:
131da177e4SLinus Torvalds  *    --
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  *  TODO:
161da177e4SLinus Torvalds  *    --
171da177e4SLinus Torvalds  */
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds #include <linux/time.h>
201da177e4SLinus Torvalds #include <linux/init.h>
211da177e4SLinus Torvalds #include <sound/core.h>
221da177e4SLinus Torvalds #include <sound/emu10k1.h>
23b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h>
24184c1e2cSJames Courtier-Dutton #include <sound/tlv.h>
25184c1e2cSJames Courtier-Dutton 
26184c1e2cSJames Courtier-Dutton #include "p17v.h"
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #define AC97_ID_STAC9758	0x83847658
291da177e4SLinus Torvalds 
300cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
31184c1e2cSJames Courtier-Dutton 
32536438f1SOswald Buddenhagen 
33536438f1SOswald Buddenhagen static int add_ctls(struct snd_emu10k1 *emu, const struct snd_kcontrol_new *tpl,
34536438f1SOswald Buddenhagen 		    const char * const *ctls, unsigned nctls)
35536438f1SOswald Buddenhagen {
36536438f1SOswald Buddenhagen 	struct snd_kcontrol_new kctl = *tpl;
37536438f1SOswald Buddenhagen 	int err;
38536438f1SOswald Buddenhagen 
39536438f1SOswald Buddenhagen 	for (unsigned i = 0; i < nctls; i++) {
40536438f1SOswald Buddenhagen 		kctl.name = ctls[i];
41536438f1SOswald Buddenhagen 		kctl.private_value = i;
42536438f1SOswald Buddenhagen 		err = snd_ctl_add(emu->card, snd_ctl_new1(&kctl, emu));
43536438f1SOswald Buddenhagen 		if (err < 0)
44536438f1SOswald Buddenhagen 			return err;
45536438f1SOswald Buddenhagen 	}
46536438f1SOswald Buddenhagen 	return 0;
47536438f1SOswald Buddenhagen }
48536438f1SOswald Buddenhagen 
49536438f1SOswald Buddenhagen 
50eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
511da177e4SLinus Torvalds {
521da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
531da177e4SLinus Torvalds 	uinfo->count = 1;
541da177e4SLinus Torvalds 	return 0;
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds 
57eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
58eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
591da177e4SLinus Torvalds {
60eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
611da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
621da177e4SLinus Torvalds 
6374415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
6474415a36SJames Courtier-Dutton 	if (idx >= 3)
6574415a36SJames Courtier-Dutton 		return -EINVAL;
661da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
671da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
681da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
691da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
701da177e4SLinus Torvalds 	return 0;
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds 
73eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
74eb4698f3STakashi Iwai 				      struct snd_ctl_elem_value *ucontrol)
751da177e4SLinus Torvalds {
761da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
771da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
781da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
791da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
801da177e4SLinus Torvalds 	return 0;
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds 
83dc39bb3eSOswald Buddenhagen #define PAIR_PS(base, one, two, sfx) base " " one sfx, base " " two sfx
84dc39bb3eSOswald Buddenhagen #define LR_PS(base, sfx) PAIR_PS(base, "Left", "Right", sfx)
859f4bd5ddSJames Courtier-Dutton 
86dc39bb3eSOswald Buddenhagen #define ADAT_PS(pfx, sfx) \
87dc39bb3eSOswald Buddenhagen 	pfx "ADAT 0" sfx, pfx "ADAT 1" sfx, pfx "ADAT 2" sfx, pfx "ADAT 3" sfx, \
88dc39bb3eSOswald Buddenhagen 	pfx "ADAT 4" sfx, pfx "ADAT 5" sfx, pfx "ADAT 6" sfx, pfx "ADAT 7" sfx
891c02e366SCtirad Fertr 
90dc39bb3eSOswald Buddenhagen #define PAIR_REGS(base, one, two) \
91dc39bb3eSOswald Buddenhagen 	base ## one ## 1, \
92dc39bb3eSOswald Buddenhagen 	base ## two ## 1
931c02e366SCtirad Fertr 
94dc39bb3eSOswald Buddenhagen #define LR_REGS(base) PAIR_REGS(base, _LEFT, _RIGHT)
95dc39bb3eSOswald Buddenhagen 
96dc39bb3eSOswald Buddenhagen #define ADAT_REGS(base) \
97dc39bb3eSOswald Buddenhagen 	base+0, base+1, base+2, base+3, base+4, base+5, base+6, base+7
981c02e366SCtirad Fertr 
9913d45709SPavel Hofman /*
10013d45709SPavel Hofman  * List of data sources available for each destination
10113d45709SPavel Hofman  */
102dc39bb3eSOswald Buddenhagen 
103dc39bb3eSOswald Buddenhagen #define DSP_TEXTS \
104dc39bb3eSOswald Buddenhagen 	"DSP 0", "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", \
105dc39bb3eSOswald Buddenhagen 	"DSP 8", "DSP 9", "DSP 10", "DSP 11", "DSP 12", "DSP 13", "DSP 14", "DSP 15", \
106dc39bb3eSOswald Buddenhagen 	"DSP 16", "DSP 17", "DSP 18", "DSP 19", "DSP 20", "DSP 21", "DSP 22", "DSP 23", \
107dc39bb3eSOswald Buddenhagen 	"DSP 24", "DSP 25", "DSP 26", "DSP 27", "DSP 28", "DSP 29", "DSP 30", "DSP 31"
108dc39bb3eSOswald Buddenhagen 
109dc39bb3eSOswald Buddenhagen #define PAIR_TEXTS(base, one, two) PAIR_PS(base, one, two, "")
110dc39bb3eSOswald Buddenhagen #define LR_TEXTS(base) LR_PS(base, "")
111dc39bb3eSOswald Buddenhagen #define ADAT_TEXTS(pfx) ADAT_PS(pfx, "")
112dc39bb3eSOswald Buddenhagen 
113dc39bb3eSOswald Buddenhagen #define EMU32_SRC_REGS \
114dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A, \
115dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+1, \
116dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, \
117dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+3, \
118dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, \
119dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+5, \
120dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+6, \
121dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+7, \
122dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+8, \
123dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+9, \
124dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xa, \
125dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xb, \
126dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xc, \
127dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xd, \
128dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xe, \
129dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0xf, \
130dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B, \
131dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+1, \
132dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+2, \
133dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+3, \
134dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+4, \
135dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+5, \
136dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+6, \
137dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+7, \
138dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+8, \
139dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+9, \
140dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xa, \
141dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xb, \
142dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xc, \
143dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xd, \
144dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xe, \
145dc39bb3eSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32B+0xf
146dc39bb3eSOswald Buddenhagen 
147dc39bb3eSOswald Buddenhagen #define EMU1010_COMMON_TEXTS \
148dc39bb3eSOswald Buddenhagen 	"Silence", \
149dc39bb3eSOswald Buddenhagen 	PAIR_TEXTS("Dock Mic", "A", "B"), \
150dc39bb3eSOswald Buddenhagen 	LR_TEXTS("Dock ADC1"), \
151dc39bb3eSOswald Buddenhagen 	LR_TEXTS("Dock ADC2"), \
152dc39bb3eSOswald Buddenhagen 	LR_TEXTS("Dock ADC3"), \
153dc39bb3eSOswald Buddenhagen 	LR_TEXTS("0202 ADC"), \
154dc39bb3eSOswald Buddenhagen 	LR_TEXTS("1010 SPDIF"), \
155dc39bb3eSOswald Buddenhagen 	ADAT_TEXTS("1010 ")
156dc39bb3eSOswald Buddenhagen 
157dc39bb3eSOswald Buddenhagen static const char * const emu1010_src_texts[] = {
158dc39bb3eSOswald Buddenhagen 	EMU1010_COMMON_TEXTS,
159dc39bb3eSOswald Buddenhagen 	DSP_TEXTS,
1609f4bd5ddSJames Courtier-Dutton };
1619f4bd5ddSJames Courtier-Dutton 
162dc39bb3eSOswald Buddenhagen static const unsigned short emu1010_src_regs[] = {
163dc39bb3eSOswald Buddenhagen 	EMU_SRC_SILENCE,
164dc39bb3eSOswald Buddenhagen 	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
165dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC1),
166dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC2),
167dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC3),
168dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_HAMOA_ADC),
169dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_HANA_SPDIF),
170dc39bb3eSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_HANA_ADAT),
171dc39bb3eSOswald Buddenhagen 	EMU32_SRC_REGS,
172dc39bb3eSOswald Buddenhagen };
173dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_src_regs) == ARRAY_SIZE(emu1010_src_texts));
174dc39bb3eSOswald Buddenhagen 
175*f69d705dSOswald Buddenhagen /* 1010 rev2 */
176*f69d705dSOswald Buddenhagen 
177*f69d705dSOswald Buddenhagen #define EMU1010b_COMMON_TEXTS \
178*f69d705dSOswald Buddenhagen 	"Silence", \
179*f69d705dSOswald Buddenhagen 	PAIR_TEXTS("Dock Mic", "A", "B"), \
180*f69d705dSOswald Buddenhagen 	LR_TEXTS("Dock ADC1"), \
181*f69d705dSOswald Buddenhagen 	LR_TEXTS("Dock ADC2"), \
182*f69d705dSOswald Buddenhagen 	LR_TEXTS("0202 ADC"), \
183*f69d705dSOswald Buddenhagen 	LR_TEXTS("Dock SPDIF"), \
184*f69d705dSOswald Buddenhagen 	LR_TEXTS("1010 SPDIF"), \
185*f69d705dSOswald Buddenhagen 	ADAT_TEXTS("Dock "), \
186*f69d705dSOswald Buddenhagen 	ADAT_TEXTS("1010 ")
187*f69d705dSOswald Buddenhagen 
188*f69d705dSOswald Buddenhagen static const char * const emu1010b_src_texts[] = {
189*f69d705dSOswald Buddenhagen 	EMU1010b_COMMON_TEXTS,
190*f69d705dSOswald Buddenhagen 	DSP_TEXTS,
191*f69d705dSOswald Buddenhagen };
192*f69d705dSOswald Buddenhagen 
193*f69d705dSOswald Buddenhagen static const unsigned short emu1010b_src_regs[] = {
194*f69d705dSOswald Buddenhagen 	EMU_SRC_SILENCE,
195*f69d705dSOswald Buddenhagen 	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
196*f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC1),
197*f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC2),
198*f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_HAMOA_ADC),
199*f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_MDOCK_SPDIF),
200*f69d705dSOswald Buddenhagen 	LR_REGS(EMU_SRC_HANA_SPDIF),
201*f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_MDOCK_ADAT),
202*f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_HANA_ADAT),
203*f69d705dSOswald Buddenhagen 	EMU32_SRC_REGS,
204*f69d705dSOswald Buddenhagen };
205*f69d705dSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010b_src_regs) == ARRAY_SIZE(emu1010b_src_texts));
206*f69d705dSOswald Buddenhagen 
2071c02e366SCtirad Fertr /* 1616(m) cardbus */
208dc39bb3eSOswald Buddenhagen 
209dc39bb3eSOswald Buddenhagen #define EMU1616_COMMON_TEXTS \
210dc39bb3eSOswald Buddenhagen 	"Silence", \
211dc39bb3eSOswald Buddenhagen 	PAIR_TEXTS("Mic", "A", "B"), \
212dc39bb3eSOswald Buddenhagen 	LR_TEXTS("ADC1"), \
213dc39bb3eSOswald Buddenhagen 	LR_TEXTS("ADC2"), \
214dc39bb3eSOswald Buddenhagen 	LR_TEXTS("SPDIF"), \
215dc39bb3eSOswald Buddenhagen 	ADAT_TEXTS("")
216dc39bb3eSOswald Buddenhagen 
217dc39bb3eSOswald Buddenhagen static const char * const emu1616_src_texts[] = {
218dc39bb3eSOswald Buddenhagen 	EMU1616_COMMON_TEXTS,
219dc39bb3eSOswald Buddenhagen 	DSP_TEXTS,
220dc39bb3eSOswald Buddenhagen };
221dc39bb3eSOswald Buddenhagen 
2229b00a1e9SOswald Buddenhagen static const unsigned short emu1616_src_regs[] = {
2231c02e366SCtirad Fertr 	EMU_SRC_SILENCE,
224dc39bb3eSOswald Buddenhagen 	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
225dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC1),
226dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC2),
227dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_MDOCK_SPDIF),
228dc39bb3eSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_MDOCK_ADAT),
229dc39bb3eSOswald Buddenhagen 	EMU32_SRC_REGS,
2301c02e366SCtirad Fertr };
231dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_src_regs) == ARRAY_SIZE(emu1616_src_texts));
2321c02e366SCtirad Fertr 
23313d45709SPavel Hofman /*
23413d45709SPavel Hofman  * Data destinations - physical EMU outputs.
23513d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
23613d45709SPavel Hofman  */
237536438f1SOswald Buddenhagen 
238536438f1SOswald Buddenhagen #define LR_CTLS(base) LR_PS(base, " Playback Enum")
239536438f1SOswald Buddenhagen #define ADAT_CTLS(pfx) ADAT_PS(pfx, " Playback Enum")
240536438f1SOswald Buddenhagen 
241536438f1SOswald Buddenhagen static const char * const emu1010_output_texts[] = {
242536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
243536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
244536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
245536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC4"),
246536438f1SOswald Buddenhagen 	LR_CTLS("Dock Phones"),
247536438f1SOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
248536438f1SOswald Buddenhagen 	LR_CTLS("0202 DAC"),
249536438f1SOswald Buddenhagen 	LR_CTLS("1010 SPDIF"),
250536438f1SOswald Buddenhagen 	ADAT_CTLS("1010 "),
2519f4bd5ddSJames Courtier-Dutton };
2529f4bd5ddSJames Courtier-Dutton 
253536438f1SOswald Buddenhagen static const unsigned short emu1010_output_dst[] = {
254536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
255536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
256536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
257536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC4),
258536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_PHONES),
259536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_SPDIF),
260536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
261536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
262536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_HANA_ADAT),
2631c02e366SCtirad Fertr };
264536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dst) == ARRAY_SIZE(emu1010_output_texts));
265536438f1SOswald Buddenhagen 
2661fc710f0SOswald Buddenhagen static const unsigned short emu1010_output_dflt[] = {
2671fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2681fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
2691fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
2701fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
2711fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2721fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2731fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2741fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2751fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
2761fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
2771fc710f0SOswald Buddenhagen };
2781fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dflt) == ARRAY_SIZE(emu1010_output_dst));
2791fc710f0SOswald Buddenhagen 
280*f69d705dSOswald Buddenhagen /* 1010 rev2 */
281*f69d705dSOswald Buddenhagen 
282*f69d705dSOswald Buddenhagen static const char * const snd_emu1010b_output_texts[] = {
283*f69d705dSOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
284*f69d705dSOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
285*f69d705dSOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
286*f69d705dSOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
287*f69d705dSOswald Buddenhagen 	ADAT_CTLS("Dock "),
288*f69d705dSOswald Buddenhagen 	LR_CTLS("0202 DAC"),
289*f69d705dSOswald Buddenhagen 	LR_CTLS("1010 SPDIF"),
290*f69d705dSOswald Buddenhagen 	ADAT_CTLS("1010 "),
291*f69d705dSOswald Buddenhagen };
292*f69d705dSOswald Buddenhagen 
293*f69d705dSOswald Buddenhagen static const unsigned short emu1010b_output_dst[] = {
294*f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
295*f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
296*f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
297*f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_MDOCK_SPDIF),
298*f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_DST_MDOCK_ADAT),
299*f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
300*f69d705dSOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
301*f69d705dSOswald Buddenhagen 	ADAT_REGS(EMU_DST_HANA_ADAT),
302*f69d705dSOswald Buddenhagen };
303*f69d705dSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010b_output_dst) == ARRAY_SIZE(snd_emu1010b_output_texts));
304*f69d705dSOswald Buddenhagen 
305*f69d705dSOswald Buddenhagen static const unsigned short emu1010b_output_dflt[] = {
306*f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
307*f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
308*f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
309*f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
310*f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
311*f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
312*f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
313*f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
314*f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
315*f69d705dSOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
316*f69d705dSOswald Buddenhagen };
317*f69d705dSOswald Buddenhagen 
318536438f1SOswald Buddenhagen /* 1616(m) cardbus */
319536438f1SOswald Buddenhagen 
320536438f1SOswald Buddenhagen static const char * const snd_emu1616_output_texts[] = {
321536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
322536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
323536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
324536438f1SOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
325536438f1SOswald Buddenhagen 	ADAT_CTLS("Dock "),
326536438f1SOswald Buddenhagen 	LR_CTLS("Mana DAC"),
327536438f1SOswald Buddenhagen };
328536438f1SOswald Buddenhagen 
329536438f1SOswald Buddenhagen static const unsigned short emu1616_output_dst[] = {
330536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
331536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
332536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
333536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_MDOCK_SPDIF),
334536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_MDOCK_ADAT),
335536438f1SOswald Buddenhagen 	EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT,
336536438f1SOswald Buddenhagen };
337536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dst) == ARRAY_SIZE(snd_emu1616_output_texts));
3381c02e366SCtirad Fertr 
3391fc710f0SOswald Buddenhagen static const unsigned short emu1616_output_dflt[] = {
3401fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3411fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
3421fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
3431fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3441fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
3451fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
3461fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
3471fc710f0SOswald Buddenhagen };
3481fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dflt) == ARRAY_SIZE(emu1616_output_dst));
3491fc710f0SOswald Buddenhagen 
35013d45709SPavel Hofman /*
351a869057cSOswald Buddenhagen  * Data destinations - FPGA outputs going to Alice2 (Audigy) for
35213d45709SPavel Hofman  *   capture (EMU32 + I2S links)
35313d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
35413d45709SPavel Hofman  */
355536438f1SOswald Buddenhagen 
356536438f1SOswald Buddenhagen static const char * const emu1010_input_texts[] = {
357536438f1SOswald Buddenhagen 	"DSP 0 Capture Enum",
358536438f1SOswald Buddenhagen 	"DSP 1 Capture Enum",
359536438f1SOswald Buddenhagen 	"DSP 2 Capture Enum",
360536438f1SOswald Buddenhagen 	"DSP 3 Capture Enum",
361536438f1SOswald Buddenhagen 	"DSP 4 Capture Enum",
362536438f1SOswald Buddenhagen 	"DSP 5 Capture Enum",
363536438f1SOswald Buddenhagen 	"DSP 6 Capture Enum",
364536438f1SOswald Buddenhagen 	"DSP 7 Capture Enum",
365536438f1SOswald Buddenhagen 	"DSP 8 Capture Enum",
366536438f1SOswald Buddenhagen 	"DSP 9 Capture Enum",
367536438f1SOswald Buddenhagen 	"DSP A Capture Enum",
368536438f1SOswald Buddenhagen 	"DSP B Capture Enum",
369536438f1SOswald Buddenhagen 	"DSP C Capture Enum",
370536438f1SOswald Buddenhagen 	"DSP D Capture Enum",
371536438f1SOswald Buddenhagen 	"DSP E Capture Enum",
372536438f1SOswald Buddenhagen 	"DSP F Capture Enum",
373536438f1SOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
374536438f1SOswald Buddenhagen 	"DSP 10 Capture Enum",
375536438f1SOswald Buddenhagen 	"DSP 11 Capture Enum",
376536438f1SOswald Buddenhagen 	"DSP 12 Capture Enum",
377536438f1SOswald Buddenhagen 	"DSP 13 Capture Enum",
378536438f1SOswald Buddenhagen 	"DSP 14 Capture Enum",
379536438f1SOswald Buddenhagen 	"DSP 15 Capture Enum",
380536438f1SOswald Buddenhagen };
381536438f1SOswald Buddenhagen 
3829b00a1e9SOswald Buddenhagen static const unsigned short emu1010_input_dst[] = {
3839f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_0,
3849f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_1,
3859f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_2,
3869f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_3,
3879f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_4,
3889f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_5,
3899f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_6,
3909f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_7,
3919f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_8,
3929f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_9,
3939f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_A,
3949f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_B,
3959f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_C,
3969f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_D,
3979f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_E,
3989f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_F,
399a869057cSOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
4009f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_LEFT,
4019f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_RIGHT,
4029f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_LEFT,
4039f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_RIGHT,
4049f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_LEFT,
4059f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_RIGHT,
4069f4bd5ddSJames Courtier-Dutton };
407536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts));
4089f4bd5ddSJames Courtier-Dutton 
4091fc710f0SOswald Buddenhagen static const unsigned short emu1010_input_dflt[] = {
4101fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_A1,
4111fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_B1,
4121fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
4131fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
4141fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
4151fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
4161fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
4171fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
4181fc710f0SOswald Buddenhagen 	/* Pavel Hofman - setting defaults for all capture channels.
4191fc710f0SOswald Buddenhagen 	 * Defaults only, users will set their own values anyways, let's
4201fc710f0SOswald Buddenhagen 	 * just copy/paste. */
4211fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_A1,
4221fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_B1,
4231fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
4241fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
4251fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
4261fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
4271fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
4281fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
4291fc710f0SOswald Buddenhagen 
4301fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
4311fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
4321fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
4331fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
4341fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC3_LEFT1,
4351fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC3_RIGHT1,
4361fc710f0SOswald Buddenhagen };
4371fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dflt) == ARRAY_SIZE(emu1010_input_dst));
4381fc710f0SOswald Buddenhagen 
439511cbe8fSOswald Buddenhagen struct snd_emu1010_routing_info {
440511cbe8fSOswald Buddenhagen 	const char * const *src_texts;
44197f1582eSOswald Buddenhagen 	const char * const *out_texts;
442511cbe8fSOswald Buddenhagen 	const unsigned short *src_regs;
443511cbe8fSOswald Buddenhagen 	const unsigned short *out_regs;
444511cbe8fSOswald Buddenhagen 	const unsigned short *in_regs;
4451fc710f0SOswald Buddenhagen 	const unsigned short *out_dflts;
4461fc710f0SOswald Buddenhagen 	const unsigned short *in_dflts;
447511cbe8fSOswald Buddenhagen 	unsigned n_srcs;
448511cbe8fSOswald Buddenhagen 	unsigned n_outs;
449511cbe8fSOswald Buddenhagen 	unsigned n_ins;
450511cbe8fSOswald Buddenhagen };
451511cbe8fSOswald Buddenhagen 
452511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info emu1010_routing_info[] = {
453511cbe8fSOswald Buddenhagen 	{
454511cbe8fSOswald Buddenhagen 		.src_regs = emu1010_src_regs,
455511cbe8fSOswald Buddenhagen 		.src_texts = emu1010_src_texts,
456511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1010_src_texts),
457511cbe8fSOswald Buddenhagen 
4581fc710f0SOswald Buddenhagen 		.out_dflts = emu1010_output_dflt,
459511cbe8fSOswald Buddenhagen 		.out_regs = emu1010_output_dst,
46097f1582eSOswald Buddenhagen 		.out_texts = emu1010_output_texts,
461511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1010_output_dst),
462511cbe8fSOswald Buddenhagen 
4631fc710f0SOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
464511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
465511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst),
466511cbe8fSOswald Buddenhagen 	},
467511cbe8fSOswald Buddenhagen 	{
468*f69d705dSOswald Buddenhagen 		/* rev2 1010 */
469*f69d705dSOswald Buddenhagen 		.src_regs = emu1010b_src_regs,
470*f69d705dSOswald Buddenhagen 		.src_texts = emu1010b_src_texts,
471*f69d705dSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1010b_src_texts),
472*f69d705dSOswald Buddenhagen 
473*f69d705dSOswald Buddenhagen 		.out_dflts = emu1010b_output_dflt,
474*f69d705dSOswald Buddenhagen 		.out_regs = emu1010b_output_dst,
475*f69d705dSOswald Buddenhagen 		.out_texts = snd_emu1010b_output_texts,
476*f69d705dSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1010b_output_dst),
477*f69d705dSOswald Buddenhagen 
478*f69d705dSOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
479*f69d705dSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
480*f69d705dSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
481*f69d705dSOswald Buddenhagen 	},
482*f69d705dSOswald Buddenhagen 	{
483511cbe8fSOswald Buddenhagen 		/* 1616(m) cardbus */
484511cbe8fSOswald Buddenhagen 		.src_regs = emu1616_src_regs,
485511cbe8fSOswald Buddenhagen 		.src_texts = emu1616_src_texts,
486511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1616_src_texts),
487511cbe8fSOswald Buddenhagen 
4881fc710f0SOswald Buddenhagen 		.out_dflts = emu1616_output_dflt,
489511cbe8fSOswald Buddenhagen 		.out_regs = emu1616_output_dst,
49097f1582eSOswald Buddenhagen 		.out_texts = snd_emu1616_output_texts,
491511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1616_output_dst),
492511cbe8fSOswald Buddenhagen 
4931fc710f0SOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
494511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
495511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
496511cbe8fSOswald Buddenhagen 	},
497511cbe8fSOswald Buddenhagen };
498511cbe8fSOswald Buddenhagen 
499511cbe8fSOswald Buddenhagen static unsigned emu1010_idx(struct snd_emu10k1 *emu)
500511cbe8fSOswald Buddenhagen {
501511cbe8fSOswald Buddenhagen 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
502*f69d705dSOswald Buddenhagen 		return 2;
503*f69d705dSOswald Buddenhagen 	else if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010B)
504511cbe8fSOswald Buddenhagen 		return 1;
505511cbe8fSOswald Buddenhagen 	else
506511cbe8fSOswald Buddenhagen 		return 0;
507511cbe8fSOswald Buddenhagen }
508511cbe8fSOswald Buddenhagen 
509511cbe8fSOswald Buddenhagen static void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu,
510511cbe8fSOswald Buddenhagen 					    int channel, int src)
511511cbe8fSOswald Buddenhagen {
512511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
513511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
514511cbe8fSOswald Buddenhagen 
515511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
516511cbe8fSOswald Buddenhagen 		emu_ri->out_regs[channel], emu_ri->src_regs[src]);
517511cbe8fSOswald Buddenhagen }
518511cbe8fSOswald Buddenhagen 
519511cbe8fSOswald Buddenhagen static void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu,
520511cbe8fSOswald Buddenhagen 					   int channel, int src)
521511cbe8fSOswald Buddenhagen {
522511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
523511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
524511cbe8fSOswald Buddenhagen 
525511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
526511cbe8fSOswald Buddenhagen 		emu_ri->in_regs[channel], emu_ri->src_regs[src]);
527511cbe8fSOswald Buddenhagen }
528511cbe8fSOswald Buddenhagen 
5291fc710f0SOswald Buddenhagen static void snd_emu1010_apply_sources(struct snd_emu10k1 *emu)
5301fc710f0SOswald Buddenhagen {
5311fc710f0SOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
5321fc710f0SOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
5331fc710f0SOswald Buddenhagen 
5341fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_outs; i++)
5351fc710f0SOswald Buddenhagen 		snd_emu1010_output_source_apply(
5361fc710f0SOswald Buddenhagen 			emu, i, emu->emu1010.output_source[i]);
5371fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_ins; i++)
5381fc710f0SOswald Buddenhagen 		snd_emu1010_input_source_apply(
5391fc710f0SOswald Buddenhagen 			emu, i, emu->emu1010.input_source[i]);
5401fc710f0SOswald Buddenhagen }
5411fc710f0SOswald Buddenhagen 
5421fc710f0SOswald Buddenhagen static u8 emu1010_map_source(const struct snd_emu1010_routing_info *emu_ri,
5431fc710f0SOswald Buddenhagen 			     unsigned val)
5441fc710f0SOswald Buddenhagen {
5451fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_srcs; i++)
5461fc710f0SOswald Buddenhagen 		if (val == emu_ri->src_regs[i])
5471fc710f0SOswald Buddenhagen 			return i;
5481fc710f0SOswald Buddenhagen 	return 0;
5491fc710f0SOswald Buddenhagen }
5501fc710f0SOswald Buddenhagen 
5511c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
5521c02e366SCtirad Fertr 						struct snd_ctl_elem_info *uinfo)
5539f4bd5ddSJames Courtier-Dutton {
5541c02e366SCtirad Fertr 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
555511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
556511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
5571c02e366SCtirad Fertr 
558511cbe8fSOswald Buddenhagen 	return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts);
5599f4bd5ddSJames Courtier-Dutton }
5609f4bd5ddSJames Courtier-Dutton 
5619f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
5629f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
5639f4bd5ddSJames Courtier-Dutton {
5649f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
565511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
566511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
567511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
5689f4bd5ddSJames Courtier-Dutton 
569511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
57074415a36SJames Courtier-Dutton 		return -EINVAL;
5719f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
5729f4bd5ddSJames Courtier-Dutton 	return 0;
5739f4bd5ddSJames Courtier-Dutton }
5749f4bd5ddSJames Courtier-Dutton 
5759f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
5769f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
5779f4bd5ddSJames Courtier-Dutton {
5789f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
579511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
580511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
581511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
582511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
583511cbe8fSOswald Buddenhagen 	int change;
5849f4bd5ddSJames Courtier-Dutton 
585511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
586aa299d01STakashi Iwai 		return -EINVAL;
587511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
58874415a36SJames Courtier-Dutton 		return -EINVAL;
589511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.output_source[channel] != val);
590511cbe8fSOswald Buddenhagen 	if (change) {
591aa299d01STakashi Iwai 		emu->emu1010.output_source[channel] = val;
592511cbe8fSOswald Buddenhagen 		snd_emu1010_output_source_apply(emu, channel, val);
593511cbe8fSOswald Buddenhagen 	}
594511cbe8fSOswald Buddenhagen 	return change;
5959f4bd5ddSJames Courtier-Dutton }
5969f4bd5ddSJames Courtier-Dutton 
597536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_output_source_ctl = {
598536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
599536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
600536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
601536438f1SOswald Buddenhagen 	.get = snd_emu1010_output_source_get,
602536438f1SOswald Buddenhagen 	.put = snd_emu1010_output_source_put
603536438f1SOswald Buddenhagen };
604536438f1SOswald Buddenhagen 
6059f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
6069f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6079f4bd5ddSJames Courtier-Dutton {
6089f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
609511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
610511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
611511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
6129f4bd5ddSJames Courtier-Dutton 
613511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
61474415a36SJames Courtier-Dutton 		return -EINVAL;
6159f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
6169f4bd5ddSJames Courtier-Dutton 	return 0;
6179f4bd5ddSJames Courtier-Dutton }
6189f4bd5ddSJames Courtier-Dutton 
6199f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
6209f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
6219f4bd5ddSJames Courtier-Dutton {
6229f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
623511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
624511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
625511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
626511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
627511cbe8fSOswald Buddenhagen 	int change;
6289f4bd5ddSJames Courtier-Dutton 
629511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
630aa299d01STakashi Iwai 		return -EINVAL;
631511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
63274415a36SJames Courtier-Dutton 		return -EINVAL;
633511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.input_source[channel] != val);
634511cbe8fSOswald Buddenhagen 	if (change) {
635aa299d01STakashi Iwai 		emu->emu1010.input_source[channel] = val;
636511cbe8fSOswald Buddenhagen 		snd_emu1010_input_source_apply(emu, channel, val);
637511cbe8fSOswald Buddenhagen 	}
638511cbe8fSOswald Buddenhagen 	return change;
6399f4bd5ddSJames Courtier-Dutton }
6409f4bd5ddSJames Courtier-Dutton 
641536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_input_source_ctl = {
642536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
643536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
644536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
645536438f1SOswald Buddenhagen 	.get = snd_emu1010_input_source_get,
646536438f1SOswald Buddenhagen 	.put = snd_emu1010_input_source_put
6479f4bd5ddSJames Courtier-Dutton };
6489f4bd5ddSJames Courtier-Dutton 
64997f1582eSOswald Buddenhagen static int add_emu1010_source_mixers(struct snd_emu10k1 *emu)
65097f1582eSOswald Buddenhagen {
65197f1582eSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
65297f1582eSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
65397f1582eSOswald Buddenhagen 	int err;
65497f1582eSOswald Buddenhagen 
65597f1582eSOswald Buddenhagen 	err = add_ctls(emu, &emu1010_output_source_ctl,
65697f1582eSOswald Buddenhagen 		       emu_ri->out_texts, emu_ri->n_outs);
65797f1582eSOswald Buddenhagen 	if (err < 0)
65897f1582eSOswald Buddenhagen 		return err;
65997f1582eSOswald Buddenhagen 	err = add_ctls(emu, &emu1010_input_source_ctl,
66097f1582eSOswald Buddenhagen 		       emu1010_input_texts, emu_ri->n_ins);
66197f1582eSOswald Buddenhagen 	return err;
66297f1582eSOswald Buddenhagen }
66397f1582eSOswald Buddenhagen 
6641c02e366SCtirad Fertr 
665536438f1SOswald Buddenhagen static const char * const snd_emu1010_adc_pads[] = {
666*f69d705dSOswald Buddenhagen 	"ADC1 14dB PAD 0202 Capture Switch",
667536438f1SOswald Buddenhagen 	"ADC1 14dB PAD Audio Dock Capture Switch",
668536438f1SOswald Buddenhagen 	"ADC2 14dB PAD Audio Dock Capture Switch",
669536438f1SOswald Buddenhagen 	"ADC3 14dB PAD Audio Dock Capture Switch",
6701c02e366SCtirad Fertr };
6711c02e366SCtirad Fertr 
672536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_adc_pad_regs[] = {
673*f69d705dSOswald Buddenhagen 	EMU_HANA_0202_ADC_PAD1,
674536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD1,
675536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD2,
676536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD3,
6779148cc50SJames Courtier-Dutton };
6789148cc50SJames Courtier-Dutton 
679a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
6809148cc50SJames Courtier-Dutton 
6819148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6829148cc50SJames Courtier-Dutton {
6839148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
684536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
685536438f1SOswald Buddenhagen 
6869148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
6879148cc50SJames Courtier-Dutton 	return 0;
6889148cc50SJames Courtier-Dutton }
6899148cc50SJames Courtier-Dutton 
6909148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6919148cc50SJames Courtier-Dutton {
6929148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
693536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
6949148cc50SJames Courtier-Dutton 	unsigned int val, cache;
6959148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
6969148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
6979148cc50SJames Courtier-Dutton 	if (val == 1)
6989148cc50SJames Courtier-Dutton 		cache = cache | mask;
6999148cc50SJames Courtier-Dutton 	else
7009148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
7019148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
7029148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
7039148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
7049148cc50SJames Courtier-Dutton 	}
7059148cc50SJames Courtier-Dutton 
7069148cc50SJames Courtier-Dutton 	return 0;
7079148cc50SJames Courtier-Dutton }
7089148cc50SJames Courtier-Dutton 
709536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_adc_pads_ctl = {
710536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
711536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
712536438f1SOswald Buddenhagen 	.info = snd_emu1010_adc_pads_info,
713536438f1SOswald Buddenhagen 	.get = snd_emu1010_adc_pads_get,
714536438f1SOswald Buddenhagen 	.put = snd_emu1010_adc_pads_put
715536438f1SOswald Buddenhagen };
7169148cc50SJames Courtier-Dutton 
7179148cc50SJames Courtier-Dutton 
718536438f1SOswald Buddenhagen static const char * const snd_emu1010_dac_pads[] = {
719*f69d705dSOswald Buddenhagen 	"DAC1 0202 14dB PAD Playback Switch",
720536438f1SOswald Buddenhagen 	"DAC1 Audio Dock 14dB PAD Playback Switch",
721536438f1SOswald Buddenhagen 	"DAC2 Audio Dock 14dB PAD Playback Switch",
722536438f1SOswald Buddenhagen 	"DAC3 Audio Dock 14dB PAD Playback Switch",
723536438f1SOswald Buddenhagen 	"DAC4 Audio Dock 14dB PAD Playback Switch",
724536438f1SOswald Buddenhagen };
7259148cc50SJames Courtier-Dutton 
726536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_dac_regs[] = {
727*f69d705dSOswald Buddenhagen 	EMU_HANA_0202_DAC_PAD1,
728536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD1,
729536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD2,
730536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD3,
731536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD4,
7329148cc50SJames Courtier-Dutton };
7339148cc50SJames Courtier-Dutton 
734a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
7359148cc50SJames Courtier-Dutton 
7369148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
7379148cc50SJames Courtier-Dutton {
7389148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
739536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
740536438f1SOswald Buddenhagen 
7419148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
7429148cc50SJames Courtier-Dutton 	return 0;
7439148cc50SJames Courtier-Dutton }
7449148cc50SJames Courtier-Dutton 
7459148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
7469148cc50SJames Courtier-Dutton {
7479148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
748536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
7499148cc50SJames Courtier-Dutton 	unsigned int val, cache;
750cc766807SOswald Buddenhagen 	int change;
751cc766807SOswald Buddenhagen 
7529148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
7539148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
7549148cc50SJames Courtier-Dutton 	if (val == 1)
7559148cc50SJames Courtier-Dutton 		cache = cache | mask;
7569148cc50SJames Courtier-Dutton 	else
7579148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
758cc766807SOswald Buddenhagen 	change = (cache != emu->emu1010.dac_pads);
759cc766807SOswald Buddenhagen 	if (change) {
7609148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
7619148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
7629148cc50SJames Courtier-Dutton 	}
7639148cc50SJames Courtier-Dutton 
764cc766807SOswald Buddenhagen 	return change;
7659148cc50SJames Courtier-Dutton }
7669148cc50SJames Courtier-Dutton 
767536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_dac_pads_ctl = {
768536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
769536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
770536438f1SOswald Buddenhagen 	.info = snd_emu1010_dac_pads_info,
771536438f1SOswald Buddenhagen 	.get = snd_emu1010_dac_pads_get,
772536438f1SOswald Buddenhagen 	.put = snd_emu1010_dac_pads_put
7739f4bd5ddSJames Courtier-Dutton };
7749f4bd5ddSJames Courtier-Dutton 
775b0dbdaeaSJames Courtier-Dutton 
77697f1582eSOswald Buddenhagen struct snd_emu1010_pads_info {
77797f1582eSOswald Buddenhagen 	const char * const *adc_ctls, * const *dac_ctls;
77897f1582eSOswald Buddenhagen 	unsigned n_adc_ctls, n_dac_ctls;
77997f1582eSOswald Buddenhagen };
78097f1582eSOswald Buddenhagen 
78197f1582eSOswald Buddenhagen const struct snd_emu1010_pads_info emu1010_pads_info[] = {
78297f1582eSOswald Buddenhagen 	{
78397f1582eSOswald Buddenhagen 		/* all other e-mu cards for now */
78497f1582eSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads,
78597f1582eSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads),
78697f1582eSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads,
78797f1582eSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads),
78897f1582eSOswald Buddenhagen 	},
78997f1582eSOswald Buddenhagen 	{
790*f69d705dSOswald Buddenhagen 		/* rev2 1010 */
79197f1582eSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads,
792*f69d705dSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 1,
79397f1582eSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads,
794*f69d705dSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 1,
795*f69d705dSOswald Buddenhagen 	},
796*f69d705dSOswald Buddenhagen 	{
797*f69d705dSOswald Buddenhagen 		/* 1616(m) cardbus */
798*f69d705dSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads + 1,
799*f69d705dSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 2,
800*f69d705dSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads + 1,
80197f1582eSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 2,
80297f1582eSOswald Buddenhagen 	},
80397f1582eSOswald Buddenhagen };
80497f1582eSOswald Buddenhagen 
80597f1582eSOswald Buddenhagen 
806b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
807b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
808b0dbdaeaSJames Courtier-Dutton {
8091541c66dSTakashi Iwai 	static const char * const texts[4] = {
810edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
811b0dbdaeaSJames Courtier-Dutton 	};
812b0dbdaeaSJames Courtier-Dutton 
8131541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 4, texts);
814b0dbdaeaSJames Courtier-Dutton }
815b0dbdaeaSJames Courtier-Dutton 
816b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
817b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
818b0dbdaeaSJames Courtier-Dutton {
819b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
820b0dbdaeaSJames Courtier-Dutton 
821b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
822b0dbdaeaSJames Courtier-Dutton 	return 0;
823b0dbdaeaSJames Courtier-Dutton }
824b0dbdaeaSJames Courtier-Dutton 
825b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
826b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
827b0dbdaeaSJames Courtier-Dutton {
828b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
829b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
830b0dbdaeaSJames Courtier-Dutton 	int change = 0;
831b0dbdaeaSJames Courtier-Dutton 
832b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
83374415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 4; */
83474415a36SJames Courtier-Dutton 	if (val >= 4)
83574415a36SJames Courtier-Dutton 		return -EINVAL;
836b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
837b0dbdaeaSJames Courtier-Dutton 	if (change) {
838b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
839b0dbdaeaSJames Courtier-Dutton 		switch (val) {
840b0dbdaeaSJames Courtier-Dutton 		case 0:
841b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
842b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
843b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
844a869057cSOswald Buddenhagen 			/* Default fallback clock 44.1kHz */
845b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
846b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
847b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
848b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
849b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
850b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
851b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
852b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
853e40a0b2eSJames Courtier-Dutton 			msleep(10);
854b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
855b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
856b0dbdaeaSJames Courtier-Dutton 			break;
857b0dbdaeaSJames Courtier-Dutton 		case 1:
858b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
859b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
860b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
861b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
862b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
863b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
864b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
865b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
866b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
867b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
868b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
869b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
870e40a0b2eSJames Courtier-Dutton 			msleep(10);
871b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
872b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
873b0dbdaeaSJames Courtier-Dutton 			break;
874edec7bbbSJames Courtier-Dutton 
875edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
876edec7bbbSJames Courtier-Dutton 			/* Mute all */
877edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
878edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
879edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
880edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
881edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
882edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
883edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
884edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
885edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
886edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
887edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
888edec7bbbSJames Courtier-Dutton 			msleep(10);
889edec7bbbSJames Courtier-Dutton 			/* Unmute all */
890edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
891edec7bbbSJames Courtier-Dutton 			break;
892edec7bbbSJames Courtier-Dutton 
893edec7bbbSJames Courtier-Dutton 		case 3:
894edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
895edec7bbbSJames Courtier-Dutton 			/* Mute all */
896edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
897edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
898edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
899edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
900edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
901edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
902edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
903edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
904edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
905edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
906edec7bbbSJames Courtier-Dutton 			msleep(10);
907edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
908edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
909edec7bbbSJames Courtier-Dutton 
910edec7bbbSJames Courtier-Dutton 
911edec7bbbSJames Courtier-Dutton 			break;
912b0dbdaeaSJames Courtier-Dutton 		}
913b0dbdaeaSJames Courtier-Dutton 	}
914b0dbdaeaSJames Courtier-Dutton         return change;
915b0dbdaeaSJames Courtier-Dutton }
916b0dbdaeaSJames Courtier-Dutton 
917f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock =
918b0dbdaeaSJames Courtier-Dutton {
919b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
920b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
921b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
922b0dbdaeaSJames Courtier-Dutton 	.count =	1,
923b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
924b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
925b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
926b0dbdaeaSJames Courtier-Dutton };
927b0dbdaeaSJames Courtier-Dutton 
92899dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
92999dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
93099dcab46SMichael Gernoth {
93199dcab46SMichael Gernoth 	static const char * const texts[2] = {
93299dcab46SMichael Gernoth 		"SPDIF", "ADAT"
93399dcab46SMichael Gernoth 	};
93499dcab46SMichael Gernoth 
93599dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
93699dcab46SMichael Gernoth }
93799dcab46SMichael Gernoth 
93899dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol,
93999dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
94099dcab46SMichael Gernoth {
94199dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
94299dcab46SMichael Gernoth 
94399dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out;
94499dcab46SMichael Gernoth 	return 0;
94599dcab46SMichael Gernoth }
94699dcab46SMichael Gernoth 
94799dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
94899dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
94999dcab46SMichael Gernoth {
95099dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
95199dcab46SMichael Gernoth 	unsigned int val;
95299dcab46SMichael Gernoth 	u32 tmp;
95399dcab46SMichael Gernoth 	int change = 0;
95499dcab46SMichael Gernoth 
95599dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
95699dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
95799dcab46SMichael Gernoth 	if (val >= 2)
95899dcab46SMichael Gernoth 		return -EINVAL;
95999dcab46SMichael Gernoth 	change = (emu->emu1010.optical_out != val);
96099dcab46SMichael Gernoth 	if (change) {
96199dcab46SMichael Gernoth 		emu->emu1010.optical_out = val;
9629d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
9639d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
96499dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
96599dcab46SMichael Gernoth 	}
96699dcab46SMichael Gernoth 	return change;
96799dcab46SMichael Gernoth }
96899dcab46SMichael Gernoth 
969f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = {
97099dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
97199dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
97299dcab46SMichael Gernoth 	.name =         "Optical Output Mode",
97399dcab46SMichael Gernoth 	.count =	1,
97499dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_out_info,
97599dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_out_get,
97699dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_out_put
97799dcab46SMichael Gernoth };
97899dcab46SMichael Gernoth 
97999dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
98099dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
98199dcab46SMichael Gernoth {
98299dcab46SMichael Gernoth 	static const char * const texts[2] = {
98399dcab46SMichael Gernoth 		"SPDIF", "ADAT"
98499dcab46SMichael Gernoth 	};
98599dcab46SMichael Gernoth 
98699dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
98799dcab46SMichael Gernoth }
98899dcab46SMichael Gernoth 
98999dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
99099dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
99199dcab46SMichael Gernoth {
99299dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
99399dcab46SMichael Gernoth 
99499dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
99599dcab46SMichael Gernoth 	return 0;
99699dcab46SMichael Gernoth }
99799dcab46SMichael Gernoth 
99899dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
99999dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
100099dcab46SMichael Gernoth {
100199dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
100299dcab46SMichael Gernoth 	unsigned int val;
100399dcab46SMichael Gernoth 	u32 tmp;
100499dcab46SMichael Gernoth 	int change = 0;
100599dcab46SMichael Gernoth 
100699dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
100799dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
100899dcab46SMichael Gernoth 	if (val >= 2)
100999dcab46SMichael Gernoth 		return -EINVAL;
101099dcab46SMichael Gernoth 	change = (emu->emu1010.optical_in != val);
101199dcab46SMichael Gernoth 	if (change) {
101299dcab46SMichael Gernoth 		emu->emu1010.optical_in = val;
10139d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
10149d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
101599dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
101699dcab46SMichael Gernoth 	}
101799dcab46SMichael Gernoth 	return change;
101899dcab46SMichael Gernoth }
101999dcab46SMichael Gernoth 
1020f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = {
102199dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
102299dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
102399dcab46SMichael Gernoth 	.name =         "Optical Input Mode",
102499dcab46SMichael Gernoth 	.count =	1,
102599dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_in_info,
102699dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_in_get,
102799dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_in_put
102899dcab46SMichael Gernoth };
102999dcab46SMichael Gernoth 
1030184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
1031184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
1032184c1e2cSJames Courtier-Dutton {
1033184c1e2cSJames Courtier-Dutton #if 0
10341541c66dSTakashi Iwai 	static const char * const texts[4] = {
1035184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
1036184c1e2cSJames Courtier-Dutton 	};
1037184c1e2cSJames Courtier-Dutton #endif
10381541c66dSTakashi Iwai 	static const char * const texts[2] = {
1039184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
1040184c1e2cSJames Courtier-Dutton 	};
1041184c1e2cSJames Courtier-Dutton 
10421541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
1043184c1e2cSJames Courtier-Dutton }
1044184c1e2cSJames Courtier-Dutton 
1045184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
1046184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
1047184c1e2cSJames Courtier-Dutton {
1048184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1049184c1e2cSJames Courtier-Dutton 
1050184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
1051184c1e2cSJames Courtier-Dutton 	return 0;
1052184c1e2cSJames Courtier-Dutton }
1053184c1e2cSJames Courtier-Dutton 
1054184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
1055184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
1056184c1e2cSJames Courtier-Dutton {
1057184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1058184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
1059184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
1060a1c87c0bSOswald Buddenhagen 	u16 gpio;
1061184c1e2cSJames Courtier-Dutton 	int change = 0;
1062184c1e2cSJames Courtier-Dutton 	unsigned long flags;
1063184c1e2cSJames Courtier-Dutton 	u32 source;
1064184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
1065184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
1066184c1e2cSJames Courtier-Dutton 	 * for the particular source.
1067184c1e2cSJames Courtier-Dutton 	 */
106874415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
106974415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
107074415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
107174415a36SJames Courtier-Dutton 	if (source_id >= 2)
107274415a36SJames Courtier-Dutton 		return -EINVAL;
1073184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
1074184c1e2cSJames Courtier-Dutton 	if (change) {
1075184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
1076184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
1077a1c87c0bSOswald Buddenhagen 		gpio = inw(emu->port + A_IOCFG);
1078184c1e2cSJames Courtier-Dutton 		if (source_id==0)
1079a1c87c0bSOswald Buddenhagen 			outw(gpio | 0x4, emu->port + A_IOCFG);
1080184c1e2cSJames Courtier-Dutton 		else
1081a1c87c0bSOswald Buddenhagen 			outw(gpio & ~0x4, emu->port + A_IOCFG);
1082184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
1083184c1e2cSJames Courtier-Dutton 
1084184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
1085184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
1086184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
1087184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
1088184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
1089184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
1090184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
1091184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
1092184c1e2cSJames Courtier-Dutton 
1093184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
1094184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
1095184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
1096184c1e2cSJames Courtier-Dutton 	}
1097184c1e2cSJames Courtier-Dutton         return change;
1098184c1e2cSJames Courtier-Dutton }
1099184c1e2cSJames Courtier-Dutton 
1100f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source =
1101184c1e2cSJames Courtier-Dutton {
1102184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
1103184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
1104184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
1105184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
1106184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
1107184c1e2cSJames Courtier-Dutton };
1108184c1e2cSJames Courtier-Dutton 
1109184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
1110184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
1111184c1e2cSJames Courtier-Dutton {
1112184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1113184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
1114184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
1115184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
1116184c1e2cSJames Courtier-Dutton 	return 0;
1117184c1e2cSJames Courtier-Dutton }
1118184c1e2cSJames Courtier-Dutton 
1119184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
1120184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
1121184c1e2cSJames Courtier-Dutton {
1122184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
112374415a36SJames Courtier-Dutton 	unsigned int source_id;
1124184c1e2cSJames Courtier-Dutton 
1125184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
112674415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
112774415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
112874415a36SJames Courtier-Dutton 	if (source_id >= 2)
112974415a36SJames Courtier-Dutton 		return -EINVAL;
1130184c1e2cSJames Courtier-Dutton 
1131184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
1132184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
1133184c1e2cSJames Courtier-Dutton 	return 0;
1134184c1e2cSJames Courtier-Dutton }
1135184c1e2cSJames Courtier-Dutton 
1136184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
1137184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
1138184c1e2cSJames Courtier-Dutton {
1139184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1140184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
114114a29565SOswald Buddenhagen 	unsigned int ngain0, ngain1;
114274415a36SJames Courtier-Dutton 	unsigned int source_id;
1143184c1e2cSJames Courtier-Dutton 	int change = 0;
1144184c1e2cSJames Courtier-Dutton 
1145184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
114674415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
114774415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
114874415a36SJames Courtier-Dutton 	if (source_id >= 2)
114974415a36SJames Courtier-Dutton 		return -EINVAL;
115014a29565SOswald Buddenhagen 	ngain0 = ucontrol->value.integer.value[0];
115114a29565SOswald Buddenhagen 	ngain1 = ucontrol->value.integer.value[1];
115214a29565SOswald Buddenhagen 	if (ngain0 > 0xff)
115314a29565SOswald Buddenhagen 		return -EINVAL;
115414a29565SOswald Buddenhagen 	if (ngain1 > 0xff)
115514a29565SOswald Buddenhagen 		return -EINVAL;
1156184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
115714a29565SOswald Buddenhagen 	if (ogain != ngain0) {
1158184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
115914a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0);
116014a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][0] = ngain0;
1161184c1e2cSJames Courtier-Dutton 		change = 1;
1162184c1e2cSJames Courtier-Dutton 	}
1163184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
116414a29565SOswald Buddenhagen 	if (ogain != ngain1) {
1165184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
116614a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1);
116714a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][1] = ngain1;
1168184c1e2cSJames Courtier-Dutton 		change = 1;
1169184c1e2cSJames Courtier-Dutton 	}
1170184c1e2cSJames Courtier-Dutton 
1171184c1e2cSJames Courtier-Dutton 	return change;
1172184c1e2cSJames Courtier-Dutton }
1173184c1e2cSJames Courtier-Dutton 
1174536438f1SOswald Buddenhagen static const struct snd_kcontrol_new i2c_volume_ctl = {
1175536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1176536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1177536438f1SOswald Buddenhagen 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,
1178536438f1SOswald Buddenhagen 	.info = snd_audigy_i2c_volume_info,
1179536438f1SOswald Buddenhagen 	.get = snd_audigy_i2c_volume_get,
1180536438f1SOswald Buddenhagen 	.put = snd_audigy_i2c_volume_put,
1181536438f1SOswald Buddenhagen 	.tlv = { .p = snd_audigy_db_scale2 }
1182536438f1SOswald Buddenhagen };
1183184c1e2cSJames Courtier-Dutton 
1184536438f1SOswald Buddenhagen static const char * const snd_audigy_i2c_volume_ctls[] = {
1185536438f1SOswald Buddenhagen 	"Mic Capture Volume",
1186536438f1SOswald Buddenhagen 	"Line Capture Volume",
1187184c1e2cSJames Courtier-Dutton };
1188184c1e2cSJames Courtier-Dutton 
11890af68e5eSTakashi Iwai #if 0
1190eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11911da177e4SLinus Torvalds {
11921541c66dSTakashi Iwai 	static const char * const texts[] = {"44100", "48000", "96000"};
11931da177e4SLinus Torvalds 
11941541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 3, texts);
11951da177e4SLinus Torvalds }
11961da177e4SLinus Torvalds 
1197eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
1198eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
11991da177e4SLinus Torvalds {
1200eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12011da177e4SLinus Torvalds 	unsigned int tmp;
12021da177e4SLinus Torvalds 
12031da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
12041da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
12051da177e4SLinus Torvalds 	case A_SPDIF_44100:
12061da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
12071da177e4SLinus Torvalds 		break;
12081da177e4SLinus Torvalds 	case A_SPDIF_48000:
12091da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
12101da177e4SLinus Torvalds 		break;
12111da177e4SLinus Torvalds 	case A_SPDIF_96000:
12121da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
12131da177e4SLinus Torvalds 		break;
12141da177e4SLinus Torvalds 	default:
12151da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
12161da177e4SLinus Torvalds 	}
12171da177e4SLinus Torvalds 	return 0;
12181da177e4SLinus Torvalds }
12191da177e4SLinus Torvalds 
1220eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
1221eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
12221da177e4SLinus Torvalds {
1223eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12241da177e4SLinus Torvalds 	int change;
12251da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
12261da177e4SLinus Torvalds 	unsigned long flags;
12271da177e4SLinus Torvalds 
12281da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
12291da177e4SLinus Torvalds 	case 0:
12301da177e4SLinus Torvalds 		val = A_SPDIF_44100;
12311da177e4SLinus Torvalds 		break;
12321da177e4SLinus Torvalds 	case 1:
12331da177e4SLinus Torvalds 		val = A_SPDIF_48000;
12341da177e4SLinus Torvalds 		break;
12351da177e4SLinus Torvalds 	case 2:
12361da177e4SLinus Torvalds 		val = A_SPDIF_96000;
12371da177e4SLinus Torvalds 		break;
12381da177e4SLinus Torvalds 	default:
12391da177e4SLinus Torvalds 		val = A_SPDIF_48000;
12401da177e4SLinus Torvalds 		break;
12411da177e4SLinus Torvalds 	}
12421da177e4SLinus Torvalds 
12431da177e4SLinus Torvalds 
12441da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12451da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
12461da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
12471da177e4SLinus Torvalds 	tmp |= val;
124812bda107STakashi Iwai 	change = (tmp != reg);
124912bda107STakashi Iwai 	if (change)
12501da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
12511da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12521da177e4SLinus Torvalds 	return change;
12531da177e4SLinus Torvalds }
12541da177e4SLinus Torvalds 
1255b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate =
12561da177e4SLinus Torvalds {
12571da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
12581da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
12591da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
12601da177e4SLinus Torvalds 	.count =	1,
12611da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
12621da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
12631da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
12641da177e4SLinus Torvalds };
12650af68e5eSTakashi Iwai #endif
12661da177e4SLinus Torvalds 
1267eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1268eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
12691da177e4SLinus Torvalds {
1270eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12711da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
12721da177e4SLinus Torvalds 	int change;
12731da177e4SLinus Torvalds 	unsigned int val;
12741da177e4SLinus Torvalds 
127574415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
127674415a36SJames Courtier-Dutton 	if (idx >= 3)
127774415a36SJames Courtier-Dutton 		return -EINVAL;
12781da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
12791da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
12801da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
12811da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
12821da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
12831da177e4SLinus Torvalds 	if (change) {
12841da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
12851da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
12861da177e4SLinus Torvalds 	}
12871da177e4SLinus Torvalds 	return change;
12881da177e4SLinus Torvalds }
12891da177e4SLinus Torvalds 
1290f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
12911da177e4SLinus Torvalds {
12921da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
12935549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12941da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
12957583cb51STakashi Iwai 	.count =	3,
12961da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
12971da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
12981da177e4SLinus Torvalds };
12991da177e4SLinus Torvalds 
1300f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
13011da177e4SLinus Torvalds {
13025549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
13031da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
13047583cb51STakashi Iwai 	.count =	3,
13051da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
13061da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
13071da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
13081da177e4SLinus Torvalds };
13091da177e4SLinus Torvalds 
13101da177e4SLinus Torvalds 
1311eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
13121da177e4SLinus Torvalds {
13131da177e4SLinus Torvalds 	if (emu->audigy) {
13141da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
13151da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
13161da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
13171da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
13181da177e4SLinus Torvalds 	} else {
13191da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
13201da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
13211da177e4SLinus Torvalds 	}
13221da177e4SLinus Torvalds }
13231da177e4SLinus Torvalds 
1324eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
13251da177e4SLinus Torvalds {
13261da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
13271da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
13281da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
13291da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
13301da177e4SLinus Torvalds 	if (emu->audigy) {
133151d652f4SOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice,
133251d652f4SOswald Buddenhagen 				      snd_emu10k1_compose_audigy_sendamounts(volume));
13331da177e4SLinus Torvalds 	}
13341da177e4SLinus Torvalds }
13351da177e4SLinus Torvalds 
13361da177e4SLinus Torvalds /* PCM stream controls */
13371da177e4SLinus Torvalds 
1338eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13391da177e4SLinus Torvalds {
1340eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13411da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13421da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
13431da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13441da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
13451da177e4SLinus Torvalds 	return 0;
13461da177e4SLinus Torvalds }
13471da177e4SLinus Torvalds 
1348eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1349eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
13501da177e4SLinus Torvalds {
1351eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1352eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1353eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13541da177e4SLinus Torvalds 	int voice, idx;
13551da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13561da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
13571da177e4SLinus Torvalds 
13581da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
13591da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
13601da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
13611da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
13621da177e4SLinus Torvalds 	return 0;
13631da177e4SLinus Torvalds }
13641da177e4SLinus Torvalds 
1365eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1366eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
13671da177e4SLinus Torvalds {
13681da177e4SLinus Torvalds 	unsigned long flags;
1369eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1370eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1371eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13721da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
13731da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13741da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
13751da177e4SLinus Torvalds 
13761da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13771da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
13781da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
13791da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
13801da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
13811da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
13821da177e4SLinus Torvalds 				change = 1;
13831da177e4SLinus Torvalds 			}
13841da177e4SLinus Torvalds 		}
13851da177e4SLinus Torvalds 	if (change && mix->epcm) {
13861da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
13871da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
13881da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
13891da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
13901da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
13911da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
13921da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
13931da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
13941da177e4SLinus Torvalds 		}
13951da177e4SLinus Torvalds 	}
13961da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13971da177e4SLinus Torvalds 	return change;
13981da177e4SLinus Torvalds }
13991da177e4SLinus Torvalds 
1400f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control =
14011da177e4SLinus Torvalds {
14021da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
140367ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14041da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
14051da177e4SLinus Torvalds 	.count =	32,
14061da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
14071da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
14081da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
14091da177e4SLinus Torvalds };
14101da177e4SLinus Torvalds 
1411eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14121da177e4SLinus Torvalds {
1413eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14141da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14151da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
14161da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14171da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
14181da177e4SLinus Torvalds 	return 0;
14191da177e4SLinus Torvalds }
14201da177e4SLinus Torvalds 
1421eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1422eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
14231da177e4SLinus Torvalds {
1424eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1425eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1426eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14271da177e4SLinus Torvalds 	int idx;
14281da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14291da177e4SLinus Torvalds 
14301da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
14311da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
14321da177e4SLinus Torvalds 	return 0;
14331da177e4SLinus Torvalds }
14341da177e4SLinus Torvalds 
1435eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1436eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
14371da177e4SLinus Torvalds {
14381da177e4SLinus Torvalds 	unsigned long flags;
1439eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1440eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1441eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14421da177e4SLinus Torvalds 	int change = 0, idx, val;
14431da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14441da177e4SLinus Torvalds 
14451da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14461da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
14471da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
14481da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
14491da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
14501da177e4SLinus Torvalds 			change = 1;
14511da177e4SLinus Torvalds 		}
14521da177e4SLinus Torvalds 	}
14531da177e4SLinus Torvalds 	if (change && mix->epcm) {
14541da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
14551da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
14561da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
14571da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
14581da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
14591da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
14601da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
14611da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
14621da177e4SLinus Torvalds 		}
14631da177e4SLinus Torvalds 	}
14641da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14651da177e4SLinus Torvalds 	return change;
14661da177e4SLinus Torvalds }
14671da177e4SLinus Torvalds 
1468f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
14691da177e4SLinus Torvalds {
14701da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
147167ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14721da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
14731da177e4SLinus Torvalds 	.count =	32,
14741da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
14751da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
14761da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
14771da177e4SLinus Torvalds };
14781da177e4SLinus Torvalds 
1479eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14801da177e4SLinus Torvalds {
14811da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14821da177e4SLinus Torvalds 	uinfo->count = 3;
14831da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1484bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
14851da177e4SLinus Torvalds 	return 0;
14861da177e4SLinus Torvalds }
14871da177e4SLinus Torvalds 
1488eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1489eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
14901da177e4SLinus Torvalds {
1491eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1492eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1493eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14941da177e4SLinus Torvalds 	int idx;
14951da177e4SLinus Torvalds 
14961da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
1497bcdbd3b7SOswald Buddenhagen 		ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U;
14981da177e4SLinus Torvalds 	return 0;
14991da177e4SLinus Torvalds }
15001da177e4SLinus Torvalds 
1501eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1502eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
15031da177e4SLinus Torvalds {
15041da177e4SLinus Torvalds 	unsigned long flags;
1505eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1506eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1507eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15081da177e4SLinus Torvalds 	int change = 0, idx, val;
15091da177e4SLinus Torvalds 
15101da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15111da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
1512bcdbd3b7SOswald Buddenhagen 		unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff;
1513bcdbd3b7SOswald Buddenhagen 		val = uval * 0x8000U / 0xffffU;
15141da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
15151da177e4SLinus Torvalds 			mix->attn[idx] = val;
15161da177e4SLinus Torvalds 			change = 1;
15171da177e4SLinus Torvalds 		}
15181da177e4SLinus Torvalds 	}
15191da177e4SLinus Torvalds 	if (change && mix->epcm) {
15201da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
15211da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
15221da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
15231da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
15241da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
15251da177e4SLinus Torvalds 		}
15261da177e4SLinus Torvalds 	}
15271da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15281da177e4SLinus Torvalds 	return change;
15291da177e4SLinus Torvalds }
15301da177e4SLinus Torvalds 
1531f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control =
15321da177e4SLinus Torvalds {
15331da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
153467ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15351da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
15361da177e4SLinus Torvalds 	.count =	32,
15371da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
15381da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
15391da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
15401da177e4SLinus Torvalds };
15411da177e4SLinus Torvalds 
15421da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
15431da177e4SLinus Torvalds 
1544eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15451da177e4SLinus Torvalds {
1546eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15471da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15481da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
15491da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
15501da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
15511da177e4SLinus Torvalds 	return 0;
15521da177e4SLinus Torvalds }
15531da177e4SLinus Torvalds 
1554eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1555eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
15561da177e4SLinus Torvalds {
1557eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1558eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1559eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15601da177e4SLinus Torvalds 	int idx;
15611da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15621da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
15631da177e4SLinus Torvalds 
15641da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
15651da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
15661da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
15671da177e4SLinus Torvalds 	return 0;
15681da177e4SLinus Torvalds }
15691da177e4SLinus Torvalds 
1570eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1571eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
15721da177e4SLinus Torvalds {
15731da177e4SLinus Torvalds 	unsigned long flags;
1574eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15751da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1576eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
15771da177e4SLinus Torvalds 	int change = 0, idx, val;
15781da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15791da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
15801da177e4SLinus Torvalds 
15811da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15821da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
15831da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
15841da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
15851da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
15861da177e4SLinus Torvalds 			change = 1;
15871da177e4SLinus Torvalds 		}
15881da177e4SLinus Torvalds 	}
15891da177e4SLinus Torvalds 
15901da177e4SLinus Torvalds 	if (change && mix->epcm) {
15911da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
15921da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
15931da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
15941da177e4SLinus Torvalds 		}
15951da177e4SLinus Torvalds 	}
15961da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15971da177e4SLinus Torvalds 	return change;
15981da177e4SLinus Torvalds }
15991da177e4SLinus Torvalds 
1600f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
16011da177e4SLinus Torvalds {
16021da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
16031da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
16041da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
16051da177e4SLinus Torvalds 	.count =	16,
16061da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
16071da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
16081da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
16091da177e4SLinus Torvalds };
16101da177e4SLinus Torvalds 
1611eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
16121da177e4SLinus Torvalds {
1613eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
16141da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
16151da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
16161da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
16171da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
16181da177e4SLinus Torvalds 	return 0;
16191da177e4SLinus Torvalds }
16201da177e4SLinus Torvalds 
1621eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1622eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
16231da177e4SLinus Torvalds {
1624eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1625eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1626eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
16271da177e4SLinus Torvalds 	int idx;
16281da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
16291da177e4SLinus Torvalds 
16301da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
16311da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
16321da177e4SLinus Torvalds 	return 0;
16331da177e4SLinus Torvalds }
16341da177e4SLinus Torvalds 
1635eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1636eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
16371da177e4SLinus Torvalds {
16381da177e4SLinus Torvalds 	unsigned long flags;
1639eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
16401da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1641eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
16421da177e4SLinus Torvalds 	int change = 0, idx, val;
16431da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
16441da177e4SLinus Torvalds 
16451da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
16461da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
16471da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
16481da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
16491da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
16501da177e4SLinus Torvalds 			change = 1;
16511da177e4SLinus Torvalds 		}
16521da177e4SLinus Torvalds 	}
16531da177e4SLinus Torvalds 	if (change && mix->epcm) {
16541da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
16551da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
16561da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
16571da177e4SLinus Torvalds 		}
16581da177e4SLinus Torvalds 	}
16591da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
16601da177e4SLinus Torvalds 	return change;
16611da177e4SLinus Torvalds }
16621da177e4SLinus Torvalds 
16631da177e4SLinus Torvalds 
1664f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
16651da177e4SLinus Torvalds {
16661da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
16671da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
16681da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
16691da177e4SLinus Torvalds 	.count =	16,
16701da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
16711da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
16721da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
16731da177e4SLinus Torvalds };
16741da177e4SLinus Torvalds 
1675eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
16761da177e4SLinus Torvalds {
16771da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
16781da177e4SLinus Torvalds 	uinfo->count = 1;
16791da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1680bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
16811da177e4SLinus Torvalds 	return 0;
16821da177e4SLinus Torvalds }
16831da177e4SLinus Torvalds 
1684eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1685eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
16861da177e4SLinus Torvalds {
1687eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1688eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1689eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
16901da177e4SLinus Torvalds 
1691bcdbd3b7SOswald Buddenhagen 	ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U;
16921da177e4SLinus Torvalds 	return 0;
16931da177e4SLinus Torvalds }
16941da177e4SLinus Torvalds 
1695eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1696eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
16971da177e4SLinus Torvalds {
16981da177e4SLinus Torvalds 	unsigned long flags;
1699eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
17001da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1701eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
17021da177e4SLinus Torvalds 	int change = 0, val;
1703bcdbd3b7SOswald Buddenhagen 	unsigned uval;
17041da177e4SLinus Torvalds 
17051da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1706bcdbd3b7SOswald Buddenhagen 	uval = ucontrol->value.integer.value[0] & 0x1ffff;
1707bcdbd3b7SOswald Buddenhagen 	val = uval * 0x8000U / 0xffffU;
17081da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
17091da177e4SLinus Torvalds 		mix->attn[0] = val;
17101da177e4SLinus Torvalds 		change = 1;
17111da177e4SLinus Torvalds 	}
17121da177e4SLinus Torvalds 	if (change && mix->epcm) {
17131da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
17141da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
17151da177e4SLinus Torvalds 		}
17161da177e4SLinus Torvalds 	}
17171da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
17181da177e4SLinus Torvalds 	return change;
17191da177e4SLinus Torvalds }
17201da177e4SLinus Torvalds 
1721f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
17221da177e4SLinus Torvalds {
17231da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
17241da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
17251da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
17261da177e4SLinus Torvalds 	.count =	16,
17271da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
17281da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
17291da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
17301da177e4SLinus Torvalds };
17311da177e4SLinus Torvalds 
1732a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
17331da177e4SLinus Torvalds 
1734eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1735eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
17361da177e4SLinus Torvalds {
1737eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
17381da177e4SLinus Torvalds 
17391da177e4SLinus Torvalds 	if (emu->audigy)
1740a1c87c0bSOswald Buddenhagen 		ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
17411da177e4SLinus Torvalds 	else
17421da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1743d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1744d2cd74b1STakashi Iwai 		ucontrol->value.integer.value[0] =
1745d2cd74b1STakashi Iwai 			!ucontrol->value.integer.value[0];
1746d2cd74b1STakashi Iwai 
17471da177e4SLinus Torvalds 	return 0;
17481da177e4SLinus Torvalds }
17491da177e4SLinus Torvalds 
1750eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1751eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
17521da177e4SLinus Torvalds {
17531da177e4SLinus Torvalds 	unsigned long flags;
1754eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1755d2cd74b1STakashi Iwai 	unsigned int reg, val, sw;
17561da177e4SLinus Torvalds 	int change = 0;
17571da177e4SLinus Torvalds 
1758d2cd74b1STakashi Iwai 	sw = ucontrol->value.integer.value[0];
1759d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1760d2cd74b1STakashi Iwai 		sw = !sw;
176150164f69SOswald Buddenhagen 	spin_lock_irqsave(&emu->emu_lock, flags);
1762184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1763184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1764184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
1765a1c87c0bSOswald Buddenhagen 		reg = inw(emu->port + A_IOCFG);
1766d2cd74b1STakashi Iwai 		val = sw ? A_IOCFG_GPOUT0 : 0;
17671da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
17681da177e4SLinus Torvalds 		if (change) {
17691da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
17701da177e4SLinus Torvalds 			reg |= val;
1771a1c87c0bSOswald Buddenhagen 			outw(reg | val, emu->port + A_IOCFG);
17721da177e4SLinus Torvalds 		}
17731da177e4SLinus Torvalds 	}
17741da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
1775d2cd74b1STakashi Iwai 	val = sw ? HCFG_GPOUT0 : 0;
17761da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
17771da177e4SLinus Torvalds 	if (change) {
17781da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
17791da177e4SLinus Torvalds 		reg |= val;
17801da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
17811da177e4SLinus Torvalds 	}
178250164f69SOswald Buddenhagen 	spin_unlock_irqrestore(&emu->emu_lock, flags);
17831da177e4SLinus Torvalds 	return change;
17841da177e4SLinus Torvalds }
17851da177e4SLinus Torvalds 
1786f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
17871da177e4SLinus Torvalds {
17881da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
17891da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
17901da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
17911da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
17921da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
17931da177e4SLinus Torvalds };
17941da177e4SLinus Torvalds 
1795f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif =
17961da177e4SLinus Torvalds {
17971da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
17981da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
17991da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
18001da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
18011da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
18021da177e4SLinus Torvalds };
18031da177e4SLinus Torvalds 
180416950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
180516950e09STakashi Iwai 
180616950e09STakashi Iwai #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
180716950e09STakashi Iwai 
180816950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
180916950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
181016950e09STakashi Iwai {
181116950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
181216950e09STakashi Iwai 	unsigned int val;
181316950e09STakashi Iwai 
181416950e09STakashi Iwai 	/* FIXME: better to use a cached version */
181516950e09STakashi Iwai 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
181616950e09STakashi Iwai 	ucontrol->value.integer.value[0] = !!val;
181716950e09STakashi Iwai 	return 0;
181816950e09STakashi Iwai }
181916950e09STakashi Iwai 
182016950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
182116950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
182216950e09STakashi Iwai {
182316950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
182416950e09STakashi Iwai 	unsigned int val;
182516950e09STakashi Iwai 
182616950e09STakashi Iwai 	if (ucontrol->value.integer.value[0])
182716950e09STakashi Iwai 		val = 0x0f0f;
182816950e09STakashi Iwai 	else
182916950e09STakashi Iwai 		val = 0;
183016950e09STakashi Iwai 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
183116950e09STakashi Iwai }
183216950e09STakashi Iwai 
1833f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost =
183416950e09STakashi Iwai {
183516950e09STakashi Iwai 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
18362a52feb1SMaciej S. Szmigiero 	.name =		"Mic Extra Boost",
183716950e09STakashi Iwai 	.info =		snd_audigy_capture_boost_info,
183816950e09STakashi Iwai 	.get =		snd_audigy_capture_boost_get,
183916950e09STakashi Iwai 	.put =		snd_audigy_capture_boost_put
184016950e09STakashi Iwai };
184116950e09STakashi Iwai 
184216950e09STakashi Iwai 
18431da177e4SLinus Torvalds /*
18441da177e4SLinus Torvalds  */
1845eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
18461da177e4SLinus Torvalds {
1847eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
18481da177e4SLinus Torvalds 	emu->ac97 = NULL;
18491da177e4SLinus Torvalds }
18501da177e4SLinus Torvalds 
18511da177e4SLinus Torvalds /*
18521da177e4SLinus Torvalds  */
1853eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
18541da177e4SLinus Torvalds {
1855eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
18561da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
18571da177e4SLinus Torvalds 	strcpy(id.name, name);
18581da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
18591da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
18601da177e4SLinus Torvalds }
18611da177e4SLinus Torvalds 
1862eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
18631da177e4SLinus Torvalds {
1864eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
18651da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
18661da177e4SLinus Torvalds 	strcpy(sid.name, name);
18671da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
18681da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
18691da177e4SLinus Torvalds }
18701da177e4SLinus Torvalds 
1871eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
18721da177e4SLinus Torvalds {
1873eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
18741da177e4SLinus Torvalds 	if (kctl) {
187536476b81SMaciej S. Szmigiero 		snd_ctl_rename(card, kctl, dst);
18761da177e4SLinus Torvalds 		return 0;
18771da177e4SLinus Torvalds 	}
18781da177e4SLinus Torvalds 	return -ENOENT;
18791da177e4SLinus Torvalds }
18801da177e4SLinus Torvalds 
1881e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
188267ed4161SClemens Ladisch 		      int pcm_device, int multi_device)
18831da177e4SLinus Torvalds {
1884155e3d3bSOswald Buddenhagen 	int err;
1885eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1886eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
18876fddce26STakashi Iwai 	const char * const *c;
18886fddce26STakashi Iwai 	static const char * const emu10k1_remove_ctls[] = {
18891da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
18901da177e4SLinus Torvalds 		"Master Mono Playback Switch",
18911da177e4SLinus Torvalds 		"Master Mono Playback Volume",
18921da177e4SLinus Torvalds 		"PCM Out Path & Mute",
18931da177e4SLinus Torvalds 		"Mono Output Select",
18941da177e4SLinus Torvalds 		"Surround Playback Switch",
18951da177e4SLinus Torvalds 		"Surround Playback Volume",
18961da177e4SLinus Torvalds 		"Center Playback Switch",
18971da177e4SLinus Torvalds 		"Center Playback Volume",
18981da177e4SLinus Torvalds 		"LFE Playback Switch",
18991da177e4SLinus Torvalds 		"LFE Playback Volume",
19001da177e4SLinus Torvalds 		NULL
19011da177e4SLinus Torvalds 	};
19026fddce26STakashi Iwai 	static const char * const emu10k1_rename_ctls[] = {
19031da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
19041da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
19051da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
19061da177e4SLinus Torvalds 		NULL
19071da177e4SLinus Torvalds 	};
19086fddce26STakashi Iwai 	static const char * const audigy_remove_ctls[] = {
19091da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
191021fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
191121fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
19121da177e4SLinus Torvalds 		"PCM Playback Switch",
19131da177e4SLinus Torvalds 		"PCM Playback Volume",
19141da177e4SLinus Torvalds 		"Master Playback Switch",
19151da177e4SLinus Torvalds 		"Master Playback Volume",
19161da177e4SLinus Torvalds 		"PCM Out Path & Mute",
19171da177e4SLinus Torvalds 		"Mono Output Select",
19181da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
19191da177e4SLinus Torvalds 		"Capture Source",
19201da177e4SLinus Torvalds 		"Capture Switch",
19211da177e4SLinus Torvalds 		"Capture Volume",
19221da177e4SLinus Torvalds 		"Mic Select",
1923274b2000SMaciej S. Szmigiero 		"Headphone Playback Switch",
1924274b2000SMaciej S. Szmigiero 		"Headphone Playback Volume",
1925274b2000SMaciej S. Szmigiero 		"3D Control - Center",
1926274b2000SMaciej S. Szmigiero 		"3D Control - Depth",
1927274b2000SMaciej S. Szmigiero 		"3D Control - Switch",
19281da177e4SLinus Torvalds 		"Video Playback Switch",
19291da177e4SLinus Torvalds 		"Video Playback Volume",
19301da177e4SLinus Torvalds 		"Mic Playback Switch",
19311da177e4SLinus Torvalds 		"Mic Playback Volume",
1932274b2000SMaciej S. Szmigiero 		"External Amplifier",
19331da177e4SLinus Torvalds 		NULL
19341da177e4SLinus Torvalds 	};
19356fddce26STakashi Iwai 	static const char * const audigy_rename_ctls[] = {
19361da177e4SLinus Torvalds 		/* use conventional names */
19371da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
19381da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
19391da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
19401da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
194152051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
194252051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
19431da177e4SLinus Torvalds 		NULL
19441da177e4SLinus Torvalds 	};
19456fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_i2c_adc[] = {
1946184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1947184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1948184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1949184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1950184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1951eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1952184c1e2cSJames Courtier-Dutton 		NULL
1953184c1e2cSJames Courtier-Dutton 	};
19546fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_i2c_adc[] = {
1955184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1956184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1957184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1958184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1959184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1960eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1961184c1e2cSJames Courtier-Dutton 		NULL
1962184c1e2cSJames Courtier-Dutton 	};
19636fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_1361t_adc[] = {
196421fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
196521fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
196621fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
196721fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
196821fdddeaSJames Courtier-Dutton 		"Capture Source",
196921fdddeaSJames Courtier-Dutton 		"Capture Switch",
197021fdddeaSJames Courtier-Dutton 		"Capture Volume",
197121fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
197221fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
197321fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
197421fdddeaSJames Courtier-Dutton 		"3D Control - Center",
197521fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
197621fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
197721fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
197821fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
197921fdddeaSJames Courtier-Dutton 		NULL
198021fdddeaSJames Courtier-Dutton 	};
19816fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_1361t_adc[] = {
198221fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
198321fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
198421fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1985d355c82aSJaroslav Kysela 		"Beep Playback Switch", "Beep Capture Switch",
1986d355c82aSJaroslav Kysela 		"Beep Playback Volume", "Beep Capture Volume",
198721fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
198821fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
198921fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
199021fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
199121fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
199221fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
199321fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
199421fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
199521fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
199621fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
199721fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
199821fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
199952051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
200052051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
200121fdddeaSJames Courtier-Dutton 		NULL
200221fdddeaSJames Courtier-Dutton 	};
20031da177e4SLinus Torvalds 
20042b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
2005eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
2006eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
200751055da5STakashi Iwai 		static const struct snd_ac97_bus_ops ops = {
20081da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
20091da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
20101da177e4SLinus Torvalds 		};
20111da177e4SLinus Torvalds 
201212bda107STakashi Iwai 		err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus);
201312bda107STakashi Iwai 		if (err < 0)
20141da177e4SLinus Torvalds 			return err;
20151da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
20161da177e4SLinus Torvalds 
20171da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
20181da177e4SLinus Torvalds 		ac97.private_data = emu;
20191da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
20201da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
202112bda107STakashi Iwai 		err = snd_ac97_mixer(pbus, &ac97, &emu->ac97);
202212bda107STakashi Iwai 		if (err < 0) {
2023b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
20241da177e4SLinus Torvalds 				return err;
20256f002b02STakashi Iwai 			dev_info(emu->card->dev,
20266f002b02STakashi Iwai 				 "AC97 is optional on this board\n");
20276f002b02STakashi Iwai 			dev_info(emu->card->dev,
20286f002b02STakashi Iwai 				 "Proceeding without ac97 mixers...\n");
2029b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
2030b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
2031b1508693STakashi Iwai 		}
20321da177e4SLinus Torvalds 		if (emu->audigy) {
20331da177e4SLinus Torvalds 			/* set master volume to 0 dB */
20344d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
20351da177e4SLinus Torvalds 			/* set capture source to mic */
20364d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
203752051942SMaciej S. Szmigiero 			/* set mono output (TAD) to mic */
203852051942SMaciej S. Szmigiero 			snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE,
203952051942SMaciej S. Szmigiero 				0x0200, 0x0200);
204021fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
204121fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
204221fdddeaSJames Courtier-Dutton 			else
20431da177e4SLinus Torvalds 				c = audigy_remove_ctls;
20441da177e4SLinus Torvalds 		} else {
20451da177e4SLinus Torvalds 			/*
20461da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
20471da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
20481da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
20491da177e4SLinus Torvalds 			 */
20501da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
20511da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
20521da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
20532594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
2054b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Volume");
2055b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Switch");
20561da177e4SLinus Torvalds 			}
20571da177e4SLinus Torvalds 			/* remove unused AC97 controls */
20584d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
20594d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
20601da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
20611da177e4SLinus Torvalds 		}
20621da177e4SLinus Torvalds 		for (; *c; c++)
20631da177e4SLinus Torvalds 			remove_ctl(card, *c);
2064184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
2065184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
2066184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
2067184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
20681da177e4SLinus Torvalds 	} else {
2069f12aa40cSTakashi Iwai 	no_ac97:
20702b637da5SLee Revell 		if (emu->card_capabilities->ecard)
20711da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
20721da177e4SLinus Torvalds 		else if (emu->audigy)
20731da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
20741da177e4SLinus Torvalds 		else
20751da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
20761da177e4SLinus Torvalds 	}
20771da177e4SLinus Torvalds 
20781da177e4SLinus Torvalds 	if (emu->audigy)
207921fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
208021fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
2081184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
2082184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
208321fdddeaSJames Courtier-Dutton 		else
20841da177e4SLinus Torvalds 			c = audigy_rename_ctls;
20851da177e4SLinus Torvalds 	else
20861da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
20871da177e4SLinus Torvalds 	for (; *c; c += 2)
20881da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
208921fdddeaSJames Courtier-Dutton 
2090e217b960SRaymond Yau 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
2091e217b960SRaymond Yau 		remove_ctl(card, "Center Playback Volume");
2092e217b960SRaymond Yau 		remove_ctl(card, "LFE Playback Volume");
2093e217b960SRaymond Yau 		remove_ctl(card, "Wave Center Playback Volume");
2094e217b960SRaymond Yau 		remove_ctl(card, "Wave LFE Playback Volume");
2095e217b960SRaymond Yau 	}
2096e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
2097e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
2098e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
2099e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
2100e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
2101e3b9bc0eSJames Courtier-Dutton 	}
210212bda107STakashi Iwai 	kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu);
210312bda107STakashi Iwai 	if (!kctl)
21041da177e4SLinus Torvalds 		return -ENOMEM;
210567ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
210612bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
210712bda107STakashi Iwai 	if (err)
21081da177e4SLinus Torvalds 		return err;
210912bda107STakashi Iwai 	kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu);
211012bda107STakashi Iwai 	if (!kctl)
21111da177e4SLinus Torvalds 		return -ENOMEM;
211267ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
211312bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
211412bda107STakashi Iwai 	if (err)
21151da177e4SLinus Torvalds 		return err;
211612bda107STakashi Iwai 	kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu);
211712bda107STakashi Iwai 	if (!kctl)
21181da177e4SLinus Torvalds 		return -ENOMEM;
211967ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
212012bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
212112bda107STakashi Iwai 	if (err)
21221da177e4SLinus Torvalds 		return err;
21231da177e4SLinus Torvalds 
212412bda107STakashi Iwai 	kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu);
212512bda107STakashi Iwai 	if (!kctl)
21261da177e4SLinus Torvalds 		return -ENOMEM;
212767ed4161SClemens Ladisch 	kctl->id.device = multi_device;
212812bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
212912bda107STakashi Iwai 	if (err)
21301da177e4SLinus Torvalds 		return err;
21311da177e4SLinus Torvalds 
213212bda107STakashi Iwai 	kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu);
213312bda107STakashi Iwai 	if (!kctl)
21341da177e4SLinus Torvalds 		return -ENOMEM;
213567ed4161SClemens Ladisch 	kctl->id.device = multi_device;
213612bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
213712bda107STakashi Iwai 	if (err)
21381da177e4SLinus Torvalds 		return err;
21391da177e4SLinus Torvalds 
214012bda107STakashi Iwai 	kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu);
214112bda107STakashi Iwai 	if (!kctl)
21421da177e4SLinus Torvalds 		return -ENOMEM;
214367ed4161SClemens Ladisch 	kctl->id.device = multi_device;
214412bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
214512bda107STakashi Iwai 	if (err)
21461da177e4SLinus Torvalds 		return err;
21471da177e4SLinus Torvalds 
2148a8661af5SOswald Buddenhagen 	if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) {
21491da177e4SLinus Torvalds 		/* sb live! and audigy */
215012bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu);
215112bda107STakashi Iwai 		if (!kctl)
21521da177e4SLinus Torvalds 			return -ENOMEM;
21535549d549SClemens Ladisch 		if (!emu->audigy)
21545549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
215512bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
215612bda107STakashi Iwai 		if (err)
21571da177e4SLinus Torvalds 			return err;
215812bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu);
215912bda107STakashi Iwai 		if (!kctl)
21601da177e4SLinus Torvalds 			return -ENOMEM;
21615549d549SClemens Ladisch 		if (!emu->audigy)
21625549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
216312bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
216412bda107STakashi Iwai 		if (err)
21651da177e4SLinus Torvalds 			return err;
21661da177e4SLinus Torvalds 	}
21671da177e4SLinus Torvalds 
2168190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
216919b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
217019b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
217112bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu);
217212bda107STakashi Iwai 		if (!kctl)
21731da177e4SLinus Torvalds 			return -ENOMEM;
217412bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
217512bda107STakashi Iwai 		if (err)
21761da177e4SLinus Torvalds 			return err;
2177001f7589SJames Courtier-Dutton #if 0
217812bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu);
217912bda107STakashi Iwai 		if (!kctl)
21801da177e4SLinus Torvalds 			return -ENOMEM;
218112bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
218212bda107STakashi Iwai 		if (err)
21831da177e4SLinus Torvalds 			return err;
2184001f7589SJames Courtier-Dutton #endif
21852b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
21861da177e4SLinus Torvalds 		/* sb live! */
218712bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu);
218812bda107STakashi Iwai 		if (!kctl)
21891da177e4SLinus Torvalds 			return -ENOMEM;
219012bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
219112bda107STakashi Iwai 		if (err)
21921da177e4SLinus Torvalds 			return err;
21931da177e4SLinus Torvalds 	}
21942b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
219512bda107STakashi Iwai 		err = snd_p16v_mixer(emu);
219612bda107STakashi Iwai 		if (err)
21971da177e4SLinus Torvalds 			return err;
21981da177e4SLinus Torvalds 	}
21991da177e4SLinus Torvalds 
22001fc710f0SOswald Buddenhagen 	if (emu->card_capabilities->emu_model) {
22011fc710f0SOswald Buddenhagen 		unsigned i, emu_idx = emu1010_idx(emu);
22021fc710f0SOswald Buddenhagen 		const struct snd_emu1010_routing_info *emu_ri =
22031fc710f0SOswald Buddenhagen 			&emu1010_routing_info[emu_idx];
220497f1582eSOswald Buddenhagen 		const struct snd_emu1010_pads_info *emu_pi = &emu1010_pads_info[emu_idx];
22051fc710f0SOswald Buddenhagen 
22061fc710f0SOswald Buddenhagen 		for (i = 0; i < emu_ri->n_ins; i++)
22071fc710f0SOswald Buddenhagen 			emu->emu1010.input_source[i] =
22081fc710f0SOswald Buddenhagen 				emu1010_map_source(emu_ri, emu_ri->in_dflts[i]);
22091fc710f0SOswald Buddenhagen 		for (i = 0; i < emu_ri->n_outs; i++)
22101fc710f0SOswald Buddenhagen 			emu->emu1010.output_source[i] =
22111fc710f0SOswald Buddenhagen 				emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
22121fc710f0SOswald Buddenhagen 		snd_emu1010_apply_sources(emu);
22131fc710f0SOswald Buddenhagen 
22141c02e366SCtirad Fertr 		err = snd_ctl_add(card,
22151c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
22161c02e366SCtirad Fertr 		if (err < 0)
22171c02e366SCtirad Fertr 			return err;
221897f1582eSOswald Buddenhagen 
221997f1582eSOswald Buddenhagen 		err = add_ctls(emu, &emu1010_adc_pads_ctl,
222097f1582eSOswald Buddenhagen 			       emu_pi->adc_ctls, emu_pi->n_adc_ctls);
222197f1582eSOswald Buddenhagen 		if (err < 0)
222297f1582eSOswald Buddenhagen 			return err;
222397f1582eSOswald Buddenhagen 		err = add_ctls(emu, &emu1010_dac_pads_ctl,
222497f1582eSOswald Buddenhagen 			       emu_pi->dac_ctls, emu_pi->n_dac_ctls);
222597f1582eSOswald Buddenhagen 		if (err < 0)
222697f1582eSOswald Buddenhagen 			return err;
222797f1582eSOswald Buddenhagen 
222899dcab46SMichael Gernoth 		err = snd_ctl_add(card,
222999dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
223099dcab46SMichael Gernoth 		if (err < 0)
223199dcab46SMichael Gernoth 			return err;
223299dcab46SMichael Gernoth 		err = snd_ctl_add(card,
223399dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
223499dcab46SMichael Gernoth 		if (err < 0)
223599dcab46SMichael Gernoth 			return err;
22361c02e366SCtirad Fertr 
223797f1582eSOswald Buddenhagen 		err = add_emu1010_source_mixers(emu);
223899dcab46SMichael Gernoth 		if (err < 0)
223999dcab46SMichael Gernoth 			return err;
22409f4bd5ddSJames Courtier-Dutton 	}
22419f4bd5ddSJames Courtier-Dutton 
2242184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2243184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2244184c1e2cSJames Courtier-Dutton 		if (err < 0)
2245184c1e2cSJames Courtier-Dutton 			return err;
2246184c1e2cSJames Courtier-Dutton 
2247536438f1SOswald Buddenhagen 		err = add_ctls(emu, &i2c_volume_ctl,
2248536438f1SOswald Buddenhagen 			       snd_audigy_i2c_volume_ctls,
2249536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_audigy_i2c_volume_ctls));
2250184c1e2cSJames Courtier-Dutton 		if (err < 0)
2251184c1e2cSJames Courtier-Dutton 			return err;
2252184c1e2cSJames Courtier-Dutton 	}
2253184c1e2cSJames Courtier-Dutton 
225416950e09STakashi Iwai 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
225516950e09STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
225616950e09STakashi Iwai 						     emu));
225716950e09STakashi Iwai 		if (err < 0)
225816950e09STakashi Iwai 			return err;
225916950e09STakashi Iwai 	}
226016950e09STakashi Iwai 
22611da177e4SLinus Torvalds 	return 0;
22621da177e4SLinus Torvalds }
2263