xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision 50164f69f8c71377bfa3d356b8a6bc18b2197a45)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
3c1017a4cSJaroslav Kysela  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
41da177e4SLinus Torvalds  *                   Takashi Iwai <tiwai@suse.de>
51da177e4SLinus Torvalds  *                   Creative Labs, Inc.
61da177e4SLinus Torvalds  *  Routines for control of EMU10K1 chips / mixer routines
71da177e4SLinus Torvalds  *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
81da177e4SLinus Torvalds  *
99f4bd5ddSJames Courtier-Dutton  *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
109f4bd5ddSJames Courtier-Dutton  *  	Added EMU 1010 support.
119f4bd5ddSJames Courtier-Dutton  *
121da177e4SLinus Torvalds  *  BUGS:
131da177e4SLinus Torvalds  *    --
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  *  TODO:
161da177e4SLinus Torvalds  *    --
171da177e4SLinus Torvalds  */
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds #include <linux/time.h>
201da177e4SLinus Torvalds #include <linux/init.h>
211da177e4SLinus Torvalds #include <sound/core.h>
221da177e4SLinus Torvalds #include <sound/emu10k1.h>
23b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h>
24184c1e2cSJames Courtier-Dutton #include <sound/tlv.h>
25184c1e2cSJames Courtier-Dutton 
26184c1e2cSJames Courtier-Dutton #include "p17v.h"
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #define AC97_ID_STAC9758	0x83847658
291da177e4SLinus Torvalds 
300cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
31184c1e2cSJames Courtier-Dutton 
32eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
331da177e4SLinus Torvalds {
341da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
351da177e4SLinus Torvalds 	uinfo->count = 1;
361da177e4SLinus Torvalds 	return 0;
371da177e4SLinus Torvalds }
381da177e4SLinus Torvalds 
39eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
40eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
411da177e4SLinus Torvalds {
42eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
431da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
441da177e4SLinus Torvalds 	unsigned long flags;
451da177e4SLinus Torvalds 
4674415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
4774415a36SJames Courtier-Dutton 	if (idx >= 3)
4874415a36SJames Courtier-Dutton 		return -EINVAL;
491da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
501da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
511da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
521da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
531da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
541da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
551da177e4SLinus Torvalds 	return 0;
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds 
58eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
59eb4698f3STakashi Iwai 				      struct snd_ctl_elem_value *ucontrol)
601da177e4SLinus Torvalds {
611da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
621da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
631da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
641da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
651da177e4SLinus Torvalds 	return 0;
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds 
6813d45709SPavel Hofman /*
6913d45709SPavel Hofman  * Items labels in enum mixer controls assigning source data to
7013d45709SPavel Hofman  * each destination
7113d45709SPavel Hofman  */
721541c66dSTakashi Iwai static const char * const emu1010_src_texts[] = {
739f4bd5ddSJames Courtier-Dutton 	"Silence",
749f4bd5ddSJames Courtier-Dutton 	"Dock Mic A",
759f4bd5ddSJames Courtier-Dutton 	"Dock Mic B",
769f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Left",
779f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Right",
789f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Left",
799f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Right",
809f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Left",
819f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Right",
829f4bd5ddSJames Courtier-Dutton 	"0202 ADC Left",
839f4bd5ddSJames Courtier-Dutton 	"0202 ADC Right",
849f4bd5ddSJames Courtier-Dutton 	"0202 SPDIF Left",
859f4bd5ddSJames Courtier-Dutton 	"0202 SPDIF Right",
869f4bd5ddSJames Courtier-Dutton 	"ADAT 0",
879f4bd5ddSJames Courtier-Dutton 	"ADAT 1",
889f4bd5ddSJames Courtier-Dutton 	"ADAT 2",
899f4bd5ddSJames Courtier-Dutton 	"ADAT 3",
909f4bd5ddSJames Courtier-Dutton 	"ADAT 4",
919f4bd5ddSJames Courtier-Dutton 	"ADAT 5",
929f4bd5ddSJames Courtier-Dutton 	"ADAT 6",
939f4bd5ddSJames Courtier-Dutton 	"ADAT 7",
949f4bd5ddSJames Courtier-Dutton 	"DSP 0",
959f4bd5ddSJames Courtier-Dutton 	"DSP 1",
969f4bd5ddSJames Courtier-Dutton 	"DSP 2",
979f4bd5ddSJames Courtier-Dutton 	"DSP 3",
989f4bd5ddSJames Courtier-Dutton 	"DSP 4",
999f4bd5ddSJames Courtier-Dutton 	"DSP 5",
1009f4bd5ddSJames Courtier-Dutton 	"DSP 6",
1019f4bd5ddSJames Courtier-Dutton 	"DSP 7",
1029f4bd5ddSJames Courtier-Dutton 	"DSP 8",
1039f4bd5ddSJames Courtier-Dutton 	"DSP 9",
1049f4bd5ddSJames Courtier-Dutton 	"DSP 10",
1059f4bd5ddSJames Courtier-Dutton 	"DSP 11",
1069f4bd5ddSJames Courtier-Dutton 	"DSP 12",
1079f4bd5ddSJames Courtier-Dutton 	"DSP 13",
1089f4bd5ddSJames Courtier-Dutton 	"DSP 14",
1099f4bd5ddSJames Courtier-Dutton 	"DSP 15",
1109f4bd5ddSJames Courtier-Dutton 	"DSP 16",
1119f4bd5ddSJames Courtier-Dutton 	"DSP 17",
1129f4bd5ddSJames Courtier-Dutton 	"DSP 18",
1139f4bd5ddSJames Courtier-Dutton 	"DSP 19",
1149f4bd5ddSJames Courtier-Dutton 	"DSP 20",
1159f4bd5ddSJames Courtier-Dutton 	"DSP 21",
1169f4bd5ddSJames Courtier-Dutton 	"DSP 22",
1179f4bd5ddSJames Courtier-Dutton 	"DSP 23",
1189f4bd5ddSJames Courtier-Dutton 	"DSP 24",
1199f4bd5ddSJames Courtier-Dutton 	"DSP 25",
1209f4bd5ddSJames Courtier-Dutton 	"DSP 26",
1219f4bd5ddSJames Courtier-Dutton 	"DSP 27",
1229f4bd5ddSJames Courtier-Dutton 	"DSP 28",
1239f4bd5ddSJames Courtier-Dutton 	"DSP 29",
1249f4bd5ddSJames Courtier-Dutton 	"DSP 30",
1259f4bd5ddSJames Courtier-Dutton 	"DSP 31",
1269f4bd5ddSJames Courtier-Dutton };
1279f4bd5ddSJames Courtier-Dutton 
1281c02e366SCtirad Fertr /* 1616(m) cardbus */
1291c02e366SCtirad Fertr 
1301541c66dSTakashi Iwai static const char * const emu1616_src_texts[] = {
1311c02e366SCtirad Fertr 	"Silence",
1321c02e366SCtirad Fertr 	"Dock Mic A",
1331c02e366SCtirad Fertr 	"Dock Mic B",
1341c02e366SCtirad Fertr 	"Dock ADC1 Left",
1351c02e366SCtirad Fertr 	"Dock ADC1 Right",
1361c02e366SCtirad Fertr 	"Dock ADC2 Left",
1371c02e366SCtirad Fertr 	"Dock ADC2 Right",
1381c02e366SCtirad Fertr 	"Dock SPDIF Left",
1391c02e366SCtirad Fertr 	"Dock SPDIF Right",
1401c02e366SCtirad Fertr 	"ADAT 0",
1411c02e366SCtirad Fertr 	"ADAT 1",
1421c02e366SCtirad Fertr 	"ADAT 2",
1431c02e366SCtirad Fertr 	"ADAT 3",
1441c02e366SCtirad Fertr 	"ADAT 4",
1451c02e366SCtirad Fertr 	"ADAT 5",
1461c02e366SCtirad Fertr 	"ADAT 6",
1471c02e366SCtirad Fertr 	"ADAT 7",
1481c02e366SCtirad Fertr 	"DSP 0",
1491c02e366SCtirad Fertr 	"DSP 1",
1501c02e366SCtirad Fertr 	"DSP 2",
1511c02e366SCtirad Fertr 	"DSP 3",
1521c02e366SCtirad Fertr 	"DSP 4",
1531c02e366SCtirad Fertr 	"DSP 5",
1541c02e366SCtirad Fertr 	"DSP 6",
1551c02e366SCtirad Fertr 	"DSP 7",
1561c02e366SCtirad Fertr 	"DSP 8",
1571c02e366SCtirad Fertr 	"DSP 9",
1581c02e366SCtirad Fertr 	"DSP 10",
1591c02e366SCtirad Fertr 	"DSP 11",
1601c02e366SCtirad Fertr 	"DSP 12",
1611c02e366SCtirad Fertr 	"DSP 13",
1621c02e366SCtirad Fertr 	"DSP 14",
1631c02e366SCtirad Fertr 	"DSP 15",
1641c02e366SCtirad Fertr 	"DSP 16",
1651c02e366SCtirad Fertr 	"DSP 17",
1661c02e366SCtirad Fertr 	"DSP 18",
1671c02e366SCtirad Fertr 	"DSP 19",
1681c02e366SCtirad Fertr 	"DSP 20",
1691c02e366SCtirad Fertr 	"DSP 21",
1701c02e366SCtirad Fertr 	"DSP 22",
1711c02e366SCtirad Fertr 	"DSP 23",
1721c02e366SCtirad Fertr 	"DSP 24",
1731c02e366SCtirad Fertr 	"DSP 25",
1741c02e366SCtirad Fertr 	"DSP 26",
1751c02e366SCtirad Fertr 	"DSP 27",
1761c02e366SCtirad Fertr 	"DSP 28",
1771c02e366SCtirad Fertr 	"DSP 29",
1781c02e366SCtirad Fertr 	"DSP 30",
1791c02e366SCtirad Fertr 	"DSP 31",
1801c02e366SCtirad Fertr };
1811c02e366SCtirad Fertr 
1821c02e366SCtirad Fertr 
18313d45709SPavel Hofman /*
18413d45709SPavel Hofman  * List of data sources available for each destination
18513d45709SPavel Hofman  */
1866fddce26STakashi Iwai static const unsigned int emu1010_src_regs[] = {
1879f4bd5ddSJames Courtier-Dutton 	EMU_SRC_SILENCE,/* 0 */
1889f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_MIC_A1, /* 1 */
1899f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_MIC_B1, /* 2 */
1909f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */
1919f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */
1929f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */
1939f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */
1949f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */
1959f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */
1969f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */
1979f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */
1989f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */
1999f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */
2009f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT, /* 13 */
2019f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+1, /* 14 */
2029f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+2, /* 15 */
2039f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+3, /* 16 */
2049f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+4, /* 17 */
2059f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+5, /* 18 */
2069f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+6, /* 19 */
2079f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+7, /* 20 */
2089f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A, /* 21 */
2099f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+1, /* 22 */
2109f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+2, /* 23 */
2119f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+3, /* 24 */
2129f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+4, /* 25 */
2139f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+5, /* 26 */
2149f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+6, /* 27 */
2159f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+7, /* 28 */
2169f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+8, /* 29 */
2179f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+9, /* 30 */
2189f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xa, /* 31 */
2199f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xb, /* 32 */
2209f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xc, /* 33 */
2219f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xd, /* 34 */
2229f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xe, /* 35 */
2239f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xf, /* 36 */
2249f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B, /* 37 */
2259f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+1, /* 38 */
2269f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+2, /* 39 */
2279f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+3, /* 40 */
2289f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+4, /* 41 */
2299f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+5, /* 42 */
2309f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+6, /* 43 */
2319f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+7, /* 44 */
2329f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+8, /* 45 */
2339f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+9, /* 46 */
2349f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xa, /* 47 */
2359f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xb, /* 48 */
2369f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xc, /* 49 */
2379f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xd, /* 50 */
2389f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xe, /* 51 */
2399f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
2409f4bd5ddSJames Courtier-Dutton };
2419f4bd5ddSJames Courtier-Dutton 
2421c02e366SCtirad Fertr /* 1616(m) cardbus */
2436fddce26STakashi Iwai static const unsigned int emu1616_src_regs[] = {
2441c02e366SCtirad Fertr 	EMU_SRC_SILENCE,
2451c02e366SCtirad Fertr 	EMU_SRC_DOCK_MIC_A1,
2461c02e366SCtirad Fertr 	EMU_SRC_DOCK_MIC_B1,
2471c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC1_LEFT1,
2481c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC1_RIGHT1,
2491c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC2_LEFT1,
2501c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC2_RIGHT1,
2511c02e366SCtirad Fertr 	EMU_SRC_MDOCK_SPDIF_LEFT1,
2521c02e366SCtirad Fertr 	EMU_SRC_MDOCK_SPDIF_RIGHT1,
2531c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT,
2541c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+1,
2551c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+2,
2561c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+3,
2571c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+4,
2581c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+5,
2591c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+6,
2601c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+7,
2611c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A,
2621c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+1,
2631c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+2,
2641c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+3,
2651c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+4,
2661c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+5,
2671c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+6,
2681c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+7,
2691c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+8,
2701c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+9,
2711c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xa,
2721c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xb,
2731c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xc,
2741c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xd,
2751c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xe,
2761c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xf,
2771c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B,
2781c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+1,
2791c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+2,
2801c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+3,
2811c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+4,
2821c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+5,
2831c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+6,
2841c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+7,
2851c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+8,
2861c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+9,
2871c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xa,
2881c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xb,
2891c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xc,
2901c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xd,
2911c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xe,
2921c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xf,
2931c02e366SCtirad Fertr };
2941c02e366SCtirad Fertr 
29513d45709SPavel Hofman /*
29613d45709SPavel Hofman  * Data destinations - physical EMU outputs.
29713d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
29813d45709SPavel Hofman  */
2996fddce26STakashi Iwai static const unsigned int emu1010_output_dst[] = {
3009f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
3019f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
3029f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC2_LEFT1, /* 2 */
3039f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */
3049f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC3_LEFT1, /* 4 */
3059f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */
3069f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC4_LEFT1, /* 6 */
3079f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */
3089f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_PHONES_LEFT1, /* 8 */
3099f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */
3109f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */
3119f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */
3129f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_SPDIF_LEFT1, /* 12 */
3139f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */
3149f4bd5ddSJames Courtier-Dutton 	EMU_DST_HAMOA_DAC_LEFT1, /* 14 */
3159f4bd5ddSJames Courtier-Dutton 	EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */
3169f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT, /* 16 */
3179f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+1, /* 17 */
3189f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+2, /* 18 */
3199f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+3, /* 19 */
3209f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+4, /* 20 */
3219f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+5, /* 21 */
3229f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+6, /* 22 */
3239f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+7, /* 23 */
3249f4bd5ddSJames Courtier-Dutton };
3259f4bd5ddSJames Courtier-Dutton 
3261c02e366SCtirad Fertr /* 1616(m) cardbus */
3276fddce26STakashi Iwai static const unsigned int emu1616_output_dst[] = {
3281c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC1_LEFT1,
3291c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC1_RIGHT1,
3301c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC2_LEFT1,
3311c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC2_RIGHT1,
3321c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC3_LEFT1,
3331c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC3_RIGHT1,
3341c02e366SCtirad Fertr 	EMU_DST_MDOCK_SPDIF_LEFT1,
3351c02e366SCtirad Fertr 	EMU_DST_MDOCK_SPDIF_RIGHT1,
3361c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT,
3371c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+1,
3381c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+2,
3391c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+3,
3401c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+4,
3411c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+5,
3421c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+6,
3431c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+7,
3441c02e366SCtirad Fertr 	EMU_DST_MANA_DAC_LEFT,
3451c02e366SCtirad Fertr 	EMU_DST_MANA_DAC_RIGHT,
3461c02e366SCtirad Fertr };
3471c02e366SCtirad Fertr 
34813d45709SPavel Hofman /*
349a869057cSOswald Buddenhagen  * Data destinations - FPGA outputs going to Alice2 (Audigy) for
35013d45709SPavel Hofman  *   capture (EMU32 + I2S links)
35113d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
35213d45709SPavel Hofman  */
3536fddce26STakashi Iwai static const unsigned int emu1010_input_dst[] = {
3549f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_0,
3559f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_1,
3569f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_2,
3579f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_3,
3589f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_4,
3599f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_5,
3609f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_6,
3619f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_7,
3629f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_8,
3639f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_9,
3649f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_A,
3659f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_B,
3669f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_C,
3679f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_D,
3689f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_E,
3699f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_F,
370a869057cSOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
3719f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_LEFT,
3729f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_RIGHT,
3739f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_LEFT,
3749f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_RIGHT,
3759f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_LEFT,
3769f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_RIGHT,
3779f4bd5ddSJames Courtier-Dutton };
3789f4bd5ddSJames Courtier-Dutton 
3791c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
3801c02e366SCtirad Fertr 						struct snd_ctl_elem_info *uinfo)
3819f4bd5ddSJames Courtier-Dutton {
3821c02e366SCtirad Fertr 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
3831c02e366SCtirad Fertr 
3841541c66dSTakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
3851541c66dSTakashi Iwai 		return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts);
3861541c66dSTakashi Iwai 	else
3871541c66dSTakashi Iwai 		return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts);
3889f4bd5ddSJames Courtier-Dutton }
3899f4bd5ddSJames Courtier-Dutton 
3909f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
3919f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
3929f4bd5ddSJames Courtier-Dutton {
3939f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
39474415a36SJames Courtier-Dutton 	unsigned int channel;
3959f4bd5ddSJames Courtier-Dutton 
3969f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
39774415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
3981c02e366SCtirad Fertr 	if (channel >= 24 ||
3993839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4003839e4f1STakashi Iwai 	     channel >= 18))
40174415a36SJames Courtier-Dutton 		return -EINVAL;
4029f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
4039f4bd5ddSJames Courtier-Dutton 	return 0;
4049f4bd5ddSJames Courtier-Dutton }
4059f4bd5ddSJames Courtier-Dutton 
4069f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
4079f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4089f4bd5ddSJames Courtier-Dutton {
4099f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4109f4bd5ddSJames Courtier-Dutton 	unsigned int val;
41174415a36SJames Courtier-Dutton 	unsigned int channel;
4129f4bd5ddSJames Courtier-Dutton 
413aa299d01STakashi Iwai 	val = ucontrol->value.enumerated.item[0];
4141c02e366SCtirad Fertr 	if (val >= 53 ||
4153839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4163839e4f1STakashi Iwai 	     val >= 49))
417aa299d01STakashi Iwai 		return -EINVAL;
4189f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
41974415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
4201c02e366SCtirad Fertr 	if (channel >= 24 ||
4213839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4223839e4f1STakashi Iwai 	     channel >= 18))
42374415a36SJames Courtier-Dutton 		return -EINVAL;
4241c02e366SCtirad Fertr 	if (emu->emu1010.output_source[channel] == val)
4251c02e366SCtirad Fertr 		return 0;
426aa299d01STakashi Iwai 	emu->emu1010.output_source[channel] = val;
4273839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
4281c02e366SCtirad Fertr 		snd_emu1010_fpga_link_dst_src_write(emu,
4291c02e366SCtirad Fertr 			emu1616_output_dst[channel], emu1616_src_regs[val]);
4301c02e366SCtirad Fertr 	else
4319f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
4329f4bd5ddSJames Courtier-Dutton 			emu1010_output_dst[channel], emu1010_src_regs[val]);
4331c02e366SCtirad Fertr 	return 1;
4349f4bd5ddSJames Courtier-Dutton }
4359f4bd5ddSJames Courtier-Dutton 
4369f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
4379f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4389f4bd5ddSJames Courtier-Dutton {
4399f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
44074415a36SJames Courtier-Dutton 	unsigned int channel;
4419f4bd5ddSJames Courtier-Dutton 
4429f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
44374415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
44474415a36SJames Courtier-Dutton 	if (channel >= 22)
44574415a36SJames Courtier-Dutton 		return -EINVAL;
4469f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
4479f4bd5ddSJames Courtier-Dutton 	return 0;
4489f4bd5ddSJames Courtier-Dutton }
4499f4bd5ddSJames Courtier-Dutton 
4509f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
4519f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4529f4bd5ddSJames Courtier-Dutton {
4539f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4549f4bd5ddSJames Courtier-Dutton 	unsigned int val;
45574415a36SJames Courtier-Dutton 	unsigned int channel;
4569f4bd5ddSJames Courtier-Dutton 
457aa299d01STakashi Iwai 	val = ucontrol->value.enumerated.item[0];
4581c02e366SCtirad Fertr 	if (val >= 53 ||
4593839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4603839e4f1STakashi Iwai 	     val >= 49))
461aa299d01STakashi Iwai 		return -EINVAL;
4629f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
46374415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
46474415a36SJames Courtier-Dutton 	if (channel >= 22)
46574415a36SJames Courtier-Dutton 		return -EINVAL;
4661c02e366SCtirad Fertr 	if (emu->emu1010.input_source[channel] == val)
4671c02e366SCtirad Fertr 		return 0;
468aa299d01STakashi Iwai 	emu->emu1010.input_source[channel] = val;
4693839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
4701c02e366SCtirad Fertr 		snd_emu1010_fpga_link_dst_src_write(emu,
4711c02e366SCtirad Fertr 			emu1010_input_dst[channel], emu1616_src_regs[val]);
4721c02e366SCtirad Fertr 	else
4739f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
4749f4bd5ddSJames Courtier-Dutton 			emu1010_input_dst[channel], emu1010_src_regs[val]);
4751c02e366SCtirad Fertr 	return 1;
4769f4bd5ddSJames Courtier-Dutton }
4779f4bd5ddSJames Courtier-Dutton 
4789f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \
4799f4bd5ddSJames Courtier-Dutton {								\
4809f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
4819f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
4829f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
4839f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_output_source_get,			\
4849f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_output_source_put,			\
4859f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
4869f4bd5ddSJames Courtier-Dutton }
4879f4bd5ddSJames Courtier-Dutton 
488b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = {
4894c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
4904c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
4914c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
4924c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
4934c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
4944c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
4954c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6),
4964c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
4974c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
4984c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
4994c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
5004c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
5014c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
5024c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
5034c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
5044c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
5054c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
5064c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
5074c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
5084c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
5094c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
5104c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
5114c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
5124c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
5139f4bd5ddSJames Courtier-Dutton };
5149f4bd5ddSJames Courtier-Dutton 
5151c02e366SCtirad Fertr 
5161c02e366SCtirad Fertr /* 1616(m) cardbus */
517b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = {
5181c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
5191c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
5201c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
5211c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
5221c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
5231c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
5241c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6),
5251c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7),
5261c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8),
5271c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9),
5281c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa),
5291c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb),
5301c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc),
5311c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd),
5321c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe),
5331c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf),
5341c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10),
5351c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11),
5361c02e366SCtirad Fertr };
5371c02e366SCtirad Fertr 
5381c02e366SCtirad Fertr 
5399f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \
5409f4bd5ddSJames Courtier-Dutton {								\
5419f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
5429f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
5439f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
5449f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_input_source_get,			\
5459f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_input_source_put,			\
5469f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
5479f4bd5ddSJames Courtier-Dutton }
5489f4bd5ddSJames Courtier-Dutton 
549b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = {
5504c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
5514c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
5524c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
5534c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
5544c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
5554c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
5564c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
5574c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
5584c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
5594c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
5604c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
5614c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
5624c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
5634c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
5644c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
5654c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
5664c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
5674c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
5684c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
5694c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
5704c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
5714c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
5729148cc50SJames Courtier-Dutton };
5739148cc50SJames Courtier-Dutton 
5749148cc50SJames Courtier-Dutton 
5759148cc50SJames Courtier-Dutton 
576a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
5779148cc50SJames Courtier-Dutton 
5789148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5799148cc50SJames Courtier-Dutton {
5809148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
5819148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
5829148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
5839148cc50SJames Courtier-Dutton 	return 0;
5849148cc50SJames Courtier-Dutton }
5859148cc50SJames Courtier-Dutton 
5869148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5879148cc50SJames Courtier-Dutton {
5889148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
5899148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
5909148cc50SJames Courtier-Dutton 	unsigned int val, cache;
5919148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
5929148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
5939148cc50SJames Courtier-Dutton 	if (val == 1)
5949148cc50SJames Courtier-Dutton 		cache = cache | mask;
5959148cc50SJames Courtier-Dutton 	else
5969148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
5979148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
5989148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
5999148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
6009148cc50SJames Courtier-Dutton 	}
6019148cc50SJames Courtier-Dutton 
6029148cc50SJames Courtier-Dutton 	return 0;
6039148cc50SJames Courtier-Dutton }
6049148cc50SJames Courtier-Dutton 
6059148cc50SJames Courtier-Dutton 
6069148cc50SJames Courtier-Dutton 
6079148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \
6089148cc50SJames Courtier-Dutton {								\
6099148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
6109148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
6119148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_adc_pads_info,			\
6129148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_adc_pads_get,			\
6139148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_adc_pads_put,			\
6149148cc50SJames Courtier-Dutton 	.private_value = chid					\
6159148cc50SJames Courtier-Dutton }
6169148cc50SJames Courtier-Dutton 
617b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_adc_pads[] = {
6189148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
6199148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
6209148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
6219148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
6229148cc50SJames Courtier-Dutton };
6239148cc50SJames Courtier-Dutton 
624a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
6259148cc50SJames Courtier-Dutton 
6269148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6279148cc50SJames Courtier-Dutton {
6289148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6299148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6309148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
6319148cc50SJames Courtier-Dutton 	return 0;
6329148cc50SJames Courtier-Dutton }
6339148cc50SJames Courtier-Dutton 
6349148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6359148cc50SJames Courtier-Dutton {
6369148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6379148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6389148cc50SJames Courtier-Dutton 	unsigned int val, cache;
6399148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
6409148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
6419148cc50SJames Courtier-Dutton 	if (val == 1)
6429148cc50SJames Courtier-Dutton 		cache = cache | mask;
6439148cc50SJames Courtier-Dutton 	else
6449148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
6459148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.dac_pads) {
6469148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
6479148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
6489148cc50SJames Courtier-Dutton 	}
6499148cc50SJames Courtier-Dutton 
6509148cc50SJames Courtier-Dutton 	return 0;
6519148cc50SJames Courtier-Dutton }
6529148cc50SJames Courtier-Dutton 
6539148cc50SJames Courtier-Dutton 
6549148cc50SJames Courtier-Dutton 
6559148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \
6569148cc50SJames Courtier-Dutton {								\
6579148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
6589148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
6599148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_dac_pads_info,			\
6609148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_dac_pads_get,			\
6619148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_dac_pads_put,			\
6629148cc50SJames Courtier-Dutton 	.private_value = chid					\
6639148cc50SJames Courtier-Dutton }
6649148cc50SJames Courtier-Dutton 
665b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_dac_pads[] = {
6669148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
6679148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
6689148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
6699148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
6709148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
6719f4bd5ddSJames Courtier-Dutton };
6729f4bd5ddSJames Courtier-Dutton 
673b0dbdaeaSJames Courtier-Dutton 
674b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
675b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
676b0dbdaeaSJames Courtier-Dutton {
6771541c66dSTakashi Iwai 	static const char * const texts[4] = {
678edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
679b0dbdaeaSJames Courtier-Dutton 	};
680b0dbdaeaSJames Courtier-Dutton 
6811541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 4, texts);
682b0dbdaeaSJames Courtier-Dutton }
683b0dbdaeaSJames Courtier-Dutton 
684b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
685b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
686b0dbdaeaSJames Courtier-Dutton {
687b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
688b0dbdaeaSJames Courtier-Dutton 
689b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
690b0dbdaeaSJames Courtier-Dutton 	return 0;
691b0dbdaeaSJames Courtier-Dutton }
692b0dbdaeaSJames Courtier-Dutton 
693b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
694b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
695b0dbdaeaSJames Courtier-Dutton {
696b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
697b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
698b0dbdaeaSJames Courtier-Dutton 	int change = 0;
699b0dbdaeaSJames Courtier-Dutton 
700b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
70174415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 4; */
70274415a36SJames Courtier-Dutton 	if (val >= 4)
70374415a36SJames Courtier-Dutton 		return -EINVAL;
704b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
705b0dbdaeaSJames Courtier-Dutton 	if (change) {
706b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
707b0dbdaeaSJames Courtier-Dutton 		switch (val) {
708b0dbdaeaSJames Courtier-Dutton 		case 0:
709b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
710b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
711b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
712a869057cSOswald Buddenhagen 			/* Default fallback clock 44.1kHz */
713b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
714b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
715b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
716b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
717b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
718b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
719b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
720b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
721e40a0b2eSJames Courtier-Dutton 			msleep(10);
722b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
723b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
724b0dbdaeaSJames Courtier-Dutton 			break;
725b0dbdaeaSJames Courtier-Dutton 		case 1:
726b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
727b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
728b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
729b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
730b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
731b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
732b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
733b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
734b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
735b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
736b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
737b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
738e40a0b2eSJames Courtier-Dutton 			msleep(10);
739b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
740b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
741b0dbdaeaSJames Courtier-Dutton 			break;
742edec7bbbSJames Courtier-Dutton 
743edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
744edec7bbbSJames Courtier-Dutton 			/* Mute all */
745edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
746edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
747edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
748edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
749edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
750edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
751edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
752edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
753edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
754edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
755edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
756edec7bbbSJames Courtier-Dutton 			msleep(10);
757edec7bbbSJames Courtier-Dutton 			/* Unmute all */
758edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
759edec7bbbSJames Courtier-Dutton 			break;
760edec7bbbSJames Courtier-Dutton 
761edec7bbbSJames Courtier-Dutton 		case 3:
762edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
763edec7bbbSJames Courtier-Dutton 			/* Mute all */
764edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
765edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
766edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
767edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
768edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
769edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
770edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
771edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
772edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
773edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
774edec7bbbSJames Courtier-Dutton 			msleep(10);
775edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
776edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
777edec7bbbSJames Courtier-Dutton 
778edec7bbbSJames Courtier-Dutton 
779edec7bbbSJames Courtier-Dutton 			break;
780b0dbdaeaSJames Courtier-Dutton 		}
781b0dbdaeaSJames Courtier-Dutton 	}
782b0dbdaeaSJames Courtier-Dutton         return change;
783b0dbdaeaSJames Courtier-Dutton }
784b0dbdaeaSJames Courtier-Dutton 
785f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock =
786b0dbdaeaSJames Courtier-Dutton {
787b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
788b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
789b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
790b0dbdaeaSJames Courtier-Dutton 	.count =	1,
791b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
792b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
793b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
794b0dbdaeaSJames Courtier-Dutton };
795b0dbdaeaSJames Courtier-Dutton 
79699dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
79799dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
79899dcab46SMichael Gernoth {
79999dcab46SMichael Gernoth 	static const char * const texts[2] = {
80099dcab46SMichael Gernoth 		"SPDIF", "ADAT"
80199dcab46SMichael Gernoth 	};
80299dcab46SMichael Gernoth 
80399dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
80499dcab46SMichael Gernoth }
80599dcab46SMichael Gernoth 
80699dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol,
80799dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
80899dcab46SMichael Gernoth {
80999dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
81099dcab46SMichael Gernoth 
81199dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out;
81299dcab46SMichael Gernoth 	return 0;
81399dcab46SMichael Gernoth }
81499dcab46SMichael Gernoth 
81599dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
81699dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
81799dcab46SMichael Gernoth {
81899dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
81999dcab46SMichael Gernoth 	unsigned int val;
82099dcab46SMichael Gernoth 	u32 tmp;
82199dcab46SMichael Gernoth 	int change = 0;
82299dcab46SMichael Gernoth 
82399dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
82499dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
82599dcab46SMichael Gernoth 	if (val >= 2)
82699dcab46SMichael Gernoth 		return -EINVAL;
82799dcab46SMichael Gernoth 	change = (emu->emu1010.optical_out != val);
82899dcab46SMichael Gernoth 	if (change) {
82999dcab46SMichael Gernoth 		emu->emu1010.optical_out = val;
8309d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
8319d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
83299dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
83399dcab46SMichael Gernoth 	}
83499dcab46SMichael Gernoth 	return change;
83599dcab46SMichael Gernoth }
83699dcab46SMichael Gernoth 
837f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = {
83899dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
83999dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
84099dcab46SMichael Gernoth 	.name =         "Optical Output Mode",
84199dcab46SMichael Gernoth 	.count =	1,
84299dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_out_info,
84399dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_out_get,
84499dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_out_put
84599dcab46SMichael Gernoth };
84699dcab46SMichael Gernoth 
84799dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
84899dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
84999dcab46SMichael Gernoth {
85099dcab46SMichael Gernoth 	static const char * const texts[2] = {
85199dcab46SMichael Gernoth 		"SPDIF", "ADAT"
85299dcab46SMichael Gernoth 	};
85399dcab46SMichael Gernoth 
85499dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
85599dcab46SMichael Gernoth }
85699dcab46SMichael Gernoth 
85799dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
85899dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
85999dcab46SMichael Gernoth {
86099dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
86199dcab46SMichael Gernoth 
86299dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
86399dcab46SMichael Gernoth 	return 0;
86499dcab46SMichael Gernoth }
86599dcab46SMichael Gernoth 
86699dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
86799dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
86899dcab46SMichael Gernoth {
86999dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
87099dcab46SMichael Gernoth 	unsigned int val;
87199dcab46SMichael Gernoth 	u32 tmp;
87299dcab46SMichael Gernoth 	int change = 0;
87399dcab46SMichael Gernoth 
87499dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
87599dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
87699dcab46SMichael Gernoth 	if (val >= 2)
87799dcab46SMichael Gernoth 		return -EINVAL;
87899dcab46SMichael Gernoth 	change = (emu->emu1010.optical_in != val);
87999dcab46SMichael Gernoth 	if (change) {
88099dcab46SMichael Gernoth 		emu->emu1010.optical_in = val;
8819d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
8829d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
88399dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
88499dcab46SMichael Gernoth 	}
88599dcab46SMichael Gernoth 	return change;
88699dcab46SMichael Gernoth }
88799dcab46SMichael Gernoth 
888f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = {
88999dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
89099dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
89199dcab46SMichael Gernoth 	.name =         "Optical Input Mode",
89299dcab46SMichael Gernoth 	.count =	1,
89399dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_in_info,
89499dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_in_get,
89599dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_in_put
89699dcab46SMichael Gernoth };
89799dcab46SMichael Gernoth 
898184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
899184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
900184c1e2cSJames Courtier-Dutton {
901184c1e2cSJames Courtier-Dutton #if 0
9021541c66dSTakashi Iwai 	static const char * const texts[4] = {
903184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
904184c1e2cSJames Courtier-Dutton 	};
905184c1e2cSJames Courtier-Dutton #endif
9061541c66dSTakashi Iwai 	static const char * const texts[2] = {
907184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
908184c1e2cSJames Courtier-Dutton 	};
909184c1e2cSJames Courtier-Dutton 
9101541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
911184c1e2cSJames Courtier-Dutton }
912184c1e2cSJames Courtier-Dutton 
913184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
914184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
915184c1e2cSJames Courtier-Dutton {
916184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
917184c1e2cSJames Courtier-Dutton 
918184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
919184c1e2cSJames Courtier-Dutton 	return 0;
920184c1e2cSJames Courtier-Dutton }
921184c1e2cSJames Courtier-Dutton 
922184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
923184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
924184c1e2cSJames Courtier-Dutton {
925184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
926184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
927184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
928a1c87c0bSOswald Buddenhagen 	u16 gpio;
929184c1e2cSJames Courtier-Dutton 	int change = 0;
930184c1e2cSJames Courtier-Dutton 	unsigned long flags;
931184c1e2cSJames Courtier-Dutton 	u32 source;
932184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
933184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
934184c1e2cSJames Courtier-Dutton 	 * for the particular source.
935184c1e2cSJames Courtier-Dutton 	 */
93674415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
93774415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
93874415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
93974415a36SJames Courtier-Dutton 	if (source_id >= 2)
94074415a36SJames Courtier-Dutton 		return -EINVAL;
941184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
942184c1e2cSJames Courtier-Dutton 	if (change) {
943184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
944184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
945a1c87c0bSOswald Buddenhagen 		gpio = inw(emu->port + A_IOCFG);
946184c1e2cSJames Courtier-Dutton 		if (source_id==0)
947a1c87c0bSOswald Buddenhagen 			outw(gpio | 0x4, emu->port + A_IOCFG);
948184c1e2cSJames Courtier-Dutton 		else
949a1c87c0bSOswald Buddenhagen 			outw(gpio & ~0x4, emu->port + A_IOCFG);
950184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
951184c1e2cSJames Courtier-Dutton 
952184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
953184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
954184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
955184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
956184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
957184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
958184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
959184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
960184c1e2cSJames Courtier-Dutton 
961184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
962184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
963184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
964184c1e2cSJames Courtier-Dutton 	}
965184c1e2cSJames Courtier-Dutton         return change;
966184c1e2cSJames Courtier-Dutton }
967184c1e2cSJames Courtier-Dutton 
968f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source =
969184c1e2cSJames Courtier-Dutton {
970184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
971184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
972184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
973184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
974184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
975184c1e2cSJames Courtier-Dutton };
976184c1e2cSJames Courtier-Dutton 
977184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
978184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
979184c1e2cSJames Courtier-Dutton {
980184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
981184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
982184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
983184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
984184c1e2cSJames Courtier-Dutton 	return 0;
985184c1e2cSJames Courtier-Dutton }
986184c1e2cSJames Courtier-Dutton 
987184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
988184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
989184c1e2cSJames Courtier-Dutton {
990184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
99174415a36SJames Courtier-Dutton 	unsigned int source_id;
992184c1e2cSJames Courtier-Dutton 
993184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
99474415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
99574415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
99674415a36SJames Courtier-Dutton 	if (source_id >= 2)
99774415a36SJames Courtier-Dutton 		return -EINVAL;
998184c1e2cSJames Courtier-Dutton 
999184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
1000184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
1001184c1e2cSJames Courtier-Dutton 	return 0;
1002184c1e2cSJames Courtier-Dutton }
1003184c1e2cSJames Courtier-Dutton 
1004184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
1005184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
1006184c1e2cSJames Courtier-Dutton {
1007184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1008184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
100914a29565SOswald Buddenhagen 	unsigned int ngain0, ngain1;
101074415a36SJames Courtier-Dutton 	unsigned int source_id;
1011184c1e2cSJames Courtier-Dutton 	int change = 0;
1012184c1e2cSJames Courtier-Dutton 
1013184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
101474415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
101574415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
101674415a36SJames Courtier-Dutton 	if (source_id >= 2)
101774415a36SJames Courtier-Dutton 		return -EINVAL;
101814a29565SOswald Buddenhagen 	ngain0 = ucontrol->value.integer.value[0];
101914a29565SOswald Buddenhagen 	ngain1 = ucontrol->value.integer.value[1];
102014a29565SOswald Buddenhagen 	if (ngain0 > 0xff)
102114a29565SOswald Buddenhagen 		return -EINVAL;
102214a29565SOswald Buddenhagen 	if (ngain1 > 0xff)
102314a29565SOswald Buddenhagen 		return -EINVAL;
1024184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
102514a29565SOswald Buddenhagen 	if (ogain != ngain0) {
1026184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
102714a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0);
102814a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][0] = ngain0;
1029184c1e2cSJames Courtier-Dutton 		change = 1;
1030184c1e2cSJames Courtier-Dutton 	}
1031184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
103214a29565SOswald Buddenhagen 	if (ogain != ngain1) {
1033184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
103414a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1);
103514a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][1] = ngain1;
1036184c1e2cSJames Courtier-Dutton 		change = 1;
1037184c1e2cSJames Courtier-Dutton 	}
1038184c1e2cSJames Courtier-Dutton 
1039184c1e2cSJames Courtier-Dutton 	return change;
1040184c1e2cSJames Courtier-Dutton }
1041184c1e2cSJames Courtier-Dutton 
1042184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \
1043184c1e2cSJames Courtier-Dutton {								\
1044184c1e2cSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
1045184c1e2cSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
1046184c1e2cSJames Courtier-Dutton 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
1047184c1e2cSJames Courtier-Dutton 	.info =  snd_audigy_i2c_volume_info,			\
1048184c1e2cSJames Courtier-Dutton 	.get =   snd_audigy_i2c_volume_get,			\
1049184c1e2cSJames Courtier-Dutton 	.put =   snd_audigy_i2c_volume_put,			\
1050184c1e2cSJames Courtier-Dutton 	.tlv = { .p = snd_audigy_db_scale2 },			\
1051184c1e2cSJames Courtier-Dutton 	.private_value = chid					\
1052184c1e2cSJames Courtier-Dutton }
1053184c1e2cSJames Courtier-Dutton 
1054184c1e2cSJames Courtier-Dutton 
1055b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = {
1056184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Mic Capture Volume", 0),
1057184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Line Capture Volume", 0)
1058184c1e2cSJames Courtier-Dutton };
1059184c1e2cSJames Courtier-Dutton 
10600af68e5eSTakashi Iwai #if 0
1061eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
10621da177e4SLinus Torvalds {
10631541c66dSTakashi Iwai 	static const char * const texts[] = {"44100", "48000", "96000"};
10641da177e4SLinus Torvalds 
10651541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 3, texts);
10661da177e4SLinus Torvalds }
10671da177e4SLinus Torvalds 
1068eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
1069eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10701da177e4SLinus Torvalds {
1071eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10721da177e4SLinus Torvalds 	unsigned int tmp;
10731da177e4SLinus Torvalds 	unsigned long flags;
10741da177e4SLinus Torvalds 
10751da177e4SLinus Torvalds 
10761da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10771da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
10781da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
10791da177e4SLinus Torvalds 	case A_SPDIF_44100:
10801da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
10811da177e4SLinus Torvalds 		break;
10821da177e4SLinus Torvalds 	case A_SPDIF_48000:
10831da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
10841da177e4SLinus Torvalds 		break;
10851da177e4SLinus Torvalds 	case A_SPDIF_96000:
10861da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
10871da177e4SLinus Torvalds 		break;
10881da177e4SLinus Torvalds 	default:
10891da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
10901da177e4SLinus Torvalds 	}
10911da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10921da177e4SLinus Torvalds 	return 0;
10931da177e4SLinus Torvalds }
10941da177e4SLinus Torvalds 
1095eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
1096eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10971da177e4SLinus Torvalds {
1098eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10991da177e4SLinus Torvalds 	int change;
11001da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
11011da177e4SLinus Torvalds 	unsigned long flags;
11021da177e4SLinus Torvalds 
11031da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
11041da177e4SLinus Torvalds 	case 0:
11051da177e4SLinus Torvalds 		val = A_SPDIF_44100;
11061da177e4SLinus Torvalds 		break;
11071da177e4SLinus Torvalds 	case 1:
11081da177e4SLinus Torvalds 		val = A_SPDIF_48000;
11091da177e4SLinus Torvalds 		break;
11101da177e4SLinus Torvalds 	case 2:
11111da177e4SLinus Torvalds 		val = A_SPDIF_96000;
11121da177e4SLinus Torvalds 		break;
11131da177e4SLinus Torvalds 	default:
11141da177e4SLinus Torvalds 		val = A_SPDIF_48000;
11151da177e4SLinus Torvalds 		break;
11161da177e4SLinus Torvalds 	}
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds 
11191da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11201da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
11211da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
11221da177e4SLinus Torvalds 	tmp |= val;
112312bda107STakashi Iwai 	change = (tmp != reg);
112412bda107STakashi Iwai 	if (change)
11251da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
11261da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11271da177e4SLinus Torvalds 	return change;
11281da177e4SLinus Torvalds }
11291da177e4SLinus Torvalds 
1130b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate =
11311da177e4SLinus Torvalds {
11321da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
11331da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
11341da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
11351da177e4SLinus Torvalds 	.count =	1,
11361da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
11371da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
11381da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
11391da177e4SLinus Torvalds };
11400af68e5eSTakashi Iwai #endif
11411da177e4SLinus Torvalds 
1142eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1143eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
11441da177e4SLinus Torvalds {
1145eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11461da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
11471da177e4SLinus Torvalds 	int change;
11481da177e4SLinus Torvalds 	unsigned int val;
11491da177e4SLinus Torvalds 	unsigned long flags;
11501da177e4SLinus Torvalds 
115174415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
115274415a36SJames Courtier-Dutton 	if (idx >= 3)
115374415a36SJames Courtier-Dutton 		return -EINVAL;
11541da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
11551da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
11561da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
11571da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
11581da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11591da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
11601da177e4SLinus Torvalds 	if (change) {
11611da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
11621da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
11631da177e4SLinus Torvalds 	}
11641da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11651da177e4SLinus Torvalds 	return change;
11661da177e4SLinus Torvalds }
11671da177e4SLinus Torvalds 
1168f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
11691da177e4SLinus Torvalds {
11701da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
11715549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11721da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
11737583cb51STakashi Iwai 	.count =	3,
11741da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
11751da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
11761da177e4SLinus Torvalds };
11771da177e4SLinus Torvalds 
1178f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
11791da177e4SLinus Torvalds {
11805549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
11811da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
11827583cb51STakashi Iwai 	.count =	3,
11831da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
11841da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
11851da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
11861da177e4SLinus Torvalds };
11871da177e4SLinus Torvalds 
11881da177e4SLinus Torvalds 
1189eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
11901da177e4SLinus Torvalds {
11911da177e4SLinus Torvalds 	if (emu->audigy) {
11921da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
11931da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
11941da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
11951da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
11961da177e4SLinus Torvalds 	} else {
11971da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
11981da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
11991da177e4SLinus Torvalds 	}
12001da177e4SLinus Torvalds }
12011da177e4SLinus Torvalds 
1202eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
12031da177e4SLinus Torvalds {
12041da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
12051da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
12061da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
12071da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
12081da177e4SLinus Torvalds 	if (emu->audigy) {
12091da177e4SLinus Torvalds 		unsigned int val = ((unsigned int)volume[4] << 24) |
12101da177e4SLinus Torvalds 			((unsigned int)volume[5] << 16) |
12111da177e4SLinus Torvalds 			((unsigned int)volume[6] << 8) |
12121da177e4SLinus Torvalds 			(unsigned int)volume[7];
12131da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
12141da177e4SLinus Torvalds 	}
12151da177e4SLinus Torvalds }
12161da177e4SLinus Torvalds 
12171da177e4SLinus Torvalds /* PCM stream controls */
12181da177e4SLinus Torvalds 
1219eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12201da177e4SLinus Torvalds {
1221eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12221da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12231da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
12241da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12251da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
12261da177e4SLinus Torvalds 	return 0;
12271da177e4SLinus Torvalds }
12281da177e4SLinus Torvalds 
1229eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1230eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
12311da177e4SLinus Torvalds {
12321da177e4SLinus Torvalds 	unsigned long flags;
1233eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1234eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1235eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12361da177e4SLinus Torvalds 	int voice, idx;
12371da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12381da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
12391da177e4SLinus Torvalds 
12401da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12411da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
12421da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
12431da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
12441da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
12451da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12461da177e4SLinus Torvalds 	return 0;
12471da177e4SLinus Torvalds }
12481da177e4SLinus Torvalds 
1249eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1250eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
12511da177e4SLinus Torvalds {
12521da177e4SLinus Torvalds 	unsigned long flags;
1253eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1254eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1255eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12561da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
12571da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12581da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
12591da177e4SLinus Torvalds 
12601da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12611da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
12621da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
12631da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
12641da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
12651da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
12661da177e4SLinus Torvalds 				change = 1;
12671da177e4SLinus Torvalds 			}
12681da177e4SLinus Torvalds 		}
12691da177e4SLinus Torvalds 	if (change && mix->epcm) {
12701da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
12711da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
12721da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
12731da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
12741da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
12751da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
12761da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
12771da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
12781da177e4SLinus Torvalds 		}
12791da177e4SLinus Torvalds 	}
12801da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12811da177e4SLinus Torvalds 	return change;
12821da177e4SLinus Torvalds }
12831da177e4SLinus Torvalds 
1284f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control =
12851da177e4SLinus Torvalds {
12861da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
128767ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12881da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
12891da177e4SLinus Torvalds 	.count =	32,
12901da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
12911da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
12921da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
12931da177e4SLinus Torvalds };
12941da177e4SLinus Torvalds 
1295eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12961da177e4SLinus Torvalds {
1297eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12981da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12991da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
13001da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13011da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
13021da177e4SLinus Torvalds 	return 0;
13031da177e4SLinus Torvalds }
13041da177e4SLinus Torvalds 
1305eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1306eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
13071da177e4SLinus Torvalds {
13081da177e4SLinus Torvalds 	unsigned long flags;
1309eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1310eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1311eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13121da177e4SLinus Torvalds 	int idx;
13131da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13141da177e4SLinus Torvalds 
13151da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13161da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
13171da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
13181da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13191da177e4SLinus Torvalds 	return 0;
13201da177e4SLinus Torvalds }
13211da177e4SLinus Torvalds 
1322eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1323eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
13241da177e4SLinus Torvalds {
13251da177e4SLinus Torvalds 	unsigned long flags;
1326eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1327eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1328eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13291da177e4SLinus Torvalds 	int change = 0, idx, val;
13301da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13311da177e4SLinus Torvalds 
13321da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13331da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
13341da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
13351da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
13361da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
13371da177e4SLinus Torvalds 			change = 1;
13381da177e4SLinus Torvalds 		}
13391da177e4SLinus Torvalds 	}
13401da177e4SLinus Torvalds 	if (change && mix->epcm) {
13411da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
13421da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
13431da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
13441da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
13451da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
13461da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
13471da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
13481da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
13491da177e4SLinus Torvalds 		}
13501da177e4SLinus Torvalds 	}
13511da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13521da177e4SLinus Torvalds 	return change;
13531da177e4SLinus Torvalds }
13541da177e4SLinus Torvalds 
1355f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
13561da177e4SLinus Torvalds {
13571da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
135867ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13591da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
13601da177e4SLinus Torvalds 	.count =	32,
13611da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
13621da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
13631da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
13641da177e4SLinus Torvalds };
13651da177e4SLinus Torvalds 
1366eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13671da177e4SLinus Torvalds {
13681da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13691da177e4SLinus Torvalds 	uinfo->count = 3;
13701da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13711da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
13721da177e4SLinus Torvalds 	return 0;
13731da177e4SLinus Torvalds }
13741da177e4SLinus Torvalds 
1375eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1376eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
13771da177e4SLinus Torvalds {
1378eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1379eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1380eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13811da177e4SLinus Torvalds 	unsigned long flags;
13821da177e4SLinus Torvalds 	int idx;
13831da177e4SLinus Torvalds 
13841da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13851da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
13861da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->attn[idx];
13871da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13881da177e4SLinus Torvalds 	return 0;
13891da177e4SLinus Torvalds }
13901da177e4SLinus Torvalds 
1391eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1392eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
13931da177e4SLinus Torvalds {
13941da177e4SLinus Torvalds 	unsigned long flags;
1395eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1396eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1397eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13981da177e4SLinus Torvalds 	int change = 0, idx, val;
13991da177e4SLinus Torvalds 
14001da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14011da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
14021da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 0xffff;
14031da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
14041da177e4SLinus Torvalds 			mix->attn[idx] = val;
14051da177e4SLinus Torvalds 			change = 1;
14061da177e4SLinus Torvalds 		}
14071da177e4SLinus Torvalds 	}
14081da177e4SLinus Torvalds 	if (change && mix->epcm) {
14091da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
14101da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
14111da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
14121da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
14131da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
14141da177e4SLinus Torvalds 		}
14151da177e4SLinus Torvalds 	}
14161da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14171da177e4SLinus Torvalds 	return change;
14181da177e4SLinus Torvalds }
14191da177e4SLinus Torvalds 
1420f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control =
14211da177e4SLinus Torvalds {
14221da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
142367ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14241da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
14251da177e4SLinus Torvalds 	.count =	32,
14261da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
14271da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
14281da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
14291da177e4SLinus Torvalds };
14301da177e4SLinus Torvalds 
14311da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
14321da177e4SLinus Torvalds 
1433eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14341da177e4SLinus Torvalds {
1435eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14361da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14371da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
14381da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14391da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
14401da177e4SLinus Torvalds 	return 0;
14411da177e4SLinus Torvalds }
14421da177e4SLinus Torvalds 
1443eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1444eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14451da177e4SLinus Torvalds {
14461da177e4SLinus Torvalds 	unsigned long flags;
1447eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1448eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1449eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14501da177e4SLinus Torvalds 	int idx;
14511da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14521da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14531da177e4SLinus Torvalds 
14541da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14551da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
14561da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
14571da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
14581da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14591da177e4SLinus Torvalds 	return 0;
14601da177e4SLinus Torvalds }
14611da177e4SLinus Torvalds 
1462eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1463eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14641da177e4SLinus Torvalds {
14651da177e4SLinus Torvalds 	unsigned long flags;
1466eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14671da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1468eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
14691da177e4SLinus Torvalds 	int change = 0, idx, val;
14701da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14711da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14721da177e4SLinus Torvalds 
14731da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14741da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
14751da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
14761da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
14771da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
14781da177e4SLinus Torvalds 			change = 1;
14791da177e4SLinus Torvalds 		}
14801da177e4SLinus Torvalds 	}
14811da177e4SLinus Torvalds 
14821da177e4SLinus Torvalds 	if (change && mix->epcm) {
14831da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
14841da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
14851da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
14861da177e4SLinus Torvalds 		}
14871da177e4SLinus Torvalds 	}
14881da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14891da177e4SLinus Torvalds 	return change;
14901da177e4SLinus Torvalds }
14911da177e4SLinus Torvalds 
1492f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
14931da177e4SLinus Torvalds {
14941da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
14951da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14961da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
14971da177e4SLinus Torvalds 	.count =	16,
14981da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
14991da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
15001da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
15011da177e4SLinus Torvalds };
15021da177e4SLinus Torvalds 
1503eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15041da177e4SLinus Torvalds {
1505eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15061da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15071da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
15081da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
15091da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
15101da177e4SLinus Torvalds 	return 0;
15111da177e4SLinus Torvalds }
15121da177e4SLinus Torvalds 
1513eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1514eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
15151da177e4SLinus Torvalds {
15161da177e4SLinus Torvalds 	unsigned long flags;
1517eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1518eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1519eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15201da177e4SLinus Torvalds 	int idx;
15211da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15221da177e4SLinus Torvalds 
15231da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15241da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
15251da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
15261da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15271da177e4SLinus Torvalds 	return 0;
15281da177e4SLinus Torvalds }
15291da177e4SLinus Torvalds 
1530eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1531eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
15321da177e4SLinus Torvalds {
15331da177e4SLinus Torvalds 	unsigned long flags;
1534eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15351da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1536eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
15371da177e4SLinus Torvalds 	int change = 0, idx, val;
15381da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15391da177e4SLinus Torvalds 
15401da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15411da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
15421da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
15431da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
15441da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
15451da177e4SLinus Torvalds 			change = 1;
15461da177e4SLinus Torvalds 		}
15471da177e4SLinus Torvalds 	}
15481da177e4SLinus Torvalds 	if (change && mix->epcm) {
15491da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
15501da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
15511da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
15521da177e4SLinus Torvalds 		}
15531da177e4SLinus Torvalds 	}
15541da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15551da177e4SLinus Torvalds 	return change;
15561da177e4SLinus Torvalds }
15571da177e4SLinus Torvalds 
15581da177e4SLinus Torvalds 
1559f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
15601da177e4SLinus Torvalds {
15611da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15621da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15631da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
15641da177e4SLinus Torvalds 	.count =	16,
15651da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
15661da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
15671da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
15681da177e4SLinus Torvalds };
15691da177e4SLinus Torvalds 
1570eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15711da177e4SLinus Torvalds {
15721da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15731da177e4SLinus Torvalds 	uinfo->count = 1;
15741da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
15751da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
15761da177e4SLinus Torvalds 	return 0;
15771da177e4SLinus Torvalds }
15781da177e4SLinus Torvalds 
1579eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1580eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
15811da177e4SLinus Torvalds {
1582eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1583eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1584eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15851da177e4SLinus Torvalds 	unsigned long flags;
15861da177e4SLinus Torvalds 
15871da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15881da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = mix->attn[0];
15891da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15901da177e4SLinus Torvalds 	return 0;
15911da177e4SLinus Torvalds }
15921da177e4SLinus Torvalds 
1593eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1594eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
15951da177e4SLinus Torvalds {
15961da177e4SLinus Torvalds 	unsigned long flags;
1597eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15981da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1599eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
16001da177e4SLinus Torvalds 	int change = 0, val;
16011da177e4SLinus Torvalds 
16021da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
16031da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] & 0xffff;
16041da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
16051da177e4SLinus Torvalds 		mix->attn[0] = val;
16061da177e4SLinus Torvalds 		change = 1;
16071da177e4SLinus Torvalds 	}
16081da177e4SLinus Torvalds 	if (change && mix->epcm) {
16091da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
16101da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
16111da177e4SLinus Torvalds 		}
16121da177e4SLinus Torvalds 	}
16131da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
16141da177e4SLinus Torvalds 	return change;
16151da177e4SLinus Torvalds }
16161da177e4SLinus Torvalds 
1617f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
16181da177e4SLinus Torvalds {
16191da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
16201da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
16211da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
16221da177e4SLinus Torvalds 	.count =	16,
16231da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
16241da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
16251da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
16261da177e4SLinus Torvalds };
16271da177e4SLinus Torvalds 
1628a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
16291da177e4SLinus Torvalds 
1630eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1631eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
16321da177e4SLinus Torvalds {
1633eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
16341da177e4SLinus Torvalds 
16351da177e4SLinus Torvalds 	if (emu->audigy)
1636a1c87c0bSOswald Buddenhagen 		ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
16371da177e4SLinus Torvalds 	else
16381da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1639d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1640d2cd74b1STakashi Iwai 		ucontrol->value.integer.value[0] =
1641d2cd74b1STakashi Iwai 			!ucontrol->value.integer.value[0];
1642d2cd74b1STakashi Iwai 
16431da177e4SLinus Torvalds 	return 0;
16441da177e4SLinus Torvalds }
16451da177e4SLinus Torvalds 
1646eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1647eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
16481da177e4SLinus Torvalds {
16491da177e4SLinus Torvalds 	unsigned long flags;
1650eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1651d2cd74b1STakashi Iwai 	unsigned int reg, val, sw;
16521da177e4SLinus Torvalds 	int change = 0;
16531da177e4SLinus Torvalds 
1654d2cd74b1STakashi Iwai 	sw = ucontrol->value.integer.value[0];
1655d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1656d2cd74b1STakashi Iwai 		sw = !sw;
1657*50164f69SOswald Buddenhagen 	spin_lock_irqsave(&emu->emu_lock, flags);
1658184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1659184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1660184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
1661a1c87c0bSOswald Buddenhagen 		reg = inw(emu->port + A_IOCFG);
1662d2cd74b1STakashi Iwai 		val = sw ? A_IOCFG_GPOUT0 : 0;
16631da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
16641da177e4SLinus Torvalds 		if (change) {
16651da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
16661da177e4SLinus Torvalds 			reg |= val;
1667a1c87c0bSOswald Buddenhagen 			outw(reg | val, emu->port + A_IOCFG);
16681da177e4SLinus Torvalds 		}
16691da177e4SLinus Torvalds 	}
16701da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
1671d2cd74b1STakashi Iwai 	val = sw ? HCFG_GPOUT0 : 0;
16721da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
16731da177e4SLinus Torvalds 	if (change) {
16741da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
16751da177e4SLinus Torvalds 		reg |= val;
16761da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
16771da177e4SLinus Torvalds 	}
1678*50164f69SOswald Buddenhagen 	spin_unlock_irqrestore(&emu->emu_lock, flags);
16791da177e4SLinus Torvalds 	return change;
16801da177e4SLinus Torvalds }
16811da177e4SLinus Torvalds 
1682f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
16831da177e4SLinus Torvalds {
16841da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16851da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
16861da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
16871da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
16881da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
16891da177e4SLinus Torvalds };
16901da177e4SLinus Torvalds 
1691f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif =
16921da177e4SLinus Torvalds {
16931da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16941da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
16951da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
16961da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
16971da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
16981da177e4SLinus Torvalds };
16991da177e4SLinus Torvalds 
170016950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
170116950e09STakashi Iwai 
170216950e09STakashi Iwai #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
170316950e09STakashi Iwai 
170416950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
170516950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
170616950e09STakashi Iwai {
170716950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
170816950e09STakashi Iwai 	unsigned int val;
170916950e09STakashi Iwai 
171016950e09STakashi Iwai 	/* FIXME: better to use a cached version */
171116950e09STakashi Iwai 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
171216950e09STakashi Iwai 	ucontrol->value.integer.value[0] = !!val;
171316950e09STakashi Iwai 	return 0;
171416950e09STakashi Iwai }
171516950e09STakashi Iwai 
171616950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
171716950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
171816950e09STakashi Iwai {
171916950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
172016950e09STakashi Iwai 	unsigned int val;
172116950e09STakashi Iwai 
172216950e09STakashi Iwai 	if (ucontrol->value.integer.value[0])
172316950e09STakashi Iwai 		val = 0x0f0f;
172416950e09STakashi Iwai 	else
172516950e09STakashi Iwai 		val = 0;
172616950e09STakashi Iwai 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
172716950e09STakashi Iwai }
172816950e09STakashi Iwai 
1729f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost =
173016950e09STakashi Iwai {
173116950e09STakashi Iwai 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
17322a52feb1SMaciej S. Szmigiero 	.name =		"Mic Extra Boost",
173316950e09STakashi Iwai 	.info =		snd_audigy_capture_boost_info,
173416950e09STakashi Iwai 	.get =		snd_audigy_capture_boost_get,
173516950e09STakashi Iwai 	.put =		snd_audigy_capture_boost_put
173616950e09STakashi Iwai };
173716950e09STakashi Iwai 
173816950e09STakashi Iwai 
17391da177e4SLinus Torvalds /*
17401da177e4SLinus Torvalds  */
1741eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
17421da177e4SLinus Torvalds {
1743eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
17441da177e4SLinus Torvalds 	emu->ac97 = NULL;
17451da177e4SLinus Torvalds }
17461da177e4SLinus Torvalds 
17471da177e4SLinus Torvalds /*
17481da177e4SLinus Torvalds  */
1749eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
17501da177e4SLinus Torvalds {
1751eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
17521da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
17531da177e4SLinus Torvalds 	strcpy(id.name, name);
17541da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
17551da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
17561da177e4SLinus Torvalds }
17571da177e4SLinus Torvalds 
1758eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
17591da177e4SLinus Torvalds {
1760eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
17611da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
17621da177e4SLinus Torvalds 	strcpy(sid.name, name);
17631da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
17641da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
17651da177e4SLinus Torvalds }
17661da177e4SLinus Torvalds 
1767eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
17681da177e4SLinus Torvalds {
1769eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
17701da177e4SLinus Torvalds 	if (kctl) {
177136476b81SMaciej S. Szmigiero 		snd_ctl_rename(card, kctl, dst);
17721da177e4SLinus Torvalds 		return 0;
17731da177e4SLinus Torvalds 	}
17741da177e4SLinus Torvalds 	return -ENOENT;
17751da177e4SLinus Torvalds }
17761da177e4SLinus Torvalds 
1777e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
177867ed4161SClemens Ladisch 		      int pcm_device, int multi_device)
17791da177e4SLinus Torvalds {
17801da177e4SLinus Torvalds 	int err, pcm;
1781eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1782eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
17836fddce26STakashi Iwai 	const char * const *c;
17846fddce26STakashi Iwai 	static const char * const emu10k1_remove_ctls[] = {
17851da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
17861da177e4SLinus Torvalds 		"Master Mono Playback Switch",
17871da177e4SLinus Torvalds 		"Master Mono Playback Volume",
17881da177e4SLinus Torvalds 		"PCM Out Path & Mute",
17891da177e4SLinus Torvalds 		"Mono Output Select",
17901da177e4SLinus Torvalds 		"Surround Playback Switch",
17911da177e4SLinus Torvalds 		"Surround Playback Volume",
17921da177e4SLinus Torvalds 		"Center Playback Switch",
17931da177e4SLinus Torvalds 		"Center Playback Volume",
17941da177e4SLinus Torvalds 		"LFE Playback Switch",
17951da177e4SLinus Torvalds 		"LFE Playback Volume",
17961da177e4SLinus Torvalds 		NULL
17971da177e4SLinus Torvalds 	};
17986fddce26STakashi Iwai 	static const char * const emu10k1_rename_ctls[] = {
17991da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
18001da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
18011da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
18021da177e4SLinus Torvalds 		NULL
18031da177e4SLinus Torvalds 	};
18046fddce26STakashi Iwai 	static const char * const audigy_remove_ctls[] = {
18051da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
180621fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
180721fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
18081da177e4SLinus Torvalds 		"PCM Playback Switch",
18091da177e4SLinus Torvalds 		"PCM Playback Volume",
18101da177e4SLinus Torvalds 		"Master Playback Switch",
18111da177e4SLinus Torvalds 		"Master Playback Volume",
18121da177e4SLinus Torvalds 		"PCM Out Path & Mute",
18131da177e4SLinus Torvalds 		"Mono Output Select",
18141da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
18151da177e4SLinus Torvalds 		"Capture Source",
18161da177e4SLinus Torvalds 		"Capture Switch",
18171da177e4SLinus Torvalds 		"Capture Volume",
18181da177e4SLinus Torvalds 		"Mic Select",
1819274b2000SMaciej S. Szmigiero 		"Headphone Playback Switch",
1820274b2000SMaciej S. Szmigiero 		"Headphone Playback Volume",
1821274b2000SMaciej S. Szmigiero 		"3D Control - Center",
1822274b2000SMaciej S. Szmigiero 		"3D Control - Depth",
1823274b2000SMaciej S. Szmigiero 		"3D Control - Switch",
18241da177e4SLinus Torvalds 		"Video Playback Switch",
18251da177e4SLinus Torvalds 		"Video Playback Volume",
18261da177e4SLinus Torvalds 		"Mic Playback Switch",
18271da177e4SLinus Torvalds 		"Mic Playback Volume",
1828274b2000SMaciej S. Szmigiero 		"External Amplifier",
18291da177e4SLinus Torvalds 		NULL
18301da177e4SLinus Torvalds 	};
18316fddce26STakashi Iwai 	static const char * const audigy_rename_ctls[] = {
18321da177e4SLinus Torvalds 		/* use conventional names */
18331da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
18341da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
18351da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
18361da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
183752051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
183852051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
18391da177e4SLinus Torvalds 		NULL
18401da177e4SLinus Torvalds 	};
18416fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_i2c_adc[] = {
1842184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1843184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1844184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1845184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1846184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1847eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1848184c1e2cSJames Courtier-Dutton 		NULL
1849184c1e2cSJames Courtier-Dutton 	};
18506fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_i2c_adc[] = {
1851184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1852184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1853184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1854184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1855184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1856eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1857184c1e2cSJames Courtier-Dutton 		NULL
1858184c1e2cSJames Courtier-Dutton 	};
18596fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_1361t_adc[] = {
186021fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
186121fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
186221fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
186321fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
186421fdddeaSJames Courtier-Dutton 		"Capture Source",
186521fdddeaSJames Courtier-Dutton 		"Capture Switch",
186621fdddeaSJames Courtier-Dutton 		"Capture Volume",
186721fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
186821fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
186921fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
187021fdddeaSJames Courtier-Dutton 		"3D Control - Center",
187121fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
187221fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
187321fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
187421fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
187521fdddeaSJames Courtier-Dutton 		NULL
187621fdddeaSJames Courtier-Dutton 	};
18776fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_1361t_adc[] = {
187821fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
187921fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
188021fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1881d355c82aSJaroslav Kysela 		"Beep Playback Switch", "Beep Capture Switch",
1882d355c82aSJaroslav Kysela 		"Beep Playback Volume", "Beep Capture Volume",
188321fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
188421fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
188521fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
188621fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
188721fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
188821fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
188921fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
189021fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
189121fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
189221fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
189321fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
189421fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
189552051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
189652051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
189721fdddeaSJames Courtier-Dutton 		NULL
189821fdddeaSJames Courtier-Dutton 	};
18991da177e4SLinus Torvalds 
19002b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1901eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1902eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
190351055da5STakashi Iwai 		static const struct snd_ac97_bus_ops ops = {
19041da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
19051da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
19061da177e4SLinus Torvalds 		};
19071da177e4SLinus Torvalds 
190812bda107STakashi Iwai 		err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus);
190912bda107STakashi Iwai 		if (err < 0)
19101da177e4SLinus Torvalds 			return err;
19111da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
19121da177e4SLinus Torvalds 
19131da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
19141da177e4SLinus Torvalds 		ac97.private_data = emu;
19151da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
19161da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
191712bda107STakashi Iwai 		err = snd_ac97_mixer(pbus, &ac97, &emu->ac97);
191812bda107STakashi Iwai 		if (err < 0) {
1919b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
19201da177e4SLinus Torvalds 				return err;
19216f002b02STakashi Iwai 			dev_info(emu->card->dev,
19226f002b02STakashi Iwai 				 "AC97 is optional on this board\n");
19236f002b02STakashi Iwai 			dev_info(emu->card->dev,
19246f002b02STakashi Iwai 				 "Proceeding without ac97 mixers...\n");
1925b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1926b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1927b1508693STakashi Iwai 		}
19281da177e4SLinus Torvalds 		if (emu->audigy) {
19291da177e4SLinus Torvalds 			/* set master volume to 0 dB */
19304d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
19311da177e4SLinus Torvalds 			/* set capture source to mic */
19324d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
193352051942SMaciej S. Szmigiero 			/* set mono output (TAD) to mic */
193452051942SMaciej S. Szmigiero 			snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE,
193552051942SMaciej S. Szmigiero 				0x0200, 0x0200);
193621fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
193721fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
193821fdddeaSJames Courtier-Dutton 			else
19391da177e4SLinus Torvalds 				c = audigy_remove_ctls;
19401da177e4SLinus Torvalds 		} else {
19411da177e4SLinus Torvalds 			/*
19421da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
19431da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
19441da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
19451da177e4SLinus Torvalds 			 */
19461da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
19471da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
19481da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
19492594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
1950b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Volume");
1951b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Switch");
19521da177e4SLinus Torvalds 			}
19531da177e4SLinus Torvalds 			/* remove unused AC97 controls */
19544d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
19554d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
19561da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
19571da177e4SLinus Torvalds 		}
19581da177e4SLinus Torvalds 		for (; *c; c++)
19591da177e4SLinus Torvalds 			remove_ctl(card, *c);
1960184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1961184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1962184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1963184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
19641da177e4SLinus Torvalds 	} else {
1965f12aa40cSTakashi Iwai 	no_ac97:
19662b637da5SLee Revell 		if (emu->card_capabilities->ecard)
19671da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
19681da177e4SLinus Torvalds 		else if (emu->audigy)
19691da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
19701da177e4SLinus Torvalds 		else
19711da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
19721da177e4SLinus Torvalds 	}
19731da177e4SLinus Torvalds 
19741da177e4SLinus Torvalds 	if (emu->audigy)
197521fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
197621fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1977184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1978184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
197921fdddeaSJames Courtier-Dutton 		else
19801da177e4SLinus Torvalds 			c = audigy_rename_ctls;
19811da177e4SLinus Torvalds 	else
19821da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
19831da177e4SLinus Torvalds 	for (; *c; c += 2)
19841da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
198521fdddeaSJames Courtier-Dutton 
1986e217b960SRaymond Yau 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
1987e217b960SRaymond Yau 		remove_ctl(card, "Center Playback Volume");
1988e217b960SRaymond Yau 		remove_ctl(card, "LFE Playback Volume");
1989e217b960SRaymond Yau 		remove_ctl(card, "Wave Center Playback Volume");
1990e217b960SRaymond Yau 		remove_ctl(card, "Wave LFE Playback Volume");
1991e217b960SRaymond Yau 	}
1992e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1993e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1994e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1995e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1996e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1997e3b9bc0eSJames Courtier-Dutton 	}
199812bda107STakashi Iwai 	kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu);
199912bda107STakashi Iwai 	if (!kctl)
20001da177e4SLinus Torvalds 		return -ENOMEM;
200167ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
200212bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
200312bda107STakashi Iwai 	if (err)
20041da177e4SLinus Torvalds 		return err;
200512bda107STakashi Iwai 	kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu);
200612bda107STakashi Iwai 	if (!kctl)
20071da177e4SLinus Torvalds 		return -ENOMEM;
200867ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
200912bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
201012bda107STakashi Iwai 	if (err)
20111da177e4SLinus Torvalds 		return err;
201212bda107STakashi Iwai 	kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu);
201312bda107STakashi Iwai 	if (!kctl)
20141da177e4SLinus Torvalds 		return -ENOMEM;
201567ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
201612bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
201712bda107STakashi Iwai 	if (err)
20181da177e4SLinus Torvalds 		return err;
20191da177e4SLinus Torvalds 
202012bda107STakashi Iwai 	kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu);
202112bda107STakashi Iwai 	if (!kctl)
20221da177e4SLinus Torvalds 		return -ENOMEM;
202367ed4161SClemens Ladisch 	kctl->id.device = multi_device;
202412bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
202512bda107STakashi Iwai 	if (err)
20261da177e4SLinus Torvalds 		return err;
20271da177e4SLinus Torvalds 
202812bda107STakashi Iwai 	kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu);
202912bda107STakashi Iwai 	if (!kctl)
20301da177e4SLinus Torvalds 		return -ENOMEM;
203167ed4161SClemens Ladisch 	kctl->id.device = multi_device;
203212bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
203312bda107STakashi Iwai 	if (err)
20341da177e4SLinus Torvalds 		return err;
20351da177e4SLinus Torvalds 
203612bda107STakashi Iwai 	kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu);
203712bda107STakashi Iwai 	if (!kctl)
20381da177e4SLinus Torvalds 		return -ENOMEM;
203967ed4161SClemens Ladisch 	kctl->id.device = multi_device;
204012bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
204112bda107STakashi Iwai 	if (err)
20421da177e4SLinus Torvalds 		return err;
20431da177e4SLinus Torvalds 
20441da177e4SLinus Torvalds 	/* initialize the routing and volume table for each pcm playback stream */
20451da177e4SLinus Torvalds 	for (pcm = 0; pcm < 32; pcm++) {
2046eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
20471da177e4SLinus Torvalds 		int v;
20481da177e4SLinus Torvalds 
20491da177e4SLinus Torvalds 		mix = &emu->pcm_mixer[pcm];
20501da177e4SLinus Torvalds 		mix->epcm = NULL;
20511da177e4SLinus Torvalds 
20521da177e4SLinus Torvalds 		for (v = 0; v < 4; v++)
20531da177e4SLinus Torvalds 			mix->send_routing[0][v] =
20541da177e4SLinus Torvalds 				mix->send_routing[1][v] =
20551da177e4SLinus Torvalds 				mix->send_routing[2][v] = v;
20561da177e4SLinus Torvalds 
20571da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
20581da177e4SLinus Torvalds 		mix->send_volume[0][0] = mix->send_volume[0][1] =
20591da177e4SLinus Torvalds 		mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
20601da177e4SLinus Torvalds 
20611da177e4SLinus Torvalds 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
20621da177e4SLinus Torvalds 	}
20631da177e4SLinus Torvalds 
20641da177e4SLinus Torvalds 	/* initialize the routing and volume table for the multichannel playback stream */
20651da177e4SLinus Torvalds 	for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
2066eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
20671da177e4SLinus Torvalds 		int v;
20681da177e4SLinus Torvalds 
20691da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[pcm];
20701da177e4SLinus Torvalds 		mix->epcm = NULL;
20711da177e4SLinus Torvalds 
20721da177e4SLinus Torvalds 		mix->send_routing[0][0] = pcm;
20731da177e4SLinus Torvalds 		mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
20741da177e4SLinus Torvalds 		for (v = 0; v < 2; v++)
20751da177e4SLinus Torvalds 			mix->send_routing[0][2+v] = 13+v;
20761da177e4SLinus Torvalds 		if (emu->audigy)
20771da177e4SLinus Torvalds 			for (v = 0; v < 4; v++)
20781da177e4SLinus Torvalds 				mix->send_routing[0][4+v] = 60+v;
20791da177e4SLinus Torvalds 
20801da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
20811da177e4SLinus Torvalds 		mix->send_volume[0][0]  = 255;
20821da177e4SLinus Torvalds 
20831da177e4SLinus Torvalds 		mix->attn[0] = 0xffff;
20841da177e4SLinus Torvalds 	}
20851da177e4SLinus Torvalds 
20862b637da5SLee Revell 	if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
20871da177e4SLinus Torvalds 		/* sb live! and audigy */
208812bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu);
208912bda107STakashi Iwai 		if (!kctl)
20901da177e4SLinus Torvalds 			return -ENOMEM;
20915549d549SClemens Ladisch 		if (!emu->audigy)
20925549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
209312bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
209412bda107STakashi Iwai 		if (err)
20951da177e4SLinus Torvalds 			return err;
209612bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu);
209712bda107STakashi Iwai 		if (!kctl)
20981da177e4SLinus Torvalds 			return -ENOMEM;
20995549d549SClemens Ladisch 		if (!emu->audigy)
21005549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
210112bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
210212bda107STakashi Iwai 		if (err)
21031da177e4SLinus Torvalds 			return err;
21041da177e4SLinus Torvalds 	}
21051da177e4SLinus Torvalds 
2106190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
210719b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
210819b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
210912bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu);
211012bda107STakashi Iwai 		if (!kctl)
21111da177e4SLinus Torvalds 			return -ENOMEM;
211212bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
211312bda107STakashi Iwai 		if (err)
21141da177e4SLinus Torvalds 			return err;
2115001f7589SJames Courtier-Dutton #if 0
211612bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu);
211712bda107STakashi Iwai 		if (!kctl)
21181da177e4SLinus Torvalds 			return -ENOMEM;
211912bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
212012bda107STakashi Iwai 		if (err)
21211da177e4SLinus Torvalds 			return err;
2122001f7589SJames Courtier-Dutton #endif
21232b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
21241da177e4SLinus Torvalds 		/* sb live! */
212512bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu);
212612bda107STakashi Iwai 		if (!kctl)
21271da177e4SLinus Torvalds 			return -ENOMEM;
212812bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
212912bda107STakashi Iwai 		if (err)
21301da177e4SLinus Torvalds 			return err;
21311da177e4SLinus Torvalds 	}
21322b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
213312bda107STakashi Iwai 		err = snd_p16v_mixer(emu);
213412bda107STakashi Iwai 		if (err)
21351da177e4SLinus Torvalds 			return err;
21361da177e4SLinus Torvalds 	}
21371da177e4SLinus Torvalds 
21383839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
21391c02e366SCtirad Fertr 		/* 1616(m) cardbus */
21409f4bd5ddSJames Courtier-Dutton 		int i;
21419f4bd5ddSJames Courtier-Dutton 
21421c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) {
21431c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21441c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1616_output_enum_ctls[i],
21451c02e366SCtirad Fertr 					     emu));
21469f4bd5ddSJames Courtier-Dutton 			if (err < 0)
21479f4bd5ddSJames Courtier-Dutton 				return err;
21489f4bd5ddSJames Courtier-Dutton 		}
21499f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
21501c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21511c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
21521c02e366SCtirad Fertr 					     emu));
21531c02e366SCtirad Fertr 			if (err < 0)
21541c02e366SCtirad Fertr 				return err;
21551c02e366SCtirad Fertr 		}
21561c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) {
21571c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21581c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
21591c02e366SCtirad Fertr 			if (err < 0)
21601c02e366SCtirad Fertr 				return err;
21611c02e366SCtirad Fertr 		}
21621c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) {
21631c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21641c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
21651c02e366SCtirad Fertr 			if (err < 0)
21661c02e366SCtirad Fertr 				return err;
21671c02e366SCtirad Fertr 		}
21681c02e366SCtirad Fertr 		err = snd_ctl_add(card,
21691c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
21701c02e366SCtirad Fertr 		if (err < 0)
21711c02e366SCtirad Fertr 			return err;
217299dcab46SMichael Gernoth 		err = snd_ctl_add(card,
217399dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
217499dcab46SMichael Gernoth 		if (err < 0)
217599dcab46SMichael Gernoth 			return err;
217699dcab46SMichael Gernoth 		err = snd_ctl_add(card,
217799dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
217899dcab46SMichael Gernoth 		if (err < 0)
217999dcab46SMichael Gernoth 			return err;
21801c02e366SCtirad Fertr 
218188aa1390STakashi Iwai 	} else if (emu->card_capabilities->emu_model) {
21821c02e366SCtirad Fertr 		/* all other e-mu cards for now */
21831c02e366SCtirad Fertr 		int i;
21841c02e366SCtirad Fertr 
21851c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
21861c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21871c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_output_enum_ctls[i],
21881c02e366SCtirad Fertr 					     emu));
21891c02e366SCtirad Fertr 			if (err < 0)
21901c02e366SCtirad Fertr 				return err;
21911c02e366SCtirad Fertr 		}
21921c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
21931c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21941c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
21951c02e366SCtirad Fertr 					     emu));
21969f4bd5ddSJames Courtier-Dutton 			if (err < 0)
21979f4bd5ddSJames Courtier-Dutton 				return err;
21989f4bd5ddSJames Courtier-Dutton 		}
21999148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
22001c02e366SCtirad Fertr 			err = snd_ctl_add(card,
22011c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
22029148cc50SJames Courtier-Dutton 			if (err < 0)
22039148cc50SJames Courtier-Dutton 				return err;
22049148cc50SJames Courtier-Dutton 		}
22059148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
22061c02e366SCtirad Fertr 			err = snd_ctl_add(card,
22071c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
22089148cc50SJames Courtier-Dutton 			if (err < 0)
22099148cc50SJames Courtier-Dutton 				return err;
22109148cc50SJames Courtier-Dutton 		}
22111c02e366SCtirad Fertr 		err = snd_ctl_add(card,
22121c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
2213b0dbdaeaSJames Courtier-Dutton 		if (err < 0)
2214b0dbdaeaSJames Courtier-Dutton 			return err;
221599dcab46SMichael Gernoth 		err = snd_ctl_add(card,
221699dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
221799dcab46SMichael Gernoth 		if (err < 0)
221899dcab46SMichael Gernoth 			return err;
221999dcab46SMichael Gernoth 		err = snd_ctl_add(card,
222099dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
222199dcab46SMichael Gernoth 		if (err < 0)
222299dcab46SMichael Gernoth 			return err;
22239f4bd5ddSJames Courtier-Dutton 	}
22249f4bd5ddSJames Courtier-Dutton 
2225184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2226184c1e2cSJames Courtier-Dutton 		int i;
2227184c1e2cSJames Courtier-Dutton 
2228184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2229184c1e2cSJames Courtier-Dutton 		if (err < 0)
2230184c1e2cSJames Courtier-Dutton 			return err;
2231184c1e2cSJames Courtier-Dutton 
2232184c1e2cSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
2233184c1e2cSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
2234184c1e2cSJames Courtier-Dutton 			if (err < 0)
2235184c1e2cSJames Courtier-Dutton 				return err;
2236184c1e2cSJames Courtier-Dutton 		}
2237184c1e2cSJames Courtier-Dutton 	}
2238184c1e2cSJames Courtier-Dutton 
223916950e09STakashi Iwai 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
224016950e09STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
224116950e09STakashi Iwai 						     emu));
224216950e09STakashi Iwai 		if (err < 0)
224316950e09STakashi Iwai 			return err;
224416950e09STakashi Iwai 	}
224516950e09STakashi Iwai 
22461da177e4SLinus Torvalds 	return 0;
22471da177e4SLinus Torvalds }
2248