xref: /linux/sound/pci/emu10k1/emumixer.c (revision 1c02e36681ae20a796204e8d629d13fa9d5e20b5)
11da177e4SLinus Torvalds /*
2c1017a4cSJaroslav Kysela  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
31da177e4SLinus Torvalds  *                   Takashi Iwai <tiwai@suse.de>
41da177e4SLinus Torvalds  *                   Creative Labs, Inc.
51da177e4SLinus Torvalds  *  Routines for control of EMU10K1 chips / mixer routines
61da177e4SLinus Torvalds  *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
71da177e4SLinus Torvalds  *
89f4bd5ddSJames Courtier-Dutton  *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
99f4bd5ddSJames Courtier-Dutton  *  	Added EMU 1010 support.
109f4bd5ddSJames Courtier-Dutton  *
111da177e4SLinus Torvalds  *  BUGS:
121da177e4SLinus Torvalds  *    --
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *  TODO:
151da177e4SLinus Torvalds  *    --
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *   This program is free software; you can redistribute it and/or modify
181da177e4SLinus Torvalds  *   it under the terms of the GNU General Public License as published by
191da177e4SLinus Torvalds  *   the Free Software Foundation; either version 2 of the License, or
201da177e4SLinus Torvalds  *   (at your option) any later version.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  *   This program is distributed in the hope that it will be useful,
231da177e4SLinus Torvalds  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
241da177e4SLinus Torvalds  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
251da177e4SLinus Torvalds  *   GNU General Public License for more details.
261da177e4SLinus Torvalds  *
271da177e4SLinus Torvalds  *   You should have received a copy of the GNU General Public License
281da177e4SLinus Torvalds  *   along with this program; if not, write to the Free Software
291da177e4SLinus Torvalds  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
301da177e4SLinus Torvalds  *
311da177e4SLinus Torvalds  */
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds #include <linux/time.h>
341da177e4SLinus Torvalds #include <linux/init.h>
351da177e4SLinus Torvalds #include <sound/core.h>
361da177e4SLinus Torvalds #include <sound/emu10k1.h>
37b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h>
38184c1e2cSJames Courtier-Dutton #include <sound/tlv.h>
39184c1e2cSJames Courtier-Dutton 
40184c1e2cSJames Courtier-Dutton #include "p17v.h"
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds #define AC97_ID_STAC9758	0x83847658
431da177e4SLinus Torvalds 
440cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
45184c1e2cSJames Courtier-Dutton 
46eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
471da177e4SLinus Torvalds {
481da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
491da177e4SLinus Torvalds 	uinfo->count = 1;
501da177e4SLinus Torvalds 	return 0;
511da177e4SLinus Torvalds }
521da177e4SLinus Torvalds 
53eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
54eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
551da177e4SLinus Torvalds {
56eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
571da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
581da177e4SLinus Torvalds 	unsigned long flags;
591da177e4SLinus Torvalds 
6074415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
6174415a36SJames Courtier-Dutton 	if (idx >= 3)
6274415a36SJames Courtier-Dutton 		return -EINVAL;
631da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
641da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
651da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
661da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
671da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
681da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
691da177e4SLinus Torvalds 	return 0;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
72eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
73eb4698f3STakashi Iwai 				      struct snd_ctl_elem_value *ucontrol)
741da177e4SLinus Torvalds {
751da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
761da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
771da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
781da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
791da177e4SLinus Torvalds 	return 0;
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds 
8213d45709SPavel Hofman /*
8313d45709SPavel Hofman  * Items labels in enum mixer controls assigning source data to
8413d45709SPavel Hofman  * each destination
8513d45709SPavel Hofman  */
869f4bd5ddSJames Courtier-Dutton static char *emu1010_src_texts[] = {
879f4bd5ddSJames Courtier-Dutton 	"Silence",
889f4bd5ddSJames Courtier-Dutton 	"Dock Mic A",
899f4bd5ddSJames Courtier-Dutton 	"Dock Mic B",
909f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Left",
919f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Right",
929f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Left",
939f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Right",
949f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Left",
959f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Right",
969f4bd5ddSJames Courtier-Dutton 	"0202 ADC Left",
979f4bd5ddSJames Courtier-Dutton 	"0202 ADC Right",
989f4bd5ddSJames Courtier-Dutton 	"0202 SPDIF Left",
999f4bd5ddSJames Courtier-Dutton 	"0202 SPDIF Right",
1009f4bd5ddSJames Courtier-Dutton 	"ADAT 0",
1019f4bd5ddSJames Courtier-Dutton 	"ADAT 1",
1029f4bd5ddSJames Courtier-Dutton 	"ADAT 2",
1039f4bd5ddSJames Courtier-Dutton 	"ADAT 3",
1049f4bd5ddSJames Courtier-Dutton 	"ADAT 4",
1059f4bd5ddSJames Courtier-Dutton 	"ADAT 5",
1069f4bd5ddSJames Courtier-Dutton 	"ADAT 6",
1079f4bd5ddSJames Courtier-Dutton 	"ADAT 7",
1089f4bd5ddSJames Courtier-Dutton 	"DSP 0",
1099f4bd5ddSJames Courtier-Dutton 	"DSP 1",
1109f4bd5ddSJames Courtier-Dutton 	"DSP 2",
1119f4bd5ddSJames Courtier-Dutton 	"DSP 3",
1129f4bd5ddSJames Courtier-Dutton 	"DSP 4",
1139f4bd5ddSJames Courtier-Dutton 	"DSP 5",
1149f4bd5ddSJames Courtier-Dutton 	"DSP 6",
1159f4bd5ddSJames Courtier-Dutton 	"DSP 7",
1169f4bd5ddSJames Courtier-Dutton 	"DSP 8",
1179f4bd5ddSJames Courtier-Dutton 	"DSP 9",
1189f4bd5ddSJames Courtier-Dutton 	"DSP 10",
1199f4bd5ddSJames Courtier-Dutton 	"DSP 11",
1209f4bd5ddSJames Courtier-Dutton 	"DSP 12",
1219f4bd5ddSJames Courtier-Dutton 	"DSP 13",
1229f4bd5ddSJames Courtier-Dutton 	"DSP 14",
1239f4bd5ddSJames Courtier-Dutton 	"DSP 15",
1249f4bd5ddSJames Courtier-Dutton 	"DSP 16",
1259f4bd5ddSJames Courtier-Dutton 	"DSP 17",
1269f4bd5ddSJames Courtier-Dutton 	"DSP 18",
1279f4bd5ddSJames Courtier-Dutton 	"DSP 19",
1289f4bd5ddSJames Courtier-Dutton 	"DSP 20",
1299f4bd5ddSJames Courtier-Dutton 	"DSP 21",
1309f4bd5ddSJames Courtier-Dutton 	"DSP 22",
1319f4bd5ddSJames Courtier-Dutton 	"DSP 23",
1329f4bd5ddSJames Courtier-Dutton 	"DSP 24",
1339f4bd5ddSJames Courtier-Dutton 	"DSP 25",
1349f4bd5ddSJames Courtier-Dutton 	"DSP 26",
1359f4bd5ddSJames Courtier-Dutton 	"DSP 27",
1369f4bd5ddSJames Courtier-Dutton 	"DSP 28",
1379f4bd5ddSJames Courtier-Dutton 	"DSP 29",
1389f4bd5ddSJames Courtier-Dutton 	"DSP 30",
1399f4bd5ddSJames Courtier-Dutton 	"DSP 31",
1409f4bd5ddSJames Courtier-Dutton };
1419f4bd5ddSJames Courtier-Dutton 
142*1c02e366SCtirad Fertr /* 1616(m) cardbus */
143*1c02e366SCtirad Fertr 
144*1c02e366SCtirad Fertr static char *emu1616_src_texts[] = {
145*1c02e366SCtirad Fertr 	"Silence",
146*1c02e366SCtirad Fertr 	"Dock Mic A",
147*1c02e366SCtirad Fertr 	"Dock Mic B",
148*1c02e366SCtirad Fertr 	"Dock ADC1 Left",
149*1c02e366SCtirad Fertr 	"Dock ADC1 Right",
150*1c02e366SCtirad Fertr 	"Dock ADC2 Left",
151*1c02e366SCtirad Fertr 	"Dock ADC2 Right",
152*1c02e366SCtirad Fertr 	"Dock SPDIF Left",
153*1c02e366SCtirad Fertr 	"Dock SPDIF Right",
154*1c02e366SCtirad Fertr 	"ADAT 0",
155*1c02e366SCtirad Fertr 	"ADAT 1",
156*1c02e366SCtirad Fertr 	"ADAT 2",
157*1c02e366SCtirad Fertr 	"ADAT 3",
158*1c02e366SCtirad Fertr 	"ADAT 4",
159*1c02e366SCtirad Fertr 	"ADAT 5",
160*1c02e366SCtirad Fertr 	"ADAT 6",
161*1c02e366SCtirad Fertr 	"ADAT 7",
162*1c02e366SCtirad Fertr 	"DSP 0",
163*1c02e366SCtirad Fertr 	"DSP 1",
164*1c02e366SCtirad Fertr 	"DSP 2",
165*1c02e366SCtirad Fertr 	"DSP 3",
166*1c02e366SCtirad Fertr 	"DSP 4",
167*1c02e366SCtirad Fertr 	"DSP 5",
168*1c02e366SCtirad Fertr 	"DSP 6",
169*1c02e366SCtirad Fertr 	"DSP 7",
170*1c02e366SCtirad Fertr 	"DSP 8",
171*1c02e366SCtirad Fertr 	"DSP 9",
172*1c02e366SCtirad Fertr 	"DSP 10",
173*1c02e366SCtirad Fertr 	"DSP 11",
174*1c02e366SCtirad Fertr 	"DSP 12",
175*1c02e366SCtirad Fertr 	"DSP 13",
176*1c02e366SCtirad Fertr 	"DSP 14",
177*1c02e366SCtirad Fertr 	"DSP 15",
178*1c02e366SCtirad Fertr 	"DSP 16",
179*1c02e366SCtirad Fertr 	"DSP 17",
180*1c02e366SCtirad Fertr 	"DSP 18",
181*1c02e366SCtirad Fertr 	"DSP 19",
182*1c02e366SCtirad Fertr 	"DSP 20",
183*1c02e366SCtirad Fertr 	"DSP 21",
184*1c02e366SCtirad Fertr 	"DSP 22",
185*1c02e366SCtirad Fertr 	"DSP 23",
186*1c02e366SCtirad Fertr 	"DSP 24",
187*1c02e366SCtirad Fertr 	"DSP 25",
188*1c02e366SCtirad Fertr 	"DSP 26",
189*1c02e366SCtirad Fertr 	"DSP 27",
190*1c02e366SCtirad Fertr 	"DSP 28",
191*1c02e366SCtirad Fertr 	"DSP 29",
192*1c02e366SCtirad Fertr 	"DSP 30",
193*1c02e366SCtirad Fertr 	"DSP 31",
194*1c02e366SCtirad Fertr };
195*1c02e366SCtirad Fertr 
196*1c02e366SCtirad Fertr 
19713d45709SPavel Hofman /*
19813d45709SPavel Hofman  * List of data sources available for each destination
19913d45709SPavel Hofman  */
2009f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_src_regs[] = {
2019f4bd5ddSJames Courtier-Dutton 	EMU_SRC_SILENCE,/* 0 */
2029f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_MIC_A1, /* 1 */
2039f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_MIC_B1, /* 2 */
2049f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */
2059f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */
2069f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */
2079f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */
2089f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */
2099f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */
2109f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */
2119f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */
2129f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */
2139f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */
2149f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT, /* 13 */
2159f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+1, /* 14 */
2169f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+2, /* 15 */
2179f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+3, /* 16 */
2189f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+4, /* 17 */
2199f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+5, /* 18 */
2209f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+6, /* 19 */
2219f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+7, /* 20 */
2229f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A, /* 21 */
2239f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+1, /* 22 */
2249f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+2, /* 23 */
2259f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+3, /* 24 */
2269f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+4, /* 25 */
2279f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+5, /* 26 */
2289f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+6, /* 27 */
2299f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+7, /* 28 */
2309f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+8, /* 29 */
2319f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+9, /* 30 */
2329f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xa, /* 31 */
2339f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xb, /* 32 */
2349f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xc, /* 33 */
2359f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xd, /* 34 */
2369f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xe, /* 35 */
2379f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xf, /* 36 */
2389f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B, /* 37 */
2399f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+1, /* 38 */
2409f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+2, /* 39 */
2419f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+3, /* 40 */
2429f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+4, /* 41 */
2439f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+5, /* 42 */
2449f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+6, /* 43 */
2459f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+7, /* 44 */
2469f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+8, /* 45 */
2479f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+9, /* 46 */
2489f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xa, /* 47 */
2499f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xb, /* 48 */
2509f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xc, /* 49 */
2519f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xd, /* 50 */
2529f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xe, /* 51 */
2539f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
2549f4bd5ddSJames Courtier-Dutton };
2559f4bd5ddSJames Courtier-Dutton 
256*1c02e366SCtirad Fertr /* 1616(m) cardbus */
257*1c02e366SCtirad Fertr static unsigned int emu1616_src_regs[] = {
258*1c02e366SCtirad Fertr 	EMU_SRC_SILENCE,
259*1c02e366SCtirad Fertr 	EMU_SRC_DOCK_MIC_A1,
260*1c02e366SCtirad Fertr 	EMU_SRC_DOCK_MIC_B1,
261*1c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC1_LEFT1,
262*1c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC1_RIGHT1,
263*1c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC2_LEFT1,
264*1c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC2_RIGHT1,
265*1c02e366SCtirad Fertr 	EMU_SRC_MDOCK_SPDIF_LEFT1,
266*1c02e366SCtirad Fertr 	EMU_SRC_MDOCK_SPDIF_RIGHT1,
267*1c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT,
268*1c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+1,
269*1c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+2,
270*1c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+3,
271*1c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+4,
272*1c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+5,
273*1c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+6,
274*1c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+7,
275*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A,
276*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+1,
277*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+2,
278*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+3,
279*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+4,
280*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+5,
281*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+6,
282*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+7,
283*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+8,
284*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+9,
285*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xa,
286*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xb,
287*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xc,
288*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xd,
289*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xe,
290*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xf,
291*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B,
292*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+1,
293*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+2,
294*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+3,
295*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+4,
296*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+5,
297*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+6,
298*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+7,
299*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+8,
300*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+9,
301*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xa,
302*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xb,
303*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xc,
304*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xd,
305*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xe,
306*1c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xf,
307*1c02e366SCtirad Fertr };
308*1c02e366SCtirad Fertr 
30913d45709SPavel Hofman /*
31013d45709SPavel Hofman  * Data destinations - physical EMU outputs.
31113d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
31213d45709SPavel Hofman  */
3139f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_output_dst[] = {
3149f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
3159f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
3169f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC2_LEFT1, /* 2 */
3179f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */
3189f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC3_LEFT1, /* 4 */
3199f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */
3209f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC4_LEFT1, /* 6 */
3219f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */
3229f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_PHONES_LEFT1, /* 8 */
3239f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */
3249f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */
3259f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */
3269f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_SPDIF_LEFT1, /* 12 */
3279f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */
3289f4bd5ddSJames Courtier-Dutton 	EMU_DST_HAMOA_DAC_LEFT1, /* 14 */
3299f4bd5ddSJames Courtier-Dutton 	EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */
3309f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT, /* 16 */
3319f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+1, /* 17 */
3329f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+2, /* 18 */
3339f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+3, /* 19 */
3349f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+4, /* 20 */
3359f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+5, /* 21 */
3369f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+6, /* 22 */
3379f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+7, /* 23 */
3389f4bd5ddSJames Courtier-Dutton };
3399f4bd5ddSJames Courtier-Dutton 
340*1c02e366SCtirad Fertr /* 1616(m) cardbus */
341*1c02e366SCtirad Fertr static unsigned int emu1616_output_dst[] = {
342*1c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC1_LEFT1,
343*1c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC1_RIGHT1,
344*1c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC2_LEFT1,
345*1c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC2_RIGHT1,
346*1c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC3_LEFT1,
347*1c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC3_RIGHT1,
348*1c02e366SCtirad Fertr 	EMU_DST_MDOCK_SPDIF_LEFT1,
349*1c02e366SCtirad Fertr 	EMU_DST_MDOCK_SPDIF_RIGHT1,
350*1c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT,
351*1c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+1,
352*1c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+2,
353*1c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+3,
354*1c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+4,
355*1c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+5,
356*1c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+6,
357*1c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+7,
358*1c02e366SCtirad Fertr 	EMU_DST_MANA_DAC_LEFT,
359*1c02e366SCtirad Fertr 	EMU_DST_MANA_DAC_RIGHT,
360*1c02e366SCtirad Fertr };
361*1c02e366SCtirad Fertr 
36213d45709SPavel Hofman /*
36313d45709SPavel Hofman  * Data destinations - HANA outputs going to Alice2 (audigy) for
36413d45709SPavel Hofman  *   capture (EMU32 + I2S links)
36513d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
36613d45709SPavel Hofman  */
3679f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_input_dst[] = {
3689f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_0,
3699f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_1,
3709f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_2,
3719f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_3,
3729f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_4,
3739f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_5,
3749f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_6,
3759f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_7,
3769f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_8,
3779f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_9,
3789f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_A,
3799f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_B,
3809f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_C,
3819f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_D,
3829f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_E,
3839f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_F,
3849f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_LEFT,
3859f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_RIGHT,
3869f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_LEFT,
3879f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_RIGHT,
3889f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_LEFT,
3899f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_RIGHT,
3909f4bd5ddSJames Courtier-Dutton };
3919f4bd5ddSJames Courtier-Dutton 
392*1c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
393*1c02e366SCtirad Fertr 						struct snd_ctl_elem_info *uinfo)
3949f4bd5ddSJames Courtier-Dutton {
395*1c02e366SCtirad Fertr 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
396*1c02e366SCtirad Fertr 	char **items;
397*1c02e366SCtirad Fertr 
3989f4bd5ddSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3999f4bd5ddSJames Courtier-Dutton 	uinfo->count = 1;
400*1c02e366SCtirad Fertr 	if (emu->card_capabilities->emu_model == 3) { /* 1616(m) cardbus */
401*1c02e366SCtirad Fertr 		uinfo->value.enumerated.items = 49;
402*1c02e366SCtirad Fertr 		items = emu1616_src_texts;
403*1c02e366SCtirad Fertr 	} else {
4049f4bd5ddSJames Courtier-Dutton 		uinfo->value.enumerated.items = 53;
405*1c02e366SCtirad Fertr 		items = emu1010_src_texts;
406*1c02e366SCtirad Fertr 	}
4079f4bd5ddSJames Courtier-Dutton 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
408*1c02e366SCtirad Fertr 		uinfo->value.enumerated.item =
409*1c02e366SCtirad Fertr 			uinfo->value.enumerated.items - 1;
410*1c02e366SCtirad Fertr 	strcpy(uinfo->value.enumerated.name,
411*1c02e366SCtirad Fertr 	       items[uinfo->value.enumerated.item]);
4129f4bd5ddSJames Courtier-Dutton 	return 0;
4139f4bd5ddSJames Courtier-Dutton }
4149f4bd5ddSJames Courtier-Dutton 
4159f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
4169f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4179f4bd5ddSJames Courtier-Dutton {
4189f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
41974415a36SJames Courtier-Dutton 	unsigned int channel;
4209f4bd5ddSJames Courtier-Dutton 
4219f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
42274415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
423*1c02e366SCtirad Fertr 	if (channel >= 24 ||
424*1c02e366SCtirad Fertr 	    (emu->card_capabilities->emu_model == 3 && channel >= 18))
42574415a36SJames Courtier-Dutton 		return -EINVAL;
4269f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
4279f4bd5ddSJames Courtier-Dutton 	return 0;
4289f4bd5ddSJames Courtier-Dutton }
4299f4bd5ddSJames Courtier-Dutton 
4309f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
4319f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4329f4bd5ddSJames Courtier-Dutton {
4339f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4349f4bd5ddSJames Courtier-Dutton 	unsigned int val;
43574415a36SJames Courtier-Dutton 	unsigned int channel;
4369f4bd5ddSJames Courtier-Dutton 
437aa299d01STakashi Iwai 	val = ucontrol->value.enumerated.item[0];
438*1c02e366SCtirad Fertr 	if (val >= 53 ||
439*1c02e366SCtirad Fertr 	    (emu->card_capabilities->emu_model == 3 && val >= 49))
440aa299d01STakashi Iwai 		return -EINVAL;
4419f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
44274415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
443*1c02e366SCtirad Fertr 	if (channel >= 24 ||
444*1c02e366SCtirad Fertr 	    (emu->card_capabilities->emu_model == 3 && channel >= 18))
44574415a36SJames Courtier-Dutton 		return -EINVAL;
446*1c02e366SCtirad Fertr 	if (emu->emu1010.output_source[channel] == val)
447*1c02e366SCtirad Fertr 		return 0;
448aa299d01STakashi Iwai 	emu->emu1010.output_source[channel] = val;
449*1c02e366SCtirad Fertr 	if (emu->card_capabilities->emu_model == 3) /* 1616(m) cardbus */
450*1c02e366SCtirad Fertr 		snd_emu1010_fpga_link_dst_src_write(emu,
451*1c02e366SCtirad Fertr 			emu1616_output_dst[channel], emu1616_src_regs[val]);
452*1c02e366SCtirad Fertr 	else
4539f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
4549f4bd5ddSJames Courtier-Dutton 			emu1010_output_dst[channel], emu1010_src_regs[val]);
455*1c02e366SCtirad Fertr 	return 1;
4569f4bd5ddSJames Courtier-Dutton }
4579f4bd5ddSJames Courtier-Dutton 
4589f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
4599f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4609f4bd5ddSJames Courtier-Dutton {
4619f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
46274415a36SJames Courtier-Dutton 	unsigned int channel;
4639f4bd5ddSJames Courtier-Dutton 
4649f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
46574415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
46674415a36SJames Courtier-Dutton 	if (channel >= 22)
46774415a36SJames Courtier-Dutton 		return -EINVAL;
4689f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
4699f4bd5ddSJames Courtier-Dutton 	return 0;
4709f4bd5ddSJames Courtier-Dutton }
4719f4bd5ddSJames Courtier-Dutton 
4729f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
4739f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4749f4bd5ddSJames Courtier-Dutton {
4759f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4769f4bd5ddSJames Courtier-Dutton 	unsigned int val;
47774415a36SJames Courtier-Dutton 	unsigned int channel;
4789f4bd5ddSJames Courtier-Dutton 
479aa299d01STakashi Iwai 	val = ucontrol->value.enumerated.item[0];
480*1c02e366SCtirad Fertr 	if (val >= 53 ||
481*1c02e366SCtirad Fertr 	    (emu->card_capabilities->emu_model == 3 && val >= 49))
482aa299d01STakashi Iwai 		return -EINVAL;
4839f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
48474415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
48574415a36SJames Courtier-Dutton 	if (channel >= 22)
48674415a36SJames Courtier-Dutton 		return -EINVAL;
487*1c02e366SCtirad Fertr 	if (emu->emu1010.input_source[channel] == val)
488*1c02e366SCtirad Fertr 		return 0;
489aa299d01STakashi Iwai 	emu->emu1010.input_source[channel] = val;
490*1c02e366SCtirad Fertr 	if (emu->card_capabilities->emu_model == 3) /* 1616(m) cardbus */
491*1c02e366SCtirad Fertr 		snd_emu1010_fpga_link_dst_src_write(emu,
492*1c02e366SCtirad Fertr 			emu1010_input_dst[channel], emu1616_src_regs[val]);
493*1c02e366SCtirad Fertr 	else
4949f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
4959f4bd5ddSJames Courtier-Dutton 			emu1010_input_dst[channel], emu1010_src_regs[val]);
496*1c02e366SCtirad Fertr 	return 1;
4979f4bd5ddSJames Courtier-Dutton }
4989f4bd5ddSJames Courtier-Dutton 
4999f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \
5009f4bd5ddSJames Courtier-Dutton {								\
5019f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
5029f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
5039f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
5049f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_output_source_get,			\
5059f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_output_source_put,			\
5069f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
5079f4bd5ddSJames Courtier-Dutton }
5089f4bd5ddSJames Courtier-Dutton 
5099f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = {
5104c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
5114c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
5124c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
5134c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
5144c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
5154c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
5164c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6),
5174c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
5184c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
5194c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
5204c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
5214c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
5224c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
5234c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
5244c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
5254c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
5264c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
5274c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
5284c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
5294c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
5304c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
5314c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
5324c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
5334c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
5349f4bd5ddSJames Courtier-Dutton };
5359f4bd5ddSJames Courtier-Dutton 
536*1c02e366SCtirad Fertr 
537*1c02e366SCtirad Fertr /* 1616(m) cardbus */
538*1c02e366SCtirad Fertr static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] __devinitdata = {
539*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
540*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
541*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
542*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
543*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
544*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
545*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6),
546*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7),
547*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8),
548*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9),
549*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa),
550*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb),
551*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc),
552*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd),
553*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe),
554*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf),
555*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10),
556*1c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11),
557*1c02e366SCtirad Fertr };
558*1c02e366SCtirad Fertr 
559*1c02e366SCtirad Fertr 
5609f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \
5619f4bd5ddSJames Courtier-Dutton {								\
5629f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
5639f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
5649f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
5659f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_input_source_get,			\
5669f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_input_source_put,			\
5679f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
5689f4bd5ddSJames Courtier-Dutton }
5699f4bd5ddSJames Courtier-Dutton 
5709f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = {
5714c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
5724c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
5734c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
5744c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
5754c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
5764c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
5774c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
5784c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
5794c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
5804c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
5814c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
5824c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
5834c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
5844c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
5854c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
5864c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
5874c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
5884c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
5894c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
5904c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
5914c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
5924c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
5939148cc50SJames Courtier-Dutton };
5949148cc50SJames Courtier-Dutton 
5959148cc50SJames Courtier-Dutton 
5969148cc50SJames Courtier-Dutton 
597a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
5989148cc50SJames Courtier-Dutton 
5999148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6009148cc50SJames Courtier-Dutton {
6019148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6029148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6039148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
6049148cc50SJames Courtier-Dutton 	return 0;
6059148cc50SJames Courtier-Dutton }
6069148cc50SJames Courtier-Dutton 
6079148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6089148cc50SJames Courtier-Dutton {
6099148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6109148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6119148cc50SJames Courtier-Dutton 	unsigned int val, cache;
6129148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
6139148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
6149148cc50SJames Courtier-Dutton 	if (val == 1)
6159148cc50SJames Courtier-Dutton 		cache = cache | mask;
6169148cc50SJames Courtier-Dutton 	else
6179148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
6189148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
6199148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
6209148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
6219148cc50SJames Courtier-Dutton 	}
6229148cc50SJames Courtier-Dutton 
6239148cc50SJames Courtier-Dutton 	return 0;
6249148cc50SJames Courtier-Dutton }
6259148cc50SJames Courtier-Dutton 
6269148cc50SJames Courtier-Dutton 
6279148cc50SJames Courtier-Dutton 
6289148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \
6299148cc50SJames Courtier-Dutton {								\
6309148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
6319148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
6329148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_adc_pads_info,			\
6339148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_adc_pads_get,			\
6349148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_adc_pads_put,			\
6359148cc50SJames Courtier-Dutton 	.private_value = chid					\
6369148cc50SJames Courtier-Dutton }
6379148cc50SJames Courtier-Dutton 
6389148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = {
6399148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
6409148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
6419148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
6429148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
6439148cc50SJames Courtier-Dutton };
6449148cc50SJames Courtier-Dutton 
645a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
6469148cc50SJames Courtier-Dutton 
6479148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6489148cc50SJames Courtier-Dutton {
6499148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6509148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6519148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
6529148cc50SJames Courtier-Dutton 	return 0;
6539148cc50SJames Courtier-Dutton }
6549148cc50SJames Courtier-Dutton 
6559148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6569148cc50SJames Courtier-Dutton {
6579148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6589148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6599148cc50SJames Courtier-Dutton 	unsigned int val, cache;
6609148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
6619148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
6629148cc50SJames Courtier-Dutton 	if (val == 1)
6639148cc50SJames Courtier-Dutton 		cache = cache | mask;
6649148cc50SJames Courtier-Dutton 	else
6659148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
6669148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.dac_pads) {
6679148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
6689148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
6699148cc50SJames Courtier-Dutton 	}
6709148cc50SJames Courtier-Dutton 
6719148cc50SJames Courtier-Dutton 	return 0;
6729148cc50SJames Courtier-Dutton }
6739148cc50SJames Courtier-Dutton 
6749148cc50SJames Courtier-Dutton 
6759148cc50SJames Courtier-Dutton 
6769148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \
6779148cc50SJames Courtier-Dutton {								\
6789148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
6799148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
6809148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_dac_pads_info,			\
6819148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_dac_pads_get,			\
6829148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_dac_pads_put,			\
6839148cc50SJames Courtier-Dutton 	.private_value = chid					\
6849148cc50SJames Courtier-Dutton }
6859148cc50SJames Courtier-Dutton 
6869148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = {
6879148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
6889148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
6899148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
6909148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
6919148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
6929f4bd5ddSJames Courtier-Dutton };
6939f4bd5ddSJames Courtier-Dutton 
694b0dbdaeaSJames Courtier-Dutton 
695b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
696b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
697b0dbdaeaSJames Courtier-Dutton {
698edec7bbbSJames Courtier-Dutton 	static char *texts[4] = {
699edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
700b0dbdaeaSJames Courtier-Dutton 	};
701b0dbdaeaSJames Courtier-Dutton 
702b0dbdaeaSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
703b0dbdaeaSJames Courtier-Dutton 	uinfo->count = 1;
704edec7bbbSJames Courtier-Dutton 	uinfo->value.enumerated.items = 4;
705edec7bbbSJames Courtier-Dutton 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
706edec7bbbSJames Courtier-Dutton 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
707b0dbdaeaSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
708b0dbdaeaSJames Courtier-Dutton 	return 0;
709edec7bbbSJames Courtier-Dutton 
710edec7bbbSJames Courtier-Dutton 
711b0dbdaeaSJames Courtier-Dutton }
712b0dbdaeaSJames Courtier-Dutton 
713b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
714b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
715b0dbdaeaSJames Courtier-Dutton {
716b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
717b0dbdaeaSJames Courtier-Dutton 
718b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
719b0dbdaeaSJames Courtier-Dutton 	return 0;
720b0dbdaeaSJames Courtier-Dutton }
721b0dbdaeaSJames Courtier-Dutton 
722b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
723b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
724b0dbdaeaSJames Courtier-Dutton {
725b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
726b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
727b0dbdaeaSJames Courtier-Dutton 	int change = 0;
728b0dbdaeaSJames Courtier-Dutton 
729b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
73074415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 4; */
73174415a36SJames Courtier-Dutton 	if (val >= 4)
73274415a36SJames Courtier-Dutton 		return -EINVAL;
733b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
734b0dbdaeaSJames Courtier-Dutton 	if (change) {
735b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
736b0dbdaeaSJames Courtier-Dutton 		switch (val) {
737b0dbdaeaSJames Courtier-Dutton 		case 0:
738b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
739b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
740b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
741b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
742b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
743b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
744b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
745b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
746b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
747b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
748b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
749b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
750e40a0b2eSJames Courtier-Dutton 			msleep(10);
751b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
752b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
753b0dbdaeaSJames Courtier-Dutton 			break;
754b0dbdaeaSJames Courtier-Dutton 		case 1:
755b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
756b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
757b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
758b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
759b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
760b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
761b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
762b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
763b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
764b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
765b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
766b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
767e40a0b2eSJames Courtier-Dutton 			msleep(10);
768b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
769b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
770b0dbdaeaSJames Courtier-Dutton 			break;
771edec7bbbSJames Courtier-Dutton 
772edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
773edec7bbbSJames Courtier-Dutton 			/* Mute all */
774edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
775edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
776edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
777edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
778edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
779edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
780edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
781edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
782edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
783edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
784edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
785edec7bbbSJames Courtier-Dutton 			msleep(10);
786edec7bbbSJames Courtier-Dutton 			/* Unmute all */
787edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
788edec7bbbSJames Courtier-Dutton 			break;
789edec7bbbSJames Courtier-Dutton 
790edec7bbbSJames Courtier-Dutton 		case 3:
791edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
792edec7bbbSJames Courtier-Dutton 			/* Mute all */
793edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
794edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
795edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
796edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
797edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
798edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
799edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
800edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
801edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
802edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
803edec7bbbSJames Courtier-Dutton 			msleep(10);
804edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
805edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
806edec7bbbSJames Courtier-Dutton 
807edec7bbbSJames Courtier-Dutton 
808edec7bbbSJames Courtier-Dutton 			break;
809b0dbdaeaSJames Courtier-Dutton 		}
810b0dbdaeaSJames Courtier-Dutton 	}
811b0dbdaeaSJames Courtier-Dutton         return change;
812b0dbdaeaSJames Courtier-Dutton }
813b0dbdaeaSJames Courtier-Dutton 
814b0dbdaeaSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_internal_clock =
815b0dbdaeaSJames Courtier-Dutton {
816b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
817b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
818b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
819b0dbdaeaSJames Courtier-Dutton 	.count =	1,
820b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
821b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
822b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
823b0dbdaeaSJames Courtier-Dutton };
824b0dbdaeaSJames Courtier-Dutton 
825184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
826184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
827184c1e2cSJames Courtier-Dutton {
828184c1e2cSJames Courtier-Dutton #if 0
829184c1e2cSJames Courtier-Dutton 	static char *texts[4] = {
830184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
831184c1e2cSJames Courtier-Dutton 	};
832184c1e2cSJames Courtier-Dutton #endif
833184c1e2cSJames Courtier-Dutton 	static char *texts[2] = {
834184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
835184c1e2cSJames Courtier-Dutton 	};
836184c1e2cSJames Courtier-Dutton 
837184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
838184c1e2cSJames Courtier-Dutton 	uinfo->count = 1;
839184c1e2cSJames Courtier-Dutton 	uinfo->value.enumerated.items = 2;
840184c1e2cSJames Courtier-Dutton 	if (uinfo->value.enumerated.item > 1)
841184c1e2cSJames Courtier-Dutton                 uinfo->value.enumerated.item = 1;
842184c1e2cSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
843184c1e2cSJames Courtier-Dutton 	return 0;
844184c1e2cSJames Courtier-Dutton }
845184c1e2cSJames Courtier-Dutton 
846184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
847184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
848184c1e2cSJames Courtier-Dutton {
849184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
850184c1e2cSJames Courtier-Dutton 
851184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
852184c1e2cSJames Courtier-Dutton 	return 0;
853184c1e2cSJames Courtier-Dutton }
854184c1e2cSJames Courtier-Dutton 
855184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
856184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
857184c1e2cSJames Courtier-Dutton {
858184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
859184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
860184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
861184c1e2cSJames Courtier-Dutton 	u32 gpio;
862184c1e2cSJames Courtier-Dutton 	int change = 0;
863184c1e2cSJames Courtier-Dutton 	unsigned long flags;
864184c1e2cSJames Courtier-Dutton 	u32 source;
865184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
866184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
867184c1e2cSJames Courtier-Dutton 	 * for the particular source.
868184c1e2cSJames Courtier-Dutton 	 */
86974415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
87074415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
87174415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
87274415a36SJames Courtier-Dutton 	if (source_id >= 2)
87374415a36SJames Courtier-Dutton 		return -EINVAL;
874184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
875184c1e2cSJames Courtier-Dutton 	if (change) {
876184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
877184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
878184c1e2cSJames Courtier-Dutton 		gpio = inl(emu->port + A_IOCFG);
879184c1e2cSJames Courtier-Dutton 		if (source_id==0)
880184c1e2cSJames Courtier-Dutton 			outl(gpio | 0x4, emu->port + A_IOCFG);
881184c1e2cSJames Courtier-Dutton 		else
882184c1e2cSJames Courtier-Dutton 			outl(gpio & ~0x4, emu->port + A_IOCFG);
883184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
884184c1e2cSJames Courtier-Dutton 
885184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
886184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
887184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
888184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
889184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
890184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
891184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
892184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
893184c1e2cSJames Courtier-Dutton 
894184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
895184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
896184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
897184c1e2cSJames Courtier-Dutton 	}
898184c1e2cSJames Courtier-Dutton         return change;
899184c1e2cSJames Courtier-Dutton }
900184c1e2cSJames Courtier-Dutton 
901184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_capture_source =
902184c1e2cSJames Courtier-Dutton {
903184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
904184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
905184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
906184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
907184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
908184c1e2cSJames Courtier-Dutton };
909184c1e2cSJames Courtier-Dutton 
910184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
911184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
912184c1e2cSJames Courtier-Dutton {
913184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
914184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
915184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
916184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
917184c1e2cSJames Courtier-Dutton 	return 0;
918184c1e2cSJames Courtier-Dutton }
919184c1e2cSJames Courtier-Dutton 
920184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
921184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
922184c1e2cSJames Courtier-Dutton {
923184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
92474415a36SJames Courtier-Dutton 	unsigned int source_id;
925184c1e2cSJames Courtier-Dutton 
926184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
92774415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
92874415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
92974415a36SJames Courtier-Dutton 	if (source_id >= 2)
93074415a36SJames Courtier-Dutton 		return -EINVAL;
931184c1e2cSJames Courtier-Dutton 
932184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
933184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
934184c1e2cSJames Courtier-Dutton 	return 0;
935184c1e2cSJames Courtier-Dutton }
936184c1e2cSJames Courtier-Dutton 
937184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
938184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
939184c1e2cSJames Courtier-Dutton {
940184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
941184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
942184c1e2cSJames Courtier-Dutton 	unsigned int ngain;
94374415a36SJames Courtier-Dutton 	unsigned int source_id;
944184c1e2cSJames Courtier-Dutton 	int change = 0;
945184c1e2cSJames Courtier-Dutton 
946184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
94774415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
94874415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
94974415a36SJames Courtier-Dutton 	if (source_id >= 2)
95074415a36SJames Courtier-Dutton 		return -EINVAL;
951184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
952184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[0];
953184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
954184c1e2cSJames Courtier-Dutton 		return 0;
955184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
956184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
957184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
95874415a36SJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][0] = ngain;
959184c1e2cSJames Courtier-Dutton 		change = 1;
960184c1e2cSJames Courtier-Dutton 	}
961184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
962184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[1];
963184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
964184c1e2cSJames Courtier-Dutton 		return 0;
965184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
966184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
967184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
96874415a36SJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][1] = ngain;
969184c1e2cSJames Courtier-Dutton 		change = 1;
970184c1e2cSJames Courtier-Dutton 	}
971184c1e2cSJames Courtier-Dutton 
972184c1e2cSJames Courtier-Dutton 	return change;
973184c1e2cSJames Courtier-Dutton }
974184c1e2cSJames Courtier-Dutton 
975184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \
976184c1e2cSJames Courtier-Dutton {								\
977184c1e2cSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
978184c1e2cSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
979184c1e2cSJames Courtier-Dutton 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
980184c1e2cSJames Courtier-Dutton 	.info =  snd_audigy_i2c_volume_info,			\
981184c1e2cSJames Courtier-Dutton 	.get =   snd_audigy_i2c_volume_get,			\
982184c1e2cSJames Courtier-Dutton 	.put =   snd_audigy_i2c_volume_put,			\
983184c1e2cSJames Courtier-Dutton 	.tlv = { .p = snd_audigy_db_scale2 },			\
984184c1e2cSJames Courtier-Dutton 	.private_value = chid					\
985184c1e2cSJames Courtier-Dutton }
986184c1e2cSJames Courtier-Dutton 
987184c1e2cSJames Courtier-Dutton 
988184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = {
989184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Mic Capture Volume", 0),
990184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Line Capture Volume", 0)
991184c1e2cSJames Courtier-Dutton };
992184c1e2cSJames Courtier-Dutton 
9930af68e5eSTakashi Iwai #if 0
994eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9951da177e4SLinus Torvalds {
9961da177e4SLinus Torvalds 	static char *texts[] = {"44100", "48000", "96000"};
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
9991da177e4SLinus Torvalds 	uinfo->count = 1;
10001da177e4SLinus Torvalds 	uinfo->value.enumerated.items = 3;
10011da177e4SLinus Torvalds 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
10021da177e4SLinus Torvalds 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
10031da177e4SLinus Torvalds 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
10041da177e4SLinus Torvalds 	return 0;
10051da177e4SLinus Torvalds }
10061da177e4SLinus Torvalds 
1007eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
1008eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10091da177e4SLinus Torvalds {
1010eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10111da177e4SLinus Torvalds 	unsigned int tmp;
10121da177e4SLinus Torvalds 	unsigned long flags;
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds 
10151da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10161da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
10171da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
10181da177e4SLinus Torvalds 	case A_SPDIF_44100:
10191da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
10201da177e4SLinus Torvalds 		break;
10211da177e4SLinus Torvalds 	case A_SPDIF_48000:
10221da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
10231da177e4SLinus Torvalds 		break;
10241da177e4SLinus Torvalds 	case A_SPDIF_96000:
10251da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
10261da177e4SLinus Torvalds 		break;
10271da177e4SLinus Torvalds 	default:
10281da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
10291da177e4SLinus Torvalds 	}
10301da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10311da177e4SLinus Torvalds 	return 0;
10321da177e4SLinus Torvalds }
10331da177e4SLinus Torvalds 
1034eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
1035eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10361da177e4SLinus Torvalds {
1037eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10381da177e4SLinus Torvalds 	int change;
10391da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
10401da177e4SLinus Torvalds 	unsigned long flags;
10411da177e4SLinus Torvalds 
10421da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
10431da177e4SLinus Torvalds 	case 0:
10441da177e4SLinus Torvalds 		val = A_SPDIF_44100;
10451da177e4SLinus Torvalds 		break;
10461da177e4SLinus Torvalds 	case 1:
10471da177e4SLinus Torvalds 		val = A_SPDIF_48000;
10481da177e4SLinus Torvalds 		break;
10491da177e4SLinus Torvalds 	case 2:
10501da177e4SLinus Torvalds 		val = A_SPDIF_96000;
10511da177e4SLinus Torvalds 		break;
10521da177e4SLinus Torvalds 	default:
10531da177e4SLinus Torvalds 		val = A_SPDIF_48000;
10541da177e4SLinus Torvalds 		break;
10551da177e4SLinus Torvalds 	}
10561da177e4SLinus Torvalds 
10571da177e4SLinus Torvalds 
10581da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10591da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
10601da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
10611da177e4SLinus Torvalds 	tmp |= val;
10621da177e4SLinus Torvalds 	if ((change = (tmp != reg)))
10631da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
10641da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10651da177e4SLinus Torvalds 	return change;
10661da177e4SLinus Torvalds }
10671da177e4SLinus Torvalds 
1068eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_spdif_output_rate =
10691da177e4SLinus Torvalds {
10701da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
10711da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
10721da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
10731da177e4SLinus Torvalds 	.count =	1,
10741da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
10751da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
10761da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
10771da177e4SLinus Torvalds };
10780af68e5eSTakashi Iwai #endif
10791da177e4SLinus Torvalds 
1080eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1081eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10821da177e4SLinus Torvalds {
1083eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10841da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
10851da177e4SLinus Torvalds 	int change;
10861da177e4SLinus Torvalds 	unsigned int val;
10871da177e4SLinus Torvalds 	unsigned long flags;
10881da177e4SLinus Torvalds 
108974415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
109074415a36SJames Courtier-Dutton 	if (idx >= 3)
109174415a36SJames Courtier-Dutton 		return -EINVAL;
10921da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
10931da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
10941da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
10951da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
10961da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10971da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
10981da177e4SLinus Torvalds 	if (change) {
10991da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
11001da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
11011da177e4SLinus Torvalds 	}
11021da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11031da177e4SLinus Torvalds 	return change;
11041da177e4SLinus Torvalds }
11051da177e4SLinus Torvalds 
1106eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
11071da177e4SLinus Torvalds {
11081da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
11095549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11101da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
11117583cb51STakashi Iwai 	.count =	3,
11121da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
11131da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
11141da177e4SLinus Torvalds };
11151da177e4SLinus Torvalds 
1116eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_control =
11171da177e4SLinus Torvalds {
11185549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
11191da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
11207583cb51STakashi Iwai 	.count =	3,
11211da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
11221da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
11231da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
11241da177e4SLinus Torvalds };
11251da177e4SLinus Torvalds 
11261da177e4SLinus Torvalds 
1127eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
11281da177e4SLinus Torvalds {
11291da177e4SLinus Torvalds 	if (emu->audigy) {
11301da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
11311da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
11321da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
11331da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
11341da177e4SLinus Torvalds 	} else {
11351da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
11361da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
11371da177e4SLinus Torvalds 	}
11381da177e4SLinus Torvalds }
11391da177e4SLinus Torvalds 
1140eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
11411da177e4SLinus Torvalds {
11421da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
11431da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
11441da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
11451da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
11461da177e4SLinus Torvalds 	if (emu->audigy) {
11471da177e4SLinus Torvalds 		unsigned int val = ((unsigned int)volume[4] << 24) |
11481da177e4SLinus Torvalds 			((unsigned int)volume[5] << 16) |
11491da177e4SLinus Torvalds 			((unsigned int)volume[6] << 8) |
11501da177e4SLinus Torvalds 			(unsigned int)volume[7];
11511da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
11521da177e4SLinus Torvalds 	}
11531da177e4SLinus Torvalds }
11541da177e4SLinus Torvalds 
11551da177e4SLinus Torvalds /* PCM stream controls */
11561da177e4SLinus Torvalds 
1157eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11581da177e4SLinus Torvalds {
1159eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11601da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
11611da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
11621da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11631da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
11641da177e4SLinus Torvalds 	return 0;
11651da177e4SLinus Torvalds }
11661da177e4SLinus Torvalds 
1167eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1168eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11691da177e4SLinus Torvalds {
11701da177e4SLinus Torvalds 	unsigned long flags;
1171eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1172eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1173eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11741da177e4SLinus Torvalds 	int voice, idx;
11751da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11761da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11771da177e4SLinus Torvalds 
11781da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11791da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
11801da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
11811da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
11821da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
11831da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11841da177e4SLinus Torvalds 	return 0;
11851da177e4SLinus Torvalds }
11861da177e4SLinus Torvalds 
1187eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1188eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11891da177e4SLinus Torvalds {
11901da177e4SLinus Torvalds 	unsigned long flags;
1191eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1192eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1193eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11941da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
11951da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11961da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11991da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
12001da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
12011da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
12021da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
12031da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
12041da177e4SLinus Torvalds 				change = 1;
12051da177e4SLinus Torvalds 			}
12061da177e4SLinus Torvalds 		}
12071da177e4SLinus Torvalds 	if (change && mix->epcm) {
12081da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
12091da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
12101da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
12111da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
12121da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
12131da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
12141da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
12151da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
12161da177e4SLinus Torvalds 		}
12171da177e4SLinus Torvalds 	}
12181da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12191da177e4SLinus Torvalds 	return change;
12201da177e4SLinus Torvalds }
12211da177e4SLinus Torvalds 
1222eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_routing_control =
12231da177e4SLinus Torvalds {
12241da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
122567ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12261da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
12271da177e4SLinus Torvalds 	.count =	32,
12281da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
12291da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
12301da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
12311da177e4SLinus Torvalds };
12321da177e4SLinus Torvalds 
1233eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12341da177e4SLinus Torvalds {
1235eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12361da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12371da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
12381da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12391da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
12401da177e4SLinus Torvalds 	return 0;
12411da177e4SLinus Torvalds }
12421da177e4SLinus Torvalds 
1243eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1244eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12451da177e4SLinus Torvalds {
12461da177e4SLinus Torvalds 	unsigned long flags;
1247eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1248eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1249eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12501da177e4SLinus Torvalds 	int idx;
12511da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12521da177e4SLinus Torvalds 
12531da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12541da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
12551da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
12561da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12571da177e4SLinus Torvalds 	return 0;
12581da177e4SLinus Torvalds }
12591da177e4SLinus Torvalds 
1260eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1261eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12621da177e4SLinus Torvalds {
12631da177e4SLinus Torvalds 	unsigned long flags;
1264eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1265eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1266eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12671da177e4SLinus Torvalds 	int change = 0, idx, val;
12681da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12691da177e4SLinus Torvalds 
12701da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12711da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
12721da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
12731da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
12741da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
12751da177e4SLinus Torvalds 			change = 1;
12761da177e4SLinus Torvalds 		}
12771da177e4SLinus Torvalds 	}
12781da177e4SLinus Torvalds 	if (change && mix->epcm) {
12791da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
12801da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
12811da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
12821da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
12831da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
12841da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
12851da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
12861da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
12871da177e4SLinus Torvalds 		}
12881da177e4SLinus Torvalds 	}
12891da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12901da177e4SLinus Torvalds 	return change;
12911da177e4SLinus Torvalds }
12921da177e4SLinus Torvalds 
1293eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_volume_control =
12941da177e4SLinus Torvalds {
12951da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
129667ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12971da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
12981da177e4SLinus Torvalds 	.count =	32,
12991da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
13001da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
13011da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
13021da177e4SLinus Torvalds };
13031da177e4SLinus Torvalds 
1304eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13051da177e4SLinus Torvalds {
13061da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13071da177e4SLinus Torvalds 	uinfo->count = 3;
13081da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13091da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
13101da177e4SLinus Torvalds 	return 0;
13111da177e4SLinus Torvalds }
13121da177e4SLinus Torvalds 
1313eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1314eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
13151da177e4SLinus Torvalds {
1316eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1317eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1318eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13191da177e4SLinus Torvalds 	unsigned long flags;
13201da177e4SLinus Torvalds 	int idx;
13211da177e4SLinus Torvalds 
13221da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13231da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
13241da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->attn[idx];
13251da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13261da177e4SLinus Torvalds 	return 0;
13271da177e4SLinus Torvalds }
13281da177e4SLinus Torvalds 
1329eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1330eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
13311da177e4SLinus Torvalds {
13321da177e4SLinus Torvalds 	unsigned long flags;
1333eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1334eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1335eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13361da177e4SLinus Torvalds 	int change = 0, idx, val;
13371da177e4SLinus Torvalds 
13381da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13391da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
13401da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 0xffff;
13411da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
13421da177e4SLinus Torvalds 			mix->attn[idx] = val;
13431da177e4SLinus Torvalds 			change = 1;
13441da177e4SLinus Torvalds 		}
13451da177e4SLinus Torvalds 	}
13461da177e4SLinus Torvalds 	if (change && mix->epcm) {
13471da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
13481da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
13491da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
13501da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
13511da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
13521da177e4SLinus Torvalds 		}
13531da177e4SLinus Torvalds 	}
13541da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13551da177e4SLinus Torvalds 	return change;
13561da177e4SLinus Torvalds }
13571da177e4SLinus Torvalds 
1358eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_attn_control =
13591da177e4SLinus Torvalds {
13601da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
136167ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13621da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
13631da177e4SLinus Torvalds 	.count =	32,
13641da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
13651da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
13661da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
13671da177e4SLinus Torvalds };
13681da177e4SLinus Torvalds 
13691da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
13701da177e4SLinus Torvalds 
1371eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13721da177e4SLinus Torvalds {
1373eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13741da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13751da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
13761da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13771da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
13781da177e4SLinus Torvalds 	return 0;
13791da177e4SLinus Torvalds }
13801da177e4SLinus Torvalds 
1381eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1382eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
13831da177e4SLinus Torvalds {
13841da177e4SLinus Torvalds 	unsigned long flags;
1385eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1386eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1387eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13881da177e4SLinus Torvalds 	int idx;
13891da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13901da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
13911da177e4SLinus Torvalds 
13921da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13931da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
13941da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
13951da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
13961da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13971da177e4SLinus Torvalds 	return 0;
13981da177e4SLinus Torvalds }
13991da177e4SLinus Torvalds 
1400eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1401eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14021da177e4SLinus Torvalds {
14031da177e4SLinus Torvalds 	unsigned long flags;
1404eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14051da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1406eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
14071da177e4SLinus Torvalds 	int change = 0, idx, val;
14081da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14091da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14101da177e4SLinus Torvalds 
14111da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14121da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
14131da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
14141da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
14151da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
14161da177e4SLinus Torvalds 			change = 1;
14171da177e4SLinus Torvalds 		}
14181da177e4SLinus Torvalds 	}
14191da177e4SLinus Torvalds 
14201da177e4SLinus Torvalds 	if (change && mix->epcm) {
14211da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
14221da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
14231da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
14241da177e4SLinus Torvalds 		}
14251da177e4SLinus Torvalds 	}
14261da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14271da177e4SLinus Torvalds 	return change;
14281da177e4SLinus Torvalds }
14291da177e4SLinus Torvalds 
1430eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
14311da177e4SLinus Torvalds {
14321da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
14331da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14341da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
14351da177e4SLinus Torvalds 	.count =	16,
14361da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
14371da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
14381da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
14391da177e4SLinus Torvalds };
14401da177e4SLinus Torvalds 
1441eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14421da177e4SLinus Torvalds {
1443eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14441da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14451da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
14461da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14471da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
14481da177e4SLinus Torvalds 	return 0;
14491da177e4SLinus Torvalds }
14501da177e4SLinus Torvalds 
1451eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1452eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
14531da177e4SLinus Torvalds {
14541da177e4SLinus Torvalds 	unsigned long flags;
1455eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1456eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1457eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14581da177e4SLinus Torvalds 	int idx;
14591da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14601da177e4SLinus Torvalds 
14611da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14621da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
14631da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
14641da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14651da177e4SLinus Torvalds 	return 0;
14661da177e4SLinus Torvalds }
14671da177e4SLinus Torvalds 
1468eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1469eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
14701da177e4SLinus Torvalds {
14711da177e4SLinus Torvalds 	unsigned long flags;
1472eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14731da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1474eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
14751da177e4SLinus Torvalds 	int change = 0, idx, val;
14761da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14771da177e4SLinus Torvalds 
14781da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14791da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
14801da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
14811da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
14821da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
14831da177e4SLinus Torvalds 			change = 1;
14841da177e4SLinus Torvalds 		}
14851da177e4SLinus Torvalds 	}
14861da177e4SLinus Torvalds 	if (change && mix->epcm) {
14871da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
14881da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
14891da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
14901da177e4SLinus Torvalds 		}
14911da177e4SLinus Torvalds 	}
14921da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14931da177e4SLinus Torvalds 	return change;
14941da177e4SLinus Torvalds }
14951da177e4SLinus Torvalds 
14961da177e4SLinus Torvalds 
1497eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
14981da177e4SLinus Torvalds {
14991da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15001da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15011da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
15021da177e4SLinus Torvalds 	.count =	16,
15031da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
15041da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
15051da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
15061da177e4SLinus Torvalds };
15071da177e4SLinus Torvalds 
1508eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15091da177e4SLinus Torvalds {
15101da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15111da177e4SLinus Torvalds 	uinfo->count = 1;
15121da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
15131da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
15141da177e4SLinus Torvalds 	return 0;
15151da177e4SLinus Torvalds }
15161da177e4SLinus Torvalds 
1517eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1518eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
15191da177e4SLinus Torvalds {
1520eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1521eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1522eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15231da177e4SLinus Torvalds 	unsigned long flags;
15241da177e4SLinus Torvalds 
15251da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15261da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = mix->attn[0];
15271da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15281da177e4SLinus Torvalds 	return 0;
15291da177e4SLinus Torvalds }
15301da177e4SLinus Torvalds 
1531eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1532eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
15331da177e4SLinus Torvalds {
15341da177e4SLinus Torvalds 	unsigned long flags;
1535eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15361da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1537eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
15381da177e4SLinus Torvalds 	int change = 0, val;
15391da177e4SLinus Torvalds 
15401da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15411da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] & 0xffff;
15421da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
15431da177e4SLinus Torvalds 		mix->attn[0] = val;
15441da177e4SLinus Torvalds 		change = 1;
15451da177e4SLinus Torvalds 	}
15461da177e4SLinus Torvalds 	if (change && mix->epcm) {
15471da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
15481da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
15491da177e4SLinus Torvalds 		}
15501da177e4SLinus Torvalds 	}
15511da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15521da177e4SLinus Torvalds 	return change;
15531da177e4SLinus Torvalds }
15541da177e4SLinus Torvalds 
1555eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
15561da177e4SLinus Torvalds {
15571da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15581da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15591da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
15601da177e4SLinus Torvalds 	.count =	16,
15611da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
15621da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
15631da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
15641da177e4SLinus Torvalds };
15651da177e4SLinus Torvalds 
1566a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
15671da177e4SLinus Torvalds 
1568eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1569eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
15701da177e4SLinus Torvalds {
1571eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15721da177e4SLinus Torvalds 
15731da177e4SLinus Torvalds 	if (emu->audigy)
15741da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
15751da177e4SLinus Torvalds 	else
15761da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
15771da177e4SLinus Torvalds 	return 0;
15781da177e4SLinus Torvalds }
15791da177e4SLinus Torvalds 
1580eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1581eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
15821da177e4SLinus Torvalds {
15831da177e4SLinus Torvalds 	unsigned long flags;
1584eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15851da177e4SLinus Torvalds 	unsigned int reg, val;
15861da177e4SLinus Torvalds 	int change = 0;
15871da177e4SLinus Torvalds 
15881da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1589184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1590184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1591184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
15921da177e4SLinus Torvalds 		reg = inl(emu->port + A_IOCFG);
15931da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
15941da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
15951da177e4SLinus Torvalds 		if (change) {
15961da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
15971da177e4SLinus Torvalds 			reg |= val;
15981da177e4SLinus Torvalds 			outl(reg | val, emu->port + A_IOCFG);
15991da177e4SLinus Torvalds 		}
16001da177e4SLinus Torvalds 	}
16011da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
16021da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0;
16031da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
16041da177e4SLinus Torvalds 	if (change) {
16051da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
16061da177e4SLinus Torvalds 		reg |= val;
16071da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
16081da177e4SLinus Torvalds 	}
16091da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
16101da177e4SLinus Torvalds 	return change;
16111da177e4SLinus Torvalds }
16121da177e4SLinus Torvalds 
1613eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata =
16141da177e4SLinus Torvalds {
16151da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16161da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
16171da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
16181da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
16191da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
16201da177e4SLinus Torvalds };
16211da177e4SLinus Torvalds 
1622eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata =
16231da177e4SLinus Torvalds {
16241da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16251da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
16261da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
16271da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
16281da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
16291da177e4SLinus Torvalds };
16301da177e4SLinus Torvalds 
16311da177e4SLinus Torvalds /*
16321da177e4SLinus Torvalds  */
1633eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
16341da177e4SLinus Torvalds {
1635eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
16361da177e4SLinus Torvalds 	emu->ac97 = NULL;
16371da177e4SLinus Torvalds }
16381da177e4SLinus Torvalds 
16391da177e4SLinus Torvalds /*
16401da177e4SLinus Torvalds  */
1641eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
16421da177e4SLinus Torvalds {
1643eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
16441da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
16451da177e4SLinus Torvalds 	strcpy(id.name, name);
16461da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
16471da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
16481da177e4SLinus Torvalds }
16491da177e4SLinus Torvalds 
1650eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
16511da177e4SLinus Torvalds {
1652eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
16531da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
16541da177e4SLinus Torvalds 	strcpy(sid.name, name);
16551da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
16561da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
16571da177e4SLinus Torvalds }
16581da177e4SLinus Torvalds 
1659eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
16601da177e4SLinus Torvalds {
1661eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
16621da177e4SLinus Torvalds 	if (kctl) {
16631da177e4SLinus Torvalds 		strcpy(kctl->id.name, dst);
16641da177e4SLinus Torvalds 		return 0;
16651da177e4SLinus Torvalds 	}
16661da177e4SLinus Torvalds 	return -ENOENT;
16671da177e4SLinus Torvalds }
16681da177e4SLinus Torvalds 
1669eb4698f3STakashi Iwai int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
167067ed4161SClemens Ladisch 				int pcm_device, int multi_device)
16711da177e4SLinus Torvalds {
16721da177e4SLinus Torvalds 	int err, pcm;
1673eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1674eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
16751da177e4SLinus Torvalds 	char **c;
16761da177e4SLinus Torvalds 	static char *emu10k1_remove_ctls[] = {
16771da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
16781da177e4SLinus Torvalds 		"Master Mono Playback Switch",
16791da177e4SLinus Torvalds 		"Master Mono Playback Volume",
16801da177e4SLinus Torvalds 		"PCM Out Path & Mute",
16811da177e4SLinus Torvalds 		"Mono Output Select",
16827eae36fbSTakashi Iwai 		"Front Playback Switch",
16837eae36fbSTakashi Iwai 		"Front Playback Volume",
16841da177e4SLinus Torvalds 		"Surround Playback Switch",
16851da177e4SLinus Torvalds 		"Surround Playback Volume",
16861da177e4SLinus Torvalds 		"Center Playback Switch",
16871da177e4SLinus Torvalds 		"Center Playback Volume",
16881da177e4SLinus Torvalds 		"LFE Playback Switch",
16891da177e4SLinus Torvalds 		"LFE Playback Volume",
16901da177e4SLinus Torvalds 		NULL
16911da177e4SLinus Torvalds 	};
16921da177e4SLinus Torvalds 	static char *emu10k1_rename_ctls[] = {
16931da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
16941da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
16951da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
16961da177e4SLinus Torvalds 		NULL
16971da177e4SLinus Torvalds 	};
16981da177e4SLinus Torvalds 	static char *audigy_remove_ctls[] = {
16991da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
170021fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
170121fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
17021da177e4SLinus Torvalds 		"PCM Playback Switch",
17031da177e4SLinus Torvalds 		"PCM Playback Volume",
17041da177e4SLinus Torvalds 		"Master Mono Playback Switch",
17051da177e4SLinus Torvalds 		"Master Mono Playback Volume",
17061da177e4SLinus Torvalds 		"Master Playback Switch",
17071da177e4SLinus Torvalds 		"Master Playback Volume",
17081da177e4SLinus Torvalds 		"PCM Out Path & Mute",
17091da177e4SLinus Torvalds 		"Mono Output Select",
17101da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
17111da177e4SLinus Torvalds 		"Capture Source",
17121da177e4SLinus Torvalds 		"Capture Switch",
17131da177e4SLinus Torvalds 		"Capture Volume",
17141da177e4SLinus Torvalds 		"Mic Select",
17151da177e4SLinus Torvalds 		"Video Playback Switch",
17161da177e4SLinus Torvalds 		"Video Playback Volume",
17171da177e4SLinus Torvalds 		"Mic Playback Switch",
17181da177e4SLinus Torvalds 		"Mic Playback Volume",
17191da177e4SLinus Torvalds 		NULL
17201da177e4SLinus Torvalds 	};
17211da177e4SLinus Torvalds 	static char *audigy_rename_ctls[] = {
17221da177e4SLinus Torvalds 		/* use conventional names */
17231da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
17241da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
17251da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
17261da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
17271da177e4SLinus Torvalds 		NULL
17281da177e4SLinus Torvalds 	};
1729184c1e2cSJames Courtier-Dutton 	static char *audigy_rename_ctls_i2c_adc[] = {
1730184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1731184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1732184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1733184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1734184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1735eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1736184c1e2cSJames Courtier-Dutton 		NULL
1737184c1e2cSJames Courtier-Dutton 	};
1738184c1e2cSJames Courtier-Dutton 	static char *audigy_remove_ctls_i2c_adc[] = {
1739184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1740184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1741184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1742184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1743184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1744eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1745184c1e2cSJames Courtier-Dutton 		NULL
1746184c1e2cSJames Courtier-Dutton 	};
174721fdddeaSJames Courtier-Dutton 	static char *audigy_remove_ctls_1361t_adc[] = {
174821fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
174921fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
175021fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
175121fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
175221fdddeaSJames Courtier-Dutton 		"Master Mono Playback Switch",
175321fdddeaSJames Courtier-Dutton 		"Master Mono Playback Volume",
175421fdddeaSJames Courtier-Dutton 		"Capture Source",
175521fdddeaSJames Courtier-Dutton 		"Capture Switch",
175621fdddeaSJames Courtier-Dutton 		"Capture Volume",
175721fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
175821fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
175921fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
176021fdddeaSJames Courtier-Dutton 		"3D Control - Center",
176121fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
176221fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
176321fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
176421fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
176521fdddeaSJames Courtier-Dutton 		NULL
176621fdddeaSJames Courtier-Dutton 	};
176721fdddeaSJames Courtier-Dutton 	static char *audigy_rename_ctls_1361t_adc[] = {
176821fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
176921fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
177021fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
177121fdddeaSJames Courtier-Dutton 		"PC Speaker Playback Switch", "PC Speaker Capture Switch",
177221fdddeaSJames Courtier-Dutton 		"PC Speaker Playback Volume", "PC Speaker Capture Volume",
177321fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
177421fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
177521fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
177621fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
177721fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
177821fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
177921fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
178021fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
178121fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
178221fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
178321fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
178421fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
178521fdddeaSJames Courtier-Dutton 
178621fdddeaSJames Courtier-Dutton 		NULL
178721fdddeaSJames Courtier-Dutton 	};
17881da177e4SLinus Torvalds 
17892b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1790eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1791eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
1792eb4698f3STakashi Iwai 		static struct snd_ac97_bus_ops ops = {
17931da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
17941da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
17951da177e4SLinus Torvalds 		};
17961da177e4SLinus Torvalds 
1797b1508693STakashi Iwai 		if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0)
17981da177e4SLinus Torvalds 			return err;
17991da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
18001da177e4SLinus Torvalds 
18011da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
18021da177e4SLinus Torvalds 		ac97.private_data = emu;
18031da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
18041da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
1805b1508693STakashi Iwai 		if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
1806b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
18071da177e4SLinus Torvalds 				return err;
1808b1508693STakashi Iwai 			snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n");
1809b1508693STakashi Iwai 			snd_printd(KERN_INFO"          Proceeding without ac97 mixers...\n");
1810b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1811b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1812b1508693STakashi Iwai 		}
18131da177e4SLinus Torvalds 		if (emu->audigy) {
18141da177e4SLinus Torvalds 			/* set master volume to 0 dB */
18154d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
18161da177e4SLinus Torvalds 			/* set capture source to mic */
18174d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
181821fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
181921fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
182021fdddeaSJames Courtier-Dutton 			else
18211da177e4SLinus Torvalds 				c = audigy_remove_ctls;
18221da177e4SLinus Torvalds 		} else {
18231da177e4SLinus Torvalds 			/*
18241da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
18251da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
18261da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
18271da177e4SLinus Torvalds 			 */
18281da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
18291da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
18301da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
18312594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
18321da177e4SLinus Torvalds 			}
18331da177e4SLinus Torvalds 			/* remove unused AC97 controls */
18344d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
18354d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
18361da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
18371da177e4SLinus Torvalds 		}
18381da177e4SLinus Torvalds 		for (; *c; c++)
18391da177e4SLinus Torvalds 			remove_ctl(card, *c);
1840184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1841184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1842184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1843184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
18441da177e4SLinus Torvalds 	} else {
1845f12aa40cSTakashi Iwai 	no_ac97:
18462b637da5SLee Revell 		if (emu->card_capabilities->ecard)
18471da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
18481da177e4SLinus Torvalds 		else if (emu->audigy)
18491da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
18501da177e4SLinus Torvalds 		else
18511da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
18521da177e4SLinus Torvalds 	}
18531da177e4SLinus Torvalds 
18541da177e4SLinus Torvalds 	if (emu->audigy)
185521fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
185621fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1857184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1858184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
185921fdddeaSJames Courtier-Dutton 		else
18601da177e4SLinus Torvalds 			c = audigy_rename_ctls;
18611da177e4SLinus Torvalds 	else
18621da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
18631da177e4SLinus Torvalds 	for (; *c; c += 2)
18641da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
186521fdddeaSJames Courtier-Dutton 
1866e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1867e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1868e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1869e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1870e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1871e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Switch");
1872e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Volume");
1873e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Center");
1874e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Depth");
1875e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Switch");
1876e3b9bc0eSJames Courtier-Dutton 	}
18771da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
18781da177e4SLinus Torvalds 		return -ENOMEM;
187967ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
18801da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
18811da177e4SLinus Torvalds 		return err;
18821da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
18831da177e4SLinus Torvalds 		return -ENOMEM;
188467ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
18851da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
18861da177e4SLinus Torvalds 		return err;
18871da177e4SLinus Torvalds 	if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
18881da177e4SLinus Torvalds 		return -ENOMEM;
188967ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
18901da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
18911da177e4SLinus Torvalds 		return err;
18921da177e4SLinus Torvalds 
18931da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
18941da177e4SLinus Torvalds 		return -ENOMEM;
189567ed4161SClemens Ladisch 	kctl->id.device = multi_device;
18961da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
18971da177e4SLinus Torvalds 		return err;
18981da177e4SLinus Torvalds 
18991da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
19001da177e4SLinus Torvalds 		return -ENOMEM;
190167ed4161SClemens Ladisch 	kctl->id.device = multi_device;
19021da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19031da177e4SLinus Torvalds 		return err;
19041da177e4SLinus Torvalds 
19051da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
19061da177e4SLinus Torvalds 		return -ENOMEM;
190767ed4161SClemens Ladisch 	kctl->id.device = multi_device;
19081da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19091da177e4SLinus Torvalds 		return err;
19101da177e4SLinus Torvalds 
19111da177e4SLinus Torvalds 	/* initialize the routing and volume table for each pcm playback stream */
19121da177e4SLinus Torvalds 	for (pcm = 0; pcm < 32; pcm++) {
1913eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
19141da177e4SLinus Torvalds 		int v;
19151da177e4SLinus Torvalds 
19161da177e4SLinus Torvalds 		mix = &emu->pcm_mixer[pcm];
19171da177e4SLinus Torvalds 		mix->epcm = NULL;
19181da177e4SLinus Torvalds 
19191da177e4SLinus Torvalds 		for (v = 0; v < 4; v++)
19201da177e4SLinus Torvalds 			mix->send_routing[0][v] =
19211da177e4SLinus Torvalds 				mix->send_routing[1][v] =
19221da177e4SLinus Torvalds 				mix->send_routing[2][v] = v;
19231da177e4SLinus Torvalds 
19241da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
19251da177e4SLinus Torvalds 		mix->send_volume[0][0] = mix->send_volume[0][1] =
19261da177e4SLinus Torvalds 		mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
19271da177e4SLinus Torvalds 
19281da177e4SLinus Torvalds 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
19291da177e4SLinus Torvalds 	}
19301da177e4SLinus Torvalds 
19311da177e4SLinus Torvalds 	/* initialize the routing and volume table for the multichannel playback stream */
19321da177e4SLinus Torvalds 	for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
1933eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
19341da177e4SLinus Torvalds 		int v;
19351da177e4SLinus Torvalds 
19361da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[pcm];
19371da177e4SLinus Torvalds 		mix->epcm = NULL;
19381da177e4SLinus Torvalds 
19391da177e4SLinus Torvalds 		mix->send_routing[0][0] = pcm;
19401da177e4SLinus Torvalds 		mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
19411da177e4SLinus Torvalds 		for (v = 0; v < 2; v++)
19421da177e4SLinus Torvalds 			mix->send_routing[0][2+v] = 13+v;
19431da177e4SLinus Torvalds 		if (emu->audigy)
19441da177e4SLinus Torvalds 			for (v = 0; v < 4; v++)
19451da177e4SLinus Torvalds 				mix->send_routing[0][4+v] = 60+v;
19461da177e4SLinus Torvalds 
19471da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
19481da177e4SLinus Torvalds 		mix->send_volume[0][0]  = 255;
19491da177e4SLinus Torvalds 
19501da177e4SLinus Torvalds 		mix->attn[0] = 0xffff;
19511da177e4SLinus Torvalds 	}
19521da177e4SLinus Torvalds 
19532b637da5SLee Revell 	if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
19541da177e4SLinus Torvalds 		/* sb live! and audigy */
19551da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
19561da177e4SLinus Torvalds 			return -ENOMEM;
19575549d549SClemens Ladisch 		if (!emu->audigy)
19585549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
19591da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
19601da177e4SLinus Torvalds 			return err;
19611da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
19621da177e4SLinus Torvalds 			return -ENOMEM;
19635549d549SClemens Ladisch 		if (!emu->audigy)
19645549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
19651da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
19661da177e4SLinus Torvalds 			return err;
19671da177e4SLinus Torvalds 	}
19681da177e4SLinus Torvalds 
1969190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
197019b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
197119b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
19721da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
19731da177e4SLinus Torvalds 			return -ENOMEM;
19741da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
19751da177e4SLinus Torvalds 			return err;
1976001f7589SJames Courtier-Dutton #if 0
19771da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
19781da177e4SLinus Torvalds 			return -ENOMEM;
19791da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
19801da177e4SLinus Torvalds 			return err;
1981001f7589SJames Courtier-Dutton #endif
19822b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
19831da177e4SLinus Torvalds 		/* sb live! */
19841da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
19851da177e4SLinus Torvalds 			return -ENOMEM;
19861da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
19871da177e4SLinus Torvalds 			return err;
19881da177e4SLinus Torvalds 	}
19892b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
19901da177e4SLinus Torvalds 		if ((err = snd_p16v_mixer(emu)))
19911da177e4SLinus Torvalds 			return err;
19921da177e4SLinus Torvalds 	}
19931da177e4SLinus Torvalds 
1994*1c02e366SCtirad Fertr 	if (emu->card_capabilities->emu_model == 3) {
1995*1c02e366SCtirad Fertr 		/* 1616(m) cardbus */
19969f4bd5ddSJames Courtier-Dutton 		int i;
19979f4bd5ddSJames Courtier-Dutton 
1998*1c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) {
1999*1c02e366SCtirad Fertr 			err = snd_ctl_add(card,
2000*1c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1616_output_enum_ctls[i],
2001*1c02e366SCtirad Fertr 					     emu));
20029f4bd5ddSJames Courtier-Dutton 			if (err < 0)
20039f4bd5ddSJames Courtier-Dutton 				return err;
20049f4bd5ddSJames Courtier-Dutton 		}
20059f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
2006*1c02e366SCtirad Fertr 			err = snd_ctl_add(card,
2007*1c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
2008*1c02e366SCtirad Fertr 					     emu));
2009*1c02e366SCtirad Fertr 			if (err < 0)
2010*1c02e366SCtirad Fertr 				return err;
2011*1c02e366SCtirad Fertr 		}
2012*1c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) {
2013*1c02e366SCtirad Fertr 			err = snd_ctl_add(card,
2014*1c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
2015*1c02e366SCtirad Fertr 			if (err < 0)
2016*1c02e366SCtirad Fertr 				return err;
2017*1c02e366SCtirad Fertr 		}
2018*1c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) {
2019*1c02e366SCtirad Fertr 			err = snd_ctl_add(card,
2020*1c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
2021*1c02e366SCtirad Fertr 			if (err < 0)
2022*1c02e366SCtirad Fertr 				return err;
2023*1c02e366SCtirad Fertr 		}
2024*1c02e366SCtirad Fertr 		err = snd_ctl_add(card,
2025*1c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
2026*1c02e366SCtirad Fertr 		if (err < 0)
2027*1c02e366SCtirad Fertr 			return err;
2028*1c02e366SCtirad Fertr 
2029*1c02e366SCtirad Fertr 	} else {
2030*1c02e366SCtirad Fertr 		/* all other e-mu cards for now */
2031*1c02e366SCtirad Fertr 		int i;
2032*1c02e366SCtirad Fertr 
2033*1c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
2034*1c02e366SCtirad Fertr 			err = snd_ctl_add(card,
2035*1c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_output_enum_ctls[i],
2036*1c02e366SCtirad Fertr 					     emu));
2037*1c02e366SCtirad Fertr 			if (err < 0)
2038*1c02e366SCtirad Fertr 				return err;
2039*1c02e366SCtirad Fertr 		}
2040*1c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
2041*1c02e366SCtirad Fertr 			err = snd_ctl_add(card,
2042*1c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
2043*1c02e366SCtirad Fertr 					     emu));
20449f4bd5ddSJames Courtier-Dutton 			if (err < 0)
20459f4bd5ddSJames Courtier-Dutton 				return err;
20469f4bd5ddSJames Courtier-Dutton 		}
20479148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
2048*1c02e366SCtirad Fertr 			err = snd_ctl_add(card,
2049*1c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
20509148cc50SJames Courtier-Dutton 			if (err < 0)
20519148cc50SJames Courtier-Dutton 				return err;
20529148cc50SJames Courtier-Dutton 		}
20539148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
2054*1c02e366SCtirad Fertr 			err = snd_ctl_add(card,
2055*1c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
20569148cc50SJames Courtier-Dutton 			if (err < 0)
20579148cc50SJames Courtier-Dutton 				return err;
20589148cc50SJames Courtier-Dutton 		}
2059*1c02e366SCtirad Fertr 		err = snd_ctl_add(card,
2060*1c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
2061b0dbdaeaSJames Courtier-Dutton 		if (err < 0)
2062b0dbdaeaSJames Courtier-Dutton 			return err;
20639f4bd5ddSJames Courtier-Dutton 	}
20649f4bd5ddSJames Courtier-Dutton 
2065184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2066184c1e2cSJames Courtier-Dutton 		int i;
2067184c1e2cSJames Courtier-Dutton 
2068184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2069184c1e2cSJames Courtier-Dutton 		if (err < 0)
2070184c1e2cSJames Courtier-Dutton 			return err;
2071184c1e2cSJames Courtier-Dutton 
2072184c1e2cSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
2073184c1e2cSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
2074184c1e2cSJames Courtier-Dutton 			if (err < 0)
2075184c1e2cSJames Courtier-Dutton 				return err;
2076184c1e2cSJames Courtier-Dutton 		}
2077184c1e2cSJames Courtier-Dutton 	}
2078184c1e2cSJames Courtier-Dutton 
20791da177e4SLinus Torvalds 	return 0;
20801da177e4SLinus Torvalds }
2081