xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision 511cbe8f59e30cd09a04c1dbafe6337d9111e88a)
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 
234536438f1SOswald Buddenhagen /* 1616(m) cardbus */
235536438f1SOswald Buddenhagen 
236536438f1SOswald Buddenhagen static const char * const snd_emu1616_output_texts[] = {
237536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
238536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
239536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
240536438f1SOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
241536438f1SOswald Buddenhagen 	ADAT_CTLS("Dock "),
242536438f1SOswald Buddenhagen 	LR_CTLS("Mana DAC"),
243536438f1SOswald Buddenhagen };
244536438f1SOswald Buddenhagen 
245536438f1SOswald Buddenhagen static const unsigned short emu1616_output_dst[] = {
246536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
247536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
248536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
249536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_MDOCK_SPDIF),
250536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_MDOCK_ADAT),
251536438f1SOswald Buddenhagen 	EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT,
252536438f1SOswald Buddenhagen };
253536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1616_output_dst) == ARRAY_SIZE(snd_emu1616_output_texts));
2541c02e366SCtirad Fertr 
25513d45709SPavel Hofman /*
256a869057cSOswald Buddenhagen  * Data destinations - FPGA outputs going to Alice2 (Audigy) for
25713d45709SPavel Hofman  *   capture (EMU32 + I2S links)
25813d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
25913d45709SPavel Hofman  */
260536438f1SOswald Buddenhagen 
261536438f1SOswald Buddenhagen static const char * const emu1010_input_texts[] = {
262536438f1SOswald Buddenhagen 	"DSP 0 Capture Enum",
263536438f1SOswald Buddenhagen 	"DSP 1 Capture Enum",
264536438f1SOswald Buddenhagen 	"DSP 2 Capture Enum",
265536438f1SOswald Buddenhagen 	"DSP 3 Capture Enum",
266536438f1SOswald Buddenhagen 	"DSP 4 Capture Enum",
267536438f1SOswald Buddenhagen 	"DSP 5 Capture Enum",
268536438f1SOswald Buddenhagen 	"DSP 6 Capture Enum",
269536438f1SOswald Buddenhagen 	"DSP 7 Capture Enum",
270536438f1SOswald Buddenhagen 	"DSP 8 Capture Enum",
271536438f1SOswald Buddenhagen 	"DSP 9 Capture Enum",
272536438f1SOswald Buddenhagen 	"DSP A Capture Enum",
273536438f1SOswald Buddenhagen 	"DSP B Capture Enum",
274536438f1SOswald Buddenhagen 	"DSP C Capture Enum",
275536438f1SOswald Buddenhagen 	"DSP D Capture Enum",
276536438f1SOswald Buddenhagen 	"DSP E Capture Enum",
277536438f1SOswald Buddenhagen 	"DSP F Capture Enum",
278536438f1SOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
279536438f1SOswald Buddenhagen 	"DSP 10 Capture Enum",
280536438f1SOswald Buddenhagen 	"DSP 11 Capture Enum",
281536438f1SOswald Buddenhagen 	"DSP 12 Capture Enum",
282536438f1SOswald Buddenhagen 	"DSP 13 Capture Enum",
283536438f1SOswald Buddenhagen 	"DSP 14 Capture Enum",
284536438f1SOswald Buddenhagen 	"DSP 15 Capture Enum",
285536438f1SOswald Buddenhagen };
286536438f1SOswald Buddenhagen 
2879b00a1e9SOswald Buddenhagen static const unsigned short emu1010_input_dst[] = {
2889f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_0,
2899f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_1,
2909f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_2,
2919f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_3,
2929f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_4,
2939f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_5,
2949f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_6,
2959f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_7,
2969f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_8,
2979f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_9,
2989f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_A,
2999f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_B,
3009f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_C,
3019f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_D,
3029f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_E,
3039f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_F,
304a869057cSOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
3059f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_LEFT,
3069f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_RIGHT,
3079f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_LEFT,
3089f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_RIGHT,
3099f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_LEFT,
3109f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_RIGHT,
3119f4bd5ddSJames Courtier-Dutton };
312536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts));
3139f4bd5ddSJames Courtier-Dutton 
314*511cbe8fSOswald Buddenhagen struct snd_emu1010_routing_info {
315*511cbe8fSOswald Buddenhagen 	const char * const *src_texts;
316*511cbe8fSOswald Buddenhagen 	const unsigned short *src_regs;
317*511cbe8fSOswald Buddenhagen 	const unsigned short *out_regs;
318*511cbe8fSOswald Buddenhagen 	const unsigned short *in_regs;
319*511cbe8fSOswald Buddenhagen 	unsigned n_srcs;
320*511cbe8fSOswald Buddenhagen 	unsigned n_outs;
321*511cbe8fSOswald Buddenhagen 	unsigned n_ins;
322*511cbe8fSOswald Buddenhagen };
323*511cbe8fSOswald Buddenhagen 
324*511cbe8fSOswald Buddenhagen const struct snd_emu1010_routing_info emu1010_routing_info[] = {
325*511cbe8fSOswald Buddenhagen 	{
326*511cbe8fSOswald Buddenhagen 		.src_regs = emu1010_src_regs,
327*511cbe8fSOswald Buddenhagen 		.src_texts = emu1010_src_texts,
328*511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1010_src_texts),
329*511cbe8fSOswald Buddenhagen 
330*511cbe8fSOswald Buddenhagen 		.out_regs = emu1010_output_dst,
331*511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1010_output_dst),
332*511cbe8fSOswald Buddenhagen 
333*511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
334*511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst),
335*511cbe8fSOswald Buddenhagen 	},
336*511cbe8fSOswald Buddenhagen 	{
337*511cbe8fSOswald Buddenhagen 		/* 1616(m) cardbus */
338*511cbe8fSOswald Buddenhagen 		.src_regs = emu1616_src_regs,
339*511cbe8fSOswald Buddenhagen 		.src_texts = emu1616_src_texts,
340*511cbe8fSOswald Buddenhagen 		.n_srcs = ARRAY_SIZE(emu1616_src_texts),
341*511cbe8fSOswald Buddenhagen 
342*511cbe8fSOswald Buddenhagen 		.out_regs = emu1616_output_dst,
343*511cbe8fSOswald Buddenhagen 		.n_outs = ARRAY_SIZE(emu1616_output_dst),
344*511cbe8fSOswald Buddenhagen 
345*511cbe8fSOswald Buddenhagen 		.in_regs = emu1010_input_dst,
346*511cbe8fSOswald Buddenhagen 		.n_ins = ARRAY_SIZE(emu1010_input_dst) - 6,
347*511cbe8fSOswald Buddenhagen 	},
348*511cbe8fSOswald Buddenhagen };
349*511cbe8fSOswald Buddenhagen 
350*511cbe8fSOswald Buddenhagen static unsigned emu1010_idx(struct snd_emu10k1 *emu)
351*511cbe8fSOswald Buddenhagen {
352*511cbe8fSOswald Buddenhagen 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
353*511cbe8fSOswald Buddenhagen 		return 1;
354*511cbe8fSOswald Buddenhagen 	else
355*511cbe8fSOswald Buddenhagen 		return 0;
356*511cbe8fSOswald Buddenhagen }
357*511cbe8fSOswald Buddenhagen 
358*511cbe8fSOswald Buddenhagen static void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu,
359*511cbe8fSOswald Buddenhagen 					    int channel, int src)
360*511cbe8fSOswald Buddenhagen {
361*511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
362*511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
363*511cbe8fSOswald Buddenhagen 
364*511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
365*511cbe8fSOswald Buddenhagen 		emu_ri->out_regs[channel], emu_ri->src_regs[src]);
366*511cbe8fSOswald Buddenhagen }
367*511cbe8fSOswald Buddenhagen 
368*511cbe8fSOswald Buddenhagen static void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu,
369*511cbe8fSOswald Buddenhagen 					   int channel, int src)
370*511cbe8fSOswald Buddenhagen {
371*511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
372*511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
373*511cbe8fSOswald Buddenhagen 
374*511cbe8fSOswald Buddenhagen 	snd_emu1010_fpga_link_dst_src_write(emu,
375*511cbe8fSOswald Buddenhagen 		emu_ri->in_regs[channel], emu_ri->src_regs[src]);
376*511cbe8fSOswald Buddenhagen }
377*511cbe8fSOswald Buddenhagen 
3781c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
3791c02e366SCtirad Fertr 						struct snd_ctl_elem_info *uinfo)
3809f4bd5ddSJames Courtier-Dutton {
3811c02e366SCtirad Fertr 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
382*511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
383*511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
3841c02e366SCtirad Fertr 
385*511cbe8fSOswald Buddenhagen 	return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts);
3869f4bd5ddSJames Courtier-Dutton }
3879f4bd5ddSJames Courtier-Dutton 
3889f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
3899f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
3909f4bd5ddSJames Courtier-Dutton {
3919f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
392*511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
393*511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
394*511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
3959f4bd5ddSJames Courtier-Dutton 
396*511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
39774415a36SJames Courtier-Dutton 		return -EINVAL;
3989f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
3999f4bd5ddSJames Courtier-Dutton 	return 0;
4009f4bd5ddSJames Courtier-Dutton }
4019f4bd5ddSJames Courtier-Dutton 
4029f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
4039f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4049f4bd5ddSJames Courtier-Dutton {
4059f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
406*511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
407*511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
408*511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
409*511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
410*511cbe8fSOswald Buddenhagen 	int change;
4119f4bd5ddSJames Courtier-Dutton 
412*511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
413aa299d01STakashi Iwai 		return -EINVAL;
414*511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_outs)
41574415a36SJames Courtier-Dutton 		return -EINVAL;
416*511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.output_source[channel] != val);
417*511cbe8fSOswald Buddenhagen 	if (change) {
418aa299d01STakashi Iwai 		emu->emu1010.output_source[channel] = val;
419*511cbe8fSOswald Buddenhagen 		snd_emu1010_output_source_apply(emu, channel, val);
420*511cbe8fSOswald Buddenhagen 	}
421*511cbe8fSOswald Buddenhagen 	return change;
4229f4bd5ddSJames Courtier-Dutton }
4239f4bd5ddSJames Courtier-Dutton 
424536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_output_source_ctl = {
425536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
426536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
427536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
428536438f1SOswald Buddenhagen 	.get = snd_emu1010_output_source_get,
429536438f1SOswald Buddenhagen 	.put = snd_emu1010_output_source_put
430536438f1SOswald Buddenhagen };
431536438f1SOswald Buddenhagen 
4329f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
4339f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4349f4bd5ddSJames Courtier-Dutton {
4359f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
436*511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
437*511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
438*511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
4399f4bd5ddSJames Courtier-Dutton 
440*511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
44174415a36SJames Courtier-Dutton 		return -EINVAL;
4429f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
4439f4bd5ddSJames Courtier-Dutton 	return 0;
4449f4bd5ddSJames Courtier-Dutton }
4459f4bd5ddSJames Courtier-Dutton 
4469f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
4479f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4489f4bd5ddSJames Courtier-Dutton {
4499f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
450*511cbe8fSOswald Buddenhagen 	const struct snd_emu1010_routing_info *emu_ri =
451*511cbe8fSOswald Buddenhagen 		&emu1010_routing_info[emu1010_idx(emu)];
452*511cbe8fSOswald Buddenhagen 	unsigned val = ucontrol->value.enumerated.item[0];
453*511cbe8fSOswald Buddenhagen 	unsigned channel = kcontrol->private_value;
454*511cbe8fSOswald Buddenhagen 	int change;
4559f4bd5ddSJames Courtier-Dutton 
456*511cbe8fSOswald Buddenhagen 	if (val >= emu_ri->n_srcs)
457aa299d01STakashi Iwai 		return -EINVAL;
458*511cbe8fSOswald Buddenhagen 	if (channel >= emu_ri->n_ins)
45974415a36SJames Courtier-Dutton 		return -EINVAL;
460*511cbe8fSOswald Buddenhagen 	change = (emu->emu1010.input_source[channel] != val);
461*511cbe8fSOswald Buddenhagen 	if (change) {
462aa299d01STakashi Iwai 		emu->emu1010.input_source[channel] = val;
463*511cbe8fSOswald Buddenhagen 		snd_emu1010_input_source_apply(emu, channel, val);
464*511cbe8fSOswald Buddenhagen 	}
465*511cbe8fSOswald Buddenhagen 	return change;
4669f4bd5ddSJames Courtier-Dutton }
4679f4bd5ddSJames Courtier-Dutton 
468536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_input_source_ctl = {
469536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
470536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
471536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
472536438f1SOswald Buddenhagen 	.get = snd_emu1010_input_source_get,
473536438f1SOswald Buddenhagen 	.put = snd_emu1010_input_source_put
4749f4bd5ddSJames Courtier-Dutton };
4759f4bd5ddSJames Courtier-Dutton 
4761c02e366SCtirad Fertr 
477536438f1SOswald Buddenhagen static const char * const snd_emu1010_adc_pads[] = {
478536438f1SOswald Buddenhagen 	"ADC1 14dB PAD Audio Dock Capture Switch",
479536438f1SOswald Buddenhagen 	"ADC2 14dB PAD Audio Dock Capture Switch",
480536438f1SOswald Buddenhagen 	"ADC3 14dB PAD Audio Dock Capture Switch",
481536438f1SOswald Buddenhagen 	"ADC1 14dB PAD 0202 Capture Switch",
4821c02e366SCtirad Fertr };
4831c02e366SCtirad Fertr 
484536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_adc_pad_regs[] = {
485536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD1,
486536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD2,
487536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD3,
488536438f1SOswald Buddenhagen 	EMU_HANA_0202_ADC_PAD1,
4899148cc50SJames Courtier-Dutton };
4909148cc50SJames Courtier-Dutton 
491a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
4929148cc50SJames Courtier-Dutton 
4939148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4949148cc50SJames Courtier-Dutton {
4959148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
496536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
497536438f1SOswald Buddenhagen 
4989148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
4999148cc50SJames Courtier-Dutton 	return 0;
5009148cc50SJames Courtier-Dutton }
5019148cc50SJames Courtier-Dutton 
5029148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5039148cc50SJames Courtier-Dutton {
5049148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
505536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
5069148cc50SJames Courtier-Dutton 	unsigned int val, cache;
5079148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
5089148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
5099148cc50SJames Courtier-Dutton 	if (val == 1)
5109148cc50SJames Courtier-Dutton 		cache = cache | mask;
5119148cc50SJames Courtier-Dutton 	else
5129148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
5139148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
5149148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
5159148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
5169148cc50SJames Courtier-Dutton 	}
5179148cc50SJames Courtier-Dutton 
5189148cc50SJames Courtier-Dutton 	return 0;
5199148cc50SJames Courtier-Dutton }
5209148cc50SJames Courtier-Dutton 
521536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_adc_pads_ctl = {
522536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
523536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
524536438f1SOswald Buddenhagen 	.info = snd_emu1010_adc_pads_info,
525536438f1SOswald Buddenhagen 	.get = snd_emu1010_adc_pads_get,
526536438f1SOswald Buddenhagen 	.put = snd_emu1010_adc_pads_put
527536438f1SOswald Buddenhagen };
5289148cc50SJames Courtier-Dutton 
5299148cc50SJames Courtier-Dutton 
530536438f1SOswald Buddenhagen static const char * const snd_emu1010_dac_pads[] = {
531536438f1SOswald Buddenhagen 	"DAC1 Audio Dock 14dB PAD Playback Switch",
532536438f1SOswald Buddenhagen 	"DAC2 Audio Dock 14dB PAD Playback Switch",
533536438f1SOswald Buddenhagen 	"DAC3 Audio Dock 14dB PAD Playback Switch",
534536438f1SOswald Buddenhagen 	"DAC4 Audio Dock 14dB PAD Playback Switch",
535536438f1SOswald Buddenhagen 	"DAC1 0202 14dB PAD Playback Switch",
536536438f1SOswald Buddenhagen };
5379148cc50SJames Courtier-Dutton 
538536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_dac_regs[] = {
539536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD1,
540536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD2,
541536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD3,
542536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD4,
543536438f1SOswald Buddenhagen 	EMU_HANA_0202_DAC_PAD1,
5449148cc50SJames Courtier-Dutton };
5459148cc50SJames Courtier-Dutton 
546a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
5479148cc50SJames Courtier-Dutton 
5489148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5499148cc50SJames Courtier-Dutton {
5509148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
551536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
552536438f1SOswald Buddenhagen 
5539148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
5549148cc50SJames Courtier-Dutton 	return 0;
5559148cc50SJames Courtier-Dutton }
5569148cc50SJames Courtier-Dutton 
5579148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5589148cc50SJames Courtier-Dutton {
5599148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
560536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
5619148cc50SJames Courtier-Dutton 	unsigned int val, cache;
5629148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
5639148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
5649148cc50SJames Courtier-Dutton 	if (val == 1)
5659148cc50SJames Courtier-Dutton 		cache = cache | mask;
5669148cc50SJames Courtier-Dutton 	else
5679148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
5689148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.dac_pads) {
5699148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
5709148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
5719148cc50SJames Courtier-Dutton 	}
5729148cc50SJames Courtier-Dutton 
5739148cc50SJames Courtier-Dutton 	return 0;
5749148cc50SJames Courtier-Dutton }
5759148cc50SJames Courtier-Dutton 
576536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_dac_pads_ctl = {
577536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
578536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
579536438f1SOswald Buddenhagen 	.info = snd_emu1010_dac_pads_info,
580536438f1SOswald Buddenhagen 	.get = snd_emu1010_dac_pads_get,
581536438f1SOswald Buddenhagen 	.put = snd_emu1010_dac_pads_put
5829f4bd5ddSJames Courtier-Dutton };
5839f4bd5ddSJames Courtier-Dutton 
584b0dbdaeaSJames Courtier-Dutton 
585b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
586b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
587b0dbdaeaSJames Courtier-Dutton {
5881541c66dSTakashi Iwai 	static const char * const texts[4] = {
589edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
590b0dbdaeaSJames Courtier-Dutton 	};
591b0dbdaeaSJames Courtier-Dutton 
5921541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 4, texts);
593b0dbdaeaSJames Courtier-Dutton }
594b0dbdaeaSJames Courtier-Dutton 
595b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
596b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
597b0dbdaeaSJames Courtier-Dutton {
598b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
599b0dbdaeaSJames Courtier-Dutton 
600b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
601b0dbdaeaSJames Courtier-Dutton 	return 0;
602b0dbdaeaSJames Courtier-Dutton }
603b0dbdaeaSJames Courtier-Dutton 
604b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
605b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
606b0dbdaeaSJames Courtier-Dutton {
607b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
608b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
609b0dbdaeaSJames Courtier-Dutton 	int change = 0;
610b0dbdaeaSJames Courtier-Dutton 
611b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
61274415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 4; */
61374415a36SJames Courtier-Dutton 	if (val >= 4)
61474415a36SJames Courtier-Dutton 		return -EINVAL;
615b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
616b0dbdaeaSJames Courtier-Dutton 	if (change) {
617b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
618b0dbdaeaSJames Courtier-Dutton 		switch (val) {
619b0dbdaeaSJames Courtier-Dutton 		case 0:
620b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
621b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
622b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
623a869057cSOswald Buddenhagen 			/* Default fallback clock 44.1kHz */
624b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
625b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
626b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
627b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
628b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
629b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
630b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
631b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
632e40a0b2eSJames Courtier-Dutton 			msleep(10);
633b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
634b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
635b0dbdaeaSJames Courtier-Dutton 			break;
636b0dbdaeaSJames Courtier-Dutton 		case 1:
637b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
638b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
639b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
640b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
641b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
642b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
643b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
644b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
645b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
646b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
647b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
648b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
649e40a0b2eSJames Courtier-Dutton 			msleep(10);
650b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
651b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
652b0dbdaeaSJames Courtier-Dutton 			break;
653edec7bbbSJames Courtier-Dutton 
654edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
655edec7bbbSJames Courtier-Dutton 			/* Mute all */
656edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
657edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
658edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
659edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
660edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
661edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
662edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
663edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
664edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
665edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
666edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
667edec7bbbSJames Courtier-Dutton 			msleep(10);
668edec7bbbSJames Courtier-Dutton 			/* Unmute all */
669edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
670edec7bbbSJames Courtier-Dutton 			break;
671edec7bbbSJames Courtier-Dutton 
672edec7bbbSJames Courtier-Dutton 		case 3:
673edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
674edec7bbbSJames Courtier-Dutton 			/* Mute all */
675edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
676edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
677edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
678edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
679edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
680edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
681edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
682edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
683edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
684edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
685edec7bbbSJames Courtier-Dutton 			msleep(10);
686edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
687edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
688edec7bbbSJames Courtier-Dutton 
689edec7bbbSJames Courtier-Dutton 
690edec7bbbSJames Courtier-Dutton 			break;
691b0dbdaeaSJames Courtier-Dutton 		}
692b0dbdaeaSJames Courtier-Dutton 	}
693b0dbdaeaSJames Courtier-Dutton         return change;
694b0dbdaeaSJames Courtier-Dutton }
695b0dbdaeaSJames Courtier-Dutton 
696f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock =
697b0dbdaeaSJames Courtier-Dutton {
698b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
699b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
700b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
701b0dbdaeaSJames Courtier-Dutton 	.count =	1,
702b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
703b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
704b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
705b0dbdaeaSJames Courtier-Dutton };
706b0dbdaeaSJames Courtier-Dutton 
70799dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
70899dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
70999dcab46SMichael Gernoth {
71099dcab46SMichael Gernoth 	static const char * const texts[2] = {
71199dcab46SMichael Gernoth 		"SPDIF", "ADAT"
71299dcab46SMichael Gernoth 	};
71399dcab46SMichael Gernoth 
71499dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
71599dcab46SMichael Gernoth }
71699dcab46SMichael Gernoth 
71799dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol,
71899dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
71999dcab46SMichael Gernoth {
72099dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
72199dcab46SMichael Gernoth 
72299dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out;
72399dcab46SMichael Gernoth 	return 0;
72499dcab46SMichael Gernoth }
72599dcab46SMichael Gernoth 
72699dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
72799dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
72899dcab46SMichael Gernoth {
72999dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
73099dcab46SMichael Gernoth 	unsigned int val;
73199dcab46SMichael Gernoth 	u32 tmp;
73299dcab46SMichael Gernoth 	int change = 0;
73399dcab46SMichael Gernoth 
73499dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
73599dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
73699dcab46SMichael Gernoth 	if (val >= 2)
73799dcab46SMichael Gernoth 		return -EINVAL;
73899dcab46SMichael Gernoth 	change = (emu->emu1010.optical_out != val);
73999dcab46SMichael Gernoth 	if (change) {
74099dcab46SMichael Gernoth 		emu->emu1010.optical_out = val;
7419d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
7429d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
74399dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
74499dcab46SMichael Gernoth 	}
74599dcab46SMichael Gernoth 	return change;
74699dcab46SMichael Gernoth }
74799dcab46SMichael Gernoth 
748f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = {
74999dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
75099dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
75199dcab46SMichael Gernoth 	.name =         "Optical Output Mode",
75299dcab46SMichael Gernoth 	.count =	1,
75399dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_out_info,
75499dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_out_get,
75599dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_out_put
75699dcab46SMichael Gernoth };
75799dcab46SMichael Gernoth 
75899dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
75999dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
76099dcab46SMichael Gernoth {
76199dcab46SMichael Gernoth 	static const char * const texts[2] = {
76299dcab46SMichael Gernoth 		"SPDIF", "ADAT"
76399dcab46SMichael Gernoth 	};
76499dcab46SMichael Gernoth 
76599dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
76699dcab46SMichael Gernoth }
76799dcab46SMichael Gernoth 
76899dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
76999dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
77099dcab46SMichael Gernoth {
77199dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
77299dcab46SMichael Gernoth 
77399dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
77499dcab46SMichael Gernoth 	return 0;
77599dcab46SMichael Gernoth }
77699dcab46SMichael Gernoth 
77799dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
77899dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
77999dcab46SMichael Gernoth {
78099dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
78199dcab46SMichael Gernoth 	unsigned int val;
78299dcab46SMichael Gernoth 	u32 tmp;
78399dcab46SMichael Gernoth 	int change = 0;
78499dcab46SMichael Gernoth 
78599dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
78699dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
78799dcab46SMichael Gernoth 	if (val >= 2)
78899dcab46SMichael Gernoth 		return -EINVAL;
78999dcab46SMichael Gernoth 	change = (emu->emu1010.optical_in != val);
79099dcab46SMichael Gernoth 	if (change) {
79199dcab46SMichael Gernoth 		emu->emu1010.optical_in = val;
7929d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
7939d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
79499dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
79599dcab46SMichael Gernoth 	}
79699dcab46SMichael Gernoth 	return change;
79799dcab46SMichael Gernoth }
79899dcab46SMichael Gernoth 
799f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = {
80099dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
80199dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
80299dcab46SMichael Gernoth 	.name =         "Optical Input Mode",
80399dcab46SMichael Gernoth 	.count =	1,
80499dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_in_info,
80599dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_in_get,
80699dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_in_put
80799dcab46SMichael Gernoth };
80899dcab46SMichael Gernoth 
809184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
810184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
811184c1e2cSJames Courtier-Dutton {
812184c1e2cSJames Courtier-Dutton #if 0
8131541c66dSTakashi Iwai 	static const char * const texts[4] = {
814184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
815184c1e2cSJames Courtier-Dutton 	};
816184c1e2cSJames Courtier-Dutton #endif
8171541c66dSTakashi Iwai 	static const char * const texts[2] = {
818184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
819184c1e2cSJames Courtier-Dutton 	};
820184c1e2cSJames Courtier-Dutton 
8211541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
822184c1e2cSJames Courtier-Dutton }
823184c1e2cSJames Courtier-Dutton 
824184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
825184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
826184c1e2cSJames Courtier-Dutton {
827184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
828184c1e2cSJames Courtier-Dutton 
829184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
830184c1e2cSJames Courtier-Dutton 	return 0;
831184c1e2cSJames Courtier-Dutton }
832184c1e2cSJames Courtier-Dutton 
833184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
834184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
835184c1e2cSJames Courtier-Dutton {
836184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
837184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
838184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
839a1c87c0bSOswald Buddenhagen 	u16 gpio;
840184c1e2cSJames Courtier-Dutton 	int change = 0;
841184c1e2cSJames Courtier-Dutton 	unsigned long flags;
842184c1e2cSJames Courtier-Dutton 	u32 source;
843184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
844184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
845184c1e2cSJames Courtier-Dutton 	 * for the particular source.
846184c1e2cSJames Courtier-Dutton 	 */
84774415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
84874415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
84974415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
85074415a36SJames Courtier-Dutton 	if (source_id >= 2)
85174415a36SJames Courtier-Dutton 		return -EINVAL;
852184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
853184c1e2cSJames Courtier-Dutton 	if (change) {
854184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
855184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
856a1c87c0bSOswald Buddenhagen 		gpio = inw(emu->port + A_IOCFG);
857184c1e2cSJames Courtier-Dutton 		if (source_id==0)
858a1c87c0bSOswald Buddenhagen 			outw(gpio | 0x4, emu->port + A_IOCFG);
859184c1e2cSJames Courtier-Dutton 		else
860a1c87c0bSOswald Buddenhagen 			outw(gpio & ~0x4, emu->port + A_IOCFG);
861184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
862184c1e2cSJames Courtier-Dutton 
863184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
864184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
865184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
866184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
867184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
868184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
869184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
870184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
871184c1e2cSJames Courtier-Dutton 
872184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
873184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
874184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
875184c1e2cSJames Courtier-Dutton 	}
876184c1e2cSJames Courtier-Dutton         return change;
877184c1e2cSJames Courtier-Dutton }
878184c1e2cSJames Courtier-Dutton 
879f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source =
880184c1e2cSJames Courtier-Dutton {
881184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
882184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
883184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
884184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
885184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
886184c1e2cSJames Courtier-Dutton };
887184c1e2cSJames Courtier-Dutton 
888184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
889184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
890184c1e2cSJames Courtier-Dutton {
891184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
892184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
893184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
894184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
895184c1e2cSJames Courtier-Dutton 	return 0;
896184c1e2cSJames Courtier-Dutton }
897184c1e2cSJames Courtier-Dutton 
898184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
899184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
900184c1e2cSJames Courtier-Dutton {
901184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
90274415a36SJames Courtier-Dutton 	unsigned int source_id;
903184c1e2cSJames Courtier-Dutton 
904184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
90574415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
90674415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
90774415a36SJames Courtier-Dutton 	if (source_id >= 2)
90874415a36SJames Courtier-Dutton 		return -EINVAL;
909184c1e2cSJames Courtier-Dutton 
910184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
911184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
912184c1e2cSJames Courtier-Dutton 	return 0;
913184c1e2cSJames Courtier-Dutton }
914184c1e2cSJames Courtier-Dutton 
915184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
916184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
917184c1e2cSJames Courtier-Dutton {
918184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
919184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
92014a29565SOswald Buddenhagen 	unsigned int ngain0, ngain1;
92174415a36SJames Courtier-Dutton 	unsigned int source_id;
922184c1e2cSJames Courtier-Dutton 	int change = 0;
923184c1e2cSJames Courtier-Dutton 
924184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
92574415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
92674415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
92774415a36SJames Courtier-Dutton 	if (source_id >= 2)
92874415a36SJames Courtier-Dutton 		return -EINVAL;
92914a29565SOswald Buddenhagen 	ngain0 = ucontrol->value.integer.value[0];
93014a29565SOswald Buddenhagen 	ngain1 = ucontrol->value.integer.value[1];
93114a29565SOswald Buddenhagen 	if (ngain0 > 0xff)
93214a29565SOswald Buddenhagen 		return -EINVAL;
93314a29565SOswald Buddenhagen 	if (ngain1 > 0xff)
93414a29565SOswald Buddenhagen 		return -EINVAL;
935184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
93614a29565SOswald Buddenhagen 	if (ogain != ngain0) {
937184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
93814a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0);
93914a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][0] = ngain0;
940184c1e2cSJames Courtier-Dutton 		change = 1;
941184c1e2cSJames Courtier-Dutton 	}
942184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
94314a29565SOswald Buddenhagen 	if (ogain != ngain1) {
944184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
94514a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1);
94614a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][1] = ngain1;
947184c1e2cSJames Courtier-Dutton 		change = 1;
948184c1e2cSJames Courtier-Dutton 	}
949184c1e2cSJames Courtier-Dutton 
950184c1e2cSJames Courtier-Dutton 	return change;
951184c1e2cSJames Courtier-Dutton }
952184c1e2cSJames Courtier-Dutton 
953536438f1SOswald Buddenhagen static const struct snd_kcontrol_new i2c_volume_ctl = {
954536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
955536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
956536438f1SOswald Buddenhagen 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,
957536438f1SOswald Buddenhagen 	.info = snd_audigy_i2c_volume_info,
958536438f1SOswald Buddenhagen 	.get = snd_audigy_i2c_volume_get,
959536438f1SOswald Buddenhagen 	.put = snd_audigy_i2c_volume_put,
960536438f1SOswald Buddenhagen 	.tlv = { .p = snd_audigy_db_scale2 }
961536438f1SOswald Buddenhagen };
962184c1e2cSJames Courtier-Dutton 
963536438f1SOswald Buddenhagen static const char * const snd_audigy_i2c_volume_ctls[] = {
964536438f1SOswald Buddenhagen 	"Mic Capture Volume",
965536438f1SOswald Buddenhagen 	"Line Capture Volume",
966184c1e2cSJames Courtier-Dutton };
967184c1e2cSJames Courtier-Dutton 
9680af68e5eSTakashi Iwai #if 0
969eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9701da177e4SLinus Torvalds {
9711541c66dSTakashi Iwai 	static const char * const texts[] = {"44100", "48000", "96000"};
9721da177e4SLinus Torvalds 
9731541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 3, texts);
9741da177e4SLinus Torvalds }
9751da177e4SLinus Torvalds 
976eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
977eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
9781da177e4SLinus Torvalds {
979eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
9801da177e4SLinus Torvalds 	unsigned int tmp;
9811da177e4SLinus Torvalds 
9821da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
9831da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
9841da177e4SLinus Torvalds 	case A_SPDIF_44100:
9851da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
9861da177e4SLinus Torvalds 		break;
9871da177e4SLinus Torvalds 	case A_SPDIF_48000:
9881da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
9891da177e4SLinus Torvalds 		break;
9901da177e4SLinus Torvalds 	case A_SPDIF_96000:
9911da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
9921da177e4SLinus Torvalds 		break;
9931da177e4SLinus Torvalds 	default:
9941da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
9951da177e4SLinus Torvalds 	}
9961da177e4SLinus Torvalds 	return 0;
9971da177e4SLinus Torvalds }
9981da177e4SLinus Torvalds 
999eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
1000eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10011da177e4SLinus Torvalds {
1002eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10031da177e4SLinus Torvalds 	int change;
10041da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
10051da177e4SLinus Torvalds 	unsigned long flags;
10061da177e4SLinus Torvalds 
10071da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
10081da177e4SLinus Torvalds 	case 0:
10091da177e4SLinus Torvalds 		val = A_SPDIF_44100;
10101da177e4SLinus Torvalds 		break;
10111da177e4SLinus Torvalds 	case 1:
10121da177e4SLinus Torvalds 		val = A_SPDIF_48000;
10131da177e4SLinus Torvalds 		break;
10141da177e4SLinus Torvalds 	case 2:
10151da177e4SLinus Torvalds 		val = A_SPDIF_96000;
10161da177e4SLinus Torvalds 		break;
10171da177e4SLinus Torvalds 	default:
10181da177e4SLinus Torvalds 		val = A_SPDIF_48000;
10191da177e4SLinus Torvalds 		break;
10201da177e4SLinus Torvalds 	}
10211da177e4SLinus Torvalds 
10221da177e4SLinus Torvalds 
10231da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10241da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
10251da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
10261da177e4SLinus Torvalds 	tmp |= val;
102712bda107STakashi Iwai 	change = (tmp != reg);
102812bda107STakashi Iwai 	if (change)
10291da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
10301da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10311da177e4SLinus Torvalds 	return change;
10321da177e4SLinus Torvalds }
10331da177e4SLinus Torvalds 
1034b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate =
10351da177e4SLinus Torvalds {
10361da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
10371da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
10381da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
10391da177e4SLinus Torvalds 	.count =	1,
10401da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
10411da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
10421da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
10431da177e4SLinus Torvalds };
10440af68e5eSTakashi Iwai #endif
10451da177e4SLinus Torvalds 
1046eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1047eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10481da177e4SLinus Torvalds {
1049eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10501da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
10511da177e4SLinus Torvalds 	int change;
10521da177e4SLinus Torvalds 	unsigned int val;
10531da177e4SLinus Torvalds 
105474415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
105574415a36SJames Courtier-Dutton 	if (idx >= 3)
105674415a36SJames Courtier-Dutton 		return -EINVAL;
10571da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
10581da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
10591da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
10601da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
10611da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
10621da177e4SLinus Torvalds 	if (change) {
10631da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
10641da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
10651da177e4SLinus Torvalds 	}
10661da177e4SLinus Torvalds 	return change;
10671da177e4SLinus Torvalds }
10681da177e4SLinus Torvalds 
1069f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
10701da177e4SLinus Torvalds {
10711da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
10725549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
10731da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
10747583cb51STakashi Iwai 	.count =	3,
10751da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
10761da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
10771da177e4SLinus Torvalds };
10781da177e4SLinus Torvalds 
1079f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
10801da177e4SLinus Torvalds {
10815549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
10821da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
10837583cb51STakashi Iwai 	.count =	3,
10841da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
10851da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
10861da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
10871da177e4SLinus Torvalds };
10881da177e4SLinus Torvalds 
10891da177e4SLinus Torvalds 
1090eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
10911da177e4SLinus Torvalds {
10921da177e4SLinus Torvalds 	if (emu->audigy) {
10931da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
10941da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
10951da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
10961da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
10971da177e4SLinus Torvalds 	} else {
10981da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
10991da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
11001da177e4SLinus Torvalds 	}
11011da177e4SLinus Torvalds }
11021da177e4SLinus Torvalds 
1103eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
11041da177e4SLinus Torvalds {
11051da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
11061da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
11071da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
11081da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
11091da177e4SLinus Torvalds 	if (emu->audigy) {
111051d652f4SOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice,
111151d652f4SOswald Buddenhagen 				      snd_emu10k1_compose_audigy_sendamounts(volume));
11121da177e4SLinus Torvalds 	}
11131da177e4SLinus Torvalds }
11141da177e4SLinus Torvalds 
11151da177e4SLinus Torvalds /* PCM stream controls */
11161da177e4SLinus Torvalds 
1117eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11181da177e4SLinus Torvalds {
1119eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11201da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
11211da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
11221da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11231da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
11241da177e4SLinus Torvalds 	return 0;
11251da177e4SLinus Torvalds }
11261da177e4SLinus Torvalds 
1127eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1128eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11291da177e4SLinus Torvalds {
1130eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1131eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1132eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11331da177e4SLinus Torvalds 	int voice, idx;
11341da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11351da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11361da177e4SLinus Torvalds 
11371da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
11381da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
11391da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
11401da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
11411da177e4SLinus Torvalds 	return 0;
11421da177e4SLinus Torvalds }
11431da177e4SLinus Torvalds 
1144eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1145eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11461da177e4SLinus Torvalds {
11471da177e4SLinus Torvalds 	unsigned long flags;
1148eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1149eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1150eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11511da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
11521da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11531da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11541da177e4SLinus Torvalds 
11551da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11561da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
11571da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
11581da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
11591da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
11601da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
11611da177e4SLinus Torvalds 				change = 1;
11621da177e4SLinus Torvalds 			}
11631da177e4SLinus Torvalds 		}
11641da177e4SLinus Torvalds 	if (change && mix->epcm) {
11651da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
11661da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
11671da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
11681da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
11691da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
11701da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
11711da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
11721da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
11731da177e4SLinus Torvalds 		}
11741da177e4SLinus Torvalds 	}
11751da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11761da177e4SLinus Torvalds 	return change;
11771da177e4SLinus Torvalds }
11781da177e4SLinus Torvalds 
1179f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control =
11801da177e4SLinus Torvalds {
11811da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
118267ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11831da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
11841da177e4SLinus Torvalds 	.count =	32,
11851da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
11861da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
11871da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
11881da177e4SLinus Torvalds };
11891da177e4SLinus Torvalds 
1190eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11911da177e4SLinus Torvalds {
1192eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11931da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
11941da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
11951da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11961da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
11971da177e4SLinus Torvalds 	return 0;
11981da177e4SLinus Torvalds }
11991da177e4SLinus Torvalds 
1200eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1201eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12021da177e4SLinus Torvalds {
1203eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1204eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1205eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12061da177e4SLinus Torvalds 	int idx;
12071da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12081da177e4SLinus Torvalds 
12091da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
12101da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
12111da177e4SLinus Torvalds 	return 0;
12121da177e4SLinus Torvalds }
12131da177e4SLinus Torvalds 
1214eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1215eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12161da177e4SLinus Torvalds {
12171da177e4SLinus Torvalds 	unsigned long flags;
1218eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1219eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1220eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12211da177e4SLinus Torvalds 	int change = 0, idx, val;
12221da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12231da177e4SLinus Torvalds 
12241da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12251da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
12261da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
12271da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
12281da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
12291da177e4SLinus Torvalds 			change = 1;
12301da177e4SLinus Torvalds 		}
12311da177e4SLinus Torvalds 	}
12321da177e4SLinus Torvalds 	if (change && mix->epcm) {
12331da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
12341da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
12351da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
12361da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
12371da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
12381da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
12391da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
12401da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
12411da177e4SLinus Torvalds 		}
12421da177e4SLinus Torvalds 	}
12431da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12441da177e4SLinus Torvalds 	return change;
12451da177e4SLinus Torvalds }
12461da177e4SLinus Torvalds 
1247f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
12481da177e4SLinus Torvalds {
12491da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
125067ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12511da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
12521da177e4SLinus Torvalds 	.count =	32,
12531da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
12541da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
12551da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
12561da177e4SLinus Torvalds };
12571da177e4SLinus Torvalds 
1258eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12591da177e4SLinus Torvalds {
12601da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12611da177e4SLinus Torvalds 	uinfo->count = 3;
12621da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1263bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
12641da177e4SLinus Torvalds 	return 0;
12651da177e4SLinus Torvalds }
12661da177e4SLinus Torvalds 
1267eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1268eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
12691da177e4SLinus Torvalds {
1270eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1271eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1272eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12731da177e4SLinus Torvalds 	int idx;
12741da177e4SLinus Torvalds 
12751da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
1276bcdbd3b7SOswald Buddenhagen 		ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U;
12771da177e4SLinus Torvalds 	return 0;
12781da177e4SLinus Torvalds }
12791da177e4SLinus Torvalds 
1280eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1281eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
12821da177e4SLinus Torvalds {
12831da177e4SLinus Torvalds 	unsigned long flags;
1284eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1285eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1286eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12871da177e4SLinus Torvalds 	int change = 0, idx, val;
12881da177e4SLinus Torvalds 
12891da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12901da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
1291bcdbd3b7SOswald Buddenhagen 		unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff;
1292bcdbd3b7SOswald Buddenhagen 		val = uval * 0x8000U / 0xffffU;
12931da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
12941da177e4SLinus Torvalds 			mix->attn[idx] = val;
12951da177e4SLinus Torvalds 			change = 1;
12961da177e4SLinus Torvalds 		}
12971da177e4SLinus Torvalds 	}
12981da177e4SLinus Torvalds 	if (change && mix->epcm) {
12991da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
13001da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
13011da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
13021da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
13031da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
13041da177e4SLinus Torvalds 		}
13051da177e4SLinus Torvalds 	}
13061da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13071da177e4SLinus Torvalds 	return change;
13081da177e4SLinus Torvalds }
13091da177e4SLinus Torvalds 
1310f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control =
13111da177e4SLinus Torvalds {
13121da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
131367ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13141da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
13151da177e4SLinus Torvalds 	.count =	32,
13161da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
13171da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
13181da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
13191da177e4SLinus Torvalds };
13201da177e4SLinus Torvalds 
13211da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
13221da177e4SLinus Torvalds 
1323eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13241da177e4SLinus Torvalds {
1325eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13261da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13271da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
13281da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13291da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
13301da177e4SLinus Torvalds 	return 0;
13311da177e4SLinus Torvalds }
13321da177e4SLinus Torvalds 
1333eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1334eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
13351da177e4SLinus Torvalds {
1336eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1337eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1338eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13391da177e4SLinus Torvalds 	int idx;
13401da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13411da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
13421da177e4SLinus Torvalds 
13431da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
13441da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
13451da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
13461da177e4SLinus Torvalds 	return 0;
13471da177e4SLinus Torvalds }
13481da177e4SLinus Torvalds 
1349eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1350eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
13511da177e4SLinus Torvalds {
13521da177e4SLinus Torvalds 	unsigned long flags;
1353eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13541da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1355eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
13561da177e4SLinus Torvalds 	int change = 0, idx, val;
13571da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13581da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
13591da177e4SLinus Torvalds 
13601da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13611da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
13621da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
13631da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
13641da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
13651da177e4SLinus Torvalds 			change = 1;
13661da177e4SLinus Torvalds 		}
13671da177e4SLinus Torvalds 	}
13681da177e4SLinus Torvalds 
13691da177e4SLinus Torvalds 	if (change && mix->epcm) {
13701da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
13711da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
13721da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
13731da177e4SLinus Torvalds 		}
13741da177e4SLinus Torvalds 	}
13751da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13761da177e4SLinus Torvalds 	return change;
13771da177e4SLinus Torvalds }
13781da177e4SLinus Torvalds 
1379f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
13801da177e4SLinus Torvalds {
13811da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
13821da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13831da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
13841da177e4SLinus Torvalds 	.count =	16,
13851da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
13861da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
13871da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
13881da177e4SLinus Torvalds };
13891da177e4SLinus Torvalds 
1390eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13911da177e4SLinus Torvalds {
1392eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13931da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13941da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
13951da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13961da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
13971da177e4SLinus Torvalds 	return 0;
13981da177e4SLinus Torvalds }
13991da177e4SLinus Torvalds 
1400eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1401eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
14021da177e4SLinus Torvalds {
1403eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1404eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1405eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14061da177e4SLinus Torvalds 	int idx;
14071da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14081da177e4SLinus Torvalds 
14091da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
14101da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
14111da177e4SLinus Torvalds 	return 0;
14121da177e4SLinus Torvalds }
14131da177e4SLinus Torvalds 
1414eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1415eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
14161da177e4SLinus Torvalds {
14171da177e4SLinus Torvalds 	unsigned long flags;
1418eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14191da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1420eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
14211da177e4SLinus Torvalds 	int change = 0, idx, val;
14221da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14231da177e4SLinus Torvalds 
14241da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14251da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
14261da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
14271da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
14281da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
14291da177e4SLinus Torvalds 			change = 1;
14301da177e4SLinus Torvalds 		}
14311da177e4SLinus Torvalds 	}
14321da177e4SLinus Torvalds 	if (change && mix->epcm) {
14331da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
14341da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
14351da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
14361da177e4SLinus Torvalds 		}
14371da177e4SLinus Torvalds 	}
14381da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14391da177e4SLinus Torvalds 	return change;
14401da177e4SLinus Torvalds }
14411da177e4SLinus Torvalds 
14421da177e4SLinus Torvalds 
1443f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
14441da177e4SLinus Torvalds {
14451da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
14461da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14471da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
14481da177e4SLinus Torvalds 	.count =	16,
14491da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
14501da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
14511da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
14521da177e4SLinus Torvalds };
14531da177e4SLinus Torvalds 
1454eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14551da177e4SLinus Torvalds {
14561da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14571da177e4SLinus Torvalds 	uinfo->count = 1;
14581da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1459bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
14601da177e4SLinus Torvalds 	return 0;
14611da177e4SLinus Torvalds }
14621da177e4SLinus Torvalds 
1463eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1464eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
14651da177e4SLinus Torvalds {
1466eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1467eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1468eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14691da177e4SLinus Torvalds 
1470bcdbd3b7SOswald Buddenhagen 	ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U;
14711da177e4SLinus Torvalds 	return 0;
14721da177e4SLinus Torvalds }
14731da177e4SLinus Torvalds 
1474eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1475eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
14761da177e4SLinus Torvalds {
14771da177e4SLinus Torvalds 	unsigned long flags;
1478eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14791da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1480eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
14811da177e4SLinus Torvalds 	int change = 0, val;
1482bcdbd3b7SOswald Buddenhagen 	unsigned uval;
14831da177e4SLinus Torvalds 
14841da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1485bcdbd3b7SOswald Buddenhagen 	uval = ucontrol->value.integer.value[0] & 0x1ffff;
1486bcdbd3b7SOswald Buddenhagen 	val = uval * 0x8000U / 0xffffU;
14871da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
14881da177e4SLinus Torvalds 		mix->attn[0] = val;
14891da177e4SLinus Torvalds 		change = 1;
14901da177e4SLinus Torvalds 	}
14911da177e4SLinus Torvalds 	if (change && mix->epcm) {
14921da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
14931da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
14941da177e4SLinus Torvalds 		}
14951da177e4SLinus Torvalds 	}
14961da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14971da177e4SLinus Torvalds 	return change;
14981da177e4SLinus Torvalds }
14991da177e4SLinus Torvalds 
1500f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
15011da177e4SLinus Torvalds {
15021da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15031da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15041da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
15051da177e4SLinus Torvalds 	.count =	16,
15061da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
15071da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
15081da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
15091da177e4SLinus Torvalds };
15101da177e4SLinus Torvalds 
1511a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
15121da177e4SLinus Torvalds 
1513eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1514eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
15151da177e4SLinus Torvalds {
1516eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15171da177e4SLinus Torvalds 
15181da177e4SLinus Torvalds 	if (emu->audigy)
1519a1c87c0bSOswald Buddenhagen 		ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
15201da177e4SLinus Torvalds 	else
15211da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1522d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1523d2cd74b1STakashi Iwai 		ucontrol->value.integer.value[0] =
1524d2cd74b1STakashi Iwai 			!ucontrol->value.integer.value[0];
1525d2cd74b1STakashi Iwai 
15261da177e4SLinus Torvalds 	return 0;
15271da177e4SLinus Torvalds }
15281da177e4SLinus Torvalds 
1529eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1530eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
15311da177e4SLinus Torvalds {
15321da177e4SLinus Torvalds 	unsigned long flags;
1533eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1534d2cd74b1STakashi Iwai 	unsigned int reg, val, sw;
15351da177e4SLinus Torvalds 	int change = 0;
15361da177e4SLinus Torvalds 
1537d2cd74b1STakashi Iwai 	sw = ucontrol->value.integer.value[0];
1538d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1539d2cd74b1STakashi Iwai 		sw = !sw;
154050164f69SOswald Buddenhagen 	spin_lock_irqsave(&emu->emu_lock, flags);
1541184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1542184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1543184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
1544a1c87c0bSOswald Buddenhagen 		reg = inw(emu->port + A_IOCFG);
1545d2cd74b1STakashi Iwai 		val = sw ? A_IOCFG_GPOUT0 : 0;
15461da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
15471da177e4SLinus Torvalds 		if (change) {
15481da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
15491da177e4SLinus Torvalds 			reg |= val;
1550a1c87c0bSOswald Buddenhagen 			outw(reg | val, emu->port + A_IOCFG);
15511da177e4SLinus Torvalds 		}
15521da177e4SLinus Torvalds 	}
15531da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
1554d2cd74b1STakashi Iwai 	val = sw ? HCFG_GPOUT0 : 0;
15551da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
15561da177e4SLinus Torvalds 	if (change) {
15571da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
15581da177e4SLinus Torvalds 		reg |= val;
15591da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
15601da177e4SLinus Torvalds 	}
156150164f69SOswald Buddenhagen 	spin_unlock_irqrestore(&emu->emu_lock, flags);
15621da177e4SLinus Torvalds 	return change;
15631da177e4SLinus Torvalds }
15641da177e4SLinus Torvalds 
1565f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
15661da177e4SLinus Torvalds {
15671da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
15681da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
15691da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
15701da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
15711da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
15721da177e4SLinus Torvalds };
15731da177e4SLinus Torvalds 
1574f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif =
15751da177e4SLinus Torvalds {
15761da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
15771da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
15781da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
15791da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
15801da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
15811da177e4SLinus Torvalds };
15821da177e4SLinus Torvalds 
158316950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
158416950e09STakashi Iwai 
158516950e09STakashi Iwai #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
158616950e09STakashi Iwai 
158716950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
158816950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
158916950e09STakashi Iwai {
159016950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
159116950e09STakashi Iwai 	unsigned int val;
159216950e09STakashi Iwai 
159316950e09STakashi Iwai 	/* FIXME: better to use a cached version */
159416950e09STakashi Iwai 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
159516950e09STakashi Iwai 	ucontrol->value.integer.value[0] = !!val;
159616950e09STakashi Iwai 	return 0;
159716950e09STakashi Iwai }
159816950e09STakashi Iwai 
159916950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
160016950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
160116950e09STakashi Iwai {
160216950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
160316950e09STakashi Iwai 	unsigned int val;
160416950e09STakashi Iwai 
160516950e09STakashi Iwai 	if (ucontrol->value.integer.value[0])
160616950e09STakashi Iwai 		val = 0x0f0f;
160716950e09STakashi Iwai 	else
160816950e09STakashi Iwai 		val = 0;
160916950e09STakashi Iwai 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
161016950e09STakashi Iwai }
161116950e09STakashi Iwai 
1612f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost =
161316950e09STakashi Iwai {
161416950e09STakashi Iwai 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16152a52feb1SMaciej S. Szmigiero 	.name =		"Mic Extra Boost",
161616950e09STakashi Iwai 	.info =		snd_audigy_capture_boost_info,
161716950e09STakashi Iwai 	.get =		snd_audigy_capture_boost_get,
161816950e09STakashi Iwai 	.put =		snd_audigy_capture_boost_put
161916950e09STakashi Iwai };
162016950e09STakashi Iwai 
162116950e09STakashi Iwai 
16221da177e4SLinus Torvalds /*
16231da177e4SLinus Torvalds  */
1624eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
16251da177e4SLinus Torvalds {
1626eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
16271da177e4SLinus Torvalds 	emu->ac97 = NULL;
16281da177e4SLinus Torvalds }
16291da177e4SLinus Torvalds 
16301da177e4SLinus Torvalds /*
16311da177e4SLinus Torvalds  */
1632eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
16331da177e4SLinus Torvalds {
1634eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
16351da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
16361da177e4SLinus Torvalds 	strcpy(id.name, name);
16371da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
16381da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
16391da177e4SLinus Torvalds }
16401da177e4SLinus Torvalds 
1641eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
16421da177e4SLinus Torvalds {
1643eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
16441da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
16451da177e4SLinus Torvalds 	strcpy(sid.name, name);
16461da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
16471da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
16481da177e4SLinus Torvalds }
16491da177e4SLinus Torvalds 
1650eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
16511da177e4SLinus Torvalds {
1652eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
16531da177e4SLinus Torvalds 	if (kctl) {
165436476b81SMaciej S. Szmigiero 		snd_ctl_rename(card, kctl, dst);
16551da177e4SLinus Torvalds 		return 0;
16561da177e4SLinus Torvalds 	}
16571da177e4SLinus Torvalds 	return -ENOENT;
16581da177e4SLinus Torvalds }
16591da177e4SLinus Torvalds 
1660e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
166167ed4161SClemens Ladisch 		      int pcm_device, int multi_device)
16621da177e4SLinus Torvalds {
1663155e3d3bSOswald Buddenhagen 	int err;
1664eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1665eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
16666fddce26STakashi Iwai 	const char * const *c;
16676fddce26STakashi Iwai 	static const char * const emu10k1_remove_ctls[] = {
16681da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
16691da177e4SLinus Torvalds 		"Master Mono Playback Switch",
16701da177e4SLinus Torvalds 		"Master Mono Playback Volume",
16711da177e4SLinus Torvalds 		"PCM Out Path & Mute",
16721da177e4SLinus Torvalds 		"Mono Output Select",
16731da177e4SLinus Torvalds 		"Surround Playback Switch",
16741da177e4SLinus Torvalds 		"Surround Playback Volume",
16751da177e4SLinus Torvalds 		"Center Playback Switch",
16761da177e4SLinus Torvalds 		"Center Playback Volume",
16771da177e4SLinus Torvalds 		"LFE Playback Switch",
16781da177e4SLinus Torvalds 		"LFE Playback Volume",
16791da177e4SLinus Torvalds 		NULL
16801da177e4SLinus Torvalds 	};
16816fddce26STakashi Iwai 	static const char * const emu10k1_rename_ctls[] = {
16821da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
16831da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
16841da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
16851da177e4SLinus Torvalds 		NULL
16861da177e4SLinus Torvalds 	};
16876fddce26STakashi Iwai 	static const char * const audigy_remove_ctls[] = {
16881da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
168921fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
169021fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
16911da177e4SLinus Torvalds 		"PCM Playback Switch",
16921da177e4SLinus Torvalds 		"PCM Playback Volume",
16931da177e4SLinus Torvalds 		"Master Playback Switch",
16941da177e4SLinus Torvalds 		"Master Playback Volume",
16951da177e4SLinus Torvalds 		"PCM Out Path & Mute",
16961da177e4SLinus Torvalds 		"Mono Output Select",
16971da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
16981da177e4SLinus Torvalds 		"Capture Source",
16991da177e4SLinus Torvalds 		"Capture Switch",
17001da177e4SLinus Torvalds 		"Capture Volume",
17011da177e4SLinus Torvalds 		"Mic Select",
1702274b2000SMaciej S. Szmigiero 		"Headphone Playback Switch",
1703274b2000SMaciej S. Szmigiero 		"Headphone Playback Volume",
1704274b2000SMaciej S. Szmigiero 		"3D Control - Center",
1705274b2000SMaciej S. Szmigiero 		"3D Control - Depth",
1706274b2000SMaciej S. Szmigiero 		"3D Control - Switch",
17071da177e4SLinus Torvalds 		"Video Playback Switch",
17081da177e4SLinus Torvalds 		"Video Playback Volume",
17091da177e4SLinus Torvalds 		"Mic Playback Switch",
17101da177e4SLinus Torvalds 		"Mic Playback Volume",
1711274b2000SMaciej S. Szmigiero 		"External Amplifier",
17121da177e4SLinus Torvalds 		NULL
17131da177e4SLinus Torvalds 	};
17146fddce26STakashi Iwai 	static const char * const audigy_rename_ctls[] = {
17151da177e4SLinus Torvalds 		/* use conventional names */
17161da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
17171da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
17181da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
17191da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
172052051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
172152051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
17221da177e4SLinus Torvalds 		NULL
17231da177e4SLinus Torvalds 	};
17246fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_i2c_adc[] = {
1725184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1726184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1727184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1728184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1729184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1730eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1731184c1e2cSJames Courtier-Dutton 		NULL
1732184c1e2cSJames Courtier-Dutton 	};
17336fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_i2c_adc[] = {
1734184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1735184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1736184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1737184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1738184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1739eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1740184c1e2cSJames Courtier-Dutton 		NULL
1741184c1e2cSJames Courtier-Dutton 	};
17426fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_1361t_adc[] = {
174321fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
174421fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
174521fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
174621fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
174721fdddeaSJames Courtier-Dutton 		"Capture Source",
174821fdddeaSJames Courtier-Dutton 		"Capture Switch",
174921fdddeaSJames Courtier-Dutton 		"Capture Volume",
175021fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
175121fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
175221fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
175321fdddeaSJames Courtier-Dutton 		"3D Control - Center",
175421fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
175521fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
175621fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
175721fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
175821fdddeaSJames Courtier-Dutton 		NULL
175921fdddeaSJames Courtier-Dutton 	};
17606fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_1361t_adc[] = {
176121fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
176221fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
176321fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1764d355c82aSJaroslav Kysela 		"Beep Playback Switch", "Beep Capture Switch",
1765d355c82aSJaroslav Kysela 		"Beep Playback Volume", "Beep Capture Volume",
176621fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
176721fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
176821fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
176921fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
177021fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
177121fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
177221fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
177321fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
177421fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
177521fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
177621fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
177721fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
177852051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
177952051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
178021fdddeaSJames Courtier-Dutton 		NULL
178121fdddeaSJames Courtier-Dutton 	};
17821da177e4SLinus Torvalds 
17832b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1784eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1785eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
178651055da5STakashi Iwai 		static const struct snd_ac97_bus_ops ops = {
17871da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
17881da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
17891da177e4SLinus Torvalds 		};
17901da177e4SLinus Torvalds 
179112bda107STakashi Iwai 		err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus);
179212bda107STakashi Iwai 		if (err < 0)
17931da177e4SLinus Torvalds 			return err;
17941da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
17951da177e4SLinus Torvalds 
17961da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
17971da177e4SLinus Torvalds 		ac97.private_data = emu;
17981da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
17991da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
180012bda107STakashi Iwai 		err = snd_ac97_mixer(pbus, &ac97, &emu->ac97);
180112bda107STakashi Iwai 		if (err < 0) {
1802b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
18031da177e4SLinus Torvalds 				return err;
18046f002b02STakashi Iwai 			dev_info(emu->card->dev,
18056f002b02STakashi Iwai 				 "AC97 is optional on this board\n");
18066f002b02STakashi Iwai 			dev_info(emu->card->dev,
18076f002b02STakashi Iwai 				 "Proceeding without ac97 mixers...\n");
1808b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1809b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1810b1508693STakashi Iwai 		}
18111da177e4SLinus Torvalds 		if (emu->audigy) {
18121da177e4SLinus Torvalds 			/* set master volume to 0 dB */
18134d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
18141da177e4SLinus Torvalds 			/* set capture source to mic */
18154d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
181652051942SMaciej S. Szmigiero 			/* set mono output (TAD) to mic */
181752051942SMaciej S. Szmigiero 			snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE,
181852051942SMaciej S. Szmigiero 				0x0200, 0x0200);
181921fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
182021fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
182121fdddeaSJames Courtier-Dutton 			else
18221da177e4SLinus Torvalds 				c = audigy_remove_ctls;
18231da177e4SLinus Torvalds 		} else {
18241da177e4SLinus Torvalds 			/*
18251da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
18261da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
18271da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
18281da177e4SLinus Torvalds 			 */
18291da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
18301da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
18311da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
18322594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
1833b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Volume");
1834b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Switch");
18351da177e4SLinus Torvalds 			}
18361da177e4SLinus Torvalds 			/* remove unused AC97 controls */
18374d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
18384d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
18391da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
18401da177e4SLinus Torvalds 		}
18411da177e4SLinus Torvalds 		for (; *c; c++)
18421da177e4SLinus Torvalds 			remove_ctl(card, *c);
1843184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1844184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1845184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1846184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
18471da177e4SLinus Torvalds 	} else {
1848f12aa40cSTakashi Iwai 	no_ac97:
18492b637da5SLee Revell 		if (emu->card_capabilities->ecard)
18501da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
18511da177e4SLinus Torvalds 		else if (emu->audigy)
18521da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
18531da177e4SLinus Torvalds 		else
18541da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
18551da177e4SLinus Torvalds 	}
18561da177e4SLinus Torvalds 
18571da177e4SLinus Torvalds 	if (emu->audigy)
185821fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
185921fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1860184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1861184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
186221fdddeaSJames Courtier-Dutton 		else
18631da177e4SLinus Torvalds 			c = audigy_rename_ctls;
18641da177e4SLinus Torvalds 	else
18651da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
18661da177e4SLinus Torvalds 	for (; *c; c += 2)
18671da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
186821fdddeaSJames Courtier-Dutton 
1869e217b960SRaymond Yau 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
1870e217b960SRaymond Yau 		remove_ctl(card, "Center Playback Volume");
1871e217b960SRaymond Yau 		remove_ctl(card, "LFE Playback Volume");
1872e217b960SRaymond Yau 		remove_ctl(card, "Wave Center Playback Volume");
1873e217b960SRaymond Yau 		remove_ctl(card, "Wave LFE Playback Volume");
1874e217b960SRaymond Yau 	}
1875e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1876e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1877e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1878e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1879e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1880e3b9bc0eSJames Courtier-Dutton 	}
188112bda107STakashi Iwai 	kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu);
188212bda107STakashi Iwai 	if (!kctl)
18831da177e4SLinus Torvalds 		return -ENOMEM;
188467ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
188512bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
188612bda107STakashi Iwai 	if (err)
18871da177e4SLinus Torvalds 		return err;
188812bda107STakashi Iwai 	kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu);
188912bda107STakashi Iwai 	if (!kctl)
18901da177e4SLinus Torvalds 		return -ENOMEM;
189167ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
189212bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
189312bda107STakashi Iwai 	if (err)
18941da177e4SLinus Torvalds 		return err;
189512bda107STakashi Iwai 	kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu);
189612bda107STakashi Iwai 	if (!kctl)
18971da177e4SLinus Torvalds 		return -ENOMEM;
189867ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
189912bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
190012bda107STakashi Iwai 	if (err)
19011da177e4SLinus Torvalds 		return err;
19021da177e4SLinus Torvalds 
190312bda107STakashi Iwai 	kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu);
190412bda107STakashi Iwai 	if (!kctl)
19051da177e4SLinus Torvalds 		return -ENOMEM;
190667ed4161SClemens Ladisch 	kctl->id.device = multi_device;
190712bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
190812bda107STakashi Iwai 	if (err)
19091da177e4SLinus Torvalds 		return err;
19101da177e4SLinus Torvalds 
191112bda107STakashi Iwai 	kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu);
191212bda107STakashi Iwai 	if (!kctl)
19131da177e4SLinus Torvalds 		return -ENOMEM;
191467ed4161SClemens Ladisch 	kctl->id.device = multi_device;
191512bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
191612bda107STakashi Iwai 	if (err)
19171da177e4SLinus Torvalds 		return err;
19181da177e4SLinus Torvalds 
191912bda107STakashi Iwai 	kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu);
192012bda107STakashi Iwai 	if (!kctl)
19211da177e4SLinus Torvalds 		return -ENOMEM;
192267ed4161SClemens Ladisch 	kctl->id.device = multi_device;
192312bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
192412bda107STakashi Iwai 	if (err)
19251da177e4SLinus Torvalds 		return err;
19261da177e4SLinus Torvalds 
1927a8661af5SOswald Buddenhagen 	if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) {
19281da177e4SLinus Torvalds 		/* sb live! and audigy */
192912bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu);
193012bda107STakashi Iwai 		if (!kctl)
19311da177e4SLinus Torvalds 			return -ENOMEM;
19325549d549SClemens Ladisch 		if (!emu->audigy)
19335549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
193412bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
193512bda107STakashi Iwai 		if (err)
19361da177e4SLinus Torvalds 			return err;
193712bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu);
193812bda107STakashi Iwai 		if (!kctl)
19391da177e4SLinus Torvalds 			return -ENOMEM;
19405549d549SClemens Ladisch 		if (!emu->audigy)
19415549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
194212bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
194312bda107STakashi Iwai 		if (err)
19441da177e4SLinus Torvalds 			return err;
19451da177e4SLinus Torvalds 	}
19461da177e4SLinus Torvalds 
1947190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
194819b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
194919b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
195012bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu);
195112bda107STakashi Iwai 		if (!kctl)
19521da177e4SLinus Torvalds 			return -ENOMEM;
195312bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
195412bda107STakashi Iwai 		if (err)
19551da177e4SLinus Torvalds 			return err;
1956001f7589SJames Courtier-Dutton #if 0
195712bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu);
195812bda107STakashi Iwai 		if (!kctl)
19591da177e4SLinus Torvalds 			return -ENOMEM;
196012bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
196112bda107STakashi Iwai 		if (err)
19621da177e4SLinus Torvalds 			return err;
1963001f7589SJames Courtier-Dutton #endif
19642b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
19651da177e4SLinus Torvalds 		/* sb live! */
196612bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu);
196712bda107STakashi Iwai 		if (!kctl)
19681da177e4SLinus Torvalds 			return -ENOMEM;
196912bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
197012bda107STakashi Iwai 		if (err)
19711da177e4SLinus Torvalds 			return err;
19721da177e4SLinus Torvalds 	}
19732b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
197412bda107STakashi Iwai 		err = snd_p16v_mixer(emu);
197512bda107STakashi Iwai 		if (err)
19761da177e4SLinus Torvalds 			return err;
19771da177e4SLinus Torvalds 	}
19781da177e4SLinus Torvalds 
19793839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
19801c02e366SCtirad Fertr 		/* 1616(m) cardbus */
1981536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_output_source_ctl,
1982536438f1SOswald Buddenhagen 			       snd_emu1616_output_texts,
1983536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1616_output_texts));
19849f4bd5ddSJames Courtier-Dutton 		if (err < 0)
19859f4bd5ddSJames Courtier-Dutton 			return err;
1986536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_input_source_ctl,
1987536438f1SOswald Buddenhagen 			       emu1010_input_texts,
1988536438f1SOswald Buddenhagen 			       ARRAY_SIZE(emu1010_input_texts));
19891c02e366SCtirad Fertr 		if (err < 0)
19901c02e366SCtirad Fertr 			return err;
1991536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_adc_pads_ctl,
1992536438f1SOswald Buddenhagen 			       snd_emu1010_adc_pads,
1993536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1010_adc_pads) - 2);
19941c02e366SCtirad Fertr 		if (err < 0)
19951c02e366SCtirad Fertr 			return err;
1996536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_dac_pads_ctl,
1997536438f1SOswald Buddenhagen 			       snd_emu1010_dac_pads,
1998536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1010_dac_pads) - 2);
19991c02e366SCtirad Fertr 		if (err < 0)
20001c02e366SCtirad Fertr 			return err;
20011c02e366SCtirad Fertr 		err = snd_ctl_add(card,
20021c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
20031c02e366SCtirad Fertr 		if (err < 0)
20041c02e366SCtirad Fertr 			return err;
200599dcab46SMichael Gernoth 		err = snd_ctl_add(card,
200699dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
200799dcab46SMichael Gernoth 		if (err < 0)
200899dcab46SMichael Gernoth 			return err;
200999dcab46SMichael Gernoth 		err = snd_ctl_add(card,
201099dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
201199dcab46SMichael Gernoth 		if (err < 0)
201299dcab46SMichael Gernoth 			return err;
20131c02e366SCtirad Fertr 
201488aa1390STakashi Iwai 	} else if (emu->card_capabilities->emu_model) {
20151c02e366SCtirad Fertr 		/* all other e-mu cards for now */
2016536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_output_source_ctl,
2017536438f1SOswald Buddenhagen 			       emu1010_output_texts,
2018536438f1SOswald Buddenhagen 			       ARRAY_SIZE(emu1010_output_texts));
20191c02e366SCtirad Fertr 		if (err < 0)
20201c02e366SCtirad Fertr 			return err;
2021536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_input_source_ctl,
2022536438f1SOswald Buddenhagen 			       emu1010_input_texts,
2023536438f1SOswald Buddenhagen 			       ARRAY_SIZE(emu1010_input_texts));
20249f4bd5ddSJames Courtier-Dutton 		if (err < 0)
20259f4bd5ddSJames Courtier-Dutton 			return err;
2026536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_adc_pads_ctl,
2027536438f1SOswald Buddenhagen 			       snd_emu1010_adc_pads,
2028536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1010_adc_pads));
20299148cc50SJames Courtier-Dutton 		if (err < 0)
20309148cc50SJames Courtier-Dutton 			return err;
2031536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_dac_pads_ctl,
2032536438f1SOswald Buddenhagen 			       snd_emu1010_dac_pads,
2033536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1010_dac_pads));
20349148cc50SJames Courtier-Dutton 		if (err < 0)
20359148cc50SJames Courtier-Dutton 			return err;
20361c02e366SCtirad Fertr 		err = snd_ctl_add(card,
20371c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
2038b0dbdaeaSJames Courtier-Dutton 		if (err < 0)
2039b0dbdaeaSJames Courtier-Dutton 			return err;
204099dcab46SMichael Gernoth 		err = snd_ctl_add(card,
204199dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
204299dcab46SMichael Gernoth 		if (err < 0)
204399dcab46SMichael Gernoth 			return err;
204499dcab46SMichael Gernoth 		err = snd_ctl_add(card,
204599dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
204699dcab46SMichael Gernoth 		if (err < 0)
204799dcab46SMichael Gernoth 			return err;
20489f4bd5ddSJames Courtier-Dutton 	}
20499f4bd5ddSJames Courtier-Dutton 
2050184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2051184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2052184c1e2cSJames Courtier-Dutton 		if (err < 0)
2053184c1e2cSJames Courtier-Dutton 			return err;
2054184c1e2cSJames Courtier-Dutton 
2055536438f1SOswald Buddenhagen 		err = add_ctls(emu, &i2c_volume_ctl,
2056536438f1SOswald Buddenhagen 			       snd_audigy_i2c_volume_ctls,
2057536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_audigy_i2c_volume_ctls));
2058184c1e2cSJames Courtier-Dutton 		if (err < 0)
2059184c1e2cSJames Courtier-Dutton 			return err;
2060184c1e2cSJames Courtier-Dutton 	}
2061184c1e2cSJames Courtier-Dutton 
206216950e09STakashi Iwai 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
206316950e09STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
206416950e09STakashi Iwai 						     emu));
206516950e09STakashi Iwai 		if (err < 0)
206616950e09STakashi Iwai 			return err;
206716950e09STakashi Iwai 	}
206816950e09STakashi Iwai 
20691da177e4SLinus Torvalds 	return 0;
20701da177e4SLinus Torvalds }
2071