xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision a8661af513040ed522e27d0e5339b3f757c1a351)
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 
4574415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
4674415a36SJames Courtier-Dutton 	if (idx >= 3)
4774415a36SJames Courtier-Dutton 		return -EINVAL;
481da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
491da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
501da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
511da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
521da177e4SLinus Torvalds 	return 0;
531da177e4SLinus Torvalds }
541da177e4SLinus Torvalds 
55eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
56eb4698f3STakashi Iwai 				      struct snd_ctl_elem_value *ucontrol)
571da177e4SLinus Torvalds {
581da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
591da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
601da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
611da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
621da177e4SLinus Torvalds 	return 0;
631da177e4SLinus Torvalds }
641da177e4SLinus Torvalds 
6513d45709SPavel Hofman /*
6613d45709SPavel Hofman  * Items labels in enum mixer controls assigning source data to
6713d45709SPavel Hofman  * each destination
6813d45709SPavel Hofman  */
691541c66dSTakashi Iwai static const char * const emu1010_src_texts[] = {
709f4bd5ddSJames Courtier-Dutton 	"Silence",
719f4bd5ddSJames Courtier-Dutton 	"Dock Mic A",
729f4bd5ddSJames Courtier-Dutton 	"Dock Mic B",
739f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Left",
749f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Right",
759f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Left",
769f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Right",
779f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Left",
789f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Right",
799f4bd5ddSJames Courtier-Dutton 	"0202 ADC Left",
809f4bd5ddSJames Courtier-Dutton 	"0202 ADC Right",
81946233bbSOswald Buddenhagen 	"1010 SPDIF Left",
82946233bbSOswald Buddenhagen 	"1010 SPDIF Right",
83946233bbSOswald Buddenhagen 	"1010 ADAT 0",
84946233bbSOswald Buddenhagen 	"1010 ADAT 1",
85946233bbSOswald Buddenhagen 	"1010 ADAT 2",
86946233bbSOswald Buddenhagen 	"1010 ADAT 3",
87946233bbSOswald Buddenhagen 	"1010 ADAT 4",
88946233bbSOswald Buddenhagen 	"1010 ADAT 5",
89946233bbSOswald Buddenhagen 	"1010 ADAT 6",
90946233bbSOswald Buddenhagen 	"1010 ADAT 7",
919f4bd5ddSJames Courtier-Dutton 	"DSP 0",
929f4bd5ddSJames Courtier-Dutton 	"DSP 1",
939f4bd5ddSJames Courtier-Dutton 	"DSP 2",
949f4bd5ddSJames Courtier-Dutton 	"DSP 3",
959f4bd5ddSJames Courtier-Dutton 	"DSP 4",
969f4bd5ddSJames Courtier-Dutton 	"DSP 5",
979f4bd5ddSJames Courtier-Dutton 	"DSP 6",
989f4bd5ddSJames Courtier-Dutton 	"DSP 7",
999f4bd5ddSJames Courtier-Dutton 	"DSP 8",
1009f4bd5ddSJames Courtier-Dutton 	"DSP 9",
1019f4bd5ddSJames Courtier-Dutton 	"DSP 10",
1029f4bd5ddSJames Courtier-Dutton 	"DSP 11",
1039f4bd5ddSJames Courtier-Dutton 	"DSP 12",
1049f4bd5ddSJames Courtier-Dutton 	"DSP 13",
1059f4bd5ddSJames Courtier-Dutton 	"DSP 14",
1069f4bd5ddSJames Courtier-Dutton 	"DSP 15",
1079f4bd5ddSJames Courtier-Dutton 	"DSP 16",
1089f4bd5ddSJames Courtier-Dutton 	"DSP 17",
1099f4bd5ddSJames Courtier-Dutton 	"DSP 18",
1109f4bd5ddSJames Courtier-Dutton 	"DSP 19",
1119f4bd5ddSJames Courtier-Dutton 	"DSP 20",
1129f4bd5ddSJames Courtier-Dutton 	"DSP 21",
1139f4bd5ddSJames Courtier-Dutton 	"DSP 22",
1149f4bd5ddSJames Courtier-Dutton 	"DSP 23",
1159f4bd5ddSJames Courtier-Dutton 	"DSP 24",
1169f4bd5ddSJames Courtier-Dutton 	"DSP 25",
1179f4bd5ddSJames Courtier-Dutton 	"DSP 26",
1189f4bd5ddSJames Courtier-Dutton 	"DSP 27",
1199f4bd5ddSJames Courtier-Dutton 	"DSP 28",
1209f4bd5ddSJames Courtier-Dutton 	"DSP 29",
1219f4bd5ddSJames Courtier-Dutton 	"DSP 30",
1229f4bd5ddSJames Courtier-Dutton 	"DSP 31",
1239f4bd5ddSJames Courtier-Dutton };
1249f4bd5ddSJames Courtier-Dutton 
1251c02e366SCtirad Fertr /* 1616(m) cardbus */
1261c02e366SCtirad Fertr 
1271541c66dSTakashi Iwai static const char * const emu1616_src_texts[] = {
1281c02e366SCtirad Fertr 	"Silence",
129946233bbSOswald Buddenhagen 	"Mic A",
130946233bbSOswald Buddenhagen 	"Mic B",
131946233bbSOswald Buddenhagen 	"ADC1 Left",
132946233bbSOswald Buddenhagen 	"ADC1 Right",
133946233bbSOswald Buddenhagen 	"ADC2 Left",
134946233bbSOswald Buddenhagen 	"ADC2 Right",
135946233bbSOswald Buddenhagen 	"SPDIF Left",
136946233bbSOswald Buddenhagen 	"SPDIF Right",
1371c02e366SCtirad Fertr 	"ADAT 0",
1381c02e366SCtirad Fertr 	"ADAT 1",
1391c02e366SCtirad Fertr 	"ADAT 2",
1401c02e366SCtirad Fertr 	"ADAT 3",
1411c02e366SCtirad Fertr 	"ADAT 4",
1421c02e366SCtirad Fertr 	"ADAT 5",
1431c02e366SCtirad Fertr 	"ADAT 6",
1441c02e366SCtirad Fertr 	"ADAT 7",
1451c02e366SCtirad Fertr 	"DSP 0",
1461c02e366SCtirad Fertr 	"DSP 1",
1471c02e366SCtirad Fertr 	"DSP 2",
1481c02e366SCtirad Fertr 	"DSP 3",
1491c02e366SCtirad Fertr 	"DSP 4",
1501c02e366SCtirad Fertr 	"DSP 5",
1511c02e366SCtirad Fertr 	"DSP 6",
1521c02e366SCtirad Fertr 	"DSP 7",
1531c02e366SCtirad Fertr 	"DSP 8",
1541c02e366SCtirad Fertr 	"DSP 9",
1551c02e366SCtirad Fertr 	"DSP 10",
1561c02e366SCtirad Fertr 	"DSP 11",
1571c02e366SCtirad Fertr 	"DSP 12",
1581c02e366SCtirad Fertr 	"DSP 13",
1591c02e366SCtirad Fertr 	"DSP 14",
1601c02e366SCtirad Fertr 	"DSP 15",
1611c02e366SCtirad Fertr 	"DSP 16",
1621c02e366SCtirad Fertr 	"DSP 17",
1631c02e366SCtirad Fertr 	"DSP 18",
1641c02e366SCtirad Fertr 	"DSP 19",
1651c02e366SCtirad Fertr 	"DSP 20",
1661c02e366SCtirad Fertr 	"DSP 21",
1671c02e366SCtirad Fertr 	"DSP 22",
1681c02e366SCtirad Fertr 	"DSP 23",
1691c02e366SCtirad Fertr 	"DSP 24",
1701c02e366SCtirad Fertr 	"DSP 25",
1711c02e366SCtirad Fertr 	"DSP 26",
1721c02e366SCtirad Fertr 	"DSP 27",
1731c02e366SCtirad Fertr 	"DSP 28",
1741c02e366SCtirad Fertr 	"DSP 29",
1751c02e366SCtirad Fertr 	"DSP 30",
1761c02e366SCtirad Fertr 	"DSP 31",
1771c02e366SCtirad Fertr };
1781c02e366SCtirad Fertr 
1791c02e366SCtirad Fertr 
18013d45709SPavel Hofman /*
18113d45709SPavel Hofman  * List of data sources available for each destination
18213d45709SPavel Hofman  */
1836fddce26STakashi Iwai static const unsigned int emu1010_src_regs[] = {
1849f4bd5ddSJames Courtier-Dutton 	EMU_SRC_SILENCE,/* 0 */
1859f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_MIC_A1, /* 1 */
1869f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_MIC_B1, /* 2 */
1879f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */
1889f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */
1899f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */
1909f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */
1919f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */
1929f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */
1939f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */
1949f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */
1959f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */
1969f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */
1979f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT, /* 13 */
1989f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+1, /* 14 */
1999f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+2, /* 15 */
2009f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+3, /* 16 */
2019f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+4, /* 17 */
2029f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+5, /* 18 */
2039f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+6, /* 19 */
2049f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+7, /* 20 */
2059f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A, /* 21 */
2069f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+1, /* 22 */
2079f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+2, /* 23 */
2089f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+3, /* 24 */
2099f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+4, /* 25 */
2109f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+5, /* 26 */
2119f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+6, /* 27 */
2129f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+7, /* 28 */
2139f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+8, /* 29 */
2149f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+9, /* 30 */
2159f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xa, /* 31 */
2169f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xb, /* 32 */
2179f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xc, /* 33 */
2189f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xd, /* 34 */
2199f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xe, /* 35 */
2209f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xf, /* 36 */
2219f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B, /* 37 */
2229f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+1, /* 38 */
2239f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+2, /* 39 */
2249f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+3, /* 40 */
2259f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+4, /* 41 */
2269f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+5, /* 42 */
2279f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+6, /* 43 */
2289f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+7, /* 44 */
2299f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+8, /* 45 */
2309f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+9, /* 46 */
2319f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xa, /* 47 */
2329f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xb, /* 48 */
2339f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xc, /* 49 */
2349f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xd, /* 50 */
2359f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xe, /* 51 */
2369f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
2379f4bd5ddSJames Courtier-Dutton };
2389f4bd5ddSJames Courtier-Dutton 
2391c02e366SCtirad Fertr /* 1616(m) cardbus */
2406fddce26STakashi Iwai static const unsigned int emu1616_src_regs[] = {
2411c02e366SCtirad Fertr 	EMU_SRC_SILENCE,
2421c02e366SCtirad Fertr 	EMU_SRC_DOCK_MIC_A1,
2431c02e366SCtirad Fertr 	EMU_SRC_DOCK_MIC_B1,
2441c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC1_LEFT1,
2451c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC1_RIGHT1,
2461c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC2_LEFT1,
2471c02e366SCtirad Fertr 	EMU_SRC_DOCK_ADC2_RIGHT1,
2481c02e366SCtirad Fertr 	EMU_SRC_MDOCK_SPDIF_LEFT1,
2491c02e366SCtirad Fertr 	EMU_SRC_MDOCK_SPDIF_RIGHT1,
2501c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT,
2511c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+1,
2521c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+2,
2531c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+3,
2541c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+4,
2551c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+5,
2561c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+6,
2571c02e366SCtirad Fertr 	EMU_SRC_MDOCK_ADAT+7,
2581c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A,
2591c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+1,
2601c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+2,
2611c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+3,
2621c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+4,
2631c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+5,
2641c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+6,
2651c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+7,
2661c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+8,
2671c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+9,
2681c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xa,
2691c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xb,
2701c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xc,
2711c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xd,
2721c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xe,
2731c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32A+0xf,
2741c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B,
2751c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+1,
2761c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+2,
2771c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+3,
2781c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+4,
2791c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+5,
2801c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+6,
2811c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+7,
2821c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+8,
2831c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+9,
2841c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xa,
2851c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xb,
2861c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xc,
2871c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xd,
2881c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xe,
2891c02e366SCtirad Fertr 	EMU_SRC_ALICE_EMU32B+0xf,
2901c02e366SCtirad Fertr };
2911c02e366SCtirad Fertr 
29213d45709SPavel Hofman /*
29313d45709SPavel Hofman  * Data destinations - physical EMU outputs.
29413d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
29513d45709SPavel Hofman  */
2966fddce26STakashi Iwai static const unsigned int emu1010_output_dst[] = {
2979f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
2989f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
2999f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC2_LEFT1, /* 2 */
3009f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */
3019f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC3_LEFT1, /* 4 */
3029f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */
3039f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC4_LEFT1, /* 6 */
3049f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */
3059f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_PHONES_LEFT1, /* 8 */
3069f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */
3079f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */
3089f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */
3099f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_SPDIF_LEFT1, /* 12 */
3109f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */
3119f4bd5ddSJames Courtier-Dutton 	EMU_DST_HAMOA_DAC_LEFT1, /* 14 */
3129f4bd5ddSJames Courtier-Dutton 	EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */
3139f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT, /* 16 */
3149f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+1, /* 17 */
3159f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+2, /* 18 */
3169f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+3, /* 19 */
3179f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+4, /* 20 */
3189f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+5, /* 21 */
3199f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+6, /* 22 */
3209f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+7, /* 23 */
3219f4bd5ddSJames Courtier-Dutton };
3229f4bd5ddSJames Courtier-Dutton 
3231c02e366SCtirad Fertr /* 1616(m) cardbus */
3246fddce26STakashi Iwai static const unsigned int emu1616_output_dst[] = {
3251c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC1_LEFT1,
3261c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC1_RIGHT1,
3271c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC2_LEFT1,
3281c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC2_RIGHT1,
3291c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC3_LEFT1,
3301c02e366SCtirad Fertr 	EMU_DST_DOCK_DAC3_RIGHT1,
3311c02e366SCtirad Fertr 	EMU_DST_MDOCK_SPDIF_LEFT1,
3321c02e366SCtirad Fertr 	EMU_DST_MDOCK_SPDIF_RIGHT1,
3331c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT,
3341c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+1,
3351c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+2,
3361c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+3,
3371c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+4,
3381c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+5,
3391c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+6,
3401c02e366SCtirad Fertr 	EMU_DST_MDOCK_ADAT+7,
3411c02e366SCtirad Fertr 	EMU_DST_MANA_DAC_LEFT,
3421c02e366SCtirad Fertr 	EMU_DST_MANA_DAC_RIGHT,
3431c02e366SCtirad Fertr };
3441c02e366SCtirad Fertr 
34513d45709SPavel Hofman /*
346a869057cSOswald Buddenhagen  * Data destinations - FPGA outputs going to Alice2 (Audigy) for
34713d45709SPavel Hofman  *   capture (EMU32 + I2S links)
34813d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
34913d45709SPavel Hofman  */
3506fddce26STakashi Iwai static const unsigned int emu1010_input_dst[] = {
3519f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_0,
3529f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_1,
3539f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_2,
3549f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_3,
3559f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_4,
3569f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_5,
3579f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_6,
3589f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_7,
3599f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_8,
3609f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_9,
3619f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_A,
3629f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_B,
3639f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_C,
3649f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_D,
3659f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_E,
3669f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_F,
367a869057cSOswald Buddenhagen 	/* These exist only on rev1 EMU1010 cards. */
3689f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_LEFT,
3699f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_RIGHT,
3709f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_LEFT,
3719f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_RIGHT,
3729f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_LEFT,
3739f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_RIGHT,
3749f4bd5ddSJames Courtier-Dutton };
3759f4bd5ddSJames Courtier-Dutton 
3761c02e366SCtirad Fertr static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
3771c02e366SCtirad Fertr 						struct snd_ctl_elem_info *uinfo)
3789f4bd5ddSJames Courtier-Dutton {
3791c02e366SCtirad Fertr 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
3801c02e366SCtirad Fertr 
3811541c66dSTakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
3821541c66dSTakashi Iwai 		return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts);
3831541c66dSTakashi Iwai 	else
3841541c66dSTakashi Iwai 		return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts);
3859f4bd5ddSJames Courtier-Dutton }
3869f4bd5ddSJames Courtier-Dutton 
3879f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
3889f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
3899f4bd5ddSJames Courtier-Dutton {
3909f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
39174415a36SJames Courtier-Dutton 	unsigned int channel;
3929f4bd5ddSJames Courtier-Dutton 
3939f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
39474415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
3951c02e366SCtirad Fertr 	if (channel >= 24 ||
3963839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
3973839e4f1STakashi Iwai 	     channel >= 18))
39874415a36SJames Courtier-Dutton 		return -EINVAL;
3999f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
4009f4bd5ddSJames Courtier-Dutton 	return 0;
4019f4bd5ddSJames Courtier-Dutton }
4029f4bd5ddSJames Courtier-Dutton 
4039f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
4049f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4059f4bd5ddSJames Courtier-Dutton {
4069f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4079f4bd5ddSJames Courtier-Dutton 	unsigned int val;
40874415a36SJames Courtier-Dutton 	unsigned int channel;
4099f4bd5ddSJames Courtier-Dutton 
410aa299d01STakashi Iwai 	val = ucontrol->value.enumerated.item[0];
4111c02e366SCtirad Fertr 	if (val >= 53 ||
4123839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4133839e4f1STakashi Iwai 	     val >= 49))
414aa299d01STakashi Iwai 		return -EINVAL;
4159f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
41674415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
4171c02e366SCtirad Fertr 	if (channel >= 24 ||
4183839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4193839e4f1STakashi Iwai 	     channel >= 18))
42074415a36SJames Courtier-Dutton 		return -EINVAL;
4211c02e366SCtirad Fertr 	if (emu->emu1010.output_source[channel] == val)
4221c02e366SCtirad Fertr 		return 0;
423aa299d01STakashi Iwai 	emu->emu1010.output_source[channel] = val;
4243839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
4251c02e366SCtirad Fertr 		snd_emu1010_fpga_link_dst_src_write(emu,
4261c02e366SCtirad Fertr 			emu1616_output_dst[channel], emu1616_src_regs[val]);
4271c02e366SCtirad Fertr 	else
4289f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
4299f4bd5ddSJames Courtier-Dutton 			emu1010_output_dst[channel], emu1010_src_regs[val]);
4301c02e366SCtirad Fertr 	return 1;
4319f4bd5ddSJames Courtier-Dutton }
4329f4bd5ddSJames Courtier-Dutton 
4339f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
4349f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4359f4bd5ddSJames Courtier-Dutton {
4369f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
43774415a36SJames Courtier-Dutton 	unsigned int channel;
4389f4bd5ddSJames Courtier-Dutton 
4399f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
44074415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
44174415a36SJames Courtier-Dutton 	if (channel >= 22)
44274415a36SJames Courtier-Dutton 		return -EINVAL;
4439f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
4449f4bd5ddSJames Courtier-Dutton 	return 0;
4459f4bd5ddSJames Courtier-Dutton }
4469f4bd5ddSJames Courtier-Dutton 
4479f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
4489f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
4499f4bd5ddSJames Courtier-Dutton {
4509f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4519f4bd5ddSJames Courtier-Dutton 	unsigned int val;
45274415a36SJames Courtier-Dutton 	unsigned int channel;
4539f4bd5ddSJames Courtier-Dutton 
454aa299d01STakashi Iwai 	val = ucontrol->value.enumerated.item[0];
4551c02e366SCtirad Fertr 	if (val >= 53 ||
4563839e4f1STakashi Iwai 	    (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 &&
4573839e4f1STakashi Iwai 	     val >= 49))
458aa299d01STakashi Iwai 		return -EINVAL;
4599f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
46074415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
46174415a36SJames Courtier-Dutton 	if (channel >= 22)
46274415a36SJames Courtier-Dutton 		return -EINVAL;
4631c02e366SCtirad Fertr 	if (emu->emu1010.input_source[channel] == val)
4641c02e366SCtirad Fertr 		return 0;
465aa299d01STakashi Iwai 	emu->emu1010.input_source[channel] = val;
4663839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
4671c02e366SCtirad Fertr 		snd_emu1010_fpga_link_dst_src_write(emu,
4681c02e366SCtirad Fertr 			emu1010_input_dst[channel], emu1616_src_regs[val]);
4691c02e366SCtirad Fertr 	else
4709f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
4719f4bd5ddSJames Courtier-Dutton 			emu1010_input_dst[channel], emu1010_src_regs[val]);
4721c02e366SCtirad Fertr 	return 1;
4739f4bd5ddSJames Courtier-Dutton }
4749f4bd5ddSJames Courtier-Dutton 
4759f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \
4769f4bd5ddSJames Courtier-Dutton {								\
4779f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
4789f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
4799f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
4809f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_output_source_get,			\
4819f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_output_source_put,			\
4829f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
4839f4bd5ddSJames Courtier-Dutton }
4849f4bd5ddSJames Courtier-Dutton 
485b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = {
4864c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
4874c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
4884c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
4894c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
4904c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
4914c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
4924c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6),
4934c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
4944c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
4954c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
4964c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
4974c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
4984c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
4994c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
5004c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
5014c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
5024c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
5034c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
5044c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
5054c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
5064c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
5074c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
5084c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
5094c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
5109f4bd5ddSJames Courtier-Dutton };
5119f4bd5ddSJames Courtier-Dutton 
5121c02e366SCtirad Fertr 
5131c02e366SCtirad Fertr /* 1616(m) cardbus */
514b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = {
5151c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
5161c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
5171c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
5181c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
5191c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
5201c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
5211c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6),
5221c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7),
5231c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8),
5241c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9),
5251c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa),
5261c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb),
5271c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc),
5281c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd),
5291c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe),
5301c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf),
5311c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10),
5321c02e366SCtirad Fertr 	EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11),
5331c02e366SCtirad Fertr };
5341c02e366SCtirad Fertr 
5351c02e366SCtirad Fertr 
5369f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \
5379f4bd5ddSJames Courtier-Dutton {								\
5389f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
5399f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
5409f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
5419f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_input_source_get,			\
5429f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_input_source_put,			\
5439f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
5449f4bd5ddSJames Courtier-Dutton }
5459f4bd5ddSJames Courtier-Dutton 
546b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = {
5474c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
5484c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
5494c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
5504c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
5514c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
5524c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
5534c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
5544c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
5554c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
5564c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
5574c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
5584c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
5594c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
5604c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
5614c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
5624c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
5634c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
5644c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
5654c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
5664c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
5674c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
5684c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
5699148cc50SJames Courtier-Dutton };
5709148cc50SJames Courtier-Dutton 
5719148cc50SJames Courtier-Dutton 
5729148cc50SJames Courtier-Dutton 
573a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
5749148cc50SJames Courtier-Dutton 
5759148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5769148cc50SJames Courtier-Dutton {
5779148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
5789148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
5799148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
5809148cc50SJames Courtier-Dutton 	return 0;
5819148cc50SJames Courtier-Dutton }
5829148cc50SJames Courtier-Dutton 
5839148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5849148cc50SJames Courtier-Dutton {
5859148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
5869148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
5879148cc50SJames Courtier-Dutton 	unsigned int val, cache;
5889148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
5899148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
5909148cc50SJames Courtier-Dutton 	if (val == 1)
5919148cc50SJames Courtier-Dutton 		cache = cache | mask;
5929148cc50SJames Courtier-Dutton 	else
5939148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
5949148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
5959148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
5969148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
5979148cc50SJames Courtier-Dutton 	}
5989148cc50SJames Courtier-Dutton 
5999148cc50SJames Courtier-Dutton 	return 0;
6009148cc50SJames Courtier-Dutton }
6019148cc50SJames Courtier-Dutton 
6029148cc50SJames Courtier-Dutton 
6039148cc50SJames Courtier-Dutton 
6049148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \
6059148cc50SJames Courtier-Dutton {								\
6069148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
6079148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
6089148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_adc_pads_info,			\
6099148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_adc_pads_get,			\
6109148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_adc_pads_put,			\
6119148cc50SJames Courtier-Dutton 	.private_value = chid					\
6129148cc50SJames Courtier-Dutton }
6139148cc50SJames Courtier-Dutton 
614b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_adc_pads[] = {
6159148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
6169148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
6179148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
6189148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
6199148cc50SJames Courtier-Dutton };
6209148cc50SJames Courtier-Dutton 
621a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
6229148cc50SJames Courtier-Dutton 
6239148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6249148cc50SJames Courtier-Dutton {
6259148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6269148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6279148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
6289148cc50SJames Courtier-Dutton 	return 0;
6299148cc50SJames Courtier-Dutton }
6309148cc50SJames Courtier-Dutton 
6319148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
6329148cc50SJames Courtier-Dutton {
6339148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
6349148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
6359148cc50SJames Courtier-Dutton 	unsigned int val, cache;
6369148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
6379148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
6389148cc50SJames Courtier-Dutton 	if (val == 1)
6399148cc50SJames Courtier-Dutton 		cache = cache | mask;
6409148cc50SJames Courtier-Dutton 	else
6419148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
6429148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.dac_pads) {
6439148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
6449148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
6459148cc50SJames Courtier-Dutton 	}
6469148cc50SJames Courtier-Dutton 
6479148cc50SJames Courtier-Dutton 	return 0;
6489148cc50SJames Courtier-Dutton }
6499148cc50SJames Courtier-Dutton 
6509148cc50SJames Courtier-Dutton 
6519148cc50SJames Courtier-Dutton 
6529148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \
6539148cc50SJames Courtier-Dutton {								\
6549148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
6559148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
6569148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_dac_pads_info,			\
6579148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_dac_pads_get,			\
6589148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_dac_pads_put,			\
6599148cc50SJames Courtier-Dutton 	.private_value = chid					\
6609148cc50SJames Courtier-Dutton }
6619148cc50SJames Courtier-Dutton 
662b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_emu1010_dac_pads[] = {
6639148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
6649148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
6659148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
6669148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
6679148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
6689f4bd5ddSJames Courtier-Dutton };
6699f4bd5ddSJames Courtier-Dutton 
670b0dbdaeaSJames Courtier-Dutton 
671b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
672b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
673b0dbdaeaSJames Courtier-Dutton {
6741541c66dSTakashi Iwai 	static const char * const texts[4] = {
675edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
676b0dbdaeaSJames Courtier-Dutton 	};
677b0dbdaeaSJames Courtier-Dutton 
6781541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 4, texts);
679b0dbdaeaSJames Courtier-Dutton }
680b0dbdaeaSJames Courtier-Dutton 
681b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
682b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
683b0dbdaeaSJames Courtier-Dutton {
684b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
685b0dbdaeaSJames Courtier-Dutton 
686b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
687b0dbdaeaSJames Courtier-Dutton 	return 0;
688b0dbdaeaSJames Courtier-Dutton }
689b0dbdaeaSJames Courtier-Dutton 
690b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
691b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
692b0dbdaeaSJames Courtier-Dutton {
693b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
694b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
695b0dbdaeaSJames Courtier-Dutton 	int change = 0;
696b0dbdaeaSJames Courtier-Dutton 
697b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
69874415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 4; */
69974415a36SJames Courtier-Dutton 	if (val >= 4)
70074415a36SJames Courtier-Dutton 		return -EINVAL;
701b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
702b0dbdaeaSJames Courtier-Dutton 	if (change) {
703b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
704b0dbdaeaSJames Courtier-Dutton 		switch (val) {
705b0dbdaeaSJames Courtier-Dutton 		case 0:
706b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
707b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
708b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
709a869057cSOswald Buddenhagen 			/* Default fallback clock 44.1kHz */
710b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
711b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
712b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
713b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
714b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
715b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
716b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
717b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
718e40a0b2eSJames Courtier-Dutton 			msleep(10);
719b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
720b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
721b0dbdaeaSJames Courtier-Dutton 			break;
722b0dbdaeaSJames Courtier-Dutton 		case 1:
723b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
724b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
725b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
726b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
727b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
728b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
729b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
730b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
731b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
732b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
733b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
734b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
735e40a0b2eSJames Courtier-Dutton 			msleep(10);
736b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
737b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
738b0dbdaeaSJames Courtier-Dutton 			break;
739edec7bbbSJames Courtier-Dutton 
740edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
741edec7bbbSJames Courtier-Dutton 			/* Mute all */
742edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
743edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
744edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
745edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
746edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
747edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
748edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
749edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
750edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
751edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
752edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
753edec7bbbSJames Courtier-Dutton 			msleep(10);
754edec7bbbSJames Courtier-Dutton 			/* Unmute all */
755edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
756edec7bbbSJames Courtier-Dutton 			break;
757edec7bbbSJames Courtier-Dutton 
758edec7bbbSJames Courtier-Dutton 		case 3:
759edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
760edec7bbbSJames Courtier-Dutton 			/* Mute all */
761edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
762edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
763edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
764edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
765edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
766edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
767edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
768edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
769edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
770edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
771edec7bbbSJames Courtier-Dutton 			msleep(10);
772edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
773edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
774edec7bbbSJames Courtier-Dutton 
775edec7bbbSJames Courtier-Dutton 
776edec7bbbSJames Courtier-Dutton 			break;
777b0dbdaeaSJames Courtier-Dutton 		}
778b0dbdaeaSJames Courtier-Dutton 	}
779b0dbdaeaSJames Courtier-Dutton         return change;
780b0dbdaeaSJames Courtier-Dutton }
781b0dbdaeaSJames Courtier-Dutton 
782f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_internal_clock =
783b0dbdaeaSJames Courtier-Dutton {
784b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
785b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
786b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
787b0dbdaeaSJames Courtier-Dutton 	.count =	1,
788b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
789b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
790b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
791b0dbdaeaSJames Courtier-Dutton };
792b0dbdaeaSJames Courtier-Dutton 
79399dcab46SMichael Gernoth static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol,
79499dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
79599dcab46SMichael Gernoth {
79699dcab46SMichael Gernoth 	static const char * const texts[2] = {
79799dcab46SMichael Gernoth 		"SPDIF", "ADAT"
79899dcab46SMichael Gernoth 	};
79999dcab46SMichael Gernoth 
80099dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
80199dcab46SMichael Gernoth }
80299dcab46SMichael Gernoth 
80399dcab46SMichael Gernoth static int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol,
80499dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
80599dcab46SMichael Gernoth {
80699dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
80799dcab46SMichael Gernoth 
80899dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out;
80999dcab46SMichael Gernoth 	return 0;
81099dcab46SMichael Gernoth }
81199dcab46SMichael Gernoth 
81299dcab46SMichael Gernoth static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
81399dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
81499dcab46SMichael Gernoth {
81599dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
81699dcab46SMichael Gernoth 	unsigned int val;
81799dcab46SMichael Gernoth 	u32 tmp;
81899dcab46SMichael Gernoth 	int change = 0;
81999dcab46SMichael Gernoth 
82099dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
82199dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
82299dcab46SMichael Gernoth 	if (val >= 2)
82399dcab46SMichael Gernoth 		return -EINVAL;
82499dcab46SMichael Gernoth 	change = (emu->emu1010.optical_out != val);
82599dcab46SMichael Gernoth 	if (change) {
82699dcab46SMichael Gernoth 		emu->emu1010.optical_out = val;
8279d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
8289d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
82999dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
83099dcab46SMichael Gernoth 	}
83199dcab46SMichael Gernoth 	return change;
83299dcab46SMichael Gernoth }
83399dcab46SMichael Gernoth 
834f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_out = {
83599dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
83699dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
83799dcab46SMichael Gernoth 	.name =         "Optical Output Mode",
83899dcab46SMichael Gernoth 	.count =	1,
83999dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_out_info,
84099dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_out_get,
84199dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_out_put
84299dcab46SMichael Gernoth };
84399dcab46SMichael Gernoth 
84499dcab46SMichael Gernoth static int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol,
84599dcab46SMichael Gernoth 					  struct snd_ctl_elem_info *uinfo)
84699dcab46SMichael Gernoth {
84799dcab46SMichael Gernoth 	static const char * const texts[2] = {
84899dcab46SMichael Gernoth 		"SPDIF", "ADAT"
84999dcab46SMichael Gernoth 	};
85099dcab46SMichael Gernoth 
85199dcab46SMichael Gernoth 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
85299dcab46SMichael Gernoth }
85399dcab46SMichael Gernoth 
85499dcab46SMichael Gernoth static int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol,
85599dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
85699dcab46SMichael Gernoth {
85799dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
85899dcab46SMichael Gernoth 
85999dcab46SMichael Gernoth 	ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in;
86099dcab46SMichael Gernoth 	return 0;
86199dcab46SMichael Gernoth }
86299dcab46SMichael Gernoth 
86399dcab46SMichael Gernoth static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
86499dcab46SMichael Gernoth 					struct snd_ctl_elem_value *ucontrol)
86599dcab46SMichael Gernoth {
86699dcab46SMichael Gernoth 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
86799dcab46SMichael Gernoth 	unsigned int val;
86899dcab46SMichael Gernoth 	u32 tmp;
86999dcab46SMichael Gernoth 	int change = 0;
87099dcab46SMichael Gernoth 
87199dcab46SMichael Gernoth 	val = ucontrol->value.enumerated.item[0];
87299dcab46SMichael Gernoth 	/* Limit: uinfo->value.enumerated.items = 2; */
87399dcab46SMichael Gernoth 	if (val >= 2)
87499dcab46SMichael Gernoth 		return -EINVAL;
87599dcab46SMichael Gernoth 	change = (emu->emu1010.optical_in != val);
87699dcab46SMichael Gernoth 	if (change) {
87799dcab46SMichael Gernoth 		emu->emu1010.optical_in = val;
8789d2f3863SOswald Buddenhagen 		tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
8799d2f3863SOswald Buddenhagen 			(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
88099dcab46SMichael Gernoth 		snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
88199dcab46SMichael Gernoth 	}
88299dcab46SMichael Gernoth 	return change;
88399dcab46SMichael Gernoth }
88499dcab46SMichael Gernoth 
885f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu1010_optical_in = {
88699dcab46SMichael Gernoth 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
88799dcab46SMichael Gernoth 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
88899dcab46SMichael Gernoth 	.name =         "Optical Input Mode",
88999dcab46SMichael Gernoth 	.count =	1,
89099dcab46SMichael Gernoth 	.info =         snd_emu1010_optical_in_info,
89199dcab46SMichael Gernoth 	.get =          snd_emu1010_optical_in_get,
89299dcab46SMichael Gernoth 	.put =          snd_emu1010_optical_in_put
89399dcab46SMichael Gernoth };
89499dcab46SMichael Gernoth 
895184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
896184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
897184c1e2cSJames Courtier-Dutton {
898184c1e2cSJames Courtier-Dutton #if 0
8991541c66dSTakashi Iwai 	static const char * const texts[4] = {
900184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
901184c1e2cSJames Courtier-Dutton 	};
902184c1e2cSJames Courtier-Dutton #endif
9031541c66dSTakashi Iwai 	static const char * const texts[2] = {
904184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
905184c1e2cSJames Courtier-Dutton 	};
906184c1e2cSJames Courtier-Dutton 
9071541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
908184c1e2cSJames Courtier-Dutton }
909184c1e2cSJames Courtier-Dutton 
910184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
911184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
912184c1e2cSJames Courtier-Dutton {
913184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
914184c1e2cSJames Courtier-Dutton 
915184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
916184c1e2cSJames Courtier-Dutton 	return 0;
917184c1e2cSJames Courtier-Dutton }
918184c1e2cSJames Courtier-Dutton 
919184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
920184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
921184c1e2cSJames Courtier-Dutton {
922184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
923184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
924184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
925a1c87c0bSOswald Buddenhagen 	u16 gpio;
926184c1e2cSJames Courtier-Dutton 	int change = 0;
927184c1e2cSJames Courtier-Dutton 	unsigned long flags;
928184c1e2cSJames Courtier-Dutton 	u32 source;
929184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
930184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
931184c1e2cSJames Courtier-Dutton 	 * for the particular source.
932184c1e2cSJames Courtier-Dutton 	 */
93374415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
93474415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
93574415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
93674415a36SJames Courtier-Dutton 	if (source_id >= 2)
93774415a36SJames Courtier-Dutton 		return -EINVAL;
938184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
939184c1e2cSJames Courtier-Dutton 	if (change) {
940184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
941184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
942a1c87c0bSOswald Buddenhagen 		gpio = inw(emu->port + A_IOCFG);
943184c1e2cSJames Courtier-Dutton 		if (source_id==0)
944a1c87c0bSOswald Buddenhagen 			outw(gpio | 0x4, emu->port + A_IOCFG);
945184c1e2cSJames Courtier-Dutton 		else
946a1c87c0bSOswald Buddenhagen 			outw(gpio & ~0x4, emu->port + A_IOCFG);
947184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
948184c1e2cSJames Courtier-Dutton 
949184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
950184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
951184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
952184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
953184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
954184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
955184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
956184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
957184c1e2cSJames Courtier-Dutton 
958184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
959184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
960184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
961184c1e2cSJames Courtier-Dutton 	}
962184c1e2cSJames Courtier-Dutton         return change;
963184c1e2cSJames Courtier-Dutton }
964184c1e2cSJames Courtier-Dutton 
965f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_i2c_capture_source =
966184c1e2cSJames Courtier-Dutton {
967184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
968184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
969184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
970184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
971184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
972184c1e2cSJames Courtier-Dutton };
973184c1e2cSJames Courtier-Dutton 
974184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
975184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
976184c1e2cSJames Courtier-Dutton {
977184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
978184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
979184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
980184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
981184c1e2cSJames Courtier-Dutton 	return 0;
982184c1e2cSJames Courtier-Dutton }
983184c1e2cSJames Courtier-Dutton 
984184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
985184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
986184c1e2cSJames Courtier-Dutton {
987184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
98874415a36SJames Courtier-Dutton 	unsigned int source_id;
989184c1e2cSJames Courtier-Dutton 
990184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
99174415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
99274415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
99374415a36SJames Courtier-Dutton 	if (source_id >= 2)
99474415a36SJames Courtier-Dutton 		return -EINVAL;
995184c1e2cSJames Courtier-Dutton 
996184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
997184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
998184c1e2cSJames Courtier-Dutton 	return 0;
999184c1e2cSJames Courtier-Dutton }
1000184c1e2cSJames Courtier-Dutton 
1001184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
1002184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
1003184c1e2cSJames Courtier-Dutton {
1004184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1005184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
100614a29565SOswald Buddenhagen 	unsigned int ngain0, ngain1;
100774415a36SJames Courtier-Dutton 	unsigned int source_id;
1008184c1e2cSJames Courtier-Dutton 	int change = 0;
1009184c1e2cSJames Courtier-Dutton 
1010184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
101174415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
101274415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
101374415a36SJames Courtier-Dutton 	if (source_id >= 2)
101474415a36SJames Courtier-Dutton 		return -EINVAL;
101514a29565SOswald Buddenhagen 	ngain0 = ucontrol->value.integer.value[0];
101614a29565SOswald Buddenhagen 	ngain1 = ucontrol->value.integer.value[1];
101714a29565SOswald Buddenhagen 	if (ngain0 > 0xff)
101814a29565SOswald Buddenhagen 		return -EINVAL;
101914a29565SOswald Buddenhagen 	if (ngain1 > 0xff)
102014a29565SOswald Buddenhagen 		return -EINVAL;
1021184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
102214a29565SOswald Buddenhagen 	if (ogain != ngain0) {
1023184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
102414a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0);
102514a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][0] = ngain0;
1026184c1e2cSJames Courtier-Dutton 		change = 1;
1027184c1e2cSJames Courtier-Dutton 	}
1028184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
102914a29565SOswald Buddenhagen 	if (ogain != ngain1) {
1030184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
103114a29565SOswald Buddenhagen 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1);
103214a29565SOswald Buddenhagen 		emu->i2c_capture_volume[source_id][1] = ngain1;
1033184c1e2cSJames Courtier-Dutton 		change = 1;
1034184c1e2cSJames Courtier-Dutton 	}
1035184c1e2cSJames Courtier-Dutton 
1036184c1e2cSJames Courtier-Dutton 	return change;
1037184c1e2cSJames Courtier-Dutton }
1038184c1e2cSJames Courtier-Dutton 
1039184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \
1040184c1e2cSJames Courtier-Dutton {								\
1041184c1e2cSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
1042184c1e2cSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
1043184c1e2cSJames Courtier-Dutton 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
1044184c1e2cSJames Courtier-Dutton 	.info =  snd_audigy_i2c_volume_info,			\
1045184c1e2cSJames Courtier-Dutton 	.get =   snd_audigy_i2c_volume_get,			\
1046184c1e2cSJames Courtier-Dutton 	.put =   snd_audigy_i2c_volume_put,			\
1047184c1e2cSJames Courtier-Dutton 	.tlv = { .p = snd_audigy_db_scale2 },			\
1048184c1e2cSJames Courtier-Dutton 	.private_value = chid					\
1049184c1e2cSJames Courtier-Dutton }
1050184c1e2cSJames Courtier-Dutton 
1051184c1e2cSJames Courtier-Dutton 
1052b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = {
1053184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Mic Capture Volume", 0),
1054184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Line Capture Volume", 0)
1055184c1e2cSJames Courtier-Dutton };
1056184c1e2cSJames Courtier-Dutton 
10570af68e5eSTakashi Iwai #if 0
1058eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
10591da177e4SLinus Torvalds {
10601541c66dSTakashi Iwai 	static const char * const texts[] = {"44100", "48000", "96000"};
10611da177e4SLinus Torvalds 
10621541c66dSTakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 3, texts);
10631da177e4SLinus Torvalds }
10641da177e4SLinus Torvalds 
1065eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
1066eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10671da177e4SLinus Torvalds {
1068eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10691da177e4SLinus Torvalds 	unsigned int tmp;
10701da177e4SLinus Torvalds 
10711da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
10721da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
10731da177e4SLinus Torvalds 	case A_SPDIF_44100:
10741da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
10751da177e4SLinus Torvalds 		break;
10761da177e4SLinus Torvalds 	case A_SPDIF_48000:
10771da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
10781da177e4SLinus Torvalds 		break;
10791da177e4SLinus Torvalds 	case A_SPDIF_96000:
10801da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
10811da177e4SLinus Torvalds 		break;
10821da177e4SLinus Torvalds 	default:
10831da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
10841da177e4SLinus Torvalds 	}
10851da177e4SLinus Torvalds 	return 0;
10861da177e4SLinus Torvalds }
10871da177e4SLinus Torvalds 
1088eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
1089eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
10901da177e4SLinus Torvalds {
1091eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10921da177e4SLinus Torvalds 	int change;
10931da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
10941da177e4SLinus Torvalds 	unsigned long flags;
10951da177e4SLinus Torvalds 
10961da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
10971da177e4SLinus Torvalds 	case 0:
10981da177e4SLinus Torvalds 		val = A_SPDIF_44100;
10991da177e4SLinus Torvalds 		break;
11001da177e4SLinus Torvalds 	case 1:
11011da177e4SLinus Torvalds 		val = A_SPDIF_48000;
11021da177e4SLinus Torvalds 		break;
11031da177e4SLinus Torvalds 	case 2:
11041da177e4SLinus Torvalds 		val = A_SPDIF_96000;
11051da177e4SLinus Torvalds 		break;
11061da177e4SLinus Torvalds 	default:
11071da177e4SLinus Torvalds 		val = A_SPDIF_48000;
11081da177e4SLinus Torvalds 		break;
11091da177e4SLinus Torvalds 	}
11101da177e4SLinus Torvalds 
11111da177e4SLinus Torvalds 
11121da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11131da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
11141da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
11151da177e4SLinus Torvalds 	tmp |= val;
111612bda107STakashi Iwai 	change = (tmp != reg);
111712bda107STakashi Iwai 	if (change)
11181da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
11191da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11201da177e4SLinus Torvalds 	return change;
11211da177e4SLinus Torvalds }
11221da177e4SLinus Torvalds 
1123b4e5e707STakashi Iwai static const struct snd_kcontrol_new snd_audigy_spdif_output_rate =
11241da177e4SLinus Torvalds {
11251da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
11261da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
11271da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
11281da177e4SLinus Torvalds 	.count =	1,
11291da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
11301da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
11311da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
11321da177e4SLinus Torvalds };
11330af68e5eSTakashi Iwai #endif
11341da177e4SLinus Torvalds 
1135eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
1136eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
11371da177e4SLinus Torvalds {
1138eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11391da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
11401da177e4SLinus Torvalds 	int change;
11411da177e4SLinus Torvalds 	unsigned int val;
11421da177e4SLinus Torvalds 
114374415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
114474415a36SJames Courtier-Dutton 	if (idx >= 3)
114574415a36SJames Courtier-Dutton 		return -EINVAL;
11461da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
11471da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
11481da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
11491da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
11501da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
11511da177e4SLinus Torvalds 	if (change) {
11521da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
11531da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
11541da177e4SLinus Torvalds 	}
11551da177e4SLinus Torvalds 	return change;
11561da177e4SLinus Torvalds }
11571da177e4SLinus Torvalds 
1158f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
11591da177e4SLinus Torvalds {
11601da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
11615549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11621da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
11637583cb51STakashi Iwai 	.count =	3,
11641da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
11651da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
11661da177e4SLinus Torvalds };
11671da177e4SLinus Torvalds 
1168f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_spdif_control =
11691da177e4SLinus Torvalds {
11705549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
11711da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
11727583cb51STakashi Iwai 	.count =	3,
11731da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
11741da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
11751da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
11761da177e4SLinus Torvalds };
11771da177e4SLinus Torvalds 
11781da177e4SLinus Torvalds 
1179eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
11801da177e4SLinus Torvalds {
11811da177e4SLinus Torvalds 	if (emu->audigy) {
11821da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
11831da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
11841da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
11851da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
11861da177e4SLinus Torvalds 	} else {
11871da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
11881da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
11891da177e4SLinus Torvalds 	}
11901da177e4SLinus Torvalds }
11911da177e4SLinus Torvalds 
1192eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
11931da177e4SLinus Torvalds {
11941da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
11951da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
11961da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
11971da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
11981da177e4SLinus Torvalds 	if (emu->audigy) {
11991da177e4SLinus Torvalds 		unsigned int val = ((unsigned int)volume[4] << 24) |
12001da177e4SLinus Torvalds 			((unsigned int)volume[5] << 16) |
12011da177e4SLinus Torvalds 			((unsigned int)volume[6] << 8) |
12021da177e4SLinus Torvalds 			(unsigned int)volume[7];
12031da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
12041da177e4SLinus Torvalds 	}
12051da177e4SLinus Torvalds }
12061da177e4SLinus Torvalds 
12071da177e4SLinus Torvalds /* PCM stream controls */
12081da177e4SLinus Torvalds 
1209eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12101da177e4SLinus Torvalds {
1211eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12121da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12131da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
12141da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12151da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
12161da177e4SLinus Torvalds 	return 0;
12171da177e4SLinus Torvalds }
12181da177e4SLinus Torvalds 
1219eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
1220eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
12211da177e4SLinus Torvalds {
1222eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1223eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1224eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12251da177e4SLinus Torvalds 	int voice, idx;
12261da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12271da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
12281da177e4SLinus Torvalds 
12291da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
12301da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
12311da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
12321da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
12331da177e4SLinus Torvalds 	return 0;
12341da177e4SLinus Torvalds }
12351da177e4SLinus Torvalds 
1236eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1237eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
12381da177e4SLinus Torvalds {
12391da177e4SLinus Torvalds 	unsigned long flags;
1240eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1241eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1242eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12431da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
12441da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12451da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
12461da177e4SLinus Torvalds 
12471da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12481da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
12491da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
12501da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
12511da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
12521da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
12531da177e4SLinus Torvalds 				change = 1;
12541da177e4SLinus Torvalds 			}
12551da177e4SLinus Torvalds 		}
12561da177e4SLinus Torvalds 	if (change && mix->epcm) {
12571da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
12581da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
12591da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
12601da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
12611da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
12621da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
12631da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
12641da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
12651da177e4SLinus Torvalds 		}
12661da177e4SLinus Torvalds 	}
12671da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12681da177e4SLinus Torvalds 	return change;
12691da177e4SLinus Torvalds }
12701da177e4SLinus Torvalds 
1271f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_routing_control =
12721da177e4SLinus Torvalds {
12731da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
127467ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12751da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
12761da177e4SLinus Torvalds 	.count =	32,
12771da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
12781da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
12791da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
12801da177e4SLinus Torvalds };
12811da177e4SLinus Torvalds 
1282eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12831da177e4SLinus Torvalds {
1284eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12851da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12861da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
12871da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12881da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
12891da177e4SLinus Torvalds 	return 0;
12901da177e4SLinus Torvalds }
12911da177e4SLinus Torvalds 
1292eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1293eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12941da177e4SLinus Torvalds {
1295eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1296eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1297eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12981da177e4SLinus Torvalds 	int idx;
12991da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13001da177e4SLinus Torvalds 
13011da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
13021da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
13031da177e4SLinus Torvalds 	return 0;
13041da177e4SLinus Torvalds }
13051da177e4SLinus Torvalds 
1306eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1307eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
13081da177e4SLinus Torvalds {
13091da177e4SLinus Torvalds 	unsigned long flags;
1310eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1311eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1312eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13131da177e4SLinus Torvalds 	int change = 0, idx, val;
13141da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13151da177e4SLinus Torvalds 
13161da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13171da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
13181da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
13191da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
13201da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
13211da177e4SLinus Torvalds 			change = 1;
13221da177e4SLinus Torvalds 		}
13231da177e4SLinus Torvalds 	}
13241da177e4SLinus Torvalds 	if (change && mix->epcm) {
13251da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
13261da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
13271da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
13281da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
13291da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
13301da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
13311da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
13321da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
13331da177e4SLinus Torvalds 		}
13341da177e4SLinus Torvalds 	}
13351da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13361da177e4SLinus Torvalds 	return change;
13371da177e4SLinus Torvalds }
13381da177e4SLinus Torvalds 
1339f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_send_volume_control =
13401da177e4SLinus Torvalds {
13411da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
134267ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13431da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
13441da177e4SLinus Torvalds 	.count =	32,
13451da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
13461da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
13471da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
13481da177e4SLinus Torvalds };
13491da177e4SLinus Torvalds 
1350eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13511da177e4SLinus Torvalds {
13521da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13531da177e4SLinus Torvalds 	uinfo->count = 3;
13541da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13551da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
13561da177e4SLinus Torvalds 	return 0;
13571da177e4SLinus Torvalds }
13581da177e4SLinus Torvalds 
1359eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1360eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
13611da177e4SLinus Torvalds {
1362eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1363eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1364eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13651da177e4SLinus Torvalds 	int idx;
13661da177e4SLinus Torvalds 
13671da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
13681da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->attn[idx];
13691da177e4SLinus Torvalds 	return 0;
13701da177e4SLinus Torvalds }
13711da177e4SLinus Torvalds 
1372eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1373eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
13741da177e4SLinus Torvalds {
13751da177e4SLinus Torvalds 	unsigned long flags;
1376eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1377eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1378eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13791da177e4SLinus Torvalds 	int change = 0, idx, val;
13801da177e4SLinus Torvalds 
13811da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13821da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
13831da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 0xffff;
13841da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
13851da177e4SLinus Torvalds 			mix->attn[idx] = val;
13861da177e4SLinus Torvalds 			change = 1;
13871da177e4SLinus Torvalds 		}
13881da177e4SLinus Torvalds 	}
13891da177e4SLinus Torvalds 	if (change && mix->epcm) {
13901da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
13911da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
13921da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
13931da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
13941da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
13951da177e4SLinus Torvalds 		}
13961da177e4SLinus Torvalds 	}
13971da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13981da177e4SLinus Torvalds 	return change;
13991da177e4SLinus Torvalds }
14001da177e4SLinus Torvalds 
1401f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_attn_control =
14021da177e4SLinus Torvalds {
14031da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
140467ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14051da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
14061da177e4SLinus Torvalds 	.count =	32,
14071da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
14081da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
14091da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
14101da177e4SLinus Torvalds };
14111da177e4SLinus Torvalds 
14121da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
14131da177e4SLinus Torvalds 
1414eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14151da177e4SLinus Torvalds {
1416eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14171da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14181da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
14191da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14201da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
14211da177e4SLinus Torvalds 	return 0;
14221da177e4SLinus Torvalds }
14231da177e4SLinus Torvalds 
1424eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1425eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14261da177e4SLinus Torvalds {
1427eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1428eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1429eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14301da177e4SLinus Torvalds 	int idx;
14311da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14321da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14331da177e4SLinus Torvalds 
14341da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
14351da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
14361da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
14371da177e4SLinus Torvalds 	return 0;
14381da177e4SLinus Torvalds }
14391da177e4SLinus Torvalds 
1440eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1441eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
14421da177e4SLinus Torvalds {
14431da177e4SLinus Torvalds 	unsigned long flags;
1444eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14451da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1446eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
14471da177e4SLinus Torvalds 	int change = 0, idx, val;
14481da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14491da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
14501da177e4SLinus Torvalds 
14511da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
14521da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
14531da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
14541da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
14551da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
14561da177e4SLinus Torvalds 			change = 1;
14571da177e4SLinus Torvalds 		}
14581da177e4SLinus Torvalds 	}
14591da177e4SLinus Torvalds 
14601da177e4SLinus Torvalds 	if (change && mix->epcm) {
14611da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
14621da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
14631da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
14641da177e4SLinus Torvalds 		}
14651da177e4SLinus Torvalds 	}
14661da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14671da177e4SLinus Torvalds 	return change;
14681da177e4SLinus Torvalds }
14691da177e4SLinus Torvalds 
1470f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
14711da177e4SLinus Torvalds {
14721da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
14731da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
14741da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
14751da177e4SLinus Torvalds 	.count =	16,
14761da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
14771da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
14781da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
14791da177e4SLinus Torvalds };
14801da177e4SLinus Torvalds 
1481eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
14821da177e4SLinus Torvalds {
1483eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14841da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
14851da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
14861da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
14871da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
14881da177e4SLinus Torvalds 	return 0;
14891da177e4SLinus Torvalds }
14901da177e4SLinus Torvalds 
1491eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1492eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
14931da177e4SLinus Torvalds {
1494eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1495eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1496eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
14971da177e4SLinus Torvalds 	int idx;
14981da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
14991da177e4SLinus Torvalds 
15001da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
15011da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
15021da177e4SLinus Torvalds 	return 0;
15031da177e4SLinus Torvalds }
15041da177e4SLinus Torvalds 
1505eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1506eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
15071da177e4SLinus Torvalds {
15081da177e4SLinus Torvalds 	unsigned long flags;
1509eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15101da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1511eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
15121da177e4SLinus Torvalds 	int change = 0, idx, val;
15131da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
15141da177e4SLinus Torvalds 
15151da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15161da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
15171da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
15181da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
15191da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
15201da177e4SLinus Torvalds 			change = 1;
15211da177e4SLinus Torvalds 		}
15221da177e4SLinus Torvalds 	}
15231da177e4SLinus Torvalds 	if (change && mix->epcm) {
15241da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
15251da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
15261da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
15271da177e4SLinus Torvalds 		}
15281da177e4SLinus Torvalds 	}
15291da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15301da177e4SLinus Torvalds 	return change;
15311da177e4SLinus Torvalds }
15321da177e4SLinus Torvalds 
15331da177e4SLinus Torvalds 
1534f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
15351da177e4SLinus Torvalds {
15361da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15371da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15381da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
15391da177e4SLinus Torvalds 	.count =	16,
15401da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
15411da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
15421da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
15431da177e4SLinus Torvalds };
15441da177e4SLinus Torvalds 
1545eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
15461da177e4SLinus Torvalds {
15471da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
15481da177e4SLinus Torvalds 	uinfo->count = 1;
15491da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
15501da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
15511da177e4SLinus Torvalds 	return 0;
15521da177e4SLinus Torvalds }
15531da177e4SLinus Torvalds 
1554eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1555eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
15561da177e4SLinus Torvalds {
1557eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1558eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1559eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
15601da177e4SLinus Torvalds 
15611da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = mix->attn[0];
15621da177e4SLinus Torvalds 	return 0;
15631da177e4SLinus Torvalds }
15641da177e4SLinus Torvalds 
1565eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1566eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
15671da177e4SLinus Torvalds {
15681da177e4SLinus Torvalds 	unsigned long flags;
1569eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
15701da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1571eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
15721da177e4SLinus Torvalds 	int change = 0, val;
15731da177e4SLinus Torvalds 
15741da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
15751da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] & 0xffff;
15761da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
15771da177e4SLinus Torvalds 		mix->attn[0] = val;
15781da177e4SLinus Torvalds 		change = 1;
15791da177e4SLinus Torvalds 	}
15801da177e4SLinus Torvalds 	if (change && mix->epcm) {
15811da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
15821da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
15831da177e4SLinus Torvalds 		}
15841da177e4SLinus Torvalds 	}
15851da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
15861da177e4SLinus Torvalds 	return change;
15871da177e4SLinus Torvalds }
15881da177e4SLinus Torvalds 
1589f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
15901da177e4SLinus Torvalds {
15911da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
15921da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
15931da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
15941da177e4SLinus Torvalds 	.count =	16,
15951da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
15961da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
15971da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
15981da177e4SLinus Torvalds };
15991da177e4SLinus Torvalds 
1600a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
16011da177e4SLinus Torvalds 
1602eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1603eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
16041da177e4SLinus Torvalds {
1605eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
16061da177e4SLinus Torvalds 
16071da177e4SLinus Torvalds 	if (emu->audigy)
1608a1c87c0bSOswald Buddenhagen 		ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
16091da177e4SLinus Torvalds 	else
16101da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
1611d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1612d2cd74b1STakashi Iwai 		ucontrol->value.integer.value[0] =
1613d2cd74b1STakashi Iwai 			!ucontrol->value.integer.value[0];
1614d2cd74b1STakashi Iwai 
16151da177e4SLinus Torvalds 	return 0;
16161da177e4SLinus Torvalds }
16171da177e4SLinus Torvalds 
1618eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1619eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
16201da177e4SLinus Torvalds {
16211da177e4SLinus Torvalds 	unsigned long flags;
1622eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1623d2cd74b1STakashi Iwai 	unsigned int reg, val, sw;
16241da177e4SLinus Torvalds 	int change = 0;
16251da177e4SLinus Torvalds 
1626d2cd74b1STakashi Iwai 	sw = ucontrol->value.integer.value[0];
1627d2cd74b1STakashi Iwai 	if (emu->card_capabilities->invert_shared_spdif)
1628d2cd74b1STakashi Iwai 		sw = !sw;
162950164f69SOswald Buddenhagen 	spin_lock_irqsave(&emu->emu_lock, flags);
1630184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1631184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1632184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
1633a1c87c0bSOswald Buddenhagen 		reg = inw(emu->port + A_IOCFG);
1634d2cd74b1STakashi Iwai 		val = sw ? A_IOCFG_GPOUT0 : 0;
16351da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
16361da177e4SLinus Torvalds 		if (change) {
16371da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
16381da177e4SLinus Torvalds 			reg |= val;
1639a1c87c0bSOswald Buddenhagen 			outw(reg | val, emu->port + A_IOCFG);
16401da177e4SLinus Torvalds 		}
16411da177e4SLinus Torvalds 	}
16421da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
1643d2cd74b1STakashi Iwai 	val = sw ? HCFG_GPOUT0 : 0;
16441da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
16451da177e4SLinus Torvalds 	if (change) {
16461da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
16471da177e4SLinus Torvalds 		reg |= val;
16481da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
16491da177e4SLinus Torvalds 	}
165050164f69SOswald Buddenhagen 	spin_unlock_irqrestore(&emu->emu_lock, flags);
16511da177e4SLinus Torvalds 	return change;
16521da177e4SLinus Torvalds }
16531da177e4SLinus Torvalds 
1654f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_emu10k1_shared_spdif =
16551da177e4SLinus Torvalds {
16561da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16571da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
16581da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
16591da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
16601da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
16611da177e4SLinus Torvalds };
16621da177e4SLinus Torvalds 
1663f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_shared_spdif =
16641da177e4SLinus Torvalds {
16651da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
16661da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
16671da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
16681da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
16691da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
16701da177e4SLinus Torvalds };
16711da177e4SLinus Torvalds 
167216950e09STakashi Iwai /* workaround for too low volume on Audigy due to 16bit/24bit conversion */
167316950e09STakashi Iwai 
167416950e09STakashi Iwai #define snd_audigy_capture_boost_info	snd_ctl_boolean_mono_info
167516950e09STakashi Iwai 
167616950e09STakashi Iwai static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol,
167716950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
167816950e09STakashi Iwai {
167916950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
168016950e09STakashi Iwai 	unsigned int val;
168116950e09STakashi Iwai 
168216950e09STakashi Iwai 	/* FIXME: better to use a cached version */
168316950e09STakashi Iwai 	val = snd_ac97_read(emu->ac97, AC97_REC_GAIN);
168416950e09STakashi Iwai 	ucontrol->value.integer.value[0] = !!val;
168516950e09STakashi Iwai 	return 0;
168616950e09STakashi Iwai }
168716950e09STakashi Iwai 
168816950e09STakashi Iwai static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol,
168916950e09STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
169016950e09STakashi Iwai {
169116950e09STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
169216950e09STakashi Iwai 	unsigned int val;
169316950e09STakashi Iwai 
169416950e09STakashi Iwai 	if (ucontrol->value.integer.value[0])
169516950e09STakashi Iwai 		val = 0x0f0f;
169616950e09STakashi Iwai 	else
169716950e09STakashi Iwai 		val = 0;
169816950e09STakashi Iwai 	return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val);
169916950e09STakashi Iwai }
170016950e09STakashi Iwai 
1701f3b827e0SBhumika Goyal static const struct snd_kcontrol_new snd_audigy_capture_boost =
170216950e09STakashi Iwai {
170316950e09STakashi Iwai 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
17042a52feb1SMaciej S. Szmigiero 	.name =		"Mic Extra Boost",
170516950e09STakashi Iwai 	.info =		snd_audigy_capture_boost_info,
170616950e09STakashi Iwai 	.get =		snd_audigy_capture_boost_get,
170716950e09STakashi Iwai 	.put =		snd_audigy_capture_boost_put
170816950e09STakashi Iwai };
170916950e09STakashi Iwai 
171016950e09STakashi Iwai 
17111da177e4SLinus Torvalds /*
17121da177e4SLinus Torvalds  */
1713eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
17141da177e4SLinus Torvalds {
1715eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
17161da177e4SLinus Torvalds 	emu->ac97 = NULL;
17171da177e4SLinus Torvalds }
17181da177e4SLinus Torvalds 
17191da177e4SLinus Torvalds /*
17201da177e4SLinus Torvalds  */
1721eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
17221da177e4SLinus Torvalds {
1723eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
17241da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
17251da177e4SLinus Torvalds 	strcpy(id.name, name);
17261da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
17271da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
17281da177e4SLinus Torvalds }
17291da177e4SLinus Torvalds 
1730eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
17311da177e4SLinus Torvalds {
1732eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
17331da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
17341da177e4SLinus Torvalds 	strcpy(sid.name, name);
17351da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
17361da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
17371da177e4SLinus Torvalds }
17381da177e4SLinus Torvalds 
1739eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
17401da177e4SLinus Torvalds {
1741eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
17421da177e4SLinus Torvalds 	if (kctl) {
174336476b81SMaciej S. Szmigiero 		snd_ctl_rename(card, kctl, dst);
17441da177e4SLinus Torvalds 		return 0;
17451da177e4SLinus Torvalds 	}
17461da177e4SLinus Torvalds 	return -ENOENT;
17471da177e4SLinus Torvalds }
17481da177e4SLinus Torvalds 
1749e23e7a14SBill Pemberton int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
175067ed4161SClemens Ladisch 		      int pcm_device, int multi_device)
17511da177e4SLinus Torvalds {
17521da177e4SLinus Torvalds 	int err, pcm;
1753eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1754eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
17556fddce26STakashi Iwai 	const char * const *c;
17566fddce26STakashi Iwai 	static const char * const emu10k1_remove_ctls[] = {
17571da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
17581da177e4SLinus Torvalds 		"Master Mono Playback Switch",
17591da177e4SLinus Torvalds 		"Master Mono Playback Volume",
17601da177e4SLinus Torvalds 		"PCM Out Path & Mute",
17611da177e4SLinus Torvalds 		"Mono Output Select",
17621da177e4SLinus Torvalds 		"Surround Playback Switch",
17631da177e4SLinus Torvalds 		"Surround Playback Volume",
17641da177e4SLinus Torvalds 		"Center Playback Switch",
17651da177e4SLinus Torvalds 		"Center Playback Volume",
17661da177e4SLinus Torvalds 		"LFE Playback Switch",
17671da177e4SLinus Torvalds 		"LFE Playback Volume",
17681da177e4SLinus Torvalds 		NULL
17691da177e4SLinus Torvalds 	};
17706fddce26STakashi Iwai 	static const char * const emu10k1_rename_ctls[] = {
17711da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
17721da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
17731da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
17741da177e4SLinus Torvalds 		NULL
17751da177e4SLinus Torvalds 	};
17766fddce26STakashi Iwai 	static const char * const audigy_remove_ctls[] = {
17771da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
177821fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
177921fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
17801da177e4SLinus Torvalds 		"PCM Playback Switch",
17811da177e4SLinus Torvalds 		"PCM Playback Volume",
17821da177e4SLinus Torvalds 		"Master Playback Switch",
17831da177e4SLinus Torvalds 		"Master Playback Volume",
17841da177e4SLinus Torvalds 		"PCM Out Path & Mute",
17851da177e4SLinus Torvalds 		"Mono Output Select",
17861da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
17871da177e4SLinus Torvalds 		"Capture Source",
17881da177e4SLinus Torvalds 		"Capture Switch",
17891da177e4SLinus Torvalds 		"Capture Volume",
17901da177e4SLinus Torvalds 		"Mic Select",
1791274b2000SMaciej S. Szmigiero 		"Headphone Playback Switch",
1792274b2000SMaciej S. Szmigiero 		"Headphone Playback Volume",
1793274b2000SMaciej S. Szmigiero 		"3D Control - Center",
1794274b2000SMaciej S. Szmigiero 		"3D Control - Depth",
1795274b2000SMaciej S. Szmigiero 		"3D Control - Switch",
17961da177e4SLinus Torvalds 		"Video Playback Switch",
17971da177e4SLinus Torvalds 		"Video Playback Volume",
17981da177e4SLinus Torvalds 		"Mic Playback Switch",
17991da177e4SLinus Torvalds 		"Mic Playback Volume",
1800274b2000SMaciej S. Szmigiero 		"External Amplifier",
18011da177e4SLinus Torvalds 		NULL
18021da177e4SLinus Torvalds 	};
18036fddce26STakashi Iwai 	static const char * const audigy_rename_ctls[] = {
18041da177e4SLinus Torvalds 		/* use conventional names */
18051da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
18061da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
18071da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
18081da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
180952051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
181052051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
18111da177e4SLinus Torvalds 		NULL
18121da177e4SLinus Torvalds 	};
18136fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_i2c_adc[] = {
1814184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1815184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1816184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1817184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1818184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1819eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1820184c1e2cSJames Courtier-Dutton 		NULL
1821184c1e2cSJames Courtier-Dutton 	};
18226fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_i2c_adc[] = {
1823184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1824184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1825184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1826184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1827184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1828eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1829184c1e2cSJames Courtier-Dutton 		NULL
1830184c1e2cSJames Courtier-Dutton 	};
18316fddce26STakashi Iwai 	static const char * const audigy_remove_ctls_1361t_adc[] = {
183221fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
183321fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
183421fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
183521fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
183621fdddeaSJames Courtier-Dutton 		"Capture Source",
183721fdddeaSJames Courtier-Dutton 		"Capture Switch",
183821fdddeaSJames Courtier-Dutton 		"Capture Volume",
183921fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
184021fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
184121fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
184221fdddeaSJames Courtier-Dutton 		"3D Control - Center",
184321fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
184421fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
184521fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
184621fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
184721fdddeaSJames Courtier-Dutton 		NULL
184821fdddeaSJames Courtier-Dutton 	};
18496fddce26STakashi Iwai 	static const char * const audigy_rename_ctls_1361t_adc[] = {
185021fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
185121fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
185221fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1853d355c82aSJaroslav Kysela 		"Beep Playback Switch", "Beep Capture Switch",
1854d355c82aSJaroslav Kysela 		"Beep Playback Volume", "Beep Capture Volume",
185521fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
185621fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
185721fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
185821fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
185921fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
186021fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
186121fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
186221fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
186321fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
186421fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
186521fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
186621fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
186752051942SMaciej S. Szmigiero 		"Master Mono Playback Switch", "Phone Output Playback Switch",
186852051942SMaciej S. Szmigiero 		"Master Mono Playback Volume", "Phone Output Playback Volume",
186921fdddeaSJames Courtier-Dutton 		NULL
187021fdddeaSJames Courtier-Dutton 	};
18711da177e4SLinus Torvalds 
18722b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1873eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1874eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
187551055da5STakashi Iwai 		static const struct snd_ac97_bus_ops ops = {
18761da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
18771da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
18781da177e4SLinus Torvalds 		};
18791da177e4SLinus Torvalds 
188012bda107STakashi Iwai 		err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus);
188112bda107STakashi Iwai 		if (err < 0)
18821da177e4SLinus Torvalds 			return err;
18831da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
18841da177e4SLinus Torvalds 
18851da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
18861da177e4SLinus Torvalds 		ac97.private_data = emu;
18871da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
18881da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
188912bda107STakashi Iwai 		err = snd_ac97_mixer(pbus, &ac97, &emu->ac97);
189012bda107STakashi Iwai 		if (err < 0) {
1891b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
18921da177e4SLinus Torvalds 				return err;
18936f002b02STakashi Iwai 			dev_info(emu->card->dev,
18946f002b02STakashi Iwai 				 "AC97 is optional on this board\n");
18956f002b02STakashi Iwai 			dev_info(emu->card->dev,
18966f002b02STakashi Iwai 				 "Proceeding without ac97 mixers...\n");
1897b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1898b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1899b1508693STakashi Iwai 		}
19001da177e4SLinus Torvalds 		if (emu->audigy) {
19011da177e4SLinus Torvalds 			/* set master volume to 0 dB */
19024d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
19031da177e4SLinus Torvalds 			/* set capture source to mic */
19044d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
190552051942SMaciej S. Szmigiero 			/* set mono output (TAD) to mic */
190652051942SMaciej S. Szmigiero 			snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE,
190752051942SMaciej S. Szmigiero 				0x0200, 0x0200);
190821fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
190921fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
191021fdddeaSJames Courtier-Dutton 			else
19111da177e4SLinus Torvalds 				c = audigy_remove_ctls;
19121da177e4SLinus Torvalds 		} else {
19131da177e4SLinus Torvalds 			/*
19141da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
19151da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
19161da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
19171da177e4SLinus Torvalds 			 */
19181da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
19191da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
19201da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
19212594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
1922b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Volume");
1923b6a48404SRaymond Yau 				remove_ctl(card,"Front Playback Switch");
19241da177e4SLinus Torvalds 			}
19251da177e4SLinus Torvalds 			/* remove unused AC97 controls */
19264d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
19274d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
19281da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
19291da177e4SLinus Torvalds 		}
19301da177e4SLinus Torvalds 		for (; *c; c++)
19311da177e4SLinus Torvalds 			remove_ctl(card, *c);
1932184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1933184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1934184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1935184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
19361da177e4SLinus Torvalds 	} else {
1937f12aa40cSTakashi Iwai 	no_ac97:
19382b637da5SLee Revell 		if (emu->card_capabilities->ecard)
19391da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
19401da177e4SLinus Torvalds 		else if (emu->audigy)
19411da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
19421da177e4SLinus Torvalds 		else
19431da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
19441da177e4SLinus Torvalds 	}
19451da177e4SLinus Torvalds 
19461da177e4SLinus Torvalds 	if (emu->audigy)
194721fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
194821fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1949184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1950184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
195121fdddeaSJames Courtier-Dutton 		else
19521da177e4SLinus Torvalds 			c = audigy_rename_ctls;
19531da177e4SLinus Torvalds 	else
19541da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
19551da177e4SLinus Torvalds 	for (; *c; c += 2)
19561da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
195721fdddeaSJames Courtier-Dutton 
1958e217b960SRaymond Yau 	if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */
1959e217b960SRaymond Yau 		remove_ctl(card, "Center Playback Volume");
1960e217b960SRaymond Yau 		remove_ctl(card, "LFE Playback Volume");
1961e217b960SRaymond Yau 		remove_ctl(card, "Wave Center Playback Volume");
1962e217b960SRaymond Yau 		remove_ctl(card, "Wave LFE Playback Volume");
1963e217b960SRaymond Yau 	}
1964e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1965e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1966e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1967e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1968e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1969e3b9bc0eSJames Courtier-Dutton 	}
197012bda107STakashi Iwai 	kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu);
197112bda107STakashi Iwai 	if (!kctl)
19721da177e4SLinus Torvalds 		return -ENOMEM;
197367ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
197412bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
197512bda107STakashi Iwai 	if (err)
19761da177e4SLinus Torvalds 		return err;
197712bda107STakashi Iwai 	kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu);
197812bda107STakashi Iwai 	if (!kctl)
19791da177e4SLinus Torvalds 		return -ENOMEM;
198067ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
198112bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
198212bda107STakashi Iwai 	if (err)
19831da177e4SLinus Torvalds 		return err;
198412bda107STakashi Iwai 	kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu);
198512bda107STakashi Iwai 	if (!kctl)
19861da177e4SLinus Torvalds 		return -ENOMEM;
198767ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
198812bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
198912bda107STakashi Iwai 	if (err)
19901da177e4SLinus Torvalds 		return err;
19911da177e4SLinus Torvalds 
199212bda107STakashi Iwai 	kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu);
199312bda107STakashi Iwai 	if (!kctl)
19941da177e4SLinus Torvalds 		return -ENOMEM;
199567ed4161SClemens Ladisch 	kctl->id.device = multi_device;
199612bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
199712bda107STakashi Iwai 	if (err)
19981da177e4SLinus Torvalds 		return err;
19991da177e4SLinus Torvalds 
200012bda107STakashi Iwai 	kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu);
200112bda107STakashi Iwai 	if (!kctl)
20021da177e4SLinus Torvalds 		return -ENOMEM;
200367ed4161SClemens Ladisch 	kctl->id.device = multi_device;
200412bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
200512bda107STakashi Iwai 	if (err)
20061da177e4SLinus Torvalds 		return err;
20071da177e4SLinus Torvalds 
200812bda107STakashi Iwai 	kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu);
200912bda107STakashi Iwai 	if (!kctl)
20101da177e4SLinus Torvalds 		return -ENOMEM;
201167ed4161SClemens Ladisch 	kctl->id.device = multi_device;
201212bda107STakashi Iwai 	err = snd_ctl_add(card, kctl);
201312bda107STakashi Iwai 	if (err)
20141da177e4SLinus Torvalds 		return err;
20151da177e4SLinus Torvalds 
20161da177e4SLinus Torvalds 	/* initialize the routing and volume table for each pcm playback stream */
20171da177e4SLinus Torvalds 	for (pcm = 0; pcm < 32; pcm++) {
2018eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
20191da177e4SLinus Torvalds 		int v;
20201da177e4SLinus Torvalds 
20211da177e4SLinus Torvalds 		mix = &emu->pcm_mixer[pcm];
20221da177e4SLinus Torvalds 		mix->epcm = NULL;
20231da177e4SLinus Torvalds 
20241da177e4SLinus Torvalds 		for (v = 0; v < 4; v++)
20251da177e4SLinus Torvalds 			mix->send_routing[0][v] =
20261da177e4SLinus Torvalds 				mix->send_routing[1][v] =
20271da177e4SLinus Torvalds 				mix->send_routing[2][v] = v;
20281da177e4SLinus Torvalds 
20291da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
20301da177e4SLinus Torvalds 		mix->send_volume[0][0] = mix->send_volume[0][1] =
20311da177e4SLinus Torvalds 		mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
20321da177e4SLinus Torvalds 
20331da177e4SLinus Torvalds 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
20341da177e4SLinus Torvalds 	}
20351da177e4SLinus Torvalds 
20361da177e4SLinus Torvalds 	/* initialize the routing and volume table for the multichannel playback stream */
20371da177e4SLinus Torvalds 	for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
2038eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
20391da177e4SLinus Torvalds 		int v;
20401da177e4SLinus Torvalds 
20411da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[pcm];
20421da177e4SLinus Torvalds 		mix->epcm = NULL;
20431da177e4SLinus Torvalds 
20441da177e4SLinus Torvalds 		mix->send_routing[0][0] = pcm;
20451da177e4SLinus Torvalds 		mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
20461da177e4SLinus Torvalds 		for (v = 0; v < 2; v++)
20471da177e4SLinus Torvalds 			mix->send_routing[0][2+v] = 13+v;
20481da177e4SLinus Torvalds 		if (emu->audigy)
20491da177e4SLinus Torvalds 			for (v = 0; v < 4; v++)
20501da177e4SLinus Torvalds 				mix->send_routing[0][4+v] = 60+v;
20511da177e4SLinus Torvalds 
20521da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
20531da177e4SLinus Torvalds 		mix->send_volume[0][0]  = 255;
20541da177e4SLinus Torvalds 
20551da177e4SLinus Torvalds 		mix->attn[0] = 0xffff;
20561da177e4SLinus Torvalds 	}
20571da177e4SLinus Torvalds 
2058*a8661af5SOswald Buddenhagen 	if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) {
20591da177e4SLinus Torvalds 		/* sb live! and audigy */
206012bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu);
206112bda107STakashi Iwai 		if (!kctl)
20621da177e4SLinus Torvalds 			return -ENOMEM;
20635549d549SClemens Ladisch 		if (!emu->audigy)
20645549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
206512bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
206612bda107STakashi Iwai 		if (err)
20671da177e4SLinus Torvalds 			return err;
206812bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu);
206912bda107STakashi Iwai 		if (!kctl)
20701da177e4SLinus Torvalds 			return -ENOMEM;
20715549d549SClemens Ladisch 		if (!emu->audigy)
20725549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
207312bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
207412bda107STakashi Iwai 		if (err)
20751da177e4SLinus Torvalds 			return err;
20761da177e4SLinus Torvalds 	}
20771da177e4SLinus Torvalds 
2078190d2c46SJames Courtier-Dutton 	if (emu->card_capabilities->emu_model) {
207919b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
208019b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
208112bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu);
208212bda107STakashi Iwai 		if (!kctl)
20831da177e4SLinus Torvalds 			return -ENOMEM;
208412bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
208512bda107STakashi Iwai 		if (err)
20861da177e4SLinus Torvalds 			return err;
2087001f7589SJames Courtier-Dutton #if 0
208812bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu);
208912bda107STakashi Iwai 		if (!kctl)
20901da177e4SLinus Torvalds 			return -ENOMEM;
209112bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
209212bda107STakashi Iwai 		if (err)
20931da177e4SLinus Torvalds 			return err;
2094001f7589SJames Courtier-Dutton #endif
20952b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
20961da177e4SLinus Torvalds 		/* sb live! */
209712bda107STakashi Iwai 		kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu);
209812bda107STakashi Iwai 		if (!kctl)
20991da177e4SLinus Torvalds 			return -ENOMEM;
210012bda107STakashi Iwai 		err = snd_ctl_add(card, kctl);
210112bda107STakashi Iwai 		if (err)
21021da177e4SLinus Torvalds 			return err;
21031da177e4SLinus Torvalds 	}
21042b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
210512bda107STakashi Iwai 		err = snd_p16v_mixer(emu);
210612bda107STakashi Iwai 		if (err)
21071da177e4SLinus Torvalds 			return err;
21081da177e4SLinus Torvalds 	}
21091da177e4SLinus Torvalds 
21103839e4f1STakashi Iwai 	if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
21111c02e366SCtirad Fertr 		/* 1616(m) cardbus */
21129f4bd5ddSJames Courtier-Dutton 		int i;
21139f4bd5ddSJames Courtier-Dutton 
21141c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) {
21151c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21161c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1616_output_enum_ctls[i],
21171c02e366SCtirad Fertr 					     emu));
21189f4bd5ddSJames Courtier-Dutton 			if (err < 0)
21199f4bd5ddSJames Courtier-Dutton 				return err;
21209f4bd5ddSJames Courtier-Dutton 		}
21219f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
21221c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21231c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
21241c02e366SCtirad Fertr 					     emu));
21251c02e366SCtirad Fertr 			if (err < 0)
21261c02e366SCtirad Fertr 				return err;
21271c02e366SCtirad Fertr 		}
21281c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) {
21291c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21301c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
21311c02e366SCtirad Fertr 			if (err < 0)
21321c02e366SCtirad Fertr 				return err;
21331c02e366SCtirad Fertr 		}
21341c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) {
21351c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21361c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
21371c02e366SCtirad Fertr 			if (err < 0)
21381c02e366SCtirad Fertr 				return err;
21391c02e366SCtirad Fertr 		}
21401c02e366SCtirad Fertr 		err = snd_ctl_add(card,
21411c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
21421c02e366SCtirad Fertr 		if (err < 0)
21431c02e366SCtirad Fertr 			return err;
214499dcab46SMichael Gernoth 		err = snd_ctl_add(card,
214599dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
214699dcab46SMichael Gernoth 		if (err < 0)
214799dcab46SMichael Gernoth 			return err;
214899dcab46SMichael Gernoth 		err = snd_ctl_add(card,
214999dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
215099dcab46SMichael Gernoth 		if (err < 0)
215199dcab46SMichael Gernoth 			return err;
21521c02e366SCtirad Fertr 
215388aa1390STakashi Iwai 	} else if (emu->card_capabilities->emu_model) {
21541c02e366SCtirad Fertr 		/* all other e-mu cards for now */
21551c02e366SCtirad Fertr 		int i;
21561c02e366SCtirad Fertr 
21571c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
21581c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21591c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_output_enum_ctls[i],
21601c02e366SCtirad Fertr 					     emu));
21611c02e366SCtirad Fertr 			if (err < 0)
21621c02e366SCtirad Fertr 				return err;
21631c02e366SCtirad Fertr 		}
21641c02e366SCtirad Fertr 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
21651c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21661c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_input_enum_ctls[i],
21671c02e366SCtirad Fertr 					     emu));
21689f4bd5ddSJames Courtier-Dutton 			if (err < 0)
21699f4bd5ddSJames Courtier-Dutton 				return err;
21709f4bd5ddSJames Courtier-Dutton 		}
21719148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
21721c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21731c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
21749148cc50SJames Courtier-Dutton 			if (err < 0)
21759148cc50SJames Courtier-Dutton 				return err;
21769148cc50SJames Courtier-Dutton 		}
21779148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
21781c02e366SCtirad Fertr 			err = snd_ctl_add(card,
21791c02e366SCtirad Fertr 				snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
21809148cc50SJames Courtier-Dutton 			if (err < 0)
21819148cc50SJames Courtier-Dutton 				return err;
21829148cc50SJames Courtier-Dutton 		}
21831c02e366SCtirad Fertr 		err = snd_ctl_add(card,
21841c02e366SCtirad Fertr 			snd_ctl_new1(&snd_emu1010_internal_clock, emu));
2185b0dbdaeaSJames Courtier-Dutton 		if (err < 0)
2186b0dbdaeaSJames Courtier-Dutton 			return err;
218799dcab46SMichael Gernoth 		err = snd_ctl_add(card,
218899dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_out, emu));
218999dcab46SMichael Gernoth 		if (err < 0)
219099dcab46SMichael Gernoth 			return err;
219199dcab46SMichael Gernoth 		err = snd_ctl_add(card,
219299dcab46SMichael Gernoth 			snd_ctl_new1(&snd_emu1010_optical_in, emu));
219399dcab46SMichael Gernoth 		if (err < 0)
219499dcab46SMichael Gernoth 			return err;
21959f4bd5ddSJames Courtier-Dutton 	}
21969f4bd5ddSJames Courtier-Dutton 
2197184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
2198184c1e2cSJames Courtier-Dutton 		int i;
2199184c1e2cSJames Courtier-Dutton 
2200184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
2201184c1e2cSJames Courtier-Dutton 		if (err < 0)
2202184c1e2cSJames Courtier-Dutton 			return err;
2203184c1e2cSJames Courtier-Dutton 
2204184c1e2cSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
2205184c1e2cSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
2206184c1e2cSJames Courtier-Dutton 			if (err < 0)
2207184c1e2cSJames Courtier-Dutton 				return err;
2208184c1e2cSJames Courtier-Dutton 		}
2209184c1e2cSJames Courtier-Dutton 	}
2210184c1e2cSJames Courtier-Dutton 
221116950e09STakashi Iwai 	if (emu->card_capabilities->ac97_chip && emu->audigy) {
221216950e09STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost,
221316950e09STakashi Iwai 						     emu));
221416950e09STakashi Iwai 		if (err < 0)
221516950e09STakashi Iwai 			return err;
221616950e09STakashi Iwai 	}
221716950e09STakashi Iwai 
22181da177e4SLinus Torvalds 	return 0;
22191da177e4SLinus Torvalds }
2220