xref: /OK3568_Linux_fs/kernel/sound/pci/emu10k1/emumixer.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
4*4882a593Smuzhiyun  *                   Takashi Iwai <tiwai@suse.de>
5*4882a593Smuzhiyun  *                   Creative Labs, Inc.
6*4882a593Smuzhiyun  *  Routines for control of EMU10K1 chips / mixer routines
7*4882a593Smuzhiyun  *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
10*4882a593Smuzhiyun  *  	Added EMU 1010 support.
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  *  BUGS:
13*4882a593Smuzhiyun  *    --
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  *  TODO:
16*4882a593Smuzhiyun  *    --
17*4882a593Smuzhiyun  */
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <linux/time.h>
20*4882a593Smuzhiyun #include <linux/init.h>
21*4882a593Smuzhiyun #include <sound/core.h>
22*4882a593Smuzhiyun #include <sound/emu10k1.h>
23*4882a593Smuzhiyun #include <linux/delay.h>
24*4882a593Smuzhiyun #include <sound/tlv.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include "p17v.h"
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define AC97_ID_STAC9758	0x83847658
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
31*4882a593Smuzhiyun 
snd_emu10k1_spdif_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)32*4882a593Smuzhiyun static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
35*4882a593Smuzhiyun 	uinfo->count = 1;
36*4882a593Smuzhiyun 	return 0;
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun 
snd_emu10k1_spdif_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)39*4882a593Smuzhiyun static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
40*4882a593Smuzhiyun                                  struct snd_ctl_elem_value *ucontrol)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
43*4882a593Smuzhiyun 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
44*4882a593Smuzhiyun 	unsigned long flags;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	/* Limit: emu->spdif_bits */
47*4882a593Smuzhiyun 	if (idx >= 3)
48*4882a593Smuzhiyun 		return -EINVAL;
49*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
50*4882a593Smuzhiyun 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
51*4882a593Smuzhiyun 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
52*4882a593Smuzhiyun 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
53*4882a593Smuzhiyun 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
54*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
55*4882a593Smuzhiyun 	return 0;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
snd_emu10k1_spdif_get_mask(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)58*4882a593Smuzhiyun static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
59*4882a593Smuzhiyun 				      struct snd_ctl_elem_value *ucontrol)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun 	ucontrol->value.iec958.status[0] = 0xff;
62*4882a593Smuzhiyun 	ucontrol->value.iec958.status[1] = 0xff;
63*4882a593Smuzhiyun 	ucontrol->value.iec958.status[2] = 0xff;
64*4882a593Smuzhiyun 	ucontrol->value.iec958.status[3] = 0xff;
65*4882a593Smuzhiyun 	return 0;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun /*
69*4882a593Smuzhiyun  * Items labels in enum mixer controls assigning source data to
70*4882a593Smuzhiyun  * each destination
71*4882a593Smuzhiyun  */
72*4882a593Smuzhiyun static const char * const emu1010_src_texts[] = {
73*4882a593Smuzhiyun 	"Silence",
74*4882a593Smuzhiyun 	"Dock Mic A",
75*4882a593Smuzhiyun 	"Dock Mic B",
76*4882a593Smuzhiyun 	"Dock ADC1 Left",
77*4882a593Smuzhiyun 	"Dock ADC1 Right",
78*4882a593Smuzhiyun 	"Dock ADC2 Left",
79*4882a593Smuzhiyun 	"Dock ADC2 Right",
80*4882a593Smuzhiyun 	"Dock ADC3 Left",
81*4882a593Smuzhiyun 	"Dock ADC3 Right",
82*4882a593Smuzhiyun 	"0202 ADC Left",
83*4882a593Smuzhiyun 	"0202 ADC Right",
84*4882a593Smuzhiyun 	"0202 SPDIF Left",
85*4882a593Smuzhiyun 	"0202 SPDIF Right",
86*4882a593Smuzhiyun 	"ADAT 0",
87*4882a593Smuzhiyun 	"ADAT 1",
88*4882a593Smuzhiyun 	"ADAT 2",
89*4882a593Smuzhiyun 	"ADAT 3",
90*4882a593Smuzhiyun 	"ADAT 4",
91*4882a593Smuzhiyun 	"ADAT 5",
92*4882a593Smuzhiyun 	"ADAT 6",
93*4882a593Smuzhiyun 	"ADAT 7",
94*4882a593Smuzhiyun 	"DSP 0",
95*4882a593Smuzhiyun 	"DSP 1",
96*4882a593Smuzhiyun 	"DSP 2",
97*4882a593Smuzhiyun 	"DSP 3",
98*4882a593Smuzhiyun 	"DSP 4",
99*4882a593Smuzhiyun 	"DSP 5",
100*4882a593Smuzhiyun 	"DSP 6",
101*4882a593Smuzhiyun 	"DSP 7",
102*4882a593Smuzhiyun 	"DSP 8",
103*4882a593Smuzhiyun 	"DSP 9",
104*4882a593Smuzhiyun 	"DSP 10",
105*4882a593Smuzhiyun 	"DSP 11",
106*4882a593Smuzhiyun 	"DSP 12",
107*4882a593Smuzhiyun 	"DSP 13",
108*4882a593Smuzhiyun 	"DSP 14",
109*4882a593Smuzhiyun 	"DSP 15",
110*4882a593Smuzhiyun 	"DSP 16",
111*4882a593Smuzhiyun 	"DSP 17",
112*4882a593Smuzhiyun 	"DSP 18",
113*4882a593Smuzhiyun 	"DSP 19",
114*4882a593Smuzhiyun 	"DSP 20",
115*4882a593Smuzhiyun 	"DSP 21",
116*4882a593Smuzhiyun 	"DSP 22",
117*4882a593Smuzhiyun 	"DSP 23",
118*4882a593Smuzhiyun 	"DSP 24",
119*4882a593Smuzhiyun 	"DSP 25",
120*4882a593Smuzhiyun 	"DSP 26",
121*4882a593Smuzhiyun 	"DSP 27",
122*4882a593Smuzhiyun 	"DSP 28",
123*4882a593Smuzhiyun 	"DSP 29",
124*4882a593Smuzhiyun 	"DSP 30",
125*4882a593Smuzhiyun 	"DSP 31",
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun /* 1616(m) cardbus */
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun static const char * const emu1616_src_texts[] = {
131*4882a593Smuzhiyun 	"Silence",
132*4882a593Smuzhiyun 	"Dock Mic A",
133*4882a593Smuzhiyun 	"Dock Mic B",
134*4882a593Smuzhiyun 	"Dock ADC1 Left",
135*4882a593Smuzhiyun 	"Dock ADC1 Right",
136*4882a593Smuzhiyun 	"Dock ADC2 Left",
137*4882a593Smuzhiyun 	"Dock ADC2 Right",
138*4882a593Smuzhiyun 	"Dock SPDIF Left",
139*4882a593Smuzhiyun 	"Dock SPDIF Right",
140*4882a593Smuzhiyun 	"ADAT 0",
141*4882a593Smuzhiyun 	"ADAT 1",
142*4882a593Smuzhiyun 	"ADAT 2",
143*4882a593Smuzhiyun 	"ADAT 3",
144*4882a593Smuzhiyun 	"ADAT 4",
145*4882a593Smuzhiyun 	"ADAT 5",
146*4882a593Smuzhiyun 	"ADAT 6",
147*4882a593Smuzhiyun 	"ADAT 7",
148*4882a593Smuzhiyun 	"DSP 0",
149*4882a593Smuzhiyun 	"DSP 1",
150*4882a593Smuzhiyun 	"DSP 2",
151*4882a593Smuzhiyun 	"DSP 3",
152*4882a593Smuzhiyun 	"DSP 4",
153*4882a593Smuzhiyun 	"DSP 5",
154*4882a593Smuzhiyun 	"DSP 6",
155*4882a593Smuzhiyun 	"DSP 7",
156*4882a593Smuzhiyun 	"DSP 8",
157*4882a593Smuzhiyun 	"DSP 9",
158*4882a593Smuzhiyun 	"DSP 10",
159*4882a593Smuzhiyun 	"DSP 11",
160*4882a593Smuzhiyun 	"DSP 12",
161*4882a593Smuzhiyun 	"DSP 13",
162*4882a593Smuzhiyun 	"DSP 14",
163*4882a593Smuzhiyun 	"DSP 15",
164*4882a593Smuzhiyun 	"DSP 16",
165*4882a593Smuzhiyun 	"DSP 17",
166*4882a593Smuzhiyun 	"DSP 18",
167*4882a593Smuzhiyun 	"DSP 19",
168*4882a593Smuzhiyun 	"DSP 20",
169*4882a593Smuzhiyun 	"DSP 21",
170*4882a593Smuzhiyun 	"DSP 22",
171*4882a593Smuzhiyun 	"DSP 23",
172*4882a593Smuzhiyun 	"DSP 24",
173*4882a593Smuzhiyun 	"DSP 25",
174*4882a593Smuzhiyun 	"DSP 26",
175*4882a593Smuzhiyun 	"DSP 27",
176*4882a593Smuzhiyun 	"DSP 28",
177*4882a593Smuzhiyun 	"DSP 29",
178*4882a593Smuzhiyun 	"DSP 30",
179*4882a593Smuzhiyun 	"DSP 31",
180*4882a593Smuzhiyun };
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun /*
184*4882a593Smuzhiyun  * List of data sources available for each destination
185*4882a593Smuzhiyun  */
186*4882a593Smuzhiyun static const unsigned int emu1010_src_regs[] = {
187*4882a593Smuzhiyun 	EMU_SRC_SILENCE,/* 0 */
188*4882a593Smuzhiyun 	EMU_SRC_DOCK_MIC_A1, /* 1 */
189*4882a593Smuzhiyun 	EMU_SRC_DOCK_MIC_B1, /* 2 */
190*4882a593Smuzhiyun 	EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */
191*4882a593Smuzhiyun 	EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */
192*4882a593Smuzhiyun 	EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */
193*4882a593Smuzhiyun 	EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */
194*4882a593Smuzhiyun 	EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */
195*4882a593Smuzhiyun 	EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */
196*4882a593Smuzhiyun 	EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */
197*4882a593Smuzhiyun 	EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */
198*4882a593Smuzhiyun 	EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */
199*4882a593Smuzhiyun 	EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */
200*4882a593Smuzhiyun 	EMU_SRC_HANA_ADAT, /* 13 */
201*4882a593Smuzhiyun 	EMU_SRC_HANA_ADAT+1, /* 14 */
202*4882a593Smuzhiyun 	EMU_SRC_HANA_ADAT+2, /* 15 */
203*4882a593Smuzhiyun 	EMU_SRC_HANA_ADAT+3, /* 16 */
204*4882a593Smuzhiyun 	EMU_SRC_HANA_ADAT+4, /* 17 */
205*4882a593Smuzhiyun 	EMU_SRC_HANA_ADAT+5, /* 18 */
206*4882a593Smuzhiyun 	EMU_SRC_HANA_ADAT+6, /* 19 */
207*4882a593Smuzhiyun 	EMU_SRC_HANA_ADAT+7, /* 20 */
208*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A, /* 21 */
209*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+1, /* 22 */
210*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+2, /* 23 */
211*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+3, /* 24 */
212*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+4, /* 25 */
213*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+5, /* 26 */
214*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+6, /* 27 */
215*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+7, /* 28 */
216*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+8, /* 29 */
217*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+9, /* 30 */
218*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+0xa, /* 31 */
219*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+0xb, /* 32 */
220*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+0xc, /* 33 */
221*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+0xd, /* 34 */
222*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+0xe, /* 35 */
223*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+0xf, /* 36 */
224*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B, /* 37 */
225*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+1, /* 38 */
226*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+2, /* 39 */
227*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+3, /* 40 */
228*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+4, /* 41 */
229*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+5, /* 42 */
230*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+6, /* 43 */
231*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+7, /* 44 */
232*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+8, /* 45 */
233*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+9, /* 46 */
234*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+0xa, /* 47 */
235*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+0xb, /* 48 */
236*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+0xc, /* 49 */
237*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+0xd, /* 50 */
238*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+0xe, /* 51 */
239*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
240*4882a593Smuzhiyun };
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun /* 1616(m) cardbus */
243*4882a593Smuzhiyun static const unsigned int emu1616_src_regs[] = {
244*4882a593Smuzhiyun 	EMU_SRC_SILENCE,
245*4882a593Smuzhiyun 	EMU_SRC_DOCK_MIC_A1,
246*4882a593Smuzhiyun 	EMU_SRC_DOCK_MIC_B1,
247*4882a593Smuzhiyun 	EMU_SRC_DOCK_ADC1_LEFT1,
248*4882a593Smuzhiyun 	EMU_SRC_DOCK_ADC1_RIGHT1,
249*4882a593Smuzhiyun 	EMU_SRC_DOCK_ADC2_LEFT1,
250*4882a593Smuzhiyun 	EMU_SRC_DOCK_ADC2_RIGHT1,
251*4882a593Smuzhiyun 	EMU_SRC_MDOCK_SPDIF_LEFT1,
252*4882a593Smuzhiyun 	EMU_SRC_MDOCK_SPDIF_RIGHT1,
253*4882a593Smuzhiyun 	EMU_SRC_MDOCK_ADAT,
254*4882a593Smuzhiyun 	EMU_SRC_MDOCK_ADAT+1,
255*4882a593Smuzhiyun 	EMU_SRC_MDOCK_ADAT+2,
256*4882a593Smuzhiyun 	EMU_SRC_MDOCK_ADAT+3,
257*4882a593Smuzhiyun 	EMU_SRC_MDOCK_ADAT+4,
258*4882a593Smuzhiyun 	EMU_SRC_MDOCK_ADAT+5,
259*4882a593Smuzhiyun 	EMU_SRC_MDOCK_ADAT+6,
260*4882a593Smuzhiyun 	EMU_SRC_MDOCK_ADAT+7,
261*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A,
262*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+1,
263*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+2,
264*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+3,
265*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+4,
266*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+5,
267*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+6,
268*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+7,
269*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+8,
270*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+9,
271*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+0xa,
272*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+0xb,
273*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+0xc,
274*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+0xd,
275*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+0xe,
276*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32A+0xf,
277*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B,
278*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+1,
279*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+2,
280*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+3,
281*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+4,
282*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+5,
283*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+6,
284*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+7,
285*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+8,
286*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+9,
287*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+0xa,
288*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+0xb,
289*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+0xc,
290*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+0xd,
291*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+0xe,
292*4882a593Smuzhiyun 	EMU_SRC_ALICE_EMU32B+0xf,
293*4882a593Smuzhiyun };
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun /*
296*4882a593Smuzhiyun  * Data destinations - physical EMU outputs.
297*4882a593Smuzhiyun  * Each destination has an enum mixer control to choose a data source
298*4882a593Smuzhiyun  */
299*4882a593Smuzhiyun static const unsigned int emu1010_output_dst[] = {
300*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
301*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
302*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC2_LEFT1, /* 2 */
303*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */
304*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC3_LEFT1, /* 4 */
305*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */
306*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC4_LEFT1, /* 6 */
307*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */
308*4882a593Smuzhiyun 	EMU_DST_DOCK_PHONES_LEFT1, /* 8 */
309*4882a593Smuzhiyun 	EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */
310*4882a593Smuzhiyun 	EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */
311*4882a593Smuzhiyun 	EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */
312*4882a593Smuzhiyun 	EMU_DST_HANA_SPDIF_LEFT1, /* 12 */
313*4882a593Smuzhiyun 	EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */
314*4882a593Smuzhiyun 	EMU_DST_HAMOA_DAC_LEFT1, /* 14 */
315*4882a593Smuzhiyun 	EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */
316*4882a593Smuzhiyun 	EMU_DST_HANA_ADAT, /* 16 */
317*4882a593Smuzhiyun 	EMU_DST_HANA_ADAT+1, /* 17 */
318*4882a593Smuzhiyun 	EMU_DST_HANA_ADAT+2, /* 18 */
319*4882a593Smuzhiyun 	EMU_DST_HANA_ADAT+3, /* 19 */
320*4882a593Smuzhiyun 	EMU_DST_HANA_ADAT+4, /* 20 */
321*4882a593Smuzhiyun 	EMU_DST_HANA_ADAT+5, /* 21 */
322*4882a593Smuzhiyun 	EMU_DST_HANA_ADAT+6, /* 22 */
323*4882a593Smuzhiyun 	EMU_DST_HANA_ADAT+7, /* 23 */
324*4882a593Smuzhiyun };
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun /* 1616(m) cardbus */
327*4882a593Smuzhiyun static const unsigned int emu1616_output_dst[] = {
328*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC1_LEFT1,
329*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC1_RIGHT1,
330*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC2_LEFT1,
331*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC2_RIGHT1,
332*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC3_LEFT1,
333*4882a593Smuzhiyun 	EMU_DST_DOCK_DAC3_RIGHT1,
334*4882a593Smuzhiyun 	EMU_DST_MDOCK_SPDIF_LEFT1,
335*4882a593Smuzhiyun 	EMU_DST_MDOCK_SPDIF_RIGHT1,
336*4882a593Smuzhiyun 	EMU_DST_MDOCK_ADAT,
337*4882a593Smuzhiyun 	EMU_DST_MDOCK_ADAT+1,
338*4882a593Smuzhiyun 	EMU_DST_MDOCK_ADAT+2,
339*4882a593Smuzhiyun 	EMU_DST_MDOCK_ADAT+3,
340*4882a593Smuzhiyun 	EMU_DST_MDOCK_ADAT+4,
341*4882a593Smuzhiyun 	EMU_DST_MDOCK_ADAT+5,
342*4882a593Smuzhiyun 	EMU_DST_MDOCK_ADAT+6,
343*4882a593Smuzhiyun 	EMU_DST_MDOCK_ADAT+7,
344*4882a593Smuzhiyun 	EMU_DST_MANA_DAC_LEFT,
345*4882a593Smuzhiyun 	EMU_DST_MANA_DAC_RIGHT,
346*4882a593Smuzhiyun };
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun /*
349*4882a593Smuzhiyun  * Data destinations - HANA outputs going to Alice2 (audigy) for
350*4882a593Smuzhiyun  *   capture (EMU32 + I2S links)
351*4882a593Smuzhiyun  * Each destination has an enum mixer control to choose a data source
352*4882a593Smuzhiyun  */
353*4882a593Smuzhiyun static const unsigned int emu1010_input_dst[] = {
354*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_0,
355*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_1,
356*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_2,
357*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_3,
358*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_4,
359*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_5,
360*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_6,
361*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_7,
362*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_8,
363*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_9,
364*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_A,
365*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_B,
366*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_C,
367*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_D,
368*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_E,
369*4882a593Smuzhiyun 	EMU_DST_ALICE2_EMU32_F,
370*4882a593Smuzhiyun 	EMU_DST_ALICE_I2S0_LEFT,
371*4882a593Smuzhiyun 	EMU_DST_ALICE_I2S0_RIGHT,
372*4882a593Smuzhiyun 	EMU_DST_ALICE_I2S1_LEFT,
373*4882a593Smuzhiyun 	EMU_DST_ALICE_I2S1_RIGHT,
374*4882a593Smuzhiyun 	EMU_DST_ALICE_I2S2_LEFT,
375*4882a593Smuzhiyun 	EMU_DST_ALICE_I2S2_RIGHT,
376*4882a593Smuzhiyun };
377*4882a593Smuzhiyun 
snd_emu1010_input_output_source_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)378*4882a593Smuzhiyun static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
379*4882a593Smuzhiyun 						struct snd_ctl_elem_info *uinfo)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
384*4882a593Smuzhiyun 		return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts);
385*4882a593Smuzhiyun 	else
386*4882a593Smuzhiyun 		return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts);
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun 
snd_emu1010_output_source_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)389*4882a593Smuzhiyun static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
390*4882a593Smuzhiyun                                  struct snd_ctl_elem_value *ucontrol)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
393*4882a593Smuzhiyun 	unsigned int channel;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	channel = (kcontrol->private_value) & 0xff;
396*4882a593Smuzhiyun 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
397*4882a593Smuzhiyun 	if (channel >= 24 ||
398*4882a593Smuzhiyun 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
399*4882a593Smuzhiyun 	     channel >= 18))
400*4882a593Smuzhiyun 		return -EINVAL;
401*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
402*4882a593Smuzhiyun 	return 0;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun 
snd_emu1010_output_source_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)405*4882a593Smuzhiyun static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
406*4882a593Smuzhiyun                                  struct snd_ctl_elem_value *ucontrol)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
409*4882a593Smuzhiyun 	unsigned int val;
410*4882a593Smuzhiyun 	unsigned int channel;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	val = ucontrol->value.enumerated.item[0];
413*4882a593Smuzhiyun 	if (val >= 53 ||
414*4882a593Smuzhiyun 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
415*4882a593Smuzhiyun 	     val >= 49))
416*4882a593Smuzhiyun 		return -EINVAL;
417*4882a593Smuzhiyun 	channel = (kcontrol->private_value) & 0xff;
418*4882a593Smuzhiyun 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
419*4882a593Smuzhiyun 	if (channel >= 24 ||
420*4882a593Smuzhiyun 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
421*4882a593Smuzhiyun 	     channel >= 18))
422*4882a593Smuzhiyun 		return -EINVAL;
423*4882a593Smuzhiyun 	if (emu->emu1010.output_source[channel] == val)
424*4882a593Smuzhiyun 		return 0;
425*4882a593Smuzhiyun 	emu->emu1010.output_source[channel] = val;
426*4882a593Smuzhiyun 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
427*4882a593Smuzhiyun 		snd_emu1010_fpga_link_dst_src_write(emu,
428*4882a593Smuzhiyun 			emu1616_output_dst[channel], emu1616_src_regs[val]);
429*4882a593Smuzhiyun 	else
430*4882a593Smuzhiyun 		snd_emu1010_fpga_link_dst_src_write(emu,
431*4882a593Smuzhiyun 			emu1010_output_dst[channel], emu1010_src_regs[val]);
432*4882a593Smuzhiyun 	return 1;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
snd_emu1010_input_source_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)435*4882a593Smuzhiyun static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
436*4882a593Smuzhiyun                                  struct snd_ctl_elem_value *ucontrol)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
439*4882a593Smuzhiyun 	unsigned int channel;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	channel = (kcontrol->private_value) & 0xff;
442*4882a593Smuzhiyun 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
443*4882a593Smuzhiyun 	if (channel >= 22)
444*4882a593Smuzhiyun 		return -EINVAL;
445*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
446*4882a593Smuzhiyun 	return 0;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun 
snd_emu1010_input_source_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)449*4882a593Smuzhiyun static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
450*4882a593Smuzhiyun                                  struct snd_ctl_elem_value *ucontrol)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
453*4882a593Smuzhiyun 	unsigned int val;
454*4882a593Smuzhiyun 	unsigned int channel;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	val = ucontrol->value.enumerated.item[0];
457*4882a593Smuzhiyun 	if (val >= 53 ||
458*4882a593Smuzhiyun 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
459*4882a593Smuzhiyun 	     val >= 49))
460*4882a593Smuzhiyun 		return -EINVAL;
461*4882a593Smuzhiyun 	channel = (kcontrol->private_value) & 0xff;
462*4882a593Smuzhiyun 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
463*4882a593Smuzhiyun 	if (channel >= 22)
464*4882a593Smuzhiyun 		return -EINVAL;
465*4882a593Smuzhiyun 	if (emu->emu1010.input_source[channel] == val)
466*4882a593Smuzhiyun 		return 0;
467*4882a593Smuzhiyun 	emu->emu1010.input_source[channel] = val;
468*4882a593Smuzhiyun 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
469*4882a593Smuzhiyun 		snd_emu1010_fpga_link_dst_src_write(emu,
470*4882a593Smuzhiyun 			emu1010_input_dst[channel], emu1616_src_regs[val]);
471*4882a593Smuzhiyun 	else
472*4882a593Smuzhiyun 		snd_emu1010_fpga_link_dst_src_write(emu,
473*4882a593Smuzhiyun 			emu1010_input_dst[channel], emu1010_src_regs[val]);
474*4882a593Smuzhiyun 	return 1;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun #define EMU1010_SOURCE_OUTPUT(xname,chid) \
478*4882a593Smuzhiyun {								\
479*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
480*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
481*4882a593Smuzhiyun 	.info =  snd_emu1010_input_output_source_info,		\
482*4882a593Smuzhiyun 	.get =   snd_emu1010_output_source_get,			\
483*4882a593Smuzhiyun 	.put =   snd_emu1010_output_source_put,			\
484*4882a593Smuzhiyun 	.private_value = chid					\
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = {
488*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
489*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
490*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
491*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
492*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
493*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
494*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6),
495*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
496*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
497*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
498*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
499*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
500*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
501*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
502*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
503*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
504*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
505*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
506*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
507*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
508*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
509*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
510*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
511*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
512*4882a593Smuzhiyun };
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun /* 1616(m) cardbus */
516*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = {
517*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
518*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
519*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
520*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
521*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
522*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
523*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6),
524*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7),
525*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8),
526*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9),
527*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa),
528*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb),
529*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc),
530*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd),
531*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe),
532*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf),
533*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10),
534*4882a593Smuzhiyun 	EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11),
535*4882a593Smuzhiyun };
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun #define EMU1010_SOURCE_INPUT(xname,chid) \
539*4882a593Smuzhiyun {								\
540*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
541*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
542*4882a593Smuzhiyun 	.info =  snd_emu1010_input_output_source_info,		\
543*4882a593Smuzhiyun 	.get =   snd_emu1010_input_source_get,			\
544*4882a593Smuzhiyun 	.put =   snd_emu1010_input_source_put,			\
545*4882a593Smuzhiyun 	.private_value = chid					\
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = {
549*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
550*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
551*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
552*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
553*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
554*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
555*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
556*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
557*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
558*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
559*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
560*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
561*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
562*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
563*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
564*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
565*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
566*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
567*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
568*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
569*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
570*4882a593Smuzhiyun 	EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
571*4882a593Smuzhiyun };
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
576*4882a593Smuzhiyun 
snd_emu1010_adc_pads_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)577*4882a593Smuzhiyun static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
580*4882a593Smuzhiyun 	unsigned int mask = kcontrol->private_value & 0xff;
581*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
582*4882a593Smuzhiyun 	return 0;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun 
snd_emu1010_adc_pads_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)585*4882a593Smuzhiyun static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
588*4882a593Smuzhiyun 	unsigned int mask = kcontrol->private_value & 0xff;
589*4882a593Smuzhiyun 	unsigned int val, cache;
590*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0];
591*4882a593Smuzhiyun 	cache = emu->emu1010.adc_pads;
592*4882a593Smuzhiyun 	if (val == 1)
593*4882a593Smuzhiyun 		cache = cache | mask;
594*4882a593Smuzhiyun 	else
595*4882a593Smuzhiyun 		cache = cache & ~mask;
596*4882a593Smuzhiyun 	if (cache != emu->emu1010.adc_pads) {
597*4882a593Smuzhiyun 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
598*4882a593Smuzhiyun 	        emu->emu1010.adc_pads = cache;
599*4882a593Smuzhiyun 	}
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	return 0;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun #define EMU1010_ADC_PADS(xname,chid) \
607*4882a593Smuzhiyun {								\
608*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
609*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
610*4882a593Smuzhiyun 	.info =  snd_emu1010_adc_pads_info,			\
611*4882a593Smuzhiyun 	.get =   snd_emu1010_adc_pads_get,			\
612*4882a593Smuzhiyun 	.put =   snd_emu1010_adc_pads_put,			\
613*4882a593Smuzhiyun 	.private_value = chid					\
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu1010_adc_pads[] = {
617*4882a593Smuzhiyun 	EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
618*4882a593Smuzhiyun 	EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
619*4882a593Smuzhiyun 	EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
620*4882a593Smuzhiyun 	EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
621*4882a593Smuzhiyun };
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
624*4882a593Smuzhiyun 
snd_emu1010_dac_pads_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)625*4882a593Smuzhiyun static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
626*4882a593Smuzhiyun {
627*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
628*4882a593Smuzhiyun 	unsigned int mask = kcontrol->private_value & 0xff;
629*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
630*4882a593Smuzhiyun 	return 0;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun 
snd_emu1010_dac_pads_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)633*4882a593Smuzhiyun static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
636*4882a593Smuzhiyun 	unsigned int mask = kcontrol->private_value & 0xff;
637*4882a593Smuzhiyun 	unsigned int val, cache;
638*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0];
639*4882a593Smuzhiyun 	cache = emu->emu1010.dac_pads;
640*4882a593Smuzhiyun 	if (val == 1)
641*4882a593Smuzhiyun 		cache = cache | mask;
642*4882a593Smuzhiyun 	else
643*4882a593Smuzhiyun 		cache = cache & ~mask;
644*4882a593Smuzhiyun 	if (cache != emu->emu1010.dac_pads) {
645*4882a593Smuzhiyun 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
646*4882a593Smuzhiyun 	        emu->emu1010.dac_pads = cache;
647*4882a593Smuzhiyun 	}
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	return 0;
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun #define EMU1010_DAC_PADS(xname,chid) \
655*4882a593Smuzhiyun {								\
656*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
657*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
658*4882a593Smuzhiyun 	.info =  snd_emu1010_dac_pads_info,			\
659*4882a593Smuzhiyun 	.get =   snd_emu1010_dac_pads_get,			\
660*4882a593Smuzhiyun 	.put =   snd_emu1010_dac_pads_put,			\
661*4882a593Smuzhiyun 	.private_value = chid					\
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu1010_dac_pads[] = {
665*4882a593Smuzhiyun 	EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
666*4882a593Smuzhiyun 	EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
667*4882a593Smuzhiyun 	EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
668*4882a593Smuzhiyun 	EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
669*4882a593Smuzhiyun 	EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
670*4882a593Smuzhiyun };
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 
snd_emu1010_internal_clock_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)673*4882a593Smuzhiyun static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
674*4882a593Smuzhiyun 					  struct snd_ctl_elem_info *uinfo)
675*4882a593Smuzhiyun {
676*4882a593Smuzhiyun 	static const char * const texts[4] = {
677*4882a593Smuzhiyun 		"44100", "48000", "SPDIF", "ADAT"
678*4882a593Smuzhiyun 	};
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	return snd_ctl_enum_info(uinfo, 1, 4, texts);
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun 
snd_emu1010_internal_clock_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)683*4882a593Smuzhiyun static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
684*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
689*4882a593Smuzhiyun 	return 0;
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun 
snd_emu1010_internal_clock_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)692*4882a593Smuzhiyun static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
693*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
696*4882a593Smuzhiyun 	unsigned int val;
697*4882a593Smuzhiyun 	int change = 0;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	val = ucontrol->value.enumerated.item[0] ;
700*4882a593Smuzhiyun 	/* Limit: uinfo->value.enumerated.items = 4; */
701*4882a593Smuzhiyun 	if (val >= 4)
702*4882a593Smuzhiyun 		return -EINVAL;
703*4882a593Smuzhiyun 	change = (emu->emu1010.internal_clock != val);
704*4882a593Smuzhiyun 	if (change) {
705*4882a593Smuzhiyun 		emu->emu1010.internal_clock = val;
706*4882a593Smuzhiyun 		switch (val) {
707*4882a593Smuzhiyun 		case 0:
708*4882a593Smuzhiyun 			/* 44100 */
709*4882a593Smuzhiyun 			/* Mute all */
710*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
711*4882a593Smuzhiyun 			/* Default fallback clock 48kHz */
712*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
713*4882a593Smuzhiyun 			/* Word Clock source, Internal 44.1kHz x1 */
714*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
715*4882a593Smuzhiyun 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
716*4882a593Smuzhiyun 			/* Set LEDs on Audio Dock */
717*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
718*4882a593Smuzhiyun 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
719*4882a593Smuzhiyun 			/* Allow DLL to settle */
720*4882a593Smuzhiyun 			msleep(10);
721*4882a593Smuzhiyun 			/* Unmute all */
722*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
723*4882a593Smuzhiyun 			break;
724*4882a593Smuzhiyun 		case 1:
725*4882a593Smuzhiyun 			/* 48000 */
726*4882a593Smuzhiyun 			/* Mute all */
727*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
728*4882a593Smuzhiyun 			/* Default fallback clock 48kHz */
729*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
730*4882a593Smuzhiyun 			/* Word Clock source, Internal 48kHz x1 */
731*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
732*4882a593Smuzhiyun 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
733*4882a593Smuzhiyun 			/* Set LEDs on Audio Dock */
734*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
735*4882a593Smuzhiyun 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
736*4882a593Smuzhiyun 			/* Allow DLL to settle */
737*4882a593Smuzhiyun 			msleep(10);
738*4882a593Smuzhiyun 			/* Unmute all */
739*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
740*4882a593Smuzhiyun 			break;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 		case 2: /* Take clock from S/PDIF IN */
743*4882a593Smuzhiyun 			/* Mute all */
744*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
745*4882a593Smuzhiyun 			/* Default fallback clock 48kHz */
746*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
747*4882a593Smuzhiyun 			/* Word Clock source, sync to S/PDIF input */
748*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
749*4882a593Smuzhiyun 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
750*4882a593Smuzhiyun 			/* Set LEDs on Audio Dock */
751*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
752*4882a593Smuzhiyun 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
753*4882a593Smuzhiyun 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
754*4882a593Smuzhiyun 			/* Allow DLL to settle */
755*4882a593Smuzhiyun 			msleep(10);
756*4882a593Smuzhiyun 			/* Unmute all */
757*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
758*4882a593Smuzhiyun 			break;
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 		case 3:
761*4882a593Smuzhiyun 			/* Take clock from ADAT IN */
762*4882a593Smuzhiyun 			/* Mute all */
763*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
764*4882a593Smuzhiyun 			/* Default fallback clock 48kHz */
765*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
766*4882a593Smuzhiyun 			/* Word Clock source, sync to ADAT input */
767*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
768*4882a593Smuzhiyun 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
769*4882a593Smuzhiyun 			/* Set LEDs on Audio Dock */
770*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
771*4882a593Smuzhiyun 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
772*4882a593Smuzhiyun 			/* Allow DLL to settle */
773*4882a593Smuzhiyun 			msleep(10);
774*4882a593Smuzhiyun 			/*   Unmute all */
775*4882a593Smuzhiyun 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 			break;
779*4882a593Smuzhiyun 		}
780*4882a593Smuzhiyun 	}
781*4882a593Smuzhiyun         return change;
782*4882a593Smuzhiyun }
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu1010_internal_clock =
785*4882a593Smuzhiyun {
786*4882a593Smuzhiyun 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
787*4882a593Smuzhiyun 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
788*4882a593Smuzhiyun 	.name =         "Clock Internal Rate",
789*4882a593Smuzhiyun 	.count =	1,
790*4882a593Smuzhiyun 	.info =         snd_emu1010_internal_clock_info,
791*4882a593Smuzhiyun 	.get =          snd_emu1010_internal_clock_get,
792*4882a593Smuzhiyun 	.put =          snd_emu1010_internal_clock_put
793*4882a593Smuzhiyun };
794*4882a593Smuzhiyun 
snd_emu1010_optical_out_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)795*4882a593Smuzhiyun static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
796*4882a593Smuzhiyun 					  struct snd_ctl_elem_info *uinfo)
797*4882a593Smuzhiyun {
798*4882a593Smuzhiyun 	static const char * const texts[2] = {
799*4882a593Smuzhiyun 		"SPDIF", "ADAT"
800*4882a593Smuzhiyun 	};
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun 
snd_emu1010_optical_out_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)805*4882a593Smuzhiyun static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol,
806*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out;
811*4882a593Smuzhiyun 	return 0;
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun 
snd_emu1010_optical_out_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)814*4882a593Smuzhiyun static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
815*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
816*4882a593Smuzhiyun {
817*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
818*4882a593Smuzhiyun 	unsigned int val;
819*4882a593Smuzhiyun 	u32 tmp;
820*4882a593Smuzhiyun 	int change = 0;
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 	val = ucontrol->value.enumerated.item[0];
823*4882a593Smuzhiyun 	/* Limit: uinfo->value.enumerated.items = 2; */
824*4882a593Smuzhiyun 	if (val >= 2)
825*4882a593Smuzhiyun 		return -EINVAL;
826*4882a593Smuzhiyun 	change = (emu->emu1010.optical_out != val);
827*4882a593Smuzhiyun 	if (change) {
828*4882a593Smuzhiyun 		emu->emu1010.optical_out = val;
829*4882a593Smuzhiyun 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) |
830*4882a593Smuzhiyun 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0);
831*4882a593Smuzhiyun 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
832*4882a593Smuzhiyun 	}
833*4882a593Smuzhiyun 	return change;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu1010_optical_out = {
837*4882a593Smuzhiyun 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
838*4882a593Smuzhiyun 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
839*4882a593Smuzhiyun 	.name =         "Optical Output Mode",
840*4882a593Smuzhiyun 	.count =	1,
841*4882a593Smuzhiyun 	.info =         snd_emu1010_optical_out_info,
842*4882a593Smuzhiyun 	.get =          snd_emu1010_optical_out_get,
843*4882a593Smuzhiyun 	.put =          snd_emu1010_optical_out_put
844*4882a593Smuzhiyun };
845*4882a593Smuzhiyun 
snd_emu1010_optical_in_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)846*4882a593Smuzhiyun static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
847*4882a593Smuzhiyun 					  struct snd_ctl_elem_info *uinfo)
848*4882a593Smuzhiyun {
849*4882a593Smuzhiyun 	static const char * const texts[2] = {
850*4882a593Smuzhiyun 		"SPDIF", "ADAT"
851*4882a593Smuzhiyun 	};
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
854*4882a593Smuzhiyun }
855*4882a593Smuzhiyun 
snd_emu1010_optical_in_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)856*4882a593Smuzhiyun static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
857*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
858*4882a593Smuzhiyun {
859*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
862*4882a593Smuzhiyun 	return 0;
863*4882a593Smuzhiyun }
864*4882a593Smuzhiyun 
snd_emu1010_optical_in_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)865*4882a593Smuzhiyun static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
866*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
867*4882a593Smuzhiyun {
868*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
869*4882a593Smuzhiyun 	unsigned int val;
870*4882a593Smuzhiyun 	u32 tmp;
871*4882a593Smuzhiyun 	int change = 0;
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 	val = ucontrol->value.enumerated.item[0];
874*4882a593Smuzhiyun 	/* Limit: uinfo->value.enumerated.items = 2; */
875*4882a593Smuzhiyun 	if (val >= 2)
876*4882a593Smuzhiyun 		return -EINVAL;
877*4882a593Smuzhiyun 	change = (emu->emu1010.optical_in != val);
878*4882a593Smuzhiyun 	if (change) {
879*4882a593Smuzhiyun 		emu->emu1010.optical_in = val;
880*4882a593Smuzhiyun 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) |
881*4882a593Smuzhiyun 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0);
882*4882a593Smuzhiyun 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
883*4882a593Smuzhiyun 	}
884*4882a593Smuzhiyun 	return change;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu1010_optical_in = {
888*4882a593Smuzhiyun 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
889*4882a593Smuzhiyun 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
890*4882a593Smuzhiyun 	.name =         "Optical Input Mode",
891*4882a593Smuzhiyun 	.count =	1,
892*4882a593Smuzhiyun 	.info =         snd_emu1010_optical_in_info,
893*4882a593Smuzhiyun 	.get =          snd_emu1010_optical_in_get,
894*4882a593Smuzhiyun 	.put =          snd_emu1010_optical_in_put
895*4882a593Smuzhiyun };
896*4882a593Smuzhiyun 
snd_audigy_i2c_capture_source_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)897*4882a593Smuzhiyun static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
898*4882a593Smuzhiyun 					  struct snd_ctl_elem_info *uinfo)
899*4882a593Smuzhiyun {
900*4882a593Smuzhiyun #if 0
901*4882a593Smuzhiyun 	static const char * const texts[4] = {
902*4882a593Smuzhiyun 		"Unknown1", "Unknown2", "Mic", "Line"
903*4882a593Smuzhiyun 	};
904*4882a593Smuzhiyun #endif
905*4882a593Smuzhiyun 	static const char * const texts[2] = {
906*4882a593Smuzhiyun 		"Mic", "Line"
907*4882a593Smuzhiyun 	};
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
910*4882a593Smuzhiyun }
911*4882a593Smuzhiyun 
snd_audigy_i2c_capture_source_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)912*4882a593Smuzhiyun static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
913*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
914*4882a593Smuzhiyun {
915*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
918*4882a593Smuzhiyun 	return 0;
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun 
snd_audigy_i2c_capture_source_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)921*4882a593Smuzhiyun static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
922*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
923*4882a593Smuzhiyun {
924*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
925*4882a593Smuzhiyun 	unsigned int source_id;
926*4882a593Smuzhiyun 	unsigned int ngain, ogain;
927*4882a593Smuzhiyun 	u32 gpio;
928*4882a593Smuzhiyun 	int change = 0;
929*4882a593Smuzhiyun 	unsigned long flags;
930*4882a593Smuzhiyun 	u32 source;
931*4882a593Smuzhiyun 	/* If the capture source has changed,
932*4882a593Smuzhiyun 	 * update the capture volume from the cached value
933*4882a593Smuzhiyun 	 * for the particular source.
934*4882a593Smuzhiyun 	 */
935*4882a593Smuzhiyun 	source_id = ucontrol->value.enumerated.item[0];
936*4882a593Smuzhiyun 	/* Limit: uinfo->value.enumerated.items = 2; */
937*4882a593Smuzhiyun 	/*        emu->i2c_capture_volume */
938*4882a593Smuzhiyun 	if (source_id >= 2)
939*4882a593Smuzhiyun 		return -EINVAL;
940*4882a593Smuzhiyun 	change = (emu->i2c_capture_source != source_id);
941*4882a593Smuzhiyun 	if (change) {
942*4882a593Smuzhiyun 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
943*4882a593Smuzhiyun 		spin_lock_irqsave(&emu->emu_lock, flags);
944*4882a593Smuzhiyun 		gpio = inl(emu->port + A_IOCFG);
945*4882a593Smuzhiyun 		if (source_id==0)
946*4882a593Smuzhiyun 			outl(gpio | 0x4, emu->port + A_IOCFG);
947*4882a593Smuzhiyun 		else
948*4882a593Smuzhiyun 			outl(gpio & ~0x4, emu->port + A_IOCFG);
949*4882a593Smuzhiyun 		spin_unlock_irqrestore(&emu->emu_lock, flags);
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
952*4882a593Smuzhiyun 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
953*4882a593Smuzhiyun 		if (ngain != ogain)
954*4882a593Smuzhiyun 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
955*4882a593Smuzhiyun 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
956*4882a593Smuzhiyun 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
957*4882a593Smuzhiyun 		if (ngain != ogain)
958*4882a593Smuzhiyun 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 		source = 1 << (source_id + 2);
961*4882a593Smuzhiyun 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
962*4882a593Smuzhiyun 		emu->i2c_capture_source = source_id;
963*4882a593Smuzhiyun 	}
964*4882a593Smuzhiyun         return change;
965*4882a593Smuzhiyun }
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_audigy_i2c_capture_source =
968*4882a593Smuzhiyun {
969*4882a593Smuzhiyun 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
970*4882a593Smuzhiyun 		.name =		"Capture Source",
971*4882a593Smuzhiyun 		.info =		snd_audigy_i2c_capture_source_info,
972*4882a593Smuzhiyun 		.get =		snd_audigy_i2c_capture_source_get,
973*4882a593Smuzhiyun 		.put =		snd_audigy_i2c_capture_source_put
974*4882a593Smuzhiyun };
975*4882a593Smuzhiyun 
snd_audigy_i2c_volume_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)976*4882a593Smuzhiyun static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
977*4882a593Smuzhiyun 				  struct snd_ctl_elem_info *uinfo)
978*4882a593Smuzhiyun {
979*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
980*4882a593Smuzhiyun 	uinfo->count = 2;
981*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
982*4882a593Smuzhiyun 	uinfo->value.integer.max = 255;
983*4882a593Smuzhiyun 	return 0;
984*4882a593Smuzhiyun }
985*4882a593Smuzhiyun 
snd_audigy_i2c_volume_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)986*4882a593Smuzhiyun static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
987*4882a593Smuzhiyun 				 struct snd_ctl_elem_value *ucontrol)
988*4882a593Smuzhiyun {
989*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
990*4882a593Smuzhiyun 	unsigned int source_id;
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 	source_id = kcontrol->private_value;
993*4882a593Smuzhiyun 	/* Limit: emu->i2c_capture_volume */
994*4882a593Smuzhiyun         /*        capture_source: uinfo->value.enumerated.items = 2 */
995*4882a593Smuzhiyun 	if (source_id >= 2)
996*4882a593Smuzhiyun 		return -EINVAL;
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
999*4882a593Smuzhiyun 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
1000*4882a593Smuzhiyun 	return 0;
1001*4882a593Smuzhiyun }
1002*4882a593Smuzhiyun 
snd_audigy_i2c_volume_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1003*4882a593Smuzhiyun static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
1004*4882a593Smuzhiyun 				 struct snd_ctl_elem_value *ucontrol)
1005*4882a593Smuzhiyun {
1006*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1007*4882a593Smuzhiyun 	unsigned int ogain;
1008*4882a593Smuzhiyun 	unsigned int ngain;
1009*4882a593Smuzhiyun 	unsigned int source_id;
1010*4882a593Smuzhiyun 	int change = 0;
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	source_id = kcontrol->private_value;
1013*4882a593Smuzhiyun 	/* Limit: emu->i2c_capture_volume */
1014*4882a593Smuzhiyun         /*        capture_source: uinfo->value.enumerated.items = 2 */
1015*4882a593Smuzhiyun 	if (source_id >= 2)
1016*4882a593Smuzhiyun 		return -EINVAL;
1017*4882a593Smuzhiyun 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
1018*4882a593Smuzhiyun 	ngain = ucontrol->value.integer.value[0];
1019*4882a593Smuzhiyun 	if (ngain > 0xff)
1020*4882a593Smuzhiyun 		return 0;
1021*4882a593Smuzhiyun 	if (ogain != ngain) {
1022*4882a593Smuzhiyun 		if (emu->i2c_capture_source == source_id)
1023*4882a593Smuzhiyun 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
1024*4882a593Smuzhiyun 		emu->i2c_capture_volume[source_id][0] = ngain;
1025*4882a593Smuzhiyun 		change = 1;
1026*4882a593Smuzhiyun 	}
1027*4882a593Smuzhiyun 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
1028*4882a593Smuzhiyun 	ngain = ucontrol->value.integer.value[1];
1029*4882a593Smuzhiyun 	if (ngain > 0xff)
1030*4882a593Smuzhiyun 		return 0;
1031*4882a593Smuzhiyun 	if (ogain != ngain) {
1032*4882a593Smuzhiyun 		if (emu->i2c_capture_source == source_id)
1033*4882a593Smuzhiyun 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
1034*4882a593Smuzhiyun 		emu->i2c_capture_volume[source_id][1] = ngain;
1035*4882a593Smuzhiyun 		change = 1;
1036*4882a593Smuzhiyun 	}
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 	return change;
1039*4882a593Smuzhiyun }
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun #define I2C_VOLUME(xname,chid) \
1042*4882a593Smuzhiyun {								\
1043*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
1044*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
1045*4882a593Smuzhiyun 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
1046*4882a593Smuzhiyun 	.info =  snd_audigy_i2c_volume_info,			\
1047*4882a593Smuzhiyun 	.get =   snd_audigy_i2c_volume_get,			\
1048*4882a593Smuzhiyun 	.put =   snd_audigy_i2c_volume_put,			\
1049*4882a593Smuzhiyun 	.tlv = { .p = snd_audigy_db_scale2 },			\
1050*4882a593Smuzhiyun 	.private_value = chid					\
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = {
1055*4882a593Smuzhiyun 	I2C_VOLUME("Mic Capture Volume", 0),
1056*4882a593Smuzhiyun 	I2C_VOLUME("Line Capture Volume", 0)
1057*4882a593Smuzhiyun };
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun #if 0
1060*4882a593Smuzhiyun static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1061*4882a593Smuzhiyun {
1062*4882a593Smuzhiyun 	static const char * const texts[] = {"44100", "48000", "96000"};
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun 	return snd_ctl_enum_info(uinfo, 1, 3, texts);
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun 
1067*4882a593Smuzhiyun static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
1068*4882a593Smuzhiyun                                  struct snd_ctl_elem_value *ucontrol)
1069*4882a593Smuzhiyun {
1070*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1071*4882a593Smuzhiyun 	unsigned int tmp;
1072*4882a593Smuzhiyun 	unsigned long flags;
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 
1075*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1076*4882a593Smuzhiyun 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
1077*4882a593Smuzhiyun 	switch (tmp & A_SPDIF_RATE_MASK) {
1078*4882a593Smuzhiyun 	case A_SPDIF_44100:
1079*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 0;
1080*4882a593Smuzhiyun 		break;
1081*4882a593Smuzhiyun 	case A_SPDIF_48000:
1082*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 1;
1083*4882a593Smuzhiyun 		break;
1084*4882a593Smuzhiyun 	case A_SPDIF_96000:
1085*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 2;
1086*4882a593Smuzhiyun 		break;
1087*4882a593Smuzhiyun 	default:
1088*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = 1;
1089*4882a593Smuzhiyun 	}
1090*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1091*4882a593Smuzhiyun 	return 0;
1092*4882a593Smuzhiyun }
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
1095*4882a593Smuzhiyun                                  struct snd_ctl_elem_value *ucontrol)
1096*4882a593Smuzhiyun {
1097*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1098*4882a593Smuzhiyun 	int change;
1099*4882a593Smuzhiyun 	unsigned int reg, val, tmp;
1100*4882a593Smuzhiyun 	unsigned long flags;
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	switch(ucontrol->value.enumerated.item[0]) {
1103*4882a593Smuzhiyun 	case 0:
1104*4882a593Smuzhiyun 		val = A_SPDIF_44100;
1105*4882a593Smuzhiyun 		break;
1106*4882a593Smuzhiyun 	case 1:
1107*4882a593Smuzhiyun 		val = A_SPDIF_48000;
1108*4882a593Smuzhiyun 		break;
1109*4882a593Smuzhiyun 	case 2:
1110*4882a593Smuzhiyun 		val = A_SPDIF_96000;
1111*4882a593Smuzhiyun 		break;
1112*4882a593Smuzhiyun 	default:
1113*4882a593Smuzhiyun 		val = A_SPDIF_48000;
1114*4882a593Smuzhiyun 		break;
1115*4882a593Smuzhiyun 	}
1116*4882a593Smuzhiyun 
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1119*4882a593Smuzhiyun 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
1120*4882a593Smuzhiyun 	tmp = reg & ~A_SPDIF_RATE_MASK;
1121*4882a593Smuzhiyun 	tmp |= val;
1122*4882a593Smuzhiyun 	if ((change = (tmp != reg)))
1123*4882a593Smuzhiyun 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
1124*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1125*4882a593Smuzhiyun 	return change;
1126*4882a593Smuzhiyun }
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_audigy_spdif_output_rate =
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
1131*4882a593Smuzhiyun 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
1132*4882a593Smuzhiyun 	.name =         "Audigy SPDIF Output Sample Rate",
1133*4882a593Smuzhiyun 	.count =	1,
1134*4882a593Smuzhiyun 	.info =         snd_audigy_spdif_output_rate_info,
1135*4882a593Smuzhiyun 	.get =          snd_audigy_spdif_output_rate_get,
1136*4882a593Smuzhiyun 	.put =          snd_audigy_spdif_output_rate_put
1137*4882a593Smuzhiyun };
1138*4882a593Smuzhiyun #endif
1139*4882a593Smuzhiyun 
snd_emu10k1_spdif_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1140*4882a593Smuzhiyun static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1141*4882a593Smuzhiyun                                  struct snd_ctl_elem_value *ucontrol)
1142*4882a593Smuzhiyun {
1143*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1144*4882a593Smuzhiyun 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1145*4882a593Smuzhiyun 	int change;
1146*4882a593Smuzhiyun 	unsigned int val;
1147*4882a593Smuzhiyun 	unsigned long flags;
1148*4882a593Smuzhiyun 
1149*4882a593Smuzhiyun 	/* Limit: emu->spdif_bits */
1150*4882a593Smuzhiyun 	if (idx >= 3)
1151*4882a593Smuzhiyun 		return -EINVAL;
1152*4882a593Smuzhiyun 	val = (ucontrol->value.iec958.status[0] << 0) |
1153*4882a593Smuzhiyun 	      (ucontrol->value.iec958.status[1] << 8) |
1154*4882a593Smuzhiyun 	      (ucontrol->value.iec958.status[2] << 16) |
1155*4882a593Smuzhiyun 	      (ucontrol->value.iec958.status[3] << 24);
1156*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1157*4882a593Smuzhiyun 	change = val != emu->spdif_bits[idx];
1158*4882a593Smuzhiyun 	if (change) {
1159*4882a593Smuzhiyun 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
1160*4882a593Smuzhiyun 		emu->spdif_bits[idx] = val;
1161*4882a593Smuzhiyun 	}
1162*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1163*4882a593Smuzhiyun 	return change;
1164*4882a593Smuzhiyun }
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
1167*4882a593Smuzhiyun {
1168*4882a593Smuzhiyun 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
1169*4882a593Smuzhiyun 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
1170*4882a593Smuzhiyun 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
1171*4882a593Smuzhiyun 	.count =	3,
1172*4882a593Smuzhiyun 	.info =         snd_emu10k1_spdif_info,
1173*4882a593Smuzhiyun 	.get =          snd_emu10k1_spdif_get_mask
1174*4882a593Smuzhiyun };
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
1177*4882a593Smuzhiyun {
1178*4882a593Smuzhiyun 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
1179*4882a593Smuzhiyun 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
1180*4882a593Smuzhiyun 	.count =	3,
1181*4882a593Smuzhiyun 	.info =         snd_emu10k1_spdif_info,
1182*4882a593Smuzhiyun 	.get =          snd_emu10k1_spdif_get,
1183*4882a593Smuzhiyun 	.put =          snd_emu10k1_spdif_put
1184*4882a593Smuzhiyun };
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun 
update_emu10k1_fxrt(struct snd_emu10k1 * emu,int voice,unsigned char * route)1187*4882a593Smuzhiyun static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
1188*4882a593Smuzhiyun {
1189*4882a593Smuzhiyun 	if (emu->audigy) {
1190*4882a593Smuzhiyun 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
1191*4882a593Smuzhiyun 				      snd_emu10k1_compose_audigy_fxrt1(route));
1192*4882a593Smuzhiyun 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
1193*4882a593Smuzhiyun 				      snd_emu10k1_compose_audigy_fxrt2(route));
1194*4882a593Smuzhiyun 	} else {
1195*4882a593Smuzhiyun 		snd_emu10k1_ptr_write(emu, FXRT, voice,
1196*4882a593Smuzhiyun 				      snd_emu10k1_compose_send_routing(route));
1197*4882a593Smuzhiyun 	}
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun 
update_emu10k1_send_volume(struct snd_emu10k1 * emu,int voice,unsigned char * volume)1200*4882a593Smuzhiyun static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
1201*4882a593Smuzhiyun {
1202*4882a593Smuzhiyun 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
1203*4882a593Smuzhiyun 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
1204*4882a593Smuzhiyun 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
1205*4882a593Smuzhiyun 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
1206*4882a593Smuzhiyun 	if (emu->audigy) {
1207*4882a593Smuzhiyun 		unsigned int val = ((unsigned int)volume[4] << 24) |
1208*4882a593Smuzhiyun 			((unsigned int)volume[5] << 16) |
1209*4882a593Smuzhiyun 			((unsigned int)volume[6] << 8) |
1210*4882a593Smuzhiyun 			(unsigned int)volume[7];
1211*4882a593Smuzhiyun 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
1212*4882a593Smuzhiyun 	}
1213*4882a593Smuzhiyun }
1214*4882a593Smuzhiyun 
1215*4882a593Smuzhiyun /* PCM stream controls */
1216*4882a593Smuzhiyun 
snd_emu10k1_send_routing_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1217*4882a593Smuzhiyun static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1218*4882a593Smuzhiyun {
1219*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1220*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1221*4882a593Smuzhiyun 	uinfo->count = emu->audigy ? 3*8 : 3*4;
1222*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
1223*4882a593Smuzhiyun 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
1224*4882a593Smuzhiyun 	return 0;
1225*4882a593Smuzhiyun }
1226*4882a593Smuzhiyun 
snd_emu10k1_send_routing_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1227*4882a593Smuzhiyun static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1228*4882a593Smuzhiyun                                         struct snd_ctl_elem_value *ucontrol)
1229*4882a593Smuzhiyun {
1230*4882a593Smuzhiyun 	unsigned long flags;
1231*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1232*4882a593Smuzhiyun 	struct snd_emu10k1_pcm_mixer *mix =
1233*4882a593Smuzhiyun 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
1234*4882a593Smuzhiyun 	int voice, idx;
1235*4882a593Smuzhiyun 	int num_efx = emu->audigy ? 8 : 4;
1236*4882a593Smuzhiyun 	int mask = emu->audigy ? 0x3f : 0x0f;
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1239*4882a593Smuzhiyun 	for (voice = 0; voice < 3; voice++)
1240*4882a593Smuzhiyun 		for (idx = 0; idx < num_efx; idx++)
1241*4882a593Smuzhiyun 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
1242*4882a593Smuzhiyun 				mix->send_routing[voice][idx] & mask;
1243*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1244*4882a593Smuzhiyun 	return 0;
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun 
snd_emu10k1_send_routing_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1247*4882a593Smuzhiyun static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1248*4882a593Smuzhiyun                                         struct snd_ctl_elem_value *ucontrol)
1249*4882a593Smuzhiyun {
1250*4882a593Smuzhiyun 	unsigned long flags;
1251*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1252*4882a593Smuzhiyun 	struct snd_emu10k1_pcm_mixer *mix =
1253*4882a593Smuzhiyun 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
1254*4882a593Smuzhiyun 	int change = 0, voice, idx, val;
1255*4882a593Smuzhiyun 	int num_efx = emu->audigy ? 8 : 4;
1256*4882a593Smuzhiyun 	int mask = emu->audigy ? 0x3f : 0x0f;
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1259*4882a593Smuzhiyun 	for (voice = 0; voice < 3; voice++)
1260*4882a593Smuzhiyun 		for (idx = 0; idx < num_efx; idx++) {
1261*4882a593Smuzhiyun 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
1262*4882a593Smuzhiyun 			if (mix->send_routing[voice][idx] != val) {
1263*4882a593Smuzhiyun 				mix->send_routing[voice][idx] = val;
1264*4882a593Smuzhiyun 				change = 1;
1265*4882a593Smuzhiyun 			}
1266*4882a593Smuzhiyun 		}
1267*4882a593Smuzhiyun 	if (change && mix->epcm) {
1268*4882a593Smuzhiyun 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
1269*4882a593Smuzhiyun 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
1270*4882a593Smuzhiyun 					    &mix->send_routing[1][0]);
1271*4882a593Smuzhiyun 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
1272*4882a593Smuzhiyun 					    &mix->send_routing[2][0]);
1273*4882a593Smuzhiyun 		} else if (mix->epcm->voices[0]) {
1274*4882a593Smuzhiyun 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
1275*4882a593Smuzhiyun 					    &mix->send_routing[0][0]);
1276*4882a593Smuzhiyun 		}
1277*4882a593Smuzhiyun 	}
1278*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1279*4882a593Smuzhiyun 	return change;
1280*4882a593Smuzhiyun }
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu10k1_send_routing_control =
1283*4882a593Smuzhiyun {
1284*4882a593Smuzhiyun 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
1285*4882a593Smuzhiyun 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
1286*4882a593Smuzhiyun 	.name =         "EMU10K1 PCM Send Routing",
1287*4882a593Smuzhiyun 	.count =	32,
1288*4882a593Smuzhiyun 	.info =         snd_emu10k1_send_routing_info,
1289*4882a593Smuzhiyun 	.get =          snd_emu10k1_send_routing_get,
1290*4882a593Smuzhiyun 	.put =          snd_emu10k1_send_routing_put
1291*4882a593Smuzhiyun };
1292*4882a593Smuzhiyun 
snd_emu10k1_send_volume_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1293*4882a593Smuzhiyun static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1294*4882a593Smuzhiyun {
1295*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1296*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1297*4882a593Smuzhiyun 	uinfo->count = emu->audigy ? 3*8 : 3*4;
1298*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
1299*4882a593Smuzhiyun 	uinfo->value.integer.max = 255;
1300*4882a593Smuzhiyun 	return 0;
1301*4882a593Smuzhiyun }
1302*4882a593Smuzhiyun 
snd_emu10k1_send_volume_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1303*4882a593Smuzhiyun static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1304*4882a593Smuzhiyun                                        struct snd_ctl_elem_value *ucontrol)
1305*4882a593Smuzhiyun {
1306*4882a593Smuzhiyun 	unsigned long flags;
1307*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1308*4882a593Smuzhiyun 	struct snd_emu10k1_pcm_mixer *mix =
1309*4882a593Smuzhiyun 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
1310*4882a593Smuzhiyun 	int idx;
1311*4882a593Smuzhiyun 	int num_efx = emu->audigy ? 8 : 4;
1312*4882a593Smuzhiyun 
1313*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1314*4882a593Smuzhiyun 	for (idx = 0; idx < 3*num_efx; idx++)
1315*4882a593Smuzhiyun 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
1316*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1317*4882a593Smuzhiyun 	return 0;
1318*4882a593Smuzhiyun }
1319*4882a593Smuzhiyun 
snd_emu10k1_send_volume_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1320*4882a593Smuzhiyun static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1321*4882a593Smuzhiyun                                        struct snd_ctl_elem_value *ucontrol)
1322*4882a593Smuzhiyun {
1323*4882a593Smuzhiyun 	unsigned long flags;
1324*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1325*4882a593Smuzhiyun 	struct snd_emu10k1_pcm_mixer *mix =
1326*4882a593Smuzhiyun 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
1327*4882a593Smuzhiyun 	int change = 0, idx, val;
1328*4882a593Smuzhiyun 	int num_efx = emu->audigy ? 8 : 4;
1329*4882a593Smuzhiyun 
1330*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1331*4882a593Smuzhiyun 	for (idx = 0; idx < 3*num_efx; idx++) {
1332*4882a593Smuzhiyun 		val = ucontrol->value.integer.value[idx] & 255;
1333*4882a593Smuzhiyun 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
1334*4882a593Smuzhiyun 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
1335*4882a593Smuzhiyun 			change = 1;
1336*4882a593Smuzhiyun 		}
1337*4882a593Smuzhiyun 	}
1338*4882a593Smuzhiyun 	if (change && mix->epcm) {
1339*4882a593Smuzhiyun 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
1340*4882a593Smuzhiyun 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
1341*4882a593Smuzhiyun 						   &mix->send_volume[1][0]);
1342*4882a593Smuzhiyun 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
1343*4882a593Smuzhiyun 						   &mix->send_volume[2][0]);
1344*4882a593Smuzhiyun 		} else if (mix->epcm->voices[0]) {
1345*4882a593Smuzhiyun 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
1346*4882a593Smuzhiyun 						   &mix->send_volume[0][0]);
1347*4882a593Smuzhiyun 		}
1348*4882a593Smuzhiyun 	}
1349*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1350*4882a593Smuzhiyun 	return change;
1351*4882a593Smuzhiyun }
1352*4882a593Smuzhiyun 
1353*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
1354*4882a593Smuzhiyun {
1355*4882a593Smuzhiyun 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
1356*4882a593Smuzhiyun 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
1357*4882a593Smuzhiyun 	.name =         "EMU10K1 PCM Send Volume",
1358*4882a593Smuzhiyun 	.count =	32,
1359*4882a593Smuzhiyun 	.info =         snd_emu10k1_send_volume_info,
1360*4882a593Smuzhiyun 	.get =          snd_emu10k1_send_volume_get,
1361*4882a593Smuzhiyun 	.put =          snd_emu10k1_send_volume_put
1362*4882a593Smuzhiyun };
1363*4882a593Smuzhiyun 
snd_emu10k1_attn_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1364*4882a593Smuzhiyun static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1365*4882a593Smuzhiyun {
1366*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1367*4882a593Smuzhiyun 	uinfo->count = 3;
1368*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
1369*4882a593Smuzhiyun 	uinfo->value.integer.max = 0xffff;
1370*4882a593Smuzhiyun 	return 0;
1371*4882a593Smuzhiyun }
1372*4882a593Smuzhiyun 
snd_emu10k1_attn_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1373*4882a593Smuzhiyun static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1374*4882a593Smuzhiyun                                 struct snd_ctl_elem_value *ucontrol)
1375*4882a593Smuzhiyun {
1376*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1377*4882a593Smuzhiyun 	struct snd_emu10k1_pcm_mixer *mix =
1378*4882a593Smuzhiyun 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
1379*4882a593Smuzhiyun 	unsigned long flags;
1380*4882a593Smuzhiyun 	int idx;
1381*4882a593Smuzhiyun 
1382*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1383*4882a593Smuzhiyun 	for (idx = 0; idx < 3; idx++)
1384*4882a593Smuzhiyun 		ucontrol->value.integer.value[idx] = mix->attn[idx];
1385*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1386*4882a593Smuzhiyun 	return 0;
1387*4882a593Smuzhiyun }
1388*4882a593Smuzhiyun 
snd_emu10k1_attn_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1389*4882a593Smuzhiyun static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1390*4882a593Smuzhiyun 				struct snd_ctl_elem_value *ucontrol)
1391*4882a593Smuzhiyun {
1392*4882a593Smuzhiyun 	unsigned long flags;
1393*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1394*4882a593Smuzhiyun 	struct snd_emu10k1_pcm_mixer *mix =
1395*4882a593Smuzhiyun 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
1396*4882a593Smuzhiyun 	int change = 0, idx, val;
1397*4882a593Smuzhiyun 
1398*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1399*4882a593Smuzhiyun 	for (idx = 0; idx < 3; idx++) {
1400*4882a593Smuzhiyun 		val = ucontrol->value.integer.value[idx] & 0xffff;
1401*4882a593Smuzhiyun 		if (mix->attn[idx] != val) {
1402*4882a593Smuzhiyun 			mix->attn[idx] = val;
1403*4882a593Smuzhiyun 			change = 1;
1404*4882a593Smuzhiyun 		}
1405*4882a593Smuzhiyun 	}
1406*4882a593Smuzhiyun 	if (change && mix->epcm) {
1407*4882a593Smuzhiyun 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
1408*4882a593Smuzhiyun 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
1409*4882a593Smuzhiyun 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
1410*4882a593Smuzhiyun 		} else if (mix->epcm->voices[0]) {
1411*4882a593Smuzhiyun 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
1412*4882a593Smuzhiyun 		}
1413*4882a593Smuzhiyun 	}
1414*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1415*4882a593Smuzhiyun 	return change;
1416*4882a593Smuzhiyun }
1417*4882a593Smuzhiyun 
1418*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu10k1_attn_control =
1419*4882a593Smuzhiyun {
1420*4882a593Smuzhiyun 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
1421*4882a593Smuzhiyun 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
1422*4882a593Smuzhiyun 	.name =         "EMU10K1 PCM Volume",
1423*4882a593Smuzhiyun 	.count =	32,
1424*4882a593Smuzhiyun 	.info =         snd_emu10k1_attn_info,
1425*4882a593Smuzhiyun 	.get =          snd_emu10k1_attn_get,
1426*4882a593Smuzhiyun 	.put =          snd_emu10k1_attn_put
1427*4882a593Smuzhiyun };
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun /* Mutichannel PCM stream controls */
1430*4882a593Smuzhiyun 
snd_emu10k1_efx_send_routing_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1431*4882a593Smuzhiyun static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1432*4882a593Smuzhiyun {
1433*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1434*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1435*4882a593Smuzhiyun 	uinfo->count = emu->audigy ? 8 : 4;
1436*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
1437*4882a593Smuzhiyun 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
1438*4882a593Smuzhiyun 	return 0;
1439*4882a593Smuzhiyun }
1440*4882a593Smuzhiyun 
snd_emu10k1_efx_send_routing_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1441*4882a593Smuzhiyun static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1442*4882a593Smuzhiyun                                         struct snd_ctl_elem_value *ucontrol)
1443*4882a593Smuzhiyun {
1444*4882a593Smuzhiyun 	unsigned long flags;
1445*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1446*4882a593Smuzhiyun 	struct snd_emu10k1_pcm_mixer *mix =
1447*4882a593Smuzhiyun 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
1448*4882a593Smuzhiyun 	int idx;
1449*4882a593Smuzhiyun 	int num_efx = emu->audigy ? 8 : 4;
1450*4882a593Smuzhiyun 	int mask = emu->audigy ? 0x3f : 0x0f;
1451*4882a593Smuzhiyun 
1452*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1453*4882a593Smuzhiyun 	for (idx = 0; idx < num_efx; idx++)
1454*4882a593Smuzhiyun 		ucontrol->value.integer.value[idx] =
1455*4882a593Smuzhiyun 			mix->send_routing[0][idx] & mask;
1456*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1457*4882a593Smuzhiyun 	return 0;
1458*4882a593Smuzhiyun }
1459*4882a593Smuzhiyun 
snd_emu10k1_efx_send_routing_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1460*4882a593Smuzhiyun static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1461*4882a593Smuzhiyun                                         struct snd_ctl_elem_value *ucontrol)
1462*4882a593Smuzhiyun {
1463*4882a593Smuzhiyun 	unsigned long flags;
1464*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1465*4882a593Smuzhiyun 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1466*4882a593Smuzhiyun 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
1467*4882a593Smuzhiyun 	int change = 0, idx, val;
1468*4882a593Smuzhiyun 	int num_efx = emu->audigy ? 8 : 4;
1469*4882a593Smuzhiyun 	int mask = emu->audigy ? 0x3f : 0x0f;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1472*4882a593Smuzhiyun 	for (idx = 0; idx < num_efx; idx++) {
1473*4882a593Smuzhiyun 		val = ucontrol->value.integer.value[idx] & mask;
1474*4882a593Smuzhiyun 		if (mix->send_routing[0][idx] != val) {
1475*4882a593Smuzhiyun 			mix->send_routing[0][idx] = val;
1476*4882a593Smuzhiyun 			change = 1;
1477*4882a593Smuzhiyun 		}
1478*4882a593Smuzhiyun 	}
1479*4882a593Smuzhiyun 
1480*4882a593Smuzhiyun 	if (change && mix->epcm) {
1481*4882a593Smuzhiyun 		if (mix->epcm->voices[ch]) {
1482*4882a593Smuzhiyun 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
1483*4882a593Smuzhiyun 					&mix->send_routing[0][0]);
1484*4882a593Smuzhiyun 		}
1485*4882a593Smuzhiyun 	}
1486*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1487*4882a593Smuzhiyun 	return change;
1488*4882a593Smuzhiyun }
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
1491*4882a593Smuzhiyun {
1492*4882a593Smuzhiyun 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
1493*4882a593Smuzhiyun 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
1494*4882a593Smuzhiyun 	.name =         "Multichannel PCM Send Routing",
1495*4882a593Smuzhiyun 	.count =	16,
1496*4882a593Smuzhiyun 	.info =         snd_emu10k1_efx_send_routing_info,
1497*4882a593Smuzhiyun 	.get =          snd_emu10k1_efx_send_routing_get,
1498*4882a593Smuzhiyun 	.put =          snd_emu10k1_efx_send_routing_put
1499*4882a593Smuzhiyun };
1500*4882a593Smuzhiyun 
snd_emu10k1_efx_send_volume_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1501*4882a593Smuzhiyun static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1502*4882a593Smuzhiyun {
1503*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1504*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1505*4882a593Smuzhiyun 	uinfo->count = emu->audigy ? 8 : 4;
1506*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
1507*4882a593Smuzhiyun 	uinfo->value.integer.max = 255;
1508*4882a593Smuzhiyun 	return 0;
1509*4882a593Smuzhiyun }
1510*4882a593Smuzhiyun 
snd_emu10k1_efx_send_volume_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1511*4882a593Smuzhiyun static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1512*4882a593Smuzhiyun                                        struct snd_ctl_elem_value *ucontrol)
1513*4882a593Smuzhiyun {
1514*4882a593Smuzhiyun 	unsigned long flags;
1515*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1516*4882a593Smuzhiyun 	struct snd_emu10k1_pcm_mixer *mix =
1517*4882a593Smuzhiyun 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
1518*4882a593Smuzhiyun 	int idx;
1519*4882a593Smuzhiyun 	int num_efx = emu->audigy ? 8 : 4;
1520*4882a593Smuzhiyun 
1521*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1522*4882a593Smuzhiyun 	for (idx = 0; idx < num_efx; idx++)
1523*4882a593Smuzhiyun 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
1524*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1525*4882a593Smuzhiyun 	return 0;
1526*4882a593Smuzhiyun }
1527*4882a593Smuzhiyun 
snd_emu10k1_efx_send_volume_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1528*4882a593Smuzhiyun static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1529*4882a593Smuzhiyun                                        struct snd_ctl_elem_value *ucontrol)
1530*4882a593Smuzhiyun {
1531*4882a593Smuzhiyun 	unsigned long flags;
1532*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1533*4882a593Smuzhiyun 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1534*4882a593Smuzhiyun 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
1535*4882a593Smuzhiyun 	int change = 0, idx, val;
1536*4882a593Smuzhiyun 	int num_efx = emu->audigy ? 8 : 4;
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1539*4882a593Smuzhiyun 	for (idx = 0; idx < num_efx; idx++) {
1540*4882a593Smuzhiyun 		val = ucontrol->value.integer.value[idx] & 255;
1541*4882a593Smuzhiyun 		if (mix->send_volume[0][idx] != val) {
1542*4882a593Smuzhiyun 			mix->send_volume[0][idx] = val;
1543*4882a593Smuzhiyun 			change = 1;
1544*4882a593Smuzhiyun 		}
1545*4882a593Smuzhiyun 	}
1546*4882a593Smuzhiyun 	if (change && mix->epcm) {
1547*4882a593Smuzhiyun 		if (mix->epcm->voices[ch]) {
1548*4882a593Smuzhiyun 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
1549*4882a593Smuzhiyun 						   &mix->send_volume[0][0]);
1550*4882a593Smuzhiyun 		}
1551*4882a593Smuzhiyun 	}
1552*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1553*4882a593Smuzhiyun 	return change;
1554*4882a593Smuzhiyun }
1555*4882a593Smuzhiyun 
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
1558*4882a593Smuzhiyun {
1559*4882a593Smuzhiyun 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
1560*4882a593Smuzhiyun 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
1561*4882a593Smuzhiyun 	.name =         "Multichannel PCM Send Volume",
1562*4882a593Smuzhiyun 	.count =	16,
1563*4882a593Smuzhiyun 	.info =         snd_emu10k1_efx_send_volume_info,
1564*4882a593Smuzhiyun 	.get =          snd_emu10k1_efx_send_volume_get,
1565*4882a593Smuzhiyun 	.put =          snd_emu10k1_efx_send_volume_put
1566*4882a593Smuzhiyun };
1567*4882a593Smuzhiyun 
snd_emu10k1_efx_attn_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1568*4882a593Smuzhiyun static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1569*4882a593Smuzhiyun {
1570*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1571*4882a593Smuzhiyun 	uinfo->count = 1;
1572*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
1573*4882a593Smuzhiyun 	uinfo->value.integer.max = 0xffff;
1574*4882a593Smuzhiyun 	return 0;
1575*4882a593Smuzhiyun }
1576*4882a593Smuzhiyun 
snd_emu10k1_efx_attn_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1577*4882a593Smuzhiyun static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1578*4882a593Smuzhiyun                                 struct snd_ctl_elem_value *ucontrol)
1579*4882a593Smuzhiyun {
1580*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1581*4882a593Smuzhiyun 	struct snd_emu10k1_pcm_mixer *mix =
1582*4882a593Smuzhiyun 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
1583*4882a593Smuzhiyun 	unsigned long flags;
1584*4882a593Smuzhiyun 
1585*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1586*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = mix->attn[0];
1587*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1588*4882a593Smuzhiyun 	return 0;
1589*4882a593Smuzhiyun }
1590*4882a593Smuzhiyun 
snd_emu10k1_efx_attn_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1591*4882a593Smuzhiyun static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1592*4882a593Smuzhiyun 				struct snd_ctl_elem_value *ucontrol)
1593*4882a593Smuzhiyun {
1594*4882a593Smuzhiyun 	unsigned long flags;
1595*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1596*4882a593Smuzhiyun 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1597*4882a593Smuzhiyun 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
1598*4882a593Smuzhiyun 	int change = 0, val;
1599*4882a593Smuzhiyun 
1600*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1601*4882a593Smuzhiyun 	val = ucontrol->value.integer.value[0] & 0xffff;
1602*4882a593Smuzhiyun 	if (mix->attn[0] != val) {
1603*4882a593Smuzhiyun 		mix->attn[0] = val;
1604*4882a593Smuzhiyun 		change = 1;
1605*4882a593Smuzhiyun 	}
1606*4882a593Smuzhiyun 	if (change && mix->epcm) {
1607*4882a593Smuzhiyun 		if (mix->epcm->voices[ch]) {
1608*4882a593Smuzhiyun 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
1609*4882a593Smuzhiyun 		}
1610*4882a593Smuzhiyun 	}
1611*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1612*4882a593Smuzhiyun 	return change;
1613*4882a593Smuzhiyun }
1614*4882a593Smuzhiyun 
1615*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
1616*4882a593Smuzhiyun {
1617*4882a593Smuzhiyun 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
1618*4882a593Smuzhiyun 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
1619*4882a593Smuzhiyun 	.name =         "Multichannel PCM Volume",
1620*4882a593Smuzhiyun 	.count =	16,
1621*4882a593Smuzhiyun 	.info =         snd_emu10k1_efx_attn_info,
1622*4882a593Smuzhiyun 	.get =          snd_emu10k1_efx_attn_get,
1623*4882a593Smuzhiyun 	.put =          snd_emu10k1_efx_attn_put
1624*4882a593Smuzhiyun };
1625*4882a593Smuzhiyun 
1626*4882a593Smuzhiyun #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
1627*4882a593Smuzhiyun 
snd_emu10k1_shared_spdif_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1628*4882a593Smuzhiyun static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1629*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
1630*4882a593Smuzhiyun {
1631*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1632*4882a593Smuzhiyun 
1633*4882a593Smuzhiyun 	if (emu->audigy)
1634*4882a593Smuzhiyun 		ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
1635*4882a593Smuzhiyun 	else
1636*4882a593Smuzhiyun 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1637*4882a593Smuzhiyun 	if (emu->card_capabilities->invert_shared_spdif)
1638*4882a593Smuzhiyun 		ucontrol->value.integer.value[0] =
1639*4882a593Smuzhiyun 			!ucontrol->value.integer.value[0];
1640*4882a593Smuzhiyun 
1641*4882a593Smuzhiyun 	return 0;
1642*4882a593Smuzhiyun }
1643*4882a593Smuzhiyun 
snd_emu10k1_shared_spdif_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1644*4882a593Smuzhiyun static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1645*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
1646*4882a593Smuzhiyun {
1647*4882a593Smuzhiyun 	unsigned long flags;
1648*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1649*4882a593Smuzhiyun 	unsigned int reg, val, sw;
1650*4882a593Smuzhiyun 	int change = 0;
1651*4882a593Smuzhiyun 
1652*4882a593Smuzhiyun 	sw = ucontrol->value.integer.value[0];
1653*4882a593Smuzhiyun 	if (emu->card_capabilities->invert_shared_spdif)
1654*4882a593Smuzhiyun 		sw = !sw;
1655*4882a593Smuzhiyun 	spin_lock_irqsave(&emu->reg_lock, flags);
1656*4882a593Smuzhiyun 	if ( emu->card_capabilities->i2c_adc) {
1657*4882a593Smuzhiyun 		/* Do nothing for Audigy 2 ZS Notebook */
1658*4882a593Smuzhiyun 	} else if (emu->audigy) {
1659*4882a593Smuzhiyun 		reg = inl(emu->port + A_IOCFG);
1660*4882a593Smuzhiyun 		val = sw ? A_IOCFG_GPOUT0 : 0;
1661*4882a593Smuzhiyun 		change = (reg & A_IOCFG_GPOUT0) != val;
1662*4882a593Smuzhiyun 		if (change) {
1663*4882a593Smuzhiyun 			reg &= ~A_IOCFG_GPOUT0;
1664*4882a593Smuzhiyun 			reg |= val;
1665*4882a593Smuzhiyun 			outl(reg | val, emu->port + A_IOCFG);
1666*4882a593Smuzhiyun 		}
1667*4882a593Smuzhiyun 	}
1668*4882a593Smuzhiyun 	reg = inl(emu->port + HCFG);
1669*4882a593Smuzhiyun 	val = sw ? HCFG_GPOUT0 : 0;
1670*4882a593Smuzhiyun 	change |= (reg & HCFG_GPOUT0) != val;
1671*4882a593Smuzhiyun 	if (change) {
1672*4882a593Smuzhiyun 		reg &= ~HCFG_GPOUT0;
1673*4882a593Smuzhiyun 		reg |= val;
1674*4882a593Smuzhiyun 		outl(reg | val, emu->port + HCFG);
1675*4882a593Smuzhiyun 	}
1676*4882a593Smuzhiyun 	spin_unlock_irqrestore(&emu->reg_lock, flags);
1677*4882a593Smuzhiyun 	return change;
1678*4882a593Smuzhiyun }
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
1681*4882a593Smuzhiyun {
1682*4882a593Smuzhiyun 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
1683*4882a593Smuzhiyun 	.name =		"SB Live Analog/Digital Output Jack",
1684*4882a593Smuzhiyun 	.info =		snd_emu10k1_shared_spdif_info,
1685*4882a593Smuzhiyun 	.get =		snd_emu10k1_shared_spdif_get,
1686*4882a593Smuzhiyun 	.put =		snd_emu10k1_shared_spdif_put
1687*4882a593Smuzhiyun };
1688*4882a593Smuzhiyun 
1689*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_audigy_shared_spdif =
1690*4882a593Smuzhiyun {
1691*4882a593Smuzhiyun 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
1692*4882a593Smuzhiyun 	.name =		"Audigy Analog/Digital Output Jack",
1693*4882a593Smuzhiyun 	.info =		snd_emu10k1_shared_spdif_info,
1694*4882a593Smuzhiyun 	.get =		snd_emu10k1_shared_spdif_get,
1695*4882a593Smuzhiyun 	.put =		snd_emu10k1_shared_spdif_put
1696*4882a593Smuzhiyun };
1697*4882a593Smuzhiyun 
1698*4882a593Smuzhiyun /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
1699*4882a593Smuzhiyun 
1700*4882a593Smuzhiyun #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
1701*4882a593Smuzhiyun 
snd_audigy_capture_boost_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1702*4882a593Smuzhiyun static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
1703*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
1704*4882a593Smuzhiyun {
1705*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1706*4882a593Smuzhiyun 	unsigned int val;
1707*4882a593Smuzhiyun 
1708*4882a593Smuzhiyun 	/* FIXME: better to use a cached version */
1709*4882a593Smuzhiyun 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
1710*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = !!val;
1711*4882a593Smuzhiyun 	return 0;
1712*4882a593Smuzhiyun }
1713*4882a593Smuzhiyun 
snd_audigy_capture_boost_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1714*4882a593Smuzhiyun static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
1715*4882a593Smuzhiyun 					struct snd_ctl_elem_value *ucontrol)
1716*4882a593Smuzhiyun {
1717*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1718*4882a593Smuzhiyun 	unsigned int val;
1719*4882a593Smuzhiyun 
1720*4882a593Smuzhiyun 	if (ucontrol->value.integer.value[0])
1721*4882a593Smuzhiyun 		val = 0x0f0f;
1722*4882a593Smuzhiyun 	else
1723*4882a593Smuzhiyun 		val = 0;
1724*4882a593Smuzhiyun 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
1725*4882a593Smuzhiyun }
1726*4882a593Smuzhiyun 
1727*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_audigy_capture_boost =
1728*4882a593Smuzhiyun {
1729*4882a593Smuzhiyun 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
1730*4882a593Smuzhiyun 	.name =		"Mic Extra Boost",
1731*4882a593Smuzhiyun 	.info =		snd_audigy_capture_boost_info,
1732*4882a593Smuzhiyun 	.get =		snd_audigy_capture_boost_get,
1733*4882a593Smuzhiyun 	.put =		snd_audigy_capture_boost_put
1734*4882a593Smuzhiyun };
1735*4882a593Smuzhiyun 
1736*4882a593Smuzhiyun 
1737*4882a593Smuzhiyun /*
1738*4882a593Smuzhiyun  */
snd_emu10k1_mixer_free_ac97(struct snd_ac97 * ac97)1739*4882a593Smuzhiyun static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
1740*4882a593Smuzhiyun {
1741*4882a593Smuzhiyun 	struct snd_emu10k1 *emu = ac97->private_data;
1742*4882a593Smuzhiyun 	emu->ac97 = NULL;
1743*4882a593Smuzhiyun }
1744*4882a593Smuzhiyun 
1745*4882a593Smuzhiyun /*
1746*4882a593Smuzhiyun  */
remove_ctl(struct snd_card * card,const char * name)1747*4882a593Smuzhiyun static int remove_ctl(struct snd_card *card, const char *name)
1748*4882a593Smuzhiyun {
1749*4882a593Smuzhiyun 	struct snd_ctl_elem_id id;
1750*4882a593Smuzhiyun 	memset(&id, 0, sizeof(id));
1751*4882a593Smuzhiyun 	strcpy(id.name, name);
1752*4882a593Smuzhiyun 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1753*4882a593Smuzhiyun 	return snd_ctl_remove_id(card, &id);
1754*4882a593Smuzhiyun }
1755*4882a593Smuzhiyun 
ctl_find(struct snd_card * card,const char * name)1756*4882a593Smuzhiyun static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
1757*4882a593Smuzhiyun {
1758*4882a593Smuzhiyun 	struct snd_ctl_elem_id sid;
1759*4882a593Smuzhiyun 	memset(&sid, 0, sizeof(sid));
1760*4882a593Smuzhiyun 	strcpy(sid.name, name);
1761*4882a593Smuzhiyun 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1762*4882a593Smuzhiyun 	return snd_ctl_find_id(card, &sid);
1763*4882a593Smuzhiyun }
1764*4882a593Smuzhiyun 
rename_ctl(struct snd_card * card,const char * src,const char * dst)1765*4882a593Smuzhiyun static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
1766*4882a593Smuzhiyun {
1767*4882a593Smuzhiyun 	struct snd_kcontrol *kctl = ctl_find(card, src);
1768*4882a593Smuzhiyun 	if (kctl) {
1769*4882a593Smuzhiyun 		strcpy(kctl->id.name, dst);
1770*4882a593Smuzhiyun 		return 0;
1771*4882a593Smuzhiyun 	}
1772*4882a593Smuzhiyun 	return -ENOENT;
1773*4882a593Smuzhiyun }
1774*4882a593Smuzhiyun 
snd_emu10k1_mixer(struct snd_emu10k1 * emu,int pcm_device,int multi_device)1775*4882a593Smuzhiyun int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
1776*4882a593Smuzhiyun 		      int pcm_device, int multi_device)
1777*4882a593Smuzhiyun {
1778*4882a593Smuzhiyun 	int err, pcm;
1779*4882a593Smuzhiyun 	struct snd_kcontrol *kctl;
1780*4882a593Smuzhiyun 	struct snd_card *card = emu->card;
1781*4882a593Smuzhiyun 	const char * const *c;
1782*4882a593Smuzhiyun 	static const char * const emu10k1_remove_ctls[] = {
1783*4882a593Smuzhiyun 		/* no AC97 mono, surround, center/lfe */
1784*4882a593Smuzhiyun 		"Master Mono Playback Switch",
1785*4882a593Smuzhiyun 		"Master Mono Playback Volume",
1786*4882a593Smuzhiyun 		"PCM Out Path & Mute",
1787*4882a593Smuzhiyun 		"Mono Output Select",
1788*4882a593Smuzhiyun 		"Surround Playback Switch",
1789*4882a593Smuzhiyun 		"Surround Playback Volume",
1790*4882a593Smuzhiyun 		"Center Playback Switch",
1791*4882a593Smuzhiyun 		"Center Playback Volume",
1792*4882a593Smuzhiyun 		"LFE Playback Switch",
1793*4882a593Smuzhiyun 		"LFE Playback Volume",
1794*4882a593Smuzhiyun 		NULL
1795*4882a593Smuzhiyun 	};
1796*4882a593Smuzhiyun 	static const char * const emu10k1_rename_ctls[] = {
1797*4882a593Smuzhiyun 		"Surround Digital Playback Volume", "Surround Playback Volume",
1798*4882a593Smuzhiyun 		"Center Digital Playback Volume", "Center Playback Volume",
1799*4882a593Smuzhiyun 		"LFE Digital Playback Volume", "LFE Playback Volume",
1800*4882a593Smuzhiyun 		NULL
1801*4882a593Smuzhiyun 	};
1802*4882a593Smuzhiyun 	static const char * const audigy_remove_ctls[] = {
1803*4882a593Smuzhiyun 		/* Master/PCM controls on ac97 of Audigy has no effect */
1804*4882a593Smuzhiyun 		/* On the Audigy2 the AC97 playback is piped into
1805*4882a593Smuzhiyun 		 * the Philips ADC for 24bit capture */
1806*4882a593Smuzhiyun 		"PCM Playback Switch",
1807*4882a593Smuzhiyun 		"PCM Playback Volume",
1808*4882a593Smuzhiyun 		"Master Playback Switch",
1809*4882a593Smuzhiyun 		"Master Playback Volume",
1810*4882a593Smuzhiyun 		"PCM Out Path & Mute",
1811*4882a593Smuzhiyun 		"Mono Output Select",
1812*4882a593Smuzhiyun 		/* remove unused AC97 capture controls */
1813*4882a593Smuzhiyun 		"Capture Source",
1814*4882a593Smuzhiyun 		"Capture Switch",
1815*4882a593Smuzhiyun 		"Capture Volume",
1816*4882a593Smuzhiyun 		"Mic Select",
1817*4882a593Smuzhiyun 		"Headphone Playback Switch",
1818*4882a593Smuzhiyun 		"Headphone Playback Volume",
1819*4882a593Smuzhiyun 		"3D Control - Center",
1820*4882a593Smuzhiyun 		"3D Control - Depth",
1821*4882a593Smuzhiyun 		"3D Control - Switch",
1822*4882a593Smuzhiyun 		"Video Playback Switch",
1823*4882a593Smuzhiyun 		"Video Playback Volume",
1824*4882a593Smuzhiyun 		"Mic Playback Switch",
1825*4882a593Smuzhiyun 		"Mic Playback Volume",
1826*4882a593Smuzhiyun 		"External Amplifier",
1827*4882a593Smuzhiyun 		NULL
1828*4882a593Smuzhiyun 	};
1829*4882a593Smuzhiyun 	static const char * const audigy_rename_ctls[] = {
1830*4882a593Smuzhiyun 		/* use conventional names */
1831*4882a593Smuzhiyun 		"Wave Playback Volume", "PCM Playback Volume",
1832*4882a593Smuzhiyun 		/* "Wave Capture Volume", "PCM Capture Volume", */
1833*4882a593Smuzhiyun 		"Wave Master Playback Volume", "Master Playback Volume",
1834*4882a593Smuzhiyun 		"AMic Playback Volume", "Mic Playback Volume",
1835*4882a593Smuzhiyun 		"Master Mono Playback Switch", "Phone Output Playback Switch",
1836*4882a593Smuzhiyun 		"Master Mono Playback Volume", "Phone Output Playback Volume",
1837*4882a593Smuzhiyun 		NULL
1838*4882a593Smuzhiyun 	};
1839*4882a593Smuzhiyun 	static const char * const audigy_rename_ctls_i2c_adc[] = {
1840*4882a593Smuzhiyun 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1841*4882a593Smuzhiyun 		"Line Capture Volume", "Analog Mix Capture Volume",
1842*4882a593Smuzhiyun 		"Wave Playback Volume", "OLD PCM Playback Volume",
1843*4882a593Smuzhiyun 		"Wave Master Playback Volume", "Master Playback Volume",
1844*4882a593Smuzhiyun 		"AMic Playback Volume", "Old Mic Playback Volume",
1845*4882a593Smuzhiyun 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1846*4882a593Smuzhiyun 		NULL
1847*4882a593Smuzhiyun 	};
1848*4882a593Smuzhiyun 	static const char * const audigy_remove_ctls_i2c_adc[] = {
1849*4882a593Smuzhiyun 		/* On the Audigy2 ZS Notebook
1850*4882a593Smuzhiyun 		 * Capture via WM8775  */
1851*4882a593Smuzhiyun 		"Mic Capture Volume",
1852*4882a593Smuzhiyun 		"Analog Mix Capture Volume",
1853*4882a593Smuzhiyun 		"Aux Capture Volume",
1854*4882a593Smuzhiyun 		"IEC958 Optical Capture Volume",
1855*4882a593Smuzhiyun 		NULL
1856*4882a593Smuzhiyun 	};
1857*4882a593Smuzhiyun 	static const char * const audigy_remove_ctls_1361t_adc[] = {
1858*4882a593Smuzhiyun 		/* On the Audigy2 the AC97 playback is piped into
1859*4882a593Smuzhiyun 		 * the Philips ADC for 24bit capture */
1860*4882a593Smuzhiyun 		"PCM Playback Switch",
1861*4882a593Smuzhiyun 		"PCM Playback Volume",
1862*4882a593Smuzhiyun 		"Capture Source",
1863*4882a593Smuzhiyun 		"Capture Switch",
1864*4882a593Smuzhiyun 		"Capture Volume",
1865*4882a593Smuzhiyun 		"Mic Capture Volume",
1866*4882a593Smuzhiyun 		"Headphone Playback Switch",
1867*4882a593Smuzhiyun 		"Headphone Playback Volume",
1868*4882a593Smuzhiyun 		"3D Control - Center",
1869*4882a593Smuzhiyun 		"3D Control - Depth",
1870*4882a593Smuzhiyun 		"3D Control - Switch",
1871*4882a593Smuzhiyun 		"Line2 Playback Volume",
1872*4882a593Smuzhiyun 		"Line2 Capture Volume",
1873*4882a593Smuzhiyun 		NULL
1874*4882a593Smuzhiyun 	};
1875*4882a593Smuzhiyun 	static const char * const audigy_rename_ctls_1361t_adc[] = {
1876*4882a593Smuzhiyun 		"Master Playback Switch", "Master Capture Switch",
1877*4882a593Smuzhiyun 		"Master Playback Volume", "Master Capture Volume",
1878*4882a593Smuzhiyun 		"Wave Master Playback Volume", "Master Playback Volume",
1879*4882a593Smuzhiyun 		"Beep Playback Switch", "Beep Capture Switch",
1880*4882a593Smuzhiyun 		"Beep Playback Volume", "Beep Capture Volume",
1881*4882a593Smuzhiyun 		"Phone Playback Switch", "Phone Capture Switch",
1882*4882a593Smuzhiyun 		"Phone Playback Volume", "Phone Capture Volume",
1883*4882a593Smuzhiyun 		"Mic Playback Switch", "Mic Capture Switch",
1884*4882a593Smuzhiyun 		"Mic Playback Volume", "Mic Capture Volume",
1885*4882a593Smuzhiyun 		"Line Playback Switch", "Line Capture Switch",
1886*4882a593Smuzhiyun 		"Line Playback Volume", "Line Capture Volume",
1887*4882a593Smuzhiyun 		"CD Playback Switch", "CD Capture Switch",
1888*4882a593Smuzhiyun 		"CD Playback Volume", "CD Capture Volume",
1889*4882a593Smuzhiyun 		"Aux Playback Switch", "Aux Capture Switch",
1890*4882a593Smuzhiyun 		"Aux Playback Volume", "Aux Capture Volume",
1891*4882a593Smuzhiyun 		"Video Playback Switch", "Video Capture Switch",
1892*4882a593Smuzhiyun 		"Video Playback Volume", "Video Capture Volume",
1893*4882a593Smuzhiyun 		"Master Mono Playback Switch", "Phone Output Playback Switch",
1894*4882a593Smuzhiyun 		"Master Mono Playback Volume", "Phone Output Playback Volume",
1895*4882a593Smuzhiyun 		NULL
1896*4882a593Smuzhiyun 	};
1897*4882a593Smuzhiyun 
1898*4882a593Smuzhiyun 	if (emu->card_capabilities->ac97_chip) {
1899*4882a593Smuzhiyun 		struct snd_ac97_bus *pbus;
1900*4882a593Smuzhiyun 		struct snd_ac97_template ac97;
1901*4882a593Smuzhiyun 		static const struct snd_ac97_bus_ops ops = {
1902*4882a593Smuzhiyun 			.write = snd_emu10k1_ac97_write,
1903*4882a593Smuzhiyun 			.read = snd_emu10k1_ac97_read,
1904*4882a593Smuzhiyun 		};
1905*4882a593Smuzhiyun 
1906*4882a593Smuzhiyun 		if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0)
1907*4882a593Smuzhiyun 			return err;
1908*4882a593Smuzhiyun 		pbus->no_vra = 1; /* we don't need VRA */
1909*4882a593Smuzhiyun 
1910*4882a593Smuzhiyun 		memset(&ac97, 0, sizeof(ac97));
1911*4882a593Smuzhiyun 		ac97.private_data = emu;
1912*4882a593Smuzhiyun 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
1913*4882a593Smuzhiyun 		ac97.scaps = AC97_SCAP_NO_SPDIF;
1914*4882a593Smuzhiyun 		if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
1915*4882a593Smuzhiyun 			if (emu->card_capabilities->ac97_chip == 1)
1916*4882a593Smuzhiyun 				return err;
1917*4882a593Smuzhiyun 			dev_info(emu->card->dev,
1918*4882a593Smuzhiyun 				 "AC97 is optional on this board\n");
1919*4882a593Smuzhiyun 			dev_info(emu->card->dev,
1920*4882a593Smuzhiyun 				 "Proceeding without ac97 mixers...\n");
1921*4882a593Smuzhiyun 			snd_device_free(emu->card, pbus);
1922*4882a593Smuzhiyun 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1923*4882a593Smuzhiyun 		}
1924*4882a593Smuzhiyun 		if (emu->audigy) {
1925*4882a593Smuzhiyun 			/* set master volume to 0 dB */
1926*4882a593Smuzhiyun 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
1927*4882a593Smuzhiyun 			/* set capture source to mic */
1928*4882a593Smuzhiyun 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
1929*4882a593Smuzhiyun 			/* set mono output (TAD) to mic */
1930*4882a593Smuzhiyun 			snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE,
1931*4882a593Smuzhiyun 				0x0200, 0x0200);
1932*4882a593Smuzhiyun 			if (emu->card_capabilities->adc_1361t)
1933*4882a593Smuzhiyun 				c = audigy_remove_ctls_1361t_adc;
1934*4882a593Smuzhiyun 			else
1935*4882a593Smuzhiyun 				c = audigy_remove_ctls;
1936*4882a593Smuzhiyun 		} else {
1937*4882a593Smuzhiyun 			/*
1938*4882a593Smuzhiyun 			 * Credits for cards based on STAC9758:
1939*4882a593Smuzhiyun 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
1940*4882a593Smuzhiyun 			 *   Voluspa <voluspa@comhem.se>
1941*4882a593Smuzhiyun 			 */
1942*4882a593Smuzhiyun 			if (emu->ac97->id == AC97_ID_STAC9758) {
1943*4882a593Smuzhiyun 				emu->rear_ac97 = 1;
1944*4882a593Smuzhiyun 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
1945*4882a593Smuzhiyun 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
1946*4882a593Smuzhiyun 				remove_ctl(card,"Front Playback Volume");
1947*4882a593Smuzhiyun 				remove_ctl(card,"Front Playback Switch");
1948*4882a593Smuzhiyun 			}
1949*4882a593Smuzhiyun 			/* remove unused AC97 controls */
1950*4882a593Smuzhiyun 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
1951*4882a593Smuzhiyun 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
1952*4882a593Smuzhiyun 			c = emu10k1_remove_ctls;
1953*4882a593Smuzhiyun 		}
1954*4882a593Smuzhiyun 		for (; *c; c++)
1955*4882a593Smuzhiyun 			remove_ctl(card, *c);
1956*4882a593Smuzhiyun 	} else if (emu->card_capabilities->i2c_adc) {
1957*4882a593Smuzhiyun 		c = audigy_remove_ctls_i2c_adc;
1958*4882a593Smuzhiyun 		for (; *c; c++)
1959*4882a593Smuzhiyun 			remove_ctl(card, *c);
1960*4882a593Smuzhiyun 	} else {
1961*4882a593Smuzhiyun 	no_ac97:
1962*4882a593Smuzhiyun 		if (emu->card_capabilities->ecard)
1963*4882a593Smuzhiyun 			strcpy(emu->card->mixername, "EMU APS");
1964*4882a593Smuzhiyun 		else if (emu->audigy)
1965*4882a593Smuzhiyun 			strcpy(emu->card->mixername, "SB Audigy");
1966*4882a593Smuzhiyun 		else
1967*4882a593Smuzhiyun 			strcpy(emu->card->mixername, "Emu10k1");
1968*4882a593Smuzhiyun 	}
1969*4882a593Smuzhiyun 
1970*4882a593Smuzhiyun 	if (emu->audigy)
1971*4882a593Smuzhiyun 		if (emu->card_capabilities->adc_1361t)
1972*4882a593Smuzhiyun 			c = audigy_rename_ctls_1361t_adc;
1973*4882a593Smuzhiyun 		else if (emu->card_capabilities->i2c_adc)
1974*4882a593Smuzhiyun 			c = audigy_rename_ctls_i2c_adc;
1975*4882a593Smuzhiyun 		else
1976*4882a593Smuzhiyun 			c = audigy_rename_ctls;
1977*4882a593Smuzhiyun 	else
1978*4882a593Smuzhiyun 		c = emu10k1_rename_ctls;
1979*4882a593Smuzhiyun 	for (; *c; c += 2)
1980*4882a593Smuzhiyun 		rename_ctl(card, c[0], c[1]);
1981*4882a593Smuzhiyun 
1982*4882a593Smuzhiyun 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
1983*4882a593Smuzhiyun 		remove_ctl(card, "Center Playback Volume");
1984*4882a593Smuzhiyun 		remove_ctl(card, "LFE Playback Volume");
1985*4882a593Smuzhiyun 		remove_ctl(card, "Wave Center Playback Volume");
1986*4882a593Smuzhiyun 		remove_ctl(card, "Wave LFE Playback Volume");
1987*4882a593Smuzhiyun 	}
1988*4882a593Smuzhiyun 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1989*4882a593Smuzhiyun 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1990*4882a593Smuzhiyun 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1991*4882a593Smuzhiyun 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1992*4882a593Smuzhiyun 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1993*4882a593Smuzhiyun 	}
1994*4882a593Smuzhiyun 	if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
1995*4882a593Smuzhiyun 		return -ENOMEM;
1996*4882a593Smuzhiyun 	kctl->id.device = pcm_device;
1997*4882a593Smuzhiyun 	if ((err = snd_ctl_add(card, kctl)))
1998*4882a593Smuzhiyun 		return err;
1999*4882a593Smuzhiyun 	if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
2000*4882a593Smuzhiyun 		return -ENOMEM;
2001*4882a593Smuzhiyun 	kctl->id.device = pcm_device;
2002*4882a593Smuzhiyun 	if ((err = snd_ctl_add(card, kctl)))
2003*4882a593Smuzhiyun 		return err;
2004*4882a593Smuzhiyun 	if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
2005*4882a593Smuzhiyun 		return -ENOMEM;
2006*4882a593Smuzhiyun 	kctl->id.device = pcm_device;
2007*4882a593Smuzhiyun 	if ((err = snd_ctl_add(card, kctl)))
2008*4882a593Smuzhiyun 		return err;
2009*4882a593Smuzhiyun 
2010*4882a593Smuzhiyun 	if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
2011*4882a593Smuzhiyun 		return -ENOMEM;
2012*4882a593Smuzhiyun 	kctl->id.device = multi_device;
2013*4882a593Smuzhiyun 	if ((err = snd_ctl_add(card, kctl)))
2014*4882a593Smuzhiyun 		return err;
2015*4882a593Smuzhiyun 
2016*4882a593Smuzhiyun 	if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
2017*4882a593Smuzhiyun 		return -ENOMEM;
2018*4882a593Smuzhiyun 	kctl->id.device = multi_device;
2019*4882a593Smuzhiyun 	if ((err = snd_ctl_add(card, kctl)))
2020*4882a593Smuzhiyun 		return err;
2021*4882a593Smuzhiyun 
2022*4882a593Smuzhiyun 	if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
2023*4882a593Smuzhiyun 		return -ENOMEM;
2024*4882a593Smuzhiyun 	kctl->id.device = multi_device;
2025*4882a593Smuzhiyun 	if ((err = snd_ctl_add(card, kctl)))
2026*4882a593Smuzhiyun 		return err;
2027*4882a593Smuzhiyun 
2028*4882a593Smuzhiyun 	/* initialize the routing and volume table for each pcm playback stream */
2029*4882a593Smuzhiyun 	for (pcm = 0; pcm < 32; pcm++) {
2030*4882a593Smuzhiyun 		struct snd_emu10k1_pcm_mixer *mix;
2031*4882a593Smuzhiyun 		int v;
2032*4882a593Smuzhiyun 
2033*4882a593Smuzhiyun 		mix = &emu->pcm_mixer[pcm];
2034*4882a593Smuzhiyun 		mix->epcm = NULL;
2035*4882a593Smuzhiyun 
2036*4882a593Smuzhiyun 		for (v = 0; v < 4; v++)
2037*4882a593Smuzhiyun 			mix->send_routing[0][v] =
2038*4882a593Smuzhiyun 				mix->send_routing[1][v] =
2039*4882a593Smuzhiyun 				mix->send_routing[2][v] = v;
2040*4882a593Smuzhiyun 
2041*4882a593Smuzhiyun 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
2042*4882a593Smuzhiyun 		mix->send_volume[0][0] = mix->send_volume[0][1] =
2043*4882a593Smuzhiyun 		mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
2044*4882a593Smuzhiyun 
2045*4882a593Smuzhiyun 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
2046*4882a593Smuzhiyun 	}
2047*4882a593Smuzhiyun 
2048*4882a593Smuzhiyun 	/* initialize the routing and volume table for the multichannel playback stream */
2049*4882a593Smuzhiyun 	for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
2050*4882a593Smuzhiyun 		struct snd_emu10k1_pcm_mixer *mix;
2051*4882a593Smuzhiyun 		int v;
2052*4882a593Smuzhiyun 
2053*4882a593Smuzhiyun 		mix = &emu->efx_pcm_mixer[pcm];
2054*4882a593Smuzhiyun 		mix->epcm = NULL;
2055*4882a593Smuzhiyun 
2056*4882a593Smuzhiyun 		mix->send_routing[0][0] = pcm;
2057*4882a593Smuzhiyun 		mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
2058*4882a593Smuzhiyun 		for (v = 0; v < 2; v++)
2059*4882a593Smuzhiyun 			mix->send_routing[0][2+v] = 13+v;
2060*4882a593Smuzhiyun 		if (emu->audigy)
2061*4882a593Smuzhiyun 			for (v = 0; v < 4; v++)
2062*4882a593Smuzhiyun 				mix->send_routing[0][4+v] = 60+v;
2063*4882a593Smuzhiyun 
2064*4882a593Smuzhiyun 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
2065*4882a593Smuzhiyun 		mix->send_volume[0][0]  = 255;
2066*4882a593Smuzhiyun 
2067*4882a593Smuzhiyun 		mix->attn[0] = 0xffff;
2068*4882a593Smuzhiyun 	}
2069*4882a593Smuzhiyun 
2070*4882a593Smuzhiyun 	if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
2071*4882a593Smuzhiyun 		/* sb live! and audigy */
2072*4882a593Smuzhiyun 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
2073*4882a593Smuzhiyun 			return -ENOMEM;
2074*4882a593Smuzhiyun 		if (!emu->audigy)
2075*4882a593Smuzhiyun 			kctl->id.device = emu->pcm_efx->device;
2076*4882a593Smuzhiyun 		if ((err = snd_ctl_add(card, kctl)))
2077*4882a593Smuzhiyun 			return err;
2078*4882a593Smuzhiyun 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
2079*4882a593Smuzhiyun 			return -ENOMEM;
2080*4882a593Smuzhiyun 		if (!emu->audigy)
2081*4882a593Smuzhiyun 			kctl->id.device = emu->pcm_efx->device;
2082*4882a593Smuzhiyun 		if ((err = snd_ctl_add(card, kctl)))
2083*4882a593Smuzhiyun 			return err;
2084*4882a593Smuzhiyun 	}
2085*4882a593Smuzhiyun 
2086*4882a593Smuzhiyun 	if (emu->card_capabilities->emu_model) {
2087*4882a593Smuzhiyun 		;  /* Disable the snd_audigy_spdif_shared_spdif */
2088*4882a593Smuzhiyun 	} else if (emu->audigy) {
2089*4882a593Smuzhiyun 		if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
2090*4882a593Smuzhiyun 			return -ENOMEM;
2091*4882a593Smuzhiyun 		if ((err = snd_ctl_add(card, kctl)))
2092*4882a593Smuzhiyun 			return err;
2093*4882a593Smuzhiyun #if 0
2094*4882a593Smuzhiyun 		if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
2095*4882a593Smuzhiyun 			return -ENOMEM;
2096*4882a593Smuzhiyun 		if ((err = snd_ctl_add(card, kctl)))
2097*4882a593Smuzhiyun 			return err;
2098*4882a593Smuzhiyun #endif
2099*4882a593Smuzhiyun 	} else if (! emu->card_capabilities->ecard) {
2100*4882a593Smuzhiyun 		/* sb live! */
2101*4882a593Smuzhiyun 		if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
2102*4882a593Smuzhiyun 			return -ENOMEM;
2103*4882a593Smuzhiyun 		if ((err = snd_ctl_add(card, kctl)))
2104*4882a593Smuzhiyun 			return err;
2105*4882a593Smuzhiyun 	}
2106*4882a593Smuzhiyun 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
2107*4882a593Smuzhiyun 		if ((err = snd_p16v_mixer(emu)))
2108*4882a593Smuzhiyun 			return err;
2109*4882a593Smuzhiyun 	}
2110*4882a593Smuzhiyun 
2111*4882a593Smuzhiyun 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
2112*4882a593Smuzhiyun 		/* 1616(m) cardbus */
2113*4882a593Smuzhiyun 		int i;
2114*4882a593Smuzhiyun 
2115*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) {
2116*4882a593Smuzhiyun 			err = snd_ctl_add(card,
2117*4882a593Smuzhiyun 				snd_ctl_new1(&snd_emu1616_output_enum_ctls[i],
2118*4882a593Smuzhiyun 					     emu));
2119*4882a593Smuzhiyun 			if (err < 0)
2120*4882a593Smuzhiyun 				return err;
2121*4882a593Smuzhiyun 		}
2122*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
2123*4882a593Smuzhiyun 			err = snd_ctl_add(card,
2124*4882a593Smuzhiyun 				snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
2125*4882a593Smuzhiyun 					     emu));
2126*4882a593Smuzhiyun 			if (err < 0)
2127*4882a593Smuzhiyun 				return err;
2128*4882a593Smuzhiyun 		}
2129*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) {
2130*4882a593Smuzhiyun 			err = snd_ctl_add(card,
2131*4882a593Smuzhiyun 				snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
2132*4882a593Smuzhiyun 			if (err < 0)
2133*4882a593Smuzhiyun 				return err;
2134*4882a593Smuzhiyun 		}
2135*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) {
2136*4882a593Smuzhiyun 			err = snd_ctl_add(card,
2137*4882a593Smuzhiyun 				snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
2138*4882a593Smuzhiyun 			if (err < 0)
2139*4882a593Smuzhiyun 				return err;
2140*4882a593Smuzhiyun 		}
2141*4882a593Smuzhiyun 		err = snd_ctl_add(card,
2142*4882a593Smuzhiyun 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
2143*4882a593Smuzhiyun 		if (err < 0)
2144*4882a593Smuzhiyun 			return err;
2145*4882a593Smuzhiyun 		err = snd_ctl_add(card,
2146*4882a593Smuzhiyun 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
2147*4882a593Smuzhiyun 		if (err < 0)
2148*4882a593Smuzhiyun 			return err;
2149*4882a593Smuzhiyun 		err = snd_ctl_add(card,
2150*4882a593Smuzhiyun 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
2151*4882a593Smuzhiyun 		if (err < 0)
2152*4882a593Smuzhiyun 			return err;
2153*4882a593Smuzhiyun 
2154*4882a593Smuzhiyun 	} else if (emu->card_capabilities->emu_model) {
2155*4882a593Smuzhiyun 		/* all other e-mu cards for now */
2156*4882a593Smuzhiyun 		int i;
2157*4882a593Smuzhiyun 
2158*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
2159*4882a593Smuzhiyun 			err = snd_ctl_add(card,
2160*4882a593Smuzhiyun 				snd_ctl_new1(&snd_emu1010_output_enum_ctls[i],
2161*4882a593Smuzhiyun 					     emu));
2162*4882a593Smuzhiyun 			if (err < 0)
2163*4882a593Smuzhiyun 				return err;
2164*4882a593Smuzhiyun 		}
2165*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
2166*4882a593Smuzhiyun 			err = snd_ctl_add(card,
2167*4882a593Smuzhiyun 				snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
2168*4882a593Smuzhiyun 					     emu));
2169*4882a593Smuzhiyun 			if (err < 0)
2170*4882a593Smuzhiyun 				return err;
2171*4882a593Smuzhiyun 		}
2172*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
2173*4882a593Smuzhiyun 			err = snd_ctl_add(card,
2174*4882a593Smuzhiyun 				snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
2175*4882a593Smuzhiyun 			if (err < 0)
2176*4882a593Smuzhiyun 				return err;
2177*4882a593Smuzhiyun 		}
2178*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
2179*4882a593Smuzhiyun 			err = snd_ctl_add(card,
2180*4882a593Smuzhiyun 				snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
2181*4882a593Smuzhiyun 			if (err < 0)
2182*4882a593Smuzhiyun 				return err;
2183*4882a593Smuzhiyun 		}
2184*4882a593Smuzhiyun 		err = snd_ctl_add(card,
2185*4882a593Smuzhiyun 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
2186*4882a593Smuzhiyun 		if (err < 0)
2187*4882a593Smuzhiyun 			return err;
2188*4882a593Smuzhiyun 		err = snd_ctl_add(card,
2189*4882a593Smuzhiyun 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
2190*4882a593Smuzhiyun 		if (err < 0)
2191*4882a593Smuzhiyun 			return err;
2192*4882a593Smuzhiyun 		err = snd_ctl_add(card,
2193*4882a593Smuzhiyun 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
2194*4882a593Smuzhiyun 		if (err < 0)
2195*4882a593Smuzhiyun 			return err;
2196*4882a593Smuzhiyun 	}
2197*4882a593Smuzhiyun 
2198*4882a593Smuzhiyun 	if ( emu->card_capabilities->i2c_adc) {
2199*4882a593Smuzhiyun 		int i;
2200*4882a593Smuzhiyun 
2201*4882a593Smuzhiyun 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2202*4882a593Smuzhiyun 		if (err < 0)
2203*4882a593Smuzhiyun 			return err;
2204*4882a593Smuzhiyun 
2205*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
2206*4882a593Smuzhiyun 			err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
2207*4882a593Smuzhiyun 			if (err < 0)
2208*4882a593Smuzhiyun 				return err;
2209*4882a593Smuzhiyun 		}
2210*4882a593Smuzhiyun 	}
2211*4882a593Smuzhiyun 
2212*4882a593Smuzhiyun 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
2213*4882a593Smuzhiyun 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
2214*4882a593Smuzhiyun 						     emu));
2215*4882a593Smuzhiyun 		if (err < 0)
2216*4882a593Smuzhiyun 			return err;
2217*4882a593Smuzhiyun 	}
2218*4882a593Smuzhiyun 
2219*4882a593Smuzhiyun 	return 0;
2220*4882a593Smuzhiyun }
2221