xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision 1fc710f06aa8f33abab4fdded9463eefdff7d390)
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 
1751c02e366SCtirad Fertr /* 1616(m) cardbus */
176dc39bb3eSOswald Buddenhagen 
177dc39bb3eSOswald Buddenhagen #define EMU1616_COMMON_TEXTS \
178dc39bb3eSOswald Buddenhagen 	"Silence", \
179dc39bb3eSOswald Buddenhagen 	PAIR_TEXTS("Mic", "A", "B"), \
180dc39bb3eSOswald Buddenhagen 	LR_TEXTS("ADC1"), \
181dc39bb3eSOswald Buddenhagen 	LR_TEXTS("ADC2"), \
182dc39bb3eSOswald Buddenhagen 	LR_TEXTS("SPDIF"), \
183dc39bb3eSOswald Buddenhagen 	ADAT_TEXTS("")
184dc39bb3eSOswald Buddenhagen 
185dc39bb3eSOswald Buddenhagen static const char * const emu1616_src_texts[] = {
186dc39bb3eSOswald Buddenhagen 	EMU1616_COMMON_TEXTS,
187dc39bb3eSOswald Buddenhagen 	DSP_TEXTS,
188dc39bb3eSOswald Buddenhagen };
189dc39bb3eSOswald Buddenhagen 
1909b00a1e9SOswald Buddenhagen static const unsigned short emu1616_src_regs[] = {
1911c02e366SCtirad Fertr 	EMU_SRC_SILENCE,
192dc39bb3eSOswald Buddenhagen 	PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B),
193dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC1),
194dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_DOCK_ADC2),
195dc39bb3eSOswald Buddenhagen 	LR_REGS(EMU_SRC_MDOCK_SPDIF),
196dc39bb3eSOswald Buddenhagen 	ADAT_REGS(EMU_SRC_MDOCK_ADAT),
197dc39bb3eSOswald Buddenhagen 	EMU32_SRC_REGS,
1981c02e366SCtirad Fertr };
199dc39bb3eSOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_src_regs) == ARRAY_SIZE(emu1616_src_texts));
2001c02e366SCtirad Fertr 
20113d45709SPavel Hofman /*
20213d45709SPavel Hofman  * Data destinations - physical EMU outputs.
20313d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
20413d45709SPavel Hofman  */
205536438f1SOswald Buddenhagen 
206536438f1SOswald Buddenhagen #define LR_CTLS(base) LR_PS(base, " Playback Enum")
207536438f1SOswald Buddenhagen #define ADAT_CTLS(pfx) ADAT_PS(pfx, " Playback Enum")
208536438f1SOswald Buddenhagen 
209536438f1SOswald Buddenhagen static const char * const emu1010_output_texts[] = {
210536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
211536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
212536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
213536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC4"),
214536438f1SOswald Buddenhagen 	LR_CTLS("Dock Phones"),
215536438f1SOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
216536438f1SOswald Buddenhagen 	LR_CTLS("0202 DAC"),
217536438f1SOswald Buddenhagen 	LR_CTLS("1010 SPDIF"),
218536438f1SOswald Buddenhagen 	ADAT_CTLS("1010 "),
2199f4bd5ddSJames Courtier-Dutton };
2209f4bd5ddSJames Courtier-Dutton 
221536438f1SOswald Buddenhagen static const unsigned short emu1010_output_dst[] = {
222536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
223536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
224536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
225536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC4),
226536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_PHONES),
227536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_SPDIF),
228536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
229536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
230536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_HANA_ADAT),
2311c02e366SCtirad Fertr };
232536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dst) == ARRAY_SIZE(emu1010_output_texts));
233536438f1SOswald Buddenhagen 
234*1fc710f0SOswald Buddenhagen static const unsigned short emu1010_output_dflt[] = {
235*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
236*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
237*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
238*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
239*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
240*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
241*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
242*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
243*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
244*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
245*1fc710f0SOswald Buddenhagen };
246*1fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dflt) == ARRAY_SIZE(emu1010_output_dst));
247*1fc710f0SOswald Buddenhagen 
248536438f1SOswald Buddenhagen /* 1616(m) cardbus */
249536438f1SOswald Buddenhagen 
250536438f1SOswald Buddenhagen static const char * const snd_emu1616_output_texts[] = {
251536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
252536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
253536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
254536438f1SOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
255536438f1SOswald Buddenhagen 	ADAT_CTLS("Dock "),
256536438f1SOswald Buddenhagen 	LR_CTLS("Mana DAC"),
257536438f1SOswald Buddenhagen };
258536438f1SOswald Buddenhagen 
259536438f1SOswald Buddenhagen static const unsigned short emu1616_output_dst[] = {
260536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
261536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
262536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
263536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_MDOCK_SPDIF),
264536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_MDOCK_ADAT),
265536438f1SOswald Buddenhagen 	EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT,
266536438f1SOswald Buddenhagen };
267536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dst) == ARRAY_SIZE(snd_emu1616_output_texts));
2681c02e366SCtirad Fertr 
269*1fc710f0SOswald Buddenhagen static const unsigned short emu1616_output_dflt[] = {
270*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
271*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
272*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
273*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
274*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
275*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
276*1fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
277*1fc710f0SOswald Buddenhagen };
278*1fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dflt) == ARRAY_SIZE(emu1616_output_dst));
279*1fc710f0SOswald Buddenhagen 
28013d45709SPavel Hofman /*
281a869057cSOswald Buddenhagen  * Data destinations - FPGA outputs going to Alice2 (Audigy) for
28213d45709SPavel Hofman  *   capture (EMU32 + I2S links)
28313d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
28413d45709SPavel Hofman  */
285536438f1SOswald Buddenhagen 
286536438f1SOswald Buddenhagen static const char * const emu1010_input_texts[] = {
287536438f1SOswald Buddenhagen 	"DSP 0 Capture Enum",
288536438f1SOswald Buddenhagen 	"DSP 1 Capture Enum",
289536438f1SOswald Buddenhagen 	"DSP 2 Capture Enum",
290536438f1SOswald Buddenhagen 	"DSP 3 Capture Enum",
291536438f1SOswald Buddenhagen 	"DSP 4 Capture Enum",
292536438f1SOswald Buddenhagen 	"DSP 5 Capture Enum",
293536438f1SOswald Buddenhagen 	"DSP 6 Capture Enum",
294536438f1SOswald Buddenhagen 	"DSP 7 Capture Enum",
295536438f1SOswald Buddenhagen 	"DSP 8 Capture Enum",
296536438f1SOswald Buddenhagen 	"DSP 9 Capture Enum",
297536438f1SOswald Buddenhagen 	"DSP A Capture Enum",
298536438f1SOswald Buddenhagen 	"DSP B Capture Enum",
299536438f1SOswald Buddenhagen 	"DSP C Capture Enum",
300536438f1SOswald Buddenhagen 	"DSP D Capture Enum",
301536438f1SOswald Buddenhagen 	"DSP E Capture Enum",
302536438f1SOswald Buddenhagen 	"DSP F Capture Enum",
303536438f1SOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
304536438f1SOswald Buddenhagen 	"DSP 10 Capture Enum",
305536438f1SOswald Buddenhagen 	"DSP 11 Capture Enum",
306536438f1SOswald Buddenhagen 	"DSP 12 Capture Enum",
307536438f1SOswald Buddenhagen 	"DSP 13 Capture Enum",
308536438f1SOswald Buddenhagen 	"DSP 14 Capture Enum",
309536438f1SOswald Buddenhagen 	"DSP 15 Capture Enum",
310536438f1SOswald Buddenhagen };
311536438f1SOswald Buddenhagen 
3129b00a1e9SOswald Buddenhagen static const unsigned short emu1010_input_dst[] = {
3139f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_0,
3149f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_1,
3159f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_2,
3169f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_3,
3179f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_4,
3189f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_5,
3199f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_6,
3209f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_7,
3219f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_8,
3229f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_9,
3239f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_A,
3249f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_B,
3259f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_C,
3269f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_D,
3279f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_E,
3289f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_F,
329a869057cSOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
3309f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_LEFT,
3319f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_RIGHT,
3329f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_LEFT,
3339f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_RIGHT,
3349f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_LEFT,
3359f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_RIGHT,
3369f4bd5ddSJames Courtier-Dutton };
337536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts));
3389f4bd5ddSJames Courtier-Dutton 
339*1fc710f0SOswald Buddenhagen static const unsigned short emu1010_input_dflt[] = {
340*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_A1,
341*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_B1,
342*1fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
343*1fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
344*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
345*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
346*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
347*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
348*1fc710f0SOswald Buddenhagen 	/* Pavel Hofman - setting defaults for all capture channels.
349*1fc710f0SOswald Buddenhagen 	 * Defaults only, users will set their own values anyways, let's
350*1fc710f0SOswald Buddenhagen 	 * just copy/paste. */
351*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_A1,
352*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_B1,
353*1fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
354*1fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
355*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
356*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
357*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
358*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
359*1fc710f0SOswald Buddenhagen 
360*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
361*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
362*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
363*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
364*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC3_LEFT1,
365*1fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC3_RIGHT1,
366*1fc710f0SOswald Buddenhagen };
367*1fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dflt) == ARRAY_SIZE(emu1010_input_dst));
368*1fc710f0SOswald Buddenhagen 
369511cbe8fSOswald Buddenhagen struct snd_emu1010_routing_info {
370511cbe8fSOswald Buddenhagen 	const char * const *src_texts;
371511cbe8fSOswald Buddenhagen 	const unsigned short *src_regs;
372511cbe8fSOswald Buddenhagen 	const unsigned short *out_regs;
373511cbe8fSOswald Buddenhagen 	const unsigned short *in_regs;
374*1fc710f0SOswald Buddenhagen 	const unsigned short *out_dflts;
375*1fc710f0SOswald Buddenhagen 	const unsigned short *in_dflts;
376511cbe8fSOswald Buddenhagen 	unsigned n_srcs;
377511cbe8fSOswald Buddenhagen 	unsigned n_outs;
378511cbe8fSOswald Buddenhagen 	unsigned n_ins;
379511cbe8fSOswald Buddenhagen };
380511cbe8fSOswald Buddenhagen 
381511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info emu1010_routing_info[] = {
382511cbe8fSOswald Buddenhagen 	{
383511cbe8fSOswald Buddenhagen 		.src_regs = emu1010_src_regs,
384511cbe8fSOswald Buddenhagen 		.src_texts = emu1010_src_texts,
385511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1010_src_texts),
386511cbe8fSOswald Buddenhagen 
387*1fc710f0SOswald Buddenhagen 		.out_dflts = emu1010_output_dflt,
388511cbe8fSOswald Buddenhagen 		.out_regs = emu1010_output_dst,
389511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1010_output_dst),
390511cbe8fSOswald Buddenhagen 
391*1fc710f0SOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
392511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
393511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst),
394511cbe8fSOswald Buddenhagen 	},
395511cbe8fSOswald Buddenhagen 	{
396511cbe8fSOswald Buddenhagen 		/* 1616(m) cardbus */
397511cbe8fSOswald Buddenhagen 		.src_regs = emu1616_src_regs,
398511cbe8fSOswald Buddenhagen 		.src_texts = emu1616_src_texts,
399511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1616_src_texts),
400511cbe8fSOswald Buddenhagen 
401*1fc710f0SOswald Buddenhagen 		.out_dflts = emu1616_output_dflt,
402511cbe8fSOswald Buddenhagen 		.out_regs = emu1616_output_dst,
403511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1616_output_dst),
404511cbe8fSOswald Buddenhagen 
405*1fc710f0SOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
406511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
407511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
408511cbe8fSOswald Buddenhagen 	},
409511cbe8fSOswald Buddenhagen };
410511cbe8fSOswald Buddenhagen 
411511cbe8fSOswald Buddenhagen static unsigned emu1010_idx(struct snd_emu10k1 *emu)
412511cbe8fSOswald Buddenhagen {
413511cbe8fSOswald Buddenhagen 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
414511cbe8fSOswald Buddenhagen 		return 1;
415511cbe8fSOswald Buddenhagen 	else
416511cbe8fSOswald Buddenhagen 		return 0;
417511cbe8fSOswald Buddenhagen }
418511cbe8fSOswald Buddenhagen 
419511cbe8fSOswald Buddenhagen static void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu,
420511cbe8fSOswald Buddenhagen 					    int channel, int src)
421511cbe8fSOswald Buddenhagen {
422511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
423511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
424511cbe8fSOswald Buddenhagen 
425511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
426511cbe8fSOswald Buddenhagen 		emu_ri->out_regs[channel], emu_ri->src_regs[src]);
427511cbe8fSOswald Buddenhagen }
428511cbe8fSOswald Buddenhagen 
429511cbe8fSOswald Buddenhagen static void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu,
430511cbe8fSOswald Buddenhagen 					   int channel, int src)
431511cbe8fSOswald Buddenhagen {
432511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
433511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
434511cbe8fSOswald Buddenhagen 
435511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
436511cbe8fSOswald Buddenhagen 		emu_ri->in_regs[channel], emu_ri->src_regs[src]);
437511cbe8fSOswald Buddenhagen }
438511cbe8fSOswald Buddenhagen 
439*1fc710f0SOswald Buddenhagen static void snd_emu1010_apply_sources(struct snd_emu10k1 *emu)
440*1fc710f0SOswald Buddenhagen {
441*1fc710f0SOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
442*1fc710f0SOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
443*1fc710f0SOswald Buddenhagen 
444*1fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_outs; i++)
445*1fc710f0SOswald Buddenhagen 		snd_emu1010_output_source_apply(
446*1fc710f0SOswald Buddenhagen 			emu, i, emu->emu1010.output_source[i]);
447*1fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_ins; i++)
448*1fc710f0SOswald Buddenhagen 		snd_emu1010_input_source_apply(
449*1fc710f0SOswald Buddenhagen 			emu, i, emu->emu1010.input_source[i]);
450*1fc710f0SOswald Buddenhagen }
451*1fc710f0SOswald Buddenhagen 
452*1fc710f0SOswald Buddenhagen static u8 emu1010_map_source(const struct snd_emu1010_routing_info *emu_ri,
453*1fc710f0SOswald Buddenhagen 			     unsigned val)
454*1fc710f0SOswald Buddenhagen {
455*1fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_srcs; i++)
456*1fc710f0SOswald Buddenhagen 		if (val == emu_ri->src_regs[i])
457*1fc710f0SOswald Buddenhagen 			return i;
458*1fc710f0SOswald Buddenhagen 	return 0;
459*1fc710f0SOswald Buddenhagen }
460*1fc710f0SOswald Buddenhagen 
4611c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
4621c02e366SCtirad Fertr 						struct snd_ctl_elem_info *uinfo)
4639f4bd5ddSJames Courtier-Dutton {
4641c02e366SCtirad Fertr 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
465511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
466511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
4671c02e366SCtirad Fertr 
468511cbe8fSOswald Buddenhagen 	return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts);
4699f4bd5ddSJames Courtier-Dutton }
4709f4bd5ddSJames Courtier-Dutton 
4719f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
4729f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4739f4bd5ddSJames Courtier-Dutton {
4749f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
475511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
476511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
477511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
4789f4bd5ddSJames Courtier-Dutton 
479511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
48074415a36SJames Courtier-Dutton 		return -EINVAL;
4819f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
4829f4bd5ddSJames Courtier-Dutton 	return 0;
4839f4bd5ddSJames Courtier-Dutton }
4849f4bd5ddSJames Courtier-Dutton 
4859f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
4869f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4879f4bd5ddSJames Courtier-Dutton {
4889f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
489511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
490511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
491511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
492511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
493511cbe8fSOswald Buddenhagen 	int change;
4949f4bd5ddSJames Courtier-Dutton 
495511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
496aa299d01STakashi Iwai 		return -EINVAL;
497511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
49874415a36SJames Courtier-Dutton 		return -EINVAL;
499511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.output_source[channel] != val);
500511cbe8fSOswald Buddenhagen 	if (change) {
501aa299d01STakashi Iwai 		emu->emu1010.output_source[channel] = val;
502511cbe8fSOswald Buddenhagen 		snd_emu1010_output_source_apply(emu, channel, val);
503511cbe8fSOswald Buddenhagen 	}
504511cbe8fSOswald Buddenhagen 	return change;
5059f4bd5ddSJames Courtier-Dutton }
5069f4bd5ddSJames Courtier-Dutton 
507536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_output_source_ctl = {
508536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
509536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
510536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
511536438f1SOswald Buddenhagen 	.get = snd_emu1010_output_source_get,
512536438f1SOswald Buddenhagen 	.put = snd_emu1010_output_source_put
513536438f1SOswald Buddenhagen };
514536438f1SOswald Buddenhagen 
5159f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
5169f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
5179f4bd5ddSJames Courtier-Dutton {
5189f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
519511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
520511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
521511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
5229f4bd5ddSJames Courtier-Dutton 
523511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
52474415a36SJames Courtier-Dutton 		return -EINVAL;
5259f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
5269f4bd5ddSJames Courtier-Dutton 	return 0;
5279f4bd5ddSJames Courtier-Dutton }
5289f4bd5ddSJames Courtier-Dutton 
5299f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
5309f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
5319f4bd5ddSJames Courtier-Dutton {
5329f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
533511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
534511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
535511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
536511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
537511cbe8fSOswald Buddenhagen 	int change;
5389f4bd5ddSJames Courtier-Dutton 
539511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
540aa299d01STakashi Iwai 		return -EINVAL;
541511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
54274415a36SJames Courtier-Dutton 		return -EINVAL;
543511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.input_source[channel] != val);
544511cbe8fSOswald Buddenhagen 	if (change) {
545aa299d01STakashi Iwai 		emu->emu1010.input_source[channel] = val;
546511cbe8fSOswald Buddenhagen 		snd_emu1010_input_source_apply(emu, channel, val);
547511cbe8fSOswald Buddenhagen 	}
548511cbe8fSOswald Buddenhagen 	return change;
5499f4bd5ddSJames Courtier-Dutton }
5509f4bd5ddSJames Courtier-Dutton 
551536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_input_source_ctl = {
552536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
553536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
554536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
555536438f1SOswald Buddenhagen 	.get = snd_emu1010_input_source_get,
556536438f1SOswald Buddenhagen 	.put = snd_emu1010_input_source_put
5579f4bd5ddSJames Courtier-Dutton };
5589f4bd5ddSJames Courtier-Dutton 
5591c02e366SCtirad Fertr 
560536438f1SOswald Buddenhagen static const char * const snd_emu1010_adc_pads[] = {
561536438f1SOswald Buddenhagen 	"ADC1 14dB PAD Audio Dock Capture Switch",
562536438f1SOswald Buddenhagen 	"ADC2 14dB PAD Audio Dock Capture Switch",
563536438f1SOswald Buddenhagen 	"ADC3 14dB PAD Audio Dock Capture Switch",
564536438f1SOswald Buddenhagen 	"ADC1 14dB PAD 0202 Capture Switch",
5651c02e366SCtirad Fertr };
5661c02e366SCtirad Fertr 
567536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_adc_pad_regs[] = {
568536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD1,
569536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD2,
570536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD3,
571536438f1SOswald Buddenhagen 	EMU_HANA_0202_ADC_PAD1,
5729148cc50SJames Courtier-Dutton };
5739148cc50SJames Courtier-Dutton 
574a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
5759148cc50SJames Courtier-Dutton 
5769148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5779148cc50SJames Courtier-Dutton {
5789148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
579536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
580536438f1SOswald Buddenhagen 
5819148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
5829148cc50SJames Courtier-Dutton 	return 0;
5839148cc50SJames Courtier-Dutton }
5849148cc50SJames Courtier-Dutton 
5859148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5869148cc50SJames Courtier-Dutton {
5879148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
588536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
5899148cc50SJames Courtier-Dutton 	unsigned int val, cache;
5909148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
5919148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
5929148cc50SJames Courtier-Dutton 	if (val == 1)
5939148cc50SJames Courtier-Dutton 		cache = cache | mask;
5949148cc50SJames Courtier-Dutton 	else
5959148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
5969148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
5979148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
5989148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
5999148cc50SJames Courtier-Dutton 	}
6009148cc50SJames Courtier-Dutton 
6019148cc50SJames Courtier-Dutton 	return 0;
6029148cc50SJames Courtier-Dutton }
6039148cc50SJames Courtier-Dutton 
604536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_adc_pads_ctl = {
605536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
606536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
607536438f1SOswald Buddenhagen 	.info = snd_emu1010_adc_pads_info,
608536438f1SOswald Buddenhagen 	.get = snd_emu1010_adc_pads_get,
609536438f1SOswald Buddenhagen 	.put = snd_emu1010_adc_pads_put
610536438f1SOswald Buddenhagen };
6119148cc50SJames Courtier-Dutton 
6129148cc50SJames Courtier-Dutton 
613536438f1SOswald Buddenhagen static const char * const snd_emu1010_dac_pads[] = {
614536438f1SOswald Buddenhagen 	"DAC1 Audio Dock 14dB PAD Playback Switch",
615536438f1SOswald Buddenhagen 	"DAC2 Audio Dock 14dB PAD Playback Switch",
616536438f1SOswald Buddenhagen 	"DAC3 Audio Dock 14dB PAD Playback Switch",
617536438f1SOswald Buddenhagen 	"DAC4 Audio Dock 14dB PAD Playback Switch",
618536438f1SOswald Buddenhagen 	"DAC1 0202 14dB PAD Playback Switch",
619536438f1SOswald Buddenhagen };
6209148cc50SJames Courtier-Dutton 
621536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_dac_regs[] = {
622536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD1,
623536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD2,
624536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD3,
625536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD4,
626536438f1SOswald Buddenhagen 	EMU_HANA_0202_DAC_PAD1,
6279148cc50SJames Courtier-Dutton };
6289148cc50SJames Courtier-Dutton 
629a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
6309148cc50SJames Courtier-Dutton 
6319148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6329148cc50SJames Courtier-Dutton {
6339148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
634536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
635536438f1SOswald Buddenhagen 
6369148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
6379148cc50SJames Courtier-Dutton 	return 0;
6389148cc50SJames Courtier-Dutton }
6399148cc50SJames Courtier-Dutton 
6409148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6419148cc50SJames Courtier-Dutton {
6429148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
643536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
6449148cc50SJames Courtier-Dutton 	unsigned int val, cache;
645cc766807SOswald Buddenhagen 	int change;
646cc766807SOswald Buddenhagen 
6479148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
6489148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
6499148cc50SJames Courtier-Dutton 	if (val == 1)
6509148cc50SJames Courtier-Dutton 		cache = cache | mask;
6519148cc50SJames Courtier-Dutton 	else
6529148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
653cc766807SOswald Buddenhagen 	change = (cache != emu->emu1010.dac_pads);
654cc766807SOswald Buddenhagen 	if (change) {
6559148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
6569148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
6579148cc50SJames Courtier-Dutton 	}
6589148cc50SJames Courtier-Dutton 
659cc766807SOswald Buddenhagen 	return change;
6609148cc50SJames Courtier-Dutton }
6619148cc50SJames Courtier-Dutton 
662536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_dac_pads_ctl = {
663536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
664536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
665536438f1SOswald Buddenhagen 	.info = snd_emu1010_dac_pads_info,
666536438f1SOswald Buddenhagen 	.get = snd_emu1010_dac_pads_get,
667536438f1SOswald Buddenhagen 	.put = snd_emu1010_dac_pads_put
6689f4bd5ddSJames Courtier-Dutton };
6699f4bd5ddSJames Courtier-Dutton 
670b0dbdaeaSJames Courtier-Dutton 
671b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
672b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
673b0dbdaeaSJames Courtier-Dutton {
6741541c66dSTakashi Iwai 	static const char * const texts[4] = {
675edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
676b0dbdaeaSJames Courtier-Dutton 	};
677b0dbdaeaSJames Courtier-Dutton 
6781541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 4, texts);
679b0dbdaeaSJames Courtier-Dutton }
680b0dbdaeaSJames Courtier-Dutton 
681b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
682b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
683b0dbdaeaSJames Courtier-Dutton {
684b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
685b0dbdaeaSJames Courtier-Dutton 
686b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
687b0dbdaeaSJames Courtier-Dutton 	return 0;
688b0dbdaeaSJames Courtier-Dutton }
689b0dbdaeaSJames Courtier-Dutton 
690b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
691b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
692b0dbdaeaSJames Courtier-Dutton {
693b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
694b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
695b0dbdaeaSJames Courtier-Dutton 	int change = 0;
696b0dbdaeaSJames Courtier-Dutton 
697b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
69874415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 4; */
69974415a36SJames Courtier-Dutton 	if (val >= 4)
70074415a36SJames Courtier-Dutton 		return -EINVAL;
701b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
702b0dbdaeaSJames Courtier-Dutton 	if (change) {
703b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
704b0dbdaeaSJames Courtier-Dutton 		switch (val) {
705b0dbdaeaSJames Courtier-Dutton 		case 0:
706b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
707b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
708b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
709a869057cSOswald Buddenhagen 			/* Default fallback clock 44.1kHz */
710b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
711b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
712b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
713b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
714b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
715b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
716b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
717b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
718e40a0b2eSJames Courtier-Dutton 			msleep(10);
719b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
720b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
721b0dbdaeaSJames Courtier-Dutton 			break;
722b0dbdaeaSJames Courtier-Dutton 		case 1:
723b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
724b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
725b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
726b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
727b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
728b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
729b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
730b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
731b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
732b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
733b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
734b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
735e40a0b2eSJames Courtier-Dutton 			msleep(10);
736b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
737b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
738b0dbdaeaSJames Courtier-Dutton 			break;
739edec7bbbSJames Courtier-Dutton 
740edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
741edec7bbbSJames Courtier-Dutton 			/* Mute all */
742edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
743edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
744edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
745edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
746edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
747edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
748edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
749edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
750edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
751edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
752edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
753edec7bbbSJames Courtier-Dutton 			msleep(10);
754edec7bbbSJames Courtier-Dutton 			/* Unmute all */
755edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
756edec7bbbSJames Courtier-Dutton 			break;
757edec7bbbSJames Courtier-Dutton 
758edec7bbbSJames Courtier-Dutton 		case 3:
759edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
760edec7bbbSJames Courtier-Dutton 			/* Mute all */
761edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
762edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
763edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
764edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
765edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
766edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
767edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
768edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
769edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
770edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
771edec7bbbSJames Courtier-Dutton 			msleep(10);
772edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
773edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
774edec7bbbSJames Courtier-Dutton 
775edec7bbbSJames Courtier-Dutton 
776edec7bbbSJames Courtier-Dutton 			break;
777b0dbdaeaSJames Courtier-Dutton 		}
778b0dbdaeaSJames Courtier-Dutton 	}
779b0dbdaeaSJames Courtier-Dutton         return change;
780b0dbdaeaSJames Courtier-Dutton }
781b0dbdaeaSJames Courtier-Dutton 
782f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock =
783b0dbdaeaSJames Courtier-Dutton {
784b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
785b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
786b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
787b0dbdaeaSJames Courtier-Dutton 	.count =	1,
788b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
789b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
790b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
791b0dbdaeaSJames Courtier-Dutton };
792b0dbdaeaSJames Courtier-Dutton 
79399dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
79499dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
79599dcab46SMichael Gernoth {
79699dcab46SMichael Gernoth 	static const char * const texts[2] = {
79799dcab46SMichael Gernoth 		"SPDIF", "ADAT"
79899dcab46SMichael Gernoth 	};
79999dcab46SMichael Gernoth 
80099dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
80199dcab46SMichael Gernoth }
80299dcab46SMichael Gernoth 
80399dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol,
80499dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
80599dcab46SMichael Gernoth {
80699dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
80799dcab46SMichael Gernoth 
80899dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out;
80999dcab46SMichael Gernoth 	return 0;
81099dcab46SMichael Gernoth }
81199dcab46SMichael Gernoth 
81299dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
81399dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
81499dcab46SMichael Gernoth {
81599dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
81699dcab46SMichael Gernoth 	unsigned int val;
81799dcab46SMichael Gernoth 	u32 tmp;
81899dcab46SMichael Gernoth 	int change = 0;
81999dcab46SMichael Gernoth 
82099dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
82199dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
82299dcab46SMichael Gernoth 	if (val >= 2)
82399dcab46SMichael Gernoth 		return -EINVAL;
82499dcab46SMichael Gernoth 	change = (emu->emu1010.optical_out != val);
82599dcab46SMichael Gernoth 	if (change) {
82699dcab46SMichael Gernoth 		emu->emu1010.optical_out = val;
8279d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
8289d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
82999dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
83099dcab46SMichael Gernoth 	}
83199dcab46SMichael Gernoth 	return change;
83299dcab46SMichael Gernoth }
83399dcab46SMichael Gernoth 
834f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = {
83599dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
83699dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
83799dcab46SMichael Gernoth 	.name =         "Optical Output Mode",
83899dcab46SMichael Gernoth 	.count =	1,
83999dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_out_info,
84099dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_out_get,
84199dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_out_put
84299dcab46SMichael Gernoth };
84399dcab46SMichael Gernoth 
84499dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
84599dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
84699dcab46SMichael Gernoth {
84799dcab46SMichael Gernoth 	static const char * const texts[2] = {
84899dcab46SMichael Gernoth 		"SPDIF", "ADAT"
84999dcab46SMichael Gernoth 	};
85099dcab46SMichael Gernoth 
85199dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
85299dcab46SMichael Gernoth }
85399dcab46SMichael Gernoth 
85499dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
85599dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
85699dcab46SMichael Gernoth {
85799dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
85899dcab46SMichael Gernoth 
85999dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
86099dcab46SMichael Gernoth 	return 0;
86199dcab46SMichael Gernoth }
86299dcab46SMichael Gernoth 
86399dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
86499dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
86599dcab46SMichael Gernoth {
86699dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
86799dcab46SMichael Gernoth 	unsigned int val;
86899dcab46SMichael Gernoth 	u32 tmp;
86999dcab46SMichael Gernoth 	int change = 0;
87099dcab46SMichael Gernoth 
87199dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
87299dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
87399dcab46SMichael Gernoth 	if (val >= 2)
87499dcab46SMichael Gernoth 		return -EINVAL;
87599dcab46SMichael Gernoth 	change = (emu->emu1010.optical_in != val);
87699dcab46SMichael Gernoth 	if (change) {
87799dcab46SMichael Gernoth 		emu->emu1010.optical_in = val;
8789d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
8799d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
88099dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
88199dcab46SMichael Gernoth 	}
88299dcab46SMichael Gernoth 	return change;
88399dcab46SMichael Gernoth }
88499dcab46SMichael Gernoth 
885f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = {
88699dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
88799dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
88899dcab46SMichael Gernoth 	.name =         "Optical Input Mode",
88999dcab46SMichael Gernoth 	.count =	1,
89099dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_in_info,
89199dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_in_get,
89299dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_in_put
89399dcab46SMichael Gernoth };
89499dcab46SMichael Gernoth 
895184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
896184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
897184c1e2cSJames Courtier-Dutton {
898184c1e2cSJames Courtier-Dutton #if 0
8991541c66dSTakashi Iwai 	static const char * const texts[4] = {
900184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
901184c1e2cSJames Courtier-Dutton 	};
902184c1e2cSJames Courtier-Dutton #endif
9031541c66dSTakashi Iwai 	static const char * const texts[2] = {
904184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
905184c1e2cSJames Courtier-Dutton 	};
906184c1e2cSJames Courtier-Dutton 
9071541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
908184c1e2cSJames Courtier-Dutton }
909184c1e2cSJames Courtier-Dutton 
910184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
911184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
912184c1e2cSJames Courtier-Dutton {
913184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
914184c1e2cSJames Courtier-Dutton 
915184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
916184c1e2cSJames Courtier-Dutton 	return 0;
917184c1e2cSJames Courtier-Dutton }
918184c1e2cSJames Courtier-Dutton 
919184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
920184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
921184c1e2cSJames Courtier-Dutton {
922184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
923184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
924184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
925a1c87c0bSOswald Buddenhagen 	u16 gpio;
926184c1e2cSJames Courtier-Dutton 	int change = 0;
927184c1e2cSJames Courtier-Dutton 	unsigned long flags;
928184c1e2cSJames Courtier-Dutton 	u32 source;
929184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
930184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
931184c1e2cSJames Courtier-Dutton 	 * for the particular source.
932184c1e2cSJames Courtier-Dutton 	 */
93374415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
93474415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
93574415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
93674415a36SJames Courtier-Dutton 	if (source_id >= 2)
93774415a36SJames Courtier-Dutton 		return -EINVAL;
938184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
939184c1e2cSJames Courtier-Dutton 	if (change) {
940184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
941184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
942a1c87c0bSOswald Buddenhagen 		gpio = inw(emu->port + A_IOCFG);
943184c1e2cSJames Courtier-Dutton 		if (source_id==0)
944a1c87c0bSOswald Buddenhagen 			outw(gpio | 0x4, emu->port + A_IOCFG);
945184c1e2cSJames Courtier-Dutton 		else
946a1c87c0bSOswald Buddenhagen 			outw(gpio & ~0x4, emu->port + A_IOCFG);
947184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
948184c1e2cSJames Courtier-Dutton 
949184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
950184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
951184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
952184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
953184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
954184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
955184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
956184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
957184c1e2cSJames Courtier-Dutton 
958184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
959184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
960184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
961184c1e2cSJames Courtier-Dutton 	}
962184c1e2cSJames Courtier-Dutton         return change;
963184c1e2cSJames Courtier-Dutton }
964184c1e2cSJames Courtier-Dutton 
965f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source =
966184c1e2cSJames Courtier-Dutton {
967184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
968184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
969184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
970184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
971184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
972184c1e2cSJames Courtier-Dutton };
973184c1e2cSJames Courtier-Dutton 
974184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
975184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
976184c1e2cSJames Courtier-Dutton {
977184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
978184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
979184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
980184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
981184c1e2cSJames Courtier-Dutton 	return 0;
982184c1e2cSJames Courtier-Dutton }
983184c1e2cSJames Courtier-Dutton 
984184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
985184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
986184c1e2cSJames Courtier-Dutton {
987184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
98874415a36SJames Courtier-Dutton 	unsigned int source_id;
989184c1e2cSJames Courtier-Dutton 
990184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
99174415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
99274415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
99374415a36SJames Courtier-Dutton 	if (source_id >= 2)
99474415a36SJames Courtier-Dutton 		return -EINVAL;
995184c1e2cSJames Courtier-Dutton 
996184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
997184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
998184c1e2cSJames Courtier-Dutton 	return 0;
999184c1e2cSJames Courtier-Dutton }
1000184c1e2cSJames Courtier-Dutton 
1001184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
1002184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
1003184c1e2cSJames Courtier-Dutton {
1004184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1005184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
100614a29565SOswald Buddenhagen 	unsigned int ngain0, ngain1;
100774415a36SJames Courtier-Dutton 	unsigned int source_id;
1008184c1e2cSJames Courtier-Dutton 	int change = 0;
1009184c1e2cSJames Courtier-Dutton 
1010184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
101174415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
101274415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
101374415a36SJames Courtier-Dutton 	if (source_id >= 2)
101474415a36SJames Courtier-Dutton 		return -EINVAL;
101514a29565SOswald Buddenhagen 	ngain0 = ucontrol->value.integer.value[0];
101614a29565SOswald Buddenhagen 	ngain1 = ucontrol->value.integer.value[1];
101714a29565SOswald Buddenhagen 	if (ngain0 > 0xff)
101814a29565SOswald Buddenhagen 		return -EINVAL;
101914a29565SOswald Buddenhagen 	if (ngain1 > 0xff)
102014a29565SOswald Buddenhagen 		return -EINVAL;
1021184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
102214a29565SOswald Buddenhagen 	if (ogain != ngain0) {
1023184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
102414a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0);
102514a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][0] = ngain0;
1026184c1e2cSJames Courtier-Dutton 		change = 1;
1027184c1e2cSJames Courtier-Dutton 	}
1028184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
102914a29565SOswald Buddenhagen 	if (ogain != ngain1) {
1030184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
103114a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1);
103214a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][1] = ngain1;
1033184c1e2cSJames Courtier-Dutton 		change = 1;
1034184c1e2cSJames Courtier-Dutton 	}
1035184c1e2cSJames Courtier-Dutton 
1036184c1e2cSJames Courtier-Dutton 	return change;
1037184c1e2cSJames Courtier-Dutton }
1038184c1e2cSJames Courtier-Dutton 
1039536438f1SOswald Buddenhagen static const struct snd_kcontrol_new i2c_volume_ctl = {
1040536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1041536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1042536438f1SOswald Buddenhagen 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,
1043536438f1SOswald Buddenhagen 	.info = snd_audigy_i2c_volume_info,
1044536438f1SOswald Buddenhagen 	.get = snd_audigy_i2c_volume_get,
1045536438f1SOswald Buddenhagen 	.put = snd_audigy_i2c_volume_put,
1046536438f1SOswald Buddenhagen 	.tlv = { .p = snd_audigy_db_scale2 }
1047536438f1SOswald Buddenhagen };
1048184c1e2cSJames Courtier-Dutton 
1049536438f1SOswald Buddenhagen static const char * const snd_audigy_i2c_volume_ctls[] = {
1050536438f1SOswald Buddenhagen 	"Mic Capture Volume",
1051536438f1SOswald Buddenhagen 	"Line Capture Volume",
1052184c1e2cSJames Courtier-Dutton };
1053184c1e2cSJames Courtier-Dutton 
10540af68e5eSTakashi Iwai #if 0
1055eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
10561da177e4SLinus Torvalds {
10571541c66dSTakashi Iwai 	static const char * const texts[] = {"44100", "48000", "96000"};
10581da177e4SLinus Torvalds 
10591541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 3, texts);
10601da177e4SLinus Torvalds }
10611da177e4SLinus Torvalds 
1062eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
1063eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10641da177e4SLinus Torvalds {
1065eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10661da177e4SLinus Torvalds 	unsigned int tmp;
10671da177e4SLinus Torvalds 
10681da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
10691da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
10701da177e4SLinus Torvalds 	case A_SPDIF_44100:
10711da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
10721da177e4SLinus Torvalds 		break;
10731da177e4SLinus Torvalds 	case A_SPDIF_48000:
10741da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
10751da177e4SLinus Torvalds 		break;
10761da177e4SLinus Torvalds 	case A_SPDIF_96000:
10771da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
10781da177e4SLinus Torvalds 		break;
10791da177e4SLinus Torvalds 	default:
10801da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
10811da177e4SLinus Torvalds 	}
10821da177e4SLinus Torvalds 	return 0;
10831da177e4SLinus Torvalds }
10841da177e4SLinus Torvalds 
1085eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
1086eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10871da177e4SLinus Torvalds {
1088eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10891da177e4SLinus Torvalds 	int change;
10901da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
10911da177e4SLinus Torvalds 	unsigned long flags;
10921da177e4SLinus Torvalds 
10931da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
10941da177e4SLinus Torvalds 	case 0:
10951da177e4SLinus Torvalds 		val = A_SPDIF_44100;
10961da177e4SLinus Torvalds 		break;
10971da177e4SLinus Torvalds 	case 1:
10981da177e4SLinus Torvalds 		val = A_SPDIF_48000;
10991da177e4SLinus Torvalds 		break;
11001da177e4SLinus Torvalds 	case 2:
11011da177e4SLinus Torvalds 		val = A_SPDIF_96000;
11021da177e4SLinus Torvalds 		break;
11031da177e4SLinus Torvalds 	default:
11041da177e4SLinus Torvalds 		val = A_SPDIF_48000;
11051da177e4SLinus Torvalds 		break;
11061da177e4SLinus Torvalds 	}
11071da177e4SLinus Torvalds 
11081da177e4SLinus Torvalds 
11091da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11101da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
11111da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
11121da177e4SLinus Torvalds 	tmp |= val;
111312bda107STakashi Iwai 	change = (tmp != reg);
111412bda107STakashi Iwai 	if (change)
11151da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
11161da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11171da177e4SLinus Torvalds 	return change;
11181da177e4SLinus Torvalds }
11191da177e4SLinus Torvalds 
1120b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate =
11211da177e4SLinus Torvalds {
11221da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
11231da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
11241da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
11251da177e4SLinus Torvalds 	.count =	1,
11261da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
11271da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
11281da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
11291da177e4SLinus Torvalds };
11300af68e5eSTakashi Iwai #endif
11311da177e4SLinus Torvalds 
1132eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1133eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
11341da177e4SLinus Torvalds {
1135eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11361da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
11371da177e4SLinus Torvalds 	int change;
11381da177e4SLinus Torvalds 	unsigned int val;
11391da177e4SLinus Torvalds 
114074415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
114174415a36SJames Courtier-Dutton 	if (idx >= 3)
114274415a36SJames Courtier-Dutton 		return -EINVAL;
11431da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
11441da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
11451da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
11461da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
11471da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
11481da177e4SLinus Torvalds 	if (change) {
11491da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
11501da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
11511da177e4SLinus Torvalds 	}
11521da177e4SLinus Torvalds 	return change;
11531da177e4SLinus Torvalds }
11541da177e4SLinus Torvalds 
1155f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
11561da177e4SLinus Torvalds {
11571da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
11585549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11591da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
11607583cb51STakashi Iwai 	.count =	3,
11611da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
11621da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
11631da177e4SLinus Torvalds };
11641da177e4SLinus Torvalds 
1165f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
11661da177e4SLinus Torvalds {
11675549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
11681da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
11697583cb51STakashi Iwai 	.count =	3,
11701da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
11711da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
11721da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
11731da177e4SLinus Torvalds };
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds 
1176eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
11771da177e4SLinus Torvalds {
11781da177e4SLinus Torvalds 	if (emu->audigy) {
11791da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
11801da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
11811da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
11821da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
11831da177e4SLinus Torvalds 	} else {
11841da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
11851da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
11861da177e4SLinus Torvalds 	}
11871da177e4SLinus Torvalds }
11881da177e4SLinus Torvalds 
1189eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
11901da177e4SLinus Torvalds {
11911da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
11921da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
11931da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
11941da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
11951da177e4SLinus Torvalds 	if (emu->audigy) {
119651d652f4SOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice,
119751d652f4SOswald Buddenhagen 				      snd_emu10k1_compose_audigy_sendamounts(volume));
11981da177e4SLinus Torvalds 	}
11991da177e4SLinus Torvalds }
12001da177e4SLinus Torvalds 
12011da177e4SLinus Torvalds /* PCM stream controls */
12021da177e4SLinus Torvalds 
1203eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12041da177e4SLinus Torvalds {
1205eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12061da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12071da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
12081da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12091da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
12101da177e4SLinus Torvalds 	return 0;
12111da177e4SLinus Torvalds }
12121da177e4SLinus Torvalds 
1213eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1214eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
12151da177e4SLinus Torvalds {
1216eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1217eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1218eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12191da177e4SLinus Torvalds 	int voice, idx;
12201da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12211da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
12221da177e4SLinus Torvalds 
12231da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
12241da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
12251da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
12261da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
12271da177e4SLinus Torvalds 	return 0;
12281da177e4SLinus Torvalds }
12291da177e4SLinus Torvalds 
1230eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1231eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
12321da177e4SLinus Torvalds {
12331da177e4SLinus Torvalds 	unsigned long flags;
1234eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1235eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1236eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12371da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
12381da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12391da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
12401da177e4SLinus Torvalds 
12411da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12421da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
12431da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
12441da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
12451da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
12461da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
12471da177e4SLinus Torvalds 				change = 1;
12481da177e4SLinus Torvalds 			}
12491da177e4SLinus Torvalds 		}
12501da177e4SLinus Torvalds 	if (change && mix->epcm) {
12511da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
12521da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
12531da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
12541da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
12551da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
12561da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
12571da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
12581da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
12591da177e4SLinus Torvalds 		}
12601da177e4SLinus Torvalds 	}
12611da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12621da177e4SLinus Torvalds 	return change;
12631da177e4SLinus Torvalds }
12641da177e4SLinus Torvalds 
1265f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control =
12661da177e4SLinus Torvalds {
12671da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
126867ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12691da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
12701da177e4SLinus Torvalds 	.count =	32,
12711da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
12721da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
12731da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
12741da177e4SLinus Torvalds };
12751da177e4SLinus Torvalds 
1276eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12771da177e4SLinus Torvalds {
1278eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12791da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12801da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
12811da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12821da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
12831da177e4SLinus Torvalds 	return 0;
12841da177e4SLinus Torvalds }
12851da177e4SLinus Torvalds 
1286eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1287eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12881da177e4SLinus Torvalds {
1289eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1290eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1291eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12921da177e4SLinus Torvalds 	int idx;
12931da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12941da177e4SLinus Torvalds 
12951da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
12961da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
12971da177e4SLinus Torvalds 	return 0;
12981da177e4SLinus Torvalds }
12991da177e4SLinus Torvalds 
1300eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1301eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
13021da177e4SLinus Torvalds {
13031da177e4SLinus Torvalds 	unsigned long flags;
1304eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1305eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1306eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13071da177e4SLinus Torvalds 	int change = 0, idx, val;
13081da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13091da177e4SLinus Torvalds 
13101da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13111da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
13121da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
13131da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
13141da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
13151da177e4SLinus Torvalds 			change = 1;
13161da177e4SLinus Torvalds 		}
13171da177e4SLinus Torvalds 	}
13181da177e4SLinus Torvalds 	if (change && mix->epcm) {
13191da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
13201da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
13211da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
13221da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
13231da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
13241da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
13251da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
13261da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
13271da177e4SLinus Torvalds 		}
13281da177e4SLinus Torvalds 	}
13291da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13301da177e4SLinus Torvalds 	return change;
13311da177e4SLinus Torvalds }
13321da177e4SLinus Torvalds 
1333f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
13341da177e4SLinus Torvalds {
13351da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
133667ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13371da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
13381da177e4SLinus Torvalds 	.count =	32,
13391da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
13401da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
13411da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
13421da177e4SLinus Torvalds };
13431da177e4SLinus Torvalds 
1344eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13451da177e4SLinus Torvalds {
13461da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13471da177e4SLinus Torvalds 	uinfo->count = 3;
13481da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1349bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
13501da177e4SLinus Torvalds 	return 0;
13511da177e4SLinus Torvalds }
13521da177e4SLinus Torvalds 
1353eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1354eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
13551da177e4SLinus Torvalds {
1356eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1357eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1358eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13591da177e4SLinus Torvalds 	int idx;
13601da177e4SLinus Torvalds 
13611da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
1362bcdbd3b7SOswald Buddenhagen 		ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U;
13631da177e4SLinus Torvalds 	return 0;
13641da177e4SLinus Torvalds }
13651da177e4SLinus Torvalds 
1366eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1367eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
13681da177e4SLinus Torvalds {
13691da177e4SLinus Torvalds 	unsigned long flags;
1370eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1371eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1372eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13731da177e4SLinus Torvalds 	int change = 0, idx, val;
13741da177e4SLinus Torvalds 
13751da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13761da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
1377bcdbd3b7SOswald Buddenhagen 		unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff;
1378bcdbd3b7SOswald Buddenhagen 		val = uval * 0x8000U / 0xffffU;
13791da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
13801da177e4SLinus Torvalds 			mix->attn[idx] = val;
13811da177e4SLinus Torvalds 			change = 1;
13821da177e4SLinus Torvalds 		}
13831da177e4SLinus Torvalds 	}
13841da177e4SLinus Torvalds 	if (change && mix->epcm) {
13851da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
13861da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
13871da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
13881da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
13891da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
13901da177e4SLinus Torvalds 		}
13911da177e4SLinus Torvalds 	}
13921da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13931da177e4SLinus Torvalds 	return change;
13941da177e4SLinus Torvalds }
13951da177e4SLinus Torvalds 
1396f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control =
13971da177e4SLinus Torvalds {
13981da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
139967ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14001da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
14011da177e4SLinus Torvalds 	.count =	32,
14021da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
14031da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
14041da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
14051da177e4SLinus Torvalds };
14061da177e4SLinus Torvalds 
14071da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
14081da177e4SLinus Torvalds 
1409eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14101da177e4SLinus Torvalds {
1411eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14121da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14131da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
14141da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14151da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
14161da177e4SLinus Torvalds 	return 0;
14171da177e4SLinus Torvalds }
14181da177e4SLinus Torvalds 
1419eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1420eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14211da177e4SLinus Torvalds {
1422eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1423eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1424eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14251da177e4SLinus Torvalds 	int idx;
14261da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14271da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14281da177e4SLinus Torvalds 
14291da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
14301da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
14311da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
14321da177e4SLinus Torvalds 	return 0;
14331da177e4SLinus Torvalds }
14341da177e4SLinus Torvalds 
1435eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_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);
14401da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1441eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
14421da177e4SLinus Torvalds 	int change = 0, idx, val;
14431da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14441da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14451da177e4SLinus Torvalds 
14461da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14471da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
14481da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
14491da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
14501da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
14511da177e4SLinus Torvalds 			change = 1;
14521da177e4SLinus Torvalds 		}
14531da177e4SLinus Torvalds 	}
14541da177e4SLinus Torvalds 
14551da177e4SLinus Torvalds 	if (change && mix->epcm) {
14561da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
14571da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
14581da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
14591da177e4SLinus Torvalds 		}
14601da177e4SLinus Torvalds 	}
14611da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14621da177e4SLinus Torvalds 	return change;
14631da177e4SLinus Torvalds }
14641da177e4SLinus Torvalds 
1465f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
14661da177e4SLinus Torvalds {
14671da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
14681da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14691da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
14701da177e4SLinus Torvalds 	.count =	16,
14711da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
14721da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
14731da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
14741da177e4SLinus Torvalds };
14751da177e4SLinus Torvalds 
1476eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14771da177e4SLinus Torvalds {
1478eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14791da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14801da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
14811da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14821da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
14831da177e4SLinus Torvalds 	return 0;
14841da177e4SLinus Torvalds }
14851da177e4SLinus Torvalds 
1486eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1487eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
14881da177e4SLinus Torvalds {
1489eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1490eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1491eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14921da177e4SLinus Torvalds 	int idx;
14931da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14941da177e4SLinus Torvalds 
14951da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
14961da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
14971da177e4SLinus Torvalds 	return 0;
14981da177e4SLinus Torvalds }
14991da177e4SLinus Torvalds 
1500eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1501eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
15021da177e4SLinus Torvalds {
15031da177e4SLinus Torvalds 	unsigned long flags;
1504eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15051da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1506eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
15071da177e4SLinus Torvalds 	int change = 0, idx, val;
15081da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15091da177e4SLinus Torvalds 
15101da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15111da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
15121da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
15131da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
15141da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
15151da177e4SLinus Torvalds 			change = 1;
15161da177e4SLinus Torvalds 		}
15171da177e4SLinus Torvalds 	}
15181da177e4SLinus Torvalds 	if (change && mix->epcm) {
15191da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
15201da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
15211da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
15221da177e4SLinus Torvalds 		}
15231da177e4SLinus Torvalds 	}
15241da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15251da177e4SLinus Torvalds 	return change;
15261da177e4SLinus Torvalds }
15271da177e4SLinus Torvalds 
15281da177e4SLinus Torvalds 
1529f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
15301da177e4SLinus Torvalds {
15311da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15321da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15331da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
15341da177e4SLinus Torvalds 	.count =	16,
15351da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
15361da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
15371da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
15381da177e4SLinus Torvalds };
15391da177e4SLinus Torvalds 
1540eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15411da177e4SLinus Torvalds {
15421da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15431da177e4SLinus Torvalds 	uinfo->count = 1;
15441da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1545bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
15461da177e4SLinus Torvalds 	return 0;
15471da177e4SLinus Torvalds }
15481da177e4SLinus Torvalds 
1549eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1550eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
15511da177e4SLinus Torvalds {
1552eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1553eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1554eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15551da177e4SLinus Torvalds 
1556bcdbd3b7SOswald Buddenhagen 	ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U;
15571da177e4SLinus Torvalds 	return 0;
15581da177e4SLinus Torvalds }
15591da177e4SLinus Torvalds 
1560eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1561eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
15621da177e4SLinus Torvalds {
15631da177e4SLinus Torvalds 	unsigned long flags;
1564eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15651da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1566eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
15671da177e4SLinus Torvalds 	int change = 0, val;
1568bcdbd3b7SOswald Buddenhagen 	unsigned uval;
15691da177e4SLinus Torvalds 
15701da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1571bcdbd3b7SOswald Buddenhagen 	uval = ucontrol->value.integer.value[0] & 0x1ffff;
1572bcdbd3b7SOswald Buddenhagen 	val = uval * 0x8000U / 0xffffU;
15731da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
15741da177e4SLinus Torvalds 		mix->attn[0] = val;
15751da177e4SLinus Torvalds 		change = 1;
15761da177e4SLinus Torvalds 	}
15771da177e4SLinus Torvalds 	if (change && mix->epcm) {
15781da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
15791da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
15801da177e4SLinus Torvalds 		}
15811da177e4SLinus Torvalds 	}
15821da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15831da177e4SLinus Torvalds 	return change;
15841da177e4SLinus Torvalds }
15851da177e4SLinus Torvalds 
1586f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
15871da177e4SLinus Torvalds {
15881da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15891da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15901da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
15911da177e4SLinus Torvalds 	.count =	16,
15921da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
15931da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
15941da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
15951da177e4SLinus Torvalds };
15961da177e4SLinus Torvalds 
1597a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
15981da177e4SLinus Torvalds 
1599eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1600eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
16011da177e4SLinus Torvalds {
1602eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
16031da177e4SLinus Torvalds 
16041da177e4SLinus Torvalds 	if (emu->audigy)
1605a1c87c0bSOswald Buddenhagen 		ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
16061da177e4SLinus Torvalds 	else
16071da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1608d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1609d2cd74b1STakashi Iwai 		ucontrol->value.integer.value[0] =
1610d2cd74b1STakashi Iwai 			!ucontrol->value.integer.value[0];
1611d2cd74b1STakashi Iwai 
16121da177e4SLinus Torvalds 	return 0;
16131da177e4SLinus Torvalds }
16141da177e4SLinus Torvalds 
1615eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1616eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
16171da177e4SLinus Torvalds {
16181da177e4SLinus Torvalds 	unsigned long flags;
1619eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1620d2cd74b1STakashi Iwai 	unsigned int reg, val, sw;
16211da177e4SLinus Torvalds 	int change = 0;
16221da177e4SLinus Torvalds 
1623d2cd74b1STakashi Iwai 	sw = ucontrol->value.integer.value[0];
1624d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1625d2cd74b1STakashi Iwai 		sw = !sw;
162650164f69SOswald Buddenhagen 	spin_lock_irqsave(&emu->emu_lock, flags);
1627184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1628184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1629184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
1630a1c87c0bSOswald Buddenhagen 		reg = inw(emu->port + A_IOCFG);
1631d2cd74b1STakashi Iwai 		val = sw ? A_IOCFG_GPOUT0 : 0;
16321da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
16331da177e4SLinus Torvalds 		if (change) {
16341da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
16351da177e4SLinus Torvalds 			reg |= val;
1636a1c87c0bSOswald Buddenhagen 			outw(reg | val, emu->port + A_IOCFG);
16371da177e4SLinus Torvalds 		}
16381da177e4SLinus Torvalds 	}
16391da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
1640d2cd74b1STakashi Iwai 	val = sw ? HCFG_GPOUT0 : 0;
16411da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
16421da177e4SLinus Torvalds 	if (change) {
16431da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
16441da177e4SLinus Torvalds 		reg |= val;
16451da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
16461da177e4SLinus Torvalds 	}
164750164f69SOswald Buddenhagen 	spin_unlock_irqrestore(&emu->emu_lock, flags);
16481da177e4SLinus Torvalds 	return change;
16491da177e4SLinus Torvalds }
16501da177e4SLinus Torvalds 
1651f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
16521da177e4SLinus Torvalds {
16531da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16541da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
16551da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
16561da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
16571da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
16581da177e4SLinus Torvalds };
16591da177e4SLinus Torvalds 
1660f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif =
16611da177e4SLinus Torvalds {
16621da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16631da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
16641da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
16651da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
16661da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
16671da177e4SLinus Torvalds };
16681da177e4SLinus Torvalds 
166916950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
167016950e09STakashi Iwai 
167116950e09STakashi Iwai #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
167216950e09STakashi Iwai 
167316950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
167416950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
167516950e09STakashi Iwai {
167616950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
167716950e09STakashi Iwai 	unsigned int val;
167816950e09STakashi Iwai 
167916950e09STakashi Iwai 	/* FIXME: better to use a cached version */
168016950e09STakashi Iwai 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
168116950e09STakashi Iwai 	ucontrol->value.integer.value[0] = !!val;
168216950e09STakashi Iwai 	return 0;
168316950e09STakashi Iwai }
168416950e09STakashi Iwai 
168516950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
168616950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
168716950e09STakashi Iwai {
168816950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
168916950e09STakashi Iwai 	unsigned int val;
169016950e09STakashi Iwai 
169116950e09STakashi Iwai 	if (ucontrol->value.integer.value[0])
169216950e09STakashi Iwai 		val = 0x0f0f;
169316950e09STakashi Iwai 	else
169416950e09STakashi Iwai 		val = 0;
169516950e09STakashi Iwai 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
169616950e09STakashi Iwai }
169716950e09STakashi Iwai 
1698f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost =
169916950e09STakashi Iwai {
170016950e09STakashi Iwai 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
17012a52feb1SMaciej S. Szmigiero 	.name =		"Mic Extra Boost",
170216950e09STakashi Iwai 	.info =		snd_audigy_capture_boost_info,
170316950e09STakashi Iwai 	.get =		snd_audigy_capture_boost_get,
170416950e09STakashi Iwai 	.put =		snd_audigy_capture_boost_put
170516950e09STakashi Iwai };
170616950e09STakashi Iwai 
170716950e09STakashi Iwai 
17081da177e4SLinus Torvalds /*
17091da177e4SLinus Torvalds  */
1710eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
17111da177e4SLinus Torvalds {
1712eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
17131da177e4SLinus Torvalds 	emu->ac97 = NULL;
17141da177e4SLinus Torvalds }
17151da177e4SLinus Torvalds 
17161da177e4SLinus Torvalds /*
17171da177e4SLinus Torvalds  */
1718eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
17191da177e4SLinus Torvalds {
1720eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
17211da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
17221da177e4SLinus Torvalds 	strcpy(id.name, name);
17231da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
17241da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
17251da177e4SLinus Torvalds }
17261da177e4SLinus Torvalds 
1727eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
17281da177e4SLinus Torvalds {
1729eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
17301da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
17311da177e4SLinus Torvalds 	strcpy(sid.name, name);
17321da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
17331da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
17341da177e4SLinus Torvalds }
17351da177e4SLinus Torvalds 
1736eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
17371da177e4SLinus Torvalds {
1738eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
17391da177e4SLinus Torvalds 	if (kctl) {
174036476b81SMaciej S. Szmigiero 		snd_ctl_rename(card, kctl, dst);
17411da177e4SLinus Torvalds 		return 0;
17421da177e4SLinus Torvalds 	}
17431da177e4SLinus Torvalds 	return -ENOENT;
17441da177e4SLinus Torvalds }
17451da177e4SLinus Torvalds 
1746e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
174767ed4161SClemens Ladisch 		      int pcm_device, int multi_device)
17481da177e4SLinus Torvalds {
1749155e3d3bSOswald Buddenhagen 	int err;
1750eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1751eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
17526fddce26STakashi Iwai 	const char * const *c;
17536fddce26STakashi Iwai 	static const char * const emu10k1_remove_ctls[] = {
17541da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
17551da177e4SLinus Torvalds 		"Master Mono Playback Switch",
17561da177e4SLinus Torvalds 		"Master Mono Playback Volume",
17571da177e4SLinus Torvalds 		"PCM Out Path & Mute",
17581da177e4SLinus Torvalds 		"Mono Output Select",
17591da177e4SLinus Torvalds 		"Surround Playback Switch",
17601da177e4SLinus Torvalds 		"Surround Playback Volume",
17611da177e4SLinus Torvalds 		"Center Playback Switch",
17621da177e4SLinus Torvalds 		"Center Playback Volume",
17631da177e4SLinus Torvalds 		"LFE Playback Switch",
17641da177e4SLinus Torvalds 		"LFE Playback Volume",
17651da177e4SLinus Torvalds 		NULL
17661da177e4SLinus Torvalds 	};
17676fddce26STakashi Iwai 	static const char * const emu10k1_rename_ctls[] = {
17681da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
17691da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
17701da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
17711da177e4SLinus Torvalds 		NULL
17721da177e4SLinus Torvalds 	};
17736fddce26STakashi Iwai 	static const char * const audigy_remove_ctls[] = {
17741da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
177521fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
177621fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
17771da177e4SLinus Torvalds 		"PCM Playback Switch",
17781da177e4SLinus Torvalds 		"PCM Playback Volume",
17791da177e4SLinus Torvalds 		"Master Playback Switch",
17801da177e4SLinus Torvalds 		"Master Playback Volume",
17811da177e4SLinus Torvalds 		"PCM Out Path & Mute",
17821da177e4SLinus Torvalds 		"Mono Output Select",
17831da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
17841da177e4SLinus Torvalds 		"Capture Source",
17851da177e4SLinus Torvalds 		"Capture Switch",
17861da177e4SLinus Torvalds 		"Capture Volume",
17871da177e4SLinus Torvalds 		"Mic Select",
1788274b2000SMaciej S. Szmigiero 		"Headphone Playback Switch",
1789274b2000SMaciej S. Szmigiero 		"Headphone Playback Volume",
1790274b2000SMaciej S. Szmigiero 		"3D Control - Center",
1791274b2000SMaciej S. Szmigiero 		"3D Control - Depth",
1792274b2000SMaciej S. Szmigiero 		"3D Control - Switch",
17931da177e4SLinus Torvalds 		"Video Playback Switch",
17941da177e4SLinus Torvalds 		"Video Playback Volume",
17951da177e4SLinus Torvalds 		"Mic Playback Switch",
17961da177e4SLinus Torvalds 		"Mic Playback Volume",
1797274b2000SMaciej S. Szmigiero 		"External Amplifier",
17981da177e4SLinus Torvalds 		NULL
17991da177e4SLinus Torvalds 	};
18006fddce26STakashi Iwai 	static const char * const audigy_rename_ctls[] = {
18011da177e4SLinus Torvalds 		/* use conventional names */
18021da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
18031da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
18041da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
18051da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
180652051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
180752051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
18081da177e4SLinus Torvalds 		NULL
18091da177e4SLinus Torvalds 	};
18106fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_i2c_adc[] = {
1811184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1812184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1813184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1814184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1815184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1816eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1817184c1e2cSJames Courtier-Dutton 		NULL
1818184c1e2cSJames Courtier-Dutton 	};
18196fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_i2c_adc[] = {
1820184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1821184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1822184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1823184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1824184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1825eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1826184c1e2cSJames Courtier-Dutton 		NULL
1827184c1e2cSJames Courtier-Dutton 	};
18286fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_1361t_adc[] = {
182921fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
183021fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
183121fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
183221fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
183321fdddeaSJames Courtier-Dutton 		"Capture Source",
183421fdddeaSJames Courtier-Dutton 		"Capture Switch",
183521fdddeaSJames Courtier-Dutton 		"Capture Volume",
183621fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
183721fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
183821fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
183921fdddeaSJames Courtier-Dutton 		"3D Control - Center",
184021fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
184121fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
184221fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
184321fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
184421fdddeaSJames Courtier-Dutton 		NULL
184521fdddeaSJames Courtier-Dutton 	};
18466fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_1361t_adc[] = {
184721fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
184821fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
184921fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1850d355c82aSJaroslav Kysela 		"Beep Playback Switch", "Beep Capture Switch",
1851d355c82aSJaroslav Kysela 		"Beep Playback Volume", "Beep Capture Volume",
185221fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
185321fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
185421fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
185521fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
185621fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
185721fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
185821fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
185921fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
186021fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
186121fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
186221fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
186321fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
186452051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
186552051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
186621fdddeaSJames Courtier-Dutton 		NULL
186721fdddeaSJames Courtier-Dutton 	};
18681da177e4SLinus Torvalds 
18692b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1870eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1871eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
187251055da5STakashi Iwai 		static const struct snd_ac97_bus_ops ops = {
18731da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
18741da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
18751da177e4SLinus Torvalds 		};
18761da177e4SLinus Torvalds 
187712bda107STakashi Iwai 		err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus);
187812bda107STakashi Iwai 		if (err < 0)
18791da177e4SLinus Torvalds 			return err;
18801da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
18811da177e4SLinus Torvalds 
18821da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
18831da177e4SLinus Torvalds 		ac97.private_data = emu;
18841da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
18851da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
188612bda107STakashi Iwai 		err = snd_ac97_mixer(pbus, &ac97, &emu->ac97);
188712bda107STakashi Iwai 		if (err < 0) {
1888b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
18891da177e4SLinus Torvalds 				return err;
18906f002b02STakashi Iwai 			dev_info(emu->card->dev,
18916f002b02STakashi Iwai 				 "AC97 is optional on this board\n");
18926f002b02STakashi Iwai 			dev_info(emu->card->dev,
18936f002b02STakashi Iwai 				 "Proceeding without ac97 mixers...\n");
1894b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1895b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1896b1508693STakashi Iwai 		}
18971da177e4SLinus Torvalds 		if (emu->audigy) {
18981da177e4SLinus Torvalds 			/* set master volume to 0 dB */
18994d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
19001da177e4SLinus Torvalds 			/* set capture source to mic */
19014d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
190252051942SMaciej S. Szmigiero 			/* set mono output (TAD) to mic */
190352051942SMaciej S. Szmigiero 			snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE,
190452051942SMaciej S. Szmigiero 				0x0200, 0x0200);
190521fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
190621fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
190721fdddeaSJames Courtier-Dutton 			else
19081da177e4SLinus Torvalds 				c = audigy_remove_ctls;
19091da177e4SLinus Torvalds 		} else {
19101da177e4SLinus Torvalds 			/*
19111da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
19121da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
19131da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
19141da177e4SLinus Torvalds 			 */
19151da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
19161da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
19171da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
19182594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
1919b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Volume");
1920b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Switch");
19211da177e4SLinus Torvalds 			}
19221da177e4SLinus Torvalds 			/* remove unused AC97 controls */
19234d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
19244d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
19251da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
19261da177e4SLinus Torvalds 		}
19271da177e4SLinus Torvalds 		for (; *c; c++)
19281da177e4SLinus Torvalds 			remove_ctl(card, *c);
1929184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1930184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1931184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1932184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
19331da177e4SLinus Torvalds 	} else {
1934f12aa40cSTakashi Iwai 	no_ac97:
19352b637da5SLee Revell 		if (emu->card_capabilities->ecard)
19361da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
19371da177e4SLinus Torvalds 		else if (emu->audigy)
19381da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
19391da177e4SLinus Torvalds 		else
19401da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
19411da177e4SLinus Torvalds 	}
19421da177e4SLinus Torvalds 
19431da177e4SLinus Torvalds 	if (emu->audigy)
194421fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
194521fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1946184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1947184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
194821fdddeaSJames Courtier-Dutton 		else
19491da177e4SLinus Torvalds 			c = audigy_rename_ctls;
19501da177e4SLinus Torvalds 	else
19511da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
19521da177e4SLinus Torvalds 	for (; *c; c += 2)
19531da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
195421fdddeaSJames Courtier-Dutton 
1955e217b960SRaymond Yau 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
1956e217b960SRaymond Yau 		remove_ctl(card, "Center Playback Volume");
1957e217b960SRaymond Yau 		remove_ctl(card, "LFE Playback Volume");
1958e217b960SRaymond Yau 		remove_ctl(card, "Wave Center Playback Volume");
1959e217b960SRaymond Yau 		remove_ctl(card, "Wave LFE Playback Volume");
1960e217b960SRaymond Yau 	}
1961e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1962e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1963e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1964e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1965e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1966e3b9bc0eSJames Courtier-Dutton 	}
196712bda107STakashi Iwai 	kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu);
196812bda107STakashi Iwai 	if (!kctl)
19691da177e4SLinus Torvalds 		return -ENOMEM;
197067ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
197112bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
197212bda107STakashi Iwai 	if (err)
19731da177e4SLinus Torvalds 		return err;
197412bda107STakashi Iwai 	kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu);
197512bda107STakashi Iwai 	if (!kctl)
19761da177e4SLinus Torvalds 		return -ENOMEM;
197767ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
197812bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
197912bda107STakashi Iwai 	if (err)
19801da177e4SLinus Torvalds 		return err;
198112bda107STakashi Iwai 	kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu);
198212bda107STakashi Iwai 	if (!kctl)
19831da177e4SLinus Torvalds 		return -ENOMEM;
198467ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
198512bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
198612bda107STakashi Iwai 	if (err)
19871da177e4SLinus Torvalds 		return err;
19881da177e4SLinus Torvalds 
198912bda107STakashi Iwai 	kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu);
199012bda107STakashi Iwai 	if (!kctl)
19911da177e4SLinus Torvalds 		return -ENOMEM;
199267ed4161SClemens Ladisch 	kctl->id.device = multi_device;
199312bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
199412bda107STakashi Iwai 	if (err)
19951da177e4SLinus Torvalds 		return err;
19961da177e4SLinus Torvalds 
199712bda107STakashi Iwai 	kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu);
199812bda107STakashi Iwai 	if (!kctl)
19991da177e4SLinus Torvalds 		return -ENOMEM;
200067ed4161SClemens Ladisch 	kctl->id.device = multi_device;
200112bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
200212bda107STakashi Iwai 	if (err)
20031da177e4SLinus Torvalds 		return err;
20041da177e4SLinus Torvalds 
200512bda107STakashi Iwai 	kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu);
200612bda107STakashi Iwai 	if (!kctl)
20071da177e4SLinus Torvalds 		return -ENOMEM;
200867ed4161SClemens Ladisch 	kctl->id.device = multi_device;
200912bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
201012bda107STakashi Iwai 	if (err)
20111da177e4SLinus Torvalds 		return err;
20121da177e4SLinus Torvalds 
2013a8661af5SOswald Buddenhagen 	if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) {
20141da177e4SLinus Torvalds 		/* sb live! and audigy */
201512bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu);
201612bda107STakashi Iwai 		if (!kctl)
20171da177e4SLinus Torvalds 			return -ENOMEM;
20185549d549SClemens Ladisch 		if (!emu->audigy)
20195549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
202012bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
202112bda107STakashi Iwai 		if (err)
20221da177e4SLinus Torvalds 			return err;
202312bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu);
202412bda107STakashi Iwai 		if (!kctl)
20251da177e4SLinus Torvalds 			return -ENOMEM;
20265549d549SClemens Ladisch 		if (!emu->audigy)
20275549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
202812bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
202912bda107STakashi Iwai 		if (err)
20301da177e4SLinus Torvalds 			return err;
20311da177e4SLinus Torvalds 	}
20321da177e4SLinus Torvalds 
2033190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
203419b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
203519b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
203612bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu);
203712bda107STakashi Iwai 		if (!kctl)
20381da177e4SLinus Torvalds 			return -ENOMEM;
203912bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
204012bda107STakashi Iwai 		if (err)
20411da177e4SLinus Torvalds 			return err;
2042001f7589SJames Courtier-Dutton #if 0
204312bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu);
204412bda107STakashi Iwai 		if (!kctl)
20451da177e4SLinus Torvalds 			return -ENOMEM;
204612bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
204712bda107STakashi Iwai 		if (err)
20481da177e4SLinus Torvalds 			return err;
2049001f7589SJames Courtier-Dutton #endif
20502b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
20511da177e4SLinus Torvalds 		/* sb live! */
205212bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu);
205312bda107STakashi Iwai 		if (!kctl)
20541da177e4SLinus Torvalds 			return -ENOMEM;
205512bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
205612bda107STakashi Iwai 		if (err)
20571da177e4SLinus Torvalds 			return err;
20581da177e4SLinus Torvalds 	}
20592b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
206012bda107STakashi Iwai 		err = snd_p16v_mixer(emu);
206112bda107STakashi Iwai 		if (err)
20621da177e4SLinus Torvalds 			return err;
20631da177e4SLinus Torvalds 	}
20641da177e4SLinus Torvalds 
2065*1fc710f0SOswald Buddenhagen 	if (emu->card_capabilities->emu_model) {
2066*1fc710f0SOswald Buddenhagen 		unsigned i, emu_idx = emu1010_idx(emu);
2067*1fc710f0SOswald Buddenhagen 		const struct snd_emu1010_routing_info *emu_ri =
2068*1fc710f0SOswald Buddenhagen 			&emu1010_routing_info[emu_idx];
2069*1fc710f0SOswald Buddenhagen 
2070*1fc710f0SOswald Buddenhagen 		for (i = 0; i < emu_ri->n_ins; i++)
2071*1fc710f0SOswald Buddenhagen 			emu->emu1010.input_source[i] =
2072*1fc710f0SOswald Buddenhagen 				emu1010_map_source(emu_ri, emu_ri->in_dflts[i]);
2073*1fc710f0SOswald Buddenhagen 		for (i = 0; i < emu_ri->n_outs; i++)
2074*1fc710f0SOswald Buddenhagen 			emu->emu1010.output_source[i] =
2075*1fc710f0SOswald Buddenhagen 				emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
2076*1fc710f0SOswald Buddenhagen 		snd_emu1010_apply_sources(emu);
2077*1fc710f0SOswald Buddenhagen 	}
2078*1fc710f0SOswald Buddenhagen 
20793839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
20801c02e366SCtirad Fertr 		/* 1616(m) cardbus */
2081536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_output_source_ctl,
2082536438f1SOswald Buddenhagen 			       snd_emu1616_output_texts,
2083536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1616_output_texts));
20849f4bd5ddSJames Courtier-Dutton 		if (err < 0)
20859f4bd5ddSJames Courtier-Dutton 			return err;
2086536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_input_source_ctl,
2087536438f1SOswald Buddenhagen 			       emu1010_input_texts,
2088536438f1SOswald Buddenhagen 			       ARRAY_SIZE(emu1010_input_texts));
20891c02e366SCtirad Fertr 		if (err < 0)
20901c02e366SCtirad Fertr 			return err;
2091536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_adc_pads_ctl,
2092536438f1SOswald Buddenhagen 			       snd_emu1010_adc_pads,
2093536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1010_adc_pads) - 2);
20941c02e366SCtirad Fertr 		if (err < 0)
20951c02e366SCtirad Fertr 			return err;
2096536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_dac_pads_ctl,
2097536438f1SOswald Buddenhagen 			       snd_emu1010_dac_pads,
2098536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1010_dac_pads) - 2);
20991c02e366SCtirad Fertr 		if (err < 0)
21001c02e366SCtirad Fertr 			return err;
21011c02e366SCtirad Fertr 		err = snd_ctl_add(card,
21021c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
21031c02e366SCtirad Fertr 		if (err < 0)
21041c02e366SCtirad Fertr 			return err;
210599dcab46SMichael Gernoth 		err = snd_ctl_add(card,
210699dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
210799dcab46SMichael Gernoth 		if (err < 0)
210899dcab46SMichael Gernoth 			return err;
210999dcab46SMichael Gernoth 		err = snd_ctl_add(card,
211099dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
211199dcab46SMichael Gernoth 		if (err < 0)
211299dcab46SMichael Gernoth 			return err;
21131c02e366SCtirad Fertr 
211488aa1390STakashi Iwai 	} else if (emu->card_capabilities->emu_model) {
21151c02e366SCtirad Fertr 		/* all other e-mu cards for now */
2116536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_output_source_ctl,
2117536438f1SOswald Buddenhagen 			       emu1010_output_texts,
2118536438f1SOswald Buddenhagen 			       ARRAY_SIZE(emu1010_output_texts));
21191c02e366SCtirad Fertr 		if (err < 0)
21201c02e366SCtirad Fertr 			return err;
2121536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_input_source_ctl,
2122536438f1SOswald Buddenhagen 			       emu1010_input_texts,
2123536438f1SOswald Buddenhagen 			       ARRAY_SIZE(emu1010_input_texts));
21249f4bd5ddSJames Courtier-Dutton 		if (err < 0)
21259f4bd5ddSJames Courtier-Dutton 			return err;
2126536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_adc_pads_ctl,
2127536438f1SOswald Buddenhagen 			       snd_emu1010_adc_pads,
2128536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1010_adc_pads));
21299148cc50SJames Courtier-Dutton 		if (err < 0)
21309148cc50SJames Courtier-Dutton 			return err;
2131536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_dac_pads_ctl,
2132536438f1SOswald Buddenhagen 			       snd_emu1010_dac_pads,
2133536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1010_dac_pads));
21349148cc50SJames Courtier-Dutton 		if (err < 0)
21359148cc50SJames Courtier-Dutton 			return err;
21361c02e366SCtirad Fertr 		err = snd_ctl_add(card,
21371c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
2138b0dbdaeaSJames Courtier-Dutton 		if (err < 0)
2139b0dbdaeaSJames Courtier-Dutton 			return err;
214099dcab46SMichael Gernoth 		err = snd_ctl_add(card,
214199dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
214299dcab46SMichael Gernoth 		if (err < 0)
214399dcab46SMichael Gernoth 			return err;
214499dcab46SMichael Gernoth 		err = snd_ctl_add(card,
214599dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
214699dcab46SMichael Gernoth 		if (err < 0)
214799dcab46SMichael Gernoth 			return err;
21489f4bd5ddSJames Courtier-Dutton 	}
21499f4bd5ddSJames Courtier-Dutton 
2150184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2151184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2152184c1e2cSJames Courtier-Dutton 		if (err < 0)
2153184c1e2cSJames Courtier-Dutton 			return err;
2154184c1e2cSJames Courtier-Dutton 
2155536438f1SOswald Buddenhagen 		err = add_ctls(emu, &i2c_volume_ctl,
2156536438f1SOswald Buddenhagen 			       snd_audigy_i2c_volume_ctls,
2157536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_audigy_i2c_volume_ctls));
2158184c1e2cSJames Courtier-Dutton 		if (err < 0)
2159184c1e2cSJames Courtier-Dutton 			return err;
2160184c1e2cSJames Courtier-Dutton 	}
2161184c1e2cSJames Courtier-Dutton 
216216950e09STakashi Iwai 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
216316950e09STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
216416950e09STakashi Iwai 						     emu));
216516950e09STakashi Iwai 		if (err < 0)
216616950e09STakashi Iwai 			return err;
216716950e09STakashi Iwai 	}
216816950e09STakashi Iwai 
21691da177e4SLinus Torvalds 	return 0;
21701da177e4SLinus Torvalds }
2171