xref: /linux/sound/pci/emu10k1/emumixer.c (revision 74415a36767d99d3adf31b4a62e4e50725e6b66a)
11da177e4SLinus Torvalds /*
2c1017a4cSJaroslav Kysela  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>,
31da177e4SLinus Torvalds  *                   Takashi Iwai <tiwai@suse.de>
41da177e4SLinus Torvalds  *                   Creative Labs, Inc.
51da177e4SLinus Torvalds  *  Routines for control of EMU10K1 chips / mixer routines
61da177e4SLinus Torvalds  *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
71da177e4SLinus Torvalds  *
89f4bd5ddSJames Courtier-Dutton  *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
99f4bd5ddSJames Courtier-Dutton  *  	Added EMU 1010 support.
109f4bd5ddSJames Courtier-Dutton  *
111da177e4SLinus Torvalds  *  BUGS:
121da177e4SLinus Torvalds  *    --
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *  TODO:
151da177e4SLinus Torvalds  *    --
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *   This program is free software; you can redistribute it and/or modify
181da177e4SLinus Torvalds  *   it under the terms of the GNU General Public License as published by
191da177e4SLinus Torvalds  *   the Free Software Foundation; either version 2 of the License, or
201da177e4SLinus Torvalds  *   (at your option) any later version.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  *   This program is distributed in the hope that it will be useful,
231da177e4SLinus Torvalds  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
241da177e4SLinus Torvalds  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
251da177e4SLinus Torvalds  *   GNU General Public License for more details.
261da177e4SLinus Torvalds  *
271da177e4SLinus Torvalds  *   You should have received a copy of the GNU General Public License
281da177e4SLinus Torvalds  *   along with this program; if not, write to the Free Software
291da177e4SLinus Torvalds  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
301da177e4SLinus Torvalds  *
311da177e4SLinus Torvalds  */
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds #include <sound/driver.h>
341da177e4SLinus Torvalds #include <linux/time.h>
351da177e4SLinus Torvalds #include <linux/init.h>
361da177e4SLinus Torvalds #include <sound/core.h>
371da177e4SLinus Torvalds #include <sound/emu10k1.h>
38b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h>
39184c1e2cSJames Courtier-Dutton #include <sound/tlv.h>
40184c1e2cSJames Courtier-Dutton 
41184c1e2cSJames Courtier-Dutton #include "p17v.h"
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds #define AC97_ID_STAC9758	0x83847658
441da177e4SLinus Torvalds 
450cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
46184c1e2cSJames Courtier-Dutton 
47eb4698f3STakashi Iwai static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
481da177e4SLinus Torvalds {
491da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
501da177e4SLinus Torvalds 	uinfo->count = 1;
511da177e4SLinus Torvalds 	return 0;
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds 
54eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
55eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
561da177e4SLinus Torvalds {
57eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
581da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
591da177e4SLinus Torvalds 	unsigned long flags;
601da177e4SLinus Torvalds 
61*74415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
62*74415a36SJames Courtier-Dutton 	if (idx >= 3)
63*74415a36SJames Courtier-Dutton 		return -EINVAL;
641da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
651da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
661da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
671da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
681da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
691da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
701da177e4SLinus Torvalds 	return 0;
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds 
73eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
74eb4698f3STakashi Iwai 				      struct snd_ctl_elem_value *ucontrol)
751da177e4SLinus Torvalds {
761da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
771da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
781da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
791da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
801da177e4SLinus Torvalds 	return 0;
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds 
8313d45709SPavel Hofman /*
8413d45709SPavel Hofman  * Items labels in enum mixer controls assigning source data to
8513d45709SPavel Hofman  * each destination
8613d45709SPavel Hofman  */
879f4bd5ddSJames Courtier-Dutton static char *emu1010_src_texts[] = {
889f4bd5ddSJames Courtier-Dutton 	"Silence",
899f4bd5ddSJames Courtier-Dutton 	"Dock Mic A",
909f4bd5ddSJames Courtier-Dutton 	"Dock Mic B",
919f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Left",
929f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Right",
939f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Left",
949f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Right",
959f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Left",
969f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Right",
979f4bd5ddSJames Courtier-Dutton 	"0202 ADC Left",
989f4bd5ddSJames Courtier-Dutton 	"0202 ADC Right",
999f4bd5ddSJames Courtier-Dutton 	"0202 SPDIF Left",
1009f4bd5ddSJames Courtier-Dutton 	"0202 SPDIF Right",
1019f4bd5ddSJames Courtier-Dutton 	"ADAT 0",
1029f4bd5ddSJames Courtier-Dutton 	"ADAT 1",
1039f4bd5ddSJames Courtier-Dutton 	"ADAT 2",
1049f4bd5ddSJames Courtier-Dutton 	"ADAT 3",
1059f4bd5ddSJames Courtier-Dutton 	"ADAT 4",
1069f4bd5ddSJames Courtier-Dutton 	"ADAT 5",
1079f4bd5ddSJames Courtier-Dutton 	"ADAT 6",
1089f4bd5ddSJames Courtier-Dutton 	"ADAT 7",
1099f4bd5ddSJames Courtier-Dutton 	"DSP 0",
1109f4bd5ddSJames Courtier-Dutton 	"DSP 1",
1119f4bd5ddSJames Courtier-Dutton 	"DSP 2",
1129f4bd5ddSJames Courtier-Dutton 	"DSP 3",
1139f4bd5ddSJames Courtier-Dutton 	"DSP 4",
1149f4bd5ddSJames Courtier-Dutton 	"DSP 5",
1159f4bd5ddSJames Courtier-Dutton 	"DSP 6",
1169f4bd5ddSJames Courtier-Dutton 	"DSP 7",
1179f4bd5ddSJames Courtier-Dutton 	"DSP 8",
1189f4bd5ddSJames Courtier-Dutton 	"DSP 9",
1199f4bd5ddSJames Courtier-Dutton 	"DSP 10",
1209f4bd5ddSJames Courtier-Dutton 	"DSP 11",
1219f4bd5ddSJames Courtier-Dutton 	"DSP 12",
1229f4bd5ddSJames Courtier-Dutton 	"DSP 13",
1239f4bd5ddSJames Courtier-Dutton 	"DSP 14",
1249f4bd5ddSJames Courtier-Dutton 	"DSP 15",
1259f4bd5ddSJames Courtier-Dutton 	"DSP 16",
1269f4bd5ddSJames Courtier-Dutton 	"DSP 17",
1279f4bd5ddSJames Courtier-Dutton 	"DSP 18",
1289f4bd5ddSJames Courtier-Dutton 	"DSP 19",
1299f4bd5ddSJames Courtier-Dutton 	"DSP 20",
1309f4bd5ddSJames Courtier-Dutton 	"DSP 21",
1319f4bd5ddSJames Courtier-Dutton 	"DSP 22",
1329f4bd5ddSJames Courtier-Dutton 	"DSP 23",
1339f4bd5ddSJames Courtier-Dutton 	"DSP 24",
1349f4bd5ddSJames Courtier-Dutton 	"DSP 25",
1359f4bd5ddSJames Courtier-Dutton 	"DSP 26",
1369f4bd5ddSJames Courtier-Dutton 	"DSP 27",
1379f4bd5ddSJames Courtier-Dutton 	"DSP 28",
1389f4bd5ddSJames Courtier-Dutton 	"DSP 29",
1399f4bd5ddSJames Courtier-Dutton 	"DSP 30",
1409f4bd5ddSJames Courtier-Dutton 	"DSP 31",
1419f4bd5ddSJames Courtier-Dutton };
1429f4bd5ddSJames Courtier-Dutton 
14313d45709SPavel Hofman /*
14413d45709SPavel Hofman  * List of data sources available for each destination
14513d45709SPavel Hofman  */
1469f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_src_regs[] = {
1479f4bd5ddSJames Courtier-Dutton 	EMU_SRC_SILENCE,/* 0 */
1489f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_MIC_A1, /* 1 */
1499f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_MIC_B1, /* 2 */
1509f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */
1519f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */
1529f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */
1539f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */
1549f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */
1559f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */
1569f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */
1579f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */
1589f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */
1599f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */
1609f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT, /* 13 */
1619f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+1, /* 14 */
1629f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+2, /* 15 */
1639f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+3, /* 16 */
1649f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+4, /* 17 */
1659f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+5, /* 18 */
1669f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+6, /* 19 */
1679f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+7, /* 20 */
1689f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A, /* 21 */
1699f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+1, /* 22 */
1709f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+2, /* 23 */
1719f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+3, /* 24 */
1729f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+4, /* 25 */
1739f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+5, /* 26 */
1749f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+6, /* 27 */
1759f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+7, /* 28 */
1769f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+8, /* 29 */
1779f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+9, /* 30 */
1789f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xa, /* 31 */
1799f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xb, /* 32 */
1809f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xc, /* 33 */
1819f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xd, /* 34 */
1829f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xe, /* 35 */
1839f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xf, /* 36 */
1849f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B, /* 37 */
1859f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+1, /* 38 */
1869f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+2, /* 39 */
1879f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+3, /* 40 */
1889f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+4, /* 41 */
1899f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+5, /* 42 */
1909f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+6, /* 43 */
1919f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+7, /* 44 */
1929f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+8, /* 45 */
1939f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+9, /* 46 */
1949f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xa, /* 47 */
1959f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xb, /* 48 */
1969f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xc, /* 49 */
1979f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xd, /* 50 */
1989f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xe, /* 51 */
1999f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
2009f4bd5ddSJames Courtier-Dutton };
2019f4bd5ddSJames Courtier-Dutton 
20213d45709SPavel Hofman /*
20313d45709SPavel Hofman  * Data destinations - physical EMU outputs.
20413d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
20513d45709SPavel Hofman  */
2069f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_output_dst[] = {
2079f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
2089f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
2099f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC2_LEFT1, /* 2 */
2109f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */
2119f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC3_LEFT1, /* 4 */
2129f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */
2139f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC4_LEFT1, /* 6 */
2149f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */
2159f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_PHONES_LEFT1, /* 8 */
2169f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */
2179f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */
2189f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */
2199f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_SPDIF_LEFT1, /* 12 */
2209f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */
2219f4bd5ddSJames Courtier-Dutton 	EMU_DST_HAMOA_DAC_LEFT1, /* 14 */
2229f4bd5ddSJames Courtier-Dutton 	EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */
2239f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT, /* 16 */
2249f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+1, /* 17 */
2259f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+2, /* 18 */
2269f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+3, /* 19 */
2279f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+4, /* 20 */
2289f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+5, /* 21 */
2299f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+6, /* 22 */
2309f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+7, /* 23 */
2319f4bd5ddSJames Courtier-Dutton };
2329f4bd5ddSJames Courtier-Dutton 
23313d45709SPavel Hofman /*
23413d45709SPavel Hofman  * Data destinations - HANA outputs going to Alice2 (audigy) for
23513d45709SPavel Hofman  *   capture (EMU32 + I2S links)
23613d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
23713d45709SPavel Hofman  */
2389f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_input_dst[] = {
2399f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_0,
2409f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_1,
2419f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_2,
2429f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_3,
2439f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_4,
2449f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_5,
2459f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_6,
2469f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_7,
2479f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_8,
2489f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_9,
2499f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_A,
2509f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_B,
2519f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_C,
2529f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_D,
2539f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_E,
2549f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_F,
2559f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_LEFT,
2569f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_RIGHT,
2579f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_LEFT,
2589f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_RIGHT,
2599f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_LEFT,
2609f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_RIGHT,
2619f4bd5ddSJames Courtier-Dutton };
2629f4bd5ddSJames Courtier-Dutton 
2639f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
2649f4bd5ddSJames Courtier-Dutton {
2659f4bd5ddSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2669f4bd5ddSJames Courtier-Dutton 	uinfo->count = 1;
2679f4bd5ddSJames Courtier-Dutton 	uinfo->value.enumerated.items = 53;
2689f4bd5ddSJames Courtier-Dutton 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2699f4bd5ddSJames Courtier-Dutton 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
2709f4bd5ddSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]);
2719f4bd5ddSJames Courtier-Dutton 	return 0;
2729f4bd5ddSJames Courtier-Dutton }
2739f4bd5ddSJames Courtier-Dutton 
2749f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
2759f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
2769f4bd5ddSJames Courtier-Dutton {
2779f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
278*74415a36SJames Courtier-Dutton 	unsigned int channel;
2799f4bd5ddSJames Courtier-Dutton 
2809f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
281*74415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
282*74415a36SJames Courtier-Dutton 	if (channel >= 24)
283*74415a36SJames Courtier-Dutton 		return -EINVAL;
2849f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
2859f4bd5ddSJames Courtier-Dutton 	return 0;
2869f4bd5ddSJames Courtier-Dutton }
2879f4bd5ddSJames Courtier-Dutton 
2889f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
2899f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
2909f4bd5ddSJames Courtier-Dutton {
2919f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
2929f4bd5ddSJames Courtier-Dutton 	int change = 0;
2939f4bd5ddSJames Courtier-Dutton 	unsigned int val;
294*74415a36SJames Courtier-Dutton 	unsigned int channel;
2959f4bd5ddSJames Courtier-Dutton 
2969f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
297*74415a36SJames Courtier-Dutton 	/* Limit: emu1010_output_dst, emu->emu1010.output_source */
298*74415a36SJames Courtier-Dutton 	if (channel >= 24)
299*74415a36SJames Courtier-Dutton 		return -EINVAL;
3009f4bd5ddSJames Courtier-Dutton 	if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) {
3019f4bd5ddSJames Courtier-Dutton 		val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0];
3029f4bd5ddSJames Courtier-Dutton 		change = 1;
3039f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
3049f4bd5ddSJames Courtier-Dutton 			emu1010_output_dst[channel], emu1010_src_regs[val]);
3059f4bd5ddSJames Courtier-Dutton 	}
3069f4bd5ddSJames Courtier-Dutton 	return change;
3079f4bd5ddSJames Courtier-Dutton }
3089f4bd5ddSJames Courtier-Dutton 
3099f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
3109f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
3119f4bd5ddSJames Courtier-Dutton {
3129f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
313*74415a36SJames Courtier-Dutton 	unsigned int channel;
3149f4bd5ddSJames Courtier-Dutton 
3159f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
316*74415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
317*74415a36SJames Courtier-Dutton 	if (channel >= 22)
318*74415a36SJames Courtier-Dutton 		return -EINVAL;
3199f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
3209f4bd5ddSJames Courtier-Dutton 	return 0;
3219f4bd5ddSJames Courtier-Dutton }
3229f4bd5ddSJames Courtier-Dutton 
3239f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
3249f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
3259f4bd5ddSJames Courtier-Dutton {
3269f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
3279f4bd5ddSJames Courtier-Dutton 	int change = 0;
3289f4bd5ddSJames Courtier-Dutton 	unsigned int val;
329*74415a36SJames Courtier-Dutton 	unsigned int channel;
3309f4bd5ddSJames Courtier-Dutton 
3319f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
332*74415a36SJames Courtier-Dutton 	/* Limit: emu1010_input_dst, emu->emu1010.input_source */
333*74415a36SJames Courtier-Dutton 	if (channel >= 22)
334*74415a36SJames Courtier-Dutton 		return -EINVAL;
3359f4bd5ddSJames Courtier-Dutton 	if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) {
3369f4bd5ddSJames Courtier-Dutton 		val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0];
3379f4bd5ddSJames Courtier-Dutton 		change = 1;
3389f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
3399f4bd5ddSJames Courtier-Dutton 			emu1010_input_dst[channel], emu1010_src_regs[val]);
3409f4bd5ddSJames Courtier-Dutton 	}
3419f4bd5ddSJames Courtier-Dutton 	return change;
3429f4bd5ddSJames Courtier-Dutton }
3439f4bd5ddSJames Courtier-Dutton 
3449f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \
3459f4bd5ddSJames Courtier-Dutton {								\
3469f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
3479f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
3489f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
3499f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_output_source_get,			\
3509f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_output_source_put,			\
3519f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
3529f4bd5ddSJames Courtier-Dutton }
3539f4bd5ddSJames Courtier-Dutton 
3549f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = {
3554c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
3564c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
3574c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
3584c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
3594c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
3604c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
3614c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6),
3624c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
3634c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
3644c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
3654c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
3664c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
3674c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
3684c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
3694c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
3704c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
3714c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
3724c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
3734c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
3744c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
3754c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
3764c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
3774c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
3784c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
3799f4bd5ddSJames Courtier-Dutton };
3809f4bd5ddSJames Courtier-Dutton 
3819f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \
3829f4bd5ddSJames Courtier-Dutton {								\
3839f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
3849f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
3859f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
3869f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_input_source_get,			\
3879f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_input_source_put,			\
3889f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
3899f4bd5ddSJames Courtier-Dutton }
3909f4bd5ddSJames Courtier-Dutton 
3919f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = {
3924c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
3934c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
3944c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
3954c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
3964c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
3974c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
3984c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
3994c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
4004c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
4014c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
4024c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
4034c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
4044c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
4054c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
4064c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
4074c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
4084c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
4094c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
4104c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
4114c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
4124c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
4134c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
4149148cc50SJames Courtier-Dutton };
4159148cc50SJames Courtier-Dutton 
4169148cc50SJames Courtier-Dutton 
4179148cc50SJames Courtier-Dutton 
418a5ce8890STakashi Iwai #define snd_emu1010_adc_pads_info	snd_ctl_boolean_mono_info
4199148cc50SJames Courtier-Dutton 
4209148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4219148cc50SJames Courtier-Dutton {
4229148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4239148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4249148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
4259148cc50SJames Courtier-Dutton 	return 0;
4269148cc50SJames Courtier-Dutton }
4279148cc50SJames Courtier-Dutton 
4289148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4299148cc50SJames Courtier-Dutton {
4309148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4319148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4329148cc50SJames Courtier-Dutton 	unsigned int val, cache;
4339148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
4349148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
4359148cc50SJames Courtier-Dutton 	if (val == 1)
4369148cc50SJames Courtier-Dutton 		cache = cache | mask;
4379148cc50SJames Courtier-Dutton 	else
4389148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
4399148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
4409148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
4419148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
4429148cc50SJames Courtier-Dutton 	}
4439148cc50SJames Courtier-Dutton 
4449148cc50SJames Courtier-Dutton 	return 0;
4459148cc50SJames Courtier-Dutton }
4469148cc50SJames Courtier-Dutton 
4479148cc50SJames Courtier-Dutton 
4489148cc50SJames Courtier-Dutton 
4499148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \
4509148cc50SJames Courtier-Dutton {								\
4519148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
4529148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
4539148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_adc_pads_info,			\
4549148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_adc_pads_get,			\
4559148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_adc_pads_put,			\
4569148cc50SJames Courtier-Dutton 	.private_value = chid					\
4579148cc50SJames Courtier-Dutton }
4589148cc50SJames Courtier-Dutton 
4599148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = {
4609148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
4619148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
4629148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
4639148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
4649148cc50SJames Courtier-Dutton };
4659148cc50SJames Courtier-Dutton 
466a5ce8890STakashi Iwai #define snd_emu1010_dac_pads_info	snd_ctl_boolean_mono_info
4679148cc50SJames Courtier-Dutton 
4689148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4699148cc50SJames Courtier-Dutton {
4709148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4719148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4729148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0;
4739148cc50SJames Courtier-Dutton 	return 0;
4749148cc50SJames Courtier-Dutton }
4759148cc50SJames Courtier-Dutton 
4769148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4779148cc50SJames Courtier-Dutton {
4789148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4799148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4809148cc50SJames Courtier-Dutton 	unsigned int val, cache;
4819148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
4829148cc50SJames Courtier-Dutton 	cache = emu->emu1010.dac_pads;
4839148cc50SJames Courtier-Dutton 	if (val == 1)
4849148cc50SJames Courtier-Dutton 		cache = cache | mask;
4859148cc50SJames Courtier-Dutton 	else
4869148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
4879148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.dac_pads) {
4889148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
4899148cc50SJames Courtier-Dutton 	        emu->emu1010.dac_pads = cache;
4909148cc50SJames Courtier-Dutton 	}
4919148cc50SJames Courtier-Dutton 
4929148cc50SJames Courtier-Dutton 	return 0;
4939148cc50SJames Courtier-Dutton }
4949148cc50SJames Courtier-Dutton 
4959148cc50SJames Courtier-Dutton 
4969148cc50SJames Courtier-Dutton 
4979148cc50SJames Courtier-Dutton #define EMU1010_DAC_PADS(xname,chid) \
4989148cc50SJames Courtier-Dutton {								\
4999148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
5009148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
5019148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_dac_pads_info,			\
5029148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_dac_pads_get,			\
5039148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_dac_pads_put,			\
5049148cc50SJames Courtier-Dutton 	.private_value = chid					\
5059148cc50SJames Courtier-Dutton }
5069148cc50SJames Courtier-Dutton 
5079148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = {
5089148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1),
5099148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2),
5109148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3),
5119148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4),
5129148cc50SJames Courtier-Dutton 	EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1),
5139f4bd5ddSJames Courtier-Dutton };
5149f4bd5ddSJames Courtier-Dutton 
515b0dbdaeaSJames Courtier-Dutton 
516b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
517b0dbdaeaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
518b0dbdaeaSJames Courtier-Dutton {
519edec7bbbSJames Courtier-Dutton 	static char *texts[4] = {
520edec7bbbSJames Courtier-Dutton 		"44100", "48000", "SPDIF", "ADAT"
521b0dbdaeaSJames Courtier-Dutton 	};
522b0dbdaeaSJames Courtier-Dutton 
523b0dbdaeaSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
524b0dbdaeaSJames Courtier-Dutton 	uinfo->count = 1;
525edec7bbbSJames Courtier-Dutton 	uinfo->value.enumerated.items = 4;
526edec7bbbSJames Courtier-Dutton 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
527edec7bbbSJames Courtier-Dutton 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
528b0dbdaeaSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
529b0dbdaeaSJames Courtier-Dutton 	return 0;
530edec7bbbSJames Courtier-Dutton 
531edec7bbbSJames Courtier-Dutton 
532b0dbdaeaSJames Courtier-Dutton }
533b0dbdaeaSJames Courtier-Dutton 
534b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
535b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
536b0dbdaeaSJames Courtier-Dutton {
537b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
538b0dbdaeaSJames Courtier-Dutton 
539b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
540b0dbdaeaSJames Courtier-Dutton 	return 0;
541b0dbdaeaSJames Courtier-Dutton }
542b0dbdaeaSJames Courtier-Dutton 
543b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
544b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
545b0dbdaeaSJames Courtier-Dutton {
546b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
547b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
548b0dbdaeaSJames Courtier-Dutton 	int change = 0;
549b0dbdaeaSJames Courtier-Dutton 
550b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
551*74415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 4; */
552*74415a36SJames Courtier-Dutton 	if (val >= 4)
553*74415a36SJames Courtier-Dutton 		return -EINVAL;
554b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
555b0dbdaeaSJames Courtier-Dutton 	if (change) {
556b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
557b0dbdaeaSJames Courtier-Dutton 		switch (val) {
558b0dbdaeaSJames Courtier-Dutton 		case 0:
559b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
560b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
561b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
562b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
563b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
564b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
565b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
566b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
567b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
568b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
569b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
570b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
571e40a0b2eSJames Courtier-Dutton 			msleep(10);
572b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
573b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
574b0dbdaeaSJames Courtier-Dutton 			break;
575b0dbdaeaSJames Courtier-Dutton 		case 1:
576b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
577b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
578b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
579b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
580b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
581b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
582b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
583b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
584b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
585b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
586b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
587b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
588e40a0b2eSJames Courtier-Dutton 			msleep(10);
589b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
590b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
591b0dbdaeaSJames Courtier-Dutton 			break;
592edec7bbbSJames Courtier-Dutton 
593edec7bbbSJames Courtier-Dutton 		case 2: /* Take clock from S/PDIF IN */
594edec7bbbSJames Courtier-Dutton 			/* Mute all */
595edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
596edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
597edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
598edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to S/PDIF input */
599edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
600edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X );
601edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
602edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
603edec7bbbSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
604edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
605edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
606edec7bbbSJames Courtier-Dutton 			msleep(10);
607edec7bbbSJames Courtier-Dutton 			/* Unmute all */
608edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
609edec7bbbSJames Courtier-Dutton 			break;
610edec7bbbSJames Courtier-Dutton 
611edec7bbbSJames Courtier-Dutton 		case 3:
612edec7bbbSJames Courtier-Dutton 			/* Take clock from ADAT IN */
613edec7bbbSJames Courtier-Dutton 			/* Mute all */
614edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
615edec7bbbSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
616edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
617edec7bbbSJames Courtier-Dutton 			/* Word Clock source, sync to ADAT input */
618edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
619edec7bbbSJames Courtier-Dutton 				EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X );
620edec7bbbSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
621edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK );
622edec7bbbSJames Courtier-Dutton 			/* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */
623edec7bbbSJames Courtier-Dutton 			/* Allow DLL to settle */
624edec7bbbSJames Courtier-Dutton 			msleep(10);
625edec7bbbSJames Courtier-Dutton 			/*   Unmute all */
626edec7bbbSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
627edec7bbbSJames Courtier-Dutton 
628edec7bbbSJames Courtier-Dutton 
629edec7bbbSJames Courtier-Dutton 			break;
630b0dbdaeaSJames Courtier-Dutton 		}
631b0dbdaeaSJames Courtier-Dutton 	}
632b0dbdaeaSJames Courtier-Dutton         return change;
633b0dbdaeaSJames Courtier-Dutton }
634b0dbdaeaSJames Courtier-Dutton 
635b0dbdaeaSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_internal_clock =
636b0dbdaeaSJames Courtier-Dutton {
637b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
638b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
639b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
640b0dbdaeaSJames Courtier-Dutton 	.count =	1,
641b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
642b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
643b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
644b0dbdaeaSJames Courtier-Dutton };
645b0dbdaeaSJames Courtier-Dutton 
646184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
647184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
648184c1e2cSJames Courtier-Dutton {
649184c1e2cSJames Courtier-Dutton #if 0
650184c1e2cSJames Courtier-Dutton 	static char *texts[4] = {
651184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
652184c1e2cSJames Courtier-Dutton 	};
653184c1e2cSJames Courtier-Dutton #endif
654184c1e2cSJames Courtier-Dutton 	static char *texts[2] = {
655184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
656184c1e2cSJames Courtier-Dutton 	};
657184c1e2cSJames Courtier-Dutton 
658184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
659184c1e2cSJames Courtier-Dutton 	uinfo->count = 1;
660184c1e2cSJames Courtier-Dutton 	uinfo->value.enumerated.items = 2;
661184c1e2cSJames Courtier-Dutton 	if (uinfo->value.enumerated.item > 1)
662184c1e2cSJames Courtier-Dutton                 uinfo->value.enumerated.item = 1;
663184c1e2cSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
664184c1e2cSJames Courtier-Dutton 	return 0;
665184c1e2cSJames Courtier-Dutton }
666184c1e2cSJames Courtier-Dutton 
667184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
668184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
669184c1e2cSJames Courtier-Dutton {
670184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
671184c1e2cSJames Courtier-Dutton 
672184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
673184c1e2cSJames Courtier-Dutton 	return 0;
674184c1e2cSJames Courtier-Dutton }
675184c1e2cSJames Courtier-Dutton 
676184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
677184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
678184c1e2cSJames Courtier-Dutton {
679184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
680184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
681184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
682184c1e2cSJames Courtier-Dutton 	u32 gpio;
683184c1e2cSJames Courtier-Dutton 	int change = 0;
684184c1e2cSJames Courtier-Dutton 	unsigned long flags;
685184c1e2cSJames Courtier-Dutton 	u32 source;
686184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
687184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
688184c1e2cSJames Courtier-Dutton 	 * for the particular source.
689184c1e2cSJames Courtier-Dutton 	 */
690*74415a36SJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0];
691*74415a36SJames Courtier-Dutton 	/* Limit: uinfo->value.enumerated.items = 2; */
692*74415a36SJames Courtier-Dutton 	/*        emu->i2c_capture_volume */
693*74415a36SJames Courtier-Dutton 	if (source_id >= 2)
694*74415a36SJames Courtier-Dutton 		return -EINVAL;
695184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
696184c1e2cSJames Courtier-Dutton 	if (change) {
697184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
698184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
699184c1e2cSJames Courtier-Dutton 		gpio = inl(emu->port + A_IOCFG);
700184c1e2cSJames Courtier-Dutton 		if (source_id==0)
701184c1e2cSJames Courtier-Dutton 			outl(gpio | 0x4, emu->port + A_IOCFG);
702184c1e2cSJames Courtier-Dutton 		else
703184c1e2cSJames Courtier-Dutton 			outl(gpio & ~0x4, emu->port + A_IOCFG);
704184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
705184c1e2cSJames Courtier-Dutton 
706184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
707184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
708184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
709184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
710184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
711184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
712184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
713184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
714184c1e2cSJames Courtier-Dutton 
715184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
716184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
717184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
718184c1e2cSJames Courtier-Dutton 	}
719184c1e2cSJames Courtier-Dutton         return change;
720184c1e2cSJames Courtier-Dutton }
721184c1e2cSJames Courtier-Dutton 
722184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_capture_source =
723184c1e2cSJames Courtier-Dutton {
724184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
725184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
726184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
727184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
728184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
729184c1e2cSJames Courtier-Dutton };
730184c1e2cSJames Courtier-Dutton 
731184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
732184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
733184c1e2cSJames Courtier-Dutton {
734184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
735184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
736184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
737184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
738184c1e2cSJames Courtier-Dutton 	return 0;
739184c1e2cSJames Courtier-Dutton }
740184c1e2cSJames Courtier-Dutton 
741184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
742184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
743184c1e2cSJames Courtier-Dutton {
744184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
745*74415a36SJames Courtier-Dutton 	unsigned int source_id;
746184c1e2cSJames Courtier-Dutton 
747184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
748*74415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
749*74415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
750*74415a36SJames Courtier-Dutton 	if (source_id >= 2)
751*74415a36SJames Courtier-Dutton 		return -EINVAL;
752184c1e2cSJames Courtier-Dutton 
753184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
754184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
755184c1e2cSJames Courtier-Dutton 	return 0;
756184c1e2cSJames Courtier-Dutton }
757184c1e2cSJames Courtier-Dutton 
758184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
759184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
760184c1e2cSJames Courtier-Dutton {
761184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
762184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
763184c1e2cSJames Courtier-Dutton 	unsigned int ngain;
764*74415a36SJames Courtier-Dutton 	unsigned int source_id;
765184c1e2cSJames Courtier-Dutton 	int change = 0;
766184c1e2cSJames Courtier-Dutton 
767184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
768*74415a36SJames Courtier-Dutton 	/* Limit: emu->i2c_capture_volume */
769*74415a36SJames Courtier-Dutton         /*        capture_source: uinfo->value.enumerated.items = 2 */
770*74415a36SJames Courtier-Dutton 	if (source_id >= 2)
771*74415a36SJames Courtier-Dutton 		return -EINVAL;
772184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
773184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[0];
774184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
775184c1e2cSJames Courtier-Dutton 		return 0;
776184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
777184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
778184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
779*74415a36SJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][0] = ngain;
780184c1e2cSJames Courtier-Dutton 		change = 1;
781184c1e2cSJames Courtier-Dutton 	}
782184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
783184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[1];
784184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
785184c1e2cSJames Courtier-Dutton 		return 0;
786184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
787184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
788184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
789*74415a36SJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][1] = ngain;
790184c1e2cSJames Courtier-Dutton 		change = 1;
791184c1e2cSJames Courtier-Dutton 	}
792184c1e2cSJames Courtier-Dutton 
793184c1e2cSJames Courtier-Dutton 	return change;
794184c1e2cSJames Courtier-Dutton }
795184c1e2cSJames Courtier-Dutton 
796184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \
797184c1e2cSJames Courtier-Dutton {								\
798184c1e2cSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
799184c1e2cSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
800184c1e2cSJames Courtier-Dutton 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
801184c1e2cSJames Courtier-Dutton 	.info =  snd_audigy_i2c_volume_info,			\
802184c1e2cSJames Courtier-Dutton 	.get =   snd_audigy_i2c_volume_get,			\
803184c1e2cSJames Courtier-Dutton 	.put =   snd_audigy_i2c_volume_put,			\
804184c1e2cSJames Courtier-Dutton 	.tlv = { .p = snd_audigy_db_scale2 },			\
805184c1e2cSJames Courtier-Dutton 	.private_value = chid					\
806184c1e2cSJames Courtier-Dutton }
807184c1e2cSJames Courtier-Dutton 
808184c1e2cSJames Courtier-Dutton 
809184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = {
810184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Mic Capture Volume", 0),
811184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Line Capture Volume", 0)
812184c1e2cSJames Courtier-Dutton };
813184c1e2cSJames Courtier-Dutton 
8140af68e5eSTakashi Iwai #if 0
815eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
8161da177e4SLinus Torvalds {
8171da177e4SLinus Torvalds 	static char *texts[] = {"44100", "48000", "96000"};
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
8201da177e4SLinus Torvalds 	uinfo->count = 1;
8211da177e4SLinus Torvalds 	uinfo->value.enumerated.items = 3;
8221da177e4SLinus Torvalds 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
8231da177e4SLinus Torvalds 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
8241da177e4SLinus Torvalds 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
8251da177e4SLinus Torvalds 	return 0;
8261da177e4SLinus Torvalds }
8271da177e4SLinus Torvalds 
828eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
829eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
8301da177e4SLinus Torvalds {
831eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
8321da177e4SLinus Torvalds 	unsigned int tmp;
8331da177e4SLinus Torvalds 	unsigned long flags;
8341da177e4SLinus Torvalds 
8351da177e4SLinus Torvalds 
8361da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
8371da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
8381da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
8391da177e4SLinus Torvalds 	case A_SPDIF_44100:
8401da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
8411da177e4SLinus Torvalds 		break;
8421da177e4SLinus Torvalds 	case A_SPDIF_48000:
8431da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
8441da177e4SLinus Torvalds 		break;
8451da177e4SLinus Torvalds 	case A_SPDIF_96000:
8461da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
8471da177e4SLinus Torvalds 		break;
8481da177e4SLinus Torvalds 	default:
8491da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
8501da177e4SLinus Torvalds 	}
8511da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
8521da177e4SLinus Torvalds 	return 0;
8531da177e4SLinus Torvalds }
8541da177e4SLinus Torvalds 
855eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
856eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
8571da177e4SLinus Torvalds {
858eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
8591da177e4SLinus Torvalds 	int change;
8601da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
8611da177e4SLinus Torvalds 	unsigned long flags;
8621da177e4SLinus Torvalds 
8631da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
8641da177e4SLinus Torvalds 	case 0:
8651da177e4SLinus Torvalds 		val = A_SPDIF_44100;
8661da177e4SLinus Torvalds 		break;
8671da177e4SLinus Torvalds 	case 1:
8681da177e4SLinus Torvalds 		val = A_SPDIF_48000;
8691da177e4SLinus Torvalds 		break;
8701da177e4SLinus Torvalds 	case 2:
8711da177e4SLinus Torvalds 		val = A_SPDIF_96000;
8721da177e4SLinus Torvalds 		break;
8731da177e4SLinus Torvalds 	default:
8741da177e4SLinus Torvalds 		val = A_SPDIF_48000;
8751da177e4SLinus Torvalds 		break;
8761da177e4SLinus Torvalds 	}
8771da177e4SLinus Torvalds 
8781da177e4SLinus Torvalds 
8791da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
8801da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
8811da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
8821da177e4SLinus Torvalds 	tmp |= val;
8831da177e4SLinus Torvalds 	if ((change = (tmp != reg)))
8841da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
8851da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
8861da177e4SLinus Torvalds 	return change;
8871da177e4SLinus Torvalds }
8881da177e4SLinus Torvalds 
889eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_spdif_output_rate =
8901da177e4SLinus Torvalds {
8911da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
8921da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
8931da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
8941da177e4SLinus Torvalds 	.count =	1,
8951da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
8961da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
8971da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
8981da177e4SLinus Torvalds };
8990af68e5eSTakashi Iwai #endif
9001da177e4SLinus Torvalds 
901eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
902eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
9031da177e4SLinus Torvalds {
904eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
9051da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
9061da177e4SLinus Torvalds 	int change;
9071da177e4SLinus Torvalds 	unsigned int val;
9081da177e4SLinus Torvalds 	unsigned long flags;
9091da177e4SLinus Torvalds 
910*74415a36SJames Courtier-Dutton 	/* Limit: emu->spdif_bits */
911*74415a36SJames Courtier-Dutton 	if (idx >= 3)
912*74415a36SJames Courtier-Dutton 		return -EINVAL;
9131da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
9141da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
9151da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
9161da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
9171da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
9181da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
9191da177e4SLinus Torvalds 	if (change) {
9201da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
9211da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
9221da177e4SLinus Torvalds 	}
9231da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
9241da177e4SLinus Torvalds 	return change;
9251da177e4SLinus Torvalds }
9261da177e4SLinus Torvalds 
927eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
9281da177e4SLinus Torvalds {
9291da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
9305549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
9311da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
9327583cb51STakashi Iwai 	.count =	3,
9331da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
9341da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
9351da177e4SLinus Torvalds };
9361da177e4SLinus Torvalds 
937eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_control =
9381da177e4SLinus Torvalds {
9395549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
9401da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
9417583cb51STakashi Iwai 	.count =	3,
9421da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
9431da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
9441da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
9451da177e4SLinus Torvalds };
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds 
948eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
9491da177e4SLinus Torvalds {
9501da177e4SLinus Torvalds 	if (emu->audigy) {
9511da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
9521da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
9531da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
9541da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
9551da177e4SLinus Torvalds 	} else {
9561da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
9571da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
9581da177e4SLinus Torvalds 	}
9591da177e4SLinus Torvalds }
9601da177e4SLinus Torvalds 
961eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
9621da177e4SLinus Torvalds {
9631da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
9641da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
9651da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
9661da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
9671da177e4SLinus Torvalds 	if (emu->audigy) {
9681da177e4SLinus Torvalds 		unsigned int val = ((unsigned int)volume[4] << 24) |
9691da177e4SLinus Torvalds 			((unsigned int)volume[5] << 16) |
9701da177e4SLinus Torvalds 			((unsigned int)volume[6] << 8) |
9711da177e4SLinus Torvalds 			(unsigned int)volume[7];
9721da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
9731da177e4SLinus Torvalds 	}
9741da177e4SLinus Torvalds }
9751da177e4SLinus Torvalds 
9761da177e4SLinus Torvalds /* PCM stream controls */
9771da177e4SLinus Torvalds 
978eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9791da177e4SLinus Torvalds {
980eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
9811da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
9821da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
9831da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
9841da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
9851da177e4SLinus Torvalds 	return 0;
9861da177e4SLinus Torvalds }
9871da177e4SLinus Torvalds 
988eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
989eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
9901da177e4SLinus Torvalds {
9911da177e4SLinus Torvalds 	unsigned long flags;
992eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
993eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
994eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
9951da177e4SLinus Torvalds 	int voice, idx;
9961da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
9971da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
9981da177e4SLinus Torvalds 
9991da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10001da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
10011da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
10021da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
10031da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
10041da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10051da177e4SLinus Torvalds 	return 0;
10061da177e4SLinus Torvalds }
10071da177e4SLinus Torvalds 
1008eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
1009eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
10101da177e4SLinus Torvalds {
10111da177e4SLinus Torvalds 	unsigned long flags;
1012eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1013eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1014eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10151da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
10161da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
10171da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
10181da177e4SLinus Torvalds 
10191da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10201da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
10211da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
10221da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
10231da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
10241da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
10251da177e4SLinus Torvalds 				change = 1;
10261da177e4SLinus Torvalds 			}
10271da177e4SLinus Torvalds 		}
10281da177e4SLinus Torvalds 	if (change && mix->epcm) {
10291da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
10301da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
10311da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
10321da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
10331da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
10341da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
10351da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
10361da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
10371da177e4SLinus Torvalds 		}
10381da177e4SLinus Torvalds 	}
10391da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10401da177e4SLinus Torvalds 	return change;
10411da177e4SLinus Torvalds }
10421da177e4SLinus Torvalds 
1043eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_routing_control =
10441da177e4SLinus Torvalds {
10451da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
104667ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
10471da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
10481da177e4SLinus Torvalds 	.count =	32,
10491da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
10501da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
10511da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
10521da177e4SLinus Torvalds };
10531da177e4SLinus Torvalds 
1054eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
10551da177e4SLinus Torvalds {
1056eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
10571da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
10581da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
10591da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
10601da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
10611da177e4SLinus Torvalds 	return 0;
10621da177e4SLinus Torvalds }
10631da177e4SLinus Torvalds 
1064eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1065eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
10661da177e4SLinus Torvalds {
10671da177e4SLinus Torvalds 	unsigned long flags;
1068eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1069eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1070eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10711da177e4SLinus Torvalds 	int idx;
10721da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
10731da177e4SLinus Torvalds 
10741da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10751da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
10761da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
10771da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10781da177e4SLinus Torvalds 	return 0;
10791da177e4SLinus Torvalds }
10801da177e4SLinus Torvalds 
1081eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1082eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
10831da177e4SLinus Torvalds {
10841da177e4SLinus Torvalds 	unsigned long flags;
1085eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1086*74415a36SJames Courtier-Dutton 	/* FIXME: Check limits */
1087eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1088eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10891da177e4SLinus Torvalds 	int change = 0, idx, val;
10901da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
10911da177e4SLinus Torvalds 
10921da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10931da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
10941da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
10951da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
10961da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
10971da177e4SLinus Torvalds 			change = 1;
10981da177e4SLinus Torvalds 		}
10991da177e4SLinus Torvalds 	}
11001da177e4SLinus Torvalds 	if (change && mix->epcm) {
11011da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
11021da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
11031da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
11041da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
11051da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
11061da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
11071da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
11081da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
11091da177e4SLinus Torvalds 		}
11101da177e4SLinus Torvalds 	}
11111da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11121da177e4SLinus Torvalds 	return change;
11131da177e4SLinus Torvalds }
11141da177e4SLinus Torvalds 
1115eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_volume_control =
11161da177e4SLinus Torvalds {
11171da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
111867ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11191da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
11201da177e4SLinus Torvalds 	.count =	32,
11211da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
11221da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
11231da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
11241da177e4SLinus Torvalds };
11251da177e4SLinus Torvalds 
1126eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11271da177e4SLinus Torvalds {
11281da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
11291da177e4SLinus Torvalds 	uinfo->count = 3;
11301da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11311da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
11321da177e4SLinus Torvalds 	return 0;
11331da177e4SLinus Torvalds }
11341da177e4SLinus Torvalds 
1135eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1136eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
11371da177e4SLinus Torvalds {
1138eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1139*74415a36SJames Courtier-Dutton 	/* FIXME: Check limits */
1140eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1141eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11421da177e4SLinus Torvalds 	unsigned long flags;
11431da177e4SLinus Torvalds 	int idx;
11441da177e4SLinus Torvalds 
11451da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11461da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
11471da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->attn[idx];
11481da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11491da177e4SLinus Torvalds 	return 0;
11501da177e4SLinus Torvalds }
11511da177e4SLinus Torvalds 
1152eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1153eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
11541da177e4SLinus Torvalds {
11551da177e4SLinus Torvalds 	unsigned long flags;
1156eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1157*74415a36SJames Courtier-Dutton 	/* FIXME: Check limits */
1158eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1159eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11601da177e4SLinus Torvalds 	int change = 0, idx, val;
11611da177e4SLinus Torvalds 
11621da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11631da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
11641da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 0xffff;
11651da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
11661da177e4SLinus Torvalds 			mix->attn[idx] = val;
11671da177e4SLinus Torvalds 			change = 1;
11681da177e4SLinus Torvalds 		}
11691da177e4SLinus Torvalds 	}
11701da177e4SLinus Torvalds 	if (change && mix->epcm) {
11711da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
11721da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
11731da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
11741da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
11751da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
11761da177e4SLinus Torvalds 		}
11771da177e4SLinus Torvalds 	}
11781da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11791da177e4SLinus Torvalds 	return change;
11801da177e4SLinus Torvalds }
11811da177e4SLinus Torvalds 
1182eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_attn_control =
11831da177e4SLinus Torvalds {
11841da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
118567ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11861da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
11871da177e4SLinus Torvalds 	.count =	32,
11881da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
11891da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
11901da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
11911da177e4SLinus Torvalds };
11921da177e4SLinus Torvalds 
11931da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
11941da177e4SLinus Torvalds 
1195eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11961da177e4SLinus Torvalds {
1197eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11981da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
11991da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
12001da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12011da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
12021da177e4SLinus Torvalds 	return 0;
12031da177e4SLinus Torvalds }
12041da177e4SLinus Torvalds 
1205eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1206eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
12071da177e4SLinus Torvalds {
12081da177e4SLinus Torvalds 	unsigned long flags;
1209eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1210*74415a36SJames Courtier-Dutton 	/* FIXME: Check limits */
1211eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1212eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12131da177e4SLinus Torvalds 	int idx;
12141da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12151da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
12161da177e4SLinus Torvalds 
12171da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12181da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
12191da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
12201da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
12211da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12221da177e4SLinus Torvalds 	return 0;
12231da177e4SLinus Torvalds }
12241da177e4SLinus Torvalds 
1225eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1226eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
12271da177e4SLinus Torvalds {
12281da177e4SLinus Torvalds 	unsigned long flags;
1229eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1230*74415a36SJames Courtier-Dutton 	/* FIXME: Check limits */
12311da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1232eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
12331da177e4SLinus Torvalds 	int change = 0, idx, val;
12341da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12351da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
12361da177e4SLinus Torvalds 
12371da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12381da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
12391da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
12401da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
12411da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
12421da177e4SLinus Torvalds 			change = 1;
12431da177e4SLinus Torvalds 		}
12441da177e4SLinus Torvalds 	}
12451da177e4SLinus Torvalds 
12461da177e4SLinus Torvalds 	if (change && mix->epcm) {
12471da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
12481da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
12491da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
12501da177e4SLinus Torvalds 		}
12511da177e4SLinus Torvalds 	}
12521da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12531da177e4SLinus Torvalds 	return change;
12541da177e4SLinus Torvalds }
12551da177e4SLinus Torvalds 
1256eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
12571da177e4SLinus Torvalds {
12581da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
12591da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12601da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
12611da177e4SLinus Torvalds 	.count =	16,
12621da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
12631da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
12641da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
12651da177e4SLinus Torvalds };
12661da177e4SLinus Torvalds 
1267eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12681da177e4SLinus Torvalds {
1269eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12701da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12711da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
12721da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12731da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
12741da177e4SLinus Torvalds 	return 0;
12751da177e4SLinus Torvalds }
12761da177e4SLinus Torvalds 
1277eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1278eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12791da177e4SLinus Torvalds {
12801da177e4SLinus Torvalds 	unsigned long flags;
1281eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1282*74415a36SJames Courtier-Dutton 	/* FIXME: Check limits */
1283eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1284eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12851da177e4SLinus Torvalds 	int idx;
12861da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12871da177e4SLinus Torvalds 
12881da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12891da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
12901da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
12911da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12921da177e4SLinus Torvalds 	return 0;
12931da177e4SLinus Torvalds }
12941da177e4SLinus Torvalds 
1295eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1296eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12971da177e4SLinus Torvalds {
12981da177e4SLinus Torvalds 	unsigned long flags;
1299eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1300*74415a36SJames Courtier-Dutton 	/* FIXME: Check limits */
13011da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1302eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
13031da177e4SLinus Torvalds 	int change = 0, idx, val;
13041da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
13051da177e4SLinus Torvalds 
13061da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13071da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
13081da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
13091da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
13101da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
13111da177e4SLinus Torvalds 			change = 1;
13121da177e4SLinus Torvalds 		}
13131da177e4SLinus Torvalds 	}
13141da177e4SLinus Torvalds 	if (change && mix->epcm) {
13151da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
13161da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
13171da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
13181da177e4SLinus Torvalds 		}
13191da177e4SLinus Torvalds 	}
13201da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13211da177e4SLinus Torvalds 	return change;
13221da177e4SLinus Torvalds }
13231da177e4SLinus Torvalds 
13241da177e4SLinus Torvalds 
1325eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
13261da177e4SLinus Torvalds {
13271da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
13281da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13291da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
13301da177e4SLinus Torvalds 	.count =	16,
13311da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
13321da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
13331da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
13341da177e4SLinus Torvalds };
13351da177e4SLinus Torvalds 
1336eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13371da177e4SLinus Torvalds {
13381da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
13391da177e4SLinus Torvalds 	uinfo->count = 1;
13401da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13411da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
13421da177e4SLinus Torvalds 	return 0;
13431da177e4SLinus Torvalds }
13441da177e4SLinus Torvalds 
1345eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1346eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
13471da177e4SLinus Torvalds {
1348eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1349*74415a36SJames Courtier-Dutton 	/* FIXME: Check limits */
1350eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1351eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
13521da177e4SLinus Torvalds 	unsigned long flags;
13531da177e4SLinus Torvalds 
13541da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13551da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = mix->attn[0];
13561da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13571da177e4SLinus Torvalds 	return 0;
13581da177e4SLinus Torvalds }
13591da177e4SLinus Torvalds 
1360eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1361eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
13621da177e4SLinus Torvalds {
13631da177e4SLinus Torvalds 	unsigned long flags;
1364eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1365*74415a36SJames Courtier-Dutton 	/* FIXME: Check limits */
13661da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1367eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
13681da177e4SLinus Torvalds 	int change = 0, val;
13691da177e4SLinus Torvalds 
13701da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13711da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] & 0xffff;
13721da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
13731da177e4SLinus Torvalds 		mix->attn[0] = val;
13741da177e4SLinus Torvalds 		change = 1;
13751da177e4SLinus Torvalds 	}
13761da177e4SLinus Torvalds 	if (change && mix->epcm) {
13771da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
13781da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
13791da177e4SLinus Torvalds 		}
13801da177e4SLinus Torvalds 	}
13811da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13821da177e4SLinus Torvalds 	return change;
13831da177e4SLinus Torvalds }
13841da177e4SLinus Torvalds 
1385eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
13861da177e4SLinus Torvalds {
13871da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
13881da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13891da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
13901da177e4SLinus Torvalds 	.count =	16,
13911da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
13921da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
13931da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
13941da177e4SLinus Torvalds };
13951da177e4SLinus Torvalds 
1396a5ce8890STakashi Iwai #define snd_emu10k1_shared_spdif_info	snd_ctl_boolean_mono_info
13971da177e4SLinus Torvalds 
1398eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1399eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
14001da177e4SLinus Torvalds {
1401eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14021da177e4SLinus Torvalds 
14031da177e4SLinus Torvalds 	if (emu->audigy)
14041da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
14051da177e4SLinus Torvalds 	else
14061da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
14071da177e4SLinus Torvalds 	return 0;
14081da177e4SLinus Torvalds }
14091da177e4SLinus Torvalds 
1410eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1411eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
14121da177e4SLinus Torvalds {
14131da177e4SLinus Torvalds 	unsigned long flags;
1414eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
14151da177e4SLinus Torvalds 	unsigned int reg, val;
14161da177e4SLinus Torvalds 	int change = 0;
14171da177e4SLinus Torvalds 
14181da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1419184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1420184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1421184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
14221da177e4SLinus Torvalds 		reg = inl(emu->port + A_IOCFG);
14231da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
14241da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
14251da177e4SLinus Torvalds 		if (change) {
14261da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
14271da177e4SLinus Torvalds 			reg |= val;
14281da177e4SLinus Torvalds 			outl(reg | val, emu->port + A_IOCFG);
14291da177e4SLinus Torvalds 		}
14301da177e4SLinus Torvalds 	}
14311da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
14321da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0;
14331da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
14341da177e4SLinus Torvalds 	if (change) {
14351da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
14361da177e4SLinus Torvalds 		reg |= val;
14371da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
14381da177e4SLinus Torvalds 	}
14391da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
14401da177e4SLinus Torvalds 	return change;
14411da177e4SLinus Torvalds }
14421da177e4SLinus Torvalds 
1443eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata =
14441da177e4SLinus Torvalds {
14451da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
14461da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
14471da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
14481da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
14491da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
14501da177e4SLinus Torvalds };
14511da177e4SLinus Torvalds 
1452eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata =
14531da177e4SLinus Torvalds {
14541da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
14551da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
14561da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
14571da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
14581da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
14591da177e4SLinus Torvalds };
14601da177e4SLinus Torvalds 
14611da177e4SLinus Torvalds /*
14621da177e4SLinus Torvalds  */
1463eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
14641da177e4SLinus Torvalds {
1465eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
14661da177e4SLinus Torvalds 	emu->ac97 = NULL;
14671da177e4SLinus Torvalds }
14681da177e4SLinus Torvalds 
14691da177e4SLinus Torvalds /*
14701da177e4SLinus Torvalds  */
1471eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
14721da177e4SLinus Torvalds {
1473eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
14741da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
14751da177e4SLinus Torvalds 	strcpy(id.name, name);
14761da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
14771da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
14781da177e4SLinus Torvalds }
14791da177e4SLinus Torvalds 
1480eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
14811da177e4SLinus Torvalds {
1482eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
14831da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
14841da177e4SLinus Torvalds 	strcpy(sid.name, name);
14851da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
14861da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
14871da177e4SLinus Torvalds }
14881da177e4SLinus Torvalds 
1489eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
14901da177e4SLinus Torvalds {
1491eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
14921da177e4SLinus Torvalds 	if (kctl) {
14931da177e4SLinus Torvalds 		strcpy(kctl->id.name, dst);
14941da177e4SLinus Torvalds 		return 0;
14951da177e4SLinus Torvalds 	}
14961da177e4SLinus Torvalds 	return -ENOENT;
14971da177e4SLinus Torvalds }
14981da177e4SLinus Torvalds 
1499eb4698f3STakashi Iwai int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
150067ed4161SClemens Ladisch 				int pcm_device, int multi_device)
15011da177e4SLinus Torvalds {
15021da177e4SLinus Torvalds 	int err, pcm;
1503eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1504eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
15051da177e4SLinus Torvalds 	char **c;
15061da177e4SLinus Torvalds 	static char *emu10k1_remove_ctls[] = {
15071da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
15081da177e4SLinus Torvalds 		"Master Mono Playback Switch",
15091da177e4SLinus Torvalds 		"Master Mono Playback Volume",
15101da177e4SLinus Torvalds 		"PCM Out Path & Mute",
15111da177e4SLinus Torvalds 		"Mono Output Select",
15127eae36fbSTakashi Iwai 		"Front Playback Switch",
15137eae36fbSTakashi Iwai 		"Front Playback Volume",
15141da177e4SLinus Torvalds 		"Surround Playback Switch",
15151da177e4SLinus Torvalds 		"Surround Playback Volume",
15161da177e4SLinus Torvalds 		"Center Playback Switch",
15171da177e4SLinus Torvalds 		"Center Playback Volume",
15181da177e4SLinus Torvalds 		"LFE Playback Switch",
15191da177e4SLinus Torvalds 		"LFE Playback Volume",
15201da177e4SLinus Torvalds 		NULL
15211da177e4SLinus Torvalds 	};
15221da177e4SLinus Torvalds 	static char *emu10k1_rename_ctls[] = {
15231da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
15241da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
15251da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
15261da177e4SLinus Torvalds 		NULL
15271da177e4SLinus Torvalds 	};
15281da177e4SLinus Torvalds 	static char *audigy_remove_ctls[] = {
15291da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
153021fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
153121fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
15321da177e4SLinus Torvalds 		"PCM Playback Switch",
15331da177e4SLinus Torvalds 		"PCM Playback Volume",
15341da177e4SLinus Torvalds 		"Master Mono Playback Switch",
15351da177e4SLinus Torvalds 		"Master Mono Playback Volume",
15361da177e4SLinus Torvalds 		"Master Playback Switch",
15371da177e4SLinus Torvalds 		"Master Playback Volume",
15381da177e4SLinus Torvalds 		"PCM Out Path & Mute",
15391da177e4SLinus Torvalds 		"Mono Output Select",
15401da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
15411da177e4SLinus Torvalds 		"Capture Source",
15421da177e4SLinus Torvalds 		"Capture Switch",
15431da177e4SLinus Torvalds 		"Capture Volume",
15441da177e4SLinus Torvalds 		"Mic Select",
15451da177e4SLinus Torvalds 		"Video Playback Switch",
15461da177e4SLinus Torvalds 		"Video Playback Volume",
15471da177e4SLinus Torvalds 		"Mic Playback Switch",
15481da177e4SLinus Torvalds 		"Mic Playback Volume",
15491da177e4SLinus Torvalds 		NULL
15501da177e4SLinus Torvalds 	};
15511da177e4SLinus Torvalds 	static char *audigy_rename_ctls[] = {
15521da177e4SLinus Torvalds 		/* use conventional names */
15531da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
15541da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
15551da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
15561da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
15571da177e4SLinus Torvalds 		NULL
15581da177e4SLinus Torvalds 	};
1559184c1e2cSJames Courtier-Dutton 	static char *audigy_rename_ctls_i2c_adc[] = {
1560184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1561184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1562184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1563184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1564184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1565eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1566184c1e2cSJames Courtier-Dutton 		NULL
1567184c1e2cSJames Courtier-Dutton 	};
1568184c1e2cSJames Courtier-Dutton 	static char *audigy_remove_ctls_i2c_adc[] = {
1569184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1570184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1571184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1572184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1573184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1574eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1575184c1e2cSJames Courtier-Dutton 		NULL
1576184c1e2cSJames Courtier-Dutton 	};
157721fdddeaSJames Courtier-Dutton 	static char *audigy_remove_ctls_1361t_adc[] = {
157821fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
157921fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
158021fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
158121fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
158221fdddeaSJames Courtier-Dutton 		"Master Mono Playback Switch",
158321fdddeaSJames Courtier-Dutton 		"Master Mono Playback Volume",
158421fdddeaSJames Courtier-Dutton 		"Capture Source",
158521fdddeaSJames Courtier-Dutton 		"Capture Switch",
158621fdddeaSJames Courtier-Dutton 		"Capture Volume",
158721fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
158821fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
158921fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
159021fdddeaSJames Courtier-Dutton 		"3D Control - Center",
159121fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
159221fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
159321fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
159421fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
159521fdddeaSJames Courtier-Dutton 		NULL
159621fdddeaSJames Courtier-Dutton 	};
159721fdddeaSJames Courtier-Dutton 	static char *audigy_rename_ctls_1361t_adc[] = {
159821fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
159921fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
160021fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
160121fdddeaSJames Courtier-Dutton 		"PC Speaker Playback Switch", "PC Speaker Capture Switch",
160221fdddeaSJames Courtier-Dutton 		"PC Speaker Playback Volume", "PC Speaker Capture Volume",
160321fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
160421fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
160521fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
160621fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
160721fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
160821fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
160921fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
161021fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
161121fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
161221fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
161321fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
161421fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
161521fdddeaSJames Courtier-Dutton 
161621fdddeaSJames Courtier-Dutton 		NULL
161721fdddeaSJames Courtier-Dutton 	};
16181da177e4SLinus Torvalds 
16192b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1620eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1621eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
1622eb4698f3STakashi Iwai 		static struct snd_ac97_bus_ops ops = {
16231da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
16241da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
16251da177e4SLinus Torvalds 		};
16261da177e4SLinus Torvalds 
1627b1508693STakashi Iwai 		if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0)
16281da177e4SLinus Torvalds 			return err;
16291da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
16301da177e4SLinus Torvalds 
16311da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
16321da177e4SLinus Torvalds 		ac97.private_data = emu;
16331da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
16341da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
1635b1508693STakashi Iwai 		if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
1636b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
16371da177e4SLinus Torvalds 				return err;
1638b1508693STakashi Iwai 			snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n");
1639b1508693STakashi Iwai 			snd_printd(KERN_INFO"          Proceeding without ac97 mixers...\n");
1640b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1641b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1642b1508693STakashi Iwai 		}
16431da177e4SLinus Torvalds 		if (emu->audigy) {
16441da177e4SLinus Torvalds 			/* set master volume to 0 dB */
16454d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
16461da177e4SLinus Torvalds 			/* set capture source to mic */
16474d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
164821fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
164921fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
165021fdddeaSJames Courtier-Dutton 			else
16511da177e4SLinus Torvalds 				c = audigy_remove_ctls;
16521da177e4SLinus Torvalds 		} else {
16531da177e4SLinus Torvalds 			/*
16541da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
16551da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
16561da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
16571da177e4SLinus Torvalds 			 */
16581da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
16591da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
16601da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
16612594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
16621da177e4SLinus Torvalds 			}
16631da177e4SLinus Torvalds 			/* remove unused AC97 controls */
16644d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
16654d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
16661da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
16671da177e4SLinus Torvalds 		}
16681da177e4SLinus Torvalds 		for (; *c; c++)
16691da177e4SLinus Torvalds 			remove_ctl(card, *c);
1670184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1671184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1672184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1673184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
16741da177e4SLinus Torvalds 	} else {
1675f12aa40cSTakashi Iwai 	no_ac97:
16762b637da5SLee Revell 		if (emu->card_capabilities->ecard)
16771da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
16781da177e4SLinus Torvalds 		else if (emu->audigy)
16791da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
16801da177e4SLinus Torvalds 		else
16811da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
16821da177e4SLinus Torvalds 	}
16831da177e4SLinus Torvalds 
16841da177e4SLinus Torvalds 	if (emu->audigy)
168521fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
168621fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1687184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1688184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
168921fdddeaSJames Courtier-Dutton 		else
16901da177e4SLinus Torvalds 			c = audigy_rename_ctls;
16911da177e4SLinus Torvalds 	else
16921da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
16931da177e4SLinus Torvalds 	for (; *c; c += 2)
16941da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
169521fdddeaSJames Courtier-Dutton 
1696e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1697e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1698e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1699e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1700e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1701e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Switch");
1702e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Volume");
1703e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Center");
1704e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Depth");
1705e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Switch");
1706e3b9bc0eSJames Courtier-Dutton 	}
17071da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
17081da177e4SLinus Torvalds 		return -ENOMEM;
170967ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
17101da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
17111da177e4SLinus Torvalds 		return err;
17121da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
17131da177e4SLinus Torvalds 		return -ENOMEM;
171467ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
17151da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
17161da177e4SLinus Torvalds 		return err;
17171da177e4SLinus Torvalds 	if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
17181da177e4SLinus Torvalds 		return -ENOMEM;
171967ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
17201da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
17211da177e4SLinus Torvalds 		return err;
17221da177e4SLinus Torvalds 
17231da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
17241da177e4SLinus Torvalds 		return -ENOMEM;
172567ed4161SClemens Ladisch 	kctl->id.device = multi_device;
17261da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
17271da177e4SLinus Torvalds 		return err;
17281da177e4SLinus Torvalds 
17291da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
17301da177e4SLinus Torvalds 		return -ENOMEM;
173167ed4161SClemens Ladisch 	kctl->id.device = multi_device;
17321da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
17331da177e4SLinus Torvalds 		return err;
17341da177e4SLinus Torvalds 
17351da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
17361da177e4SLinus Torvalds 		return -ENOMEM;
173767ed4161SClemens Ladisch 	kctl->id.device = multi_device;
17381da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
17391da177e4SLinus Torvalds 		return err;
17401da177e4SLinus Torvalds 
17411da177e4SLinus Torvalds 	/* initialize the routing and volume table for each pcm playback stream */
17421da177e4SLinus Torvalds 	for (pcm = 0; pcm < 32; pcm++) {
1743eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
17441da177e4SLinus Torvalds 		int v;
17451da177e4SLinus Torvalds 
17461da177e4SLinus Torvalds 		mix = &emu->pcm_mixer[pcm];
17471da177e4SLinus Torvalds 		mix->epcm = NULL;
17481da177e4SLinus Torvalds 
17491da177e4SLinus Torvalds 		for (v = 0; v < 4; v++)
17501da177e4SLinus Torvalds 			mix->send_routing[0][v] =
17511da177e4SLinus Torvalds 				mix->send_routing[1][v] =
17521da177e4SLinus Torvalds 				mix->send_routing[2][v] = v;
17531da177e4SLinus Torvalds 
17541da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
17551da177e4SLinus Torvalds 		mix->send_volume[0][0] = mix->send_volume[0][1] =
17561da177e4SLinus Torvalds 		mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
17571da177e4SLinus Torvalds 
17581da177e4SLinus Torvalds 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
17591da177e4SLinus Torvalds 	}
17601da177e4SLinus Torvalds 
17611da177e4SLinus Torvalds 	/* initialize the routing and volume table for the multichannel playback stream */
17621da177e4SLinus Torvalds 	for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
1763eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
17641da177e4SLinus Torvalds 		int v;
17651da177e4SLinus Torvalds 
17661da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[pcm];
17671da177e4SLinus Torvalds 		mix->epcm = NULL;
17681da177e4SLinus Torvalds 
17691da177e4SLinus Torvalds 		mix->send_routing[0][0] = pcm;
17701da177e4SLinus Torvalds 		mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
17711da177e4SLinus Torvalds 		for (v = 0; v < 2; v++)
17721da177e4SLinus Torvalds 			mix->send_routing[0][2+v] = 13+v;
17731da177e4SLinus Torvalds 		if (emu->audigy)
17741da177e4SLinus Torvalds 			for (v = 0; v < 4; v++)
17751da177e4SLinus Torvalds 				mix->send_routing[0][4+v] = 60+v;
17761da177e4SLinus Torvalds 
17771da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
17781da177e4SLinus Torvalds 		mix->send_volume[0][0]  = 255;
17791da177e4SLinus Torvalds 
17801da177e4SLinus Torvalds 		mix->attn[0] = 0xffff;
17811da177e4SLinus Torvalds 	}
17821da177e4SLinus Torvalds 
17832b637da5SLee Revell 	if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
17841da177e4SLinus Torvalds 		/* sb live! and audigy */
17851da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
17861da177e4SLinus Torvalds 			return -ENOMEM;
17875549d549SClemens Ladisch 		if (!emu->audigy)
17885549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
17891da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17901da177e4SLinus Torvalds 			return err;
17911da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
17921da177e4SLinus Torvalds 			return -ENOMEM;
17935549d549SClemens Ladisch 		if (!emu->audigy)
17945549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
17951da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17961da177e4SLinus Torvalds 			return err;
17971da177e4SLinus Torvalds 	}
17981da177e4SLinus Torvalds 
17999f4bd5ddSJames Courtier-Dutton 	if ( emu->card_capabilities->emu1010) {
180019b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
180119b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
18021da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
18031da177e4SLinus Torvalds 			return -ENOMEM;
18041da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
18051da177e4SLinus Torvalds 			return err;
1806001f7589SJames Courtier-Dutton #if 0
18071da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
18081da177e4SLinus Torvalds 			return -ENOMEM;
18091da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
18101da177e4SLinus Torvalds 			return err;
1811001f7589SJames Courtier-Dutton #endif
18122b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
18131da177e4SLinus Torvalds 		/* sb live! */
18141da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
18151da177e4SLinus Torvalds 			return -ENOMEM;
18161da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
18171da177e4SLinus Torvalds 			return err;
18181da177e4SLinus Torvalds 	}
18192b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
18201da177e4SLinus Torvalds 		if ((err = snd_p16v_mixer(emu)))
18211da177e4SLinus Torvalds 			return err;
18221da177e4SLinus Torvalds 	}
18231da177e4SLinus Torvalds 
18249f4bd5ddSJames Courtier-Dutton 	if ( emu->card_capabilities->emu1010) {
18259f4bd5ddSJames Courtier-Dutton 		int i;
18269f4bd5ddSJames Courtier-Dutton 
18279f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
18289f4bd5ddSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu));
18299f4bd5ddSJames Courtier-Dutton 			if (err < 0)
18309f4bd5ddSJames Courtier-Dutton 				return err;
18319f4bd5ddSJames Courtier-Dutton 		}
18329f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
18339f4bd5ddSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu));
18349f4bd5ddSJames Courtier-Dutton 			if (err < 0)
18359f4bd5ddSJames Courtier-Dutton 				return err;
18369f4bd5ddSJames Courtier-Dutton 		}
18379148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
18389148cc50SJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
18399148cc50SJames Courtier-Dutton 			if (err < 0)
18409148cc50SJames Courtier-Dutton 				return err;
18419148cc50SJames Courtier-Dutton 		}
18429148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
18439148cc50SJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
18449148cc50SJames Courtier-Dutton 			if (err < 0)
18459148cc50SJames Courtier-Dutton 				return err;
18469148cc50SJames Courtier-Dutton 		}
1847b0dbdaeaSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu));
1848b0dbdaeaSJames Courtier-Dutton 		if (err < 0)
1849b0dbdaeaSJames Courtier-Dutton 			return err;
18509f4bd5ddSJames Courtier-Dutton 	}
18519f4bd5ddSJames Courtier-Dutton 
1852184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1853184c1e2cSJames Courtier-Dutton 		int i;
1854184c1e2cSJames Courtier-Dutton 
1855184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
1856184c1e2cSJames Courtier-Dutton 		if (err < 0)
1857184c1e2cSJames Courtier-Dutton 			return err;
1858184c1e2cSJames Courtier-Dutton 
1859184c1e2cSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
1860184c1e2cSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
1861184c1e2cSJames Courtier-Dutton 			if (err < 0)
1862184c1e2cSJames Courtier-Dutton 				return err;
1863184c1e2cSJames Courtier-Dutton 		}
1864184c1e2cSJames Courtier-Dutton 	}
1865184c1e2cSJames Courtier-Dutton 
18661da177e4SLinus Torvalds 	return 0;
18671da177e4SLinus Torvalds }
1868