xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision 536438f1def68eb56fe611c07d2a6ec73ab4a5b1)
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 
32*536438f1SOswald Buddenhagen 
33*536438f1SOswald Buddenhagen static int add_ctls(struct snd_emu10k1 *emu, const struct snd_kcontrol_new *tpl,
34*536438f1SOswald Buddenhagen 		    const char * const *ctls, unsigned nctls)
35*536438f1SOswald Buddenhagen {
36*536438f1SOswald Buddenhagen 	struct snd_kcontrol_new kctl = *tpl;
37*536438f1SOswald Buddenhagen 	int err;
38*536438f1SOswald Buddenhagen 
39*536438f1SOswald Buddenhagen 	for (unsigned i = 0; i < nctls; i++) {
40*536438f1SOswald Buddenhagen 		kctl.name = ctls[i];
41*536438f1SOswald Buddenhagen 		kctl.private_value = i;
42*536438f1SOswald Buddenhagen 		err = snd_ctl_add(emu->card, snd_ctl_new1(&kctl, emu));
43*536438f1SOswald Buddenhagen 		if (err < 0)
44*536438f1SOswald Buddenhagen 			return err;
45*536438f1SOswald Buddenhagen 	}
46*536438f1SOswald Buddenhagen 	return 0;
47*536438f1SOswald Buddenhagen }
48*536438f1SOswald Buddenhagen 
49*536438f1SOswald 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  */
205*536438f1SOswald Buddenhagen 
206*536438f1SOswald Buddenhagen #define LR_CTLS(base) LR_PS(base, " Playback Enum")
207*536438f1SOswald Buddenhagen #define ADAT_CTLS(pfx) ADAT_PS(pfx, " Playback Enum")
208*536438f1SOswald Buddenhagen 
209*536438f1SOswald Buddenhagen static const char * const emu1010_output_texts[] = {
210*536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
211*536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
212*536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
213*536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC4"),
214*536438f1SOswald Buddenhagen 	LR_CTLS("Dock Phones"),
215*536438f1SOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
216*536438f1SOswald Buddenhagen 	LR_CTLS("0202 DAC"),
217*536438f1SOswald Buddenhagen 	LR_CTLS("1010 SPDIF"),
218*536438f1SOswald Buddenhagen 	ADAT_CTLS("1010 "),
2199f4bd5ddSJames Courtier-Dutton };
2209f4bd5ddSJames Courtier-Dutton 
221*536438f1SOswald Buddenhagen static const unsigned short emu1010_output_dst[] = {
222*536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
223*536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
224*536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
225*536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC4),
226*536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_PHONES),
227*536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_SPDIF),
228*536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_HAMOA_DAC),
229*536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_HANA_SPDIF),
230*536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_HANA_ADAT),
2311c02e366SCtirad Fertr };
232*536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_output_dst) == ARRAY_SIZE(emu1010_output_texts));
233*536438f1SOswald Buddenhagen 
234*536438f1SOswald Buddenhagen /* 1616(m) cardbus */
235*536438f1SOswald Buddenhagen 
236*536438f1SOswald Buddenhagen static const char * const snd_emu1616_output_texts[] = {
237*536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC1"),
238*536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC2"),
239*536438f1SOswald Buddenhagen 	LR_CTLS("Dock DAC3"),
240*536438f1SOswald Buddenhagen 	LR_CTLS("Dock SPDIF"),
241*536438f1SOswald Buddenhagen 	ADAT_CTLS("Dock "),
242*536438f1SOswald Buddenhagen 	LR_CTLS("Mana DAC"),
243*536438f1SOswald Buddenhagen };
244*536438f1SOswald Buddenhagen 
245*536438f1SOswald Buddenhagen static const unsigned short emu1616_output_dst[] = {
246*536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC1),
247*536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC2),
248*536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_DOCK_DAC3),
249*536438f1SOswald Buddenhagen 	LR_REGS(EMU_DST_MDOCK_SPDIF),
250*536438f1SOswald Buddenhagen 	ADAT_REGS(EMU_DST_MDOCK_ADAT),
251*536438f1SOswald Buddenhagen 	EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT,
252*536438f1SOswald Buddenhagen };
253*536438f1SOswald 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  */
260*536438f1SOswald Buddenhagen 
261*536438f1SOswald Buddenhagen static const char * const emu1010_input_texts[] = {
262*536438f1SOswald Buddenhagen 	"DSP 0 Capture Enum",
263*536438f1SOswald Buddenhagen 	"DSP 1 Capture Enum",
264*536438f1SOswald Buddenhagen 	"DSP 2 Capture Enum",
265*536438f1SOswald Buddenhagen 	"DSP 3 Capture Enum",
266*536438f1SOswald Buddenhagen 	"DSP 4 Capture Enum",
267*536438f1SOswald Buddenhagen 	"DSP 5 Capture Enum",
268*536438f1SOswald Buddenhagen 	"DSP 6 Capture Enum",
269*536438f1SOswald Buddenhagen 	"DSP 7 Capture Enum",
270*536438f1SOswald Buddenhagen 	"DSP 8 Capture Enum",
271*536438f1SOswald Buddenhagen 	"DSP 9 Capture Enum",
272*536438f1SOswald Buddenhagen 	"DSP A Capture Enum",
273*536438f1SOswald Buddenhagen 	"DSP B Capture Enum",
274*536438f1SOswald Buddenhagen 	"DSP C Capture Enum",
275*536438f1SOswald Buddenhagen 	"DSP D Capture Enum",
276*536438f1SOswald Buddenhagen 	"DSP E Capture Enum",
277*536438f1SOswald Buddenhagen 	"DSP F Capture Enum",
278*536438f1SOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
279*536438f1SOswald Buddenhagen 	"DSP 10 Capture Enum",
280*536438f1SOswald Buddenhagen 	"DSP 11 Capture Enum",
281*536438f1SOswald Buddenhagen 	"DSP 12 Capture Enum",
282*536438f1SOswald Buddenhagen 	"DSP 13 Capture Enum",
283*536438f1SOswald Buddenhagen 	"DSP 14 Capture Enum",
284*536438f1SOswald Buddenhagen 	"DSP 15 Capture Enum",
285*536438f1SOswald Buddenhagen };
286*536438f1SOswald 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 };
312*536438f1SOswald Buddenhagen static_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts));
3139f4bd5ddSJames Courtier-Dutton 
3141c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
3151c02e366SCtirad Fertr 						struct snd_ctl_elem_info *uinfo)
3169f4bd5ddSJames Courtier-Dutton {
3171c02e366SCtirad Fertr 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
3181c02e366SCtirad Fertr 
3191541c66dSTakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
3201541c66dSTakashi Iwai 		return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts);
3211541c66dSTakashi Iwai 	else
3221541c66dSTakashi Iwai 		return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts);
3239f4bd5ddSJames Courtier-Dutton }
3249f4bd5ddSJames Courtier-Dutton 
3259f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
3269f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
3279f4bd5ddSJames Courtier-Dutton {
3289f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
32974415a36SJames Courtier-Dutton 	unsigned int channel;
3309f4bd5ddSJames Courtier-Dutton 
3319f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
33274415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
3331c02e366SCtirad Fertr 	if (channel >= 24 ||
3343839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
3353839e4f1STakashi Iwai 	     channel >= 18))
33674415a36SJames Courtier-Dutton 		return -EINVAL;
3379f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
3389f4bd5ddSJames Courtier-Dutton 	return 0;
3399f4bd5ddSJames Courtier-Dutton }
3409f4bd5ddSJames Courtier-Dutton 
3419f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
3429f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
3439f4bd5ddSJames Courtier-Dutton {
3449f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
3459f4bd5ddSJames Courtier-Dutton 	unsigned int val;
34674415a36SJames Courtier-Dutton 	unsigned int channel;
3479f4bd5ddSJames Courtier-Dutton 
348aa299d01STakashi Iwai 	val = ucontrol->value.enumerated.item[0];
3491c02e366SCtirad Fertr 	if (val >= 53 ||
3503839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
3513839e4f1STakashi Iwai 	     val >= 49))
352aa299d01STakashi Iwai 		return -EINVAL;
3539f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
35474415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
3551c02e366SCtirad Fertr 	if (channel >= 24 ||
3563839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
3573839e4f1STakashi Iwai 	     channel >= 18))
35874415a36SJames Courtier-Dutton 		return -EINVAL;
3591c02e366SCtirad Fertr 	if (emu->emu1010.output_source[channel] == val)
3601c02e366SCtirad Fertr 		return 0;
361aa299d01STakashi Iwai 	emu->emu1010.output_source[channel] = val;
3623839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
3631c02e366SCtirad Fertr 		snd_emu1010_fpga_link_dst_src_write(emu,
3641c02e366SCtirad Fertr 			emu1616_output_dst[channel], emu1616_src_regs[val]);
3651c02e366SCtirad Fertr 	else
3669f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
3679f4bd5ddSJames Courtier-Dutton 			emu1010_output_dst[channel], emu1010_src_regs[val]);
3681c02e366SCtirad Fertr 	return 1;
3699f4bd5ddSJames Courtier-Dutton }
3709f4bd5ddSJames Courtier-Dutton 
371*536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_output_source_ctl = {
372*536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
373*536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
374*536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
375*536438f1SOswald Buddenhagen 	.get = snd_emu1010_output_source_get,
376*536438f1SOswald Buddenhagen 	.put = snd_emu1010_output_source_put
377*536438f1SOswald Buddenhagen };
378*536438f1SOswald Buddenhagen 
3799f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
3809f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
3819f4bd5ddSJames Courtier-Dutton {
3829f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
38374415a36SJames Courtier-Dutton 	unsigned int channel;
3849f4bd5ddSJames Courtier-Dutton 
3859f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
38674415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
38774415a36SJames Courtier-Dutton 	if (channel >= 22)
38874415a36SJames Courtier-Dutton 		return -EINVAL;
3899f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
3909f4bd5ddSJames Courtier-Dutton 	return 0;
3919f4bd5ddSJames Courtier-Dutton }
3929f4bd5ddSJames Courtier-Dutton 
3939f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
3949f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
3959f4bd5ddSJames Courtier-Dutton {
3969f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
3979f4bd5ddSJames Courtier-Dutton 	unsigned int val;
39874415a36SJames Courtier-Dutton 	unsigned int channel;
3999f4bd5ddSJames Courtier-Dutton 
400aa299d01STakashi Iwai 	val = ucontrol->value.enumerated.item[0];
4011c02e366SCtirad Fertr 	if (val >= 53 ||
4023839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4033839e4f1STakashi Iwai 	     val >= 49))
404aa299d01STakashi Iwai 		return -EINVAL;
4059f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
40674415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
40774415a36SJames Courtier-Dutton 	if (channel >= 22)
40874415a36SJames Courtier-Dutton 		return -EINVAL;
4091c02e366SCtirad Fertr 	if (emu->emu1010.input_source[channel] == val)
4101c02e366SCtirad Fertr 		return 0;
411aa299d01STakashi Iwai 	emu->emu1010.input_source[channel] = val;
4123839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
4131c02e366SCtirad Fertr 		snd_emu1010_fpga_link_dst_src_write(emu,
4141c02e366SCtirad Fertr 			emu1010_input_dst[channel], emu1616_src_regs[val]);
4151c02e366SCtirad Fertr 	else
4169f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
4179f4bd5ddSJames Courtier-Dutton 			emu1010_input_dst[channel], emu1010_src_regs[val]);
4181c02e366SCtirad Fertr 	return 1;
4199f4bd5ddSJames Courtier-Dutton }
4209f4bd5ddSJames Courtier-Dutton 
421*536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_input_source_ctl = {
422*536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
423*536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
424*536438f1SOswald Buddenhagen 	.info = snd_emu1010_input_output_source_info,
425*536438f1SOswald Buddenhagen 	.get = snd_emu1010_input_source_get,
426*536438f1SOswald Buddenhagen 	.put = snd_emu1010_input_source_put
4279f4bd5ddSJames Courtier-Dutton };
4289f4bd5ddSJames Courtier-Dutton 
4291c02e366SCtirad Fertr 
430*536438f1SOswald Buddenhagen static const char * const snd_emu1010_adc_pads[] = {
431*536438f1SOswald Buddenhagen 	"ADC1 14dB PAD Audio Dock Capture Switch",
432*536438f1SOswald Buddenhagen 	"ADC2 14dB PAD Audio Dock Capture Switch",
433*536438f1SOswald Buddenhagen 	"ADC3 14dB PAD Audio Dock Capture Switch",
434*536438f1SOswald Buddenhagen 	"ADC1 14dB PAD 0202 Capture Switch",
4351c02e366SCtirad Fertr };
4361c02e366SCtirad Fertr 
437*536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_adc_pad_regs[] = {
438*536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD1,
439*536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD2,
440*536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_ADC_PAD3,
441*536438f1SOswald Buddenhagen 	EMU_HANA_0202_ADC_PAD1,
4429148cc50SJames Courtier-Dutton };
4439148cc50SJames Courtier-Dutton 
444a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
4459148cc50SJames Courtier-Dutton 
4469148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4479148cc50SJames Courtier-Dutton {
4489148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
449*536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
450*536438f1SOswald Buddenhagen 
4519148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
4529148cc50SJames Courtier-Dutton 	return 0;
4539148cc50SJames Courtier-Dutton }
4549148cc50SJames Courtier-Dutton 
4559148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4569148cc50SJames Courtier-Dutton {
4579148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
458*536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value];
4599148cc50SJames Courtier-Dutton 	unsigned int val, cache;
4609148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
4619148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
4629148cc50SJames Courtier-Dutton 	if (val == 1)
4639148cc50SJames Courtier-Dutton 		cache = cache | mask;
4649148cc50SJames Courtier-Dutton 	else
4659148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
4669148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
4679148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
4689148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
4699148cc50SJames Courtier-Dutton 	}
4709148cc50SJames Courtier-Dutton 
4719148cc50SJames Courtier-Dutton 	return 0;
4729148cc50SJames Courtier-Dutton }
4739148cc50SJames Courtier-Dutton 
474*536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_adc_pads_ctl = {
475*536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
476*536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
477*536438f1SOswald Buddenhagen 	.info = snd_emu1010_adc_pads_info,
478*536438f1SOswald Buddenhagen 	.get = snd_emu1010_adc_pads_get,
479*536438f1SOswald Buddenhagen 	.put = snd_emu1010_adc_pads_put
480*536438f1SOswald Buddenhagen };
4819148cc50SJames Courtier-Dutton 
4829148cc50SJames Courtier-Dutton 
483*536438f1SOswald Buddenhagen static const char * const snd_emu1010_dac_pads[] = {
484*536438f1SOswald Buddenhagen 	"DAC1 Audio Dock 14dB PAD Playback Switch",
485*536438f1SOswald Buddenhagen 	"DAC2 Audio Dock 14dB PAD Playback Switch",
486*536438f1SOswald Buddenhagen 	"DAC3 Audio Dock 14dB PAD Playback Switch",
487*536438f1SOswald Buddenhagen 	"DAC4 Audio Dock 14dB PAD Playback Switch",
488*536438f1SOswald Buddenhagen 	"DAC1 0202 14dB PAD Playback Switch",
489*536438f1SOswald Buddenhagen };
4909148cc50SJames Courtier-Dutton 
491*536438f1SOswald Buddenhagen static const unsigned short snd_emu1010_dac_regs[] = {
492*536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD1,
493*536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD2,
494*536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD3,
495*536438f1SOswald Buddenhagen 	EMU_HANA_DOCK_DAC_PAD4,
496*536438f1SOswald Buddenhagen 	EMU_HANA_0202_DAC_PAD1,
4979148cc50SJames Courtier-Dutton };
4989148cc50SJames Courtier-Dutton 
499a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
5009148cc50SJames Courtier-Dutton 
5019148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5029148cc50SJames Courtier-Dutton {
5039148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
504*536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
505*536438f1SOswald Buddenhagen 
5069148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
5079148cc50SJames Courtier-Dutton 	return 0;
5089148cc50SJames Courtier-Dutton }
5099148cc50SJames Courtier-Dutton 
5109148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5119148cc50SJames Courtier-Dutton {
5129148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
513*536438f1SOswald Buddenhagen 	unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value];
5149148cc50SJames Courtier-Dutton 	unsigned int val, cache;
5159148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
5169148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
5179148cc50SJames Courtier-Dutton 	if (val == 1)
5189148cc50SJames Courtier-Dutton 		cache = cache | mask;
5199148cc50SJames Courtier-Dutton 	else
5209148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
5219148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.dac_pads) {
5229148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
5239148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
5249148cc50SJames Courtier-Dutton 	}
5259148cc50SJames Courtier-Dutton 
5269148cc50SJames Courtier-Dutton 	return 0;
5279148cc50SJames Courtier-Dutton }
5289148cc50SJames Courtier-Dutton 
529*536438f1SOswald Buddenhagen static const struct snd_kcontrol_new emu1010_dac_pads_ctl = {
530*536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
531*536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
532*536438f1SOswald Buddenhagen 	.info = snd_emu1010_dac_pads_info,
533*536438f1SOswald Buddenhagen 	.get = snd_emu1010_dac_pads_get,
534*536438f1SOswald Buddenhagen 	.put = snd_emu1010_dac_pads_put
5359f4bd5ddSJames Courtier-Dutton };
5369f4bd5ddSJames Courtier-Dutton 
537b0dbdaeaSJames Courtier-Dutton 
538b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
539b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
540b0dbdaeaSJames Courtier-Dutton {
5411541c66dSTakashi Iwai 	static const char * const texts[4] = {
542edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
543b0dbdaeaSJames Courtier-Dutton 	};
544b0dbdaeaSJames Courtier-Dutton 
5451541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 4, texts);
546b0dbdaeaSJames Courtier-Dutton }
547b0dbdaeaSJames Courtier-Dutton 
548b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
549b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
550b0dbdaeaSJames Courtier-Dutton {
551b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
552b0dbdaeaSJames Courtier-Dutton 
553b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
554b0dbdaeaSJames Courtier-Dutton 	return 0;
555b0dbdaeaSJames Courtier-Dutton }
556b0dbdaeaSJames Courtier-Dutton 
557b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
558b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
559b0dbdaeaSJames Courtier-Dutton {
560b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
561b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
562b0dbdaeaSJames Courtier-Dutton 	int change = 0;
563b0dbdaeaSJames Courtier-Dutton 
564b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
56574415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 4; */
56674415a36SJames Courtier-Dutton 	if (val >= 4)
56774415a36SJames Courtier-Dutton 		return -EINVAL;
568b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
569b0dbdaeaSJames Courtier-Dutton 	if (change) {
570b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
571b0dbdaeaSJames Courtier-Dutton 		switch (val) {
572b0dbdaeaSJames Courtier-Dutton 		case 0:
573b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
574b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
575b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
576a869057cSOswald Buddenhagen 			/* Default fallback clock 44.1kHz */
577b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
578b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
579b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
580b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
581b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
582b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
583b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
584b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
585e40a0b2eSJames Courtier-Dutton 			msleep(10);
586b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
587b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
588b0dbdaeaSJames Courtier-Dutton 			break;
589b0dbdaeaSJames Courtier-Dutton 		case 1:
590b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
591b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
592b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
593b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
594b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
595b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
596b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
597b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
598b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
599b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
600b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
601b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
602e40a0b2eSJames Courtier-Dutton 			msleep(10);
603b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
604b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
605b0dbdaeaSJames Courtier-Dutton 			break;
606edec7bbbSJames Courtier-Dutton 
607edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
608edec7bbbSJames Courtier-Dutton 			/* Mute all */
609edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
610edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
611edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
612edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
613edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
614edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
615edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
616edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
617edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
618edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
619edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
620edec7bbbSJames Courtier-Dutton 			msleep(10);
621edec7bbbSJames Courtier-Dutton 			/* Unmute all */
622edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
623edec7bbbSJames Courtier-Dutton 			break;
624edec7bbbSJames Courtier-Dutton 
625edec7bbbSJames Courtier-Dutton 		case 3:
626edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
627edec7bbbSJames Courtier-Dutton 			/* Mute all */
628edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
629edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
630edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
631edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
632edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
633edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
634edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
635edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
636edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
637edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
638edec7bbbSJames Courtier-Dutton 			msleep(10);
639edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
640edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
641edec7bbbSJames Courtier-Dutton 
642edec7bbbSJames Courtier-Dutton 
643edec7bbbSJames Courtier-Dutton 			break;
644b0dbdaeaSJames Courtier-Dutton 		}
645b0dbdaeaSJames Courtier-Dutton 	}
646b0dbdaeaSJames Courtier-Dutton         return change;
647b0dbdaeaSJames Courtier-Dutton }
648b0dbdaeaSJames Courtier-Dutton 
649f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock =
650b0dbdaeaSJames Courtier-Dutton {
651b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
652b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
653b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
654b0dbdaeaSJames Courtier-Dutton 	.count =	1,
655b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
656b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
657b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
658b0dbdaeaSJames Courtier-Dutton };
659b0dbdaeaSJames Courtier-Dutton 
66099dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
66199dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
66299dcab46SMichael Gernoth {
66399dcab46SMichael Gernoth 	static const char * const texts[2] = {
66499dcab46SMichael Gernoth 		"SPDIF", "ADAT"
66599dcab46SMichael Gernoth 	};
66699dcab46SMichael Gernoth 
66799dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
66899dcab46SMichael Gernoth }
66999dcab46SMichael Gernoth 
67099dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol,
67199dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
67299dcab46SMichael Gernoth {
67399dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
67499dcab46SMichael Gernoth 
67599dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out;
67699dcab46SMichael Gernoth 	return 0;
67799dcab46SMichael Gernoth }
67899dcab46SMichael Gernoth 
67999dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
68099dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
68199dcab46SMichael Gernoth {
68299dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
68399dcab46SMichael Gernoth 	unsigned int val;
68499dcab46SMichael Gernoth 	u32 tmp;
68599dcab46SMichael Gernoth 	int change = 0;
68699dcab46SMichael Gernoth 
68799dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
68899dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
68999dcab46SMichael Gernoth 	if (val >= 2)
69099dcab46SMichael Gernoth 		return -EINVAL;
69199dcab46SMichael Gernoth 	change = (emu->emu1010.optical_out != val);
69299dcab46SMichael Gernoth 	if (change) {
69399dcab46SMichael Gernoth 		emu->emu1010.optical_out = val;
6949d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
6959d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
69699dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
69799dcab46SMichael Gernoth 	}
69899dcab46SMichael Gernoth 	return change;
69999dcab46SMichael Gernoth }
70099dcab46SMichael Gernoth 
701f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = {
70299dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
70399dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
70499dcab46SMichael Gernoth 	.name =         "Optical Output Mode",
70599dcab46SMichael Gernoth 	.count =	1,
70699dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_out_info,
70799dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_out_get,
70899dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_out_put
70999dcab46SMichael Gernoth };
71099dcab46SMichael Gernoth 
71199dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
71299dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
71399dcab46SMichael Gernoth {
71499dcab46SMichael Gernoth 	static const char * const texts[2] = {
71599dcab46SMichael Gernoth 		"SPDIF", "ADAT"
71699dcab46SMichael Gernoth 	};
71799dcab46SMichael Gernoth 
71899dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
71999dcab46SMichael Gernoth }
72099dcab46SMichael Gernoth 
72199dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
72299dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
72399dcab46SMichael Gernoth {
72499dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
72599dcab46SMichael Gernoth 
72699dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
72799dcab46SMichael Gernoth 	return 0;
72899dcab46SMichael Gernoth }
72999dcab46SMichael Gernoth 
73099dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
73199dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
73299dcab46SMichael Gernoth {
73399dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
73499dcab46SMichael Gernoth 	unsigned int val;
73599dcab46SMichael Gernoth 	u32 tmp;
73699dcab46SMichael Gernoth 	int change = 0;
73799dcab46SMichael Gernoth 
73899dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
73999dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
74099dcab46SMichael Gernoth 	if (val >= 2)
74199dcab46SMichael Gernoth 		return -EINVAL;
74299dcab46SMichael Gernoth 	change = (emu->emu1010.optical_in != val);
74399dcab46SMichael Gernoth 	if (change) {
74499dcab46SMichael Gernoth 		emu->emu1010.optical_in = val;
7459d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
7469d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
74799dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
74899dcab46SMichael Gernoth 	}
74999dcab46SMichael Gernoth 	return change;
75099dcab46SMichael Gernoth }
75199dcab46SMichael Gernoth 
752f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = {
75399dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
75499dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
75599dcab46SMichael Gernoth 	.name =         "Optical Input Mode",
75699dcab46SMichael Gernoth 	.count =	1,
75799dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_in_info,
75899dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_in_get,
75999dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_in_put
76099dcab46SMichael Gernoth };
76199dcab46SMichael Gernoth 
762184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
763184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
764184c1e2cSJames Courtier-Dutton {
765184c1e2cSJames Courtier-Dutton #if 0
7661541c66dSTakashi Iwai 	static const char * const texts[4] = {
767184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
768184c1e2cSJames Courtier-Dutton 	};
769184c1e2cSJames Courtier-Dutton #endif
7701541c66dSTakashi Iwai 	static const char * const texts[2] = {
771184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
772184c1e2cSJames Courtier-Dutton 	};
773184c1e2cSJames Courtier-Dutton 
7741541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
775184c1e2cSJames Courtier-Dutton }
776184c1e2cSJames Courtier-Dutton 
777184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
778184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
779184c1e2cSJames Courtier-Dutton {
780184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
781184c1e2cSJames Courtier-Dutton 
782184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
783184c1e2cSJames Courtier-Dutton 	return 0;
784184c1e2cSJames Courtier-Dutton }
785184c1e2cSJames Courtier-Dutton 
786184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
787184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
788184c1e2cSJames Courtier-Dutton {
789184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
790184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
791184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
792a1c87c0bSOswald Buddenhagen 	u16 gpio;
793184c1e2cSJames Courtier-Dutton 	int change = 0;
794184c1e2cSJames Courtier-Dutton 	unsigned long flags;
795184c1e2cSJames Courtier-Dutton 	u32 source;
796184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
797184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
798184c1e2cSJames Courtier-Dutton 	 * for the particular source.
799184c1e2cSJames Courtier-Dutton 	 */
80074415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
80174415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
80274415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
80374415a36SJames Courtier-Dutton 	if (source_id >= 2)
80474415a36SJames Courtier-Dutton 		return -EINVAL;
805184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
806184c1e2cSJames Courtier-Dutton 	if (change) {
807184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
808184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
809a1c87c0bSOswald Buddenhagen 		gpio = inw(emu->port + A_IOCFG);
810184c1e2cSJames Courtier-Dutton 		if (source_id==0)
811a1c87c0bSOswald Buddenhagen 			outw(gpio | 0x4, emu->port + A_IOCFG);
812184c1e2cSJames Courtier-Dutton 		else
813a1c87c0bSOswald Buddenhagen 			outw(gpio & ~0x4, emu->port + A_IOCFG);
814184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
815184c1e2cSJames Courtier-Dutton 
816184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
817184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
818184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
819184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
820184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
821184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
822184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
823184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
824184c1e2cSJames Courtier-Dutton 
825184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
826184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
827184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
828184c1e2cSJames Courtier-Dutton 	}
829184c1e2cSJames Courtier-Dutton         return change;
830184c1e2cSJames Courtier-Dutton }
831184c1e2cSJames Courtier-Dutton 
832f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source =
833184c1e2cSJames Courtier-Dutton {
834184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
835184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
836184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
837184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
838184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
839184c1e2cSJames Courtier-Dutton };
840184c1e2cSJames Courtier-Dutton 
841184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
842184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
843184c1e2cSJames Courtier-Dutton {
844184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
845184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
846184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
847184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
848184c1e2cSJames Courtier-Dutton 	return 0;
849184c1e2cSJames Courtier-Dutton }
850184c1e2cSJames Courtier-Dutton 
851184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
852184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
853184c1e2cSJames Courtier-Dutton {
854184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
85574415a36SJames Courtier-Dutton 	unsigned int source_id;
856184c1e2cSJames Courtier-Dutton 
857184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
85874415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
85974415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
86074415a36SJames Courtier-Dutton 	if (source_id >= 2)
86174415a36SJames Courtier-Dutton 		return -EINVAL;
862184c1e2cSJames Courtier-Dutton 
863184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
864184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
865184c1e2cSJames Courtier-Dutton 	return 0;
866184c1e2cSJames Courtier-Dutton }
867184c1e2cSJames Courtier-Dutton 
868184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
869184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
870184c1e2cSJames Courtier-Dutton {
871184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
872184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
87314a29565SOswald Buddenhagen 	unsigned int ngain0, ngain1;
87474415a36SJames Courtier-Dutton 	unsigned int source_id;
875184c1e2cSJames Courtier-Dutton 	int change = 0;
876184c1e2cSJames Courtier-Dutton 
877184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
87874415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
87974415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
88074415a36SJames Courtier-Dutton 	if (source_id >= 2)
88174415a36SJames Courtier-Dutton 		return -EINVAL;
88214a29565SOswald Buddenhagen 	ngain0 = ucontrol->value.integer.value[0];
88314a29565SOswald Buddenhagen 	ngain1 = ucontrol->value.integer.value[1];
88414a29565SOswald Buddenhagen 	if (ngain0 > 0xff)
88514a29565SOswald Buddenhagen 		return -EINVAL;
88614a29565SOswald Buddenhagen 	if (ngain1 > 0xff)
88714a29565SOswald Buddenhagen 		return -EINVAL;
888184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
88914a29565SOswald Buddenhagen 	if (ogain != ngain0) {
890184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
89114a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0);
89214a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][0] = ngain0;
893184c1e2cSJames Courtier-Dutton 		change = 1;
894184c1e2cSJames Courtier-Dutton 	}
895184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
89614a29565SOswald Buddenhagen 	if (ogain != ngain1) {
897184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
89814a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1);
89914a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][1] = ngain1;
900184c1e2cSJames Courtier-Dutton 		change = 1;
901184c1e2cSJames Courtier-Dutton 	}
902184c1e2cSJames Courtier-Dutton 
903184c1e2cSJames Courtier-Dutton 	return change;
904184c1e2cSJames Courtier-Dutton }
905184c1e2cSJames Courtier-Dutton 
906*536438f1SOswald Buddenhagen static const struct snd_kcontrol_new i2c_volume_ctl = {
907*536438f1SOswald Buddenhagen 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
908*536438f1SOswald Buddenhagen 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
909*536438f1SOswald Buddenhagen 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,
910*536438f1SOswald Buddenhagen 	.info = snd_audigy_i2c_volume_info,
911*536438f1SOswald Buddenhagen 	.get = snd_audigy_i2c_volume_get,
912*536438f1SOswald Buddenhagen 	.put = snd_audigy_i2c_volume_put,
913*536438f1SOswald Buddenhagen 	.tlv = { .p = snd_audigy_db_scale2 }
914*536438f1SOswald Buddenhagen };
915184c1e2cSJames Courtier-Dutton 
916*536438f1SOswald Buddenhagen static const char * const snd_audigy_i2c_volume_ctls[] = {
917*536438f1SOswald Buddenhagen 	"Mic Capture Volume",
918*536438f1SOswald Buddenhagen 	"Line Capture Volume",
919184c1e2cSJames Courtier-Dutton };
920184c1e2cSJames Courtier-Dutton 
9210af68e5eSTakashi Iwai #if 0
922eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9231da177e4SLinus Torvalds {
9241541c66dSTakashi Iwai 	static const char * const texts[] = {"44100", "48000", "96000"};
9251da177e4SLinus Torvalds 
9261541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 3, texts);
9271da177e4SLinus Torvalds }
9281da177e4SLinus Torvalds 
929eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
930eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
9311da177e4SLinus Torvalds {
932eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
9331da177e4SLinus Torvalds 	unsigned int tmp;
9341da177e4SLinus Torvalds 
9351da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
9361da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
9371da177e4SLinus Torvalds 	case A_SPDIF_44100:
9381da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
9391da177e4SLinus Torvalds 		break;
9401da177e4SLinus Torvalds 	case A_SPDIF_48000:
9411da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
9421da177e4SLinus Torvalds 		break;
9431da177e4SLinus Torvalds 	case A_SPDIF_96000:
9441da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
9451da177e4SLinus Torvalds 		break;
9461da177e4SLinus Torvalds 	default:
9471da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
9481da177e4SLinus Torvalds 	}
9491da177e4SLinus Torvalds 	return 0;
9501da177e4SLinus Torvalds }
9511da177e4SLinus Torvalds 
952eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
953eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
9541da177e4SLinus Torvalds {
955eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
9561da177e4SLinus Torvalds 	int change;
9571da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
9581da177e4SLinus Torvalds 	unsigned long flags;
9591da177e4SLinus Torvalds 
9601da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
9611da177e4SLinus Torvalds 	case 0:
9621da177e4SLinus Torvalds 		val = A_SPDIF_44100;
9631da177e4SLinus Torvalds 		break;
9641da177e4SLinus Torvalds 	case 1:
9651da177e4SLinus Torvalds 		val = A_SPDIF_48000;
9661da177e4SLinus Torvalds 		break;
9671da177e4SLinus Torvalds 	case 2:
9681da177e4SLinus Torvalds 		val = A_SPDIF_96000;
9691da177e4SLinus Torvalds 		break;
9701da177e4SLinus Torvalds 	default:
9711da177e4SLinus Torvalds 		val = A_SPDIF_48000;
9721da177e4SLinus Torvalds 		break;
9731da177e4SLinus Torvalds 	}
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds 
9761da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
9771da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
9781da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
9791da177e4SLinus Torvalds 	tmp |= val;
98012bda107STakashi Iwai 	change = (tmp != reg);
98112bda107STakashi Iwai 	if (change)
9821da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
9831da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
9841da177e4SLinus Torvalds 	return change;
9851da177e4SLinus Torvalds }
9861da177e4SLinus Torvalds 
987b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate =
9881da177e4SLinus Torvalds {
9891da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
9901da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
9911da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
9921da177e4SLinus Torvalds 	.count =	1,
9931da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
9941da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
9951da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
9961da177e4SLinus Torvalds };
9970af68e5eSTakashi Iwai #endif
9981da177e4SLinus Torvalds 
999eb4698f3STakashi Iwai static int snd_emu10k1_spdif_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 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
10041da177e4SLinus Torvalds 	int change;
10051da177e4SLinus Torvalds 	unsigned int val;
10061da177e4SLinus Torvalds 
100774415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
100874415a36SJames Courtier-Dutton 	if (idx >= 3)
100974415a36SJames Courtier-Dutton 		return -EINVAL;
10101da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
10111da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
10121da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
10131da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
10141da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
10151da177e4SLinus Torvalds 	if (change) {
10161da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
10171da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
10181da177e4SLinus Torvalds 	}
10191da177e4SLinus Torvalds 	return change;
10201da177e4SLinus Torvalds }
10211da177e4SLinus Torvalds 
1022f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
10231da177e4SLinus Torvalds {
10241da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
10255549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
10261da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
10277583cb51STakashi Iwai 	.count =	3,
10281da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
10291da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
10301da177e4SLinus Torvalds };
10311da177e4SLinus Torvalds 
1032f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
10331da177e4SLinus Torvalds {
10345549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
10351da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
10367583cb51STakashi Iwai 	.count =	3,
10371da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
10381da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
10391da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
10401da177e4SLinus Torvalds };
10411da177e4SLinus Torvalds 
10421da177e4SLinus Torvalds 
1043eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
10441da177e4SLinus Torvalds {
10451da177e4SLinus Torvalds 	if (emu->audigy) {
10461da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
10471da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
10481da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
10491da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
10501da177e4SLinus Torvalds 	} else {
10511da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
10521da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
10531da177e4SLinus Torvalds 	}
10541da177e4SLinus Torvalds }
10551da177e4SLinus Torvalds 
1056eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
10571da177e4SLinus Torvalds {
10581da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
10591da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
10601da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
10611da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
10621da177e4SLinus Torvalds 	if (emu->audigy) {
106351d652f4SOswald Buddenhagen 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice,
106451d652f4SOswald Buddenhagen 				      snd_emu10k1_compose_audigy_sendamounts(volume));
10651da177e4SLinus Torvalds 	}
10661da177e4SLinus Torvalds }
10671da177e4SLinus Torvalds 
10681da177e4SLinus Torvalds /* PCM stream controls */
10691da177e4SLinus Torvalds 
1070eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
10711da177e4SLinus Torvalds {
1072eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10731da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
10741da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
10751da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
10761da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
10771da177e4SLinus Torvalds 	return 0;
10781da177e4SLinus Torvalds }
10791da177e4SLinus Torvalds 
1080eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1081eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
10821da177e4SLinus Torvalds {
1083eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1084eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1085eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10861da177e4SLinus Torvalds 	int voice, idx;
10871da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
10881da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
10891da177e4SLinus Torvalds 
10901da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
10911da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
10921da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
10931da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
10941da177e4SLinus Torvalds 	return 0;
10951da177e4SLinus Torvalds }
10961da177e4SLinus Torvalds 
1097eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1098eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
10991da177e4SLinus Torvalds {
11001da177e4SLinus Torvalds 	unsigned long flags;
1101eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1102eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1103eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11041da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
11051da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11061da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11071da177e4SLinus Torvalds 
11081da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11091da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
11101da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
11111da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
11121da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
11131da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
11141da177e4SLinus Torvalds 				change = 1;
11151da177e4SLinus Torvalds 			}
11161da177e4SLinus Torvalds 		}
11171da177e4SLinus Torvalds 	if (change && mix->epcm) {
11181da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
11191da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
11201da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
11211da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
11221da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
11231da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
11241da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
11251da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
11261da177e4SLinus Torvalds 		}
11271da177e4SLinus Torvalds 	}
11281da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11291da177e4SLinus Torvalds 	return change;
11301da177e4SLinus Torvalds }
11311da177e4SLinus Torvalds 
1132f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control =
11331da177e4SLinus Torvalds {
11341da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
113567ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11361da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
11371da177e4SLinus Torvalds 	.count =	32,
11381da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
11391da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
11401da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
11411da177e4SLinus Torvalds };
11421da177e4SLinus Torvalds 
1143eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11441da177e4SLinus Torvalds {
1145eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11461da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
11471da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
11481da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11491da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
11501da177e4SLinus Torvalds 	return 0;
11511da177e4SLinus Torvalds }
11521da177e4SLinus Torvalds 
1153eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1154eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
11551da177e4SLinus Torvalds {
1156eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1157eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1158eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11591da177e4SLinus Torvalds 	int idx;
11601da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11611da177e4SLinus Torvalds 
11621da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
11631da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
11641da177e4SLinus Torvalds 	return 0;
11651da177e4SLinus Torvalds }
11661da177e4SLinus Torvalds 
1167eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1168eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
11691da177e4SLinus Torvalds {
11701da177e4SLinus Torvalds 	unsigned long flags;
1171eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1172eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1173eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11741da177e4SLinus Torvalds 	int change = 0, idx, val;
11751da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11761da177e4SLinus Torvalds 
11771da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11781da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
11791da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
11801da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
11811da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
11821da177e4SLinus Torvalds 			change = 1;
11831da177e4SLinus Torvalds 		}
11841da177e4SLinus Torvalds 	}
11851da177e4SLinus Torvalds 	if (change && mix->epcm) {
11861da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
11871da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
11881da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
11891da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
11901da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
11911da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
11921da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
11931da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
11941da177e4SLinus Torvalds 		}
11951da177e4SLinus Torvalds 	}
11961da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11971da177e4SLinus Torvalds 	return change;
11981da177e4SLinus Torvalds }
11991da177e4SLinus Torvalds 
1200f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
12011da177e4SLinus Torvalds {
12021da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
120367ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12041da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
12051da177e4SLinus Torvalds 	.count =	32,
12061da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
12071da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
12081da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
12091da177e4SLinus Torvalds };
12101da177e4SLinus Torvalds 
1211eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12121da177e4SLinus Torvalds {
12131da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12141da177e4SLinus Torvalds 	uinfo->count = 3;
12151da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1216bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
12171da177e4SLinus Torvalds 	return 0;
12181da177e4SLinus Torvalds }
12191da177e4SLinus Torvalds 
1220eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1221eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
12221da177e4SLinus Torvalds {
1223eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1224eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1225eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12261da177e4SLinus Torvalds 	int idx;
12271da177e4SLinus Torvalds 
12281da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
1229bcdbd3b7SOswald Buddenhagen 		ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U;
12301da177e4SLinus Torvalds 	return 0;
12311da177e4SLinus Torvalds }
12321da177e4SLinus Torvalds 
1233eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1234eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
12351da177e4SLinus Torvalds {
12361da177e4SLinus Torvalds 	unsigned long flags;
1237eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1238eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1239eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12401da177e4SLinus Torvalds 	int change = 0, idx, val;
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12431da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
1244bcdbd3b7SOswald Buddenhagen 		unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff;
1245bcdbd3b7SOswald Buddenhagen 		val = uval * 0x8000U / 0xffffU;
12461da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
12471da177e4SLinus Torvalds 			mix->attn[idx] = val;
12481da177e4SLinus Torvalds 			change = 1;
12491da177e4SLinus Torvalds 		}
12501da177e4SLinus Torvalds 	}
12511da177e4SLinus Torvalds 	if (change && mix->epcm) {
12521da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
12531da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
12541da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
12551da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
12561da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
12571da177e4SLinus Torvalds 		}
12581da177e4SLinus Torvalds 	}
12591da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12601da177e4SLinus Torvalds 	return change;
12611da177e4SLinus Torvalds }
12621da177e4SLinus Torvalds 
1263f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control =
12641da177e4SLinus Torvalds {
12651da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
126667ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12671da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
12681da177e4SLinus Torvalds 	.count =	32,
12691da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
12701da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
12711da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
12721da177e4SLinus Torvalds };
12731da177e4SLinus Torvalds 
12741da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
12751da177e4SLinus Torvalds 
1276eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12771da177e4SLinus Torvalds {
1278eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12791da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12801da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
12811da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12821da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
12831da177e4SLinus Torvalds 	return 0;
12841da177e4SLinus Torvalds }
12851da177e4SLinus Torvalds 
1286eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1287eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
12881da177e4SLinus Torvalds {
1289eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1290eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1291eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12921da177e4SLinus Torvalds 	int idx;
12931da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12941da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
12951da177e4SLinus Torvalds 
12961da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
12971da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
12981da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
12991da177e4SLinus Torvalds 	return 0;
13001da177e4SLinus Torvalds }
13011da177e4SLinus Torvalds 
1302eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1303eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
13041da177e4SLinus Torvalds {
13051da177e4SLinus Torvalds 	unsigned long flags;
1306eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13071da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1308eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
13091da177e4SLinus Torvalds 	int change = 0, idx, val;
13101da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13111da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
13121da177e4SLinus Torvalds 
13131da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13141da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
13151da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
13161da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
13171da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
13181da177e4SLinus Torvalds 			change = 1;
13191da177e4SLinus Torvalds 		}
13201da177e4SLinus Torvalds 	}
13211da177e4SLinus Torvalds 
13221da177e4SLinus Torvalds 	if (change && mix->epcm) {
13231da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
13241da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
13251da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
13261da177e4SLinus Torvalds 		}
13271da177e4SLinus Torvalds 	}
13281da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13291da177e4SLinus Torvalds 	return change;
13301da177e4SLinus Torvalds }
13311da177e4SLinus Torvalds 
1332f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
13331da177e4SLinus Torvalds {
13341da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
13351da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13361da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
13371da177e4SLinus Torvalds 	.count =	16,
13381da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
13391da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
13401da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
13411da177e4SLinus Torvalds };
13421da177e4SLinus Torvalds 
1343eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13441da177e4SLinus Torvalds {
1345eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13461da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13471da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
13481da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13491da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
13501da177e4SLinus Torvalds 	return 0;
13511da177e4SLinus Torvalds }
13521da177e4SLinus Torvalds 
1353eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1354eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
13551da177e4SLinus Torvalds {
1356eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1357eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1358eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13591da177e4SLinus Torvalds 	int idx;
13601da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13611da177e4SLinus Torvalds 
13621da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
13631da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
13641da177e4SLinus Torvalds 	return 0;
13651da177e4SLinus Torvalds }
13661da177e4SLinus Torvalds 
1367eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1368eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
13691da177e4SLinus Torvalds {
13701da177e4SLinus Torvalds 	unsigned long flags;
1371eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13721da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1373eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
13741da177e4SLinus Torvalds 	int change = 0, idx, val;
13751da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13761da177e4SLinus Torvalds 
13771da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13781da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
13791da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
13801da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
13811da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
13821da177e4SLinus Torvalds 			change = 1;
13831da177e4SLinus Torvalds 		}
13841da177e4SLinus Torvalds 	}
13851da177e4SLinus Torvalds 	if (change && mix->epcm) {
13861da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
13871da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
13881da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
13891da177e4SLinus Torvalds 		}
13901da177e4SLinus Torvalds 	}
13911da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13921da177e4SLinus Torvalds 	return change;
13931da177e4SLinus Torvalds }
13941da177e4SLinus Torvalds 
13951da177e4SLinus Torvalds 
1396f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
13971da177e4SLinus Torvalds {
13981da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
13991da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14001da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
14011da177e4SLinus Torvalds 	.count =	16,
14021da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
14031da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
14041da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
14051da177e4SLinus Torvalds };
14061da177e4SLinus Torvalds 
1407eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14081da177e4SLinus Torvalds {
14091da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14101da177e4SLinus Torvalds 	uinfo->count = 1;
14111da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
1412bcdbd3b7SOswald Buddenhagen 	uinfo->value.integer.max = 0x1fffd;
14131da177e4SLinus Torvalds 	return 0;
14141da177e4SLinus Torvalds }
14151da177e4SLinus Torvalds 
1416eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1417eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
14181da177e4SLinus Torvalds {
1419eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1420eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1421eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14221da177e4SLinus Torvalds 
1423bcdbd3b7SOswald Buddenhagen 	ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U;
14241da177e4SLinus Torvalds 	return 0;
14251da177e4SLinus Torvalds }
14261da177e4SLinus Torvalds 
1427eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1428eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
14291da177e4SLinus Torvalds {
14301da177e4SLinus Torvalds 	unsigned long flags;
1431eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14321da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1433eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
14341da177e4SLinus Torvalds 	int change = 0, val;
1435bcdbd3b7SOswald Buddenhagen 	unsigned uval;
14361da177e4SLinus Torvalds 
14371da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1438bcdbd3b7SOswald Buddenhagen 	uval = ucontrol->value.integer.value[0] & 0x1ffff;
1439bcdbd3b7SOswald Buddenhagen 	val = uval * 0x8000U / 0xffffU;
14401da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
14411da177e4SLinus Torvalds 		mix->attn[0] = val;
14421da177e4SLinus Torvalds 		change = 1;
14431da177e4SLinus Torvalds 	}
14441da177e4SLinus Torvalds 	if (change && mix->epcm) {
14451da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
14461da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
14471da177e4SLinus Torvalds 		}
14481da177e4SLinus Torvalds 	}
14491da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14501da177e4SLinus Torvalds 	return change;
14511da177e4SLinus Torvalds }
14521da177e4SLinus Torvalds 
1453f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
14541da177e4SLinus Torvalds {
14551da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
14561da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14571da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
14581da177e4SLinus Torvalds 	.count =	16,
14591da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
14601da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
14611da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
14621da177e4SLinus Torvalds };
14631da177e4SLinus Torvalds 
1464a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
14651da177e4SLinus Torvalds 
1466eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1467eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
14681da177e4SLinus Torvalds {
1469eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14701da177e4SLinus Torvalds 
14711da177e4SLinus Torvalds 	if (emu->audigy)
1472a1c87c0bSOswald Buddenhagen 		ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
14731da177e4SLinus Torvalds 	else
14741da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1475d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1476d2cd74b1STakashi Iwai 		ucontrol->value.integer.value[0] =
1477d2cd74b1STakashi Iwai 			!ucontrol->value.integer.value[0];
1478d2cd74b1STakashi Iwai 
14791da177e4SLinus Torvalds 	return 0;
14801da177e4SLinus Torvalds }
14811da177e4SLinus Torvalds 
1482eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1483eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
14841da177e4SLinus Torvalds {
14851da177e4SLinus Torvalds 	unsigned long flags;
1486eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1487d2cd74b1STakashi Iwai 	unsigned int reg, val, sw;
14881da177e4SLinus Torvalds 	int change = 0;
14891da177e4SLinus Torvalds 
1490d2cd74b1STakashi Iwai 	sw = ucontrol->value.integer.value[0];
1491d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1492d2cd74b1STakashi Iwai 		sw = !sw;
149350164f69SOswald Buddenhagen 	spin_lock_irqsave(&emu->emu_lock, flags);
1494184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1495184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1496184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
1497a1c87c0bSOswald Buddenhagen 		reg = inw(emu->port + A_IOCFG);
1498d2cd74b1STakashi Iwai 		val = sw ? A_IOCFG_GPOUT0 : 0;
14991da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
15001da177e4SLinus Torvalds 		if (change) {
15011da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
15021da177e4SLinus Torvalds 			reg |= val;
1503a1c87c0bSOswald Buddenhagen 			outw(reg | val, emu->port + A_IOCFG);
15041da177e4SLinus Torvalds 		}
15051da177e4SLinus Torvalds 	}
15061da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
1507d2cd74b1STakashi Iwai 	val = sw ? HCFG_GPOUT0 : 0;
15081da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
15091da177e4SLinus Torvalds 	if (change) {
15101da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
15111da177e4SLinus Torvalds 		reg |= val;
15121da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
15131da177e4SLinus Torvalds 	}
151450164f69SOswald Buddenhagen 	spin_unlock_irqrestore(&emu->emu_lock, flags);
15151da177e4SLinus Torvalds 	return change;
15161da177e4SLinus Torvalds }
15171da177e4SLinus Torvalds 
1518f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
15191da177e4SLinus Torvalds {
15201da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
15211da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
15221da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
15231da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
15241da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
15251da177e4SLinus Torvalds };
15261da177e4SLinus Torvalds 
1527f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif =
15281da177e4SLinus Torvalds {
15291da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
15301da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
15311da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
15321da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
15331da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
15341da177e4SLinus Torvalds };
15351da177e4SLinus Torvalds 
153616950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
153716950e09STakashi Iwai 
153816950e09STakashi Iwai #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
153916950e09STakashi Iwai 
154016950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
154116950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
154216950e09STakashi Iwai {
154316950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
154416950e09STakashi Iwai 	unsigned int val;
154516950e09STakashi Iwai 
154616950e09STakashi Iwai 	/* FIXME: better to use a cached version */
154716950e09STakashi Iwai 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
154816950e09STakashi Iwai 	ucontrol->value.integer.value[0] = !!val;
154916950e09STakashi Iwai 	return 0;
155016950e09STakashi Iwai }
155116950e09STakashi Iwai 
155216950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
155316950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
155416950e09STakashi Iwai {
155516950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
155616950e09STakashi Iwai 	unsigned int val;
155716950e09STakashi Iwai 
155816950e09STakashi Iwai 	if (ucontrol->value.integer.value[0])
155916950e09STakashi Iwai 		val = 0x0f0f;
156016950e09STakashi Iwai 	else
156116950e09STakashi Iwai 		val = 0;
156216950e09STakashi Iwai 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
156316950e09STakashi Iwai }
156416950e09STakashi Iwai 
1565f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost =
156616950e09STakashi Iwai {
156716950e09STakashi Iwai 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
15682a52feb1SMaciej S. Szmigiero 	.name =		"Mic Extra Boost",
156916950e09STakashi Iwai 	.info =		snd_audigy_capture_boost_info,
157016950e09STakashi Iwai 	.get =		snd_audigy_capture_boost_get,
157116950e09STakashi Iwai 	.put =		snd_audigy_capture_boost_put
157216950e09STakashi Iwai };
157316950e09STakashi Iwai 
157416950e09STakashi Iwai 
15751da177e4SLinus Torvalds /*
15761da177e4SLinus Torvalds  */
1577eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
15781da177e4SLinus Torvalds {
1579eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
15801da177e4SLinus Torvalds 	emu->ac97 = NULL;
15811da177e4SLinus Torvalds }
15821da177e4SLinus Torvalds 
15831da177e4SLinus Torvalds /*
15841da177e4SLinus Torvalds  */
1585eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
15861da177e4SLinus Torvalds {
1587eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
15881da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
15891da177e4SLinus Torvalds 	strcpy(id.name, name);
15901da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
15911da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
15921da177e4SLinus Torvalds }
15931da177e4SLinus Torvalds 
1594eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
15951da177e4SLinus Torvalds {
1596eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
15971da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
15981da177e4SLinus Torvalds 	strcpy(sid.name, name);
15991da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
16001da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
16011da177e4SLinus Torvalds }
16021da177e4SLinus Torvalds 
1603eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
16041da177e4SLinus Torvalds {
1605eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
16061da177e4SLinus Torvalds 	if (kctl) {
160736476b81SMaciej S. Szmigiero 		snd_ctl_rename(card, kctl, dst);
16081da177e4SLinus Torvalds 		return 0;
16091da177e4SLinus Torvalds 	}
16101da177e4SLinus Torvalds 	return -ENOENT;
16111da177e4SLinus Torvalds }
16121da177e4SLinus Torvalds 
1613e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
161467ed4161SClemens Ladisch 		      int pcm_device, int multi_device)
16151da177e4SLinus Torvalds {
1616155e3d3bSOswald Buddenhagen 	int err;
1617eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1618eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
16196fddce26STakashi Iwai 	const char * const *c;
16206fddce26STakashi Iwai 	static const char * const emu10k1_remove_ctls[] = {
16211da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
16221da177e4SLinus Torvalds 		"Master Mono Playback Switch",
16231da177e4SLinus Torvalds 		"Master Mono Playback Volume",
16241da177e4SLinus Torvalds 		"PCM Out Path & Mute",
16251da177e4SLinus Torvalds 		"Mono Output Select",
16261da177e4SLinus Torvalds 		"Surround Playback Switch",
16271da177e4SLinus Torvalds 		"Surround Playback Volume",
16281da177e4SLinus Torvalds 		"Center Playback Switch",
16291da177e4SLinus Torvalds 		"Center Playback Volume",
16301da177e4SLinus Torvalds 		"LFE Playback Switch",
16311da177e4SLinus Torvalds 		"LFE Playback Volume",
16321da177e4SLinus Torvalds 		NULL
16331da177e4SLinus Torvalds 	};
16346fddce26STakashi Iwai 	static const char * const emu10k1_rename_ctls[] = {
16351da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
16361da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
16371da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
16381da177e4SLinus Torvalds 		NULL
16391da177e4SLinus Torvalds 	};
16406fddce26STakashi Iwai 	static const char * const audigy_remove_ctls[] = {
16411da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
164221fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
164321fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
16441da177e4SLinus Torvalds 		"PCM Playback Switch",
16451da177e4SLinus Torvalds 		"PCM Playback Volume",
16461da177e4SLinus Torvalds 		"Master Playback Switch",
16471da177e4SLinus Torvalds 		"Master Playback Volume",
16481da177e4SLinus Torvalds 		"PCM Out Path & Mute",
16491da177e4SLinus Torvalds 		"Mono Output Select",
16501da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
16511da177e4SLinus Torvalds 		"Capture Source",
16521da177e4SLinus Torvalds 		"Capture Switch",
16531da177e4SLinus Torvalds 		"Capture Volume",
16541da177e4SLinus Torvalds 		"Mic Select",
1655274b2000SMaciej S. Szmigiero 		"Headphone Playback Switch",
1656274b2000SMaciej S. Szmigiero 		"Headphone Playback Volume",
1657274b2000SMaciej S. Szmigiero 		"3D Control - Center",
1658274b2000SMaciej S. Szmigiero 		"3D Control - Depth",
1659274b2000SMaciej S. Szmigiero 		"3D Control - Switch",
16601da177e4SLinus Torvalds 		"Video Playback Switch",
16611da177e4SLinus Torvalds 		"Video Playback Volume",
16621da177e4SLinus Torvalds 		"Mic Playback Switch",
16631da177e4SLinus Torvalds 		"Mic Playback Volume",
1664274b2000SMaciej S. Szmigiero 		"External Amplifier",
16651da177e4SLinus Torvalds 		NULL
16661da177e4SLinus Torvalds 	};
16676fddce26STakashi Iwai 	static const char * const audigy_rename_ctls[] = {
16681da177e4SLinus Torvalds 		/* use conventional names */
16691da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
16701da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
16711da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
16721da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
167352051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
167452051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
16751da177e4SLinus Torvalds 		NULL
16761da177e4SLinus Torvalds 	};
16776fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_i2c_adc[] = {
1678184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1679184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1680184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1681184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1682184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1683eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1684184c1e2cSJames Courtier-Dutton 		NULL
1685184c1e2cSJames Courtier-Dutton 	};
16866fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_i2c_adc[] = {
1687184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1688184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1689184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1690184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1691184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1692eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1693184c1e2cSJames Courtier-Dutton 		NULL
1694184c1e2cSJames Courtier-Dutton 	};
16956fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_1361t_adc[] = {
169621fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
169721fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
169821fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
169921fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
170021fdddeaSJames Courtier-Dutton 		"Capture Source",
170121fdddeaSJames Courtier-Dutton 		"Capture Switch",
170221fdddeaSJames Courtier-Dutton 		"Capture Volume",
170321fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
170421fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
170521fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
170621fdddeaSJames Courtier-Dutton 		"3D Control - Center",
170721fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
170821fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
170921fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
171021fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
171121fdddeaSJames Courtier-Dutton 		NULL
171221fdddeaSJames Courtier-Dutton 	};
17136fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_1361t_adc[] = {
171421fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
171521fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
171621fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1717d355c82aSJaroslav Kysela 		"Beep Playback Switch", "Beep Capture Switch",
1718d355c82aSJaroslav Kysela 		"Beep Playback Volume", "Beep Capture Volume",
171921fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
172021fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
172121fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
172221fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
172321fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
172421fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
172521fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
172621fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
172721fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
172821fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
172921fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
173021fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
173152051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
173252051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
173321fdddeaSJames Courtier-Dutton 		NULL
173421fdddeaSJames Courtier-Dutton 	};
17351da177e4SLinus Torvalds 
17362b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1737eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1738eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
173951055da5STakashi Iwai 		static const struct snd_ac97_bus_ops ops = {
17401da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
17411da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
17421da177e4SLinus Torvalds 		};
17431da177e4SLinus Torvalds 
174412bda107STakashi Iwai 		err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus);
174512bda107STakashi Iwai 		if (err < 0)
17461da177e4SLinus Torvalds 			return err;
17471da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
17481da177e4SLinus Torvalds 
17491da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
17501da177e4SLinus Torvalds 		ac97.private_data = emu;
17511da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
17521da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
175312bda107STakashi Iwai 		err = snd_ac97_mixer(pbus, &ac97, &emu->ac97);
175412bda107STakashi Iwai 		if (err < 0) {
1755b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
17561da177e4SLinus Torvalds 				return err;
17576f002b02STakashi Iwai 			dev_info(emu->card->dev,
17586f002b02STakashi Iwai 				 "AC97 is optional on this board\n");
17596f002b02STakashi Iwai 			dev_info(emu->card->dev,
17606f002b02STakashi Iwai 				 "Proceeding without ac97 mixers...\n");
1761b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1762b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1763b1508693STakashi Iwai 		}
17641da177e4SLinus Torvalds 		if (emu->audigy) {
17651da177e4SLinus Torvalds 			/* set master volume to 0 dB */
17664d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
17671da177e4SLinus Torvalds 			/* set capture source to mic */
17684d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
176952051942SMaciej S. Szmigiero 			/* set mono output (TAD) to mic */
177052051942SMaciej S. Szmigiero 			snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE,
177152051942SMaciej S. Szmigiero 				0x0200, 0x0200);
177221fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
177321fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
177421fdddeaSJames Courtier-Dutton 			else
17751da177e4SLinus Torvalds 				c = audigy_remove_ctls;
17761da177e4SLinus Torvalds 		} else {
17771da177e4SLinus Torvalds 			/*
17781da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
17791da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
17801da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
17811da177e4SLinus Torvalds 			 */
17821da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
17831da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
17841da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
17852594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
1786b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Volume");
1787b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Switch");
17881da177e4SLinus Torvalds 			}
17891da177e4SLinus Torvalds 			/* remove unused AC97 controls */
17904d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
17914d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
17921da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
17931da177e4SLinus Torvalds 		}
17941da177e4SLinus Torvalds 		for (; *c; c++)
17951da177e4SLinus Torvalds 			remove_ctl(card, *c);
1796184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1797184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1798184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1799184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
18001da177e4SLinus Torvalds 	} else {
1801f12aa40cSTakashi Iwai 	no_ac97:
18022b637da5SLee Revell 		if (emu->card_capabilities->ecard)
18031da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
18041da177e4SLinus Torvalds 		else if (emu->audigy)
18051da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
18061da177e4SLinus Torvalds 		else
18071da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
18081da177e4SLinus Torvalds 	}
18091da177e4SLinus Torvalds 
18101da177e4SLinus Torvalds 	if (emu->audigy)
181121fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
181221fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1813184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1814184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
181521fdddeaSJames Courtier-Dutton 		else
18161da177e4SLinus Torvalds 			c = audigy_rename_ctls;
18171da177e4SLinus Torvalds 	else
18181da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
18191da177e4SLinus Torvalds 	for (; *c; c += 2)
18201da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
182121fdddeaSJames Courtier-Dutton 
1822e217b960SRaymond Yau 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
1823e217b960SRaymond Yau 		remove_ctl(card, "Center Playback Volume");
1824e217b960SRaymond Yau 		remove_ctl(card, "LFE Playback Volume");
1825e217b960SRaymond Yau 		remove_ctl(card, "Wave Center Playback Volume");
1826e217b960SRaymond Yau 		remove_ctl(card, "Wave LFE Playback Volume");
1827e217b960SRaymond Yau 	}
1828e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1829e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1830e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1831e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1832e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1833e3b9bc0eSJames Courtier-Dutton 	}
183412bda107STakashi Iwai 	kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu);
183512bda107STakashi Iwai 	if (!kctl)
18361da177e4SLinus Torvalds 		return -ENOMEM;
183767ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
183812bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
183912bda107STakashi Iwai 	if (err)
18401da177e4SLinus Torvalds 		return err;
184112bda107STakashi Iwai 	kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu);
184212bda107STakashi Iwai 	if (!kctl)
18431da177e4SLinus Torvalds 		return -ENOMEM;
184467ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
184512bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
184612bda107STakashi Iwai 	if (err)
18471da177e4SLinus Torvalds 		return err;
184812bda107STakashi Iwai 	kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu);
184912bda107STakashi Iwai 	if (!kctl)
18501da177e4SLinus Torvalds 		return -ENOMEM;
185167ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
185212bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
185312bda107STakashi Iwai 	if (err)
18541da177e4SLinus Torvalds 		return err;
18551da177e4SLinus Torvalds 
185612bda107STakashi Iwai 	kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu);
185712bda107STakashi Iwai 	if (!kctl)
18581da177e4SLinus Torvalds 		return -ENOMEM;
185967ed4161SClemens Ladisch 	kctl->id.device = multi_device;
186012bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
186112bda107STakashi Iwai 	if (err)
18621da177e4SLinus Torvalds 		return err;
18631da177e4SLinus Torvalds 
186412bda107STakashi Iwai 	kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu);
186512bda107STakashi Iwai 	if (!kctl)
18661da177e4SLinus Torvalds 		return -ENOMEM;
186767ed4161SClemens Ladisch 	kctl->id.device = multi_device;
186812bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
186912bda107STakashi Iwai 	if (err)
18701da177e4SLinus Torvalds 		return err;
18711da177e4SLinus Torvalds 
187212bda107STakashi Iwai 	kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu);
187312bda107STakashi Iwai 	if (!kctl)
18741da177e4SLinus Torvalds 		return -ENOMEM;
187567ed4161SClemens Ladisch 	kctl->id.device = multi_device;
187612bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
187712bda107STakashi Iwai 	if (err)
18781da177e4SLinus Torvalds 		return err;
18791da177e4SLinus Torvalds 
1880a8661af5SOswald Buddenhagen 	if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) {
18811da177e4SLinus Torvalds 		/* sb live! and audigy */
188212bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu);
188312bda107STakashi Iwai 		if (!kctl)
18841da177e4SLinus Torvalds 			return -ENOMEM;
18855549d549SClemens Ladisch 		if (!emu->audigy)
18865549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
188712bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
188812bda107STakashi Iwai 		if (err)
18891da177e4SLinus Torvalds 			return err;
189012bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu);
189112bda107STakashi Iwai 		if (!kctl)
18921da177e4SLinus Torvalds 			return -ENOMEM;
18935549d549SClemens Ladisch 		if (!emu->audigy)
18945549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
189512bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
189612bda107STakashi Iwai 		if (err)
18971da177e4SLinus Torvalds 			return err;
18981da177e4SLinus Torvalds 	}
18991da177e4SLinus Torvalds 
1900190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
190119b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
190219b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
190312bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu);
190412bda107STakashi Iwai 		if (!kctl)
19051da177e4SLinus Torvalds 			return -ENOMEM;
190612bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
190712bda107STakashi Iwai 		if (err)
19081da177e4SLinus Torvalds 			return err;
1909001f7589SJames Courtier-Dutton #if 0
191012bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu);
191112bda107STakashi Iwai 		if (!kctl)
19121da177e4SLinus Torvalds 			return -ENOMEM;
191312bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
191412bda107STakashi Iwai 		if (err)
19151da177e4SLinus Torvalds 			return err;
1916001f7589SJames Courtier-Dutton #endif
19172b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
19181da177e4SLinus Torvalds 		/* sb live! */
191912bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu);
192012bda107STakashi Iwai 		if (!kctl)
19211da177e4SLinus Torvalds 			return -ENOMEM;
192212bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
192312bda107STakashi Iwai 		if (err)
19241da177e4SLinus Torvalds 			return err;
19251da177e4SLinus Torvalds 	}
19262b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
192712bda107STakashi Iwai 		err = snd_p16v_mixer(emu);
192812bda107STakashi Iwai 		if (err)
19291da177e4SLinus Torvalds 			return err;
19301da177e4SLinus Torvalds 	}
19311da177e4SLinus Torvalds 
19323839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
19331c02e366SCtirad Fertr 		/* 1616(m) cardbus */
1934*536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_output_source_ctl,
1935*536438f1SOswald Buddenhagen 			       snd_emu1616_output_texts,
1936*536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1616_output_texts));
19379f4bd5ddSJames Courtier-Dutton 		if (err < 0)
19389f4bd5ddSJames Courtier-Dutton 			return err;
1939*536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_input_source_ctl,
1940*536438f1SOswald Buddenhagen 			       emu1010_input_texts,
1941*536438f1SOswald Buddenhagen 			       ARRAY_SIZE(emu1010_input_texts));
19421c02e366SCtirad Fertr 		if (err < 0)
19431c02e366SCtirad Fertr 			return err;
1944*536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_adc_pads_ctl,
1945*536438f1SOswald Buddenhagen 			       snd_emu1010_adc_pads,
1946*536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1010_adc_pads) - 2);
19471c02e366SCtirad Fertr 		if (err < 0)
19481c02e366SCtirad Fertr 			return err;
1949*536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_dac_pads_ctl,
1950*536438f1SOswald Buddenhagen 			       snd_emu1010_dac_pads,
1951*536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1010_dac_pads) - 2);
19521c02e366SCtirad Fertr 		if (err < 0)
19531c02e366SCtirad Fertr 			return err;
19541c02e366SCtirad Fertr 		err = snd_ctl_add(card,
19551c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
19561c02e366SCtirad Fertr 		if (err < 0)
19571c02e366SCtirad Fertr 			return err;
195899dcab46SMichael Gernoth 		err = snd_ctl_add(card,
195999dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
196099dcab46SMichael Gernoth 		if (err < 0)
196199dcab46SMichael Gernoth 			return err;
196299dcab46SMichael Gernoth 		err = snd_ctl_add(card,
196399dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
196499dcab46SMichael Gernoth 		if (err < 0)
196599dcab46SMichael Gernoth 			return err;
19661c02e366SCtirad Fertr 
196788aa1390STakashi Iwai 	} else if (emu->card_capabilities->emu_model) {
19681c02e366SCtirad Fertr 		/* all other e-mu cards for now */
1969*536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_output_source_ctl,
1970*536438f1SOswald Buddenhagen 			       emu1010_output_texts,
1971*536438f1SOswald Buddenhagen 			       ARRAY_SIZE(emu1010_output_texts));
19721c02e366SCtirad Fertr 		if (err < 0)
19731c02e366SCtirad Fertr 			return err;
1974*536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_input_source_ctl,
1975*536438f1SOswald Buddenhagen 			       emu1010_input_texts,
1976*536438f1SOswald Buddenhagen 			       ARRAY_SIZE(emu1010_input_texts));
19779f4bd5ddSJames Courtier-Dutton 		if (err < 0)
19789f4bd5ddSJames Courtier-Dutton 			return err;
1979*536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_adc_pads_ctl,
1980*536438f1SOswald Buddenhagen 			       snd_emu1010_adc_pads,
1981*536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1010_adc_pads));
19829148cc50SJames Courtier-Dutton 		if (err < 0)
19839148cc50SJames Courtier-Dutton 			return err;
1984*536438f1SOswald Buddenhagen 		err = add_ctls(emu, &emu1010_dac_pads_ctl,
1985*536438f1SOswald Buddenhagen 			       snd_emu1010_dac_pads,
1986*536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_emu1010_dac_pads));
19879148cc50SJames Courtier-Dutton 		if (err < 0)
19889148cc50SJames Courtier-Dutton 			return err;
19891c02e366SCtirad Fertr 		err = snd_ctl_add(card,
19901c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
1991b0dbdaeaSJames Courtier-Dutton 		if (err < 0)
1992b0dbdaeaSJames Courtier-Dutton 			return err;
199399dcab46SMichael Gernoth 		err = snd_ctl_add(card,
199499dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
199599dcab46SMichael Gernoth 		if (err < 0)
199699dcab46SMichael Gernoth 			return err;
199799dcab46SMichael Gernoth 		err = snd_ctl_add(card,
199899dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
199999dcab46SMichael Gernoth 		if (err < 0)
200099dcab46SMichael Gernoth 			return err;
20019f4bd5ddSJames Courtier-Dutton 	}
20029f4bd5ddSJames Courtier-Dutton 
2003184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2004184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2005184c1e2cSJames Courtier-Dutton 		if (err < 0)
2006184c1e2cSJames Courtier-Dutton 			return err;
2007184c1e2cSJames Courtier-Dutton 
2008*536438f1SOswald Buddenhagen 		err = add_ctls(emu, &i2c_volume_ctl,
2009*536438f1SOswald Buddenhagen 			       snd_audigy_i2c_volume_ctls,
2010*536438f1SOswald Buddenhagen 			       ARRAY_SIZE(snd_audigy_i2c_volume_ctls));
2011184c1e2cSJames Courtier-Dutton 		if (err < 0)
2012184c1e2cSJames Courtier-Dutton 			return err;
2013184c1e2cSJames Courtier-Dutton 	}
2014184c1e2cSJames Courtier-Dutton 
201516950e09STakashi Iwai 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
201616950e09STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
201716950e09STakashi Iwai 						     emu));
201816950e09STakashi Iwai 		if (err < 0)
201916950e09STakashi Iwai 			return err;
202016950e09STakashi Iwai 	}
202116950e09STakashi Iwai 
20221da177e4SLinus Torvalds 	return 0;
20231da177e4SLinus Torvalds }
2024