xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision 97f1582e92c91e77bcf4af3dbf445c6694eb2dff)
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 
2341fc710f0SOswald Buddenhagen static const unsigned short emu1010_output_dflt[] = {
2351fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2361fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
2371fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
2381fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
2391fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2401fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2411fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2421fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2431fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
2441fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
2451fc710f0SOswald Buddenhagen };
2461fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dflt) == ARRAY_SIZE(emu1010_output_dst));
2471fc710f0SOswald 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 
2691fc710f0SOswald Buddenhagen static const unsigned short emu1616_output_dflt[] = {
2701fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2711fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
2721fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5,
2731fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2741fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3,
2751fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7,
2761fc710f0SOswald Buddenhagen 	EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1,
2771fc710f0SOswald Buddenhagen };
2781fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dflt) == ARRAY_SIZE(emu1616_output_dst));
2791fc710f0SOswald 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 
3391fc710f0SOswald Buddenhagen static const unsigned short emu1010_input_dflt[] = {
3401fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_A1,
3411fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_B1,
3421fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
3431fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
3441fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
3451fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
3461fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
3471fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
3481fc710f0SOswald Buddenhagen 	/* Pavel Hofman - setting defaults for all capture channels.
3491fc710f0SOswald Buddenhagen 	 * Defaults only, users will set their own values anyways, let's
3501fc710f0SOswald Buddenhagen 	 * just copy/paste. */
3511fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_A1,
3521fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_MIC_B1,
3531fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_LEFT1,
3541fc710f0SOswald Buddenhagen 	EMU_SRC_HAMOA_ADC_RIGHT1,
3551fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
3561fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
3571fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
3581fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
3591fc710f0SOswald Buddenhagen 
3601fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_LEFT1,
3611fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC1_RIGHT1,
3621fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_LEFT1,
3631fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC2_RIGHT1,
3641fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC3_LEFT1,
3651fc710f0SOswald Buddenhagen 	EMU_SRC_DOCK_ADC3_RIGHT1,
3661fc710f0SOswald Buddenhagen };
3671fc710f0SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dflt) == ARRAY_SIZE(emu1010_input_dst));
3681fc710f0SOswald Buddenhagen 
369511cbe8fSOswald Buddenhagen struct snd_emu1010_routing_info {
370511cbe8fSOswald Buddenhagen 	const char * const *src_texts;
371*97f1582eSOswald Buddenhagen 	const char * const *out_texts;
372511cbe8fSOswald Buddenhagen 	const unsigned short *src_regs;
373511cbe8fSOswald Buddenhagen 	const unsigned short *out_regs;
374511cbe8fSOswald Buddenhagen 	const unsigned short *in_regs;
3751fc710f0SOswald Buddenhagen 	const unsigned short *out_dflts;
3761fc710f0SOswald Buddenhagen 	const unsigned short *in_dflts;
377511cbe8fSOswald Buddenhagen 	unsigned n_srcs;
378511cbe8fSOswald Buddenhagen 	unsigned n_outs;
379511cbe8fSOswald Buddenhagen 	unsigned n_ins;
380511cbe8fSOswald Buddenhagen };
381511cbe8fSOswald Buddenhagen 
382511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info emu1010_routing_info[] = {
383511cbe8fSOswald Buddenhagen 	{
384511cbe8fSOswald Buddenhagen 		.src_regs = emu1010_src_regs,
385511cbe8fSOswald Buddenhagen 		.src_texts = emu1010_src_texts,
386511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1010_src_texts),
387511cbe8fSOswald Buddenhagen 
3881fc710f0SOswald Buddenhagen 		.out_dflts = emu1010_output_dflt,
389511cbe8fSOswald Buddenhagen 		.out_regs = emu1010_output_dst,
390*97f1582eSOswald Buddenhagen 		.out_texts = emu1010_output_texts,
391511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1010_output_dst),
392511cbe8fSOswald Buddenhagen 
3931fc710f0SOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
394511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
395511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst),
396511cbe8fSOswald Buddenhagen 	},
397511cbe8fSOswald Buddenhagen 	{
398511cbe8fSOswald Buddenhagen 		/* 1616(m) cardbus */
399511cbe8fSOswald Buddenhagen 		.src_regs = emu1616_src_regs,
400511cbe8fSOswald Buddenhagen 		.src_texts = emu1616_src_texts,
401511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1616_src_texts),
402511cbe8fSOswald Buddenhagen 
4031fc710f0SOswald Buddenhagen 		.out_dflts = emu1616_output_dflt,
404511cbe8fSOswald Buddenhagen 		.out_regs = emu1616_output_dst,
405*97f1582eSOswald Buddenhagen 		.out_texts = snd_emu1616_output_texts,
406511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1616_output_dst),
407511cbe8fSOswald Buddenhagen 
4081fc710f0SOswald Buddenhagen 		.in_dflts = emu1010_input_dflt,
409511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
410511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
411511cbe8fSOswald Buddenhagen 	},
412511cbe8fSOswald Buddenhagen };
413511cbe8fSOswald Buddenhagen 
414511cbe8fSOswald Buddenhagen static unsigned emu1010_idx(struct snd_emu10k1 *emu)
415511cbe8fSOswald Buddenhagen {
416511cbe8fSOswald Buddenhagen 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
417511cbe8fSOswald Buddenhagen 		return 1;
418511cbe8fSOswald Buddenhagen 	else
419511cbe8fSOswald Buddenhagen 		return 0;
420511cbe8fSOswald Buddenhagen }
421511cbe8fSOswald Buddenhagen 
422511cbe8fSOswald Buddenhagen static void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu,
423511cbe8fSOswald Buddenhagen 					    int channel, int src)
424511cbe8fSOswald Buddenhagen {
425511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
426511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
427511cbe8fSOswald Buddenhagen 
428511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
429511cbe8fSOswald Buddenhagen 		emu_ri->out_regs[channel], emu_ri->src_regs[src]);
430511cbe8fSOswald Buddenhagen }
431511cbe8fSOswald Buddenhagen 
432511cbe8fSOswald Buddenhagen static void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu,
433511cbe8fSOswald Buddenhagen 					   int channel, int src)
434511cbe8fSOswald Buddenhagen {
435511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
436511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
437511cbe8fSOswald Buddenhagen 
438511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
439511cbe8fSOswald Buddenhagen 		emu_ri->in_regs[channel], emu_ri->src_regs[src]);
440511cbe8fSOswald Buddenhagen }
441511cbe8fSOswald Buddenhagen 
4421fc710f0SOswald Buddenhagen static void snd_emu1010_apply_sources(struct snd_emu10k1 *emu)
4431fc710f0SOswald Buddenhagen {
4441fc710f0SOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
4451fc710f0SOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
4461fc710f0SOswald Buddenhagen 
4471fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_outs; i++)
4481fc710f0SOswald Buddenhagen 		snd_emu1010_output_source_apply(
4491fc710f0SOswald Buddenhagen 			emu, i, emu->emu1010.output_source[i]);
4501fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_ins; i++)
4511fc710f0SOswald Buddenhagen 		snd_emu1010_input_source_apply(
4521fc710f0SOswald Buddenhagen 			emu, i, emu->emu1010.input_source[i]);
4531fc710f0SOswald Buddenhagen }
4541fc710f0SOswald Buddenhagen 
4551fc710f0SOswald Buddenhagen static u8 emu1010_map_source(const struct snd_emu1010_routing_info *emu_ri,
4561fc710f0SOswald Buddenhagen 			     unsigned val)
4571fc710f0SOswald Buddenhagen {
4581fc710f0SOswald Buddenhagen 	for (unsigned i = 0; i < emu_ri->n_srcs; i++)
4591fc710f0SOswald Buddenhagen 		if (val == emu_ri->src_regs[i])
4601fc710f0SOswald Buddenhagen 			return i;
4611fc710f0SOswald Buddenhagen 	return 0;
4621fc710f0SOswald Buddenhagen }
4631fc710f0SOswald Buddenhagen 
4641c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
4651c02e366SCtirad Fertr 						struct snd_ctl_elem_info *uinfo)
4669f4bd5ddSJames Courtier-Dutton {
4671c02e366SCtirad Fertr 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
468511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
469511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
4701c02e366SCtirad Fertr 
471511cbe8fSOswald Buddenhagen 	return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts);
4729f4bd5ddSJames Courtier-Dutton }
4739f4bd5ddSJames Courtier-Dutton 
4749f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
4759f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4769f4bd5ddSJames Courtier-Dutton {
4779f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
478511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
479511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
480511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
4819f4bd5ddSJames Courtier-Dutton 
482511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
48374415a36SJames Courtier-Dutton 		return -EINVAL;
4849f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
4859f4bd5ddSJames Courtier-Dutton 	return 0;
4869f4bd5ddSJames Courtier-Dutton }
4879f4bd5ddSJames Courtier-Dutton 
4889f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
4899f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4909f4bd5ddSJames Courtier-Dutton {
4919f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
492511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
493511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
494511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
495511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
496511cbe8fSOswald Buddenhagen 	int change;
4979f4bd5ddSJames Courtier-Dutton 
498511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
499aa299d01STakashi Iwai 		return -EINVAL;
500511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
50174415a36SJames Courtier-Dutton 		return -EINVAL;
502511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.output_source[channel] != val);
503511cbe8fSOswald Buddenhagen 	if (change) {
504aa299d01STakashi Iwai 		emu->emu1010.output_source[channel] = val;
505511cbe8fSOswald Buddenhagen 		snd_emu1010_output_source_apply(emu, channel, val);
506511cbe8fSOswald Buddenhagen 	}
507511cbe8fSOswald Buddenhagen 	return change;
5089f4bd5ddSJames Courtier-Dutton }
5099f4bd5ddSJames Courtier-Dutton 
510536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_output_source_ctl = {
511536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
512536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
513536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
514536438f1SOswald Buddenhagen 	.get = snd_emu1010_output_source_get,
515536438f1SOswald Buddenhagen 	.put = snd_emu1010_output_source_put
516536438f1SOswald Buddenhagen };
517536438f1SOswald Buddenhagen 
5189f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
5199f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
5209f4bd5ddSJames Courtier-Dutton {
5219f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
522511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
523511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
524511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
5259f4bd5ddSJames Courtier-Dutton 
526511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
52774415a36SJames Courtier-Dutton 		return -EINVAL;
5289f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
5299f4bd5ddSJames Courtier-Dutton 	return 0;
5309f4bd5ddSJames Courtier-Dutton }
5319f4bd5ddSJames Courtier-Dutton 
5329f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
5339f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
5349f4bd5ddSJames Courtier-Dutton {
5359f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
536511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
537511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
538511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
539511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
540511cbe8fSOswald Buddenhagen 	int change;
5419f4bd5ddSJames Courtier-Dutton 
542511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
543aa299d01STakashi Iwai 		return -EINVAL;
544511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
54574415a36SJames Courtier-Dutton 		return -EINVAL;
546511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.input_source[channel] != val);
547511cbe8fSOswald Buddenhagen 	if (change) {
548aa299d01STakashi Iwai 		emu->emu1010.input_source[channel] = val;
549511cbe8fSOswald Buddenhagen 		snd_emu1010_input_source_apply(emu, channel, val);
550511cbe8fSOswald Buddenhagen 	}
551511cbe8fSOswald Buddenhagen 	return change;
5529f4bd5ddSJames Courtier-Dutton }
5539f4bd5ddSJames Courtier-Dutton 
554536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_input_source_ctl = {
555536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
556536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
557536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
558536438f1SOswald Buddenhagen 	.get = snd_emu1010_input_source_get,
559536438f1SOswald Buddenhagen 	.put = snd_emu1010_input_source_put
5609f4bd5ddSJames Courtier-Dutton };
5619f4bd5ddSJames Courtier-Dutton 
562*97f1582eSOswald Buddenhagen static int add_emu1010_source_mixers(struct snd_emu10k1 *emu)
563*97f1582eSOswald Buddenhagen {
564*97f1582eSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
565*97f1582eSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
566*97f1582eSOswald Buddenhagen 	int err;
567*97f1582eSOswald Buddenhagen 
568*97f1582eSOswald Buddenhagen 	err = add_ctls(emu, &emu1010_output_source_ctl,
569*97f1582eSOswald Buddenhagen 		       emu_ri->out_texts, emu_ri->n_outs);
570*97f1582eSOswald Buddenhagen 	if (err < 0)
571*97f1582eSOswald Buddenhagen 		return err;
572*97f1582eSOswald Buddenhagen 	err = add_ctls(emu, &emu1010_input_source_ctl,
573*97f1582eSOswald Buddenhagen 		       emu1010_input_texts, emu_ri->n_ins);
574*97f1582eSOswald Buddenhagen 	return err;
575*97f1582eSOswald Buddenhagen }
576*97f1582eSOswald Buddenhagen 
5771c02e366SCtirad Fertr 
578536438f1SOswald Buddenhagen static const char * const snd_emu1010_adc_pads[] = {
579536438f1SOswald Buddenhagen 	"ADC1 14dB PAD Audio Dock Capture Switch",
580536438f1SOswald Buddenhagen 	"ADC2 14dB PAD Audio Dock Capture Switch",
581536438f1SOswald Buddenhagen 	"ADC3 14dB PAD Audio Dock Capture Switch",
582536438f1SOswald Buddenhagen 	"ADC1 14dB PAD 0202 Capture Switch",
5831c02e366SCtirad Fertr };
5841c02e366SCtirad Fertr 
585536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_adc_pad_regs[] = {
586536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD1,
587536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD2,
588536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD3,
589536438f1SOswald Buddenhagen 	EMU_HANA_0202_ADC_PAD1,
5909148cc50SJames Courtier-Dutton };
5919148cc50SJames Courtier-Dutton 
592a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
5939148cc50SJames Courtier-Dutton 
5949148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5959148cc50SJames Courtier-Dutton {
5969148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
597536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
598536438f1SOswald Buddenhagen 
5999148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
6009148cc50SJames Courtier-Dutton 	return 0;
6019148cc50SJames Courtier-Dutton }
6029148cc50SJames Courtier-Dutton 
6039148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6049148cc50SJames Courtier-Dutton {
6059148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
606536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
6079148cc50SJames Courtier-Dutton 	unsigned int val, cache;
6089148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
6099148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
6109148cc50SJames Courtier-Dutton 	if (val == 1)
6119148cc50SJames Courtier-Dutton 		cache = cache | mask;
6129148cc50SJames Courtier-Dutton 	else
6139148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
6149148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
6159148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
6169148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
6179148cc50SJames Courtier-Dutton 	}
6189148cc50SJames Courtier-Dutton 
6199148cc50SJames Courtier-Dutton 	return 0;
6209148cc50SJames Courtier-Dutton }
6219148cc50SJames Courtier-Dutton 
622536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_adc_pads_ctl = {
623536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
624536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
625536438f1SOswald Buddenhagen 	.info = snd_emu1010_adc_pads_info,
626536438f1SOswald Buddenhagen 	.get = snd_emu1010_adc_pads_get,
627536438f1SOswald Buddenhagen 	.put = snd_emu1010_adc_pads_put
628536438f1SOswald Buddenhagen };
6299148cc50SJames Courtier-Dutton 
6309148cc50SJames Courtier-Dutton 
631536438f1SOswald Buddenhagen static const char * const snd_emu1010_dac_pads[] = {
632536438f1SOswald Buddenhagen 	"DAC1 Audio Dock 14dB PAD Playback Switch",
633536438f1SOswald Buddenhagen 	"DAC2 Audio Dock 14dB PAD Playback Switch",
634536438f1SOswald Buddenhagen 	"DAC3 Audio Dock 14dB PAD Playback Switch",
635536438f1SOswald Buddenhagen 	"DAC4 Audio Dock 14dB PAD Playback Switch",
636536438f1SOswald Buddenhagen 	"DAC1 0202 14dB PAD Playback Switch",
637536438f1SOswald Buddenhagen };
6389148cc50SJames Courtier-Dutton 
639536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_dac_regs[] = {
640536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD1,
641536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD2,
642536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD3,
643536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD4,
644536438f1SOswald Buddenhagen 	EMU_HANA_0202_DAC_PAD1,
6459148cc50SJames Courtier-Dutton };
6469148cc50SJames Courtier-Dutton 
647a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
6489148cc50SJames Courtier-Dutton 
6499148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6509148cc50SJames Courtier-Dutton {
6519148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
652536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
653536438f1SOswald Buddenhagen 
6549148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
6559148cc50SJames Courtier-Dutton 	return 0;
6569148cc50SJames Courtier-Dutton }
6579148cc50SJames Courtier-Dutton 
6589148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6599148cc50SJames Courtier-Dutton {
6609148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
661536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
6629148cc50SJames Courtier-Dutton 	unsigned int val, cache;
663cc766807SOswald Buddenhagen 	int change;
664cc766807SOswald Buddenhagen 
6659148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
6669148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
6679148cc50SJames Courtier-Dutton 	if (val == 1)
6689148cc50SJames Courtier-Dutton 		cache = cache | mask;
6699148cc50SJames Courtier-Dutton 	else
6709148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
671cc766807SOswald Buddenhagen 	change = (cache != emu->emu1010.dac_pads);
672cc766807SOswald Buddenhagen 	if (change) {
6739148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
6749148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
6759148cc50SJames Courtier-Dutton 	}
6769148cc50SJames Courtier-Dutton 
677cc766807SOswald Buddenhagen 	return change;
6789148cc50SJames Courtier-Dutton }
6799148cc50SJames Courtier-Dutton 
680536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_dac_pads_ctl = {
681536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
682536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
683536438f1SOswald Buddenhagen 	.info = snd_emu1010_dac_pads_info,
684536438f1SOswald Buddenhagen 	.get = snd_emu1010_dac_pads_get,
685536438f1SOswald Buddenhagen 	.put = snd_emu1010_dac_pads_put
6869f4bd5ddSJames Courtier-Dutton };
6879f4bd5ddSJames Courtier-Dutton 
688b0dbdaeaSJames Courtier-Dutton 
689*97f1582eSOswald Buddenhagen struct snd_emu1010_pads_info {
690*97f1582eSOswald Buddenhagen 	const char * const *adc_ctls, * const *dac_ctls;
691*97f1582eSOswald Buddenhagen 	unsigned n_adc_ctls, n_dac_ctls;
692*97f1582eSOswald Buddenhagen };
693*97f1582eSOswald Buddenhagen 
694*97f1582eSOswald Buddenhagen const struct snd_emu1010_pads_info emu1010_pads_info[] = {
695*97f1582eSOswald Buddenhagen 	{
696*97f1582eSOswald Buddenhagen 		/* all other e-mu cards for now */
697*97f1582eSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads,
698*97f1582eSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads),
699*97f1582eSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads,
700*97f1582eSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads),
701*97f1582eSOswald Buddenhagen 	},
702*97f1582eSOswald Buddenhagen 	{
703*97f1582eSOswald Buddenhagen 		/* 1616(m) cardbus */
704*97f1582eSOswald Buddenhagen 		.adc_ctls = snd_emu1010_adc_pads,
705*97f1582eSOswald Buddenhagen 		.n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 2,
706*97f1582eSOswald Buddenhagen 		.dac_ctls = snd_emu1010_dac_pads,
707*97f1582eSOswald Buddenhagen 		.n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 2,
708*97f1582eSOswald Buddenhagen 	},
709*97f1582eSOswald Buddenhagen };
710*97f1582eSOswald Buddenhagen 
711*97f1582eSOswald Buddenhagen 
712b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
713b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
714b0dbdaeaSJames Courtier-Dutton {
7151541c66dSTakashi Iwai 	static const char * const texts[4] = {
716edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
717b0dbdaeaSJames Courtier-Dutton 	};
718b0dbdaeaSJames Courtier-Dutton 
7191541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 4, texts);
720b0dbdaeaSJames Courtier-Dutton }
721b0dbdaeaSJames Courtier-Dutton 
722b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
723b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
724b0dbdaeaSJames Courtier-Dutton {
725b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
726b0dbdaeaSJames Courtier-Dutton 
727b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
728b0dbdaeaSJames Courtier-Dutton 	return 0;
729b0dbdaeaSJames Courtier-Dutton }
730b0dbdaeaSJames Courtier-Dutton 
731b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
732b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
733b0dbdaeaSJames Courtier-Dutton {
734b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
735b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
736b0dbdaeaSJames Courtier-Dutton 	int change = 0;
737b0dbdaeaSJames Courtier-Dutton 
738b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
73974415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 4; */
74074415a36SJames Courtier-Dutton 	if (val >= 4)
74174415a36SJames Courtier-Dutton 		return -EINVAL;
742b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
743b0dbdaeaSJames Courtier-Dutton 	if (change) {
744b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
745b0dbdaeaSJames Courtier-Dutton 		switch (val) {
746b0dbdaeaSJames Courtier-Dutton 		case 0:
747b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
748b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
749b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
750a869057cSOswald Buddenhagen 			/* Default fallback clock 44.1kHz */
751b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
752b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
753b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
754b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
755b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
756b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
757b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
758b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
759e40a0b2eSJames Courtier-Dutton 			msleep(10);
760b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
761b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
762b0dbdaeaSJames Courtier-Dutton 			break;
763b0dbdaeaSJames Courtier-Dutton 		case 1:
764b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
765b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
766b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
767b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
768b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
769b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
770b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
771b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
772b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
773b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
774b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
775b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
776e40a0b2eSJames Courtier-Dutton 			msleep(10);
777b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
778b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
779b0dbdaeaSJames Courtier-Dutton 			break;
780edec7bbbSJames Courtier-Dutton 
781edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
782edec7bbbSJames Courtier-Dutton 			/* Mute all */
783edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
784edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
785edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
786edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
787edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
788edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
789edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
790edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
791edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
792edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
793edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
794edec7bbbSJames Courtier-Dutton 			msleep(10);
795edec7bbbSJames Courtier-Dutton 			/* Unmute all */
796edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
797edec7bbbSJames Courtier-Dutton 			break;
798edec7bbbSJames Courtier-Dutton 
799edec7bbbSJames Courtier-Dutton 		case 3:
800edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
801edec7bbbSJames Courtier-Dutton 			/* Mute all */
802edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
803edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
804edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
805edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
806edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
807edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
808edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
809edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
810edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
811edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
812edec7bbbSJames Courtier-Dutton 			msleep(10);
813edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
814edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
815edec7bbbSJames Courtier-Dutton 
816edec7bbbSJames Courtier-Dutton 
817edec7bbbSJames Courtier-Dutton 			break;
818b0dbdaeaSJames Courtier-Dutton 		}
819b0dbdaeaSJames Courtier-Dutton 	}
820b0dbdaeaSJames Courtier-Dutton         return change;
821b0dbdaeaSJames Courtier-Dutton }
822b0dbdaeaSJames Courtier-Dutton 
823f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock =
824b0dbdaeaSJames Courtier-Dutton {
825b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
826b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
827b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
828b0dbdaeaSJames Courtier-Dutton 	.count =	1,
829b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
830b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
831b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
832b0dbdaeaSJames Courtier-Dutton };
833b0dbdaeaSJames Courtier-Dutton 
83499dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
83599dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
83699dcab46SMichael Gernoth {
83799dcab46SMichael Gernoth 	static const char * const texts[2] = {
83899dcab46SMichael Gernoth 		"SPDIF", "ADAT"
83999dcab46SMichael Gernoth 	};
84099dcab46SMichael Gernoth 
84199dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
84299dcab46SMichael Gernoth }
84399dcab46SMichael Gernoth 
84499dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol,
84599dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
84699dcab46SMichael Gernoth {
84799dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
84899dcab46SMichael Gernoth 
84999dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out;
85099dcab46SMichael Gernoth 	return 0;
85199dcab46SMichael Gernoth }
85299dcab46SMichael Gernoth 
85399dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
85499dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
85599dcab46SMichael Gernoth {
85699dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
85799dcab46SMichael Gernoth 	unsigned int val;
85899dcab46SMichael Gernoth 	u32 tmp;
85999dcab46SMichael Gernoth 	int change = 0;
86099dcab46SMichael Gernoth 
86199dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
86299dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
86399dcab46SMichael Gernoth 	if (val >= 2)
86499dcab46SMichael Gernoth 		return -EINVAL;
86599dcab46SMichael Gernoth 	change = (emu->emu1010.optical_out != val);
86699dcab46SMichael Gernoth 	if (change) {
86799dcab46SMichael Gernoth 		emu->emu1010.optical_out = val;
8689d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
8699d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
87099dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
87199dcab46SMichael Gernoth 	}
87299dcab46SMichael Gernoth 	return change;
87399dcab46SMichael Gernoth }
87499dcab46SMichael Gernoth 
875f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = {
87699dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
87799dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
87899dcab46SMichael Gernoth 	.name =         "Optical Output Mode",
87999dcab46SMichael Gernoth 	.count =	1,
88099dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_out_info,
88199dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_out_get,
88299dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_out_put
88399dcab46SMichael Gernoth };
88499dcab46SMichael Gernoth 
88599dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
88699dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
88799dcab46SMichael Gernoth {
88899dcab46SMichael Gernoth 	static const char * const texts[2] = {
88999dcab46SMichael Gernoth 		"SPDIF", "ADAT"
89099dcab46SMichael Gernoth 	};
89199dcab46SMichael Gernoth 
89299dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
89399dcab46SMichael Gernoth }
89499dcab46SMichael Gernoth 
89599dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
89699dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
89799dcab46SMichael Gernoth {
89899dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
89999dcab46SMichael Gernoth 
90099dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
90199dcab46SMichael Gernoth 	return 0;
90299dcab46SMichael Gernoth }
90399dcab46SMichael Gernoth 
90499dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
90599dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
90699dcab46SMichael Gernoth {
90799dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
90899dcab46SMichael Gernoth 	unsigned int val;
90999dcab46SMichael Gernoth 	u32 tmp;
91099dcab46SMichael Gernoth 	int change = 0;
91199dcab46SMichael Gernoth 
91299dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
91399dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
91499dcab46SMichael Gernoth 	if (val >= 2)
91599dcab46SMichael Gernoth 		return -EINVAL;
91699dcab46SMichael Gernoth 	change = (emu->emu1010.optical_in != val);
91799dcab46SMichael Gernoth 	if (change) {
91899dcab46SMichael Gernoth 		emu->emu1010.optical_in = val;
9199d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
9209d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
92199dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
92299dcab46SMichael Gernoth 	}
92399dcab46SMichael Gernoth 	return change;
92499dcab46SMichael Gernoth }
92599dcab46SMichael Gernoth 
926f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = {
92799dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
92899dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
92999dcab46SMichael Gernoth 	.name =         "Optical Input Mode",
93099dcab46SMichael Gernoth 	.count =	1,
93199dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_in_info,
93299dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_in_get,
93399dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_in_put
93499dcab46SMichael Gernoth };
93599dcab46SMichael Gernoth 
936184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
937184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
938184c1e2cSJames Courtier-Dutton {
939184c1e2cSJames Courtier-Dutton #if 0
9401541c66dSTakashi Iwai 	static const char * const texts[4] = {
941184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
942184c1e2cSJames Courtier-Dutton 	};
943184c1e2cSJames Courtier-Dutton #endif
9441541c66dSTakashi Iwai 	static const char * const texts[2] = {
945184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
946184c1e2cSJames Courtier-Dutton 	};
947184c1e2cSJames Courtier-Dutton 
9481541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
949184c1e2cSJames Courtier-Dutton }
950184c1e2cSJames Courtier-Dutton 
951184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
952184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
953184c1e2cSJames Courtier-Dutton {
954184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
955184c1e2cSJames Courtier-Dutton 
956184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
957184c1e2cSJames Courtier-Dutton 	return 0;
958184c1e2cSJames Courtier-Dutton }
959184c1e2cSJames Courtier-Dutton 
960184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
961184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
962184c1e2cSJames Courtier-Dutton {
963184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
964184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
965184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
966a1c87c0bSOswald Buddenhagen 	u16 gpio;
967184c1e2cSJames Courtier-Dutton 	int change = 0;
968184c1e2cSJames Courtier-Dutton 	unsigned long flags;
969184c1e2cSJames Courtier-Dutton 	u32 source;
970184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
971184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
972184c1e2cSJames Courtier-Dutton 	 * for the particular source.
973184c1e2cSJames Courtier-Dutton 	 */
97474415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
97574415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
97674415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
97774415a36SJames Courtier-Dutton 	if (source_id >= 2)
97874415a36SJames Courtier-Dutton 		return -EINVAL;
979184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
980184c1e2cSJames Courtier-Dutton 	if (change) {
981184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
982184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
983a1c87c0bSOswald Buddenhagen 		gpio = inw(emu->port + A_IOCFG);
984184c1e2cSJames Courtier-Dutton 		if (source_id==0)
985a1c87c0bSOswald Buddenhagen 			outw(gpio | 0x4, emu->port + A_IOCFG);
986184c1e2cSJames Courtier-Dutton 		else
987a1c87c0bSOswald Buddenhagen 			outw(gpio & ~0x4, emu->port + A_IOCFG);
988184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
989184c1e2cSJames Courtier-Dutton 
990184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
991184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
992184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
993184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
994184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
995184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
996184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
997184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
998184c1e2cSJames Courtier-Dutton 
999184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
1000184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
1001184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
1002184c1e2cSJames Courtier-Dutton 	}
1003184c1e2cSJames Courtier-Dutton         return change;
1004184c1e2cSJames Courtier-Dutton }
1005184c1e2cSJames Courtier-Dutton 
1006f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source =
1007184c1e2cSJames Courtier-Dutton {
1008184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
1009184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
1010184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
1011184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
1012184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
1013184c1e2cSJames Courtier-Dutton };
1014184c1e2cSJames Courtier-Dutton 
1015184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
1016184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
1017184c1e2cSJames Courtier-Dutton {
1018184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1019184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
1020184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
1021184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
1022184c1e2cSJames Courtier-Dutton 	return 0;
1023184c1e2cSJames Courtier-Dutton }
1024184c1e2cSJames Courtier-Dutton 
1025184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
1026184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
1027184c1e2cSJames Courtier-Dutton {
1028184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
102974415a36SJames Courtier-Dutton 	unsigned int source_id;
1030184c1e2cSJames Courtier-Dutton 
1031184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
103274415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
103374415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
103474415a36SJames Courtier-Dutton 	if (source_id >= 2)
103574415a36SJames Courtier-Dutton 		return -EINVAL;
1036184c1e2cSJames Courtier-Dutton 
1037184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
1038184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
1039184c1e2cSJames Courtier-Dutton 	return 0;
1040184c1e2cSJames Courtier-Dutton }
1041184c1e2cSJames Courtier-Dutton 
1042184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
1043184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
1044184c1e2cSJames Courtier-Dutton {
1045184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1046184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
104714a29565SOswald Buddenhagen 	unsigned int ngain0, ngain1;
104874415a36SJames Courtier-Dutton 	unsigned int source_id;
1049184c1e2cSJames Courtier-Dutton 	int change = 0;
1050184c1e2cSJames Courtier-Dutton 
1051184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
105274415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
105374415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
105474415a36SJames Courtier-Dutton 	if (source_id >= 2)
105574415a36SJames Courtier-Dutton 		return -EINVAL;
105614a29565SOswald Buddenhagen 	ngain0 = ucontrol->value.integer.value[0];
105714a29565SOswald Buddenhagen 	ngain1 = ucontrol->value.integer.value[1];
105814a29565SOswald Buddenhagen 	if (ngain0 > 0xff)
105914a29565SOswald Buddenhagen 		return -EINVAL;
106014a29565SOswald Buddenhagen 	if (ngain1 > 0xff)
106114a29565SOswald Buddenhagen 		return -EINVAL;
1062184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
106314a29565SOswald Buddenhagen 	if (ogain != ngain0) {
1064184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
106514a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0);
106614a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][0] = ngain0;
1067184c1e2cSJames Courtier-Dutton 		change = 1;
1068184c1e2cSJames Courtier-Dutton 	}
1069184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
107014a29565SOswald Buddenhagen 	if (ogain != ngain1) {
1071184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
107214a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1);
107314a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][1] = ngain1;
1074184c1e2cSJames Courtier-Dutton 		change = 1;
1075184c1e2cSJames Courtier-Dutton 	}
1076184c1e2cSJames Courtier-Dutton 
1077184c1e2cSJames Courtier-Dutton 	return change;
1078184c1e2cSJames Courtier-Dutton }
1079184c1e2cSJames Courtier-Dutton 
1080536438f1SOswald Buddenhagen static const struct snd_kcontrol_new i2c_volume_ctl = {
1081536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1082536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1083536438f1SOswald Buddenhagen 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,
1084536438f1SOswald Buddenhagen 	.info = snd_audigy_i2c_volume_info,
1085536438f1SOswald Buddenhagen 	.get = snd_audigy_i2c_volume_get,
1086536438f1SOswald Buddenhagen 	.put = snd_audigy_i2c_volume_put,
1087536438f1SOswald Buddenhagen 	.tlv = { .p = snd_audigy_db_scale2 }
1088536438f1SOswald Buddenhagen };
1089184c1e2cSJames Courtier-Dutton 
1090536438f1SOswald Buddenhagen static const char * const snd_audigy_i2c_volume_ctls[] = {
1091536438f1SOswald Buddenhagen 	"Mic Capture Volume",
1092536438f1SOswald Buddenhagen 	"Line Capture Volume",
1093184c1e2cSJames Courtier-Dutton };
1094184c1e2cSJames Courtier-Dutton 
10950af68e5eSTakashi Iwai #if 0
1096eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
10971da177e4SLinus Torvalds {
10981541c66dSTakashi Iwai 	static const char * const texts[] = {"44100", "48000", "96000"};
10991da177e4SLinus Torvalds 
11001541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 3, texts);
11011da177e4SLinus Torvalds }
11021da177e4SLinus Torvalds 
1103eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
1104eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
11051da177e4SLinus Torvalds {
1106eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11071da177e4SLinus Torvalds 	unsigned int tmp;
11081da177e4SLinus Torvalds 
11091da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
11101da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
11111da177e4SLinus Torvalds 	case A_SPDIF_44100:
11121da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
11131da177e4SLinus Torvalds 		break;
11141da177e4SLinus Torvalds 	case A_SPDIF_48000:
11151da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
11161da177e4SLinus Torvalds 		break;
11171da177e4SLinus Torvalds 	case A_SPDIF_96000:
11181da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
11191da177e4SLinus Torvalds 		break;
11201da177e4SLinus Torvalds 	default:
11211da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
11221da177e4SLinus Torvalds 	}
11231da177e4SLinus Torvalds 	return 0;
11241da177e4SLinus Torvalds }
11251da177e4SLinus Torvalds 
1126eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
1127eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
11281da177e4SLinus Torvalds {
1129eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11301da177e4SLinus Torvalds 	int change;
11311da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
11321da177e4SLinus Torvalds 	unsigned long flags;
11331da177e4SLinus Torvalds 
11341da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
11351da177e4SLinus Torvalds 	case 0:
11361da177e4SLinus Torvalds 		val = A_SPDIF_44100;
11371da177e4SLinus Torvalds 		break;
11381da177e4SLinus Torvalds 	case 1:
11391da177e4SLinus Torvalds 		val = A_SPDIF_48000;
11401da177e4SLinus Torvalds 		break;
11411da177e4SLinus Torvalds 	case 2:
11421da177e4SLinus Torvalds 		val = A_SPDIF_96000;
11431da177e4SLinus Torvalds 		break;
11441da177e4SLinus Torvalds 	default:
11451da177e4SLinus Torvalds 		val = A_SPDIF_48000;
11461da177e4SLinus Torvalds 		break;
11471da177e4SLinus Torvalds 	}
11481da177e4SLinus Torvalds 
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11511da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
11521da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
11531da177e4SLinus Torvalds 	tmp |= val;
115412bda107STakashi Iwai 	change = (tmp != reg);
115512bda107STakashi Iwai 	if (change)
11561da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
11571da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11581da177e4SLinus Torvalds 	return change;
11591da177e4SLinus Torvalds }
11601da177e4SLinus Torvalds 
1161b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate =
11621da177e4SLinus Torvalds {
11631da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
11641da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
11651da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
11661da177e4SLinus Torvalds 	.count =	1,
11671da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
11681da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
11691da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
11701da177e4SLinus Torvalds };
11710af68e5eSTakashi Iwai #endif
11721da177e4SLinus Torvalds 
1173eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1174eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
11751da177e4SLinus Torvalds {
1176eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11771da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
11781da177e4SLinus Torvalds 	int change;
11791da177e4SLinus Torvalds 	unsigned int val;
11801da177e4SLinus Torvalds 
118174415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
118274415a36SJames Courtier-Dutton 	if (idx >= 3)
118374415a36SJames Courtier-Dutton 		return -EINVAL;
11841da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
11851da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
11861da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
11871da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
11881da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
11891da177e4SLinus Torvalds 	if (change) {
11901da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
11911da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
11921da177e4SLinus Torvalds 	}
11931da177e4SLinus Torvalds 	return change;
11941da177e4SLinus Torvalds }
11951da177e4SLinus Torvalds 
1196f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
11971da177e4SLinus Torvalds {
11981da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
11995549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12001da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
12017583cb51STakashi Iwai 	.count =	3,
12021da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
12031da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
12041da177e4SLinus Torvalds };
12051da177e4SLinus Torvalds 
1206f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
12071da177e4SLinus Torvalds {
12085549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
12091da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
12107583cb51STakashi Iwai 	.count =	3,
12111da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
12121da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
12131da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
12141da177e4SLinus Torvalds };
12151da177e4SLinus Torvalds 
12161da177e4SLinus Torvalds 
1217eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
12181da177e4SLinus Torvalds {
12191da177e4SLinus Torvalds 	if (emu->audigy) {
12201da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
12211da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
12221da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
12231da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
12241da177e4SLinus Torvalds 	} else {
12251da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
12261da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
12271da177e4SLinus Torvalds 	}
12281da177e4SLinus Torvalds }
12291da177e4SLinus Torvalds 
1230eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
12311da177e4SLinus Torvalds {
12321da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
12331da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
12341da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
12351da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
12361da177e4SLinus Torvalds 	if (emu->audigy) {
123751d652f4SOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice,
123851d652f4SOswald Buddenhagen 				      snd_emu10k1_compose_audigy_sendamounts(volume));
12391da177e4SLinus Torvalds 	}
12401da177e4SLinus Torvalds }
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds /* PCM stream controls */
12431da177e4SLinus Torvalds 
1244eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12451da177e4SLinus Torvalds {
1246eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12471da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12481da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
12491da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12501da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
12511da177e4SLinus Torvalds 	return 0;
12521da177e4SLinus Torvalds }
12531da177e4SLinus Torvalds 
1254eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1255eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
12561da177e4SLinus Torvalds {
1257eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1258eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1259eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12601da177e4SLinus Torvalds 	int voice, idx;
12611da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12621da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
12651da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
12661da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
12671da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
12681da177e4SLinus Torvalds 	return 0;
12691da177e4SLinus Torvalds }
12701da177e4SLinus Torvalds 
1271eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1272eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
12731da177e4SLinus Torvalds {
12741da177e4SLinus Torvalds 	unsigned long flags;
1275eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1276eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1277eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12781da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
12791da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12801da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
12811da177e4SLinus Torvalds 
12821da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12831da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
12841da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
12851da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
12861da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
12871da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
12881da177e4SLinus Torvalds 				change = 1;
12891da177e4SLinus Torvalds 			}
12901da177e4SLinus Torvalds 		}
12911da177e4SLinus Torvalds 	if (change && mix->epcm) {
12921da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
12931da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
12941da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
12951da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
12961da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
12971da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
12981da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
12991da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
13001da177e4SLinus Torvalds 		}
13011da177e4SLinus Torvalds 	}
13021da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13031da177e4SLinus Torvalds 	return change;
13041da177e4SLinus Torvalds }
13051da177e4SLinus Torvalds 
1306f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control =
13071da177e4SLinus Torvalds {
13081da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
130967ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13101da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
13111da177e4SLinus Torvalds 	.count =	32,
13121da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
13131da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
13141da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
13151da177e4SLinus Torvalds };
13161da177e4SLinus Torvalds 
1317eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13181da177e4SLinus Torvalds {
1319eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13201da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13211da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
13221da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13231da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
13241da177e4SLinus Torvalds 	return 0;
13251da177e4SLinus Torvalds }
13261da177e4SLinus Torvalds 
1327eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1328eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
13291da177e4SLinus Torvalds {
1330eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1331eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1332eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13331da177e4SLinus Torvalds 	int idx;
13341da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13351da177e4SLinus Torvalds 
13361da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
13371da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
13381da177e4SLinus Torvalds 	return 0;
13391da177e4SLinus Torvalds }
13401da177e4SLinus Torvalds 
1341eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1342eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
13431da177e4SLinus Torvalds {
13441da177e4SLinus Torvalds 	unsigned long flags;
1345eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1346eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1347eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13481da177e4SLinus Torvalds 	int change = 0, idx, val;
13491da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13501da177e4SLinus Torvalds 
13511da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13521da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
13531da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
13541da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
13551da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
13561da177e4SLinus Torvalds 			change = 1;
13571da177e4SLinus Torvalds 		}
13581da177e4SLinus Torvalds 	}
13591da177e4SLinus Torvalds 	if (change && mix->epcm) {
13601da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
13611da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
13621da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
13631da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
13641da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
13651da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
13661da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
13671da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
13681da177e4SLinus Torvalds 		}
13691da177e4SLinus Torvalds 	}
13701da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13711da177e4SLinus Torvalds 	return change;
13721da177e4SLinus Torvalds }
13731da177e4SLinus Torvalds 
1374f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
13751da177e4SLinus Torvalds {
13761da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
137767ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13781da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
13791da177e4SLinus Torvalds 	.count =	32,
13801da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
13811da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
13821da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
13831da177e4SLinus Torvalds };
13841da177e4SLinus Torvalds 
1385eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13861da177e4SLinus Torvalds {
13871da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13881da177e4SLinus Torvalds 	uinfo->count = 3;
13891da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1390bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
13911da177e4SLinus Torvalds 	return 0;
13921da177e4SLinus Torvalds }
13931da177e4SLinus Torvalds 
1394eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1395eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
13961da177e4SLinus Torvalds {
1397eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1398eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1399eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14001da177e4SLinus Torvalds 	int idx;
14011da177e4SLinus Torvalds 
14021da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
1403bcdbd3b7SOswald Buddenhagen 		ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U;
14041da177e4SLinus Torvalds 	return 0;
14051da177e4SLinus Torvalds }
14061da177e4SLinus Torvalds 
1407eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1408eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
14091da177e4SLinus Torvalds {
14101da177e4SLinus Torvalds 	unsigned long flags;
1411eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1412eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1413eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14141da177e4SLinus Torvalds 	int change = 0, idx, val;
14151da177e4SLinus Torvalds 
14161da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14171da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
1418bcdbd3b7SOswald Buddenhagen 		unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff;
1419bcdbd3b7SOswald Buddenhagen 		val = uval * 0x8000U / 0xffffU;
14201da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
14211da177e4SLinus Torvalds 			mix->attn[idx] = val;
14221da177e4SLinus Torvalds 			change = 1;
14231da177e4SLinus Torvalds 		}
14241da177e4SLinus Torvalds 	}
14251da177e4SLinus Torvalds 	if (change && mix->epcm) {
14261da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
14271da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
14281da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
14291da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
14301da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
14311da177e4SLinus Torvalds 		}
14321da177e4SLinus Torvalds 	}
14331da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14341da177e4SLinus Torvalds 	return change;
14351da177e4SLinus Torvalds }
14361da177e4SLinus Torvalds 
1437f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control =
14381da177e4SLinus Torvalds {
14391da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
144067ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14411da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
14421da177e4SLinus Torvalds 	.count =	32,
14431da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
14441da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
14451da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
14461da177e4SLinus Torvalds };
14471da177e4SLinus Torvalds 
14481da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
14491da177e4SLinus Torvalds 
1450eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14511da177e4SLinus Torvalds {
1452eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14531da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14541da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
14551da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14561da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
14571da177e4SLinus Torvalds 	return 0;
14581da177e4SLinus Torvalds }
14591da177e4SLinus Torvalds 
1460eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1461eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14621da177e4SLinus Torvalds {
1463eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1464eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1465eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14661da177e4SLinus Torvalds 	int idx;
14671da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14681da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14691da177e4SLinus Torvalds 
14701da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
14711da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
14721da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
14731da177e4SLinus Torvalds 	return 0;
14741da177e4SLinus Torvalds }
14751da177e4SLinus Torvalds 
1476eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1477eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14781da177e4SLinus Torvalds {
14791da177e4SLinus Torvalds 	unsigned long flags;
1480eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14811da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1482eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
14831da177e4SLinus Torvalds 	int change = 0, idx, val;
14841da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14851da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14861da177e4SLinus Torvalds 
14871da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14881da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
14891da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
14901da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
14911da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
14921da177e4SLinus Torvalds 			change = 1;
14931da177e4SLinus Torvalds 		}
14941da177e4SLinus Torvalds 	}
14951da177e4SLinus Torvalds 
14961da177e4SLinus Torvalds 	if (change && mix->epcm) {
14971da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
14981da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
14991da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
15001da177e4SLinus Torvalds 		}
15011da177e4SLinus Torvalds 	}
15021da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15031da177e4SLinus Torvalds 	return change;
15041da177e4SLinus Torvalds }
15051da177e4SLinus Torvalds 
1506f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
15071da177e4SLinus Torvalds {
15081da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15091da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15101da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
15111da177e4SLinus Torvalds 	.count =	16,
15121da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
15131da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
15141da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
15151da177e4SLinus Torvalds };
15161da177e4SLinus Torvalds 
1517eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15181da177e4SLinus Torvalds {
1519eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15201da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15211da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
15221da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
15231da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
15241da177e4SLinus Torvalds 	return 0;
15251da177e4SLinus Torvalds }
15261da177e4SLinus Torvalds 
1527eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1528eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
15291da177e4SLinus Torvalds {
1530eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1531eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1532eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15331da177e4SLinus Torvalds 	int idx;
15341da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15351da177e4SLinus Torvalds 
15361da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
15371da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
15381da177e4SLinus Torvalds 	return 0;
15391da177e4SLinus Torvalds }
15401da177e4SLinus Torvalds 
1541eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1542eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
15431da177e4SLinus Torvalds {
15441da177e4SLinus Torvalds 	unsigned long flags;
1545eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15461da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1547eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
15481da177e4SLinus Torvalds 	int change = 0, idx, val;
15491da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15501da177e4SLinus Torvalds 
15511da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15521da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
15531da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
15541da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
15551da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
15561da177e4SLinus Torvalds 			change = 1;
15571da177e4SLinus Torvalds 		}
15581da177e4SLinus Torvalds 	}
15591da177e4SLinus Torvalds 	if (change && mix->epcm) {
15601da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
15611da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
15621da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
15631da177e4SLinus Torvalds 		}
15641da177e4SLinus Torvalds 	}
15651da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15661da177e4SLinus Torvalds 	return change;
15671da177e4SLinus Torvalds }
15681da177e4SLinus Torvalds 
15691da177e4SLinus Torvalds 
1570f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
15711da177e4SLinus Torvalds {
15721da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15731da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15741da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
15751da177e4SLinus Torvalds 	.count =	16,
15761da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
15771da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
15781da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
15791da177e4SLinus Torvalds };
15801da177e4SLinus Torvalds 
1581eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15821da177e4SLinus Torvalds {
15831da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15841da177e4SLinus Torvalds 	uinfo->count = 1;
15851da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1586bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
15871da177e4SLinus Torvalds 	return 0;
15881da177e4SLinus Torvalds }
15891da177e4SLinus Torvalds 
1590eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1591eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
15921da177e4SLinus Torvalds {
1593eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1594eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1595eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15961da177e4SLinus Torvalds 
1597bcdbd3b7SOswald Buddenhagen 	ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U;
15981da177e4SLinus Torvalds 	return 0;
15991da177e4SLinus Torvalds }
16001da177e4SLinus Torvalds 
1601eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1602eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
16031da177e4SLinus Torvalds {
16041da177e4SLinus Torvalds 	unsigned long flags;
1605eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
16061da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1607eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
16081da177e4SLinus Torvalds 	int change = 0, val;
1609bcdbd3b7SOswald Buddenhagen 	unsigned uval;
16101da177e4SLinus Torvalds 
16111da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1612bcdbd3b7SOswald Buddenhagen 	uval = ucontrol->value.integer.value[0] & 0x1ffff;
1613bcdbd3b7SOswald Buddenhagen 	val = uval * 0x8000U / 0xffffU;
16141da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
16151da177e4SLinus Torvalds 		mix->attn[0] = val;
16161da177e4SLinus Torvalds 		change = 1;
16171da177e4SLinus Torvalds 	}
16181da177e4SLinus Torvalds 	if (change && mix->epcm) {
16191da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
16201da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
16211da177e4SLinus Torvalds 		}
16221da177e4SLinus Torvalds 	}
16231da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
16241da177e4SLinus Torvalds 	return change;
16251da177e4SLinus Torvalds }
16261da177e4SLinus Torvalds 
1627f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
16281da177e4SLinus Torvalds {
16291da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
16301da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
16311da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
16321da177e4SLinus Torvalds 	.count =	16,
16331da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
16341da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
16351da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
16361da177e4SLinus Torvalds };
16371da177e4SLinus Torvalds 
1638a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
16391da177e4SLinus Torvalds 
1640eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1641eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
16421da177e4SLinus Torvalds {
1643eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
16441da177e4SLinus Torvalds 
16451da177e4SLinus Torvalds 	if (emu->audigy)
1646a1c87c0bSOswald Buddenhagen 		ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
16471da177e4SLinus Torvalds 	else
16481da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1649d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1650d2cd74b1STakashi Iwai 		ucontrol->value.integer.value[0] =
1651d2cd74b1STakashi Iwai 			!ucontrol->value.integer.value[0];
1652d2cd74b1STakashi Iwai 
16531da177e4SLinus Torvalds 	return 0;
16541da177e4SLinus Torvalds }
16551da177e4SLinus Torvalds 
1656eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1657eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
16581da177e4SLinus Torvalds {
16591da177e4SLinus Torvalds 	unsigned long flags;
1660eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1661d2cd74b1STakashi Iwai 	unsigned int reg, val, sw;
16621da177e4SLinus Torvalds 	int change = 0;
16631da177e4SLinus Torvalds 
1664d2cd74b1STakashi Iwai 	sw = ucontrol->value.integer.value[0];
1665d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1666d2cd74b1STakashi Iwai 		sw = !sw;
166750164f69SOswald Buddenhagen 	spin_lock_irqsave(&emu->emu_lock, flags);
1668184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1669184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1670184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
1671a1c87c0bSOswald Buddenhagen 		reg = inw(emu->port + A_IOCFG);
1672d2cd74b1STakashi Iwai 		val = sw ? A_IOCFG_GPOUT0 : 0;
16731da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
16741da177e4SLinus Torvalds 		if (change) {
16751da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
16761da177e4SLinus Torvalds 			reg |= val;
1677a1c87c0bSOswald Buddenhagen 			outw(reg | val, emu->port + A_IOCFG);
16781da177e4SLinus Torvalds 		}
16791da177e4SLinus Torvalds 	}
16801da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
1681d2cd74b1STakashi Iwai 	val = sw ? HCFG_GPOUT0 : 0;
16821da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
16831da177e4SLinus Torvalds 	if (change) {
16841da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
16851da177e4SLinus Torvalds 		reg |= val;
16861da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
16871da177e4SLinus Torvalds 	}
168850164f69SOswald Buddenhagen 	spin_unlock_irqrestore(&emu->emu_lock, flags);
16891da177e4SLinus Torvalds 	return change;
16901da177e4SLinus Torvalds }
16911da177e4SLinus Torvalds 
1692f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
16931da177e4SLinus Torvalds {
16941da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16951da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
16961da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
16971da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
16981da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
16991da177e4SLinus Torvalds };
17001da177e4SLinus Torvalds 
1701f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif =
17021da177e4SLinus Torvalds {
17031da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
17041da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
17051da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
17061da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
17071da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
17081da177e4SLinus Torvalds };
17091da177e4SLinus Torvalds 
171016950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
171116950e09STakashi Iwai 
171216950e09STakashi Iwai #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
171316950e09STakashi Iwai 
171416950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
171516950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
171616950e09STakashi Iwai {
171716950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
171816950e09STakashi Iwai 	unsigned int val;
171916950e09STakashi Iwai 
172016950e09STakashi Iwai 	/* FIXME: better to use a cached version */
172116950e09STakashi Iwai 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
172216950e09STakashi Iwai 	ucontrol->value.integer.value[0] = !!val;
172316950e09STakashi Iwai 	return 0;
172416950e09STakashi Iwai }
172516950e09STakashi Iwai 
172616950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
172716950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
172816950e09STakashi Iwai {
172916950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
173016950e09STakashi Iwai 	unsigned int val;
173116950e09STakashi Iwai 
173216950e09STakashi Iwai 	if (ucontrol->value.integer.value[0])
173316950e09STakashi Iwai 		val = 0x0f0f;
173416950e09STakashi Iwai 	else
173516950e09STakashi Iwai 		val = 0;
173616950e09STakashi Iwai 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
173716950e09STakashi Iwai }
173816950e09STakashi Iwai 
1739f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost =
174016950e09STakashi Iwai {
174116950e09STakashi Iwai 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
17422a52feb1SMaciej S. Szmigiero 	.name =		"Mic Extra Boost",
174316950e09STakashi Iwai 	.info =		snd_audigy_capture_boost_info,
174416950e09STakashi Iwai 	.get =		snd_audigy_capture_boost_get,
174516950e09STakashi Iwai 	.put =		snd_audigy_capture_boost_put
174616950e09STakashi Iwai };
174716950e09STakashi Iwai 
174816950e09STakashi Iwai 
17491da177e4SLinus Torvalds /*
17501da177e4SLinus Torvalds  */
1751eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
17521da177e4SLinus Torvalds {
1753eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
17541da177e4SLinus Torvalds 	emu->ac97 = NULL;
17551da177e4SLinus Torvalds }
17561da177e4SLinus Torvalds 
17571da177e4SLinus Torvalds /*
17581da177e4SLinus Torvalds  */
1759eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
17601da177e4SLinus Torvalds {
1761eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
17621da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
17631da177e4SLinus Torvalds 	strcpy(id.name, name);
17641da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
17651da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
17661da177e4SLinus Torvalds }
17671da177e4SLinus Torvalds 
1768eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
17691da177e4SLinus Torvalds {
1770eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
17711da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
17721da177e4SLinus Torvalds 	strcpy(sid.name, name);
17731da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
17741da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
17751da177e4SLinus Torvalds }
17761da177e4SLinus Torvalds 
1777eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
17781da177e4SLinus Torvalds {
1779eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
17801da177e4SLinus Torvalds 	if (kctl) {
178136476b81SMaciej S. Szmigiero 		snd_ctl_rename(card, kctl, dst);
17821da177e4SLinus Torvalds 		return 0;
17831da177e4SLinus Torvalds 	}
17841da177e4SLinus Torvalds 	return -ENOENT;
17851da177e4SLinus Torvalds }
17861da177e4SLinus Torvalds 
1787e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
178867ed4161SClemens Ladisch 		      int pcm_device, int multi_device)
17891da177e4SLinus Torvalds {
1790155e3d3bSOswald Buddenhagen 	int err;
1791eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1792eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
17936fddce26STakashi Iwai 	const char * const *c;
17946fddce26STakashi Iwai 	static const char * const emu10k1_remove_ctls[] = {
17951da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
17961da177e4SLinus Torvalds 		"Master Mono Playback Switch",
17971da177e4SLinus Torvalds 		"Master Mono Playback Volume",
17981da177e4SLinus Torvalds 		"PCM Out Path & Mute",
17991da177e4SLinus Torvalds 		"Mono Output Select",
18001da177e4SLinus Torvalds 		"Surround Playback Switch",
18011da177e4SLinus Torvalds 		"Surround Playback Volume",
18021da177e4SLinus Torvalds 		"Center Playback Switch",
18031da177e4SLinus Torvalds 		"Center Playback Volume",
18041da177e4SLinus Torvalds 		"LFE Playback Switch",
18051da177e4SLinus Torvalds 		"LFE Playback Volume",
18061da177e4SLinus Torvalds 		NULL
18071da177e4SLinus Torvalds 	};
18086fddce26STakashi Iwai 	static const char * const emu10k1_rename_ctls[] = {
18091da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
18101da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
18111da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
18121da177e4SLinus Torvalds 		NULL
18131da177e4SLinus Torvalds 	};
18146fddce26STakashi Iwai 	static const char * const audigy_remove_ctls[] = {
18151da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
181621fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
181721fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
18181da177e4SLinus Torvalds 		"PCM Playback Switch",
18191da177e4SLinus Torvalds 		"PCM Playback Volume",
18201da177e4SLinus Torvalds 		"Master Playback Switch",
18211da177e4SLinus Torvalds 		"Master Playback Volume",
18221da177e4SLinus Torvalds 		"PCM Out Path & Mute",
18231da177e4SLinus Torvalds 		"Mono Output Select",
18241da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
18251da177e4SLinus Torvalds 		"Capture Source",
18261da177e4SLinus Torvalds 		"Capture Switch",
18271da177e4SLinus Torvalds 		"Capture Volume",
18281da177e4SLinus Torvalds 		"Mic Select",
1829274b2000SMaciej S. Szmigiero 		"Headphone Playback Switch",
1830274b2000SMaciej S. Szmigiero 		"Headphone Playback Volume",
1831274b2000SMaciej S. Szmigiero 		"3D Control - Center",
1832274b2000SMaciej S. Szmigiero 		"3D Control - Depth",
1833274b2000SMaciej S. Szmigiero 		"3D Control - Switch",
18341da177e4SLinus Torvalds 		"Video Playback Switch",
18351da177e4SLinus Torvalds 		"Video Playback Volume",
18361da177e4SLinus Torvalds 		"Mic Playback Switch",
18371da177e4SLinus Torvalds 		"Mic Playback Volume",
1838274b2000SMaciej S. Szmigiero 		"External Amplifier",
18391da177e4SLinus Torvalds 		NULL
18401da177e4SLinus Torvalds 	};
18416fddce26STakashi Iwai 	static const char * const audigy_rename_ctls[] = {
18421da177e4SLinus Torvalds 		/* use conventional names */
18431da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
18441da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
18451da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
18461da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
184752051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
184852051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
18491da177e4SLinus Torvalds 		NULL
18501da177e4SLinus Torvalds 	};
18516fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_i2c_adc[] = {
1852184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1853184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1854184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1855184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1856184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1857eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1858184c1e2cSJames Courtier-Dutton 		NULL
1859184c1e2cSJames Courtier-Dutton 	};
18606fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_i2c_adc[] = {
1861184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1862184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1863184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1864184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1865184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1866eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1867184c1e2cSJames Courtier-Dutton 		NULL
1868184c1e2cSJames Courtier-Dutton 	};
18696fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_1361t_adc[] = {
187021fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
187121fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
187221fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
187321fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
187421fdddeaSJames Courtier-Dutton 		"Capture Source",
187521fdddeaSJames Courtier-Dutton 		"Capture Switch",
187621fdddeaSJames Courtier-Dutton 		"Capture Volume",
187721fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
187821fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
187921fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
188021fdddeaSJames Courtier-Dutton 		"3D Control - Center",
188121fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
188221fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
188321fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
188421fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
188521fdddeaSJames Courtier-Dutton 		NULL
188621fdddeaSJames Courtier-Dutton 	};
18876fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_1361t_adc[] = {
188821fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
188921fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
189021fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1891d355c82aSJaroslav Kysela 		"Beep Playback Switch", "Beep Capture Switch",
1892d355c82aSJaroslav Kysela 		"Beep Playback Volume", "Beep Capture Volume",
189321fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
189421fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
189521fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
189621fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
189721fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
189821fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
189921fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
190021fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
190121fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
190221fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
190321fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
190421fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
190552051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
190652051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
190721fdddeaSJames Courtier-Dutton 		NULL
190821fdddeaSJames Courtier-Dutton 	};
19091da177e4SLinus Torvalds 
19102b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1911eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1912eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
191351055da5STakashi Iwai 		static const struct snd_ac97_bus_ops ops = {
19141da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
19151da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
19161da177e4SLinus Torvalds 		};
19171da177e4SLinus Torvalds 
191812bda107STakashi Iwai 		err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus);
191912bda107STakashi Iwai 		if (err < 0)
19201da177e4SLinus Torvalds 			return err;
19211da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
19221da177e4SLinus Torvalds 
19231da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
19241da177e4SLinus Torvalds 		ac97.private_data = emu;
19251da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
19261da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
192712bda107STakashi Iwai 		err = snd_ac97_mixer(pbus, &ac97, &emu->ac97);
192812bda107STakashi Iwai 		if (err < 0) {
1929b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
19301da177e4SLinus Torvalds 				return err;
19316f002b02STakashi Iwai 			dev_info(emu->card->dev,
19326f002b02STakashi Iwai 				 "AC97 is optional on this board\n");
19336f002b02STakashi Iwai 			dev_info(emu->card->dev,
19346f002b02STakashi Iwai 				 "Proceeding without ac97 mixers...\n");
1935b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1936b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1937b1508693STakashi Iwai 		}
19381da177e4SLinus Torvalds 		if (emu->audigy) {
19391da177e4SLinus Torvalds 			/* set master volume to 0 dB */
19404d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
19411da177e4SLinus Torvalds 			/* set capture source to mic */
19424d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
194352051942SMaciej S. Szmigiero 			/* set mono output (TAD) to mic */
194452051942SMaciej S. Szmigiero 			snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE,
194552051942SMaciej S. Szmigiero 				0x0200, 0x0200);
194621fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
194721fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
194821fdddeaSJames Courtier-Dutton 			else
19491da177e4SLinus Torvalds 				c = audigy_remove_ctls;
19501da177e4SLinus Torvalds 		} else {
19511da177e4SLinus Torvalds 			/*
19521da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
19531da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
19541da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
19551da177e4SLinus Torvalds 			 */
19561da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
19571da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
19581da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
19592594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
1960b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Volume");
1961b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Switch");
19621da177e4SLinus Torvalds 			}
19631da177e4SLinus Torvalds 			/* remove unused AC97 controls */
19644d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
19654d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
19661da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
19671da177e4SLinus Torvalds 		}
19681da177e4SLinus Torvalds 		for (; *c; c++)
19691da177e4SLinus Torvalds 			remove_ctl(card, *c);
1970184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1971184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1972184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1973184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
19741da177e4SLinus Torvalds 	} else {
1975f12aa40cSTakashi Iwai 	no_ac97:
19762b637da5SLee Revell 		if (emu->card_capabilities->ecard)
19771da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
19781da177e4SLinus Torvalds 		else if (emu->audigy)
19791da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
19801da177e4SLinus Torvalds 		else
19811da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
19821da177e4SLinus Torvalds 	}
19831da177e4SLinus Torvalds 
19841da177e4SLinus Torvalds 	if (emu->audigy)
198521fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
198621fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1987184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1988184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
198921fdddeaSJames Courtier-Dutton 		else
19901da177e4SLinus Torvalds 			c = audigy_rename_ctls;
19911da177e4SLinus Torvalds 	else
19921da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
19931da177e4SLinus Torvalds 	for (; *c; c += 2)
19941da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
199521fdddeaSJames Courtier-Dutton 
1996e217b960SRaymond Yau 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
1997e217b960SRaymond Yau 		remove_ctl(card, "Center Playback Volume");
1998e217b960SRaymond Yau 		remove_ctl(card, "LFE Playback Volume");
1999e217b960SRaymond Yau 		remove_ctl(card, "Wave Center Playback Volume");
2000e217b960SRaymond Yau 		remove_ctl(card, "Wave LFE Playback Volume");
2001e217b960SRaymond Yau 	}
2002e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
2003e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
2004e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
2005e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
2006e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
2007e3b9bc0eSJames Courtier-Dutton 	}
200812bda107STakashi Iwai 	kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu);
200912bda107STakashi Iwai 	if (!kctl)
20101da177e4SLinus Torvalds 		return -ENOMEM;
201167ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
201212bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
201312bda107STakashi Iwai 	if (err)
20141da177e4SLinus Torvalds 		return err;
201512bda107STakashi Iwai 	kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu);
201612bda107STakashi Iwai 	if (!kctl)
20171da177e4SLinus Torvalds 		return -ENOMEM;
201867ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
201912bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
202012bda107STakashi Iwai 	if (err)
20211da177e4SLinus Torvalds 		return err;
202212bda107STakashi Iwai 	kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu);
202312bda107STakashi Iwai 	if (!kctl)
20241da177e4SLinus Torvalds 		return -ENOMEM;
202567ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
202612bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
202712bda107STakashi Iwai 	if (err)
20281da177e4SLinus Torvalds 		return err;
20291da177e4SLinus Torvalds 
203012bda107STakashi Iwai 	kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu);
203112bda107STakashi Iwai 	if (!kctl)
20321da177e4SLinus Torvalds 		return -ENOMEM;
203367ed4161SClemens Ladisch 	kctl->id.device = multi_device;
203412bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
203512bda107STakashi Iwai 	if (err)
20361da177e4SLinus Torvalds 		return err;
20371da177e4SLinus Torvalds 
203812bda107STakashi Iwai 	kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu);
203912bda107STakashi Iwai 	if (!kctl)
20401da177e4SLinus Torvalds 		return -ENOMEM;
204167ed4161SClemens Ladisch 	kctl->id.device = multi_device;
204212bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
204312bda107STakashi Iwai 	if (err)
20441da177e4SLinus Torvalds 		return err;
20451da177e4SLinus Torvalds 
204612bda107STakashi Iwai 	kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu);
204712bda107STakashi Iwai 	if (!kctl)
20481da177e4SLinus Torvalds 		return -ENOMEM;
204967ed4161SClemens Ladisch 	kctl->id.device = multi_device;
205012bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
205112bda107STakashi Iwai 	if (err)
20521da177e4SLinus Torvalds 		return err;
20531da177e4SLinus Torvalds 
2054a8661af5SOswald Buddenhagen 	if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) {
20551da177e4SLinus Torvalds 		/* sb live! and audigy */
205612bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu);
205712bda107STakashi Iwai 		if (!kctl)
20581da177e4SLinus Torvalds 			return -ENOMEM;
20595549d549SClemens Ladisch 		if (!emu->audigy)
20605549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
206112bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
206212bda107STakashi Iwai 		if (err)
20631da177e4SLinus Torvalds 			return err;
206412bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu);
206512bda107STakashi Iwai 		if (!kctl)
20661da177e4SLinus Torvalds 			return -ENOMEM;
20675549d549SClemens Ladisch 		if (!emu->audigy)
20685549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
206912bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
207012bda107STakashi Iwai 		if (err)
20711da177e4SLinus Torvalds 			return err;
20721da177e4SLinus Torvalds 	}
20731da177e4SLinus Torvalds 
2074190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
207519b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
207619b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
207712bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu);
207812bda107STakashi Iwai 		if (!kctl)
20791da177e4SLinus Torvalds 			return -ENOMEM;
208012bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
208112bda107STakashi Iwai 		if (err)
20821da177e4SLinus Torvalds 			return err;
2083001f7589SJames Courtier-Dutton #if 0
208412bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu);
208512bda107STakashi Iwai 		if (!kctl)
20861da177e4SLinus Torvalds 			return -ENOMEM;
208712bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
208812bda107STakashi Iwai 		if (err)
20891da177e4SLinus Torvalds 			return err;
2090001f7589SJames Courtier-Dutton #endif
20912b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
20921da177e4SLinus Torvalds 		/* sb live! */
209312bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu);
209412bda107STakashi Iwai 		if (!kctl)
20951da177e4SLinus Torvalds 			return -ENOMEM;
209612bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
209712bda107STakashi Iwai 		if (err)
20981da177e4SLinus Torvalds 			return err;
20991da177e4SLinus Torvalds 	}
21002b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
210112bda107STakashi Iwai 		err = snd_p16v_mixer(emu);
210212bda107STakashi Iwai 		if (err)
21031da177e4SLinus Torvalds 			return err;
21041da177e4SLinus Torvalds 	}
21051da177e4SLinus Torvalds 
21061fc710f0SOswald Buddenhagen 	if (emu->card_capabilities->emu_model) {
21071fc710f0SOswald Buddenhagen 		unsigned i, emu_idx = emu1010_idx(emu);
21081fc710f0SOswald Buddenhagen 		const struct snd_emu1010_routing_info *emu_ri =
21091fc710f0SOswald Buddenhagen 			&emu1010_routing_info[emu_idx];
2110*97f1582eSOswald Buddenhagen 		const struct snd_emu1010_pads_info *emu_pi = &emu1010_pads_info[emu_idx];
21111fc710f0SOswald Buddenhagen 
21121fc710f0SOswald Buddenhagen 		for (i = 0; i < emu_ri->n_ins; i++)
21131fc710f0SOswald Buddenhagen 			emu->emu1010.input_source[i] =
21141fc710f0SOswald Buddenhagen 				emu1010_map_source(emu_ri, emu_ri->in_dflts[i]);
21151fc710f0SOswald Buddenhagen 		for (i = 0; i < emu_ri->n_outs; i++)
21161fc710f0SOswald Buddenhagen 			emu->emu1010.output_source[i] =
21171fc710f0SOswald Buddenhagen 				emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
21181fc710f0SOswald Buddenhagen 		snd_emu1010_apply_sources(emu);
21191fc710f0SOswald Buddenhagen 
21201c02e366SCtirad Fertr 		err = snd_ctl_add(card,
21211c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
21221c02e366SCtirad Fertr 		if (err < 0)
21231c02e366SCtirad Fertr 			return err;
2124*97f1582eSOswald Buddenhagen 
2125*97f1582eSOswald Buddenhagen 		err = add_ctls(emu, &emu1010_adc_pads_ctl,
2126*97f1582eSOswald Buddenhagen 			       emu_pi->adc_ctls, emu_pi->n_adc_ctls);
2127*97f1582eSOswald Buddenhagen 		if (err < 0)
2128*97f1582eSOswald Buddenhagen 			return err;
2129*97f1582eSOswald Buddenhagen 		err = add_ctls(emu, &emu1010_dac_pads_ctl,
2130*97f1582eSOswald Buddenhagen 			       emu_pi->dac_ctls, emu_pi->n_dac_ctls);
2131*97f1582eSOswald Buddenhagen 		if (err < 0)
2132*97f1582eSOswald Buddenhagen 			return err;
2133*97f1582eSOswald Buddenhagen 
213499dcab46SMichael Gernoth 		err = snd_ctl_add(card,
213599dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
213699dcab46SMichael Gernoth 		if (err < 0)
213799dcab46SMichael Gernoth 			return err;
213899dcab46SMichael Gernoth 		err = snd_ctl_add(card,
213999dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
214099dcab46SMichael Gernoth 		if (err < 0)
214199dcab46SMichael Gernoth 			return err;
21421c02e366SCtirad Fertr 
2143*97f1582eSOswald Buddenhagen 		err = add_emu1010_source_mixers(emu);
214499dcab46SMichael Gernoth 		if (err < 0)
214599dcab46SMichael Gernoth 			return err;
21469f4bd5ddSJames Courtier-Dutton 	}
21479f4bd5ddSJames Courtier-Dutton 
2148184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2149184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2150184c1e2cSJames Courtier-Dutton 		if (err < 0)
2151184c1e2cSJames Courtier-Dutton 			return err;
2152184c1e2cSJames Courtier-Dutton 
2153536438f1SOswald Buddenhagen 		err = add_ctls(emu, &i2c_volume_ctl,
2154536438f1SOswald Buddenhagen 			       snd_audigy_i2c_volume_ctls,
2155536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_audigy_i2c_volume_ctls));
2156184c1e2cSJames Courtier-Dutton 		if (err < 0)
2157184c1e2cSJames Courtier-Dutton 			return err;
2158184c1e2cSJames Courtier-Dutton 	}
2159184c1e2cSJames Courtier-Dutton 
216016950e09STakashi Iwai 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
216116950e09STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
216216950e09STakashi Iwai 						     emu));
216316950e09STakashi Iwai 		if (err < 0)
216416950e09STakashi Iwai 			return err;
216516950e09STakashi Iwai 	}
216616950e09STakashi Iwai 
21671da177e4SLinus Torvalds 	return 0;
21681da177e4SLinus Torvalds }
2169