xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision 184c1e2c)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  Copyright (c) by Jaroslav Kysela <perex@suse.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 <sound/driver.h>
341da177e4SLinus Torvalds #include <linux/time.h>
351da177e4SLinus Torvalds #include <linux/init.h>
361da177e4SLinus Torvalds #include <sound/core.h>
371da177e4SLinus Torvalds #include <sound/emu10k1.h>
38b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h>
39184c1e2cSJames Courtier-Dutton #include <sound/tlv.h>
40184c1e2cSJames Courtier-Dutton 
41184c1e2cSJames Courtier-Dutton #include "p17v.h"
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds #define AC97_ID_STAC9758	0x83847658
441da177e4SLinus Torvalds 
45184c1e2cSJames Courtier-Dutton static DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
46184c1e2cSJames Courtier-Dutton 
47eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
481da177e4SLinus Torvalds {
491da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
501da177e4SLinus Torvalds 	uinfo->count = 1;
511da177e4SLinus Torvalds 	return 0;
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds 
54eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
55eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
561da177e4SLinus Torvalds {
57eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
581da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
591da177e4SLinus Torvalds 	unsigned long flags;
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
621da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
631da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
641da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
651da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
661da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
671da177e4SLinus Torvalds 	return 0;
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds 
70eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
71eb4698f3STakashi Iwai 				      struct snd_ctl_elem_value *ucontrol)
721da177e4SLinus Torvalds {
731da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
741da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
751da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
761da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
771da177e4SLinus Torvalds 	return 0;
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds 
809f4bd5ddSJames Courtier-Dutton static char *emu1010_src_texts[] = {
819f4bd5ddSJames Courtier-Dutton 	"Silence",
829f4bd5ddSJames Courtier-Dutton 	"Dock Mic A",
839f4bd5ddSJames Courtier-Dutton 	"Dock Mic B",
849f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Left",
859f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Right",
869f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Left",
879f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Right",
889f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Left",
899f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Right",
909f4bd5ddSJames Courtier-Dutton 	"0202 ADC Left",
919f4bd5ddSJames Courtier-Dutton 	"0202 ADC Right",
929f4bd5ddSJames Courtier-Dutton 	"0202 SPDIF Left",
939f4bd5ddSJames Courtier-Dutton 	"0202 SPDIF Right",
949f4bd5ddSJames Courtier-Dutton 	"ADAT 0",
959f4bd5ddSJames Courtier-Dutton 	"ADAT 1",
969f4bd5ddSJames Courtier-Dutton 	"ADAT 2",
979f4bd5ddSJames Courtier-Dutton 	"ADAT 3",
989f4bd5ddSJames Courtier-Dutton 	"ADAT 4",
999f4bd5ddSJames Courtier-Dutton 	"ADAT 5",
1009f4bd5ddSJames Courtier-Dutton 	"ADAT 6",
1019f4bd5ddSJames Courtier-Dutton 	"ADAT 7",
1029f4bd5ddSJames Courtier-Dutton 	"DSP 0",
1039f4bd5ddSJames Courtier-Dutton 	"DSP 1",
1049f4bd5ddSJames Courtier-Dutton 	"DSP 2",
1059f4bd5ddSJames Courtier-Dutton 	"DSP 3",
1069f4bd5ddSJames Courtier-Dutton 	"DSP 4",
1079f4bd5ddSJames Courtier-Dutton 	"DSP 5",
1089f4bd5ddSJames Courtier-Dutton 	"DSP 6",
1099f4bd5ddSJames Courtier-Dutton 	"DSP 7",
1109f4bd5ddSJames Courtier-Dutton 	"DSP 8",
1119f4bd5ddSJames Courtier-Dutton 	"DSP 9",
1129f4bd5ddSJames Courtier-Dutton 	"DSP 10",
1139f4bd5ddSJames Courtier-Dutton 	"DSP 11",
1149f4bd5ddSJames Courtier-Dutton 	"DSP 12",
1159f4bd5ddSJames Courtier-Dutton 	"DSP 13",
1169f4bd5ddSJames Courtier-Dutton 	"DSP 14",
1179f4bd5ddSJames Courtier-Dutton 	"DSP 15",
1189f4bd5ddSJames Courtier-Dutton 	"DSP 16",
1199f4bd5ddSJames Courtier-Dutton 	"DSP 17",
1209f4bd5ddSJames Courtier-Dutton 	"DSP 18",
1219f4bd5ddSJames Courtier-Dutton 	"DSP 19",
1229f4bd5ddSJames Courtier-Dutton 	"DSP 20",
1239f4bd5ddSJames Courtier-Dutton 	"DSP 21",
1249f4bd5ddSJames Courtier-Dutton 	"DSP 22",
1259f4bd5ddSJames Courtier-Dutton 	"DSP 23",
1269f4bd5ddSJames Courtier-Dutton 	"DSP 24",
1279f4bd5ddSJames Courtier-Dutton 	"DSP 25",
1289f4bd5ddSJames Courtier-Dutton 	"DSP 26",
1299f4bd5ddSJames Courtier-Dutton 	"DSP 27",
1309f4bd5ddSJames Courtier-Dutton 	"DSP 28",
1319f4bd5ddSJames Courtier-Dutton 	"DSP 29",
1329f4bd5ddSJames Courtier-Dutton 	"DSP 30",
1339f4bd5ddSJames Courtier-Dutton 	"DSP 31",
1349f4bd5ddSJames Courtier-Dutton };
1359f4bd5ddSJames Courtier-Dutton 
1369f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_src_regs[] = {
1379f4bd5ddSJames Courtier-Dutton 	EMU_SRC_SILENCE,/* 0 */
1389f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_MIC_A1, /* 1 */
1399f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_MIC_B1, /* 2 */
1409f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */
1419f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */
1429f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */
1439f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */
1449f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */
1459f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */
1469f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */
1479f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */
1489f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */
1499f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */
1509f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT, /* 13 */
1519f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+1, /* 14 */
1529f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+2, /* 15 */
1539f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+3, /* 16 */
1549f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+4, /* 17 */
1559f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+5, /* 18 */
1569f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+6, /* 19 */
1579f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+7, /* 20 */
1589f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A, /* 21 */
1599f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+1, /* 22 */
1609f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+2, /* 23 */
1619f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+3, /* 24 */
1629f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+4, /* 25 */
1639f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+5, /* 26 */
1649f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+6, /* 27 */
1659f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+7, /* 28 */
1669f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+8, /* 29 */
1679f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+9, /* 30 */
1689f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xa, /* 31 */
1699f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xb, /* 32 */
1709f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xc, /* 33 */
1719f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xd, /* 34 */
1729f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xe, /* 35 */
1739f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xf, /* 36 */
1749f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B, /* 37 */
1759f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+1, /* 38 */
1769f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+2, /* 39 */
1779f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+3, /* 40 */
1789f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+4, /* 41 */
1799f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+5, /* 42 */
1809f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+6, /* 43 */
1819f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+7, /* 44 */
1829f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+8, /* 45 */
1839f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+9, /* 46 */
1849f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xa, /* 47 */
1859f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xb, /* 48 */
1869f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xc, /* 49 */
1879f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xd, /* 50 */
1889f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xe, /* 51 */
1899f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
1909f4bd5ddSJames Courtier-Dutton };
1919f4bd5ddSJames Courtier-Dutton 
1929f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_output_dst[] = {
1939f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
1949f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
1959f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC2_LEFT1, /* 2 */
1969f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */
1979f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC3_LEFT1, /* 4 */
1989f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */
1999f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC4_LEFT1, /* 6 */
2009f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */
2019f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_PHONES_LEFT1, /* 8 */
2029f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */
2039f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */
2049f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */
2059f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_SPDIF_LEFT1, /* 12 */
2069f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */
2079f4bd5ddSJames Courtier-Dutton 	EMU_DST_HAMOA_DAC_LEFT1, /* 14 */
2089f4bd5ddSJames Courtier-Dutton 	EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */
2099f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT, /* 16 */
2109f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+1, /* 17 */
2119f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+2, /* 18 */
2129f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+3, /* 19 */
2139f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+4, /* 20 */
2149f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+5, /* 21 */
2159f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+6, /* 22 */
2169f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+7, /* 23 */
2179f4bd5ddSJames Courtier-Dutton };
2189f4bd5ddSJames Courtier-Dutton 
2199f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_input_dst[] = {
2209f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_0,
2219f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_1,
2229f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_2,
2239f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_3,
2249f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_4,
2259f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_5,
2269f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_6,
2279f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_7,
2289f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_8,
2299f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_9,
2309f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_A,
2319f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_B,
2329f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_C,
2339f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_D,
2349f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_E,
2359f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_F,
2369f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_LEFT,
2379f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_RIGHT,
2389f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_LEFT,
2399f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_RIGHT,
2409f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_LEFT,
2419f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_RIGHT,
2429f4bd5ddSJames Courtier-Dutton };
2439f4bd5ddSJames Courtier-Dutton 
2449f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
2459f4bd5ddSJames Courtier-Dutton {
2469f4bd5ddSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2479f4bd5ddSJames Courtier-Dutton 	uinfo->count = 1;
2489f4bd5ddSJames Courtier-Dutton 	uinfo->value.enumerated.items = 53;
2499f4bd5ddSJames Courtier-Dutton 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2509f4bd5ddSJames Courtier-Dutton 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
2519f4bd5ddSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]);
2529f4bd5ddSJames Courtier-Dutton 	return 0;
2539f4bd5ddSJames Courtier-Dutton }
2549f4bd5ddSJames Courtier-Dutton 
2559f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
2569f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
2579f4bd5ddSJames Courtier-Dutton {
2589f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
2599f4bd5ddSJames Courtier-Dutton 	int channel;
2609f4bd5ddSJames Courtier-Dutton 
2619f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
2629f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
2639f4bd5ddSJames Courtier-Dutton 	return 0;
2649f4bd5ddSJames Courtier-Dutton }
2659f4bd5ddSJames Courtier-Dutton 
2669f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
2679f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
2689f4bd5ddSJames Courtier-Dutton {
2699f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
2709f4bd5ddSJames Courtier-Dutton 	int change = 0;
2719f4bd5ddSJames Courtier-Dutton 	unsigned int val;
2729f4bd5ddSJames Courtier-Dutton 	int channel;
2739f4bd5ddSJames Courtier-Dutton 
2749f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
2759f4bd5ddSJames Courtier-Dutton 	if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) {
2769f4bd5ddSJames Courtier-Dutton 		val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0];
2779f4bd5ddSJames Courtier-Dutton 		change = 1;
2789f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
2799f4bd5ddSJames Courtier-Dutton 			emu1010_output_dst[channel], emu1010_src_regs[val]);
2809f4bd5ddSJames Courtier-Dutton 	}
2819f4bd5ddSJames Courtier-Dutton 	return change;
2829f4bd5ddSJames Courtier-Dutton }
2839f4bd5ddSJames Courtier-Dutton 
2849f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
2859f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
2869f4bd5ddSJames Courtier-Dutton {
2879f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
2889f4bd5ddSJames Courtier-Dutton 	int channel;
2899f4bd5ddSJames Courtier-Dutton 
2909f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
2919f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
2929f4bd5ddSJames Courtier-Dutton 	return 0;
2939f4bd5ddSJames Courtier-Dutton }
2949f4bd5ddSJames Courtier-Dutton 
2959f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
2969f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
2979f4bd5ddSJames Courtier-Dutton {
2989f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
2999f4bd5ddSJames Courtier-Dutton 	int change = 0;
3009f4bd5ddSJames Courtier-Dutton 	unsigned int val;
3019f4bd5ddSJames Courtier-Dutton 	int channel;
3029f4bd5ddSJames Courtier-Dutton 
3039f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
3049f4bd5ddSJames Courtier-Dutton 	if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) {
3059f4bd5ddSJames Courtier-Dutton 		val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0];
3069f4bd5ddSJames Courtier-Dutton 		change = 1;
3079f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
3089f4bd5ddSJames Courtier-Dutton 			emu1010_input_dst[channel], emu1010_src_regs[val]);
3099f4bd5ddSJames Courtier-Dutton 	}
3109f4bd5ddSJames Courtier-Dutton 	return change;
3119f4bd5ddSJames Courtier-Dutton }
3129f4bd5ddSJames Courtier-Dutton 
3139f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \
3149f4bd5ddSJames Courtier-Dutton {								\
3159f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
3169f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
3179f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
3189f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_output_source_get,			\
3199f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_output_source_put,			\
3209f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
3219f4bd5ddSJames Courtier-Dutton }
3229f4bd5ddSJames Courtier-Dutton 
3239f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = {
3244c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
3254c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
3264c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
3274c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
3284c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
3294c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
3304c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6),
3314c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
3324c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
3334c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
3344c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
3354c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
3364c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
3374c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
3384c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
3394c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
3404c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
3414c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
3424c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
3434c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
3444c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
3454c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
3464c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
3474c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
3489f4bd5ddSJames Courtier-Dutton };
3499f4bd5ddSJames Courtier-Dutton 
3509f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \
3519f4bd5ddSJames Courtier-Dutton {								\
3529f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
3539f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
3549f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
3559f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_input_source_get,			\
3569f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_input_source_put,			\
3579f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
3589f4bd5ddSJames Courtier-Dutton }
3599f4bd5ddSJames Courtier-Dutton 
3609f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = {
3614c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
3624c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
3634c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
3644c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
3654c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
3664c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
3674c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
3684c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
3694c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
3704c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
3714c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
3724c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
3734c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
3744c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
3754c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
3764c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
3774c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
3784c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
3794c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
3804c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
3814c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
3824c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
3839148cc50SJames Courtier-Dutton };
3849148cc50SJames Courtier-Dutton 
3859148cc50SJames Courtier-Dutton 
3869148cc50SJames Courtier-Dutton 
3879148cc50SJames Courtier-Dutton 
3889148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
3899148cc50SJames Courtier-Dutton {
3909148cc50SJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3919148cc50SJames Courtier-Dutton 	uinfo->count = 1;
3929148cc50SJames Courtier-Dutton 	uinfo->value.integer.min = 0;
3939148cc50SJames Courtier-Dutton 	uinfo->value.integer.max = 1;
3949148cc50SJames Courtier-Dutton 	return 0;
3959148cc50SJames Courtier-Dutton }
3969148cc50SJames Courtier-Dutton 
3979148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3989148cc50SJames Courtier-Dutton {
3999148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4009148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4019148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
4029148cc50SJames Courtier-Dutton 	return 0;
4039148cc50SJames Courtier-Dutton }
4049148cc50SJames Courtier-Dutton 
4059148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4069148cc50SJames Courtier-Dutton {
4079148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4089148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4099148cc50SJames Courtier-Dutton 	unsigned int val, cache;
4109148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
4119148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
4129148cc50SJames Courtier-Dutton 	if (val == 1)
4139148cc50SJames Courtier-Dutton 		cache = cache | mask;
4149148cc50SJames Courtier-Dutton 	else
4159148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
4169148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
4179148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
4189148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
4199148cc50SJames Courtier-Dutton 	}
4209148cc50SJames Courtier-Dutton 
4219148cc50SJames Courtier-Dutton 	return 0;
4229148cc50SJames Courtier-Dutton }
4239148cc50SJames Courtier-Dutton 
4249148cc50SJames Courtier-Dutton 
4259148cc50SJames Courtier-Dutton 
4269148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \
4279148cc50SJames Courtier-Dutton {								\
4289148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
4299148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
4309148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_adc_pads_info,			\
4319148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_adc_pads_get,			\
4329148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_adc_pads_put,			\
4339148cc50SJames Courtier-Dutton 	.private_value = chid					\
4349148cc50SJames Courtier-Dutton }
4359148cc50SJames Courtier-Dutton 
4369148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = {
4379148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
4389148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
4399148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
4409148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
4419148cc50SJames Courtier-Dutton };
4429148cc50SJames Courtier-Dutton 
4439148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
4449148cc50SJames Courtier-Dutton {
4459148cc50SJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
4469148cc50SJames Courtier-Dutton 	uinfo->count = 1;
4479148cc50SJames Courtier-Dutton 	uinfo->value.integer.min = 0;
4489148cc50SJames Courtier-Dutton 	uinfo->value.integer.max = 1;
4499148cc50SJames Courtier-Dutton 	return 0;
4509148cc50SJames Courtier-Dutton }
4519148cc50SJames Courtier-Dutton 
4529148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4539148cc50SJames Courtier-Dutton {
4549148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4559148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4569148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
4579148cc50SJames Courtier-Dutton 	return 0;
4589148cc50SJames Courtier-Dutton }
4599148cc50SJames Courtier-Dutton 
4609148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4619148cc50SJames Courtier-Dutton {
4629148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4639148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4649148cc50SJames Courtier-Dutton 	unsigned int val, cache;
4659148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
4669148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
4679148cc50SJames Courtier-Dutton 	if (val == 1)
4689148cc50SJames Courtier-Dutton 		cache = cache | mask;
4699148cc50SJames Courtier-Dutton 	else
4709148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
4719148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.dac_pads) {
4729148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
4739148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
4749148cc50SJames Courtier-Dutton 	}
4759148cc50SJames Courtier-Dutton 
4769148cc50SJames Courtier-Dutton 	return 0;
4779148cc50SJames Courtier-Dutton }
4789148cc50SJames Courtier-Dutton 
4799148cc50SJames Courtier-Dutton 
4809148cc50SJames Courtier-Dutton 
4819148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \
4829148cc50SJames Courtier-Dutton {								\
4839148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
4849148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
4859148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_dac_pads_info,			\
4869148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_dac_pads_get,			\
4879148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_dac_pads_put,			\
4889148cc50SJames Courtier-Dutton 	.private_value = chid					\
4899148cc50SJames Courtier-Dutton }
4909148cc50SJames Courtier-Dutton 
4919148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = {
4929148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
4939148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
4949148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
4959148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
4969148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
4979f4bd5ddSJames Courtier-Dutton };
4989f4bd5ddSJames Courtier-Dutton 
499b0dbdaeaSJames Courtier-Dutton 
500b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
501b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
502b0dbdaeaSJames Courtier-Dutton {
503b0dbdaeaSJames Courtier-Dutton 	static char *texts[2] = {
504b0dbdaeaSJames Courtier-Dutton 		"44100", "48000"
505b0dbdaeaSJames Courtier-Dutton 	};
506b0dbdaeaSJames Courtier-Dutton 
507b0dbdaeaSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
508b0dbdaeaSJames Courtier-Dutton 	uinfo->count = 1;
509b0dbdaeaSJames Courtier-Dutton 	uinfo->value.enumerated.items = 2;
510b0dbdaeaSJames Courtier-Dutton 	if (uinfo->value.enumerated.item > 1)
511b0dbdaeaSJames Courtier-Dutton                 uinfo->value.enumerated.item = 1;
512b0dbdaeaSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
513b0dbdaeaSJames Courtier-Dutton 	return 0;
514b0dbdaeaSJames Courtier-Dutton }
515b0dbdaeaSJames Courtier-Dutton 
516b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
517b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
518b0dbdaeaSJames Courtier-Dutton {
519b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
520b0dbdaeaSJames Courtier-Dutton 
521b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
522b0dbdaeaSJames Courtier-Dutton 	return 0;
523b0dbdaeaSJames Courtier-Dutton }
524b0dbdaeaSJames Courtier-Dutton 
525b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
526b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
527b0dbdaeaSJames Courtier-Dutton {
528b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
529b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
530b0dbdaeaSJames Courtier-Dutton 	int change = 0;
531b0dbdaeaSJames Courtier-Dutton 
532b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
533b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
534b0dbdaeaSJames Courtier-Dutton 	if (change) {
535b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
536b0dbdaeaSJames Courtier-Dutton 		switch (val) {
537b0dbdaeaSJames Courtier-Dutton 		case 0:
538b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
539b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
540b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
541b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
542b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
543b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
544b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
545b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
546b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
547b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
548b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
549b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
550e40a0b2eSJames Courtier-Dutton 			msleep(10);
551b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
552b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
553b0dbdaeaSJames Courtier-Dutton 			break;
554b0dbdaeaSJames Courtier-Dutton 		case 1:
555b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
556b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
557b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
558b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
559b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
560b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
561b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
562b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
563b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
564b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
565b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
566b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
567e40a0b2eSJames Courtier-Dutton 			msleep(10);
568b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
569b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
570b0dbdaeaSJames Courtier-Dutton 			break;
571b0dbdaeaSJames Courtier-Dutton 		}
572b0dbdaeaSJames Courtier-Dutton 	}
573b0dbdaeaSJames Courtier-Dutton         return change;
574b0dbdaeaSJames Courtier-Dutton }
575b0dbdaeaSJames Courtier-Dutton 
576b0dbdaeaSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_internal_clock =
577b0dbdaeaSJames Courtier-Dutton {
578b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
579b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
580b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
581b0dbdaeaSJames Courtier-Dutton 	.count =	1,
582b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
583b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
584b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
585b0dbdaeaSJames Courtier-Dutton };
586b0dbdaeaSJames Courtier-Dutton 
587184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
588184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
589184c1e2cSJames Courtier-Dutton {
590184c1e2cSJames Courtier-Dutton #if 0
591184c1e2cSJames Courtier-Dutton 	static char *texts[4] = {
592184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
593184c1e2cSJames Courtier-Dutton 	};
594184c1e2cSJames Courtier-Dutton #endif
595184c1e2cSJames Courtier-Dutton 	static char *texts[2] = {
596184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
597184c1e2cSJames Courtier-Dutton 	};
598184c1e2cSJames Courtier-Dutton 
599184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
600184c1e2cSJames Courtier-Dutton 	uinfo->count = 1;
601184c1e2cSJames Courtier-Dutton 	uinfo->value.enumerated.items = 2;
602184c1e2cSJames Courtier-Dutton 	if (uinfo->value.enumerated.item > 1)
603184c1e2cSJames Courtier-Dutton                 uinfo->value.enumerated.item = 1;
604184c1e2cSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
605184c1e2cSJames Courtier-Dutton 	return 0;
606184c1e2cSJames Courtier-Dutton }
607184c1e2cSJames Courtier-Dutton 
608184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
609184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
610184c1e2cSJames Courtier-Dutton {
611184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
612184c1e2cSJames Courtier-Dutton 
613184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
614184c1e2cSJames Courtier-Dutton 	return 0;
615184c1e2cSJames Courtier-Dutton }
616184c1e2cSJames Courtier-Dutton 
617184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
618184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
619184c1e2cSJames Courtier-Dutton {
620184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
621184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
622184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
623184c1e2cSJames Courtier-Dutton 	u32 gpio;
624184c1e2cSJames Courtier-Dutton 	int change = 0;
625184c1e2cSJames Courtier-Dutton 	unsigned long flags;
626184c1e2cSJames Courtier-Dutton 	u32 source;
627184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
628184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
629184c1e2cSJames Courtier-Dutton 	 * for the particular source.
630184c1e2cSJames Courtier-Dutton 	 */
631184c1e2cSJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */
632184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
633184c1e2cSJames Courtier-Dutton 	if (change) {
634184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
635184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
636184c1e2cSJames Courtier-Dutton 		gpio = inl(emu->port + A_IOCFG);
637184c1e2cSJames Courtier-Dutton 		if (source_id==0)
638184c1e2cSJames Courtier-Dutton 			outl(gpio | 0x4, emu->port + A_IOCFG);
639184c1e2cSJames Courtier-Dutton 		else
640184c1e2cSJames Courtier-Dutton 			outl(gpio & ~0x4, emu->port + A_IOCFG);
641184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
642184c1e2cSJames Courtier-Dutton 
643184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
644184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
645184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
646184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
647184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
648184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
649184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
650184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
651184c1e2cSJames Courtier-Dutton 
652184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
653184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
654184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
655184c1e2cSJames Courtier-Dutton 	}
656184c1e2cSJames Courtier-Dutton         return change;
657184c1e2cSJames Courtier-Dutton }
658184c1e2cSJames Courtier-Dutton 
659184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_capture_source =
660184c1e2cSJames Courtier-Dutton {
661184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
662184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
663184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
664184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
665184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
666184c1e2cSJames Courtier-Dutton };
667184c1e2cSJames Courtier-Dutton 
668184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
669184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
670184c1e2cSJames Courtier-Dutton {
671184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
672184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
673184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
674184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
675184c1e2cSJames Courtier-Dutton 	return 0;
676184c1e2cSJames Courtier-Dutton }
677184c1e2cSJames Courtier-Dutton 
678184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
679184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
680184c1e2cSJames Courtier-Dutton {
681184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
682184c1e2cSJames Courtier-Dutton 	int source_id;
683184c1e2cSJames Courtier-Dutton 
684184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
685184c1e2cSJames Courtier-Dutton 
686184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
687184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
688184c1e2cSJames Courtier-Dutton 	return 0;
689184c1e2cSJames Courtier-Dutton }
690184c1e2cSJames Courtier-Dutton 
691184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
692184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
693184c1e2cSJames Courtier-Dutton {
694184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
695184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
696184c1e2cSJames Courtier-Dutton 	unsigned int ngain;
697184c1e2cSJames Courtier-Dutton 	int source_id;
698184c1e2cSJames Courtier-Dutton 	int change = 0;
699184c1e2cSJames Courtier-Dutton 
700184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
701184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
702184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[0];
703184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
704184c1e2cSJames Courtier-Dutton 		return 0;
705184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
706184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
707184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
708184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
709184c1e2cSJames Courtier-Dutton 		change = 1;
710184c1e2cSJames Courtier-Dutton 	}
711184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
712184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[1];
713184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
714184c1e2cSJames Courtier-Dutton 		return 0;
715184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
716184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
717184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
718184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
719184c1e2cSJames Courtier-Dutton 		change = 1;
720184c1e2cSJames Courtier-Dutton 	}
721184c1e2cSJames Courtier-Dutton 
722184c1e2cSJames Courtier-Dutton 	return change;
723184c1e2cSJames Courtier-Dutton }
724184c1e2cSJames Courtier-Dutton 
725184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \
726184c1e2cSJames Courtier-Dutton {								\
727184c1e2cSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
728184c1e2cSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
729184c1e2cSJames Courtier-Dutton 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
730184c1e2cSJames Courtier-Dutton 	.info =  snd_audigy_i2c_volume_info,			\
731184c1e2cSJames Courtier-Dutton 	.get =   snd_audigy_i2c_volume_get,			\
732184c1e2cSJames Courtier-Dutton 	.put =   snd_audigy_i2c_volume_put,			\
733184c1e2cSJames Courtier-Dutton 	.tlv = { .p = snd_audigy_db_scale2 },			\
734184c1e2cSJames Courtier-Dutton 	.private_value = chid					\
735184c1e2cSJames Courtier-Dutton }
736184c1e2cSJames Courtier-Dutton 
737184c1e2cSJames Courtier-Dutton 
738184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = {
739184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Mic Capture Volume", 0),
740184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Line Capture Volume", 0)
741184c1e2cSJames Courtier-Dutton };
742184c1e2cSJames Courtier-Dutton 
7430af68e5eSTakashi Iwai #if 0
744eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
7451da177e4SLinus Torvalds {
7461da177e4SLinus Torvalds 	static char *texts[] = {"44100", "48000", "96000"};
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
7491da177e4SLinus Torvalds 	uinfo->count = 1;
7501da177e4SLinus Torvalds 	uinfo->value.enumerated.items = 3;
7511da177e4SLinus Torvalds 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
7521da177e4SLinus Torvalds 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
7531da177e4SLinus Torvalds 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
7541da177e4SLinus Torvalds 	return 0;
7551da177e4SLinus Torvalds }
7561da177e4SLinus Torvalds 
757eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
758eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
7591da177e4SLinus Torvalds {
760eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
7611da177e4SLinus Torvalds 	unsigned int tmp;
7621da177e4SLinus Torvalds 	unsigned long flags;
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 
7651da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
7661da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
7671da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
7681da177e4SLinus Torvalds 	case A_SPDIF_44100:
7691da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
7701da177e4SLinus Torvalds 		break;
7711da177e4SLinus Torvalds 	case A_SPDIF_48000:
7721da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
7731da177e4SLinus Torvalds 		break;
7741da177e4SLinus Torvalds 	case A_SPDIF_96000:
7751da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
7761da177e4SLinus Torvalds 		break;
7771da177e4SLinus Torvalds 	default:
7781da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
7791da177e4SLinus Torvalds 	}
7801da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
7811da177e4SLinus Torvalds 	return 0;
7821da177e4SLinus Torvalds }
7831da177e4SLinus Torvalds 
784eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
785eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
7861da177e4SLinus Torvalds {
787eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
7881da177e4SLinus Torvalds 	int change;
7891da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
7901da177e4SLinus Torvalds 	unsigned long flags;
7911da177e4SLinus Torvalds 
7921da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
7931da177e4SLinus Torvalds 	case 0:
7941da177e4SLinus Torvalds 		val = A_SPDIF_44100;
7951da177e4SLinus Torvalds 		break;
7961da177e4SLinus Torvalds 	case 1:
7971da177e4SLinus Torvalds 		val = A_SPDIF_48000;
7981da177e4SLinus Torvalds 		break;
7991da177e4SLinus Torvalds 	case 2:
8001da177e4SLinus Torvalds 		val = A_SPDIF_96000;
8011da177e4SLinus Torvalds 		break;
8021da177e4SLinus Torvalds 	default:
8031da177e4SLinus Torvalds 		val = A_SPDIF_48000;
8041da177e4SLinus Torvalds 		break;
8051da177e4SLinus Torvalds 	}
8061da177e4SLinus Torvalds 
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
8091da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
8101da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
8111da177e4SLinus Torvalds 	tmp |= val;
8121da177e4SLinus Torvalds 	if ((change = (tmp != reg)))
8131da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
8141da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
8151da177e4SLinus Torvalds 	return change;
8161da177e4SLinus Torvalds }
8171da177e4SLinus Torvalds 
818eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_spdif_output_rate =
8191da177e4SLinus Torvalds {
8201da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
8211da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
8221da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
8231da177e4SLinus Torvalds 	.count =	1,
8241da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
8251da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
8261da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
8271da177e4SLinus Torvalds };
8280af68e5eSTakashi Iwai #endif
8291da177e4SLinus Torvalds 
830eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
831eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
8321da177e4SLinus Torvalds {
833eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
8341da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
8351da177e4SLinus Torvalds 	int change;
8361da177e4SLinus Torvalds 	unsigned int val;
8371da177e4SLinus Torvalds 	unsigned long flags;
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
8401da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
8411da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
8421da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
8431da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
8441da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
8451da177e4SLinus Torvalds 	if (change) {
8461da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
8471da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
8481da177e4SLinus Torvalds 	}
8491da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
8501da177e4SLinus Torvalds 	return change;
8511da177e4SLinus Torvalds }
8521da177e4SLinus Torvalds 
853eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
8541da177e4SLinus Torvalds {
8551da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
8565549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
8571da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
8581da177e4SLinus Torvalds 	.count =	4,
8591da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
8601da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
8611da177e4SLinus Torvalds };
8621da177e4SLinus Torvalds 
863eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_control =
8641da177e4SLinus Torvalds {
8655549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
8661da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
8671da177e4SLinus Torvalds 	.count =	4,
8681da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
8691da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
8701da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
8711da177e4SLinus Torvalds };
8721da177e4SLinus Torvalds 
8731da177e4SLinus Torvalds 
874eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
8751da177e4SLinus Torvalds {
8761da177e4SLinus Torvalds 	if (emu->audigy) {
8771da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
8781da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
8791da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
8801da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
8811da177e4SLinus Torvalds 	} else {
8821da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
8831da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
8841da177e4SLinus Torvalds 	}
8851da177e4SLinus Torvalds }
8861da177e4SLinus Torvalds 
887eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
8881da177e4SLinus Torvalds {
8891da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
8901da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
8911da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
8921da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
8931da177e4SLinus Torvalds 	if (emu->audigy) {
8941da177e4SLinus Torvalds 		unsigned int val = ((unsigned int)volume[4] << 24) |
8951da177e4SLinus Torvalds 			((unsigned int)volume[5] << 16) |
8961da177e4SLinus Torvalds 			((unsigned int)volume[6] << 8) |
8971da177e4SLinus Torvalds 			(unsigned int)volume[7];
8981da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
8991da177e4SLinus Torvalds 	}
9001da177e4SLinus Torvalds }
9011da177e4SLinus Torvalds 
9021da177e4SLinus Torvalds /* PCM stream controls */
9031da177e4SLinus Torvalds 
904eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9051da177e4SLinus Torvalds {
906eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
9071da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
9081da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
9091da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
9101da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
9111da177e4SLinus Torvalds 	return 0;
9121da177e4SLinus Torvalds }
9131da177e4SLinus Torvalds 
914eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
915eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
9161da177e4SLinus Torvalds {
9171da177e4SLinus Torvalds 	unsigned long flags;
918eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
919eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
920eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
9211da177e4SLinus Torvalds 	int voice, idx;
9221da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
9231da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
9241da177e4SLinus Torvalds 
9251da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
9261da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
9271da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
9281da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
9291da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
9301da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
9311da177e4SLinus Torvalds 	return 0;
9321da177e4SLinus Torvalds }
9331da177e4SLinus Torvalds 
934eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
935eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
9361da177e4SLinus Torvalds {
9371da177e4SLinus Torvalds 	unsigned long flags;
938eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
939eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
940eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
9411da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
9421da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
9431da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
9441da177e4SLinus Torvalds 
9451da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
9461da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
9471da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
9481da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
9491da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
9501da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
9511da177e4SLinus Torvalds 				change = 1;
9521da177e4SLinus Torvalds 			}
9531da177e4SLinus Torvalds 		}
9541da177e4SLinus Torvalds 	if (change && mix->epcm) {
9551da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
9561da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
9571da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
9581da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
9591da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
9601da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
9611da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
9621da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
9631da177e4SLinus Torvalds 		}
9641da177e4SLinus Torvalds 	}
9651da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
9661da177e4SLinus Torvalds 	return change;
9671da177e4SLinus Torvalds }
9681da177e4SLinus Torvalds 
969eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_routing_control =
9701da177e4SLinus Torvalds {
9711da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
97267ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
9731da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
9741da177e4SLinus Torvalds 	.count =	32,
9751da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
9761da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
9771da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
9781da177e4SLinus Torvalds };
9791da177e4SLinus Torvalds 
980eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9811da177e4SLinus Torvalds {
982eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
9831da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
9841da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
9851da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
9861da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
9871da177e4SLinus Torvalds 	return 0;
9881da177e4SLinus Torvalds }
9891da177e4SLinus Torvalds 
990eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
991eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
9921da177e4SLinus Torvalds {
9931da177e4SLinus Torvalds 	unsigned long flags;
994eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
995eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
996eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
9971da177e4SLinus Torvalds 	int idx;
9981da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
9991da177e4SLinus Torvalds 
10001da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10011da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
10021da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
10031da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10041da177e4SLinus Torvalds 	return 0;
10051da177e4SLinus Torvalds }
10061da177e4SLinus Torvalds 
1007eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1008eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
10091da177e4SLinus Torvalds {
10101da177e4SLinus Torvalds 	unsigned long flags;
1011eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1012eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1013eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10141da177e4SLinus Torvalds 	int change = 0, idx, val;
10151da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
10161da177e4SLinus Torvalds 
10171da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10181da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
10191da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
10201da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
10211da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
10221da177e4SLinus Torvalds 			change = 1;
10231da177e4SLinus Torvalds 		}
10241da177e4SLinus Torvalds 	}
10251da177e4SLinus Torvalds 	if (change && mix->epcm) {
10261da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
10271da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
10281da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
10291da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
10301da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
10311da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
10321da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
10331da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
10341da177e4SLinus Torvalds 		}
10351da177e4SLinus Torvalds 	}
10361da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10371da177e4SLinus Torvalds 	return change;
10381da177e4SLinus Torvalds }
10391da177e4SLinus Torvalds 
1040eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_volume_control =
10411da177e4SLinus Torvalds {
10421da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
104367ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
10441da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
10451da177e4SLinus Torvalds 	.count =	32,
10461da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
10471da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
10481da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
10491da177e4SLinus Torvalds };
10501da177e4SLinus Torvalds 
1051eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
10521da177e4SLinus Torvalds {
10531da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
10541da177e4SLinus Torvalds 	uinfo->count = 3;
10551da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
10561da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
10571da177e4SLinus Torvalds 	return 0;
10581da177e4SLinus Torvalds }
10591da177e4SLinus Torvalds 
1060eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1061eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
10621da177e4SLinus Torvalds {
1063eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1064eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1065eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10661da177e4SLinus Torvalds 	unsigned long flags;
10671da177e4SLinus Torvalds 	int idx;
10681da177e4SLinus Torvalds 
10691da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10701da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
10711da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->attn[idx];
10721da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10731da177e4SLinus Torvalds 	return 0;
10741da177e4SLinus Torvalds }
10751da177e4SLinus Torvalds 
1076eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1077eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
10781da177e4SLinus Torvalds {
10791da177e4SLinus Torvalds 	unsigned long flags;
1080eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1081eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1082eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10831da177e4SLinus Torvalds 	int change = 0, idx, val;
10841da177e4SLinus Torvalds 
10851da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10861da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
10871da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 0xffff;
10881da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
10891da177e4SLinus Torvalds 			mix->attn[idx] = val;
10901da177e4SLinus Torvalds 			change = 1;
10911da177e4SLinus Torvalds 		}
10921da177e4SLinus Torvalds 	}
10931da177e4SLinus Torvalds 	if (change && mix->epcm) {
10941da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
10951da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
10961da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
10971da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
10981da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
10991da177e4SLinus Torvalds 		}
11001da177e4SLinus Torvalds 	}
11011da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11021da177e4SLinus Torvalds 	return change;
11031da177e4SLinus Torvalds }
11041da177e4SLinus Torvalds 
1105eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_attn_control =
11061da177e4SLinus Torvalds {
11071da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
110867ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11091da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
11101da177e4SLinus Torvalds 	.count =	32,
11111da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
11121da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
11131da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
11141da177e4SLinus Torvalds };
11151da177e4SLinus Torvalds 
11161da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
11171da177e4SLinus Torvalds 
1118eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11191da177e4SLinus Torvalds {
1120eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11211da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
11221da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
11231da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11241da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
11251da177e4SLinus Torvalds 	return 0;
11261da177e4SLinus Torvalds }
11271da177e4SLinus Torvalds 
1128eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1129eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11301da177e4SLinus Torvalds {
11311da177e4SLinus Torvalds 	unsigned long flags;
1132eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1133eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1134eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11351da177e4SLinus Torvalds 	int idx;
11361da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11371da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11381da177e4SLinus Torvalds 
11391da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11401da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
11411da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
11421da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
11431da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11441da177e4SLinus Torvalds 	return 0;
11451da177e4SLinus Torvalds }
11461da177e4SLinus Torvalds 
1147eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1148eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11491da177e4SLinus Torvalds {
11501da177e4SLinus Torvalds 	unsigned long flags;
1151eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11521da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1153eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
11541da177e4SLinus Torvalds 	int change = 0, idx, val;
11551da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11561da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11591da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
11601da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
11611da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
11621da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
11631da177e4SLinus Torvalds 			change = 1;
11641da177e4SLinus Torvalds 		}
11651da177e4SLinus Torvalds 	}
11661da177e4SLinus Torvalds 
11671da177e4SLinus Torvalds 	if (change && mix->epcm) {
11681da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
11691da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
11701da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
11711da177e4SLinus Torvalds 		}
11721da177e4SLinus Torvalds 	}
11731da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11741da177e4SLinus Torvalds 	return change;
11751da177e4SLinus Torvalds }
11761da177e4SLinus Torvalds 
1177eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
11781da177e4SLinus Torvalds {
11791da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
11801da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11811da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
11821da177e4SLinus Torvalds 	.count =	16,
11831da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
11841da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
11851da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
11861da177e4SLinus Torvalds };
11871da177e4SLinus Torvalds 
1188eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11891da177e4SLinus Torvalds {
1190eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11911da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
11921da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
11931da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11941da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
11951da177e4SLinus Torvalds 	return 0;
11961da177e4SLinus Torvalds }
11971da177e4SLinus Torvalds 
1198eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1199eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12001da177e4SLinus Torvalds {
12011da177e4SLinus Torvalds 	unsigned long flags;
1202eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1203eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1204eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12051da177e4SLinus Torvalds 	int idx;
12061da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12071da177e4SLinus Torvalds 
12081da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12091da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
12101da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
12111da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12121da177e4SLinus Torvalds 	return 0;
12131da177e4SLinus Torvalds }
12141da177e4SLinus Torvalds 
1215eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1216eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12171da177e4SLinus Torvalds {
12181da177e4SLinus Torvalds 	unsigned long flags;
1219eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12201da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1221eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
12221da177e4SLinus Torvalds 	int change = 0, idx, val;
12231da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12241da177e4SLinus Torvalds 
12251da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12261da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
12271da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
12281da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
12291da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
12301da177e4SLinus Torvalds 			change = 1;
12311da177e4SLinus Torvalds 		}
12321da177e4SLinus Torvalds 	}
12331da177e4SLinus Torvalds 	if (change && mix->epcm) {
12341da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
12351da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
12361da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
12371da177e4SLinus Torvalds 		}
12381da177e4SLinus Torvalds 	}
12391da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12401da177e4SLinus Torvalds 	return change;
12411da177e4SLinus Torvalds }
12421da177e4SLinus Torvalds 
12431da177e4SLinus Torvalds 
1244eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
12451da177e4SLinus Torvalds {
12461da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
12471da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12481da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
12491da177e4SLinus Torvalds 	.count =	16,
12501da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
12511da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
12521da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
12531da177e4SLinus Torvalds };
12541da177e4SLinus Torvalds 
1255eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12561da177e4SLinus Torvalds {
12571da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12581da177e4SLinus Torvalds 	uinfo->count = 1;
12591da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12601da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
12611da177e4SLinus Torvalds 	return 0;
12621da177e4SLinus Torvalds }
12631da177e4SLinus Torvalds 
1264eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1265eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
12661da177e4SLinus Torvalds {
1267eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1268eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1269eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12701da177e4SLinus Torvalds 	unsigned long flags;
12711da177e4SLinus Torvalds 
12721da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12731da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = mix->attn[0];
12741da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12751da177e4SLinus Torvalds 	return 0;
12761da177e4SLinus Torvalds }
12771da177e4SLinus Torvalds 
1278eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1279eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
12801da177e4SLinus Torvalds {
12811da177e4SLinus Torvalds 	unsigned long flags;
1282eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12831da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1284eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
12851da177e4SLinus Torvalds 	int change = 0, val;
12861da177e4SLinus Torvalds 
12871da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12881da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] & 0xffff;
12891da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
12901da177e4SLinus Torvalds 		mix->attn[0] = val;
12911da177e4SLinus Torvalds 		change = 1;
12921da177e4SLinus Torvalds 	}
12931da177e4SLinus Torvalds 	if (change && mix->epcm) {
12941da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
12951da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
12961da177e4SLinus Torvalds 		}
12971da177e4SLinus Torvalds 	}
12981da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12991da177e4SLinus Torvalds 	return change;
13001da177e4SLinus Torvalds }
13011da177e4SLinus Torvalds 
1302eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
13031da177e4SLinus Torvalds {
13041da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
13051da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13061da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
13071da177e4SLinus Torvalds 	.count =	16,
13081da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
13091da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
13101da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
13111da177e4SLinus Torvalds };
13121da177e4SLinus Torvalds 
1313eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13141da177e4SLinus Torvalds {
13151da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
13161da177e4SLinus Torvalds 	uinfo->count = 1;
13171da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13181da177e4SLinus Torvalds 	uinfo->value.integer.max = 1;
13191da177e4SLinus Torvalds 	return 0;
13201da177e4SLinus Torvalds }
13211da177e4SLinus Torvalds 
1322eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1323eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
13241da177e4SLinus Torvalds {
1325eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13261da177e4SLinus Torvalds 
13271da177e4SLinus Torvalds 	if (emu->audigy)
13281da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
13291da177e4SLinus Torvalds 	else
13301da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
13311da177e4SLinus Torvalds 	return 0;
13321da177e4SLinus Torvalds }
13331da177e4SLinus Torvalds 
1334eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1335eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
13361da177e4SLinus Torvalds {
13371da177e4SLinus Torvalds 	unsigned long flags;
1338eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13391da177e4SLinus Torvalds 	unsigned int reg, val;
13401da177e4SLinus Torvalds 	int change = 0;
13411da177e4SLinus Torvalds 
13421da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1343184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1344184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1345184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
13461da177e4SLinus Torvalds 		reg = inl(emu->port + A_IOCFG);
13471da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
13481da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
13491da177e4SLinus Torvalds 		if (change) {
13501da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
13511da177e4SLinus Torvalds 			reg |= val;
13521da177e4SLinus Torvalds 			outl(reg | val, emu->port + A_IOCFG);
13531da177e4SLinus Torvalds 		}
13541da177e4SLinus Torvalds 	}
13551da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
13561da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0;
13571da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
13581da177e4SLinus Torvalds 	if (change) {
13591da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
13601da177e4SLinus Torvalds 		reg |= val;
13611da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
13621da177e4SLinus Torvalds 	}
13631da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13641da177e4SLinus Torvalds 	return change;
13651da177e4SLinus Torvalds }
13661da177e4SLinus Torvalds 
1367eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata =
13681da177e4SLinus Torvalds {
13691da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
13701da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
13711da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
13721da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
13731da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
13741da177e4SLinus Torvalds };
13751da177e4SLinus Torvalds 
1376eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata =
13771da177e4SLinus Torvalds {
13781da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
13791da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
13801da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
13811da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
13821da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
13831da177e4SLinus Torvalds };
13841da177e4SLinus Torvalds 
13851da177e4SLinus Torvalds /*
13861da177e4SLinus Torvalds  */
1387eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
13881da177e4SLinus Torvalds {
1389eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
13901da177e4SLinus Torvalds 	emu->ac97 = NULL;
13911da177e4SLinus Torvalds }
13921da177e4SLinus Torvalds 
13931da177e4SLinus Torvalds /*
13941da177e4SLinus Torvalds  */
1395eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
13961da177e4SLinus Torvalds {
1397eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
13981da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
13991da177e4SLinus Torvalds 	strcpy(id.name, name);
14001da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
14011da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
14021da177e4SLinus Torvalds }
14031da177e4SLinus Torvalds 
1404eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
14051da177e4SLinus Torvalds {
1406eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
14071da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
14081da177e4SLinus Torvalds 	strcpy(sid.name, name);
14091da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
14101da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
14111da177e4SLinus Torvalds }
14121da177e4SLinus Torvalds 
1413eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
14141da177e4SLinus Torvalds {
1415eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
14161da177e4SLinus Torvalds 	if (kctl) {
14171da177e4SLinus Torvalds 		strcpy(kctl->id.name, dst);
14181da177e4SLinus Torvalds 		return 0;
14191da177e4SLinus Torvalds 	}
14201da177e4SLinus Torvalds 	return -ENOENT;
14211da177e4SLinus Torvalds }
14221da177e4SLinus Torvalds 
1423eb4698f3STakashi Iwai int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
142467ed4161SClemens Ladisch 				int pcm_device, int multi_device)
14251da177e4SLinus Torvalds {
14261da177e4SLinus Torvalds 	int err, pcm;
1427eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1428eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
14291da177e4SLinus Torvalds 	char **c;
14301da177e4SLinus Torvalds 	static char *emu10k1_remove_ctls[] = {
14311da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
14321da177e4SLinus Torvalds 		"Master Mono Playback Switch",
14331da177e4SLinus Torvalds 		"Master Mono Playback Volume",
14341da177e4SLinus Torvalds 		"PCM Out Path & Mute",
14351da177e4SLinus Torvalds 		"Mono Output Select",
14367eae36fbSTakashi Iwai 		"Front Playback Switch",
14377eae36fbSTakashi Iwai 		"Front Playback Volume",
14381da177e4SLinus Torvalds 		"Surround Playback Switch",
14391da177e4SLinus Torvalds 		"Surround Playback Volume",
14401da177e4SLinus Torvalds 		"Center Playback Switch",
14411da177e4SLinus Torvalds 		"Center Playback Volume",
14421da177e4SLinus Torvalds 		"LFE Playback Switch",
14431da177e4SLinus Torvalds 		"LFE Playback Volume",
14441da177e4SLinus Torvalds 		NULL
14451da177e4SLinus Torvalds 	};
14461da177e4SLinus Torvalds 	static char *emu10k1_rename_ctls[] = {
14471da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
14481da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
14491da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
14501da177e4SLinus Torvalds 		NULL
14511da177e4SLinus Torvalds 	};
14521da177e4SLinus Torvalds 	static char *audigy_remove_ctls[] = {
14531da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
145421fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
145521fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
14561da177e4SLinus Torvalds 		"PCM Playback Switch",
14571da177e4SLinus Torvalds 		"PCM Playback Volume",
14581da177e4SLinus Torvalds 		"Master Mono Playback Switch",
14591da177e4SLinus Torvalds 		"Master Mono Playback Volume",
14601da177e4SLinus Torvalds 		"Master Playback Switch",
14611da177e4SLinus Torvalds 		"Master Playback Volume",
14621da177e4SLinus Torvalds 		"PCM Out Path & Mute",
14631da177e4SLinus Torvalds 		"Mono Output Select",
14641da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
14651da177e4SLinus Torvalds 		"Capture Source",
14661da177e4SLinus Torvalds 		"Capture Switch",
14671da177e4SLinus Torvalds 		"Capture Volume",
14681da177e4SLinus Torvalds 		"Mic Select",
14691da177e4SLinus Torvalds 		"Video Playback Switch",
14701da177e4SLinus Torvalds 		"Video Playback Volume",
14711da177e4SLinus Torvalds 		"Mic Playback Switch",
14721da177e4SLinus Torvalds 		"Mic Playback Volume",
14731da177e4SLinus Torvalds 		NULL
14741da177e4SLinus Torvalds 	};
14751da177e4SLinus Torvalds 	static char *audigy_rename_ctls[] = {
14761da177e4SLinus Torvalds 		/* use conventional names */
14771da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
14781da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
14791da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
14801da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
14811da177e4SLinus Torvalds 		NULL
14821da177e4SLinus Torvalds 	};
1483184c1e2cSJames Courtier-Dutton 	static char *audigy_rename_ctls_i2c_adc[] = {
1484184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1485184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1486184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1487184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1488184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1489184c1e2cSJames Courtier-Dutton 		NULL
1490184c1e2cSJames Courtier-Dutton 	};
1491184c1e2cSJames Courtier-Dutton 	static char *audigy_remove_ctls_i2c_adc[] = {
1492184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1493184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1494184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1495184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1496184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1497184c1e2cSJames Courtier-Dutton 		NULL
1498184c1e2cSJames Courtier-Dutton 	};
149921fdddeaSJames Courtier-Dutton 	static char *audigy_remove_ctls_1361t_adc[] = {
150021fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
150121fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
150221fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
150321fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
150421fdddeaSJames Courtier-Dutton 		"Master Mono Playback Switch",
150521fdddeaSJames Courtier-Dutton 		"Master Mono Playback Volume",
150621fdddeaSJames Courtier-Dutton 		"Capture Source",
150721fdddeaSJames Courtier-Dutton 		"Capture Switch",
150821fdddeaSJames Courtier-Dutton 		"Capture Volume",
150921fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
151021fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
151121fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
151221fdddeaSJames Courtier-Dutton 		"3D Control - Center",
151321fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
151421fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
151521fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
151621fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
151721fdddeaSJames Courtier-Dutton 		NULL
151821fdddeaSJames Courtier-Dutton 	};
151921fdddeaSJames Courtier-Dutton 	static char *audigy_rename_ctls_1361t_adc[] = {
152021fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
152121fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
152221fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
152321fdddeaSJames Courtier-Dutton 		"PC Speaker Playback Switch", "PC Speaker Capture Switch",
152421fdddeaSJames Courtier-Dutton 		"PC Speaker Playback Volume", "PC Speaker Capture Volume",
152521fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
152621fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
152721fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
152821fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
152921fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
153021fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
153121fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
153221fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
153321fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
153421fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
153521fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
153621fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
153721fdddeaSJames Courtier-Dutton 
153821fdddeaSJames Courtier-Dutton 		NULL
153921fdddeaSJames Courtier-Dutton 	};
15401da177e4SLinus Torvalds 
15412b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1542eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1543eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
1544eb4698f3STakashi Iwai 		static struct snd_ac97_bus_ops ops = {
15451da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
15461da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
15471da177e4SLinus Torvalds 		};
15481da177e4SLinus Torvalds 
1549b1508693STakashi Iwai 		if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0)
15501da177e4SLinus Torvalds 			return err;
15511da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
15521da177e4SLinus Torvalds 
15531da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
15541da177e4SLinus Torvalds 		ac97.private_data = emu;
15551da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
15561da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
1557b1508693STakashi Iwai 		if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
1558b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
15591da177e4SLinus Torvalds 				return err;
1560b1508693STakashi Iwai 			snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n");
1561b1508693STakashi Iwai 			snd_printd(KERN_INFO"          Proceeding without ac97 mixers...\n");
1562b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1563b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1564b1508693STakashi Iwai 		}
15651da177e4SLinus Torvalds 		if (emu->audigy) {
15661da177e4SLinus Torvalds 			/* set master volume to 0 dB */
15674d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
15681da177e4SLinus Torvalds 			/* set capture source to mic */
15694d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
157021fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
157121fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
157221fdddeaSJames Courtier-Dutton 			else
15731da177e4SLinus Torvalds 				c = audigy_remove_ctls;
15741da177e4SLinus Torvalds 		} else {
15751da177e4SLinus Torvalds 			/*
15761da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
15771da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
15781da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
15791da177e4SLinus Torvalds 			 */
15801da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
15811da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
15821da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
15831da177e4SLinus Torvalds 			}
15841da177e4SLinus Torvalds 			/* remove unused AC97 controls */
15854d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
15864d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
15871da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
15881da177e4SLinus Torvalds 		}
15891da177e4SLinus Torvalds 		for (; *c; c++)
15901da177e4SLinus Torvalds 			remove_ctl(card, *c);
1591184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1592184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1593184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1594184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
15951da177e4SLinus Torvalds 	} else {
1596f12aa40cSTakashi Iwai 	no_ac97:
15972b637da5SLee Revell 		if (emu->card_capabilities->ecard)
15981da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
15991da177e4SLinus Torvalds 		else if (emu->audigy)
16001da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
16011da177e4SLinus Torvalds 		else
16021da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
16031da177e4SLinus Torvalds 	}
16041da177e4SLinus Torvalds 
16051da177e4SLinus Torvalds 	if (emu->audigy)
160621fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
160721fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1608184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1609184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
161021fdddeaSJames Courtier-Dutton 		else
16111da177e4SLinus Torvalds 			c = audigy_rename_ctls;
16121da177e4SLinus Torvalds 	else
16131da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
16141da177e4SLinus Torvalds 	for (; *c; c += 2)
16151da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
161621fdddeaSJames Courtier-Dutton 
1617e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1618e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1619e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1620e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1621e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1622e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Switch");
1623e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Volume");
1624e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Center");
1625e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Depth");
1626e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Switch");
1627e3b9bc0eSJames Courtier-Dutton 	}
16281da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
16291da177e4SLinus Torvalds 		return -ENOMEM;
163067ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
16311da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16321da177e4SLinus Torvalds 		return err;
16331da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
16341da177e4SLinus Torvalds 		return -ENOMEM;
163567ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
16361da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16371da177e4SLinus Torvalds 		return err;
16381da177e4SLinus Torvalds 	if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
16391da177e4SLinus Torvalds 		return -ENOMEM;
164067ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
16411da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16421da177e4SLinus Torvalds 		return err;
16431da177e4SLinus Torvalds 
16441da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
16451da177e4SLinus Torvalds 		return -ENOMEM;
164667ed4161SClemens Ladisch 	kctl->id.device = multi_device;
16471da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16481da177e4SLinus Torvalds 		return err;
16491da177e4SLinus Torvalds 
16501da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
16511da177e4SLinus Torvalds 		return -ENOMEM;
165267ed4161SClemens Ladisch 	kctl->id.device = multi_device;
16531da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16541da177e4SLinus Torvalds 		return err;
16551da177e4SLinus Torvalds 
16561da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
16571da177e4SLinus Torvalds 		return -ENOMEM;
165867ed4161SClemens Ladisch 	kctl->id.device = multi_device;
16591da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16601da177e4SLinus Torvalds 		return err;
16611da177e4SLinus Torvalds 
16621da177e4SLinus Torvalds 	/* initialize the routing and volume table for each pcm playback stream */
16631da177e4SLinus Torvalds 	for (pcm = 0; pcm < 32; pcm++) {
1664eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
16651da177e4SLinus Torvalds 		int v;
16661da177e4SLinus Torvalds 
16671da177e4SLinus Torvalds 		mix = &emu->pcm_mixer[pcm];
16681da177e4SLinus Torvalds 		mix->epcm = NULL;
16691da177e4SLinus Torvalds 
16701da177e4SLinus Torvalds 		for (v = 0; v < 4; v++)
16711da177e4SLinus Torvalds 			mix->send_routing[0][v] =
16721da177e4SLinus Torvalds 				mix->send_routing[1][v] =
16731da177e4SLinus Torvalds 				mix->send_routing[2][v] = v;
16741da177e4SLinus Torvalds 
16751da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
16761da177e4SLinus Torvalds 		mix->send_volume[0][0] = mix->send_volume[0][1] =
16771da177e4SLinus Torvalds 		mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
16781da177e4SLinus Torvalds 
16791da177e4SLinus Torvalds 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
16801da177e4SLinus Torvalds 	}
16811da177e4SLinus Torvalds 
16821da177e4SLinus Torvalds 	/* initialize the routing and volume table for the multichannel playback stream */
16831da177e4SLinus Torvalds 	for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
1684eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
16851da177e4SLinus Torvalds 		int v;
16861da177e4SLinus Torvalds 
16871da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[pcm];
16881da177e4SLinus Torvalds 		mix->epcm = NULL;
16891da177e4SLinus Torvalds 
16901da177e4SLinus Torvalds 		mix->send_routing[0][0] = pcm;
16911da177e4SLinus Torvalds 		mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
16921da177e4SLinus Torvalds 		for (v = 0; v < 2; v++)
16931da177e4SLinus Torvalds 			mix->send_routing[0][2+v] = 13+v;
16941da177e4SLinus Torvalds 		if (emu->audigy)
16951da177e4SLinus Torvalds 			for (v = 0; v < 4; v++)
16961da177e4SLinus Torvalds 				mix->send_routing[0][4+v] = 60+v;
16971da177e4SLinus Torvalds 
16981da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
16991da177e4SLinus Torvalds 		mix->send_volume[0][0]  = 255;
17001da177e4SLinus Torvalds 
17011da177e4SLinus Torvalds 		mix->attn[0] = 0xffff;
17021da177e4SLinus Torvalds 	}
17031da177e4SLinus Torvalds 
17042b637da5SLee Revell 	if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
17051da177e4SLinus Torvalds 		/* sb live! and audigy */
17061da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
17071da177e4SLinus Torvalds 			return -ENOMEM;
17085549d549SClemens Ladisch 		if (!emu->audigy)
17095549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
17101da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17111da177e4SLinus Torvalds 			return err;
17121da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
17131da177e4SLinus Torvalds 			return -ENOMEM;
17145549d549SClemens Ladisch 		if (!emu->audigy)
17155549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
17161da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17171da177e4SLinus Torvalds 			return err;
17181da177e4SLinus Torvalds 	}
17191da177e4SLinus Torvalds 
17209f4bd5ddSJames Courtier-Dutton 	if ( emu->card_capabilities->emu1010) {
172119b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
172219b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
17231da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
17241da177e4SLinus Torvalds 			return -ENOMEM;
17251da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17261da177e4SLinus Torvalds 			return err;
1727001f7589SJames Courtier-Dutton #if 0
17281da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
17291da177e4SLinus Torvalds 			return -ENOMEM;
17301da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17311da177e4SLinus Torvalds 			return err;
1732001f7589SJames Courtier-Dutton #endif
17332b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
17341da177e4SLinus Torvalds 		/* sb live! */
17351da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
17361da177e4SLinus Torvalds 			return -ENOMEM;
17371da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17381da177e4SLinus Torvalds 			return err;
17391da177e4SLinus Torvalds 	}
17402b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
17411da177e4SLinus Torvalds 		if ((err = snd_p16v_mixer(emu)))
17421da177e4SLinus Torvalds 			return err;
17431da177e4SLinus Torvalds 	}
17441da177e4SLinus Torvalds 
17459f4bd5ddSJames Courtier-Dutton 	if ( emu->card_capabilities->emu1010) {
17469f4bd5ddSJames Courtier-Dutton 		int i;
17479f4bd5ddSJames Courtier-Dutton 
17489f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
17499f4bd5ddSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu));
17509f4bd5ddSJames Courtier-Dutton 			if (err < 0)
17519f4bd5ddSJames Courtier-Dutton 				return err;
17529f4bd5ddSJames Courtier-Dutton 		}
17539f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
17549f4bd5ddSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu));
17559f4bd5ddSJames Courtier-Dutton 			if (err < 0)
17569f4bd5ddSJames Courtier-Dutton 				return err;
17579f4bd5ddSJames Courtier-Dutton 		}
17589148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
17599148cc50SJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
17609148cc50SJames Courtier-Dutton 			if (err < 0)
17619148cc50SJames Courtier-Dutton 				return err;
17629148cc50SJames Courtier-Dutton 		}
17639148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
17649148cc50SJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
17659148cc50SJames Courtier-Dutton 			if (err < 0)
17669148cc50SJames Courtier-Dutton 				return err;
17679148cc50SJames Courtier-Dutton 		}
1768b0dbdaeaSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu));
1769b0dbdaeaSJames Courtier-Dutton 		if (err < 0)
1770b0dbdaeaSJames Courtier-Dutton 			return err;
17719f4bd5ddSJames Courtier-Dutton 	}
17729f4bd5ddSJames Courtier-Dutton 
1773184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1774184c1e2cSJames Courtier-Dutton 		int i;
1775184c1e2cSJames Courtier-Dutton 
1776184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
1777184c1e2cSJames Courtier-Dutton 		if (err < 0)
1778184c1e2cSJames Courtier-Dutton 			return err;
1779184c1e2cSJames Courtier-Dutton 
1780184c1e2cSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
1781184c1e2cSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
1782184c1e2cSJames Courtier-Dutton 			if (err < 0)
1783184c1e2cSJames Courtier-Dutton 				return err;
1784184c1e2cSJames Courtier-Dutton 		}
1785184c1e2cSJames Courtier-Dutton 	}
1786184c1e2cSJames Courtier-Dutton 
17871da177e4SLinus Torvalds 	return 0;
17881da177e4SLinus Torvalds }
1789