xref: /linux/sound/pci/emu10k1/emumixer.c (revision 1541c66d3bb78c8a388025b074c75658c790b72f)
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  */
86*1541c66dSTakashi Iwai static const char * const 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 
1421c02e366SCtirad Fertr /* 1616(m) cardbus */
1431c02e366SCtirad Fertr 
144*1541c66dSTakashi Iwai static const char * const emu1616_src_texts[] = {
1451c02e366SCtirad Fertr 	"Silence",
1461c02e366SCtirad Fertr 	"Dock Mic A",
1471c02e366SCtirad Fertr 	"Dock Mic B",
1481c02e366SCtirad Fertr 	"Dock ADC1 Left",
1491c02e366SCtirad Fertr 	"Dock ADC1 Right",
1501c02e366SCtirad Fertr 	"Dock ADC2 Left",
1511c02e366SCtirad Fertr 	"Dock ADC2 Right",
1521c02e366SCtirad Fertr 	"Dock SPDIF Left",
1531c02e366SCtirad Fertr 	"Dock SPDIF Right",
1541c02e366SCtirad Fertr 	"ADAT 0",
1551c02e366SCtirad Fertr 	"ADAT 1",
1561c02e366SCtirad Fertr 	"ADAT 2",
1571c02e366SCtirad Fertr 	"ADAT 3",
1581c02e366SCtirad Fertr 	"ADAT 4",
1591c02e366SCtirad Fertr 	"ADAT 5",
1601c02e366SCtirad Fertr 	"ADAT 6",
1611c02e366SCtirad Fertr 	"ADAT 7",
1621c02e366SCtirad Fertr 	"DSP 0",
1631c02e366SCtirad Fertr 	"DSP 1",
1641c02e366SCtirad Fertr 	"DSP 2",
1651c02e366SCtirad Fertr 	"DSP 3",
1661c02e366SCtirad Fertr 	"DSP 4",
1671c02e366SCtirad Fertr 	"DSP 5",
1681c02e366SCtirad Fertr 	"DSP 6",
1691c02e366SCtirad Fertr 	"DSP 7",
1701c02e366SCtirad Fertr 	"DSP 8",
1711c02e366SCtirad Fertr 	"DSP 9",
1721c02e366SCtirad Fertr 	"DSP 10",
1731c02e366SCtirad Fertr 	"DSP 11",
1741c02e366SCtirad Fertr 	"DSP 12",
1751c02e366SCtirad Fertr 	"DSP 13",
1761c02e366SCtirad Fertr 	"DSP 14",
1771c02e366SCtirad Fertr 	"DSP 15",
1781c02e366SCtirad Fertr 	"DSP 16",
1791c02e366SCtirad Fertr 	"DSP 17",
1801c02e366SCtirad Fertr 	"DSP 18",
1811c02e366SCtirad Fertr 	"DSP 19",
1821c02e366SCtirad Fertr 	"DSP 20",
1831c02e366SCtirad Fertr 	"DSP 21",
1841c02e366SCtirad Fertr 	"DSP 22",
1851c02e366SCtirad Fertr 	"DSP 23",
1861c02e366SCtirad Fertr 	"DSP 24",
1871c02e366SCtirad Fertr 	"DSP 25",
1881c02e366SCtirad Fertr 	"DSP 26",
1891c02e366SCtirad Fertr 	"DSP 27",
1901c02e366SCtirad Fertr 	"DSP 28",
1911c02e366SCtirad Fertr 	"DSP 29",
1921c02e366SCtirad Fertr 	"DSP 30",
1931c02e366SCtirad Fertr 	"DSP 31",
1941c02e366SCtirad Fertr };
1951c02e366SCtirad Fertr 
1961c02e366SCtirad 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 
2561c02e366SCtirad Fertr /* 1616(m) cardbus */
2571c02e366SCtirad Fertr static unsigned int emu1616_src_regs[] = {
2581c02e366SCtirad Fertr 	EMU_SRC_SILENCE,
2591c02e366SCtirad Fertr 	EMU_SRC_DOCK_MIC_A1,
2601c02e366SCtirad Fertr 	EMU_SRC_DOCK_MIC_B1,
2611c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC1_LEFT1,
2621c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC1_RIGHT1,
2631c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC2_LEFT1,
2641c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC2_RIGHT1,
2651c02e366SCtirad Fertr 	EMU_SRC_MDOCK_SPDIF_LEFT1,
2661c02e366SCtirad Fertr 	EMU_SRC_MDOCK_SPDIF_RIGHT1,
2671c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT,
2681c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+1,
2691c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+2,
2701c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+3,
2711c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+4,
2721c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+5,
2731c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+6,
2741c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+7,
2751c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A,
2761c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+1,
2771c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+2,
2781c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+3,
2791c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+4,
2801c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+5,
2811c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+6,
2821c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+7,
2831c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+8,
2841c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+9,
2851c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xa,
2861c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xb,
2871c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xc,
2881c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xd,
2891c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xe,
2901c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xf,
2911c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B,
2921c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+1,
2931c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+2,
2941c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+3,
2951c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+4,
2961c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+5,
2971c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+6,
2981c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+7,
2991c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+8,
3001c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+9,
3011c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xa,
3021c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xb,
3031c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xc,
3041c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xd,
3051c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xe,
3061c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xf,
3071c02e366SCtirad Fertr };
3081c02e366SCtirad 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 
3401c02e366SCtirad Fertr /* 1616(m) cardbus */
3411c02e366SCtirad Fertr static unsigned int emu1616_output_dst[] = {
3421c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC1_LEFT1,
3431c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC1_RIGHT1,
3441c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC2_LEFT1,
3451c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC2_RIGHT1,
3461c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC3_LEFT1,
3471c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC3_RIGHT1,
3481c02e366SCtirad Fertr 	EMU_DST_MDOCK_SPDIF_LEFT1,
3491c02e366SCtirad Fertr 	EMU_DST_MDOCK_SPDIF_RIGHT1,
3501c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT,
3511c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+1,
3521c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+2,
3531c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+3,
3541c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+4,
3551c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+5,
3561c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+6,
3571c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+7,
3581c02e366SCtirad Fertr 	EMU_DST_MANA_DAC_LEFT,
3591c02e366SCtirad Fertr 	EMU_DST_MANA_DAC_RIGHT,
3601c02e366SCtirad Fertr };
3611c02e366SCtirad 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 
3921c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
3931c02e366SCtirad Fertr 						struct snd_ctl_elem_info *uinfo)
3949f4bd5ddSJames Courtier-Dutton {
3951c02e366SCtirad Fertr 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
3961c02e366SCtirad Fertr 
397*1541c66dSTakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
398*1541c66dSTakashi Iwai 		return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts);
399*1541c66dSTakashi Iwai 	else
400*1541c66dSTakashi Iwai 		return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts);
4019f4bd5ddSJames Courtier-Dutton }
4029f4bd5ddSJames Courtier-Dutton 
4039f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
4049f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4059f4bd5ddSJames Courtier-Dutton {
4069f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
40774415a36SJames Courtier-Dutton 	unsigned int channel;
4089f4bd5ddSJames Courtier-Dutton 
4099f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
41074415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
4111c02e366SCtirad Fertr 	if (channel >= 24 ||
4123839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4133839e4f1STakashi Iwai 	     channel >= 18))
41474415a36SJames Courtier-Dutton 		return -EINVAL;
4159f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
4169f4bd5ddSJames Courtier-Dutton 	return 0;
4179f4bd5ddSJames Courtier-Dutton }
4189f4bd5ddSJames Courtier-Dutton 
4199f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
4209f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4219f4bd5ddSJames Courtier-Dutton {
4229f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4239f4bd5ddSJames Courtier-Dutton 	unsigned int val;
42474415a36SJames Courtier-Dutton 	unsigned int channel;
4259f4bd5ddSJames Courtier-Dutton 
426aa299d01STakashi Iwai 	val = ucontrol->value.enumerated.item[0];
4271c02e366SCtirad Fertr 	if (val >= 53 ||
4283839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4293839e4f1STakashi Iwai 	     val >= 49))
430aa299d01STakashi Iwai 		return -EINVAL;
4319f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
43274415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
4331c02e366SCtirad Fertr 	if (channel >= 24 ||
4343839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4353839e4f1STakashi Iwai 	     channel >= 18))
43674415a36SJames Courtier-Dutton 		return -EINVAL;
4371c02e366SCtirad Fertr 	if (emu->emu1010.output_source[channel] == val)
4381c02e366SCtirad Fertr 		return 0;
439aa299d01STakashi Iwai 	emu->emu1010.output_source[channel] = val;
4403839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
4411c02e366SCtirad Fertr 		snd_emu1010_fpga_link_dst_src_write(emu,
4421c02e366SCtirad Fertr 			emu1616_output_dst[channel], emu1616_src_regs[val]);
4431c02e366SCtirad Fertr 	else
4449f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
4459f4bd5ddSJames Courtier-Dutton 			emu1010_output_dst[channel], emu1010_src_regs[val]);
4461c02e366SCtirad Fertr 	return 1;
4479f4bd5ddSJames Courtier-Dutton }
4489f4bd5ddSJames Courtier-Dutton 
4499f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
4509f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4519f4bd5ddSJames Courtier-Dutton {
4529f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
45374415a36SJames Courtier-Dutton 	unsigned int channel;
4549f4bd5ddSJames Courtier-Dutton 
4559f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
45674415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
45774415a36SJames Courtier-Dutton 	if (channel >= 22)
45874415a36SJames Courtier-Dutton 		return -EINVAL;
4599f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
4609f4bd5ddSJames Courtier-Dutton 	return 0;
4619f4bd5ddSJames Courtier-Dutton }
4629f4bd5ddSJames Courtier-Dutton 
4639f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
4649f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4659f4bd5ddSJames Courtier-Dutton {
4669f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4679f4bd5ddSJames Courtier-Dutton 	unsigned int val;
46874415a36SJames Courtier-Dutton 	unsigned int channel;
4699f4bd5ddSJames Courtier-Dutton 
470aa299d01STakashi Iwai 	val = ucontrol->value.enumerated.item[0];
4711c02e366SCtirad Fertr 	if (val >= 53 ||
4723839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4733839e4f1STakashi Iwai 	     val >= 49))
474aa299d01STakashi Iwai 		return -EINVAL;
4759f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
47674415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
47774415a36SJames Courtier-Dutton 	if (channel >= 22)
47874415a36SJames Courtier-Dutton 		return -EINVAL;
4791c02e366SCtirad Fertr 	if (emu->emu1010.input_source[channel] == val)
4801c02e366SCtirad Fertr 		return 0;
481aa299d01STakashi Iwai 	emu->emu1010.input_source[channel] = val;
4823839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
4831c02e366SCtirad Fertr 		snd_emu1010_fpga_link_dst_src_write(emu,
4841c02e366SCtirad Fertr 			emu1010_input_dst[channel], emu1616_src_regs[val]);
4851c02e366SCtirad Fertr 	else
4869f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
4879f4bd5ddSJames Courtier-Dutton 			emu1010_input_dst[channel], emu1010_src_regs[val]);
4881c02e366SCtirad Fertr 	return 1;
4899f4bd5ddSJames Courtier-Dutton }
4909f4bd5ddSJames Courtier-Dutton 
4919f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \
4929f4bd5ddSJames Courtier-Dutton {								\
4939f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
4949f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
4959f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
4969f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_output_source_get,			\
4979f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_output_source_put,			\
4989f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
4999f4bd5ddSJames Courtier-Dutton }
5009f4bd5ddSJames Courtier-Dutton 
501e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = {
5024c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
5034c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
5044c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
5054c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
5064c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
5074c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
5084c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6),
5094c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
5104c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
5114c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
5124c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
5134c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
5144c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
5154c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
5164c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
5174c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
5184c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
5194c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
5204c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
5214c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
5224c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
5234c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
5244c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
5254c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
5269f4bd5ddSJames Courtier-Dutton };
5279f4bd5ddSJames Courtier-Dutton 
5281c02e366SCtirad Fertr 
5291c02e366SCtirad Fertr /* 1616(m) cardbus */
530e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = {
5311c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
5321c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
5331c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
5341c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
5351c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
5361c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
5371c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6),
5381c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7),
5391c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8),
5401c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9),
5411c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa),
5421c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb),
5431c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc),
5441c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd),
5451c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe),
5461c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf),
5471c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10),
5481c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11),
5491c02e366SCtirad Fertr };
5501c02e366SCtirad Fertr 
5511c02e366SCtirad Fertr 
5529f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \
5539f4bd5ddSJames Courtier-Dutton {								\
5549f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
5559f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
5569f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
5579f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_input_source_get,			\
5589f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_input_source_put,			\
5599f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
5609f4bd5ddSJames Courtier-Dutton }
5619f4bd5ddSJames Courtier-Dutton 
562e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = {
5634c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
5644c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
5654c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
5664c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
5674c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
5684c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
5694c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
5704c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
5714c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
5724c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
5734c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
5744c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
5754c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
5764c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
5774c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
5784c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
5794c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
5804c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
5814c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
5824c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
5834c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
5844c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
5859148cc50SJames Courtier-Dutton };
5869148cc50SJames Courtier-Dutton 
5879148cc50SJames Courtier-Dutton 
5889148cc50SJames Courtier-Dutton 
589a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
5909148cc50SJames Courtier-Dutton 
5919148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5929148cc50SJames Courtier-Dutton {
5939148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
5949148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
5959148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
5969148cc50SJames Courtier-Dutton 	return 0;
5979148cc50SJames Courtier-Dutton }
5989148cc50SJames Courtier-Dutton 
5999148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(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 	unsigned int val, cache;
6049148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
6059148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
6069148cc50SJames Courtier-Dutton 	if (val == 1)
6079148cc50SJames Courtier-Dutton 		cache = cache | mask;
6089148cc50SJames Courtier-Dutton 	else
6099148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
6109148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
6119148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
6129148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
6139148cc50SJames Courtier-Dutton 	}
6149148cc50SJames Courtier-Dutton 
6159148cc50SJames Courtier-Dutton 	return 0;
6169148cc50SJames Courtier-Dutton }
6179148cc50SJames Courtier-Dutton 
6189148cc50SJames Courtier-Dutton 
6199148cc50SJames Courtier-Dutton 
6209148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \
6219148cc50SJames Courtier-Dutton {								\
6229148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
6239148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
6249148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_adc_pads_info,			\
6259148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_adc_pads_get,			\
6269148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_adc_pads_put,			\
6279148cc50SJames Courtier-Dutton 	.private_value = chid					\
6289148cc50SJames Courtier-Dutton }
6299148cc50SJames Courtier-Dutton 
630e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_emu1010_adc_pads[] = {
6319148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
6329148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
6339148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
6349148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
6359148cc50SJames Courtier-Dutton };
6369148cc50SJames Courtier-Dutton 
637a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
6389148cc50SJames Courtier-Dutton 
6399148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6409148cc50SJames Courtier-Dutton {
6419148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6429148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6439148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
6449148cc50SJames Courtier-Dutton 	return 0;
6459148cc50SJames Courtier-Dutton }
6469148cc50SJames Courtier-Dutton 
6479148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(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 	unsigned int val, cache;
6529148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
6539148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
6549148cc50SJames Courtier-Dutton 	if (val == 1)
6559148cc50SJames Courtier-Dutton 		cache = cache | mask;
6569148cc50SJames Courtier-Dutton 	else
6579148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
6589148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.dac_pads) {
6599148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
6609148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
6619148cc50SJames Courtier-Dutton 	}
6629148cc50SJames Courtier-Dutton 
6639148cc50SJames Courtier-Dutton 	return 0;
6649148cc50SJames Courtier-Dutton }
6659148cc50SJames Courtier-Dutton 
6669148cc50SJames Courtier-Dutton 
6679148cc50SJames Courtier-Dutton 
6689148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \
6699148cc50SJames Courtier-Dutton {								\
6709148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
6719148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
6729148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_dac_pads_info,			\
6739148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_dac_pads_get,			\
6749148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_dac_pads_put,			\
6759148cc50SJames Courtier-Dutton 	.private_value = chid					\
6769148cc50SJames Courtier-Dutton }
6779148cc50SJames Courtier-Dutton 
678e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_emu1010_dac_pads[] = {
6799148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
6809148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
6819148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
6829148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
6839148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
6849f4bd5ddSJames Courtier-Dutton };
6859f4bd5ddSJames Courtier-Dutton 
686b0dbdaeaSJames Courtier-Dutton 
687b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
688b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
689b0dbdaeaSJames Courtier-Dutton {
690*1541c66dSTakashi Iwai 	static const char * const texts[4] = {
691edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
692b0dbdaeaSJames Courtier-Dutton 	};
693b0dbdaeaSJames Courtier-Dutton 
694*1541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 4, texts);
695b0dbdaeaSJames Courtier-Dutton }
696b0dbdaeaSJames Courtier-Dutton 
697b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
698b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
699b0dbdaeaSJames Courtier-Dutton {
700b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
701b0dbdaeaSJames Courtier-Dutton 
702b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
703b0dbdaeaSJames Courtier-Dutton 	return 0;
704b0dbdaeaSJames Courtier-Dutton }
705b0dbdaeaSJames Courtier-Dutton 
706b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
707b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
708b0dbdaeaSJames Courtier-Dutton {
709b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
710b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
711b0dbdaeaSJames Courtier-Dutton 	int change = 0;
712b0dbdaeaSJames Courtier-Dutton 
713b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
71474415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 4; */
71574415a36SJames Courtier-Dutton 	if (val >= 4)
71674415a36SJames Courtier-Dutton 		return -EINVAL;
717b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
718b0dbdaeaSJames Courtier-Dutton 	if (change) {
719b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
720b0dbdaeaSJames Courtier-Dutton 		switch (val) {
721b0dbdaeaSJames Courtier-Dutton 		case 0:
722b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
723b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
724b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
725b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
726b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
727b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
728b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
729b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
730b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
731b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
732b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
733b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
734e40a0b2eSJames Courtier-Dutton 			msleep(10);
735b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
736b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
737b0dbdaeaSJames Courtier-Dutton 			break;
738b0dbdaeaSJames Courtier-Dutton 		case 1:
739b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
740b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
741b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
742b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
743b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
744b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
745b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
746b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
747b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
748b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
749b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
750b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
751e40a0b2eSJames Courtier-Dutton 			msleep(10);
752b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
753b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
754b0dbdaeaSJames Courtier-Dutton 			break;
755edec7bbbSJames Courtier-Dutton 
756edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
757edec7bbbSJames Courtier-Dutton 			/* Mute all */
758edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
759edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
760edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
761edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
762edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
763edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
764edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
765edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
766edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
767edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
768edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
769edec7bbbSJames Courtier-Dutton 			msleep(10);
770edec7bbbSJames Courtier-Dutton 			/* Unmute all */
771edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
772edec7bbbSJames Courtier-Dutton 			break;
773edec7bbbSJames Courtier-Dutton 
774edec7bbbSJames Courtier-Dutton 		case 3:
775edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
776edec7bbbSJames Courtier-Dutton 			/* Mute all */
777edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
778edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
779edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
780edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
781edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
782edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
783edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
784edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
785edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
786edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
787edec7bbbSJames Courtier-Dutton 			msleep(10);
788edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
789edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
790edec7bbbSJames Courtier-Dutton 
791edec7bbbSJames Courtier-Dutton 
792edec7bbbSJames Courtier-Dutton 			break;
793b0dbdaeaSJames Courtier-Dutton 		}
794b0dbdaeaSJames Courtier-Dutton 	}
795b0dbdaeaSJames Courtier-Dutton         return change;
796b0dbdaeaSJames Courtier-Dutton }
797b0dbdaeaSJames Courtier-Dutton 
798b0dbdaeaSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_internal_clock =
799b0dbdaeaSJames Courtier-Dutton {
800b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
801b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
802b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
803b0dbdaeaSJames Courtier-Dutton 	.count =	1,
804b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
805b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
806b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
807b0dbdaeaSJames Courtier-Dutton };
808b0dbdaeaSJames Courtier-Dutton 
809184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
810184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
811184c1e2cSJames Courtier-Dutton {
812184c1e2cSJames Courtier-Dutton #if 0
813*1541c66dSTakashi Iwai 	static const char * const texts[4] = {
814184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
815184c1e2cSJames Courtier-Dutton 	};
816184c1e2cSJames Courtier-Dutton #endif
817*1541c66dSTakashi Iwai 	static const char * const texts[2] = {
818184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
819184c1e2cSJames Courtier-Dutton 	};
820184c1e2cSJames Courtier-Dutton 
821*1541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
822184c1e2cSJames Courtier-Dutton }
823184c1e2cSJames Courtier-Dutton 
824184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
825184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
826184c1e2cSJames Courtier-Dutton {
827184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
828184c1e2cSJames Courtier-Dutton 
829184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
830184c1e2cSJames Courtier-Dutton 	return 0;
831184c1e2cSJames Courtier-Dutton }
832184c1e2cSJames Courtier-Dutton 
833184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
834184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
835184c1e2cSJames Courtier-Dutton {
836184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
837184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
838184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
839184c1e2cSJames Courtier-Dutton 	u32 gpio;
840184c1e2cSJames Courtier-Dutton 	int change = 0;
841184c1e2cSJames Courtier-Dutton 	unsigned long flags;
842184c1e2cSJames Courtier-Dutton 	u32 source;
843184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
844184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
845184c1e2cSJames Courtier-Dutton 	 * for the particular source.
846184c1e2cSJames Courtier-Dutton 	 */
84774415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
84874415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
84974415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
85074415a36SJames Courtier-Dutton 	if (source_id >= 2)
85174415a36SJames Courtier-Dutton 		return -EINVAL;
852184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
853184c1e2cSJames Courtier-Dutton 	if (change) {
854184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
855184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
856184c1e2cSJames Courtier-Dutton 		gpio = inl(emu->port + A_IOCFG);
857184c1e2cSJames Courtier-Dutton 		if (source_id==0)
858184c1e2cSJames Courtier-Dutton 			outl(gpio | 0x4, emu->port + A_IOCFG);
859184c1e2cSJames Courtier-Dutton 		else
860184c1e2cSJames Courtier-Dutton 			outl(gpio & ~0x4, emu->port + A_IOCFG);
861184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
862184c1e2cSJames Courtier-Dutton 
863184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
864184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
865184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
866184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
867184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
868184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
869184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
870184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
871184c1e2cSJames Courtier-Dutton 
872184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
873184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
874184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
875184c1e2cSJames Courtier-Dutton 	}
876184c1e2cSJames Courtier-Dutton         return change;
877184c1e2cSJames Courtier-Dutton }
878184c1e2cSJames Courtier-Dutton 
879184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_capture_source =
880184c1e2cSJames Courtier-Dutton {
881184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
882184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
883184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
884184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
885184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
886184c1e2cSJames Courtier-Dutton };
887184c1e2cSJames Courtier-Dutton 
888184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
889184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
890184c1e2cSJames Courtier-Dutton {
891184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
892184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
893184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
894184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
895184c1e2cSJames Courtier-Dutton 	return 0;
896184c1e2cSJames Courtier-Dutton }
897184c1e2cSJames Courtier-Dutton 
898184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
899184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
900184c1e2cSJames Courtier-Dutton {
901184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
90274415a36SJames Courtier-Dutton 	unsigned int source_id;
903184c1e2cSJames Courtier-Dutton 
904184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
90574415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
90674415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
90774415a36SJames Courtier-Dutton 	if (source_id >= 2)
90874415a36SJames Courtier-Dutton 		return -EINVAL;
909184c1e2cSJames Courtier-Dutton 
910184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
911184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
912184c1e2cSJames Courtier-Dutton 	return 0;
913184c1e2cSJames Courtier-Dutton }
914184c1e2cSJames Courtier-Dutton 
915184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
916184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
917184c1e2cSJames Courtier-Dutton {
918184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
919184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
920184c1e2cSJames Courtier-Dutton 	unsigned int ngain;
92174415a36SJames Courtier-Dutton 	unsigned int source_id;
922184c1e2cSJames Courtier-Dutton 	int change = 0;
923184c1e2cSJames Courtier-Dutton 
924184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
92574415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
92674415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
92774415a36SJames Courtier-Dutton 	if (source_id >= 2)
92874415a36SJames Courtier-Dutton 		return -EINVAL;
929184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
930184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[0];
931184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
932184c1e2cSJames Courtier-Dutton 		return 0;
933184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
934184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
935184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
93674415a36SJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][0] = ngain;
937184c1e2cSJames Courtier-Dutton 		change = 1;
938184c1e2cSJames Courtier-Dutton 	}
939184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
940184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[1];
941184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
942184c1e2cSJames Courtier-Dutton 		return 0;
943184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
944184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
945184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
94674415a36SJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][1] = ngain;
947184c1e2cSJames Courtier-Dutton 		change = 1;
948184c1e2cSJames Courtier-Dutton 	}
949184c1e2cSJames Courtier-Dutton 
950184c1e2cSJames Courtier-Dutton 	return change;
951184c1e2cSJames Courtier-Dutton }
952184c1e2cSJames Courtier-Dutton 
953184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \
954184c1e2cSJames Courtier-Dutton {								\
955184c1e2cSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
956184c1e2cSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
957184c1e2cSJames Courtier-Dutton 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
958184c1e2cSJames Courtier-Dutton 	.info =  snd_audigy_i2c_volume_info,			\
959184c1e2cSJames Courtier-Dutton 	.get =   snd_audigy_i2c_volume_get,			\
960184c1e2cSJames Courtier-Dutton 	.put =   snd_audigy_i2c_volume_put,			\
961184c1e2cSJames Courtier-Dutton 	.tlv = { .p = snd_audigy_db_scale2 },			\
962184c1e2cSJames Courtier-Dutton 	.private_value = chid					\
963184c1e2cSJames Courtier-Dutton }
964184c1e2cSJames Courtier-Dutton 
965184c1e2cSJames Courtier-Dutton 
966e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = {
967184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Mic Capture Volume", 0),
968184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Line Capture Volume", 0)
969184c1e2cSJames Courtier-Dutton };
970184c1e2cSJames Courtier-Dutton 
9710af68e5eSTakashi Iwai #if 0
972eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9731da177e4SLinus Torvalds {
974*1541c66dSTakashi Iwai 	static const char * const texts[] = {"44100", "48000", "96000"};
9751da177e4SLinus Torvalds 
976*1541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 3, texts);
9771da177e4SLinus Torvalds }
9781da177e4SLinus Torvalds 
979eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
980eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
9811da177e4SLinus Torvalds {
982eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
9831da177e4SLinus Torvalds 	unsigned int tmp;
9841da177e4SLinus Torvalds 	unsigned long flags;
9851da177e4SLinus Torvalds 
9861da177e4SLinus Torvalds 
9871da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
9881da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
9891da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
9901da177e4SLinus Torvalds 	case A_SPDIF_44100:
9911da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
9921da177e4SLinus Torvalds 		break;
9931da177e4SLinus Torvalds 	case A_SPDIF_48000:
9941da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
9951da177e4SLinus Torvalds 		break;
9961da177e4SLinus Torvalds 	case A_SPDIF_96000:
9971da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
9981da177e4SLinus Torvalds 		break;
9991da177e4SLinus Torvalds 	default:
10001da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
10011da177e4SLinus Torvalds 	}
10021da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10031da177e4SLinus Torvalds 	return 0;
10041da177e4SLinus Torvalds }
10051da177e4SLinus Torvalds 
1006eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
1007eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10081da177e4SLinus Torvalds {
1009eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10101da177e4SLinus Torvalds 	int change;
10111da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
10121da177e4SLinus Torvalds 	unsigned long flags;
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
10151da177e4SLinus Torvalds 	case 0:
10161da177e4SLinus Torvalds 		val = A_SPDIF_44100;
10171da177e4SLinus Torvalds 		break;
10181da177e4SLinus Torvalds 	case 1:
10191da177e4SLinus Torvalds 		val = A_SPDIF_48000;
10201da177e4SLinus Torvalds 		break;
10211da177e4SLinus Torvalds 	case 2:
10221da177e4SLinus Torvalds 		val = A_SPDIF_96000;
10231da177e4SLinus Torvalds 		break;
10241da177e4SLinus Torvalds 	default:
10251da177e4SLinus Torvalds 		val = A_SPDIF_48000;
10261da177e4SLinus Torvalds 		break;
10271da177e4SLinus Torvalds 	}
10281da177e4SLinus Torvalds 
10291da177e4SLinus Torvalds 
10301da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10311da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
10321da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
10331da177e4SLinus Torvalds 	tmp |= val;
10341da177e4SLinus Torvalds 	if ((change = (tmp != reg)))
10351da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
10361da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10371da177e4SLinus Torvalds 	return change;
10381da177e4SLinus Torvalds }
10391da177e4SLinus Torvalds 
1040eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_spdif_output_rate =
10411da177e4SLinus Torvalds {
10421da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
10431da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
10441da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
10451da177e4SLinus Torvalds 	.count =	1,
10461da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
10471da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
10481da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
10491da177e4SLinus Torvalds };
10500af68e5eSTakashi Iwai #endif
10511da177e4SLinus Torvalds 
1052eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1053eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10541da177e4SLinus Torvalds {
1055eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10561da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
10571da177e4SLinus Torvalds 	int change;
10581da177e4SLinus Torvalds 	unsigned int val;
10591da177e4SLinus Torvalds 	unsigned long flags;
10601da177e4SLinus Torvalds 
106174415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
106274415a36SJames Courtier-Dutton 	if (idx >= 3)
106374415a36SJames Courtier-Dutton 		return -EINVAL;
10641da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
10651da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
10661da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
10671da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
10681da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10691da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
10701da177e4SLinus Torvalds 	if (change) {
10711da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
10721da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
10731da177e4SLinus Torvalds 	}
10741da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10751da177e4SLinus Torvalds 	return change;
10761da177e4SLinus Torvalds }
10771da177e4SLinus Torvalds 
1078eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
10791da177e4SLinus Torvalds {
10801da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
10815549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
10821da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
10837583cb51STakashi Iwai 	.count =	3,
10841da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
10851da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
10861da177e4SLinus Torvalds };
10871da177e4SLinus Torvalds 
1088eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_control =
10891da177e4SLinus Torvalds {
10905549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
10911da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
10927583cb51STakashi Iwai 	.count =	3,
10931da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
10941da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
10951da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
10961da177e4SLinus Torvalds };
10971da177e4SLinus Torvalds 
10981da177e4SLinus Torvalds 
1099eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
11001da177e4SLinus Torvalds {
11011da177e4SLinus Torvalds 	if (emu->audigy) {
11021da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
11031da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
11041da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
11051da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
11061da177e4SLinus Torvalds 	} else {
11071da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
11081da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
11091da177e4SLinus Torvalds 	}
11101da177e4SLinus Torvalds }
11111da177e4SLinus Torvalds 
1112eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
11131da177e4SLinus Torvalds {
11141da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
11151da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
11161da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
11171da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
11181da177e4SLinus Torvalds 	if (emu->audigy) {
11191da177e4SLinus Torvalds 		unsigned int val = ((unsigned int)volume[4] << 24) |
11201da177e4SLinus Torvalds 			((unsigned int)volume[5] << 16) |
11211da177e4SLinus Torvalds 			((unsigned int)volume[6] << 8) |
11221da177e4SLinus Torvalds 			(unsigned int)volume[7];
11231da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
11241da177e4SLinus Torvalds 	}
11251da177e4SLinus Torvalds }
11261da177e4SLinus Torvalds 
11271da177e4SLinus Torvalds /* PCM stream controls */
11281da177e4SLinus Torvalds 
1129eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11301da177e4SLinus Torvalds {
1131eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11321da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
11331da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
11341da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11351da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
11361da177e4SLinus Torvalds 	return 0;
11371da177e4SLinus Torvalds }
11381da177e4SLinus Torvalds 
1139eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1140eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11411da177e4SLinus Torvalds {
11421da177e4SLinus Torvalds 	unsigned long flags;
1143eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1144eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1145eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11461da177e4SLinus Torvalds 	int voice, idx;
11471da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11481da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11511da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
11521da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
11531da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
11541da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
11551da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11561da177e4SLinus Torvalds 	return 0;
11571da177e4SLinus Torvalds }
11581da177e4SLinus Torvalds 
1159eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1160eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11611da177e4SLinus Torvalds {
11621da177e4SLinus Torvalds 	unsigned long flags;
1163eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1164eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1165eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11661da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
11671da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11681da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11691da177e4SLinus Torvalds 
11701da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11711da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
11721da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
11731da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
11741da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
11751da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
11761da177e4SLinus Torvalds 				change = 1;
11771da177e4SLinus Torvalds 			}
11781da177e4SLinus Torvalds 		}
11791da177e4SLinus Torvalds 	if (change && mix->epcm) {
11801da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
11811da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
11821da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
11831da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
11841da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
11851da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
11861da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
11871da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
11881da177e4SLinus Torvalds 		}
11891da177e4SLinus Torvalds 	}
11901da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11911da177e4SLinus Torvalds 	return change;
11921da177e4SLinus Torvalds }
11931da177e4SLinus Torvalds 
1194eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_routing_control =
11951da177e4SLinus Torvalds {
11961da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
119767ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11981da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
11991da177e4SLinus Torvalds 	.count =	32,
12001da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
12011da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
12021da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
12031da177e4SLinus Torvalds };
12041da177e4SLinus Torvalds 
1205eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12061da177e4SLinus Torvalds {
1207eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12081da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12091da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
12101da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12111da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
12121da177e4SLinus Torvalds 	return 0;
12131da177e4SLinus Torvalds }
12141da177e4SLinus Torvalds 
1215eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1216eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12171da177e4SLinus Torvalds {
12181da177e4SLinus Torvalds 	unsigned long flags;
1219eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1220eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1221eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12221da177e4SLinus Torvalds 	int idx;
12231da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12241da177e4SLinus Torvalds 
12251da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12261da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
12271da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
12281da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12291da177e4SLinus Torvalds 	return 0;
12301da177e4SLinus Torvalds }
12311da177e4SLinus Torvalds 
1232eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1233eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12341da177e4SLinus Torvalds {
12351da177e4SLinus Torvalds 	unsigned long flags;
1236eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1237eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1238eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12391da177e4SLinus Torvalds 	int change = 0, idx, val;
12401da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12431da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
12441da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
12451da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
12461da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
12471da177e4SLinus Torvalds 			change = 1;
12481da177e4SLinus Torvalds 		}
12491da177e4SLinus Torvalds 	}
12501da177e4SLinus Torvalds 	if (change && mix->epcm) {
12511da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
12521da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
12531da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
12541da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
12551da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
12561da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
12571da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
12581da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
12591da177e4SLinus Torvalds 		}
12601da177e4SLinus Torvalds 	}
12611da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12621da177e4SLinus Torvalds 	return change;
12631da177e4SLinus Torvalds }
12641da177e4SLinus Torvalds 
1265eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_volume_control =
12661da177e4SLinus Torvalds {
12671da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
126867ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12691da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
12701da177e4SLinus Torvalds 	.count =	32,
12711da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
12721da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
12731da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
12741da177e4SLinus Torvalds };
12751da177e4SLinus Torvalds 
1276eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12771da177e4SLinus Torvalds {
12781da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12791da177e4SLinus Torvalds 	uinfo->count = 3;
12801da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12811da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
12821da177e4SLinus Torvalds 	return 0;
12831da177e4SLinus Torvalds }
12841da177e4SLinus Torvalds 
1285eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1286eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
12871da177e4SLinus Torvalds {
1288eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1289eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1290eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12911da177e4SLinus Torvalds 	unsigned long flags;
12921da177e4SLinus Torvalds 	int idx;
12931da177e4SLinus Torvalds 
12941da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12951da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
12961da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->attn[idx];
12971da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12981da177e4SLinus Torvalds 	return 0;
12991da177e4SLinus Torvalds }
13001da177e4SLinus Torvalds 
1301eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1302eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
13031da177e4SLinus Torvalds {
13041da177e4SLinus Torvalds 	unsigned long flags;
1305eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1306eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1307eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13081da177e4SLinus Torvalds 	int change = 0, idx, val;
13091da177e4SLinus Torvalds 
13101da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13111da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
13121da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 0xffff;
13131da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
13141da177e4SLinus Torvalds 			mix->attn[idx] = val;
13151da177e4SLinus Torvalds 			change = 1;
13161da177e4SLinus Torvalds 		}
13171da177e4SLinus Torvalds 	}
13181da177e4SLinus Torvalds 	if (change && mix->epcm) {
13191da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
13201da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
13211da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
13221da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
13231da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
13241da177e4SLinus Torvalds 		}
13251da177e4SLinus Torvalds 	}
13261da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13271da177e4SLinus Torvalds 	return change;
13281da177e4SLinus Torvalds }
13291da177e4SLinus Torvalds 
1330eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_attn_control =
13311da177e4SLinus Torvalds {
13321da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
133367ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13341da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
13351da177e4SLinus Torvalds 	.count =	32,
13361da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
13371da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
13381da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
13391da177e4SLinus Torvalds };
13401da177e4SLinus Torvalds 
13411da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
13421da177e4SLinus Torvalds 
1343eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13441da177e4SLinus Torvalds {
1345eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13461da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13471da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
13481da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13491da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
13501da177e4SLinus Torvalds 	return 0;
13511da177e4SLinus Torvalds }
13521da177e4SLinus Torvalds 
1353eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1354eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
13551da177e4SLinus Torvalds {
13561da177e4SLinus Torvalds 	unsigned long flags;
1357eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1358eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1359eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13601da177e4SLinus Torvalds 	int idx;
13611da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13621da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
13631da177e4SLinus Torvalds 
13641da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13651da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
13661da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
13671da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
13681da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13691da177e4SLinus Torvalds 	return 0;
13701da177e4SLinus Torvalds }
13711da177e4SLinus Torvalds 
1372eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1373eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
13741da177e4SLinus Torvalds {
13751da177e4SLinus Torvalds 	unsigned long flags;
1376eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13771da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1378eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
13791da177e4SLinus Torvalds 	int change = 0, idx, val;
13801da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13811da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
13821da177e4SLinus Torvalds 
13831da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13841da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
13851da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
13861da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
13871da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
13881da177e4SLinus Torvalds 			change = 1;
13891da177e4SLinus Torvalds 		}
13901da177e4SLinus Torvalds 	}
13911da177e4SLinus Torvalds 
13921da177e4SLinus Torvalds 	if (change && mix->epcm) {
13931da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
13941da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
13951da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
13961da177e4SLinus Torvalds 		}
13971da177e4SLinus Torvalds 	}
13981da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13991da177e4SLinus Torvalds 	return change;
14001da177e4SLinus Torvalds }
14011da177e4SLinus Torvalds 
1402eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
14031da177e4SLinus Torvalds {
14041da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
14051da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14061da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
14071da177e4SLinus Torvalds 	.count =	16,
14081da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
14091da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
14101da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
14111da177e4SLinus Torvalds };
14121da177e4SLinus Torvalds 
1413eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14141da177e4SLinus Torvalds {
1415eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14161da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14171da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
14181da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14191da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
14201da177e4SLinus Torvalds 	return 0;
14211da177e4SLinus Torvalds }
14221da177e4SLinus Torvalds 
1423eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1424eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
14251da177e4SLinus Torvalds {
14261da177e4SLinus Torvalds 	unsigned long flags;
1427eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1428eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1429eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14301da177e4SLinus Torvalds 	int idx;
14311da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14321da177e4SLinus Torvalds 
14331da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14341da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
14351da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
14361da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14371da177e4SLinus Torvalds 	return 0;
14381da177e4SLinus Torvalds }
14391da177e4SLinus Torvalds 
1440eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1441eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
14421da177e4SLinus Torvalds {
14431da177e4SLinus Torvalds 	unsigned long flags;
1444eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14451da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1446eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
14471da177e4SLinus Torvalds 	int change = 0, idx, val;
14481da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14491da177e4SLinus Torvalds 
14501da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14511da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
14521da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
14531da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
14541da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
14551da177e4SLinus Torvalds 			change = 1;
14561da177e4SLinus Torvalds 		}
14571da177e4SLinus Torvalds 	}
14581da177e4SLinus Torvalds 	if (change && mix->epcm) {
14591da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
14601da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
14611da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
14621da177e4SLinus Torvalds 		}
14631da177e4SLinus Torvalds 	}
14641da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14651da177e4SLinus Torvalds 	return change;
14661da177e4SLinus Torvalds }
14671da177e4SLinus Torvalds 
14681da177e4SLinus Torvalds 
1469eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
14701da177e4SLinus Torvalds {
14711da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
14721da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14731da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
14741da177e4SLinus Torvalds 	.count =	16,
14751da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
14761da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
14771da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
14781da177e4SLinus Torvalds };
14791da177e4SLinus Torvalds 
1480eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14811da177e4SLinus Torvalds {
14821da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14831da177e4SLinus Torvalds 	uinfo->count = 1;
14841da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14851da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
14861da177e4SLinus Torvalds 	return 0;
14871da177e4SLinus Torvalds }
14881da177e4SLinus Torvalds 
1489eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1490eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
14911da177e4SLinus Torvalds {
1492eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1493eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1494eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14951da177e4SLinus Torvalds 	unsigned long flags;
14961da177e4SLinus Torvalds 
14971da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14981da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = mix->attn[0];
14991da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15001da177e4SLinus Torvalds 	return 0;
15011da177e4SLinus Torvalds }
15021da177e4SLinus Torvalds 
1503eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1504eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
15051da177e4SLinus Torvalds {
15061da177e4SLinus Torvalds 	unsigned long flags;
1507eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15081da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1509eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
15101da177e4SLinus Torvalds 	int change = 0, val;
15111da177e4SLinus Torvalds 
15121da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15131da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] & 0xffff;
15141da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
15151da177e4SLinus Torvalds 		mix->attn[0] = val;
15161da177e4SLinus Torvalds 		change = 1;
15171da177e4SLinus Torvalds 	}
15181da177e4SLinus Torvalds 	if (change && mix->epcm) {
15191da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
15201da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
15211da177e4SLinus Torvalds 		}
15221da177e4SLinus Torvalds 	}
15231da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15241da177e4SLinus Torvalds 	return change;
15251da177e4SLinus Torvalds }
15261da177e4SLinus Torvalds 
1527eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
15281da177e4SLinus Torvalds {
15291da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15301da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15311da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
15321da177e4SLinus Torvalds 	.count =	16,
15331da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
15341da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
15351da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
15361da177e4SLinus Torvalds };
15371da177e4SLinus Torvalds 
1538a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
15391da177e4SLinus Torvalds 
1540eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1541eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
15421da177e4SLinus Torvalds {
1543eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15441da177e4SLinus Torvalds 
15451da177e4SLinus Torvalds 	if (emu->audigy)
15461da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
15471da177e4SLinus Torvalds 	else
15481da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1549d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1550d2cd74b1STakashi Iwai 		ucontrol->value.integer.value[0] =
1551d2cd74b1STakashi Iwai 			!ucontrol->value.integer.value[0];
1552d2cd74b1STakashi Iwai 
15531da177e4SLinus Torvalds 	return 0;
15541da177e4SLinus Torvalds }
15551da177e4SLinus Torvalds 
1556eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1557eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
15581da177e4SLinus Torvalds {
15591da177e4SLinus Torvalds 	unsigned long flags;
1560eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1561d2cd74b1STakashi Iwai 	unsigned int reg, val, sw;
15621da177e4SLinus Torvalds 	int change = 0;
15631da177e4SLinus Torvalds 
1564d2cd74b1STakashi Iwai 	sw = ucontrol->value.integer.value[0];
1565d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1566d2cd74b1STakashi Iwai 		sw = !sw;
15671da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1568184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1569184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1570184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
15711da177e4SLinus Torvalds 		reg = inl(emu->port + A_IOCFG);
1572d2cd74b1STakashi Iwai 		val = sw ? A_IOCFG_GPOUT0 : 0;
15731da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
15741da177e4SLinus Torvalds 		if (change) {
15751da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
15761da177e4SLinus Torvalds 			reg |= val;
15771da177e4SLinus Torvalds 			outl(reg | val, emu->port + A_IOCFG);
15781da177e4SLinus Torvalds 		}
15791da177e4SLinus Torvalds 	}
15801da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
1581d2cd74b1STakashi Iwai 	val = sw ? HCFG_GPOUT0 : 0;
15821da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
15831da177e4SLinus Torvalds 	if (change) {
15841da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
15851da177e4SLinus Torvalds 		reg |= val;
15861da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
15871da177e4SLinus Torvalds 	}
15881da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15891da177e4SLinus Torvalds 	return change;
15901da177e4SLinus Torvalds }
15911da177e4SLinus Torvalds 
1592e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_emu10k1_shared_spdif =
15931da177e4SLinus Torvalds {
15941da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
15951da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
15961da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
15971da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
15981da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
15991da177e4SLinus Torvalds };
16001da177e4SLinus Torvalds 
1601e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_audigy_shared_spdif =
16021da177e4SLinus Torvalds {
16031da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16041da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
16051da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
16061da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
16071da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
16081da177e4SLinus Torvalds };
16091da177e4SLinus Torvalds 
161016950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
161116950e09STakashi Iwai 
161216950e09STakashi Iwai #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
161316950e09STakashi Iwai 
161416950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
161516950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
161616950e09STakashi Iwai {
161716950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
161816950e09STakashi Iwai 	unsigned int val;
161916950e09STakashi Iwai 
162016950e09STakashi Iwai 	/* FIXME: better to use a cached version */
162116950e09STakashi Iwai 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
162216950e09STakashi Iwai 	ucontrol->value.integer.value[0] = !!val;
162316950e09STakashi Iwai 	return 0;
162416950e09STakashi Iwai }
162516950e09STakashi Iwai 
162616950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
162716950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
162816950e09STakashi Iwai {
162916950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
163016950e09STakashi Iwai 	unsigned int val;
163116950e09STakashi Iwai 
163216950e09STakashi Iwai 	if (ucontrol->value.integer.value[0])
163316950e09STakashi Iwai 		val = 0x0f0f;
163416950e09STakashi Iwai 	else
163516950e09STakashi Iwai 		val = 0;
163616950e09STakashi Iwai 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
163716950e09STakashi Iwai }
163816950e09STakashi Iwai 
1639e23e7a14SBill Pemberton static struct snd_kcontrol_new snd_audigy_capture_boost =
164016950e09STakashi Iwai {
164116950e09STakashi Iwai 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
164216950e09STakashi Iwai 	.name =		"Analog Capture Boost",
164316950e09STakashi Iwai 	.info =		snd_audigy_capture_boost_info,
164416950e09STakashi Iwai 	.get =		snd_audigy_capture_boost_get,
164516950e09STakashi Iwai 	.put =		snd_audigy_capture_boost_put
164616950e09STakashi Iwai };
164716950e09STakashi Iwai 
164816950e09STakashi Iwai 
16491da177e4SLinus Torvalds /*
16501da177e4SLinus Torvalds  */
1651eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
16521da177e4SLinus Torvalds {
1653eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
16541da177e4SLinus Torvalds 	emu->ac97 = NULL;
16551da177e4SLinus Torvalds }
16561da177e4SLinus Torvalds 
16571da177e4SLinus Torvalds /*
16581da177e4SLinus Torvalds  */
1659eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
16601da177e4SLinus Torvalds {
1661eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
16621da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
16631da177e4SLinus Torvalds 	strcpy(id.name, name);
16641da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
16651da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
16661da177e4SLinus Torvalds }
16671da177e4SLinus Torvalds 
1668eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
16691da177e4SLinus Torvalds {
1670eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
16711da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
16721da177e4SLinus Torvalds 	strcpy(sid.name, name);
16731da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
16741da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
16751da177e4SLinus Torvalds }
16761da177e4SLinus Torvalds 
1677eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
16781da177e4SLinus Torvalds {
1679eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
16801da177e4SLinus Torvalds 	if (kctl) {
16811da177e4SLinus Torvalds 		strcpy(kctl->id.name, dst);
16821da177e4SLinus Torvalds 		return 0;
16831da177e4SLinus Torvalds 	}
16841da177e4SLinus Torvalds 	return -ENOENT;
16851da177e4SLinus Torvalds }
16861da177e4SLinus Torvalds 
1687e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
168867ed4161SClemens Ladisch 		      int pcm_device, int multi_device)
16891da177e4SLinus Torvalds {
16901da177e4SLinus Torvalds 	int err, pcm;
1691eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1692eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
16931da177e4SLinus Torvalds 	char **c;
16941da177e4SLinus Torvalds 	static char *emu10k1_remove_ctls[] = {
16951da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
16961da177e4SLinus Torvalds 		"Master Mono Playback Switch",
16971da177e4SLinus Torvalds 		"Master Mono Playback Volume",
16981da177e4SLinus Torvalds 		"PCM Out Path & Mute",
16991da177e4SLinus Torvalds 		"Mono Output Select",
17001da177e4SLinus Torvalds 		"Surround Playback Switch",
17011da177e4SLinus Torvalds 		"Surround Playback Volume",
17021da177e4SLinus Torvalds 		"Center Playback Switch",
17031da177e4SLinus Torvalds 		"Center Playback Volume",
17041da177e4SLinus Torvalds 		"LFE Playback Switch",
17051da177e4SLinus Torvalds 		"LFE Playback Volume",
17061da177e4SLinus Torvalds 		NULL
17071da177e4SLinus Torvalds 	};
17081da177e4SLinus Torvalds 	static char *emu10k1_rename_ctls[] = {
17091da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
17101da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
17111da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
17121da177e4SLinus Torvalds 		NULL
17131da177e4SLinus Torvalds 	};
17141da177e4SLinus Torvalds 	static char *audigy_remove_ctls[] = {
17151da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
171621fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
171721fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
17181da177e4SLinus Torvalds 		"PCM Playback Switch",
17191da177e4SLinus Torvalds 		"PCM Playback Volume",
17201da177e4SLinus Torvalds 		"Master Mono Playback Switch",
17211da177e4SLinus Torvalds 		"Master Mono Playback Volume",
17221da177e4SLinus Torvalds 		"Master Playback Switch",
17231da177e4SLinus Torvalds 		"Master Playback Volume",
17241da177e4SLinus Torvalds 		"PCM Out Path & Mute",
17251da177e4SLinus Torvalds 		"Mono Output Select",
17261da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
17271da177e4SLinus Torvalds 		"Capture Source",
17281da177e4SLinus Torvalds 		"Capture Switch",
17291da177e4SLinus Torvalds 		"Capture Volume",
17301da177e4SLinus Torvalds 		"Mic Select",
17311da177e4SLinus Torvalds 		"Video Playback Switch",
17321da177e4SLinus Torvalds 		"Video Playback Volume",
17331da177e4SLinus Torvalds 		"Mic Playback Switch",
17341da177e4SLinus Torvalds 		"Mic Playback Volume",
17351da177e4SLinus Torvalds 		NULL
17361da177e4SLinus Torvalds 	};
17371da177e4SLinus Torvalds 	static char *audigy_rename_ctls[] = {
17381da177e4SLinus Torvalds 		/* use conventional names */
17391da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
17401da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
17411da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
17421da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
17431da177e4SLinus Torvalds 		NULL
17441da177e4SLinus Torvalds 	};
1745184c1e2cSJames Courtier-Dutton 	static char *audigy_rename_ctls_i2c_adc[] = {
1746184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1747184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1748184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1749184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1750184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1751eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1752184c1e2cSJames Courtier-Dutton 		NULL
1753184c1e2cSJames Courtier-Dutton 	};
1754184c1e2cSJames Courtier-Dutton 	static char *audigy_remove_ctls_i2c_adc[] = {
1755184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1756184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1757184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1758184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1759184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1760eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1761184c1e2cSJames Courtier-Dutton 		NULL
1762184c1e2cSJames Courtier-Dutton 	};
176321fdddeaSJames Courtier-Dutton 	static char *audigy_remove_ctls_1361t_adc[] = {
176421fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
176521fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
176621fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
176721fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
176821fdddeaSJames Courtier-Dutton 		"Master Mono Playback Switch",
176921fdddeaSJames Courtier-Dutton 		"Master Mono Playback Volume",
177021fdddeaSJames Courtier-Dutton 		"Capture Source",
177121fdddeaSJames Courtier-Dutton 		"Capture Switch",
177221fdddeaSJames Courtier-Dutton 		"Capture Volume",
177321fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
177421fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
177521fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
177621fdddeaSJames Courtier-Dutton 		"3D Control - Center",
177721fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
177821fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
177921fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
178021fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
178121fdddeaSJames Courtier-Dutton 		NULL
178221fdddeaSJames Courtier-Dutton 	};
178321fdddeaSJames Courtier-Dutton 	static char *audigy_rename_ctls_1361t_adc[] = {
178421fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
178521fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
178621fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1787d355c82aSJaroslav Kysela 		"Beep Playback Switch", "Beep Capture Switch",
1788d355c82aSJaroslav Kysela 		"Beep Playback Volume", "Beep Capture Volume",
178921fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
179021fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
179121fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
179221fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
179321fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
179421fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
179521fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
179621fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
179721fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
179821fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
179921fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
180021fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
180121fdddeaSJames Courtier-Dutton 
180221fdddeaSJames Courtier-Dutton 		NULL
180321fdddeaSJames Courtier-Dutton 	};
18041da177e4SLinus Torvalds 
18052b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1806eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1807eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
1808eb4698f3STakashi Iwai 		static struct snd_ac97_bus_ops ops = {
18091da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
18101da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
18111da177e4SLinus Torvalds 		};
18121da177e4SLinus Torvalds 
1813b1508693STakashi Iwai 		if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0)
18141da177e4SLinus Torvalds 			return err;
18151da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
18161da177e4SLinus Torvalds 
18171da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
18181da177e4SLinus Torvalds 		ac97.private_data = emu;
18191da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
18201da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
1821b1508693STakashi Iwai 		if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
1822b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
18231da177e4SLinus Torvalds 				return err;
18246f002b02STakashi Iwai 			dev_info(emu->card->dev,
18256f002b02STakashi Iwai 				 "AC97 is optional on this board\n");
18266f002b02STakashi Iwai 			dev_info(emu->card->dev,
18276f002b02STakashi Iwai 				 "Proceeding without ac97 mixers...\n");
1828b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1829b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1830b1508693STakashi Iwai 		}
18311da177e4SLinus Torvalds 		if (emu->audigy) {
18321da177e4SLinus Torvalds 			/* set master volume to 0 dB */
18334d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
18341da177e4SLinus Torvalds 			/* set capture source to mic */
18354d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
183621fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
183721fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
183821fdddeaSJames Courtier-Dutton 			else
18391da177e4SLinus Torvalds 				c = audigy_remove_ctls;
18401da177e4SLinus Torvalds 		} else {
18411da177e4SLinus Torvalds 			/*
18421da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
18431da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
18441da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
18451da177e4SLinus Torvalds 			 */
18461da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
18471da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
18481da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
18492594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
1850b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Volume");
1851b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Switch");
18521da177e4SLinus Torvalds 			}
18531da177e4SLinus Torvalds 			/* remove unused AC97 controls */
18544d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
18554d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
18561da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
18571da177e4SLinus Torvalds 		}
18581da177e4SLinus Torvalds 		for (; *c; c++)
18591da177e4SLinus Torvalds 			remove_ctl(card, *c);
1860184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1861184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1862184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1863184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
18641da177e4SLinus Torvalds 	} else {
1865f12aa40cSTakashi Iwai 	no_ac97:
18662b637da5SLee Revell 		if (emu->card_capabilities->ecard)
18671da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
18681da177e4SLinus Torvalds 		else if (emu->audigy)
18691da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
18701da177e4SLinus Torvalds 		else
18711da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
18721da177e4SLinus Torvalds 	}
18731da177e4SLinus Torvalds 
18741da177e4SLinus Torvalds 	if (emu->audigy)
187521fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
187621fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1877184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1878184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
187921fdddeaSJames Courtier-Dutton 		else
18801da177e4SLinus Torvalds 			c = audigy_rename_ctls;
18811da177e4SLinus Torvalds 	else
18821da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
18831da177e4SLinus Torvalds 	for (; *c; c += 2)
18841da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
188521fdddeaSJames Courtier-Dutton 
1886e217b960SRaymond Yau 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
1887e217b960SRaymond Yau 		remove_ctl(card, "Center Playback Volume");
1888e217b960SRaymond Yau 		remove_ctl(card, "LFE Playback Volume");
1889e217b960SRaymond Yau 		remove_ctl(card, "Wave Center Playback Volume");
1890e217b960SRaymond Yau 		remove_ctl(card, "Wave LFE Playback Volume");
1891e217b960SRaymond Yau 	}
1892e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1893e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1894e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1895e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1896e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1897e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Switch");
1898e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Volume");
1899e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Center");
1900e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Depth");
1901e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Switch");
1902e3b9bc0eSJames Courtier-Dutton 	}
19031da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
19041da177e4SLinus Torvalds 		return -ENOMEM;
190567ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
19061da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19071da177e4SLinus Torvalds 		return err;
19081da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
19091da177e4SLinus Torvalds 		return -ENOMEM;
191067ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
19111da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19121da177e4SLinus Torvalds 		return err;
19131da177e4SLinus Torvalds 	if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
19141da177e4SLinus Torvalds 		return -ENOMEM;
191567ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
19161da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19171da177e4SLinus Torvalds 		return err;
19181da177e4SLinus Torvalds 
19191da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
19201da177e4SLinus Torvalds 		return -ENOMEM;
192167ed4161SClemens Ladisch 	kctl->id.device = multi_device;
19221da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19231da177e4SLinus Torvalds 		return err;
19241da177e4SLinus Torvalds 
19251da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
19261da177e4SLinus Torvalds 		return -ENOMEM;
192767ed4161SClemens Ladisch 	kctl->id.device = multi_device;
19281da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19291da177e4SLinus Torvalds 		return err;
19301da177e4SLinus Torvalds 
19311da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
19321da177e4SLinus Torvalds 		return -ENOMEM;
193367ed4161SClemens Ladisch 	kctl->id.device = multi_device;
19341da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19351da177e4SLinus Torvalds 		return err;
19361da177e4SLinus Torvalds 
19371da177e4SLinus Torvalds 	/* initialize the routing and volume table for each pcm playback stream */
19381da177e4SLinus Torvalds 	for (pcm = 0; pcm < 32; pcm++) {
1939eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
19401da177e4SLinus Torvalds 		int v;
19411da177e4SLinus Torvalds 
19421da177e4SLinus Torvalds 		mix = &emu->pcm_mixer[pcm];
19431da177e4SLinus Torvalds 		mix->epcm = NULL;
19441da177e4SLinus Torvalds 
19451da177e4SLinus Torvalds 		for (v = 0; v < 4; v++)
19461da177e4SLinus Torvalds 			mix->send_routing[0][v] =
19471da177e4SLinus Torvalds 				mix->send_routing[1][v] =
19481da177e4SLinus Torvalds 				mix->send_routing[2][v] = v;
19491da177e4SLinus Torvalds 
19501da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
19511da177e4SLinus Torvalds 		mix->send_volume[0][0] = mix->send_volume[0][1] =
19521da177e4SLinus Torvalds 		mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
19531da177e4SLinus Torvalds 
19541da177e4SLinus Torvalds 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
19551da177e4SLinus Torvalds 	}
19561da177e4SLinus Torvalds 
19571da177e4SLinus Torvalds 	/* initialize the routing and volume table for the multichannel playback stream */
19581da177e4SLinus Torvalds 	for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
1959eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
19601da177e4SLinus Torvalds 		int v;
19611da177e4SLinus Torvalds 
19621da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[pcm];
19631da177e4SLinus Torvalds 		mix->epcm = NULL;
19641da177e4SLinus Torvalds 
19651da177e4SLinus Torvalds 		mix->send_routing[0][0] = pcm;
19661da177e4SLinus Torvalds 		mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
19671da177e4SLinus Torvalds 		for (v = 0; v < 2; v++)
19681da177e4SLinus Torvalds 			mix->send_routing[0][2+v] = 13+v;
19691da177e4SLinus Torvalds 		if (emu->audigy)
19701da177e4SLinus Torvalds 			for (v = 0; v < 4; v++)
19711da177e4SLinus Torvalds 				mix->send_routing[0][4+v] = 60+v;
19721da177e4SLinus Torvalds 
19731da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
19741da177e4SLinus Torvalds 		mix->send_volume[0][0]  = 255;
19751da177e4SLinus Torvalds 
19761da177e4SLinus Torvalds 		mix->attn[0] = 0xffff;
19771da177e4SLinus Torvalds 	}
19781da177e4SLinus Torvalds 
19792b637da5SLee Revell 	if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
19801da177e4SLinus Torvalds 		/* sb live! and audigy */
19811da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
19821da177e4SLinus Torvalds 			return -ENOMEM;
19835549d549SClemens Ladisch 		if (!emu->audigy)
19845549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
19851da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
19861da177e4SLinus Torvalds 			return err;
19871da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
19881da177e4SLinus Torvalds 			return -ENOMEM;
19895549d549SClemens Ladisch 		if (!emu->audigy)
19905549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
19911da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
19921da177e4SLinus Torvalds 			return err;
19931da177e4SLinus Torvalds 	}
19941da177e4SLinus Torvalds 
1995190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
199619b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
199719b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
19981da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
19991da177e4SLinus Torvalds 			return -ENOMEM;
20001da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
20011da177e4SLinus Torvalds 			return err;
2002001f7589SJames Courtier-Dutton #if 0
20031da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
20041da177e4SLinus Torvalds 			return -ENOMEM;
20051da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
20061da177e4SLinus Torvalds 			return err;
2007001f7589SJames Courtier-Dutton #endif
20082b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
20091da177e4SLinus Torvalds 		/* sb live! */
20101da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
20111da177e4SLinus Torvalds 			return -ENOMEM;
20121da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
20131da177e4SLinus Torvalds 			return err;
20141da177e4SLinus Torvalds 	}
20152b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
20161da177e4SLinus Torvalds 		if ((err = snd_p16v_mixer(emu)))
20171da177e4SLinus Torvalds 			return err;
20181da177e4SLinus Torvalds 	}
20191da177e4SLinus Torvalds 
20203839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
20211c02e366SCtirad Fertr 		/* 1616(m) cardbus */
20229f4bd5ddSJames Courtier-Dutton 		int i;
20239f4bd5ddSJames Courtier-Dutton 
20241c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) {
20251c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20261c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1616_output_enum_ctls[i],
20271c02e366SCtirad Fertr 					     emu));
20289f4bd5ddSJames Courtier-Dutton 			if (err < 0)
20299f4bd5ddSJames Courtier-Dutton 				return err;
20309f4bd5ddSJames Courtier-Dutton 		}
20319f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
20321c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20331c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
20341c02e366SCtirad Fertr 					     emu));
20351c02e366SCtirad Fertr 			if (err < 0)
20361c02e366SCtirad Fertr 				return err;
20371c02e366SCtirad Fertr 		}
20381c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) {
20391c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20401c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
20411c02e366SCtirad Fertr 			if (err < 0)
20421c02e366SCtirad Fertr 				return err;
20431c02e366SCtirad Fertr 		}
20441c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) {
20451c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20461c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
20471c02e366SCtirad Fertr 			if (err < 0)
20481c02e366SCtirad Fertr 				return err;
20491c02e366SCtirad Fertr 		}
20501c02e366SCtirad Fertr 		err = snd_ctl_add(card,
20511c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
20521c02e366SCtirad Fertr 		if (err < 0)
20531c02e366SCtirad Fertr 			return err;
20541c02e366SCtirad Fertr 
205588aa1390STakashi Iwai 	} else if (emu->card_capabilities->emu_model) {
20561c02e366SCtirad Fertr 		/* all other e-mu cards for now */
20571c02e366SCtirad Fertr 		int i;
20581c02e366SCtirad Fertr 
20591c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
20601c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20611c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_output_enum_ctls[i],
20621c02e366SCtirad Fertr 					     emu));
20631c02e366SCtirad Fertr 			if (err < 0)
20641c02e366SCtirad Fertr 				return err;
20651c02e366SCtirad Fertr 		}
20661c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
20671c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20681c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
20691c02e366SCtirad Fertr 					     emu));
20709f4bd5ddSJames Courtier-Dutton 			if (err < 0)
20719f4bd5ddSJames Courtier-Dutton 				return err;
20729f4bd5ddSJames Courtier-Dutton 		}
20739148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
20741c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20751c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
20769148cc50SJames Courtier-Dutton 			if (err < 0)
20779148cc50SJames Courtier-Dutton 				return err;
20789148cc50SJames Courtier-Dutton 		}
20799148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
20801c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20811c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
20829148cc50SJames Courtier-Dutton 			if (err < 0)
20839148cc50SJames Courtier-Dutton 				return err;
20849148cc50SJames Courtier-Dutton 		}
20851c02e366SCtirad Fertr 		err = snd_ctl_add(card,
20861c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
2087b0dbdaeaSJames Courtier-Dutton 		if (err < 0)
2088b0dbdaeaSJames Courtier-Dutton 			return err;
20899f4bd5ddSJames Courtier-Dutton 	}
20909f4bd5ddSJames Courtier-Dutton 
2091184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2092184c1e2cSJames Courtier-Dutton 		int i;
2093184c1e2cSJames Courtier-Dutton 
2094184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2095184c1e2cSJames Courtier-Dutton 		if (err < 0)
2096184c1e2cSJames Courtier-Dutton 			return err;
2097184c1e2cSJames Courtier-Dutton 
2098184c1e2cSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
2099184c1e2cSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
2100184c1e2cSJames Courtier-Dutton 			if (err < 0)
2101184c1e2cSJames Courtier-Dutton 				return err;
2102184c1e2cSJames Courtier-Dutton 		}
2103184c1e2cSJames Courtier-Dutton 	}
2104184c1e2cSJames Courtier-Dutton 
210516950e09STakashi Iwai 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
210616950e09STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
210716950e09STakashi Iwai 						     emu));
210816950e09STakashi Iwai 		if (err < 0)
210916950e09STakashi Iwai 			return err;
211016950e09STakashi Iwai 	}
211116950e09STakashi Iwai 
21121da177e4SLinus Torvalds 	return 0;
21131da177e4SLinus Torvalds }
2114