xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision b6a48404088d91514b9e78c3237976a5aa87cb14)
11da177e4SLinus Torvalds /*
2c1017a4cSJaroslav Kysela  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
31da177e4SLinus Torvalds  *                   Takashi Iwai <tiwai@suse.de>
41da177e4SLinus Torvalds  *                   Creative Labs, Inc.
51da177e4SLinus Torvalds  *  Routines for control of EMU10K1 chips / mixer routines
61da177e4SLinus Torvalds  *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
71da177e4SLinus Torvalds  *
89f4bd5ddSJames Courtier-Dutton  *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
99f4bd5ddSJames Courtier-Dutton  *  	Added EMU 1010 support.
109f4bd5ddSJames Courtier-Dutton  *
111da177e4SLinus Torvalds  *  BUGS:
121da177e4SLinus Torvalds  *    --
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *  TODO:
151da177e4SLinus Torvalds  *    --
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *   This program is free software; you can redistribute it and/or modify
181da177e4SLinus Torvalds  *   it under the terms of the GNU General Public License as published by
191da177e4SLinus Torvalds  *   the Free Software Foundation; either version 2 of the License, or
201da177e4SLinus Torvalds  *   (at your option) any later version.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  *   This program is distributed in the hope that it will be useful,
231da177e4SLinus Torvalds  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
241da177e4SLinus Torvalds  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
251da177e4SLinus Torvalds  *   GNU General Public License for more details.
261da177e4SLinus Torvalds  *
271da177e4SLinus Torvalds  *   You should have received a copy of the GNU General Public License
281da177e4SLinus Torvalds  *   along with this program; if not, write to the Free Software
291da177e4SLinus Torvalds  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
301da177e4SLinus Torvalds  *
311da177e4SLinus Torvalds  */
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds #include <linux/time.h>
341da177e4SLinus Torvalds #include <linux/init.h>
351da177e4SLinus Torvalds #include <sound/core.h>
361da177e4SLinus Torvalds #include <sound/emu10k1.h>
37b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h>
38184c1e2cSJames Courtier-Dutton #include <sound/tlv.h>
39184c1e2cSJames Courtier-Dutton 
40184c1e2cSJames Courtier-Dutton #include "p17v.h"
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds #define AC97_ID_STAC9758	0x83847658
431da177e4SLinus Torvalds 
440cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
45184c1e2cSJames Courtier-Dutton 
46eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
471da177e4SLinus Torvalds {
481da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
491da177e4SLinus Torvalds 	uinfo->count = 1;
501da177e4SLinus Torvalds 	return 0;
511da177e4SLinus Torvalds }
521da177e4SLinus Torvalds 
53eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
54eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
551da177e4SLinus Torvalds {
56eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
571da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
581da177e4SLinus Torvalds 	unsigned long flags;
591da177e4SLinus Torvalds 
6074415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
6174415a36SJames Courtier-Dutton 	if (idx >= 3)
6274415a36SJames Courtier-Dutton 		return -EINVAL;
631da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
641da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
651da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
661da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
671da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
681da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
691da177e4SLinus Torvalds 	return 0;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
72eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
73eb4698f3STakashi Iwai 				      struct snd_ctl_elem_value *ucontrol)
741da177e4SLinus Torvalds {
751da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
761da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
771da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
781da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
791da177e4SLinus Torvalds 	return 0;
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds 
8213d45709SPavel Hofman /*
8313d45709SPavel Hofman  * Items labels in enum mixer controls assigning source data to
8413d45709SPavel Hofman  * each destination
8513d45709SPavel Hofman  */
869f4bd5ddSJames Courtier-Dutton static char *emu1010_src_texts[] = {
879f4bd5ddSJames Courtier-Dutton 	"Silence",
889f4bd5ddSJames Courtier-Dutton 	"Dock Mic A",
899f4bd5ddSJames Courtier-Dutton 	"Dock Mic B",
909f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Left",
919f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Right",
929f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Left",
939f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Right",
949f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Left",
959f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Right",
969f4bd5ddSJames Courtier-Dutton 	"0202 ADC Left",
979f4bd5ddSJames Courtier-Dutton 	"0202 ADC Right",
989f4bd5ddSJames Courtier-Dutton 	"0202 SPDIF Left",
999f4bd5ddSJames Courtier-Dutton 	"0202 SPDIF Right",
1009f4bd5ddSJames Courtier-Dutton 	"ADAT 0",
1019f4bd5ddSJames Courtier-Dutton 	"ADAT 1",
1029f4bd5ddSJames Courtier-Dutton 	"ADAT 2",
1039f4bd5ddSJames Courtier-Dutton 	"ADAT 3",
1049f4bd5ddSJames Courtier-Dutton 	"ADAT 4",
1059f4bd5ddSJames Courtier-Dutton 	"ADAT 5",
1069f4bd5ddSJames Courtier-Dutton 	"ADAT 6",
1079f4bd5ddSJames Courtier-Dutton 	"ADAT 7",
1089f4bd5ddSJames Courtier-Dutton 	"DSP 0",
1099f4bd5ddSJames Courtier-Dutton 	"DSP 1",
1109f4bd5ddSJames Courtier-Dutton 	"DSP 2",
1119f4bd5ddSJames Courtier-Dutton 	"DSP 3",
1129f4bd5ddSJames Courtier-Dutton 	"DSP 4",
1139f4bd5ddSJames Courtier-Dutton 	"DSP 5",
1149f4bd5ddSJames Courtier-Dutton 	"DSP 6",
1159f4bd5ddSJames Courtier-Dutton 	"DSP 7",
1169f4bd5ddSJames Courtier-Dutton 	"DSP 8",
1179f4bd5ddSJames Courtier-Dutton 	"DSP 9",
1189f4bd5ddSJames Courtier-Dutton 	"DSP 10",
1199f4bd5ddSJames Courtier-Dutton 	"DSP 11",
1209f4bd5ddSJames Courtier-Dutton 	"DSP 12",
1219f4bd5ddSJames Courtier-Dutton 	"DSP 13",
1229f4bd5ddSJames Courtier-Dutton 	"DSP 14",
1239f4bd5ddSJames Courtier-Dutton 	"DSP 15",
1249f4bd5ddSJames Courtier-Dutton 	"DSP 16",
1259f4bd5ddSJames Courtier-Dutton 	"DSP 17",
1269f4bd5ddSJames Courtier-Dutton 	"DSP 18",
1279f4bd5ddSJames Courtier-Dutton 	"DSP 19",
1289f4bd5ddSJames Courtier-Dutton 	"DSP 20",
1299f4bd5ddSJames Courtier-Dutton 	"DSP 21",
1309f4bd5ddSJames Courtier-Dutton 	"DSP 22",
1319f4bd5ddSJames Courtier-Dutton 	"DSP 23",
1329f4bd5ddSJames Courtier-Dutton 	"DSP 24",
1339f4bd5ddSJames Courtier-Dutton 	"DSP 25",
1349f4bd5ddSJames Courtier-Dutton 	"DSP 26",
1359f4bd5ddSJames Courtier-Dutton 	"DSP 27",
1369f4bd5ddSJames Courtier-Dutton 	"DSP 28",
1379f4bd5ddSJames Courtier-Dutton 	"DSP 29",
1389f4bd5ddSJames Courtier-Dutton 	"DSP 30",
1399f4bd5ddSJames Courtier-Dutton 	"DSP 31",
1409f4bd5ddSJames Courtier-Dutton };
1419f4bd5ddSJames Courtier-Dutton 
1421c02e366SCtirad Fertr /* 1616(m) cardbus */
1431c02e366SCtirad Fertr 
1441c02e366SCtirad Fertr static char *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 	char **items;
3971c02e366SCtirad Fertr 
3989f4bd5ddSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3999f4bd5ddSJames Courtier-Dutton 	uinfo->count = 1;
4003839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
4011c02e366SCtirad Fertr 		uinfo->value.enumerated.items = 49;
4021c02e366SCtirad Fertr 		items = emu1616_src_texts;
4031c02e366SCtirad Fertr 	} else {
4049f4bd5ddSJames Courtier-Dutton 		uinfo->value.enumerated.items = 53;
4051c02e366SCtirad Fertr 		items = emu1010_src_texts;
4061c02e366SCtirad Fertr 	}
4079f4bd5ddSJames Courtier-Dutton 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
4081c02e366SCtirad Fertr 		uinfo->value.enumerated.item =
4091c02e366SCtirad Fertr 			uinfo->value.enumerated.items - 1;
4101c02e366SCtirad Fertr 	strcpy(uinfo->value.enumerated.name,
4111c02e366SCtirad Fertr 	       items[uinfo->value.enumerated.item]);
4129f4bd5ddSJames Courtier-Dutton 	return 0;
4139f4bd5ddSJames Courtier-Dutton }
4149f4bd5ddSJames Courtier-Dutton 
4159f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
4169f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4179f4bd5ddSJames Courtier-Dutton {
4189f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
41974415a36SJames Courtier-Dutton 	unsigned int channel;
4209f4bd5ddSJames Courtier-Dutton 
4219f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
42274415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
4231c02e366SCtirad Fertr 	if (channel >= 24 ||
4243839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4253839e4f1STakashi Iwai 	     channel >= 18))
42674415a36SJames Courtier-Dutton 		return -EINVAL;
4279f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
4289f4bd5ddSJames Courtier-Dutton 	return 0;
4299f4bd5ddSJames Courtier-Dutton }
4309f4bd5ddSJames Courtier-Dutton 
4319f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
4329f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4339f4bd5ddSJames Courtier-Dutton {
4349f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4359f4bd5ddSJames Courtier-Dutton 	unsigned int val;
43674415a36SJames Courtier-Dutton 	unsigned int channel;
4379f4bd5ddSJames Courtier-Dutton 
438aa299d01STakashi Iwai 	val = ucontrol->value.enumerated.item[0];
4391c02e366SCtirad Fertr 	if (val >= 53 ||
4403839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4413839e4f1STakashi Iwai 	     val >= 49))
442aa299d01STakashi Iwai 		return -EINVAL;
4439f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
44474415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
4451c02e366SCtirad Fertr 	if (channel >= 24 ||
4463839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4473839e4f1STakashi Iwai 	     channel >= 18))
44874415a36SJames Courtier-Dutton 		return -EINVAL;
4491c02e366SCtirad Fertr 	if (emu->emu1010.output_source[channel] == val)
4501c02e366SCtirad Fertr 		return 0;
451aa299d01STakashi Iwai 	emu->emu1010.output_source[channel] = val;
4523839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
4531c02e366SCtirad Fertr 		snd_emu1010_fpga_link_dst_src_write(emu,
4541c02e366SCtirad Fertr 			emu1616_output_dst[channel], emu1616_src_regs[val]);
4551c02e366SCtirad Fertr 	else
4569f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
4579f4bd5ddSJames Courtier-Dutton 			emu1010_output_dst[channel], emu1010_src_regs[val]);
4581c02e366SCtirad Fertr 	return 1;
4599f4bd5ddSJames Courtier-Dutton }
4609f4bd5ddSJames Courtier-Dutton 
4619f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
4629f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4639f4bd5ddSJames Courtier-Dutton {
4649f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
46574415a36SJames Courtier-Dutton 	unsigned int channel;
4669f4bd5ddSJames Courtier-Dutton 
4679f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
46874415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
46974415a36SJames Courtier-Dutton 	if (channel >= 22)
47074415a36SJames Courtier-Dutton 		return -EINVAL;
4719f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
4729f4bd5ddSJames Courtier-Dutton 	return 0;
4739f4bd5ddSJames Courtier-Dutton }
4749f4bd5ddSJames Courtier-Dutton 
4759f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
4769f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4779f4bd5ddSJames Courtier-Dutton {
4789f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4799f4bd5ddSJames Courtier-Dutton 	unsigned int val;
48074415a36SJames Courtier-Dutton 	unsigned int channel;
4819f4bd5ddSJames Courtier-Dutton 
482aa299d01STakashi Iwai 	val = ucontrol->value.enumerated.item[0];
4831c02e366SCtirad Fertr 	if (val >= 53 ||
4843839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4853839e4f1STakashi Iwai 	     val >= 49))
486aa299d01STakashi Iwai 		return -EINVAL;
4879f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
48874415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
48974415a36SJames Courtier-Dutton 	if (channel >= 22)
49074415a36SJames Courtier-Dutton 		return -EINVAL;
4911c02e366SCtirad Fertr 	if (emu->emu1010.input_source[channel] == val)
4921c02e366SCtirad Fertr 		return 0;
493aa299d01STakashi Iwai 	emu->emu1010.input_source[channel] = val;
4943839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
4951c02e366SCtirad Fertr 		snd_emu1010_fpga_link_dst_src_write(emu,
4961c02e366SCtirad Fertr 			emu1010_input_dst[channel], emu1616_src_regs[val]);
4971c02e366SCtirad Fertr 	else
4989f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
4999f4bd5ddSJames Courtier-Dutton 			emu1010_input_dst[channel], emu1010_src_regs[val]);
5001c02e366SCtirad Fertr 	return 1;
5019f4bd5ddSJames Courtier-Dutton }
5029f4bd5ddSJames Courtier-Dutton 
5039f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \
5049f4bd5ddSJames Courtier-Dutton {								\
5059f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
5069f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
5079f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
5089f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_output_source_get,			\
5099f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_output_source_put,			\
5109f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
5119f4bd5ddSJames Courtier-Dutton }
5129f4bd5ddSJames Courtier-Dutton 
5139f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = {
5144c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
5154c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
5164c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
5174c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
5184c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
5194c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
5204c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6),
5214c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
5224c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
5234c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
5244c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
5254c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
5264c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
5274c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
5284c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
5294c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
5304c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
5314c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
5324c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
5334c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
5344c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
5354c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
5364c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
5374c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
5389f4bd5ddSJames Courtier-Dutton };
5399f4bd5ddSJames Courtier-Dutton 
5401c02e366SCtirad Fertr 
5411c02e366SCtirad Fertr /* 1616(m) cardbus */
5421c02e366SCtirad Fertr static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] __devinitdata = {
5431c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
5441c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
5451c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
5461c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
5471c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
5481c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
5491c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6),
5501c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7),
5511c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8),
5521c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9),
5531c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa),
5541c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb),
5551c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc),
5561c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd),
5571c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe),
5581c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf),
5591c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10),
5601c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11),
5611c02e366SCtirad Fertr };
5621c02e366SCtirad Fertr 
5631c02e366SCtirad Fertr 
5649f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \
5659f4bd5ddSJames Courtier-Dutton {								\
5669f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
5679f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
5689f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
5699f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_input_source_get,			\
5709f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_input_source_put,			\
5719f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
5729f4bd5ddSJames Courtier-Dutton }
5739f4bd5ddSJames Courtier-Dutton 
5749f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = {
5754c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
5764c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
5774c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
5784c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
5794c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
5804c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
5814c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
5824c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
5834c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
5844c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
5854c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
5864c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
5874c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
5884c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
5894c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
5904c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
5914c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
5924c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
5934c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
5944c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
5954c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
5964c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
5979148cc50SJames Courtier-Dutton };
5989148cc50SJames Courtier-Dutton 
5999148cc50SJames Courtier-Dutton 
6009148cc50SJames Courtier-Dutton 
601a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
6029148cc50SJames Courtier-Dutton 
6039148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6049148cc50SJames Courtier-Dutton {
6059148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6069148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6079148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
6089148cc50SJames Courtier-Dutton 	return 0;
6099148cc50SJames Courtier-Dutton }
6109148cc50SJames Courtier-Dutton 
6119148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6129148cc50SJames Courtier-Dutton {
6139148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6149148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6159148cc50SJames Courtier-Dutton 	unsigned int val, cache;
6169148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
6179148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
6189148cc50SJames Courtier-Dutton 	if (val == 1)
6199148cc50SJames Courtier-Dutton 		cache = cache | mask;
6209148cc50SJames Courtier-Dutton 	else
6219148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
6229148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
6239148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
6249148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
6259148cc50SJames Courtier-Dutton 	}
6269148cc50SJames Courtier-Dutton 
6279148cc50SJames Courtier-Dutton 	return 0;
6289148cc50SJames Courtier-Dutton }
6299148cc50SJames Courtier-Dutton 
6309148cc50SJames Courtier-Dutton 
6319148cc50SJames Courtier-Dutton 
6329148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \
6339148cc50SJames Courtier-Dutton {								\
6349148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
6359148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
6369148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_adc_pads_info,			\
6379148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_adc_pads_get,			\
6389148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_adc_pads_put,			\
6399148cc50SJames Courtier-Dutton 	.private_value = chid					\
6409148cc50SJames Courtier-Dutton }
6419148cc50SJames Courtier-Dutton 
6429148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = {
6439148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
6449148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
6459148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
6469148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
6479148cc50SJames Courtier-Dutton };
6489148cc50SJames Courtier-Dutton 
649a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
6509148cc50SJames Courtier-Dutton 
6519148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6529148cc50SJames Courtier-Dutton {
6539148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6549148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6559148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
6569148cc50SJames Courtier-Dutton 	return 0;
6579148cc50SJames Courtier-Dutton }
6589148cc50SJames Courtier-Dutton 
6599148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6609148cc50SJames Courtier-Dutton {
6619148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6629148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6639148cc50SJames Courtier-Dutton 	unsigned int val, cache;
6649148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
6659148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
6669148cc50SJames Courtier-Dutton 	if (val == 1)
6679148cc50SJames Courtier-Dutton 		cache = cache | mask;
6689148cc50SJames Courtier-Dutton 	else
6699148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
6709148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.dac_pads) {
6719148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
6729148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
6739148cc50SJames Courtier-Dutton 	}
6749148cc50SJames Courtier-Dutton 
6759148cc50SJames Courtier-Dutton 	return 0;
6769148cc50SJames Courtier-Dutton }
6779148cc50SJames Courtier-Dutton 
6789148cc50SJames Courtier-Dutton 
6799148cc50SJames Courtier-Dutton 
6809148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \
6819148cc50SJames Courtier-Dutton {								\
6829148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
6839148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
6849148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_dac_pads_info,			\
6859148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_dac_pads_get,			\
6869148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_dac_pads_put,			\
6879148cc50SJames Courtier-Dutton 	.private_value = chid					\
6889148cc50SJames Courtier-Dutton }
6899148cc50SJames Courtier-Dutton 
6909148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = {
6919148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
6929148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
6939148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
6949148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
6959148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
6969f4bd5ddSJames Courtier-Dutton };
6979f4bd5ddSJames Courtier-Dutton 
698b0dbdaeaSJames Courtier-Dutton 
699b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
700b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
701b0dbdaeaSJames Courtier-Dutton {
702edec7bbbSJames Courtier-Dutton 	static char *texts[4] = {
703edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
704b0dbdaeaSJames Courtier-Dutton 	};
705b0dbdaeaSJames Courtier-Dutton 
706b0dbdaeaSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
707b0dbdaeaSJames Courtier-Dutton 	uinfo->count = 1;
708edec7bbbSJames Courtier-Dutton 	uinfo->value.enumerated.items = 4;
709edec7bbbSJames Courtier-Dutton 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
710edec7bbbSJames Courtier-Dutton 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
711b0dbdaeaSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
712b0dbdaeaSJames Courtier-Dutton 	return 0;
713edec7bbbSJames Courtier-Dutton 
714edec7bbbSJames Courtier-Dutton 
715b0dbdaeaSJames Courtier-Dutton }
716b0dbdaeaSJames Courtier-Dutton 
717b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
718b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
719b0dbdaeaSJames Courtier-Dutton {
720b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
721b0dbdaeaSJames Courtier-Dutton 
722b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
723b0dbdaeaSJames Courtier-Dutton 	return 0;
724b0dbdaeaSJames Courtier-Dutton }
725b0dbdaeaSJames Courtier-Dutton 
726b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
727b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
728b0dbdaeaSJames Courtier-Dutton {
729b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
730b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
731b0dbdaeaSJames Courtier-Dutton 	int change = 0;
732b0dbdaeaSJames Courtier-Dutton 
733b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
73474415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 4; */
73574415a36SJames Courtier-Dutton 	if (val >= 4)
73674415a36SJames Courtier-Dutton 		return -EINVAL;
737b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
738b0dbdaeaSJames Courtier-Dutton 	if (change) {
739b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
740b0dbdaeaSJames Courtier-Dutton 		switch (val) {
741b0dbdaeaSJames Courtier-Dutton 		case 0:
742b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
743b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
744b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
745b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
746b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
747b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
748b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
749b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
750b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
751b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
752b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
753b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
754e40a0b2eSJames Courtier-Dutton 			msleep(10);
755b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
756b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
757b0dbdaeaSJames Courtier-Dutton 			break;
758b0dbdaeaSJames Courtier-Dutton 		case 1:
759b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
760b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
761b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
762b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
763b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
764b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
765b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
766b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
767b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
768b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
769b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
770b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
771e40a0b2eSJames Courtier-Dutton 			msleep(10);
772b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
773b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
774b0dbdaeaSJames Courtier-Dutton 			break;
775edec7bbbSJames Courtier-Dutton 
776edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
777edec7bbbSJames Courtier-Dutton 			/* Mute all */
778edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
779edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
780edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
781edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
782edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
783edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
784edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
785edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
786edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
787edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
788edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
789edec7bbbSJames Courtier-Dutton 			msleep(10);
790edec7bbbSJames Courtier-Dutton 			/* Unmute all */
791edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
792edec7bbbSJames Courtier-Dutton 			break;
793edec7bbbSJames Courtier-Dutton 
794edec7bbbSJames Courtier-Dutton 		case 3:
795edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
796edec7bbbSJames Courtier-Dutton 			/* Mute all */
797edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
798edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
799edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
800edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
801edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
802edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
803edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
804edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
805edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
806edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
807edec7bbbSJames Courtier-Dutton 			msleep(10);
808edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
809edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
810edec7bbbSJames Courtier-Dutton 
811edec7bbbSJames Courtier-Dutton 
812edec7bbbSJames Courtier-Dutton 			break;
813b0dbdaeaSJames Courtier-Dutton 		}
814b0dbdaeaSJames Courtier-Dutton 	}
815b0dbdaeaSJames Courtier-Dutton         return change;
816b0dbdaeaSJames Courtier-Dutton }
817b0dbdaeaSJames Courtier-Dutton 
818b0dbdaeaSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_internal_clock =
819b0dbdaeaSJames Courtier-Dutton {
820b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
821b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
822b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
823b0dbdaeaSJames Courtier-Dutton 	.count =	1,
824b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
825b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
826b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
827b0dbdaeaSJames Courtier-Dutton };
828b0dbdaeaSJames Courtier-Dutton 
829184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
830184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
831184c1e2cSJames Courtier-Dutton {
832184c1e2cSJames Courtier-Dutton #if 0
833184c1e2cSJames Courtier-Dutton 	static char *texts[4] = {
834184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
835184c1e2cSJames Courtier-Dutton 	};
836184c1e2cSJames Courtier-Dutton #endif
837184c1e2cSJames Courtier-Dutton 	static char *texts[2] = {
838184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
839184c1e2cSJames Courtier-Dutton 	};
840184c1e2cSJames Courtier-Dutton 
841184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
842184c1e2cSJames Courtier-Dutton 	uinfo->count = 1;
843184c1e2cSJames Courtier-Dutton 	uinfo->value.enumerated.items = 2;
844184c1e2cSJames Courtier-Dutton 	if (uinfo->value.enumerated.item > 1)
845184c1e2cSJames Courtier-Dutton                 uinfo->value.enumerated.item = 1;
846184c1e2cSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
847184c1e2cSJames Courtier-Dutton 	return 0;
848184c1e2cSJames Courtier-Dutton }
849184c1e2cSJames Courtier-Dutton 
850184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
851184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
852184c1e2cSJames Courtier-Dutton {
853184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
854184c1e2cSJames Courtier-Dutton 
855184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
856184c1e2cSJames Courtier-Dutton 	return 0;
857184c1e2cSJames Courtier-Dutton }
858184c1e2cSJames Courtier-Dutton 
859184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
860184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
861184c1e2cSJames Courtier-Dutton {
862184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
863184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
864184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
865184c1e2cSJames Courtier-Dutton 	u32 gpio;
866184c1e2cSJames Courtier-Dutton 	int change = 0;
867184c1e2cSJames Courtier-Dutton 	unsigned long flags;
868184c1e2cSJames Courtier-Dutton 	u32 source;
869184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
870184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
871184c1e2cSJames Courtier-Dutton 	 * for the particular source.
872184c1e2cSJames Courtier-Dutton 	 */
87374415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
87474415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
87574415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
87674415a36SJames Courtier-Dutton 	if (source_id >= 2)
87774415a36SJames Courtier-Dutton 		return -EINVAL;
878184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
879184c1e2cSJames Courtier-Dutton 	if (change) {
880184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
881184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
882184c1e2cSJames Courtier-Dutton 		gpio = inl(emu->port + A_IOCFG);
883184c1e2cSJames Courtier-Dutton 		if (source_id==0)
884184c1e2cSJames Courtier-Dutton 			outl(gpio | 0x4, emu->port + A_IOCFG);
885184c1e2cSJames Courtier-Dutton 		else
886184c1e2cSJames Courtier-Dutton 			outl(gpio & ~0x4, emu->port + A_IOCFG);
887184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
888184c1e2cSJames Courtier-Dutton 
889184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
890184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
891184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
892184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
893184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
894184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
895184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
896184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
897184c1e2cSJames Courtier-Dutton 
898184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
899184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
900184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
901184c1e2cSJames Courtier-Dutton 	}
902184c1e2cSJames Courtier-Dutton         return change;
903184c1e2cSJames Courtier-Dutton }
904184c1e2cSJames Courtier-Dutton 
905184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_capture_source =
906184c1e2cSJames Courtier-Dutton {
907184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
908184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
909184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
910184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
911184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
912184c1e2cSJames Courtier-Dutton };
913184c1e2cSJames Courtier-Dutton 
914184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
915184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
916184c1e2cSJames Courtier-Dutton {
917184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
918184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
919184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
920184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
921184c1e2cSJames Courtier-Dutton 	return 0;
922184c1e2cSJames Courtier-Dutton }
923184c1e2cSJames Courtier-Dutton 
924184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
925184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
926184c1e2cSJames Courtier-Dutton {
927184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
92874415a36SJames Courtier-Dutton 	unsigned int source_id;
929184c1e2cSJames Courtier-Dutton 
930184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
93174415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
93274415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
93374415a36SJames Courtier-Dutton 	if (source_id >= 2)
93474415a36SJames Courtier-Dutton 		return -EINVAL;
935184c1e2cSJames Courtier-Dutton 
936184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
937184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
938184c1e2cSJames Courtier-Dutton 	return 0;
939184c1e2cSJames Courtier-Dutton }
940184c1e2cSJames Courtier-Dutton 
941184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
942184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
943184c1e2cSJames Courtier-Dutton {
944184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
945184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
946184c1e2cSJames Courtier-Dutton 	unsigned int ngain;
94774415a36SJames Courtier-Dutton 	unsigned int source_id;
948184c1e2cSJames Courtier-Dutton 	int change = 0;
949184c1e2cSJames Courtier-Dutton 
950184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
95174415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
95274415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
95374415a36SJames Courtier-Dutton 	if (source_id >= 2)
95474415a36SJames Courtier-Dutton 		return -EINVAL;
955184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
956184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[0];
957184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
958184c1e2cSJames Courtier-Dutton 		return 0;
959184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
960184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
961184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
96274415a36SJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][0] = ngain;
963184c1e2cSJames Courtier-Dutton 		change = 1;
964184c1e2cSJames Courtier-Dutton 	}
965184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
966184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[1];
967184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
968184c1e2cSJames Courtier-Dutton 		return 0;
969184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
970184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
971184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
97274415a36SJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][1] = ngain;
973184c1e2cSJames Courtier-Dutton 		change = 1;
974184c1e2cSJames Courtier-Dutton 	}
975184c1e2cSJames Courtier-Dutton 
976184c1e2cSJames Courtier-Dutton 	return change;
977184c1e2cSJames Courtier-Dutton }
978184c1e2cSJames Courtier-Dutton 
979184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \
980184c1e2cSJames Courtier-Dutton {								\
981184c1e2cSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
982184c1e2cSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
983184c1e2cSJames Courtier-Dutton 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
984184c1e2cSJames Courtier-Dutton 	.info =  snd_audigy_i2c_volume_info,			\
985184c1e2cSJames Courtier-Dutton 	.get =   snd_audigy_i2c_volume_get,			\
986184c1e2cSJames Courtier-Dutton 	.put =   snd_audigy_i2c_volume_put,			\
987184c1e2cSJames Courtier-Dutton 	.tlv = { .p = snd_audigy_db_scale2 },			\
988184c1e2cSJames Courtier-Dutton 	.private_value = chid					\
989184c1e2cSJames Courtier-Dutton }
990184c1e2cSJames Courtier-Dutton 
991184c1e2cSJames Courtier-Dutton 
992184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = {
993184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Mic Capture Volume", 0),
994184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Line Capture Volume", 0)
995184c1e2cSJames Courtier-Dutton };
996184c1e2cSJames Courtier-Dutton 
9970af68e5eSTakashi Iwai #if 0
998eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9991da177e4SLinus Torvalds {
10001da177e4SLinus Torvalds 	static char *texts[] = {"44100", "48000", "96000"};
10011da177e4SLinus Torvalds 
10021da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
10031da177e4SLinus Torvalds 	uinfo->count = 1;
10041da177e4SLinus Torvalds 	uinfo->value.enumerated.items = 3;
10051da177e4SLinus Torvalds 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
10061da177e4SLinus Torvalds 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
10071da177e4SLinus Torvalds 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
10081da177e4SLinus Torvalds 	return 0;
10091da177e4SLinus Torvalds }
10101da177e4SLinus Torvalds 
1011eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
1012eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10131da177e4SLinus Torvalds {
1014eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10151da177e4SLinus Torvalds 	unsigned int tmp;
10161da177e4SLinus Torvalds 	unsigned long flags;
10171da177e4SLinus Torvalds 
10181da177e4SLinus Torvalds 
10191da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10201da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
10211da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
10221da177e4SLinus Torvalds 	case A_SPDIF_44100:
10231da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
10241da177e4SLinus Torvalds 		break;
10251da177e4SLinus Torvalds 	case A_SPDIF_48000:
10261da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
10271da177e4SLinus Torvalds 		break;
10281da177e4SLinus Torvalds 	case A_SPDIF_96000:
10291da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
10301da177e4SLinus Torvalds 		break;
10311da177e4SLinus Torvalds 	default:
10321da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
10331da177e4SLinus Torvalds 	}
10341da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10351da177e4SLinus Torvalds 	return 0;
10361da177e4SLinus Torvalds }
10371da177e4SLinus Torvalds 
1038eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
1039eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10401da177e4SLinus Torvalds {
1041eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10421da177e4SLinus Torvalds 	int change;
10431da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
10441da177e4SLinus Torvalds 	unsigned long flags;
10451da177e4SLinus Torvalds 
10461da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
10471da177e4SLinus Torvalds 	case 0:
10481da177e4SLinus Torvalds 		val = A_SPDIF_44100;
10491da177e4SLinus Torvalds 		break;
10501da177e4SLinus Torvalds 	case 1:
10511da177e4SLinus Torvalds 		val = A_SPDIF_48000;
10521da177e4SLinus Torvalds 		break;
10531da177e4SLinus Torvalds 	case 2:
10541da177e4SLinus Torvalds 		val = A_SPDIF_96000;
10551da177e4SLinus Torvalds 		break;
10561da177e4SLinus Torvalds 	default:
10571da177e4SLinus Torvalds 		val = A_SPDIF_48000;
10581da177e4SLinus Torvalds 		break;
10591da177e4SLinus Torvalds 	}
10601da177e4SLinus Torvalds 
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10631da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
10641da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
10651da177e4SLinus Torvalds 	tmp |= val;
10661da177e4SLinus Torvalds 	if ((change = (tmp != reg)))
10671da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
10681da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10691da177e4SLinus Torvalds 	return change;
10701da177e4SLinus Torvalds }
10711da177e4SLinus Torvalds 
1072eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_spdif_output_rate =
10731da177e4SLinus Torvalds {
10741da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
10751da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
10761da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
10771da177e4SLinus Torvalds 	.count =	1,
10781da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
10791da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
10801da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
10811da177e4SLinus Torvalds };
10820af68e5eSTakashi Iwai #endif
10831da177e4SLinus Torvalds 
1084eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1085eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10861da177e4SLinus Torvalds {
1087eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10881da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
10891da177e4SLinus Torvalds 	int change;
10901da177e4SLinus Torvalds 	unsigned int val;
10911da177e4SLinus Torvalds 	unsigned long flags;
10921da177e4SLinus Torvalds 
109374415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
109474415a36SJames Courtier-Dutton 	if (idx >= 3)
109574415a36SJames Courtier-Dutton 		return -EINVAL;
10961da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
10971da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
10981da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
10991da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
11001da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11011da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
11021da177e4SLinus Torvalds 	if (change) {
11031da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
11041da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
11051da177e4SLinus Torvalds 	}
11061da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11071da177e4SLinus Torvalds 	return change;
11081da177e4SLinus Torvalds }
11091da177e4SLinus Torvalds 
1110eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
11111da177e4SLinus Torvalds {
11121da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
11135549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11141da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
11157583cb51STakashi Iwai 	.count =	3,
11161da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
11171da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
11181da177e4SLinus Torvalds };
11191da177e4SLinus Torvalds 
1120eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_control =
11211da177e4SLinus Torvalds {
11225549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
11231da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
11247583cb51STakashi Iwai 	.count =	3,
11251da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
11261da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
11271da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
11281da177e4SLinus Torvalds };
11291da177e4SLinus Torvalds 
11301da177e4SLinus Torvalds 
1131eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
11321da177e4SLinus Torvalds {
11331da177e4SLinus Torvalds 	if (emu->audigy) {
11341da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
11351da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
11361da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
11371da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
11381da177e4SLinus Torvalds 	} else {
11391da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
11401da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
11411da177e4SLinus Torvalds 	}
11421da177e4SLinus Torvalds }
11431da177e4SLinus Torvalds 
1144eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
11451da177e4SLinus Torvalds {
11461da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
11471da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
11481da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
11491da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
11501da177e4SLinus Torvalds 	if (emu->audigy) {
11511da177e4SLinus Torvalds 		unsigned int val = ((unsigned int)volume[4] << 24) |
11521da177e4SLinus Torvalds 			((unsigned int)volume[5] << 16) |
11531da177e4SLinus Torvalds 			((unsigned int)volume[6] << 8) |
11541da177e4SLinus Torvalds 			(unsigned int)volume[7];
11551da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
11561da177e4SLinus Torvalds 	}
11571da177e4SLinus Torvalds }
11581da177e4SLinus Torvalds 
11591da177e4SLinus Torvalds /* PCM stream controls */
11601da177e4SLinus Torvalds 
1161eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11621da177e4SLinus Torvalds {
1163eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11641da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
11651da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
11661da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11671da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
11681da177e4SLinus Torvalds 	return 0;
11691da177e4SLinus Torvalds }
11701da177e4SLinus Torvalds 
1171eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1172eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11731da177e4SLinus Torvalds {
11741da177e4SLinus Torvalds 	unsigned long flags;
1175eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1176eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1177eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11781da177e4SLinus Torvalds 	int voice, idx;
11791da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11801da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11811da177e4SLinus Torvalds 
11821da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11831da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
11841da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
11851da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
11861da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
11871da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11881da177e4SLinus Torvalds 	return 0;
11891da177e4SLinus Torvalds }
11901da177e4SLinus Torvalds 
1191eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1192eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11931da177e4SLinus Torvalds {
11941da177e4SLinus Torvalds 	unsigned long flags;
1195eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1196eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1197eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11981da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
11991da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12001da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
12011da177e4SLinus Torvalds 
12021da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12031da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
12041da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
12051da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
12061da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
12071da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
12081da177e4SLinus Torvalds 				change = 1;
12091da177e4SLinus Torvalds 			}
12101da177e4SLinus Torvalds 		}
12111da177e4SLinus Torvalds 	if (change && mix->epcm) {
12121da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
12131da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
12141da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
12151da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
12161da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
12171da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
12181da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
12191da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
12201da177e4SLinus Torvalds 		}
12211da177e4SLinus Torvalds 	}
12221da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12231da177e4SLinus Torvalds 	return change;
12241da177e4SLinus Torvalds }
12251da177e4SLinus Torvalds 
1226eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_routing_control =
12271da177e4SLinus Torvalds {
12281da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
122967ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12301da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
12311da177e4SLinus Torvalds 	.count =	32,
12321da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
12331da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
12341da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
12351da177e4SLinus Torvalds };
12361da177e4SLinus Torvalds 
1237eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12381da177e4SLinus Torvalds {
1239eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12401da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12411da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
12421da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12431da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
12441da177e4SLinus Torvalds 	return 0;
12451da177e4SLinus Torvalds }
12461da177e4SLinus Torvalds 
1247eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1248eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12491da177e4SLinus Torvalds {
12501da177e4SLinus Torvalds 	unsigned long flags;
1251eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1252eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1253eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12541da177e4SLinus Torvalds 	int idx;
12551da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12581da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
12591da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
12601da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12611da177e4SLinus Torvalds 	return 0;
12621da177e4SLinus Torvalds }
12631da177e4SLinus Torvalds 
1264eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1265eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12661da177e4SLinus Torvalds {
12671da177e4SLinus Torvalds 	unsigned long flags;
1268eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1269eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1270eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12711da177e4SLinus Torvalds 	int change = 0, idx, val;
12721da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12731da177e4SLinus Torvalds 
12741da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12751da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
12761da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
12771da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
12781da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
12791da177e4SLinus Torvalds 			change = 1;
12801da177e4SLinus Torvalds 		}
12811da177e4SLinus Torvalds 	}
12821da177e4SLinus Torvalds 	if (change && mix->epcm) {
12831da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
12841da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
12851da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
12861da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
12871da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
12881da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
12891da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
12901da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
12911da177e4SLinus Torvalds 		}
12921da177e4SLinus Torvalds 	}
12931da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12941da177e4SLinus Torvalds 	return change;
12951da177e4SLinus Torvalds }
12961da177e4SLinus Torvalds 
1297eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_volume_control =
12981da177e4SLinus Torvalds {
12991da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
130067ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13011da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
13021da177e4SLinus Torvalds 	.count =	32,
13031da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
13041da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
13051da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
13061da177e4SLinus Torvalds };
13071da177e4SLinus Torvalds 
1308eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13091da177e4SLinus Torvalds {
13101da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13111da177e4SLinus Torvalds 	uinfo->count = 3;
13121da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13131da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
13141da177e4SLinus Torvalds 	return 0;
13151da177e4SLinus Torvalds }
13161da177e4SLinus Torvalds 
1317eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1318eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
13191da177e4SLinus Torvalds {
1320eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1321eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1322eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13231da177e4SLinus Torvalds 	unsigned long flags;
13241da177e4SLinus Torvalds 	int idx;
13251da177e4SLinus Torvalds 
13261da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13271da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
13281da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->attn[idx];
13291da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13301da177e4SLinus Torvalds 	return 0;
13311da177e4SLinus Torvalds }
13321da177e4SLinus Torvalds 
1333eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1334eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
13351da177e4SLinus Torvalds {
13361da177e4SLinus Torvalds 	unsigned long flags;
1337eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1338eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1339eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13401da177e4SLinus Torvalds 	int change = 0, idx, val;
13411da177e4SLinus Torvalds 
13421da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13431da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
13441da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 0xffff;
13451da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
13461da177e4SLinus Torvalds 			mix->attn[idx] = val;
13471da177e4SLinus Torvalds 			change = 1;
13481da177e4SLinus Torvalds 		}
13491da177e4SLinus Torvalds 	}
13501da177e4SLinus Torvalds 	if (change && mix->epcm) {
13511da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
13521da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
13531da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
13541da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
13551da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
13561da177e4SLinus Torvalds 		}
13571da177e4SLinus Torvalds 	}
13581da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13591da177e4SLinus Torvalds 	return change;
13601da177e4SLinus Torvalds }
13611da177e4SLinus Torvalds 
1362eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_attn_control =
13631da177e4SLinus Torvalds {
13641da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
136567ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13661da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
13671da177e4SLinus Torvalds 	.count =	32,
13681da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
13691da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
13701da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
13711da177e4SLinus Torvalds };
13721da177e4SLinus Torvalds 
13731da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
13741da177e4SLinus Torvalds 
1375eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13761da177e4SLinus Torvalds {
1377eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13781da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13791da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
13801da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13811da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
13821da177e4SLinus Torvalds 	return 0;
13831da177e4SLinus Torvalds }
13841da177e4SLinus Torvalds 
1385eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1386eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
13871da177e4SLinus Torvalds {
13881da177e4SLinus Torvalds 	unsigned long flags;
1389eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1390eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1391eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13921da177e4SLinus Torvalds 	int idx;
13931da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13941da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
13951da177e4SLinus Torvalds 
13961da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13971da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
13981da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
13991da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
14001da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14011da177e4SLinus Torvalds 	return 0;
14021da177e4SLinus Torvalds }
14031da177e4SLinus Torvalds 
1404eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1405eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14061da177e4SLinus Torvalds {
14071da177e4SLinus Torvalds 	unsigned long flags;
1408eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14091da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1410eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
14111da177e4SLinus Torvalds 	int change = 0, idx, val;
14121da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14131da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14141da177e4SLinus Torvalds 
14151da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14161da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
14171da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
14181da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
14191da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
14201da177e4SLinus Torvalds 			change = 1;
14211da177e4SLinus Torvalds 		}
14221da177e4SLinus Torvalds 	}
14231da177e4SLinus Torvalds 
14241da177e4SLinus Torvalds 	if (change && mix->epcm) {
14251da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
14261da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
14271da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
14281da177e4SLinus Torvalds 		}
14291da177e4SLinus Torvalds 	}
14301da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14311da177e4SLinus Torvalds 	return change;
14321da177e4SLinus Torvalds }
14331da177e4SLinus Torvalds 
1434eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
14351da177e4SLinus Torvalds {
14361da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
14371da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14381da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
14391da177e4SLinus Torvalds 	.count =	16,
14401da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
14411da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
14421da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
14431da177e4SLinus Torvalds };
14441da177e4SLinus Torvalds 
1445eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14461da177e4SLinus Torvalds {
1447eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14481da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14491da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
14501da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14511da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
14521da177e4SLinus Torvalds 	return 0;
14531da177e4SLinus Torvalds }
14541da177e4SLinus Torvalds 
1455eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1456eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
14571da177e4SLinus Torvalds {
14581da177e4SLinus Torvalds 	unsigned long flags;
1459eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1460eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1461eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14621da177e4SLinus Torvalds 	int idx;
14631da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14641da177e4SLinus Torvalds 
14651da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14661da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
14671da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
14681da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14691da177e4SLinus Torvalds 	return 0;
14701da177e4SLinus Torvalds }
14711da177e4SLinus Torvalds 
1472eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1473eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
14741da177e4SLinus Torvalds {
14751da177e4SLinus Torvalds 	unsigned long flags;
1476eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14771da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1478eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
14791da177e4SLinus Torvalds 	int change = 0, idx, val;
14801da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14811da177e4SLinus Torvalds 
14821da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14831da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
14841da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
14851da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
14861da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
14871da177e4SLinus Torvalds 			change = 1;
14881da177e4SLinus Torvalds 		}
14891da177e4SLinus Torvalds 	}
14901da177e4SLinus Torvalds 	if (change && mix->epcm) {
14911da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
14921da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
14931da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
14941da177e4SLinus Torvalds 		}
14951da177e4SLinus Torvalds 	}
14961da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14971da177e4SLinus Torvalds 	return change;
14981da177e4SLinus Torvalds }
14991da177e4SLinus Torvalds 
15001da177e4SLinus Torvalds 
1501eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
15021da177e4SLinus Torvalds {
15031da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15041da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15051da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
15061da177e4SLinus Torvalds 	.count =	16,
15071da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
15081da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
15091da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
15101da177e4SLinus Torvalds };
15111da177e4SLinus Torvalds 
1512eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15131da177e4SLinus Torvalds {
15141da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15151da177e4SLinus Torvalds 	uinfo->count = 1;
15161da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
15171da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
15181da177e4SLinus Torvalds 	return 0;
15191da177e4SLinus Torvalds }
15201da177e4SLinus Torvalds 
1521eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1522eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
15231da177e4SLinus Torvalds {
1524eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1525eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1526eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15271da177e4SLinus Torvalds 	unsigned long flags;
15281da177e4SLinus Torvalds 
15291da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15301da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = mix->attn[0];
15311da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15321da177e4SLinus Torvalds 	return 0;
15331da177e4SLinus Torvalds }
15341da177e4SLinus Torvalds 
1535eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1536eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
15371da177e4SLinus Torvalds {
15381da177e4SLinus Torvalds 	unsigned long flags;
1539eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15401da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1541eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
15421da177e4SLinus Torvalds 	int change = 0, val;
15431da177e4SLinus Torvalds 
15441da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15451da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] & 0xffff;
15461da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
15471da177e4SLinus Torvalds 		mix->attn[0] = val;
15481da177e4SLinus Torvalds 		change = 1;
15491da177e4SLinus Torvalds 	}
15501da177e4SLinus Torvalds 	if (change && mix->epcm) {
15511da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
15521da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
15531da177e4SLinus Torvalds 		}
15541da177e4SLinus Torvalds 	}
15551da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15561da177e4SLinus Torvalds 	return change;
15571da177e4SLinus Torvalds }
15581da177e4SLinus Torvalds 
1559eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
15601da177e4SLinus Torvalds {
15611da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15621da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15631da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
15641da177e4SLinus Torvalds 	.count =	16,
15651da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
15661da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
15671da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
15681da177e4SLinus Torvalds };
15691da177e4SLinus Torvalds 
1570a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
15711da177e4SLinus Torvalds 
1572eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1573eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
15741da177e4SLinus Torvalds {
1575eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15761da177e4SLinus Torvalds 
15771da177e4SLinus Torvalds 	if (emu->audigy)
15781da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
15791da177e4SLinus Torvalds 	else
15801da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1581d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1582d2cd74b1STakashi Iwai 		ucontrol->value.integer.value[0] =
1583d2cd74b1STakashi Iwai 			!ucontrol->value.integer.value[0];
1584d2cd74b1STakashi Iwai 
15851da177e4SLinus Torvalds 	return 0;
15861da177e4SLinus Torvalds }
15871da177e4SLinus Torvalds 
1588eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1589eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
15901da177e4SLinus Torvalds {
15911da177e4SLinus Torvalds 	unsigned long flags;
1592eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1593d2cd74b1STakashi Iwai 	unsigned int reg, val, sw;
15941da177e4SLinus Torvalds 	int change = 0;
15951da177e4SLinus Torvalds 
1596d2cd74b1STakashi Iwai 	sw = ucontrol->value.integer.value[0];
1597d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1598d2cd74b1STakashi Iwai 		sw = !sw;
15991da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1600184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1601184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1602184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
16031da177e4SLinus Torvalds 		reg = inl(emu->port + A_IOCFG);
1604d2cd74b1STakashi Iwai 		val = sw ? A_IOCFG_GPOUT0 : 0;
16051da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
16061da177e4SLinus Torvalds 		if (change) {
16071da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
16081da177e4SLinus Torvalds 			reg |= val;
16091da177e4SLinus Torvalds 			outl(reg | val, emu->port + A_IOCFG);
16101da177e4SLinus Torvalds 		}
16111da177e4SLinus Torvalds 	}
16121da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
1613d2cd74b1STakashi Iwai 	val = sw ? HCFG_GPOUT0 : 0;
16141da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
16151da177e4SLinus Torvalds 	if (change) {
16161da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
16171da177e4SLinus Torvalds 		reg |= val;
16181da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
16191da177e4SLinus Torvalds 	}
16201da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
16211da177e4SLinus Torvalds 	return change;
16221da177e4SLinus Torvalds }
16231da177e4SLinus Torvalds 
1624eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata =
16251da177e4SLinus Torvalds {
16261da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16271da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
16281da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
16291da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
16301da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
16311da177e4SLinus Torvalds };
16321da177e4SLinus Torvalds 
1633eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata =
16341da177e4SLinus Torvalds {
16351da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16361da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
16371da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
16381da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
16391da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
16401da177e4SLinus Torvalds };
16411da177e4SLinus Torvalds 
164216950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
164316950e09STakashi Iwai 
164416950e09STakashi Iwai #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
164516950e09STakashi Iwai 
164616950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
164716950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
164816950e09STakashi Iwai {
164916950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
165016950e09STakashi Iwai 	unsigned int val;
165116950e09STakashi Iwai 
165216950e09STakashi Iwai 	/* FIXME: better to use a cached version */
165316950e09STakashi Iwai 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
165416950e09STakashi Iwai 	ucontrol->value.integer.value[0] = !!val;
165516950e09STakashi Iwai 	return 0;
165616950e09STakashi Iwai }
165716950e09STakashi Iwai 
165816950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
165916950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
166016950e09STakashi Iwai {
166116950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
166216950e09STakashi Iwai 	unsigned int val;
166316950e09STakashi Iwai 
166416950e09STakashi Iwai 	if (ucontrol->value.integer.value[0])
166516950e09STakashi Iwai 		val = 0x0f0f;
166616950e09STakashi Iwai 	else
166716950e09STakashi Iwai 		val = 0;
166816950e09STakashi Iwai 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
166916950e09STakashi Iwai }
167016950e09STakashi Iwai 
167116950e09STakashi Iwai static struct snd_kcontrol_new snd_audigy_capture_boost __devinitdata =
167216950e09STakashi Iwai {
167316950e09STakashi Iwai 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
167416950e09STakashi Iwai 	.name =		"Analog Capture Boost",
167516950e09STakashi Iwai 	.info =		snd_audigy_capture_boost_info,
167616950e09STakashi Iwai 	.get =		snd_audigy_capture_boost_get,
167716950e09STakashi Iwai 	.put =		snd_audigy_capture_boost_put
167816950e09STakashi Iwai };
167916950e09STakashi Iwai 
168016950e09STakashi Iwai 
16811da177e4SLinus Torvalds /*
16821da177e4SLinus Torvalds  */
1683eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
16841da177e4SLinus Torvalds {
1685eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
16861da177e4SLinus Torvalds 	emu->ac97 = NULL;
16871da177e4SLinus Torvalds }
16881da177e4SLinus Torvalds 
16891da177e4SLinus Torvalds /*
16901da177e4SLinus Torvalds  */
1691eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
16921da177e4SLinus Torvalds {
1693eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
16941da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
16951da177e4SLinus Torvalds 	strcpy(id.name, name);
16961da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
16971da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
16981da177e4SLinus Torvalds }
16991da177e4SLinus Torvalds 
1700eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
17011da177e4SLinus Torvalds {
1702eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
17031da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
17041da177e4SLinus Torvalds 	strcpy(sid.name, name);
17051da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
17061da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
17071da177e4SLinus Torvalds }
17081da177e4SLinus Torvalds 
1709eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
17101da177e4SLinus Torvalds {
1711eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
17121da177e4SLinus Torvalds 	if (kctl) {
17131da177e4SLinus Torvalds 		strcpy(kctl->id.name, dst);
17141da177e4SLinus Torvalds 		return 0;
17151da177e4SLinus Torvalds 	}
17161da177e4SLinus Torvalds 	return -ENOENT;
17171da177e4SLinus Torvalds }
17181da177e4SLinus Torvalds 
1719eb4698f3STakashi Iwai int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
172067ed4161SClemens Ladisch 				int pcm_device, int multi_device)
17211da177e4SLinus Torvalds {
17221da177e4SLinus Torvalds 	int err, pcm;
1723eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1724eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
17251da177e4SLinus Torvalds 	char **c;
17261da177e4SLinus Torvalds 	static char *emu10k1_remove_ctls[] = {
17271da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
17281da177e4SLinus Torvalds 		"Master Mono Playback Switch",
17291da177e4SLinus Torvalds 		"Master Mono Playback Volume",
17301da177e4SLinus Torvalds 		"PCM Out Path & Mute",
17311da177e4SLinus Torvalds 		"Mono Output Select",
17321da177e4SLinus Torvalds 		"Surround Playback Switch",
17331da177e4SLinus Torvalds 		"Surround Playback Volume",
17341da177e4SLinus Torvalds 		"Center Playback Switch",
17351da177e4SLinus Torvalds 		"Center Playback Volume",
17361da177e4SLinus Torvalds 		"LFE Playback Switch",
17371da177e4SLinus Torvalds 		"LFE Playback Volume",
17381da177e4SLinus Torvalds 		NULL
17391da177e4SLinus Torvalds 	};
17401da177e4SLinus Torvalds 	static char *emu10k1_rename_ctls[] = {
17411da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
17421da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
17431da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
17441da177e4SLinus Torvalds 		NULL
17451da177e4SLinus Torvalds 	};
17461da177e4SLinus Torvalds 	static char *audigy_remove_ctls[] = {
17471da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
174821fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
174921fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
17501da177e4SLinus Torvalds 		"PCM Playback Switch",
17511da177e4SLinus Torvalds 		"PCM Playback Volume",
17521da177e4SLinus Torvalds 		"Master Mono Playback Switch",
17531da177e4SLinus Torvalds 		"Master Mono Playback Volume",
17541da177e4SLinus Torvalds 		"Master Playback Switch",
17551da177e4SLinus Torvalds 		"Master Playback Volume",
17561da177e4SLinus Torvalds 		"PCM Out Path & Mute",
17571da177e4SLinus Torvalds 		"Mono Output Select",
17581da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
17591da177e4SLinus Torvalds 		"Capture Source",
17601da177e4SLinus Torvalds 		"Capture Switch",
17611da177e4SLinus Torvalds 		"Capture Volume",
17621da177e4SLinus Torvalds 		"Mic Select",
17631da177e4SLinus Torvalds 		"Video Playback Switch",
17641da177e4SLinus Torvalds 		"Video Playback Volume",
17651da177e4SLinus Torvalds 		"Mic Playback Switch",
17661da177e4SLinus Torvalds 		"Mic Playback Volume",
17671da177e4SLinus Torvalds 		NULL
17681da177e4SLinus Torvalds 	};
17691da177e4SLinus Torvalds 	static char *audigy_rename_ctls[] = {
17701da177e4SLinus Torvalds 		/* use conventional names */
17711da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
17721da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
17731da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
17741da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
17751da177e4SLinus Torvalds 		NULL
17761da177e4SLinus Torvalds 	};
1777184c1e2cSJames Courtier-Dutton 	static char *audigy_rename_ctls_i2c_adc[] = {
1778184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1779184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1780184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1781184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1782184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1783eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1784184c1e2cSJames Courtier-Dutton 		NULL
1785184c1e2cSJames Courtier-Dutton 	};
1786184c1e2cSJames Courtier-Dutton 	static char *audigy_remove_ctls_i2c_adc[] = {
1787184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1788184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1789184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1790184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1791184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1792eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1793184c1e2cSJames Courtier-Dutton 		NULL
1794184c1e2cSJames Courtier-Dutton 	};
179521fdddeaSJames Courtier-Dutton 	static char *audigy_remove_ctls_1361t_adc[] = {
179621fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
179721fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
179821fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
179921fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
180021fdddeaSJames Courtier-Dutton 		"Master Mono Playback Switch",
180121fdddeaSJames Courtier-Dutton 		"Master Mono Playback Volume",
180221fdddeaSJames Courtier-Dutton 		"Capture Source",
180321fdddeaSJames Courtier-Dutton 		"Capture Switch",
180421fdddeaSJames Courtier-Dutton 		"Capture Volume",
180521fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
180621fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
180721fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
180821fdddeaSJames Courtier-Dutton 		"3D Control - Center",
180921fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
181021fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
181121fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
181221fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
181321fdddeaSJames Courtier-Dutton 		NULL
181421fdddeaSJames Courtier-Dutton 	};
181521fdddeaSJames Courtier-Dutton 	static char *audigy_rename_ctls_1361t_adc[] = {
181621fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
181721fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
181821fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1819d355c82aSJaroslav Kysela 		"Beep Playback Switch", "Beep Capture Switch",
1820d355c82aSJaroslav Kysela 		"Beep Playback Volume", "Beep Capture Volume",
182121fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
182221fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
182321fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
182421fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
182521fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
182621fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
182721fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
182821fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
182921fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
183021fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
183121fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
183221fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
183321fdddeaSJames Courtier-Dutton 
183421fdddeaSJames Courtier-Dutton 		NULL
183521fdddeaSJames Courtier-Dutton 	};
18361da177e4SLinus Torvalds 
18372b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1838eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1839eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
1840eb4698f3STakashi Iwai 		static struct snd_ac97_bus_ops ops = {
18411da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
18421da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
18431da177e4SLinus Torvalds 		};
18441da177e4SLinus Torvalds 
1845b1508693STakashi Iwai 		if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0)
18461da177e4SLinus Torvalds 			return err;
18471da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
18481da177e4SLinus Torvalds 
18491da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
18501da177e4SLinus Torvalds 		ac97.private_data = emu;
18511da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
18521da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
1853b1508693STakashi Iwai 		if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
1854b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
18551da177e4SLinus Torvalds 				return err;
1856b1508693STakashi Iwai 			snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n");
1857b1508693STakashi Iwai 			snd_printd(KERN_INFO"          Proceeding without ac97 mixers...\n");
1858b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1859b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1860b1508693STakashi Iwai 		}
18611da177e4SLinus Torvalds 		if (emu->audigy) {
18621da177e4SLinus Torvalds 			/* set master volume to 0 dB */
18634d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
18641da177e4SLinus Torvalds 			/* set capture source to mic */
18654d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
186621fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
186721fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
186821fdddeaSJames Courtier-Dutton 			else
18691da177e4SLinus Torvalds 				c = audigy_remove_ctls;
18701da177e4SLinus Torvalds 		} else {
18711da177e4SLinus Torvalds 			/*
18721da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
18731da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
18741da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
18751da177e4SLinus Torvalds 			 */
18761da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
18771da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
18781da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
18792594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
1880*b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Volume");
1881*b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Switch");
18821da177e4SLinus Torvalds 			}
18831da177e4SLinus Torvalds 			/* remove unused AC97 controls */
18844d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
18854d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
18861da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
18871da177e4SLinus Torvalds 		}
18881da177e4SLinus Torvalds 		for (; *c; c++)
18891da177e4SLinus Torvalds 			remove_ctl(card, *c);
1890184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1891184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1892184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1893184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
18941da177e4SLinus Torvalds 	} else {
1895f12aa40cSTakashi Iwai 	no_ac97:
18962b637da5SLee Revell 		if (emu->card_capabilities->ecard)
18971da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
18981da177e4SLinus Torvalds 		else if (emu->audigy)
18991da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
19001da177e4SLinus Torvalds 		else
19011da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
19021da177e4SLinus Torvalds 	}
19031da177e4SLinus Torvalds 
19041da177e4SLinus Torvalds 	if (emu->audigy)
190521fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
190621fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1907184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1908184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
190921fdddeaSJames Courtier-Dutton 		else
19101da177e4SLinus Torvalds 			c = audigy_rename_ctls;
19111da177e4SLinus Torvalds 	else
19121da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
19131da177e4SLinus Torvalds 	for (; *c; c += 2)
19141da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
191521fdddeaSJames Courtier-Dutton 
1916e217b960SRaymond Yau 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
1917e217b960SRaymond Yau 		remove_ctl(card, "Center Playback Volume");
1918e217b960SRaymond Yau 		remove_ctl(card, "LFE Playback Volume");
1919e217b960SRaymond Yau 		remove_ctl(card, "Wave Center Playback Volume");
1920e217b960SRaymond Yau 		remove_ctl(card, "Wave LFE Playback Volume");
1921e217b960SRaymond Yau 	}
1922e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1923e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1924e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1925e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1926e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1927e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Switch");
1928e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Volume");
1929e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Center");
1930e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Depth");
1931e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Switch");
1932e3b9bc0eSJames Courtier-Dutton 	}
19331da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
19341da177e4SLinus Torvalds 		return -ENOMEM;
193567ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
19361da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19371da177e4SLinus Torvalds 		return err;
19381da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
19391da177e4SLinus Torvalds 		return -ENOMEM;
194067ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
19411da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19421da177e4SLinus Torvalds 		return err;
19431da177e4SLinus Torvalds 	if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
19441da177e4SLinus Torvalds 		return -ENOMEM;
194567ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
19461da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19471da177e4SLinus Torvalds 		return err;
19481da177e4SLinus Torvalds 
19491da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
19501da177e4SLinus Torvalds 		return -ENOMEM;
195167ed4161SClemens Ladisch 	kctl->id.device = multi_device;
19521da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19531da177e4SLinus Torvalds 		return err;
19541da177e4SLinus Torvalds 
19551da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
19561da177e4SLinus Torvalds 		return -ENOMEM;
195767ed4161SClemens Ladisch 	kctl->id.device = multi_device;
19581da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19591da177e4SLinus Torvalds 		return err;
19601da177e4SLinus Torvalds 
19611da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
19621da177e4SLinus Torvalds 		return -ENOMEM;
196367ed4161SClemens Ladisch 	kctl->id.device = multi_device;
19641da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
19651da177e4SLinus Torvalds 		return err;
19661da177e4SLinus Torvalds 
19671da177e4SLinus Torvalds 	/* initialize the routing and volume table for each pcm playback stream */
19681da177e4SLinus Torvalds 	for (pcm = 0; pcm < 32; pcm++) {
1969eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
19701da177e4SLinus Torvalds 		int v;
19711da177e4SLinus Torvalds 
19721da177e4SLinus Torvalds 		mix = &emu->pcm_mixer[pcm];
19731da177e4SLinus Torvalds 		mix->epcm = NULL;
19741da177e4SLinus Torvalds 
19751da177e4SLinus Torvalds 		for (v = 0; v < 4; v++)
19761da177e4SLinus Torvalds 			mix->send_routing[0][v] =
19771da177e4SLinus Torvalds 				mix->send_routing[1][v] =
19781da177e4SLinus Torvalds 				mix->send_routing[2][v] = v;
19791da177e4SLinus Torvalds 
19801da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
19811da177e4SLinus Torvalds 		mix->send_volume[0][0] = mix->send_volume[0][1] =
19821da177e4SLinus Torvalds 		mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
19831da177e4SLinus Torvalds 
19841da177e4SLinus Torvalds 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
19851da177e4SLinus Torvalds 	}
19861da177e4SLinus Torvalds 
19871da177e4SLinus Torvalds 	/* initialize the routing and volume table for the multichannel playback stream */
19881da177e4SLinus Torvalds 	for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
1989eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
19901da177e4SLinus Torvalds 		int v;
19911da177e4SLinus Torvalds 
19921da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[pcm];
19931da177e4SLinus Torvalds 		mix->epcm = NULL;
19941da177e4SLinus Torvalds 
19951da177e4SLinus Torvalds 		mix->send_routing[0][0] = pcm;
19961da177e4SLinus Torvalds 		mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
19971da177e4SLinus Torvalds 		for (v = 0; v < 2; v++)
19981da177e4SLinus Torvalds 			mix->send_routing[0][2+v] = 13+v;
19991da177e4SLinus Torvalds 		if (emu->audigy)
20001da177e4SLinus Torvalds 			for (v = 0; v < 4; v++)
20011da177e4SLinus Torvalds 				mix->send_routing[0][4+v] = 60+v;
20021da177e4SLinus Torvalds 
20031da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
20041da177e4SLinus Torvalds 		mix->send_volume[0][0]  = 255;
20051da177e4SLinus Torvalds 
20061da177e4SLinus Torvalds 		mix->attn[0] = 0xffff;
20071da177e4SLinus Torvalds 	}
20081da177e4SLinus Torvalds 
20092b637da5SLee Revell 	if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
20101da177e4SLinus Torvalds 		/* sb live! and audigy */
20111da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
20121da177e4SLinus Torvalds 			return -ENOMEM;
20135549d549SClemens Ladisch 		if (!emu->audigy)
20145549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
20151da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
20161da177e4SLinus Torvalds 			return err;
20171da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
20181da177e4SLinus Torvalds 			return -ENOMEM;
20195549d549SClemens Ladisch 		if (!emu->audigy)
20205549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
20211da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
20221da177e4SLinus Torvalds 			return err;
20231da177e4SLinus Torvalds 	}
20241da177e4SLinus Torvalds 
2025190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
202619b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
202719b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
20281da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
20291da177e4SLinus Torvalds 			return -ENOMEM;
20301da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
20311da177e4SLinus Torvalds 			return err;
2032001f7589SJames Courtier-Dutton #if 0
20331da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
20341da177e4SLinus Torvalds 			return -ENOMEM;
20351da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
20361da177e4SLinus Torvalds 			return err;
2037001f7589SJames Courtier-Dutton #endif
20382b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
20391da177e4SLinus Torvalds 		/* sb live! */
20401da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
20411da177e4SLinus Torvalds 			return -ENOMEM;
20421da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
20431da177e4SLinus Torvalds 			return err;
20441da177e4SLinus Torvalds 	}
20452b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
20461da177e4SLinus Torvalds 		if ((err = snd_p16v_mixer(emu)))
20471da177e4SLinus Torvalds 			return err;
20481da177e4SLinus Torvalds 	}
20491da177e4SLinus Torvalds 
20503839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
20511c02e366SCtirad Fertr 		/* 1616(m) cardbus */
20529f4bd5ddSJames Courtier-Dutton 		int i;
20539f4bd5ddSJames Courtier-Dutton 
20541c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) {
20551c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20561c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1616_output_enum_ctls[i],
20571c02e366SCtirad Fertr 					     emu));
20589f4bd5ddSJames Courtier-Dutton 			if (err < 0)
20599f4bd5ddSJames Courtier-Dutton 				return err;
20609f4bd5ddSJames Courtier-Dutton 		}
20619f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
20621c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20631c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
20641c02e366SCtirad Fertr 					     emu));
20651c02e366SCtirad Fertr 			if (err < 0)
20661c02e366SCtirad Fertr 				return err;
20671c02e366SCtirad Fertr 		}
20681c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) {
20691c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20701c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
20711c02e366SCtirad Fertr 			if (err < 0)
20721c02e366SCtirad Fertr 				return err;
20731c02e366SCtirad Fertr 		}
20741c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) {
20751c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20761c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
20771c02e366SCtirad Fertr 			if (err < 0)
20781c02e366SCtirad Fertr 				return err;
20791c02e366SCtirad Fertr 		}
20801c02e366SCtirad Fertr 		err = snd_ctl_add(card,
20811c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
20821c02e366SCtirad Fertr 		if (err < 0)
20831c02e366SCtirad Fertr 			return err;
20841c02e366SCtirad Fertr 
208588aa1390STakashi Iwai 	} else if (emu->card_capabilities->emu_model) {
20861c02e366SCtirad Fertr 		/* all other e-mu cards for now */
20871c02e366SCtirad Fertr 		int i;
20881c02e366SCtirad Fertr 
20891c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
20901c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20911c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_output_enum_ctls[i],
20921c02e366SCtirad Fertr 					     emu));
20931c02e366SCtirad Fertr 			if (err < 0)
20941c02e366SCtirad Fertr 				return err;
20951c02e366SCtirad Fertr 		}
20961c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
20971c02e366SCtirad Fertr 			err = snd_ctl_add(card,
20981c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
20991c02e366SCtirad Fertr 					     emu));
21009f4bd5ddSJames Courtier-Dutton 			if (err < 0)
21019f4bd5ddSJames Courtier-Dutton 				return err;
21029f4bd5ddSJames Courtier-Dutton 		}
21039148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
21041c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21051c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
21069148cc50SJames Courtier-Dutton 			if (err < 0)
21079148cc50SJames Courtier-Dutton 				return err;
21089148cc50SJames Courtier-Dutton 		}
21099148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
21101c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21111c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
21129148cc50SJames Courtier-Dutton 			if (err < 0)
21139148cc50SJames Courtier-Dutton 				return err;
21149148cc50SJames Courtier-Dutton 		}
21151c02e366SCtirad Fertr 		err = snd_ctl_add(card,
21161c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
2117b0dbdaeaSJames Courtier-Dutton 		if (err < 0)
2118b0dbdaeaSJames Courtier-Dutton 			return err;
21199f4bd5ddSJames Courtier-Dutton 	}
21209f4bd5ddSJames Courtier-Dutton 
2121184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2122184c1e2cSJames Courtier-Dutton 		int i;
2123184c1e2cSJames Courtier-Dutton 
2124184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2125184c1e2cSJames Courtier-Dutton 		if (err < 0)
2126184c1e2cSJames Courtier-Dutton 			return err;
2127184c1e2cSJames Courtier-Dutton 
2128184c1e2cSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
2129184c1e2cSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
2130184c1e2cSJames Courtier-Dutton 			if (err < 0)
2131184c1e2cSJames Courtier-Dutton 				return err;
2132184c1e2cSJames Courtier-Dutton 		}
2133184c1e2cSJames Courtier-Dutton 	}
2134184c1e2cSJames Courtier-Dutton 
213516950e09STakashi Iwai 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
213616950e09STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
213716950e09STakashi Iwai 						     emu));
213816950e09STakashi Iwai 		if (err < 0)
213916950e09STakashi Iwai 			return err;
214016950e09STakashi Iwai 	}
214116950e09STakashi Iwai 
21421da177e4SLinus Torvalds 	return 0;
21431da177e4SLinus Torvalds }
2144