xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision 13d457094bc364e942884266036fd1b2ab74308b)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
31da177e4SLinus Torvalds  *                   Takashi Iwai <tiwai@suse.de>
41da177e4SLinus Torvalds  *                   Creative Labs, Inc.
51da177e4SLinus Torvalds  *  Routines for control of EMU10K1 chips / mixer routines
61da177e4SLinus Torvalds  *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
71da177e4SLinus Torvalds  *
89f4bd5ddSJames Courtier-Dutton  *  Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
99f4bd5ddSJames Courtier-Dutton  *  	Added EMU 1010 support.
109f4bd5ddSJames Courtier-Dutton  *
111da177e4SLinus Torvalds  *  BUGS:
121da177e4SLinus Torvalds  *    --
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *  TODO:
151da177e4SLinus Torvalds  *    --
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *   This program is free software; you can redistribute it and/or modify
181da177e4SLinus Torvalds  *   it under the terms of the GNU General Public License as published by
191da177e4SLinus Torvalds  *   the Free Software Foundation; either version 2 of the License, or
201da177e4SLinus Torvalds  *   (at your option) any later version.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  *   This program is distributed in the hope that it will be useful,
231da177e4SLinus Torvalds  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
241da177e4SLinus Torvalds  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
251da177e4SLinus Torvalds  *   GNU General Public License for more details.
261da177e4SLinus Torvalds  *
271da177e4SLinus Torvalds  *   You should have received a copy of the GNU General Public License
281da177e4SLinus Torvalds  *   along with this program; if not, write to the Free Software
291da177e4SLinus Torvalds  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
301da177e4SLinus Torvalds  *
311da177e4SLinus Torvalds  */
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds #include <sound/driver.h>
341da177e4SLinus Torvalds #include <linux/time.h>
351da177e4SLinus Torvalds #include <linux/init.h>
361da177e4SLinus Torvalds #include <sound/core.h>
371da177e4SLinus Torvalds #include <sound/emu10k1.h>
38b0dbdaeaSJames Courtier-Dutton #include <linux/delay.h>
39184c1e2cSJames Courtier-Dutton #include <sound/tlv.h>
40184c1e2cSJames Courtier-Dutton 
41184c1e2cSJames Courtier-Dutton #include "p17v.h"
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds #define AC97_ID_STAC9758	0x83847658
441da177e4SLinus Torvalds 
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 
611da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
621da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
631da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
641da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
651da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
661da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
671da177e4SLinus Torvalds 	return 0;
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds 
70eb4698f3STakashi Iwai static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
71eb4698f3STakashi Iwai 				      struct snd_ctl_elem_value *ucontrol)
721da177e4SLinus Torvalds {
731da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
741da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
751da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
761da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
771da177e4SLinus Torvalds 	return 0;
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds 
80*13d45709SPavel Hofman /*
81*13d45709SPavel Hofman  * Items labels in enum mixer controls assigning source data to
82*13d45709SPavel Hofman  * each destination
83*13d45709SPavel Hofman  */
849f4bd5ddSJames Courtier-Dutton static char *emu1010_src_texts[] = {
859f4bd5ddSJames Courtier-Dutton 	"Silence",
869f4bd5ddSJames Courtier-Dutton 	"Dock Mic A",
879f4bd5ddSJames Courtier-Dutton 	"Dock Mic B",
889f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Left",
899f4bd5ddSJames Courtier-Dutton 	"Dock ADC1 Right",
909f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Left",
919f4bd5ddSJames Courtier-Dutton 	"Dock ADC2 Right",
929f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Left",
939f4bd5ddSJames Courtier-Dutton 	"Dock ADC3 Right",
949f4bd5ddSJames Courtier-Dutton 	"0202 ADC Left",
959f4bd5ddSJames Courtier-Dutton 	"0202 ADC Right",
969f4bd5ddSJames Courtier-Dutton 	"0202 SPDIF Left",
979f4bd5ddSJames Courtier-Dutton 	"0202 SPDIF Right",
989f4bd5ddSJames Courtier-Dutton 	"ADAT 0",
999f4bd5ddSJames Courtier-Dutton 	"ADAT 1",
1009f4bd5ddSJames Courtier-Dutton 	"ADAT 2",
1019f4bd5ddSJames Courtier-Dutton 	"ADAT 3",
1029f4bd5ddSJames Courtier-Dutton 	"ADAT 4",
1039f4bd5ddSJames Courtier-Dutton 	"ADAT 5",
1049f4bd5ddSJames Courtier-Dutton 	"ADAT 6",
1059f4bd5ddSJames Courtier-Dutton 	"ADAT 7",
1069f4bd5ddSJames Courtier-Dutton 	"DSP 0",
1079f4bd5ddSJames Courtier-Dutton 	"DSP 1",
1089f4bd5ddSJames Courtier-Dutton 	"DSP 2",
1099f4bd5ddSJames Courtier-Dutton 	"DSP 3",
1109f4bd5ddSJames Courtier-Dutton 	"DSP 4",
1119f4bd5ddSJames Courtier-Dutton 	"DSP 5",
1129f4bd5ddSJames Courtier-Dutton 	"DSP 6",
1139f4bd5ddSJames Courtier-Dutton 	"DSP 7",
1149f4bd5ddSJames Courtier-Dutton 	"DSP 8",
1159f4bd5ddSJames Courtier-Dutton 	"DSP 9",
1169f4bd5ddSJames Courtier-Dutton 	"DSP 10",
1179f4bd5ddSJames Courtier-Dutton 	"DSP 11",
1189f4bd5ddSJames Courtier-Dutton 	"DSP 12",
1199f4bd5ddSJames Courtier-Dutton 	"DSP 13",
1209f4bd5ddSJames Courtier-Dutton 	"DSP 14",
1219f4bd5ddSJames Courtier-Dutton 	"DSP 15",
1229f4bd5ddSJames Courtier-Dutton 	"DSP 16",
1239f4bd5ddSJames Courtier-Dutton 	"DSP 17",
1249f4bd5ddSJames Courtier-Dutton 	"DSP 18",
1259f4bd5ddSJames Courtier-Dutton 	"DSP 19",
1269f4bd5ddSJames Courtier-Dutton 	"DSP 20",
1279f4bd5ddSJames Courtier-Dutton 	"DSP 21",
1289f4bd5ddSJames Courtier-Dutton 	"DSP 22",
1299f4bd5ddSJames Courtier-Dutton 	"DSP 23",
1309f4bd5ddSJames Courtier-Dutton 	"DSP 24",
1319f4bd5ddSJames Courtier-Dutton 	"DSP 25",
1329f4bd5ddSJames Courtier-Dutton 	"DSP 26",
1339f4bd5ddSJames Courtier-Dutton 	"DSP 27",
1349f4bd5ddSJames Courtier-Dutton 	"DSP 28",
1359f4bd5ddSJames Courtier-Dutton 	"DSP 29",
1369f4bd5ddSJames Courtier-Dutton 	"DSP 30",
1379f4bd5ddSJames Courtier-Dutton 	"DSP 31",
1389f4bd5ddSJames Courtier-Dutton };
1399f4bd5ddSJames Courtier-Dutton 
140*13d45709SPavel Hofman /*
141*13d45709SPavel Hofman  * List of data sources available for each destination
142*13d45709SPavel Hofman  */
1439f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_src_regs[] = {
1449f4bd5ddSJames Courtier-Dutton 	EMU_SRC_SILENCE,/* 0 */
1459f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_MIC_A1, /* 1 */
1469f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_MIC_B1, /* 2 */
1479f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */
1489f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */
1499f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */
1509f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */
1519f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */
1529f4bd5ddSJames Courtier-Dutton 	EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */
1539f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */
1549f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */
1559f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */
1569f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */
1579f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT, /* 13 */
1589f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+1, /* 14 */
1599f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+2, /* 15 */
1609f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+3, /* 16 */
1619f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+4, /* 17 */
1629f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+5, /* 18 */
1639f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+6, /* 19 */
1649f4bd5ddSJames Courtier-Dutton 	EMU_SRC_HANA_ADAT+7, /* 20 */
1659f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A, /* 21 */
1669f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+1, /* 22 */
1679f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+2, /* 23 */
1689f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+3, /* 24 */
1699f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+4, /* 25 */
1709f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+5, /* 26 */
1719f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+6, /* 27 */
1729f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+7, /* 28 */
1739f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+8, /* 29 */
1749f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+9, /* 30 */
1759f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xa, /* 31 */
1769f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xb, /* 32 */
1779f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xc, /* 33 */
1789f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xd, /* 34 */
1799f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xe, /* 35 */
1809f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32A+0xf, /* 36 */
1819f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B, /* 37 */
1829f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+1, /* 38 */
1839f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+2, /* 39 */
1849f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+3, /* 40 */
1859f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+4, /* 41 */
1869f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+5, /* 42 */
1879f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+6, /* 43 */
1889f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+7, /* 44 */
1899f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+8, /* 45 */
1909f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+9, /* 46 */
1919f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xa, /* 47 */
1929f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xb, /* 48 */
1939f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xc, /* 49 */
1949f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xd, /* 50 */
1959f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xe, /* 51 */
1969f4bd5ddSJames Courtier-Dutton 	EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
1979f4bd5ddSJames Courtier-Dutton };
1989f4bd5ddSJames Courtier-Dutton 
199*13d45709SPavel Hofman /*
200*13d45709SPavel Hofman  * Data destinations - physical EMU outputs.
201*13d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
202*13d45709SPavel Hofman  */
2039f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_output_dst[] = {
2049f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
2059f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
2069f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC2_LEFT1, /* 2 */
2079f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */
2089f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC3_LEFT1, /* 4 */
2099f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */
2109f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC4_LEFT1, /* 6 */
2119f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */
2129f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_PHONES_LEFT1, /* 8 */
2139f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */
2149f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */
2159f4bd5ddSJames Courtier-Dutton 	EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */
2169f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_SPDIF_LEFT1, /* 12 */
2179f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */
2189f4bd5ddSJames Courtier-Dutton 	EMU_DST_HAMOA_DAC_LEFT1, /* 14 */
2199f4bd5ddSJames Courtier-Dutton 	EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */
2209f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT, /* 16 */
2219f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+1, /* 17 */
2229f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+2, /* 18 */
2239f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+3, /* 19 */
2249f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+4, /* 20 */
2259f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+5, /* 21 */
2269f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+6, /* 22 */
2279f4bd5ddSJames Courtier-Dutton 	EMU_DST_HANA_ADAT+7, /* 23 */
2289f4bd5ddSJames Courtier-Dutton };
2299f4bd5ddSJames Courtier-Dutton 
230*13d45709SPavel Hofman /*
231*13d45709SPavel Hofman  * Data destinations - HANA outputs going to Alice2 (audigy) for
232*13d45709SPavel Hofman  *   capture (EMU32 + I2S links)
233*13d45709SPavel Hofman  * Each destination has an enum mixer control to choose a data source
234*13d45709SPavel Hofman  */
2359f4bd5ddSJames Courtier-Dutton static unsigned int emu1010_input_dst[] = {
2369f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_0,
2379f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_1,
2389f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_2,
2399f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_3,
2409f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_4,
2419f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_5,
2429f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_6,
2439f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_7,
2449f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_8,
2459f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_9,
2469f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_A,
2479f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_B,
2489f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_C,
2499f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_D,
2509f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_E,
2519f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE2_EMU32_F,
2529f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_LEFT,
2539f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S0_RIGHT,
2549f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_LEFT,
2559f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S1_RIGHT,
2569f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_LEFT,
2579f4bd5ddSJames Courtier-Dutton 	EMU_DST_ALICE_I2S2_RIGHT,
2589f4bd5ddSJames Courtier-Dutton };
2599f4bd5ddSJames Courtier-Dutton 
2609f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
2619f4bd5ddSJames Courtier-Dutton {
2629f4bd5ddSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2639f4bd5ddSJames Courtier-Dutton 	uinfo->count = 1;
2649f4bd5ddSJames Courtier-Dutton 	uinfo->value.enumerated.items = 53;
2659f4bd5ddSJames Courtier-Dutton 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2669f4bd5ddSJames Courtier-Dutton 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
2679f4bd5ddSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]);
2689f4bd5ddSJames Courtier-Dutton 	return 0;
2699f4bd5ddSJames Courtier-Dutton }
2709f4bd5ddSJames Courtier-Dutton 
2719f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
2729f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
2739f4bd5ddSJames Courtier-Dutton {
2749f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
2759f4bd5ddSJames Courtier-Dutton 	int channel;
2769f4bd5ddSJames Courtier-Dutton 
2779f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
2789f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel];
2799f4bd5ddSJames Courtier-Dutton 	return 0;
2809f4bd5ddSJames Courtier-Dutton }
2819f4bd5ddSJames Courtier-Dutton 
2829f4bd5ddSJames Courtier-Dutton static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
2839f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
2849f4bd5ddSJames Courtier-Dutton {
2859f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
2869f4bd5ddSJames Courtier-Dutton 	int change = 0;
2879f4bd5ddSJames Courtier-Dutton 	unsigned int val;
2889f4bd5ddSJames Courtier-Dutton 	int channel;
2899f4bd5ddSJames Courtier-Dutton 
2909f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
2919f4bd5ddSJames Courtier-Dutton 	if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) {
2929f4bd5ddSJames Courtier-Dutton 		val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0];
2939f4bd5ddSJames Courtier-Dutton 		change = 1;
2949f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
2959f4bd5ddSJames Courtier-Dutton 			emu1010_output_dst[channel], emu1010_src_regs[val]);
2969f4bd5ddSJames Courtier-Dutton 	}
2979f4bd5ddSJames Courtier-Dutton 	return change;
2989f4bd5ddSJames Courtier-Dutton }
2999f4bd5ddSJames Courtier-Dutton 
3009f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol,
3019f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
3029f4bd5ddSJames Courtier-Dutton {
3039f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
3049f4bd5ddSJames Courtier-Dutton 	int channel;
3059f4bd5ddSJames Courtier-Dutton 
3069f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
3079f4bd5ddSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel];
3089f4bd5ddSJames Courtier-Dutton 	return 0;
3099f4bd5ddSJames Courtier-Dutton }
3109f4bd5ddSJames Courtier-Dutton 
3119f4bd5ddSJames Courtier-Dutton static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
3129f4bd5ddSJames Courtier-Dutton                                  struct snd_ctl_elem_value *ucontrol)
3139f4bd5ddSJames Courtier-Dutton {
3149f4bd5ddSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
3159f4bd5ddSJames Courtier-Dutton 	int change = 0;
3169f4bd5ddSJames Courtier-Dutton 	unsigned int val;
3179f4bd5ddSJames Courtier-Dutton 	int channel;
3189f4bd5ddSJames Courtier-Dutton 
3199f4bd5ddSJames Courtier-Dutton 	channel = (kcontrol->private_value) & 0xff;
3209f4bd5ddSJames Courtier-Dutton 	if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) {
3219f4bd5ddSJames Courtier-Dutton 		val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0];
3229f4bd5ddSJames Courtier-Dutton 		change = 1;
3239f4bd5ddSJames Courtier-Dutton 		snd_emu1010_fpga_link_dst_src_write(emu,
3249f4bd5ddSJames Courtier-Dutton 			emu1010_input_dst[channel], emu1010_src_regs[val]);
3259f4bd5ddSJames Courtier-Dutton 	}
3269f4bd5ddSJames Courtier-Dutton 	return change;
3279f4bd5ddSJames Courtier-Dutton }
3289f4bd5ddSJames Courtier-Dutton 
3299f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_OUTPUT(xname,chid) \
3309f4bd5ddSJames Courtier-Dutton {								\
3319f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
3329f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
3339f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
3349f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_output_source_get,			\
3359f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_output_source_put,			\
3369f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
3379f4bd5ddSJames Courtier-Dutton }
3389f4bd5ddSJames Courtier-Dutton 
3399f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = {
3404c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0),
3414c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1),
3424c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2),
3434c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3),
3444c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4),
3454c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5),
3464c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6),
3474c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7),
3484c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8),
3494c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9),
3504c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa),
3514c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb),
3524c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc),
3534c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd),
3544c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe),
3554c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf),
3564c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10),
3574c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11),
3584c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12),
3594c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13),
3604c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14),
3614c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15),
3624c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16),
3634c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17),
3649f4bd5ddSJames Courtier-Dutton };
3659f4bd5ddSJames Courtier-Dutton 
3669f4bd5ddSJames Courtier-Dutton #define EMU1010_SOURCE_INPUT(xname,chid) \
3679f4bd5ddSJames Courtier-Dutton {								\
3689f4bd5ddSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
3699f4bd5ddSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
3709f4bd5ddSJames Courtier-Dutton 	.info =  snd_emu1010_input_output_source_info,		\
3719f4bd5ddSJames Courtier-Dutton 	.get =   snd_emu1010_input_source_get,			\
3729f4bd5ddSJames Courtier-Dutton 	.put =   snd_emu1010_input_source_put,			\
3739f4bd5ddSJames Courtier-Dutton 	.private_value = chid					\
3749f4bd5ddSJames Courtier-Dutton }
3759f4bd5ddSJames Courtier-Dutton 
3769f4bd5ddSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = {
3774c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0),
3784c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1),
3794c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2),
3804c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3),
3814c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4),
3824c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5),
3834c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6),
3844c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7),
3854c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8),
3864c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9),
3874c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa),
3884c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb),
3894c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc),
3904c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd),
3914c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe),
3924c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf),
3934c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10),
3944c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11),
3954c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12),
3964c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13),
3974c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14),
3984c07c818SJames Courtier-Dutton 	EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15),
3999148cc50SJames Courtier-Dutton };
4009148cc50SJames Courtier-Dutton 
4019148cc50SJames Courtier-Dutton 
4029148cc50SJames Courtier-Dutton 
4039148cc50SJames Courtier-Dutton 
4049148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
4059148cc50SJames Courtier-Dutton {
4069148cc50SJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
4079148cc50SJames Courtier-Dutton 	uinfo->count = 1;
4089148cc50SJames Courtier-Dutton 	uinfo->value.integer.min = 0;
4099148cc50SJames Courtier-Dutton 	uinfo->value.integer.max = 1;
4109148cc50SJames Courtier-Dutton 	return 0;
4119148cc50SJames Courtier-Dutton }
4129148cc50SJames Courtier-Dutton 
4139148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4149148cc50SJames Courtier-Dutton {
4159148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4169148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4179148cc50SJames Courtier-Dutton 	ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0;
4189148cc50SJames Courtier-Dutton 	return 0;
4199148cc50SJames Courtier-Dutton }
4209148cc50SJames Courtier-Dutton 
4219148cc50SJames Courtier-Dutton static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4229148cc50SJames Courtier-Dutton {
4239148cc50SJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
4249148cc50SJames Courtier-Dutton 	unsigned int mask = kcontrol->private_value & 0xff;
4259148cc50SJames Courtier-Dutton 	unsigned int val, cache;
4269148cc50SJames Courtier-Dutton 	val = ucontrol->value.integer.value[0];
4279148cc50SJames Courtier-Dutton 	cache = emu->emu1010.adc_pads;
4289148cc50SJames Courtier-Dutton 	if (val == 1)
4299148cc50SJames Courtier-Dutton 		cache = cache | mask;
4309148cc50SJames Courtier-Dutton 	else
4319148cc50SJames Courtier-Dutton 		cache = cache & ~mask;
4329148cc50SJames Courtier-Dutton 	if (cache != emu->emu1010.adc_pads) {
4339148cc50SJames Courtier-Dutton 		snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
4349148cc50SJames Courtier-Dutton 	        emu->emu1010.adc_pads = cache;
4359148cc50SJames Courtier-Dutton 	}
4369148cc50SJames Courtier-Dutton 
4379148cc50SJames Courtier-Dutton 	return 0;
4389148cc50SJames Courtier-Dutton }
4399148cc50SJames Courtier-Dutton 
4409148cc50SJames Courtier-Dutton 
4419148cc50SJames Courtier-Dutton 
4429148cc50SJames Courtier-Dutton #define EMU1010_ADC_PADS(xname,chid) \
4439148cc50SJames Courtier-Dutton {								\
4449148cc50SJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
4459148cc50SJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,		\
4469148cc50SJames Courtier-Dutton 	.info =  snd_emu1010_adc_pads_info,			\
4479148cc50SJames Courtier-Dutton 	.get =   snd_emu1010_adc_pads_get,			\
4489148cc50SJames Courtier-Dutton 	.put =   snd_emu1010_adc_pads_put,			\
4499148cc50SJames Courtier-Dutton 	.private_value = chid					\
4509148cc50SJames Courtier-Dutton }
4519148cc50SJames Courtier-Dutton 
4529148cc50SJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = {
4539148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1),
4549148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2),
4559148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3),
4569148cc50SJames Courtier-Dutton 	EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1),
4579148cc50SJames Courtier-Dutton };
4589148cc50SJames Courtier-Dutton 
4599148cc50SJames Courtier-Dutton static int snd_emu1010_dac_pads_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
4609148cc50SJames Courtier-Dutton {
4619148cc50SJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
4629148cc50SJames Courtier-Dutton 	uinfo->count = 1;
4639148cc50SJames Courtier-Dutton 	uinfo->value.integer.min = 0;
4649148cc50SJames Courtier-Dutton 	uinfo->value.integer.max = 1;
4659148cc50SJames Courtier-Dutton 	return 0;
4669148cc50SJames Courtier-Dutton }
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 {
519b0dbdaeaSJames Courtier-Dutton 	static char *texts[2] = {
520b0dbdaeaSJames Courtier-Dutton 		"44100", "48000"
521b0dbdaeaSJames Courtier-Dutton 	};
522b0dbdaeaSJames Courtier-Dutton 
523b0dbdaeaSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
524b0dbdaeaSJames Courtier-Dutton 	uinfo->count = 1;
525b0dbdaeaSJames Courtier-Dutton 	uinfo->value.enumerated.items = 2;
526b0dbdaeaSJames Courtier-Dutton 	if (uinfo->value.enumerated.item > 1)
527b0dbdaeaSJames Courtier-Dutton                 uinfo->value.enumerated.item = 1;
528b0dbdaeaSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
529b0dbdaeaSJames Courtier-Dutton 	return 0;
530b0dbdaeaSJames Courtier-Dutton }
531b0dbdaeaSJames Courtier-Dutton 
532b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
533b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
534b0dbdaeaSJames Courtier-Dutton {
535b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
536b0dbdaeaSJames Courtier-Dutton 
537b0dbdaeaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock;
538b0dbdaeaSJames Courtier-Dutton 	return 0;
539b0dbdaeaSJames Courtier-Dutton }
540b0dbdaeaSJames Courtier-Dutton 
541b0dbdaeaSJames Courtier-Dutton static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol,
542b0dbdaeaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
543b0dbdaeaSJames Courtier-Dutton {
544b0dbdaeaSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
545b0dbdaeaSJames Courtier-Dutton 	unsigned int val;
546b0dbdaeaSJames Courtier-Dutton 	int change = 0;
547b0dbdaeaSJames Courtier-Dutton 
548b0dbdaeaSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
549b0dbdaeaSJames Courtier-Dutton 	change = (emu->emu1010.internal_clock != val);
550b0dbdaeaSJames Courtier-Dutton 	if (change) {
551b0dbdaeaSJames Courtier-Dutton 		emu->emu1010.internal_clock = val;
552b0dbdaeaSJames Courtier-Dutton 		switch (val) {
553b0dbdaeaSJames Courtier-Dutton 		case 0:
554b0dbdaeaSJames Courtier-Dutton 			/* 44100 */
555b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
556b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
557b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
558b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K );
559b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 44.1kHz x1 */
560b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
561b0dbdaeaSJames Courtier-Dutton 			EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X );
562b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
563b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
564b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK );
565b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
566e40a0b2eSJames Courtier-Dutton 			msleep(10);
567b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
568b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
569b0dbdaeaSJames Courtier-Dutton 			break;
570b0dbdaeaSJames Courtier-Dutton 		case 1:
571b0dbdaeaSJames Courtier-Dutton 			/* 48000 */
572b0dbdaeaSJames Courtier-Dutton 			/* Mute all */
573b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE );
574b0dbdaeaSJames Courtier-Dutton 			/* Default fallback clock 48kHz */
575b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K );
576b0dbdaeaSJames Courtier-Dutton 			/* Word Clock source, Internal 48kHz x1 */
577b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK,
578b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X );
579b0dbdaeaSJames Courtier-Dutton 			/* Set LEDs on Audio Dock */
580b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2,
581b0dbdaeaSJames Courtier-Dutton 				EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK );
582b0dbdaeaSJames Courtier-Dutton 			/* Allow DLL to settle */
583e40a0b2eSJames Courtier-Dutton 			msleep(10);
584b0dbdaeaSJames Courtier-Dutton 			/* Unmute all */
585b0dbdaeaSJames Courtier-Dutton 			snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE );
586b0dbdaeaSJames Courtier-Dutton 			break;
587b0dbdaeaSJames Courtier-Dutton 		}
588b0dbdaeaSJames Courtier-Dutton 	}
589b0dbdaeaSJames Courtier-Dutton         return change;
590b0dbdaeaSJames Courtier-Dutton }
591b0dbdaeaSJames Courtier-Dutton 
592b0dbdaeaSJames Courtier-Dutton static struct snd_kcontrol_new snd_emu1010_internal_clock =
593b0dbdaeaSJames Courtier-Dutton {
594b0dbdaeaSJames Courtier-Dutton 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
595b0dbdaeaSJames Courtier-Dutton 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
596b0dbdaeaSJames Courtier-Dutton 	.name =         "Clock Internal Rate",
597b0dbdaeaSJames Courtier-Dutton 	.count =	1,
598b0dbdaeaSJames Courtier-Dutton 	.info =         snd_emu1010_internal_clock_info,
599b0dbdaeaSJames Courtier-Dutton 	.get =          snd_emu1010_internal_clock_get,
600b0dbdaeaSJames Courtier-Dutton 	.put =          snd_emu1010_internal_clock_put
601b0dbdaeaSJames Courtier-Dutton };
602b0dbdaeaSJames Courtier-Dutton 
603184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
604184c1e2cSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
605184c1e2cSJames Courtier-Dutton {
606184c1e2cSJames Courtier-Dutton #if 0
607184c1e2cSJames Courtier-Dutton 	static char *texts[4] = {
608184c1e2cSJames Courtier-Dutton 		"Unknown1", "Unknown2", "Mic", "Line"
609184c1e2cSJames Courtier-Dutton 	};
610184c1e2cSJames Courtier-Dutton #endif
611184c1e2cSJames Courtier-Dutton 	static char *texts[2] = {
612184c1e2cSJames Courtier-Dutton 		"Mic", "Line"
613184c1e2cSJames Courtier-Dutton 	};
614184c1e2cSJames Courtier-Dutton 
615184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
616184c1e2cSJames Courtier-Dutton 	uinfo->count = 1;
617184c1e2cSJames Courtier-Dutton 	uinfo->value.enumerated.items = 2;
618184c1e2cSJames Courtier-Dutton 	if (uinfo->value.enumerated.item > 1)
619184c1e2cSJames Courtier-Dutton                 uinfo->value.enumerated.item = 1;
620184c1e2cSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
621184c1e2cSJames Courtier-Dutton 	return 0;
622184c1e2cSJames Courtier-Dutton }
623184c1e2cSJames Courtier-Dutton 
624184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
625184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
626184c1e2cSJames Courtier-Dutton {
627184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
628184c1e2cSJames Courtier-Dutton 
629184c1e2cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
630184c1e2cSJames Courtier-Dutton 	return 0;
631184c1e2cSJames Courtier-Dutton }
632184c1e2cSJames Courtier-Dutton 
633184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
634184c1e2cSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
635184c1e2cSJames Courtier-Dutton {
636184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
637184c1e2cSJames Courtier-Dutton 	unsigned int source_id;
638184c1e2cSJames Courtier-Dutton 	unsigned int ngain, ogain;
639184c1e2cSJames Courtier-Dutton 	u32 gpio;
640184c1e2cSJames Courtier-Dutton 	int change = 0;
641184c1e2cSJames Courtier-Dutton 	unsigned long flags;
642184c1e2cSJames Courtier-Dutton 	u32 source;
643184c1e2cSJames Courtier-Dutton 	/* If the capture source has changed,
644184c1e2cSJames Courtier-Dutton 	 * update the capture volume from the cached value
645184c1e2cSJames Courtier-Dutton 	 * for the particular source.
646184c1e2cSJames Courtier-Dutton 	 */
647184c1e2cSJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */
648184c1e2cSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
649184c1e2cSJames Courtier-Dutton 	if (change) {
650184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */
651184c1e2cSJames Courtier-Dutton 		spin_lock_irqsave(&emu->emu_lock, flags);
652184c1e2cSJames Courtier-Dutton 		gpio = inl(emu->port + A_IOCFG);
653184c1e2cSJames Courtier-Dutton 		if (source_id==0)
654184c1e2cSJames Courtier-Dutton 			outl(gpio | 0x4, emu->port + A_IOCFG);
655184c1e2cSJames Courtier-Dutton 		else
656184c1e2cSJames Courtier-Dutton 			outl(gpio & ~0x4, emu->port + A_IOCFG);
657184c1e2cSJames Courtier-Dutton 		spin_unlock_irqrestore(&emu->emu_lock, flags);
658184c1e2cSJames Courtier-Dutton 
659184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
660184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
661184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
662184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
663184c1e2cSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Right */
664184c1e2cSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
665184c1e2cSJames Courtier-Dutton 		if (ngain != ogain)
666184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
667184c1e2cSJames Courtier-Dutton 
668184c1e2cSJames Courtier-Dutton 		source = 1 << (source_id + 2);
669184c1e2cSJames Courtier-Dutton 		snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */
670184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
671184c1e2cSJames Courtier-Dutton 	}
672184c1e2cSJames Courtier-Dutton         return change;
673184c1e2cSJames Courtier-Dutton }
674184c1e2cSJames Courtier-Dutton 
675184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_capture_source =
676184c1e2cSJames Courtier-Dutton {
677184c1e2cSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
678184c1e2cSJames Courtier-Dutton 		.name =		"Capture Source",
679184c1e2cSJames Courtier-Dutton 		.info =		snd_audigy_i2c_capture_source_info,
680184c1e2cSJames Courtier-Dutton 		.get =		snd_audigy_i2c_capture_source_get,
681184c1e2cSJames Courtier-Dutton 		.put =		snd_audigy_i2c_capture_source_put
682184c1e2cSJames Courtier-Dutton };
683184c1e2cSJames Courtier-Dutton 
684184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol,
685184c1e2cSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
686184c1e2cSJames Courtier-Dutton {
687184c1e2cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
688184c1e2cSJames Courtier-Dutton 	uinfo->count = 2;
689184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.min = 0;
690184c1e2cSJames Courtier-Dutton 	uinfo->value.integer.max = 255;
691184c1e2cSJames Courtier-Dutton 	return 0;
692184c1e2cSJames Courtier-Dutton }
693184c1e2cSJames Courtier-Dutton 
694184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol,
695184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
696184c1e2cSJames Courtier-Dutton {
697184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
698184c1e2cSJames Courtier-Dutton 	int source_id;
699184c1e2cSJames Courtier-Dutton 
700184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
701184c1e2cSJames Courtier-Dutton 
702184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
703184c1e2cSJames Courtier-Dutton 	ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
704184c1e2cSJames Courtier-Dutton 	return 0;
705184c1e2cSJames Courtier-Dutton }
706184c1e2cSJames Courtier-Dutton 
707184c1e2cSJames Courtier-Dutton static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol,
708184c1e2cSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
709184c1e2cSJames Courtier-Dutton {
710184c1e2cSJames Courtier-Dutton 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
711184c1e2cSJames Courtier-Dutton 	unsigned int ogain;
712184c1e2cSJames Courtier-Dutton 	unsigned int ngain;
713184c1e2cSJames Courtier-Dutton 	int source_id;
714184c1e2cSJames Courtier-Dutton 	int change = 0;
715184c1e2cSJames Courtier-Dutton 
716184c1e2cSJames Courtier-Dutton 	source_id = kcontrol->private_value;
717184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
718184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[0];
719184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
720184c1e2cSJames Courtier-Dutton 		return 0;
721184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
722184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
723184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
724184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
725184c1e2cSJames Courtier-Dutton 		change = 1;
726184c1e2cSJames Courtier-Dutton 	}
727184c1e2cSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
728184c1e2cSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[1];
729184c1e2cSJames Courtier-Dutton 	if (ngain > 0xff)
730184c1e2cSJames Courtier-Dutton 		return 0;
731184c1e2cSJames Courtier-Dutton 	if (ogain != ngain) {
732184c1e2cSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
733184c1e2cSJames Courtier-Dutton 			snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
734184c1e2cSJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
735184c1e2cSJames Courtier-Dutton 		change = 1;
736184c1e2cSJames Courtier-Dutton 	}
737184c1e2cSJames Courtier-Dutton 
738184c1e2cSJames Courtier-Dutton 	return change;
739184c1e2cSJames Courtier-Dutton }
740184c1e2cSJames Courtier-Dutton 
741184c1e2cSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \
742184c1e2cSJames Courtier-Dutton {								\
743184c1e2cSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
744184c1e2cSJames Courtier-Dutton 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
745184c1e2cSJames Courtier-Dutton 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
746184c1e2cSJames Courtier-Dutton 	.info =  snd_audigy_i2c_volume_info,			\
747184c1e2cSJames Courtier-Dutton 	.get =   snd_audigy_i2c_volume_get,			\
748184c1e2cSJames Courtier-Dutton 	.put =   snd_audigy_i2c_volume_put,			\
749184c1e2cSJames Courtier-Dutton 	.tlv = { .p = snd_audigy_db_scale2 },			\
750184c1e2cSJames Courtier-Dutton 	.private_value = chid					\
751184c1e2cSJames Courtier-Dutton }
752184c1e2cSJames Courtier-Dutton 
753184c1e2cSJames Courtier-Dutton 
754184c1e2cSJames Courtier-Dutton static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = {
755184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Mic Capture Volume", 0),
756184c1e2cSJames Courtier-Dutton 	I2C_VOLUME("Line Capture Volume", 0)
757184c1e2cSJames Courtier-Dutton };
758184c1e2cSJames Courtier-Dutton 
7590af68e5eSTakashi Iwai #if 0
760eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
7611da177e4SLinus Torvalds {
7621da177e4SLinus Torvalds 	static char *texts[] = {"44100", "48000", "96000"};
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
7651da177e4SLinus Torvalds 	uinfo->count = 1;
7661da177e4SLinus Torvalds 	uinfo->value.enumerated.items = 3;
7671da177e4SLinus Torvalds 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
7681da177e4SLinus Torvalds 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
7691da177e4SLinus Torvalds 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
7701da177e4SLinus Torvalds 	return 0;
7711da177e4SLinus Torvalds }
7721da177e4SLinus Torvalds 
773eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
774eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
7751da177e4SLinus Torvalds {
776eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
7771da177e4SLinus Torvalds 	unsigned int tmp;
7781da177e4SLinus Torvalds 	unsigned long flags;
7791da177e4SLinus Torvalds 
7801da177e4SLinus Torvalds 
7811da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
7821da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
7831da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
7841da177e4SLinus Torvalds 	case A_SPDIF_44100:
7851da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
7861da177e4SLinus Torvalds 		break;
7871da177e4SLinus Torvalds 	case A_SPDIF_48000:
7881da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
7891da177e4SLinus Torvalds 		break;
7901da177e4SLinus Torvalds 	case A_SPDIF_96000:
7911da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
7921da177e4SLinus Torvalds 		break;
7931da177e4SLinus Torvalds 	default:
7941da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
7951da177e4SLinus Torvalds 	}
7961da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
7971da177e4SLinus Torvalds 	return 0;
7981da177e4SLinus Torvalds }
7991da177e4SLinus Torvalds 
800eb4698f3STakashi Iwai static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
801eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
8021da177e4SLinus Torvalds {
803eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
8041da177e4SLinus Torvalds 	int change;
8051da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
8061da177e4SLinus Torvalds 	unsigned long flags;
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
8091da177e4SLinus Torvalds 	case 0:
8101da177e4SLinus Torvalds 		val = A_SPDIF_44100;
8111da177e4SLinus Torvalds 		break;
8121da177e4SLinus Torvalds 	case 1:
8131da177e4SLinus Torvalds 		val = A_SPDIF_48000;
8141da177e4SLinus Torvalds 		break;
8151da177e4SLinus Torvalds 	case 2:
8161da177e4SLinus Torvalds 		val = A_SPDIF_96000;
8171da177e4SLinus Torvalds 		break;
8181da177e4SLinus Torvalds 	default:
8191da177e4SLinus Torvalds 		val = A_SPDIF_48000;
8201da177e4SLinus Torvalds 		break;
8211da177e4SLinus Torvalds 	}
8221da177e4SLinus Torvalds 
8231da177e4SLinus Torvalds 
8241da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
8251da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
8261da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
8271da177e4SLinus Torvalds 	tmp |= val;
8281da177e4SLinus Torvalds 	if ((change = (tmp != reg)))
8291da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
8301da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
8311da177e4SLinus Torvalds 	return change;
8321da177e4SLinus Torvalds }
8331da177e4SLinus Torvalds 
834eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_spdif_output_rate =
8351da177e4SLinus Torvalds {
8361da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
8371da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
8381da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
8391da177e4SLinus Torvalds 	.count =	1,
8401da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
8411da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
8421da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
8431da177e4SLinus Torvalds };
8440af68e5eSTakashi Iwai #endif
8451da177e4SLinus Torvalds 
846eb4698f3STakashi Iwai static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
847eb4698f3STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
8481da177e4SLinus Torvalds {
849eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
8501da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
8511da177e4SLinus Torvalds 	int change;
8521da177e4SLinus Torvalds 	unsigned int val;
8531da177e4SLinus Torvalds 	unsigned long flags;
8541da177e4SLinus Torvalds 
8551da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
8561da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
8571da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
8581da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
8591da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
8601da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
8611da177e4SLinus Torvalds 	if (change) {
8621da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
8631da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
8641da177e4SLinus Torvalds 	}
8651da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
8661da177e4SLinus Torvalds 	return change;
8671da177e4SLinus Torvalds }
8681da177e4SLinus Torvalds 
869eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
8701da177e4SLinus Torvalds {
8711da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
8725549d549SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
8731da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
8741da177e4SLinus Torvalds 	.count =	4,
8751da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
8761da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
8771da177e4SLinus Torvalds };
8781da177e4SLinus Torvalds 
879eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_spdif_control =
8801da177e4SLinus Torvalds {
8815549d549SClemens Ladisch 	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
8821da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
8831da177e4SLinus Torvalds 	.count =	4,
8841da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
8851da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
8861da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
8871da177e4SLinus Torvalds };
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds 
890eb4698f3STakashi Iwai static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
8911da177e4SLinus Torvalds {
8921da177e4SLinus Torvalds 	if (emu->audigy) {
8931da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
8941da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
8951da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
8961da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
8971da177e4SLinus Torvalds 	} else {
8981da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
8991da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
9001da177e4SLinus Torvalds 	}
9011da177e4SLinus Torvalds }
9021da177e4SLinus Torvalds 
903eb4698f3STakashi Iwai static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
9041da177e4SLinus Torvalds {
9051da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
9061da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
9071da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
9081da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
9091da177e4SLinus Torvalds 	if (emu->audigy) {
9101da177e4SLinus Torvalds 		unsigned int val = ((unsigned int)volume[4] << 24) |
9111da177e4SLinus Torvalds 			((unsigned int)volume[5] << 16) |
9121da177e4SLinus Torvalds 			((unsigned int)volume[6] << 8) |
9131da177e4SLinus Torvalds 			(unsigned int)volume[7];
9141da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
9151da177e4SLinus Torvalds 	}
9161da177e4SLinus Torvalds }
9171da177e4SLinus Torvalds 
9181da177e4SLinus Torvalds /* PCM stream controls */
9191da177e4SLinus Torvalds 
920eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9211da177e4SLinus Torvalds {
922eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
9231da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
9241da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
9251da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
9261da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
9271da177e4SLinus Torvalds 	return 0;
9281da177e4SLinus Torvalds }
9291da177e4SLinus Torvalds 
930eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
931eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
9321da177e4SLinus Torvalds {
9331da177e4SLinus Torvalds 	unsigned long flags;
934eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
935eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
936eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
9371da177e4SLinus Torvalds 	int voice, idx;
9381da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
9391da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
9421da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
9431da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
9441da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
9451da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
9461da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
9471da177e4SLinus Torvalds 	return 0;
9481da177e4SLinus Torvalds }
9491da177e4SLinus Torvalds 
950eb4698f3STakashi Iwai static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
951eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
9521da177e4SLinus Torvalds {
9531da177e4SLinus Torvalds 	unsigned long flags;
954eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
955eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
956eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
9571da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
9581da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
9591da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
9601da177e4SLinus Torvalds 
9611da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
9621da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
9631da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
9641da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
9651da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
9661da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
9671da177e4SLinus Torvalds 				change = 1;
9681da177e4SLinus Torvalds 			}
9691da177e4SLinus Torvalds 		}
9701da177e4SLinus Torvalds 	if (change && mix->epcm) {
9711da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
9721da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
9731da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
9741da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
9751da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
9761da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
9771da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
9781da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
9791da177e4SLinus Torvalds 		}
9801da177e4SLinus Torvalds 	}
9811da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
9821da177e4SLinus Torvalds 	return change;
9831da177e4SLinus Torvalds }
9841da177e4SLinus Torvalds 
985eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_routing_control =
9861da177e4SLinus Torvalds {
9871da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
98867ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
9891da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
9901da177e4SLinus Torvalds 	.count =	32,
9911da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
9921da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
9931da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
9941da177e4SLinus Torvalds };
9951da177e4SLinus Torvalds 
996eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9971da177e4SLinus Torvalds {
998eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
9991da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
10001da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
10011da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
10021da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
10031da177e4SLinus Torvalds 	return 0;
10041da177e4SLinus Torvalds }
10051da177e4SLinus Torvalds 
1006eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
1007eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
10081da177e4SLinus Torvalds {
10091da177e4SLinus Torvalds 	unsigned long flags;
1010eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1011eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1012eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10131da177e4SLinus Torvalds 	int idx;
10141da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
10151da177e4SLinus Torvalds 
10161da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10171da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
10181da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
10191da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10201da177e4SLinus Torvalds 	return 0;
10211da177e4SLinus Torvalds }
10221da177e4SLinus Torvalds 
1023eb4698f3STakashi Iwai static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
1024eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
10251da177e4SLinus Torvalds {
10261da177e4SLinus Torvalds 	unsigned long flags;
1027eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1028eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1029eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10301da177e4SLinus Torvalds 	int change = 0, idx, val;
10311da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
10321da177e4SLinus Torvalds 
10331da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10341da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
10351da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
10361da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
10371da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
10381da177e4SLinus Torvalds 			change = 1;
10391da177e4SLinus Torvalds 		}
10401da177e4SLinus Torvalds 	}
10411da177e4SLinus Torvalds 	if (change && mix->epcm) {
10421da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
10431da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
10441da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
10451da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
10461da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
10471da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
10481da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
10491da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
10501da177e4SLinus Torvalds 		}
10511da177e4SLinus Torvalds 	}
10521da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10531da177e4SLinus Torvalds 	return change;
10541da177e4SLinus Torvalds }
10551da177e4SLinus Torvalds 
1056eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_send_volume_control =
10571da177e4SLinus Torvalds {
10581da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
105967ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
10601da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
10611da177e4SLinus Torvalds 	.count =	32,
10621da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
10631da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
10641da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
10651da177e4SLinus Torvalds };
10661da177e4SLinus Torvalds 
1067eb4698f3STakashi Iwai static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
10681da177e4SLinus Torvalds {
10691da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
10701da177e4SLinus Torvalds 	uinfo->count = 3;
10711da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
10721da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
10731da177e4SLinus Torvalds 	return 0;
10741da177e4SLinus Torvalds }
10751da177e4SLinus Torvalds 
1076eb4698f3STakashi Iwai static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
1077eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
10781da177e4SLinus Torvalds {
1079eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1080eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1081eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10821da177e4SLinus Torvalds 	unsigned long flags;
10831da177e4SLinus Torvalds 	int idx;
10841da177e4SLinus Torvalds 
10851da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
10861da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
10871da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->attn[idx];
10881da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
10891da177e4SLinus Torvalds 	return 0;
10901da177e4SLinus Torvalds }
10911da177e4SLinus Torvalds 
1092eb4698f3STakashi Iwai static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
1093eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
10941da177e4SLinus Torvalds {
10951da177e4SLinus Torvalds 	unsigned long flags;
1096eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1097eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1098eb4698f3STakashi Iwai 		&emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
10991da177e4SLinus Torvalds 	int change = 0, idx, val;
11001da177e4SLinus Torvalds 
11011da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11021da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
11031da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 0xffff;
11041da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
11051da177e4SLinus Torvalds 			mix->attn[idx] = val;
11061da177e4SLinus Torvalds 			change = 1;
11071da177e4SLinus Torvalds 		}
11081da177e4SLinus Torvalds 	}
11091da177e4SLinus Torvalds 	if (change && mix->epcm) {
11101da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
11111da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
11121da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
11131da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
11141da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
11151da177e4SLinus Torvalds 		}
11161da177e4SLinus Torvalds 	}
11171da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11181da177e4SLinus Torvalds 	return change;
11191da177e4SLinus Torvalds }
11201da177e4SLinus Torvalds 
1121eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_attn_control =
11221da177e4SLinus Torvalds {
11231da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
112467ed4161SClemens Ladisch 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11251da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
11261da177e4SLinus Torvalds 	.count =	32,
11271da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
11281da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
11291da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
11301da177e4SLinus Torvalds };
11311da177e4SLinus Torvalds 
11321da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
11331da177e4SLinus Torvalds 
1134eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
11351da177e4SLinus Torvalds {
1136eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11371da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
11381da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
11391da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
11401da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
11411da177e4SLinus Torvalds 	return 0;
11421da177e4SLinus Torvalds }
11431da177e4SLinus Torvalds 
1144eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
1145eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11461da177e4SLinus Torvalds {
11471da177e4SLinus Torvalds 	unsigned long flags;
1148eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1149eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1150eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
11511da177e4SLinus Torvalds 	int idx;
11521da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11531da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11541da177e4SLinus Torvalds 
11551da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11561da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
11571da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
11581da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
11591da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11601da177e4SLinus Torvalds 	return 0;
11611da177e4SLinus Torvalds }
11621da177e4SLinus Torvalds 
1163eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
1164eb4698f3STakashi Iwai                                         struct snd_ctl_elem_value *ucontrol)
11651da177e4SLinus Torvalds {
11661da177e4SLinus Torvalds 	unsigned long flags;
1167eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
11681da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1169eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
11701da177e4SLinus Torvalds 	int change = 0, idx, val;
11711da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
11721da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
11731da177e4SLinus Torvalds 
11741da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
11751da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
11761da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
11771da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
11781da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
11791da177e4SLinus Torvalds 			change = 1;
11801da177e4SLinus Torvalds 		}
11811da177e4SLinus Torvalds 	}
11821da177e4SLinus Torvalds 
11831da177e4SLinus Torvalds 	if (change && mix->epcm) {
11841da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
11851da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
11861da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
11871da177e4SLinus Torvalds 		}
11881da177e4SLinus Torvalds 	}
11891da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
11901da177e4SLinus Torvalds 	return change;
11911da177e4SLinus Torvalds }
11921da177e4SLinus Torvalds 
1193eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
11941da177e4SLinus Torvalds {
11951da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
11961da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
11971da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
11981da177e4SLinus Torvalds 	.count =	16,
11991da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
12001da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
12011da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
12021da177e4SLinus Torvalds };
12031da177e4SLinus Torvalds 
1204eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12051da177e4SLinus Torvalds {
1206eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12071da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12081da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
12091da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12101da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
12111da177e4SLinus Torvalds 	return 0;
12121da177e4SLinus Torvalds }
12131da177e4SLinus Torvalds 
1214eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
1215eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12161da177e4SLinus Torvalds {
12171da177e4SLinus Torvalds 	unsigned long flags;
1218eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1219eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1220eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12211da177e4SLinus Torvalds 	int idx;
12221da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12231da177e4SLinus Torvalds 
12241da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12251da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
12261da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
12271da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12281da177e4SLinus Torvalds 	return 0;
12291da177e4SLinus Torvalds }
12301da177e4SLinus Torvalds 
1231eb4698f3STakashi Iwai static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
1232eb4698f3STakashi Iwai                                        struct snd_ctl_elem_value *ucontrol)
12331da177e4SLinus Torvalds {
12341da177e4SLinus Torvalds 	unsigned long flags;
1235eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12361da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1237eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
12381da177e4SLinus Torvalds 	int change = 0, idx, val;
12391da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
12401da177e4SLinus Torvalds 
12411da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12421da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
12431da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
12441da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
12451da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
12461da177e4SLinus Torvalds 			change = 1;
12471da177e4SLinus Torvalds 		}
12481da177e4SLinus Torvalds 	}
12491da177e4SLinus Torvalds 	if (change && mix->epcm) {
12501da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
12511da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
12521da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
12531da177e4SLinus Torvalds 		}
12541da177e4SLinus Torvalds 	}
12551da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12561da177e4SLinus Torvalds 	return change;
12571da177e4SLinus Torvalds }
12581da177e4SLinus Torvalds 
12591da177e4SLinus Torvalds 
1260eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
12611da177e4SLinus Torvalds {
12621da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
12631da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
12641da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
12651da177e4SLinus Torvalds 	.count =	16,
12661da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
12671da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
12681da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
12691da177e4SLinus Torvalds };
12701da177e4SLinus Torvalds 
1271eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
12721da177e4SLinus Torvalds {
12731da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
12741da177e4SLinus Torvalds 	uinfo->count = 1;
12751da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
12761da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
12771da177e4SLinus Torvalds 	return 0;
12781da177e4SLinus Torvalds }
12791da177e4SLinus Torvalds 
1280eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
1281eb4698f3STakashi Iwai                                 struct snd_ctl_elem_value *ucontrol)
12821da177e4SLinus Torvalds {
1283eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
1284eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix =
1285eb4698f3STakashi Iwai 		&emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
12861da177e4SLinus Torvalds 	unsigned long flags;
12871da177e4SLinus Torvalds 
12881da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
12891da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = mix->attn[0];
12901da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
12911da177e4SLinus Torvalds 	return 0;
12921da177e4SLinus Torvalds }
12931da177e4SLinus Torvalds 
1294eb4698f3STakashi Iwai static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
1295eb4698f3STakashi Iwai 				struct snd_ctl_elem_value *ucontrol)
12961da177e4SLinus Torvalds {
12971da177e4SLinus Torvalds 	unsigned long flags;
1298eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
12991da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1300eb4698f3STakashi Iwai 	struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
13011da177e4SLinus Torvalds 	int change = 0, val;
13021da177e4SLinus Torvalds 
13031da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
13041da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] & 0xffff;
13051da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
13061da177e4SLinus Torvalds 		mix->attn[0] = val;
13071da177e4SLinus Torvalds 		change = 1;
13081da177e4SLinus Torvalds 	}
13091da177e4SLinus Torvalds 	if (change && mix->epcm) {
13101da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
13111da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
13121da177e4SLinus Torvalds 		}
13131da177e4SLinus Torvalds 	}
13141da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13151da177e4SLinus Torvalds 	return change;
13161da177e4SLinus Torvalds }
13171da177e4SLinus Torvalds 
1318eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
13191da177e4SLinus Torvalds {
13201da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
13211da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
13221da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
13231da177e4SLinus Torvalds 	.count =	16,
13241da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
13251da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
13261da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
13271da177e4SLinus Torvalds };
13281da177e4SLinus Torvalds 
1329eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
13301da177e4SLinus Torvalds {
13311da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
13321da177e4SLinus Torvalds 	uinfo->count = 1;
13331da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
13341da177e4SLinus Torvalds 	uinfo->value.integer.max = 1;
13351da177e4SLinus Torvalds 	return 0;
13361da177e4SLinus Torvalds }
13371da177e4SLinus Torvalds 
1338eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
1339eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
13401da177e4SLinus Torvalds {
1341eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13421da177e4SLinus Torvalds 
13431da177e4SLinus Torvalds 	if (emu->audigy)
13441da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
13451da177e4SLinus Torvalds 	else
13461da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
13471da177e4SLinus Torvalds 	return 0;
13481da177e4SLinus Torvalds }
13491da177e4SLinus Torvalds 
1350eb4698f3STakashi Iwai static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
1351eb4698f3STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
13521da177e4SLinus Torvalds {
13531da177e4SLinus Torvalds 	unsigned long flags;
1354eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
13551da177e4SLinus Torvalds 	unsigned int reg, val;
13561da177e4SLinus Torvalds 	int change = 0;
13571da177e4SLinus Torvalds 
13581da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
1359184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1360184c1e2cSJames Courtier-Dutton 		/* Do nothing for Audigy 2 ZS Notebook */
1361184c1e2cSJames Courtier-Dutton 	} else if (emu->audigy) {
13621da177e4SLinus Torvalds 		reg = inl(emu->port + A_IOCFG);
13631da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
13641da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
13651da177e4SLinus Torvalds 		if (change) {
13661da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
13671da177e4SLinus Torvalds 			reg |= val;
13681da177e4SLinus Torvalds 			outl(reg | val, emu->port + A_IOCFG);
13691da177e4SLinus Torvalds 		}
13701da177e4SLinus Torvalds 	}
13711da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
13721da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0;
13731da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
13741da177e4SLinus Torvalds 	if (change) {
13751da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
13761da177e4SLinus Torvalds 		reg |= val;
13771da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
13781da177e4SLinus Torvalds 	}
13791da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
13801da177e4SLinus Torvalds 	return change;
13811da177e4SLinus Torvalds }
13821da177e4SLinus Torvalds 
1383eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata =
13841da177e4SLinus Torvalds {
13851da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
13861da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
13871da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
13881da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
13891da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
13901da177e4SLinus Torvalds };
13911da177e4SLinus Torvalds 
1392eb4698f3STakashi Iwai static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata =
13931da177e4SLinus Torvalds {
13941da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
13951da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
13961da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
13971da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
13981da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
13991da177e4SLinus Torvalds };
14001da177e4SLinus Torvalds 
14011da177e4SLinus Torvalds /*
14021da177e4SLinus Torvalds  */
1403eb4698f3STakashi Iwai static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
14041da177e4SLinus Torvalds {
1405eb4698f3STakashi Iwai 	struct snd_emu10k1 *emu = ac97->private_data;
14061da177e4SLinus Torvalds 	emu->ac97 = NULL;
14071da177e4SLinus Torvalds }
14081da177e4SLinus Torvalds 
14091da177e4SLinus Torvalds /*
14101da177e4SLinus Torvalds  */
1411eb4698f3STakashi Iwai static int remove_ctl(struct snd_card *card, const char *name)
14121da177e4SLinus Torvalds {
1413eb4698f3STakashi Iwai 	struct snd_ctl_elem_id id;
14141da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
14151da177e4SLinus Torvalds 	strcpy(id.name, name);
14161da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
14171da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
14181da177e4SLinus Torvalds }
14191da177e4SLinus Torvalds 
1420eb4698f3STakashi Iwai static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
14211da177e4SLinus Torvalds {
1422eb4698f3STakashi Iwai 	struct snd_ctl_elem_id sid;
14231da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
14241da177e4SLinus Torvalds 	strcpy(sid.name, name);
14251da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
14261da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
14271da177e4SLinus Torvalds }
14281da177e4SLinus Torvalds 
1429eb4698f3STakashi Iwai static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
14301da177e4SLinus Torvalds {
1431eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
14321da177e4SLinus Torvalds 	if (kctl) {
14331da177e4SLinus Torvalds 		strcpy(kctl->id.name, dst);
14341da177e4SLinus Torvalds 		return 0;
14351da177e4SLinus Torvalds 	}
14361da177e4SLinus Torvalds 	return -ENOENT;
14371da177e4SLinus Torvalds }
14381da177e4SLinus Torvalds 
1439eb4698f3STakashi Iwai int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
144067ed4161SClemens Ladisch 				int pcm_device, int multi_device)
14411da177e4SLinus Torvalds {
14421da177e4SLinus Torvalds 	int err, pcm;
1443eb4698f3STakashi Iwai 	struct snd_kcontrol *kctl;
1444eb4698f3STakashi Iwai 	struct snd_card *card = emu->card;
14451da177e4SLinus Torvalds 	char **c;
14461da177e4SLinus Torvalds 	static char *emu10k1_remove_ctls[] = {
14471da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
14481da177e4SLinus Torvalds 		"Master Mono Playback Switch",
14491da177e4SLinus Torvalds 		"Master Mono Playback Volume",
14501da177e4SLinus Torvalds 		"PCM Out Path & Mute",
14511da177e4SLinus Torvalds 		"Mono Output Select",
14527eae36fbSTakashi Iwai 		"Front Playback Switch",
14537eae36fbSTakashi Iwai 		"Front Playback Volume",
14541da177e4SLinus Torvalds 		"Surround Playback Switch",
14551da177e4SLinus Torvalds 		"Surround Playback Volume",
14561da177e4SLinus Torvalds 		"Center Playback Switch",
14571da177e4SLinus Torvalds 		"Center Playback Volume",
14581da177e4SLinus Torvalds 		"LFE Playback Switch",
14591da177e4SLinus Torvalds 		"LFE Playback Volume",
14601da177e4SLinus Torvalds 		NULL
14611da177e4SLinus Torvalds 	};
14621da177e4SLinus Torvalds 	static char *emu10k1_rename_ctls[] = {
14631da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
14641da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
14651da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
14661da177e4SLinus Torvalds 		NULL
14671da177e4SLinus Torvalds 	};
14681da177e4SLinus Torvalds 	static char *audigy_remove_ctls[] = {
14691da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
147021fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
147121fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
14721da177e4SLinus Torvalds 		"PCM Playback Switch",
14731da177e4SLinus Torvalds 		"PCM Playback Volume",
14741da177e4SLinus Torvalds 		"Master Mono Playback Switch",
14751da177e4SLinus Torvalds 		"Master Mono Playback Volume",
14761da177e4SLinus Torvalds 		"Master Playback Switch",
14771da177e4SLinus Torvalds 		"Master Playback Volume",
14781da177e4SLinus Torvalds 		"PCM Out Path & Mute",
14791da177e4SLinus Torvalds 		"Mono Output Select",
14801da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
14811da177e4SLinus Torvalds 		"Capture Source",
14821da177e4SLinus Torvalds 		"Capture Switch",
14831da177e4SLinus Torvalds 		"Capture Volume",
14841da177e4SLinus Torvalds 		"Mic Select",
14851da177e4SLinus Torvalds 		"Video Playback Switch",
14861da177e4SLinus Torvalds 		"Video Playback Volume",
14871da177e4SLinus Torvalds 		"Mic Playback Switch",
14881da177e4SLinus Torvalds 		"Mic Playback Volume",
14891da177e4SLinus Torvalds 		NULL
14901da177e4SLinus Torvalds 	};
14911da177e4SLinus Torvalds 	static char *audigy_rename_ctls[] = {
14921da177e4SLinus Torvalds 		/* use conventional names */
14931da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
14941da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
14951da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
14961da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
14971da177e4SLinus Torvalds 		NULL
14981da177e4SLinus Torvalds 	};
1499184c1e2cSJames Courtier-Dutton 	static char *audigy_rename_ctls_i2c_adc[] = {
1500184c1e2cSJames Courtier-Dutton 		//"Analog Mix Capture Volume","OLD Analog Mix Capture Volume",
1501184c1e2cSJames Courtier-Dutton 		"Line Capture Volume", "Analog Mix Capture Volume",
1502184c1e2cSJames Courtier-Dutton 		"Wave Playback Volume", "OLD PCM Playback Volume",
1503184c1e2cSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
1504184c1e2cSJames Courtier-Dutton 		"AMic Playback Volume", "Old Mic Playback Volume",
1505eb41dab6SJames Courtier-Dutton 		"CD Capture Volume", "IEC958 Optical Capture Volume",
1506184c1e2cSJames Courtier-Dutton 		NULL
1507184c1e2cSJames Courtier-Dutton 	};
1508184c1e2cSJames Courtier-Dutton 	static char *audigy_remove_ctls_i2c_adc[] = {
1509184c1e2cSJames Courtier-Dutton 		/* On the Audigy2 ZS Notebook
1510184c1e2cSJames Courtier-Dutton 		 * Capture via WM8775  */
1511184c1e2cSJames Courtier-Dutton 		"Mic Capture Volume",
1512184c1e2cSJames Courtier-Dutton 		"Analog Mix Capture Volume",
1513184c1e2cSJames Courtier-Dutton 		"Aux Capture Volume",
1514eb41dab6SJames Courtier-Dutton 		"IEC958 Optical Capture Volume",
1515184c1e2cSJames Courtier-Dutton 		NULL
1516184c1e2cSJames Courtier-Dutton 	};
151721fdddeaSJames Courtier-Dutton 	static char *audigy_remove_ctls_1361t_adc[] = {
151821fdddeaSJames Courtier-Dutton 		/* On the Audigy2 the AC97 playback is piped into
151921fdddeaSJames Courtier-Dutton 		 * the Philips ADC for 24bit capture */
152021fdddeaSJames Courtier-Dutton 		"PCM Playback Switch",
152121fdddeaSJames Courtier-Dutton 		"PCM Playback Volume",
152221fdddeaSJames Courtier-Dutton 		"Master Mono Playback Switch",
152321fdddeaSJames Courtier-Dutton 		"Master Mono Playback Volume",
152421fdddeaSJames Courtier-Dutton 		"Capture Source",
152521fdddeaSJames Courtier-Dutton 		"Capture Switch",
152621fdddeaSJames Courtier-Dutton 		"Capture Volume",
152721fdddeaSJames Courtier-Dutton 		"Mic Capture Volume",
152821fdddeaSJames Courtier-Dutton 		"Headphone Playback Switch",
152921fdddeaSJames Courtier-Dutton 		"Headphone Playback Volume",
153021fdddeaSJames Courtier-Dutton 		"3D Control - Center",
153121fdddeaSJames Courtier-Dutton 		"3D Control - Depth",
153221fdddeaSJames Courtier-Dutton 		"3D Control - Switch",
153321fdddeaSJames Courtier-Dutton 		"Line2 Playback Volume",
153421fdddeaSJames Courtier-Dutton 		"Line2 Capture Volume",
153521fdddeaSJames Courtier-Dutton 		NULL
153621fdddeaSJames Courtier-Dutton 	};
153721fdddeaSJames Courtier-Dutton 	static char *audigy_rename_ctls_1361t_adc[] = {
153821fdddeaSJames Courtier-Dutton 		"Master Playback Switch", "Master Capture Switch",
153921fdddeaSJames Courtier-Dutton 		"Master Playback Volume", "Master Capture Volume",
154021fdddeaSJames Courtier-Dutton 		"Wave Master Playback Volume", "Master Playback Volume",
154121fdddeaSJames Courtier-Dutton 		"PC Speaker Playback Switch", "PC Speaker Capture Switch",
154221fdddeaSJames Courtier-Dutton 		"PC Speaker Playback Volume", "PC Speaker Capture Volume",
154321fdddeaSJames Courtier-Dutton 		"Phone Playback Switch", "Phone Capture Switch",
154421fdddeaSJames Courtier-Dutton 		"Phone Playback Volume", "Phone Capture Volume",
154521fdddeaSJames Courtier-Dutton 		"Mic Playback Switch", "Mic Capture Switch",
154621fdddeaSJames Courtier-Dutton 		"Mic Playback Volume", "Mic Capture Volume",
154721fdddeaSJames Courtier-Dutton 		"Line Playback Switch", "Line Capture Switch",
154821fdddeaSJames Courtier-Dutton 		"Line Playback Volume", "Line Capture Volume",
154921fdddeaSJames Courtier-Dutton 		"CD Playback Switch", "CD Capture Switch",
155021fdddeaSJames Courtier-Dutton 		"CD Playback Volume", "CD Capture Volume",
155121fdddeaSJames Courtier-Dutton 		"Aux Playback Switch", "Aux Capture Switch",
155221fdddeaSJames Courtier-Dutton 		"Aux Playback Volume", "Aux Capture Volume",
155321fdddeaSJames Courtier-Dutton 		"Video Playback Switch", "Video Capture Switch",
155421fdddeaSJames Courtier-Dutton 		"Video Playback Volume", "Video Capture Volume",
155521fdddeaSJames Courtier-Dutton 
155621fdddeaSJames Courtier-Dutton 		NULL
155721fdddeaSJames Courtier-Dutton 	};
15581da177e4SLinus Torvalds 
15592b637da5SLee Revell 	if (emu->card_capabilities->ac97_chip) {
1560eb4698f3STakashi Iwai 		struct snd_ac97_bus *pbus;
1561eb4698f3STakashi Iwai 		struct snd_ac97_template ac97;
1562eb4698f3STakashi Iwai 		static struct snd_ac97_bus_ops ops = {
15631da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
15641da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
15651da177e4SLinus Torvalds 		};
15661da177e4SLinus Torvalds 
1567b1508693STakashi Iwai 		if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0)
15681da177e4SLinus Torvalds 			return err;
15691da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
15701da177e4SLinus Torvalds 
15711da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
15721da177e4SLinus Torvalds 		ac97.private_data = emu;
15731da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
15741da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
1575b1508693STakashi Iwai 		if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
1576b1508693STakashi Iwai 			if (emu->card_capabilities->ac97_chip == 1)
15771da177e4SLinus Torvalds 				return err;
1578b1508693STakashi Iwai 			snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n");
1579b1508693STakashi Iwai 			snd_printd(KERN_INFO"          Proceeding without ac97 mixers...\n");
1580b1508693STakashi Iwai 			snd_device_free(emu->card, pbus);
1581b1508693STakashi Iwai 			goto no_ac97; /* FIXME: get rid of ugly gotos.. */
1582b1508693STakashi Iwai 		}
15831da177e4SLinus Torvalds 		if (emu->audigy) {
15841da177e4SLinus Torvalds 			/* set master volume to 0 dB */
15854d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
15861da177e4SLinus Torvalds 			/* set capture source to mic */
15874d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
158821fdddeaSJames Courtier-Dutton 			if (emu->card_capabilities->adc_1361t)
158921fdddeaSJames Courtier-Dutton 				c = audigy_remove_ctls_1361t_adc;
159021fdddeaSJames Courtier-Dutton 			else
15911da177e4SLinus Torvalds 				c = audigy_remove_ctls;
15921da177e4SLinus Torvalds 		} else {
15931da177e4SLinus Torvalds 			/*
15941da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
15951da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
15961da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
15971da177e4SLinus Torvalds 			 */
15981da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
15991da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
16001da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
16012594d960SRolf Stefan Wilke 				snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202);
16021da177e4SLinus Torvalds 			}
16031da177e4SLinus Torvalds 			/* remove unused AC97 controls */
16044d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
16054d7d7596STakashi Iwai 			snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
16061da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
16071da177e4SLinus Torvalds 		}
16081da177e4SLinus Torvalds 		for (; *c; c++)
16091da177e4SLinus Torvalds 			remove_ctl(card, *c);
1610184c1e2cSJames Courtier-Dutton 	} else if (emu->card_capabilities->i2c_adc) {
1611184c1e2cSJames Courtier-Dutton 		c = audigy_remove_ctls_i2c_adc;
1612184c1e2cSJames Courtier-Dutton 		for (; *c; c++)
1613184c1e2cSJames Courtier-Dutton 			remove_ctl(card, *c);
16141da177e4SLinus Torvalds 	} else {
1615f12aa40cSTakashi Iwai 	no_ac97:
16162b637da5SLee Revell 		if (emu->card_capabilities->ecard)
16171da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
16181da177e4SLinus Torvalds 		else if (emu->audigy)
16191da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
16201da177e4SLinus Torvalds 		else
16211da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
16221da177e4SLinus Torvalds 	}
16231da177e4SLinus Torvalds 
16241da177e4SLinus Torvalds 	if (emu->audigy)
162521fdddeaSJames Courtier-Dutton 		if (emu->card_capabilities->adc_1361t)
162621fdddeaSJames Courtier-Dutton 			c = audigy_rename_ctls_1361t_adc;
1627184c1e2cSJames Courtier-Dutton 		else if (emu->card_capabilities->i2c_adc)
1628184c1e2cSJames Courtier-Dutton 			c = audigy_rename_ctls_i2c_adc;
162921fdddeaSJames Courtier-Dutton 		else
16301da177e4SLinus Torvalds 			c = audigy_rename_ctls;
16311da177e4SLinus Torvalds 	else
16321da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
16331da177e4SLinus Torvalds 	for (; *c; c += 2)
16341da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
163521fdddeaSJames Courtier-Dutton 
1636e3b9bc0eSJames Courtier-Dutton 	if (emu->card_capabilities->subsystem == 0x20071102) {  /* Audigy 4 Pro */
1637e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
1638e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
1639e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
1640e3b9bc0eSJames Courtier-Dutton 		rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
1641e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Switch");
1642e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "Headphone Playback Volume");
1643e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Center");
1644e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Depth");
1645e3b9bc0eSJames Courtier-Dutton 		remove_ctl(card, "3D Control - Switch");
1646e3b9bc0eSJames Courtier-Dutton 	}
16471da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
16481da177e4SLinus Torvalds 		return -ENOMEM;
164967ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
16501da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16511da177e4SLinus Torvalds 		return err;
16521da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
16531da177e4SLinus Torvalds 		return -ENOMEM;
165467ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
16551da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16561da177e4SLinus Torvalds 		return err;
16571da177e4SLinus Torvalds 	if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
16581da177e4SLinus Torvalds 		return -ENOMEM;
165967ed4161SClemens Ladisch 	kctl->id.device = pcm_device;
16601da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16611da177e4SLinus Torvalds 		return err;
16621da177e4SLinus Torvalds 
16631da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
16641da177e4SLinus Torvalds 		return -ENOMEM;
166567ed4161SClemens Ladisch 	kctl->id.device = multi_device;
16661da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16671da177e4SLinus Torvalds 		return err;
16681da177e4SLinus Torvalds 
16691da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
16701da177e4SLinus Torvalds 		return -ENOMEM;
167167ed4161SClemens Ladisch 	kctl->id.device = multi_device;
16721da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16731da177e4SLinus Torvalds 		return err;
16741da177e4SLinus Torvalds 
16751da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
16761da177e4SLinus Torvalds 		return -ENOMEM;
167767ed4161SClemens Ladisch 	kctl->id.device = multi_device;
16781da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
16791da177e4SLinus Torvalds 		return err;
16801da177e4SLinus Torvalds 
16811da177e4SLinus Torvalds 	/* initialize the routing and volume table for each pcm playback stream */
16821da177e4SLinus Torvalds 	for (pcm = 0; pcm < 32; pcm++) {
1683eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
16841da177e4SLinus Torvalds 		int v;
16851da177e4SLinus Torvalds 
16861da177e4SLinus Torvalds 		mix = &emu->pcm_mixer[pcm];
16871da177e4SLinus Torvalds 		mix->epcm = NULL;
16881da177e4SLinus Torvalds 
16891da177e4SLinus Torvalds 		for (v = 0; v < 4; v++)
16901da177e4SLinus Torvalds 			mix->send_routing[0][v] =
16911da177e4SLinus Torvalds 				mix->send_routing[1][v] =
16921da177e4SLinus Torvalds 				mix->send_routing[2][v] = v;
16931da177e4SLinus Torvalds 
16941da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
16951da177e4SLinus Torvalds 		mix->send_volume[0][0] = mix->send_volume[0][1] =
16961da177e4SLinus Torvalds 		mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
16971da177e4SLinus Torvalds 
16981da177e4SLinus Torvalds 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
16991da177e4SLinus Torvalds 	}
17001da177e4SLinus Torvalds 
17011da177e4SLinus Torvalds 	/* initialize the routing and volume table for the multichannel playback stream */
17021da177e4SLinus Torvalds 	for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
1703eb4698f3STakashi Iwai 		struct snd_emu10k1_pcm_mixer *mix;
17041da177e4SLinus Torvalds 		int v;
17051da177e4SLinus Torvalds 
17061da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[pcm];
17071da177e4SLinus Torvalds 		mix->epcm = NULL;
17081da177e4SLinus Torvalds 
17091da177e4SLinus Torvalds 		mix->send_routing[0][0] = pcm;
17101da177e4SLinus Torvalds 		mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
17111da177e4SLinus Torvalds 		for (v = 0; v < 2; v++)
17121da177e4SLinus Torvalds 			mix->send_routing[0][2+v] = 13+v;
17131da177e4SLinus Torvalds 		if (emu->audigy)
17141da177e4SLinus Torvalds 			for (v = 0; v < 4; v++)
17151da177e4SLinus Torvalds 				mix->send_routing[0][4+v] = 60+v;
17161da177e4SLinus Torvalds 
17171da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
17181da177e4SLinus Torvalds 		mix->send_volume[0][0]  = 255;
17191da177e4SLinus Torvalds 
17201da177e4SLinus Torvalds 		mix->attn[0] = 0xffff;
17211da177e4SLinus Torvalds 	}
17221da177e4SLinus Torvalds 
17232b637da5SLee Revell 	if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
17241da177e4SLinus Torvalds 		/* sb live! and audigy */
17251da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
17261da177e4SLinus Torvalds 			return -ENOMEM;
17275549d549SClemens Ladisch 		if (!emu->audigy)
17285549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
17291da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17301da177e4SLinus Torvalds 			return err;
17311da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
17321da177e4SLinus Torvalds 			return -ENOMEM;
17335549d549SClemens Ladisch 		if (!emu->audigy)
17345549d549SClemens Ladisch 			kctl->id.device = emu->pcm_efx->device;
17351da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17361da177e4SLinus Torvalds 			return err;
17371da177e4SLinus Torvalds 	}
17381da177e4SLinus Torvalds 
17399f4bd5ddSJames Courtier-Dutton 	if ( emu->card_capabilities->emu1010) {
174019b99fbaSJames Courtier-Dutton 		;  /* Disable the snd_audigy_spdif_shared_spdif */
174119b99fbaSJames Courtier-Dutton 	} else if (emu->audigy) {
17421da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
17431da177e4SLinus Torvalds 			return -ENOMEM;
17441da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17451da177e4SLinus Torvalds 			return err;
1746001f7589SJames Courtier-Dutton #if 0
17471da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
17481da177e4SLinus Torvalds 			return -ENOMEM;
17491da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17501da177e4SLinus Torvalds 			return err;
1751001f7589SJames Courtier-Dutton #endif
17522b637da5SLee Revell 	} else if (! emu->card_capabilities->ecard) {
17531da177e4SLinus Torvalds 		/* sb live! */
17541da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
17551da177e4SLinus Torvalds 			return -ENOMEM;
17561da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
17571da177e4SLinus Torvalds 			return err;
17581da177e4SLinus Torvalds 	}
17592b637da5SLee Revell 	if (emu->card_capabilities->ca0151_chip) { /* P16V */
17601da177e4SLinus Torvalds 		if ((err = snd_p16v_mixer(emu)))
17611da177e4SLinus Torvalds 			return err;
17621da177e4SLinus Torvalds 	}
17631da177e4SLinus Torvalds 
17649f4bd5ddSJames Courtier-Dutton 	if ( emu->card_capabilities->emu1010) {
17659f4bd5ddSJames Courtier-Dutton 		int i;
17669f4bd5ddSJames Courtier-Dutton 
17679f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) {
17689f4bd5ddSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu));
17699f4bd5ddSJames Courtier-Dutton 			if (err < 0)
17709f4bd5ddSJames Courtier-Dutton 				return err;
17719f4bd5ddSJames Courtier-Dutton 		}
17729f4bd5ddSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) {
17739f4bd5ddSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu));
17749f4bd5ddSJames Courtier-Dutton 			if (err < 0)
17759f4bd5ddSJames Courtier-Dutton 				return err;
17769f4bd5ddSJames Courtier-Dutton 		}
17779148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) {
17789148cc50SJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu));
17799148cc50SJames Courtier-Dutton 			if (err < 0)
17809148cc50SJames Courtier-Dutton 				return err;
17819148cc50SJames Courtier-Dutton 		}
17829148cc50SJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) {
17839148cc50SJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu));
17849148cc50SJames Courtier-Dutton 			if (err < 0)
17859148cc50SJames Courtier-Dutton 				return err;
17869148cc50SJames Courtier-Dutton 		}
1787b0dbdaeaSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu));
1788b0dbdaeaSJames Courtier-Dutton 		if (err < 0)
1789b0dbdaeaSJames Courtier-Dutton 			return err;
17909f4bd5ddSJames Courtier-Dutton 	}
17919f4bd5ddSJames Courtier-Dutton 
1792184c1e2cSJames Courtier-Dutton 	if ( emu->card_capabilities->i2c_adc) {
1793184c1e2cSJames Courtier-Dutton 		int i;
1794184c1e2cSJames Courtier-Dutton 
1795184c1e2cSJames Courtier-Dutton 		err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu));
1796184c1e2cSJames Courtier-Dutton 		if (err < 0)
1797184c1e2cSJames Courtier-Dutton 			return err;
1798184c1e2cSJames Courtier-Dutton 
1799184c1e2cSJames Courtier-Dutton 		for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) {
1800184c1e2cSJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu));
1801184c1e2cSJames Courtier-Dutton 			if (err < 0)
1802184c1e2cSJames Courtier-Dutton 				return err;
1803184c1e2cSJames Courtier-Dutton 		}
1804184c1e2cSJames Courtier-Dutton 	}
1805184c1e2cSJames Courtier-Dutton 
18061da177e4SLinus Torvalds 	return 0;
18071da177e4SLinus Torvalds }
1808